added: TTY support to platform layer and `core.os`
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 28 Jun 2023 22:33:22 +0000 (17:33 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 28 Jun 2023 22:33:22 +0000 (17:33 -0500)
core/os/tty.onyx [new file with mode: 0644]
core/runtime/platform/js/platform.onyx
core/runtime/platform/onyx/platform.onyx
core/runtime/platform/wasi/platform.onyx
core/std.onyx
runtime/onyx_runtime.c
runtime/src/ort_tty.h [new file with mode: 0644]

diff --git a/core/os/tty.onyx b/core/os/tty.onyx
new file mode 100644 (file)
index 0000000..4609ae4
--- /dev/null
@@ -0,0 +1,55 @@
+package core.os
+
+use runtime
+
+TTY_State :: struct {
+    rows: i32;
+    cols: i32;
+    stdin_is_tty: bool;
+    stdout_is_tty: bool;
+    stderr_is_tty: bool;
+    echo: bool;
+    input_buffered: bool;
+    input_linefeeds: bool;
+}
+
+tty_sane :: () {
+    state := tty_get();
+    state.echo = true;
+    state.input_buffered = true;
+    tty_set(&state);
+}
+
+tty_raw :: () {
+    state := tty_get();
+    state.echo = false;
+    state.input_buffered = false;
+    tty_set(&state);
+}
+
+#if runtime.platform.Supports_TTY {
+
+tty_get :: () -> TTY_State {
+    state: TTY_State;
+    runtime.platform.__tty_get(&state);
+    return state;
+}
+
+tty_set :: (state: &TTY_State) -> bool {
+    return runtime.platform.__tty_set(state);
+}
+
+} else {
+
+tty_get :: () -> TTY_State {
+    assert(false, "core.os.tty_get not supported on this platform.");
+}
+
+tty_set :: (state: &TTY_State) -> bool {
+    assert(false, "core.os.tty_get not supported on this platform.");
+    return false;
+}
+
+}
+
+
index e60d205b8776cf62a48dd4b3c1dc779608118256..5b17a96b47fc36ff754a825682f7193d3a3e27f1 100644 (file)
@@ -20,6 +20,7 @@ Supports_Type_Info :: true
 Supports_Threads :: true
 Supports_Env_Vars :: false
 Supports_Futexes :: true
+Supports_TTY :: false
 
 __output_string   :: (s: str)      -> u32  #foreign "host" "print_str" ---
 __output_error    :: (s: str)      -> u32  #foreign "host" "print_str" ---
index 70592a9f476e9759c234d77da9bcebf7f1536e61..578ea682720ba9541f1b512316e0973fa780ed5b 100644 (file)
@@ -28,6 +28,7 @@ Supports_Type_Info :: true
 Supports_Threads :: true
 Supports_Env_Vars :: true
 Supports_Futexes :: true
+Supports_TTY :: true
 
 
 #library "onyx_runtime"
@@ -69,6 +70,10 @@ ProcessData :: #distinct u64
     __futex_wait :: (addr: rawptr, expected: i32, timeout: i32) -> i32 ---
     __futex_wake :: (addr: rawptr, maximum: i32) -> i32 ---
 
+    // TTY
+    __tty_get :: (state: &os.TTY_State) -> void ---
+    __tty_set :: (state: &os.TTY_State) -> bool ---
+
     // Time and sleep
     __time :: () -> u64 ---
 
index f6fe6716a489ef6bdaaf992ebaf7acc0e7e63c0a..8722ad90af54c5a05dd26f99bdbf9d8e1867ee8a 100644 (file)
@@ -37,6 +37,7 @@ Supports_Type_Info :: true
 Supports_Threads :: true
 Supports_Env_Vars :: true
 Supports_Futexes :: false
+Supports_TTY :: false
 
 
 __output_string :: (s: str) -> u32 {
index ad9a0a49ef790f4661a1db9b74754f87455966fb..74076f74597f36ab903be2c13b9e3e09abe5343c 100644 (file)
@@ -106,6 +106,10 @@ use runtime
     #load "./os/env"
 }
 
