First commit, about step 8 in tutorial
This commit is contained in:
commit
8522d9fb33
169
.gitignore
vendored
Normal file
169
.gitignore
vendored
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
|
||||||
|
# Created by https://www.gitignore.io/api/vim,emacs,composer,jetbrains+all
|
||||||
|
# Edit at https://www.gitignore.io/?templates=vim,emacs,composer,jetbrains+all
|
||||||
|
|
||||||
|
### Composer ###
|
||||||
|
composer.phar
|
||||||
|
/vendor/
|
||||||
|
|
||||||
|
# Commit your application's lock file https://getcomposer.org/doc/01-basic-usage.md#commit-your-composer-lock-file-to-version-control
|
||||||
|
# You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file
|
||||||
|
# composer.lock
|
||||||
|
|
||||||
|
### Emacs ###
|
||||||
|
# -*- mode: gitignore; -*-
|
||||||
|
*~
|
||||||
|
\#*\#
|
||||||
|
/.emacs.desktop
|
||||||
|
/.emacs.desktop.lock
|
||||||
|
*.elc
|
||||||
|
auto-save-list
|
||||||
|
tramp
|
||||||
|
.\#*
|
||||||
|
|
||||||
|
# Org-mode
|
||||||
|
.org-id-locations
|
||||||
|
*_archive
|
||||||
|
|
||||||
|
# flymake-mode
|
||||||
|
*_flymake.*
|
||||||
|
|
||||||
|
# eshell files
|
||||||
|
/eshell/history
|
||||||
|
/eshell/lastdir
|
||||||
|
|
||||||
|
# elpa packages
|
||||||
|
/elpa/
|
||||||
|
|
||||||
|
# reftex files
|
||||||
|
*.rel
|
||||||
|
|
||||||
|
# AUCTeX auto folder
|
||||||
|
/auto/
|
||||||
|
|
||||||
|
# cask packages
|
||||||
|
.cask/
|
||||||
|
dist/
|
||||||
|
|
||||||
|
# Flycheck
|
||||||
|
flycheck_*.el
|
||||||
|
|
||||||
|
# server auth directory
|
||||||
|
/server/
|
||||||
|
|
||||||
|
# projectiles files
|
||||||
|
.projectile
|
||||||
|
|
||||||
|
# directory configuration
|
||||||
|
.dir-locals.el
|
||||||
|
|
||||||
|
# network security
|
||||||
|
/network-security.data
|
||||||
|
|
||||||
|
|
||||||
|
### JetBrains+all ###
|
||||||
|
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
|
||||||
|
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||||
|
|
||||||
|
# User-specific stuff
|
||||||
|
.idea/**/workspace.xml
|
||||||
|
.idea/**/tasks.xml
|
||||||
|
.idea/**/usage.statistics.xml
|
||||||
|
.idea/**/dictionaries
|
||||||
|
.idea/**/shelf
|
||||||
|
|
||||||
|
# Generated files
|
||||||
|
.idea/**/contentModel.xml
|
||||||
|
|
||||||
|
# Sensitive or high-churn files
|
||||||
|
.idea/**/dataSources/
|
||||||
|
.idea/**/dataSources.ids
|
||||||
|
.idea/**/dataSources.local.xml
|
||||||
|
.idea/**/sqlDataSources.xml
|
||||||
|
.idea/**/dynamic.xml
|
||||||
|
.idea/**/uiDesigner.xml
|
||||||
|
.idea/**/dbnavigator.xml
|
||||||
|
|
||||||
|
# Gradle
|
||||||
|
.idea/**/gradle.xml
|
||||||
|
.idea/**/libraries
|
||||||
|
|
||||||
|
# Gradle and Maven with auto-import
|
||||||
|
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||||
|
# since they will be recreated, and may cause churn. Uncomment if using
|
||||||
|
# auto-import.
|
||||||
|
# .idea/modules.xml
|
||||||
|
# .idea/*.iml
|
||||||
|
# .idea/modules
|
||||||
|
# *.iml
|
||||||
|
# *.ipr
|
||||||
|
|
||||||
|
# CMake
|
||||||
|
cmake-build-*/
|
||||||
|
|
||||||
|
# Mongo Explorer plugin
|
||||||
|
.idea/**/mongoSettings.xml
|
||||||
|
|
||||||
|
# File-based project format
|
||||||
|
*.iws
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
out/
|
||||||
|
|
||||||
|
# mpeltonen/sbt-idea plugin
|
||||||
|
.idea_modules/
|
||||||
|
|
||||||
|
# JIRA plugin
|
||||||
|
atlassian-ide-plugin.xml
|
||||||
|
|
||||||
|
# Cursive Clojure plugin
|
||||||
|
.idea/replstate.xml
|
||||||
|
|
||||||
|
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||||
|
com_crashlytics_export_strings.xml
|
||||||
|
crashlytics.properties
|
||||||
|
crashlytics-build.properties
|
||||||
|
fabric.properties
|
||||||
|
|
||||||
|
# Editor-based Rest Client
|
||||||
|
.idea/httpRequests
|
||||||
|
|
||||||
|
# Android studio 3.1+ serialized cache file
|
||||||
|
.idea/caches/build_file_checksums.ser
|
||||||
|
|
||||||
|
### JetBrains+all Patch ###
|
||||||
|
# Ignores the whole .idea folder and all .iml files
|
||||||
|
# See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360
|
||||||
|
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023
|
||||||
|
|
||||||
|
*.iml
|
||||||
|
modules.xml
|
||||||
|
.idea/misc.xml
|
||||||
|
*.ipr
|
||||||
|
|
||||||
|
# Sonarlint plugin
|
||||||
|
.idea/sonarlint
|
||||||
|
|
||||||
|
### Vim ###
|
||||||
|
# Swap
|
||||||
|
[._]*.s[a-v][a-z]
|
||||||
|
[._]*.sw[a-p]
|
||||||
|
[._]s[a-rt-v][a-z]
|
||||||
|
[._]ss[a-gi-z]
|
||||||
|
[._]sw[a-p]
|
||||||
|
|
||||||
|
# Session
|
||||||
|
Session.vim
|
||||||
|
Sessionx.vim
|
||||||
|
|
||||||
|
# Temporary
|
||||||
|
.netrwhist
|
||||||
|
# Auto-generated tag files
|
||||||
|
tags
|
||||||
|
# Persistent undo
|
||||||
|
[._]*.un~
|
||||||
|
|
||||||
|
# End of https://www.gitignore.io/api/vim,emacs,composer,jetbrains+all
|
41
kilo
Executable file
41
kilo
Executable file
@ -0,0 +1,41 @@
|
|||||||
|
#!/usr/bin/php
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Kilo;
|
||||||
|
|
||||||
|
use FFI;
|
||||||
|
|
||||||
|
require_once __DIR__ . '/src/constants.php';
|
||||||
|
require_once __DIR__ . '/src/functions.php';
|
||||||
|
|
||||||
|
$ffi = FFI::load(__DIR__ . '/src/ffi.h');
|
||||||
|
$original_termios = $ffi->new("struct termios");
|
||||||
|
|
||||||
|
function main(): int
|
||||||
|
{
|
||||||
|
global $ffi;
|
||||||
|
|
||||||
|
enableRawMode();
|
||||||
|
|
||||||
|
// Input Loop
|
||||||
|
do
|
||||||
|
{
|
||||||
|
$input = read_stdin();
|
||||||
|
if ($ffi->iscntrl($input))
|
||||||
|
{
|
||||||
|
printf("%d\n", $input);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("%d ('%c')\n", $input, $input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while ($input !== 'q');
|
||||||
|
|
||||||
|
disableRawMode();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Init
|
||||||
|
main();
|
130
src/constants.php
Normal file
130
src/constants.php
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Kilo;
|
||||||
|
|
||||||
|
define('STDIN_FILENO', 0);
|
||||||
|
define('TCSAFLUSH', 2);
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// ! Termios bitflags
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/* Input modes */
|
||||||
|
define('IGNBRK', (1 << 0)); /* Ignore break condition. */
|
||||||
|
define('BRKINT', (1 << 1)); /* Signal interrupt on break. */
|
||||||
|
define('IGNPAR', (1 << 2)); /* Ignore characters with parity errors. */
|
||||||
|
define('PARMRK', (1 << 3)); /* Mark parity and framing errors. */
|
||||||
|
define('INPCK', (1 << 4)); /* Enable input parity check. */
|
||||||
|
define('ISTRIP', (1 << 5)); /* Strip 8th bit off characters. */
|
||||||
|
define('INLCR', (1 << 6)); /* Map NL to CR on input. */
|
||||||
|
define('IGNCR', (1 << 7)); /* Ignore CR. */
|
||||||
|
define('ICRNL', (1 << 8)); /* Map CR to NL on input. */
|
||||||
|
define('IXON', (1 << 9)); /* Enable start/stop output control. */
|
||||||
|
define('IXOFF', (1 << 10)); /* Enable start/stop input control. */
|
||||||
|
define('IXANY', (1 << 11)); /* Any character will restart after stop. */
|
||||||
|
define('IMAXBEL', (1 << 13)); /* Ring bell when input queue is full. */
|
||||||
|
define('IUCLC', (1 << 14)); /* Translate upper case input to lower case. */
|
||||||
|
|
||||||
|
/* Output modes */
|
||||||
|
define('OPOST', (1 << 0)); /* Perform output processing. */
|
||||||
|
define('ONLCR', (1 << 1)); /* Map NL to CR-NL on output. */
|
||||||
|
define('OXTABS', (1 << 2)); /* Expand tabs to spaces. */
|
||||||
|
define('ONOEOT', (1 << 3)); /* Discard EOT (^D) on output. */
|
||||||
|
define('OCRNL', (1 << 4)); /* Map CR to NL. */
|
||||||
|
define('ONOCR', (1 << 5)); /* Discard CR's when on column 0. */
|
||||||
|
define('ONLRET', (1 << 6)); /* Move to column 0 on NL. */
|
||||||
|
define('NLDLY', (3 << 8)); /* NL delay. */
|
||||||
|
define('NL0', (0 << 8)); /* NL type 0. */
|
||||||
|
define('NL1', (1 << 8)); /* NL type 1. */
|
||||||
|
define('TABDLY', (3 << 10 | 1 << 2)); /* TAB delay. */
|
||||||
|
define('TAB0', (0 << 10)); /* TAB delay type 0. */
|
||||||
|
define('TAB1', (1 << 10)); /* TAB delay type 1. */
|
||||||
|
define('TAB2', (2 << 10)); /* TAB delay type 2. */
|
||||||
|
define('TAB3', (1 << 2)); /* Expand tabs to spaces. */
|
||||||
|
define('CRDLY', (3 << 12)); /* CR delay. */
|
||||||
|
define('CR0', (0 << 12)); /* CR delay type 0. */
|
||||||
|
define('CR1', (1 << 12)); /* CR delay type 1. */
|
||||||
|
define('CR2', (2 << 12)); /* CR delay type 2. */
|
||||||
|
define('CR3', (3 << 12)); /* CR delay type 3. */
|
||||||
|
define('FFDLY', (1 << 14)); /* FF delay. */
|
||||||
|
define('FF0', (0 << 14)); /* FF delay type 0. */
|
||||||
|
define('FF1', (1 << 14)); /* FF delay type 1. */
|
||||||
|
define('BSDLY', (1 << 15)); /* BS delay. */
|
||||||
|
define('BS0', (0 << 15)); /* BS delay type 0. */
|
||||||
|
define('BS1', (1 << 15)); /* BS delay type 1. */
|
||||||
|
define('VTDLY', (1 << 16)); /* VT delay. */
|
||||||
|
define('VT0', (0 << 16)); /* VT delay type 0. */
|
||||||
|
define('VT1', (1 << 16)); /* VT delay type 1. */
|
||||||
|
define('OLCUC', (1 << 17)); /* Translate lower case output to upper case */
|
||||||
|
define('OFILL', (1 << 18)); /* Send fill characters for delays. */
|
||||||
|
define('OFDEL', (1 << 19)); /* Fill is DEL. */
|
||||||
|
|
||||||
|
/* Control modes */
|
||||||
|
define('CIGNORE', (1 << 0)); /* Ignore these control flags. */
|
||||||
|
define('CS5', 0); /* 5 bits per byte. */
|
||||||
|
define('CS6', (1 << 8)); /* 6 bits per byte. */
|
||||||
|
define('CS7', (1 << 9)); /* 7 bits per byte. */
|
||||||
|
define('CS8', (CS6|CS7)); /* 8 bits per byte. */
|
||||||
|
define('CSIZE', (CS5|CS6|CS7|CS8)); /* Number of bits per byte (mask). */
|
||||||
|
define('CSTOPB', (1 << 10)); /* Two stop bits instead of one. */
|
||||||
|
define('CREAD', (1 << 11)); /* Enable receiver. */
|
||||||
|
define('PARENB', (1 << 12)); /* Parity enable. */
|
||||||
|
define('PARODD', (1 << 13)); /* Odd parity instead of even. */
|
||||||
|
define('HUPCL', (1 << 14)); /* Hang up on last close. */
|
||||||
|
define('CLOCAL', (1 << 15)); /* Ignore modem status lines. */
|
||||||
|
define('CRTSCTS', (1 << 16)); /* RTS/CTS flow control. */
|
||||||
|
define('CRTS_IFLOW', CRTSCTS); /* Compatibility. */
|
||||||
|
define('CCTS_OFLOW', CRTSCTS); /* Compatibility. */
|
||||||
|
define('CDTRCTS', (1 << 17)); /* DTR/CTS flow control. */
|
||||||
|
define('MDMBUF', (1 << 20)); /* DTR/DCD flow control. */
|
||||||
|
define('CHWFLOW', (MDMBUF|CRTSCTS|CDTRCTS)); /* All types of flow control. */
|
||||||
|
|
||||||
|
/* Local modes */
|
||||||
|
define('ECHOKE', (1 << 0)); /* Visual erase for KILL. */
|
||||||
|
define('_ECHOE', (1 << 1)); /* Visual erase for ERASE. */
|
||||||
|
define('ECHOE', _ECHOE);
|
||||||
|
define('_ECHOK', (1 << 2)); /* Echo NL after KILL. */
|
||||||
|
define('ECHOK', _ECHOK);
|
||||||
|
define('_ECHO', (1 << 3)); /* Enable echo. */
|
||||||
|
define('ECHO', _ECHO);
|
||||||
|
define('_ECHONL', (1 << 4)); /* Echo NL even if ECHO is off. */
|
||||||
|
define('ECHONL', _ECHONL);
|
||||||
|
define('ECHOPRT', (1 << 5)); /* Hardcopy visual erase. */
|
||||||
|
define('ECHOCTL', (1 << 6)); /* Echo control characters as ^X. */
|
||||||
|
define('_ISIG', (1 << 7)); /* Enable signals. */
|
||||||
|
define('ISIG', _ISIG);
|
||||||
|
define('_ICANON', (1 << 8)); /* Do erase and kill processing. */
|
||||||
|
define('ICANON', _ICANON);
|
||||||
|
define('ALTWERASE', (1 << 9)); /* Alternate WERASE algorithm. */
|
||||||
|
define('_IEXTEN', (1 << 10)); /* Enable DISCARD and LNEXT. */
|
||||||
|
define('IEXTEN', _IEXTEN);
|
||||||
|
define('EXTPROC', (1 << 11)); /* External processing. */
|
||||||
|
define('_TOSTOP', (1 << 22)); /* Send SIGTTOU for background output. */
|
||||||
|
define('TOSTOP', _TOSTOP);
|
||||||
|
define('FLUSHO', (1 << 23)); /* Output being flushed (state). */
|
||||||
|
define('XCASE', (1 << 24)); /* Canonical upper/lower case. */
|
||||||
|
define('NOKERNINFO', (1 << 25)); /* Disable VSTATUS. */
|
||||||
|
define('PENDIN', (1 << 29)); /* Retype pending input (state). */
|
||||||
|
define('_NOFLSH', (1 << 31)); /* Disable flush after interrupt. */
|
||||||
|
define('NOFLSH', _NOFLSH);
|
||||||
|
|
||||||
|
/* Control characters */
|
||||||
|
define('VEOF', 0); /* End-of-file character [ICANON]. */
|
||||||
|
define('VEOL', 1); /* End-of-line character [ICANON]. */
|
||||||
|
define('VEOL2', 2); /* Second EOL character [ICANON]. */
|
||||||
|
define('VERASE', 3); /* Erase character [ICANON]. */
|
||||||
|
define('VWERASE', 4); /* Word-erase character [ICANON]. */
|
||||||
|
define('VKILL', 5); /* Kill-line character [ICANON]. */
|
||||||
|
define('VREPRINT', 6); /* Reprint-line character [ICANON]. */
|
||||||
|
define('VINTR', 8); /* Interrupt character [ISIG]. */
|
||||||
|
define('VQUIT', 9); /* Quit character [ISIG]. */
|
||||||
|
define('VSUSP', 10); /* Suspend character [ISIG]. */
|
||||||
|
define('VDSUSP', 11); /* Delayed suspend character [ISIG]. */
|
||||||
|
define('VSTART', 12); /* Start (X-ON) character [IXON, IXOFF]. */
|
||||||
|
define('VSTOP', 13); /* Stop (X-OFF) character [IXON, IXOFF]. */
|
||||||
|
define('VLNEXT', 14); /* Literal-next character [IEXTEN]. */
|
||||||
|
define('VDISCARD', 15); /* Discard character [IEXTEN]. */
|
||||||
|
define('VMIN', 16); /* Minimum number of bytes read at once [!ICANON]. */
|
||||||
|
define('VTIME', 17); /* Time-out value (tenths of a second) [!ICANON]. */
|
||||||
|
define('VSTATUS', 18); /* Status character [ICANON]. */
|
||||||
|
define('NCCS', 20); /* Value duplicated in <hurd/tioctl.defs>. */
|
57
src/ffi.h
Normal file
57
src/ffi.h
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
/**
|
||||||
|
* Interfaces for PHP FFI
|
||||||
|
*
|
||||||
|
* Most of the structure code is cribbed from GLib
|
||||||
|
*
|
||||||
|
* Defines are not (generally) recognized by the FFI integration
|
||||||
|
*/
|
||||||
|
|
||||||
|
// PHP 'constants' for FFI integration
|
||||||
|
// These seem to be the only define statements supported by the FFI integration
|
||||||
|
#define FFI_SCOPE "terminal"
|
||||||
|
#define FFI_LIB "libc.so.6"
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//! <termios.h>
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/* Type of terminal control flag masks. */
|
||||||
|
typedef unsigned long int tcflag_t;
|
||||||
|
|
||||||
|
/* Type of control characters. */
|
||||||
|
typedef unsigned char cc_t;
|
||||||
|
|
||||||
|
/* Type of baud rate specifiers. */
|
||||||
|
typedef long int speed_t;
|
||||||
|
|
||||||
|
/* Terminal control structure. */
|
||||||
|
struct termios
|
||||||
|
{
|
||||||
|
/* Input modes. */
|
||||||
|
tcflag_t c_iflag;
|
||||||
|
|
||||||
|
/* Output modes. */
|
||||||
|
tcflag_t c_oflag;
|
||||||
|
|
||||||
|
/* Control modes. */
|
||||||
|
tcflag_t c_cflag;
|
||||||
|
|
||||||
|
/* Local modes. */
|
||||||
|
tcflag_t c_lflag;
|
||||||
|
|
||||||
|
/* Control characters. */
|
||||||
|
cc_t c_cc[20];
|
||||||
|
|
||||||
|
/* Input and output baud rates. */
|
||||||
|
speed_t __ispeed, __ospeed;
|
||||||
|
};
|
||||||
|
|
||||||
|
int tcgetattr (int fd, struct termios *termios_p);
|
||||||
|
int tcsetattr (int fd, int optional_actions, const struct termios *termios_p);
|
||||||
|
|
||||||
|
void cfmakeraw (struct termios *termios_p);
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//! <ctype.h>
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
int iscntrl (int);
|
40
src/functions.php
Normal file
40
src/functions.php
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Kilo;
|
||||||
|
|
||||||
|
use FFI;
|
||||||
|
|
||||||
|
// require_once 'constants.php';
|
||||||
|
|
||||||
|
function enableRawMode(): void
|
||||||
|
{
|
||||||
|
global $ffi;
|
||||||
|
global $original_termios;
|
||||||
|
|
||||||
|
|
||||||
|
// Populate the original terminal settings
|
||||||
|
$ffi->tcgetattr(STDIN_FILENO, FFI::addr($original_termios));
|
||||||
|
|
||||||
|
$termios = clone $original_termios;
|
||||||
|
|
||||||
|
$termios->c_lflag &= ~(_ECHO | ICANON);
|
||||||
|
|
||||||
|
// Turn on raw mode
|
||||||
|
$ffi->tcsetattr(STDIN_FILENO, TCSAFLUSH, FFI::addr($termios));
|
||||||
|
}
|
||||||
|
|
||||||
|
function disableRawMode(): void
|
||||||
|
{
|
||||||
|
global $ffi;
|
||||||
|
global $original_termios;
|
||||||
|
|
||||||
|
$ffi->tcsetattr(STDIN_FILENO, TCSAFLUSH, FFI::addr($original_termios));
|
||||||
|
}
|
||||||
|
|
||||||
|
function read_stdin() {
|
||||||
|
$handle = fopen('php://stdin', 'r');
|
||||||
|
$input = rtrim(fgets($handle, 128));
|
||||||
|
fclose($handle);
|
||||||
|
|
||||||
|
return $input;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user