From 8522d9fb33edd3ed4db507e199d7396d594ff559 Mon Sep 17 00:00:00 2001 From: Timothy J Warren Date: Thu, 10 Oct 2019 12:28:46 -0400 Subject: [PATCH] First commit, about step 8 in tutorial --- .gitignore | 169 ++++++++++++++++++++++++++++++++++++++++++++++ kilo | 41 +++++++++++ src/constants.php | 130 +++++++++++++++++++++++++++++++++++ src/ffi.h | 57 ++++++++++++++++ src/functions.php | 40 +++++++++++ 5 files changed, 437 insertions(+) create mode 100644 .gitignore create mode 100755 kilo create mode 100644 src/constants.php create mode 100644 src/ffi.h create mode 100644 src/functions.php diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5e04216 --- /dev/null +++ b/.gitignore @@ -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 diff --git a/kilo b/kilo new file mode 100755 index 0000000..ebb29d1 --- /dev/null +++ b/kilo @@ -0,0 +1,41 @@ +#!/usr/bin/php +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(); diff --git a/src/constants.php b/src/constants.php new file mode 100644 index 0000000..c9c4c1c --- /dev/null +++ b/src/constants.php @@ -0,0 +1,130 @@ +. */ \ No newline at end of file diff --git a/src/ffi.h b/src/ffi.h new file mode 100644 index 0000000..c419ae9 --- /dev/null +++ b/src/ffi.h @@ -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" + +// ----------------------------------------------------------------------------- +//! +// ----------------------------------------------------------------------------- + +/* 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); + +// ----------------------------------------------------------------------------- +//! +// ----------------------------------------------------------------------------- +int iscntrl (int); diff --git a/src/functions.php b/src/functions.php new file mode 100644 index 0000000..2185df5 --- /dev/null +++ b/src/functions.php @@ -0,0 +1,40 @@ +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; +} \ No newline at end of file