+#if runtime.platform.Supports_TTY {
+    #load "./os/tty"
+}
+
 #if runtime.Multi_Threading_Enabled {
     #load "./intrinsics/atomics"
 
index 9be0bf3d8e911d0ac2860773783d3403123e58ca..24dc0d1d213cf20ef1fcdf66051959009108b3bd 100644 (file)
@@ -21,6 +21,9 @@
     #include <linux/futex.h>
     #include <sys/syscall.h>
     #include <poll.h>
+    #include <termios.h>
+    #include <sys/ioctl.h>
+    #include <unistd.h>
 #endif
 
 #include "types.h"  // For POINTER_SIZE
@@ -32,6 +35,7 @@
 #include "src/ort_os.h"
 #include "src/ort_cptr.h"
 #include "src/ort_net.h"
+#include "src/ort_tty.h"
 
 
 ONYX_LIBRARY {
@@ -75,6 +79,8 @@ ONYX_LIBRARY {
     ONYX_FUNC(__random_get)
     ONYX_FUNC(__futex_wait)
     ONYX_FUNC(__futex_wake)
+    ONYX_FUNC(__tty_get)
+    ONYX_FUNC(__tty_set)
     ONYX_FUNC(__register_cleanup)
 
     ONYX_FUNC(__net_create_socket)
diff --git a/runtime/src/ort_tty.h b/runtime/src/ort_tty.h
new file mode 100644 (file)
index 0000000..fa5b8fc
--- /dev/null
@@ -0,0 +1,72 @@
+
+struct Onyx_TTY_State {
+    int rows, columns;
+    unsigned char stdin_is_tty, stdout_is_tty, stderr_is_tty;
+    unsigned char echo, input_buffered, input_linefeeds;
+};
+
+ONYX_DEF(__tty_get, (WASM_I32), ()) {
+    struct Onyx_TTY_State *state = ONYX_PTR(params->data[0].of.i32);
+
+#ifdef _BH_LINUX
+    struct winsize sz;
+    ioctl(0, TIOCGWINSZ, &sz);
+    state->rows = sz.ws_row;
+    state->columns = sz.ws_col;
+
+    struct termios term;
+    state->stdout_is_tty = tcgetattr(1, &term) == 0;
+    state->stderr_is_tty = tcgetattr(2, &term) == 0;
+    state->stdin_is_tty = tcgetattr(0, &term) == 0; // Do stdin last because we use it next.
+
+    state->echo = (term.c_lflag & ECHO) != 0;
+    state->input_buffered = (term.c_lflag & ICANON) != 0;
+    state->input_linefeeds = (term.c_lflag & ONLCR) != 0;
+#endif
+
+#ifdef _BH_WINDOWS
+    memset(state, 0, sizeof(*state));
+
+    state->rows = 80;
+    state->columns = 25;
+    state->echo = 1;
+    state->input_buffered = 1;
+    state->linefeeds_ignored = 0;
+#endif
+
+    return NULL;
+}
+
+ONYX_DEF(__tty_set, (WASM_I32), (WASM_I32)) {
+    struct Onyx_TTY_State *state = ONYX_PTR(params->data[0].of.i32);
+
+#ifdef _BH_LINUX
+    int success = 1;
+
+    struct termios term;
+    if (!tcgetattr(0, &term)) {
+        if (state->echo) term.c_lflag |=  (ECHO | ECHOE | ECHOK | ECHOCTL | IEXTEN);
+        else             term.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHOCTL | IEXTEN);
+
+        if (state->input_buffered) term.c_lflag |=  ICANON;
+        else                       term.c_lflag &= ~ICANON;
+
+        if (state->input_linefeeds) term.c_lflag |=  ONLCR;
+        else                        term.c_lflag &= ~ONLCR;
+
+        success = tcsetattr(0, TCSANOW, &term) == 0;
+
+    } else {
+        success = 0;
+    }
+
+    results->data[0] = WASM_I32_VAL(success);
+#endif
+
+#ifdef _BH_WINDOWS
+    results->data[0] = WASM_I32_VAL(0);
+#endif
+    return NULL;
+}
+
+