From 476f5e6977f3f0c9e4f035f7b6e5bfb223f92460 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Sun, 20 Sep 2026 16:35:27 +0800 Subject: [PATCH 1/2] 0.3.0 --- the keystrokes the host keeps for itself are a position now openkal 0.14 adds KAL_TERM_PASS_CONTROL, and this implementation forwards it to the host's terminal exactly as it forwards the other two positions: ISIG, IXON and IEXTEN together, because the position states that NO keystroke is reserved. Under node with a real terminal the three are the host's own. In a browser there is no terminal at all, and the property word already says so before any of this is reached --- which is the arrangement this package's terminal source exists to demonstrate, and it needed no change for a third position. A position whose requested value is the one in effect is not written, and with line assembly off the least number of bytes a read waits for is established, so that a terminal left at VMIN=0 does not make kal_stream_read report the end of an input that has not ended (clause 7.4). --- README.md | 6 +++--- mcpp.toml | 4 ++-- src/terminal.cpp | 40 +++++++++++++++++++++++++++++++++++++--- 3 files changed, 42 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index d86914c..0154eb9 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ So the interface is carried by a feature: ```toml [dependencies] -openkal-emscripten = { version = "0.2.0", features = ["threads"] } +openkal-emscripten = { version = "0.3.0", features = ["threads"] } ``` Without it, `src/threads/task.cpp` compiles to nothing, the eight `kal_task_*` @@ -143,10 +143,10 @@ implementation in its source: ```toml [dependencies] -openkal = "0.13.0" +openkal = "0.14.0" [target.'cfg(os = "emscripten")'.dependencies] -openkal-emscripten = "0.2.0" +openkal-emscripten = "0.3.0" ``` ## Licence diff --git a/mcpp.toml b/mcpp.toml index 5fc8b79..bb02995 100644 --- a/mcpp.toml +++ b/mcpp.toml @@ -1,7 +1,7 @@ [package] namespace = "mcpplibs" name = "openkal-emscripten" -version = "0.2.0" +version = "0.3.0" description = "An implementation of openkal for Emscripten, written ABOVE a C library rather than beneath one, because on this platform there is no kernel to issue calls to." license = "Apache-2.0" @@ -18,7 +18,7 @@ authors = ["mcpplibs"] repo = "https://github.com/mcpplibs/openkal-emscripten" [dependencies] -openkal = "0.13.0" +openkal = "0.14.0" [build] # THE DIALECT FLAGS ARE THE SAME AS EVERY OTHER IMPLEMENTATION'S AND THE REASON diff --git a/src/terminal.cpp b/src/terminal.cpp index 65e910b..ed07eaf 100644 --- a/src/terminal.cpp +++ b/src/terminal.cpp @@ -29,6 +29,15 @@ int kal_terminal_get_mode(kal_stream s, kal_uintptr* mode) { kal_uintptr m = 0; if ((t.c_lflag & ICANON) != 0) m |= KAL_TERM_LINE_EDIT; if ((t.c_lflag & ECHO) != 0) m |= KAL_TERM_ECHO; + // KAL_TERM_PASS_CONTROL IS READ FROM THREE FLAGS AND NOT FROM ISIG. The + // position states that the environment reserves NO keystroke, so it is set + // only where every mechanism by which this environment reserves one is off: + // ISIG for the interrupt and its neighbours, IXON for the pair that stops + // and starts output, IEXTEN for the one that takes the next keystroke + // literally. Under node these are the host's own; in a browser there is no + // terminal and the property word says so before any of this is reached. + if ((t.c_lflag & (ISIG | IEXTEN)) == 0 && + (t.c_iflag & IXON) == 0) m |= KAL_TERM_PASS_CONTROL; *mode = m; return kal_ok; } @@ -37,12 +46,37 @@ int kal_terminal_set_mode(kal_stream s, kal_uintptr mode) { struct termios t{}; const int fd = static_cast(s.h); if (::tcgetattr(fd, &t) != 0) return oke::last(); - // READ, MODIFY, WRITE, AND ONLY THE TWO BITS openkal NAMES. A mode + const bool reserved_none = (t.c_lflag & (ISIG | IEXTEN)) == 0 && + (t.c_iflag & IXON) == 0; + // READ, MODIFY, WRITE, AND ONLY THE POSITIONS openkal NAMES. A mode // composed from scratch would silently reset every other attribute of the - // terminal -- flow control, the special characters, the baud rate -- none - // of which this interface claims to own. + // terminal -- the special characters, the baud rate -- none of which this + // interface claims to own. if (mode & KAL_TERM_LINE_EDIT) t.c_lflag |= ICANON; else t.c_lflag &= ~ICANON; if (mode & KAL_TERM_ECHO) t.c_lflag |= ECHO; else t.c_lflag &= ~ECHO; + + // A POSITION WHOSE REQUESTED VALUE IS THE ONE IN EFFECT IS NOT WRITTEN. + // This one stands for three flags, so establishing it again would settle + // two mechanisms the caller never asked about. + if (((mode & KAL_TERM_PASS_CONTROL) != 0) != reserved_none) { + if (mode & KAL_TERM_PASS_CONTROL) { + t.c_lflag &= ~(ISIG | IEXTEN); + t.c_iflag &= ~IXON; + } else { + t.c_lflag |= (ISIG | IEXTEN); + t.c_iflag |= IXON; + } + } + + // AND A MODE IS NOT A WAY TO END THE INPUT. With line assembly off, how + // long a read waits is decided by VMIN and VTIME, and a terminal left at + // VMIN=0 makes `kal_stream_read' report zero --- which clause 7.4 says + // denotes the end of the input. A caller that wants a read which gives up + // asks `kal_timeout_read' for one. + if ((mode & KAL_TERM_LINE_EDIT) == 0) { + t.c_cc[VMIN] = 1; + t.c_cc[VTIME] = 0; + } // TCSANOW and not TCSADRAIN: openkal's caller has just been told what the // mode is and is entitled to have it take effect before its next read. if (::tcsetattr(fd, TCSANOW, &t) != 0) return oke::last(); From 9b07918dcdc9a7be3ea1ffc63d2ee2cd2cc3f6ea Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Sun, 20 Sep 2026 16:43:01 +0800 Subject: [PATCH 2/2] the absence check takes the working trees, and the engine pin meets the index floor The check builds a program that calls kal_process_spawn and asserts that the link fails naming it. It reached openkal by the version this package's manifest asks for, so on the branch that raises that version it asked the index for one not registered yet and reported 'the build did not fail naming kal_process_spawn' for a build that never started. Both dependencies now name the working trees, which is what the check is about; and MCPP_VERSION moves to the engine the index requires, which the same step met as a second failure. --- .github/workflows/ci.yml | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e45489f..1091441 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,7 +40,7 @@ env: # `em++`'s C compiler is `emcc` and not `em` (a C translation unit in the # conformance suite does not compile without that), and the wasm target rows # resolve the emsdk payload. - MCPP_VERSION: 2026.9.12.2 + MCPP_VERSION: 2026.9.18.3 XLINGS_VERSION: v2026.8.17.2 XLINGS_NON_INTERACTIVE: '1' @@ -189,24 +189,32 @@ jobs: work="$RUNNER_TEMP/absent" rm -rf "$work"; mkdir -p "$work/src" impl="$(pwd)" - # BOTH DEPENDENCIES NAMED THE SAME WAY, and this step therefore runs - # BEFORE the manifest is pointed at the specification's working tree. - # mcpp refuses a graph in which one package reaches `openkal` by path - # and another by version -- measured: + # BOTH DEPENDENCIES NAMED THE SAME WAY. mcpp refuses a graph in + # which one package reaches `openkal` by path and another by version + # -- measured: # # error: dependency 'mcpplibs.openkal' is requested as both a path # dep (by 'absent') and a version dep (by # 'mcpplibs.openkal-emscripten@path'). Pick one. # - # so the consumer uses the version this implementation's committed - # manifest names, which is the arrangement an ordinary consumer has. + # AND BOTH NAME THE WORKING TREE RATHER THAN A PUBLISHED VERSION. + # They named the version this implementation's manifest asks for, + # which is the arrangement an ordinary consumer has --- and which + # made this step unrunnable during the release it is part of: a + # branch that raises the version asks the index for one that is not + # registered yet, and the step then reports "the build did not fail + # naming kal_process_spawn" for a build that never started. What this + # step asserts is a property of the two trees, so it takes the trees. + sed 's|^openkal = .*$|openkal = { path = "'"$impl"'/.spec" }|' \ + "$impl/mcpp.toml" > "$impl/mcpp.toml.next" + mv "$impl/mcpp.toml.next" "$impl/mcpp.toml" cat > "$work/mcpp.toml" << TOML [package] name = "absent" version = "0.1.0" [dependencies] - openkal = "$(grep -oP '^openkal = "\K[0-9.]+' "$impl/mcpp.toml")" + openkal = { path = "$impl/.spec" } openkal-emscripten = { path = "$impl" } TOML cat > "$work/src/main.cpp" << 'CPP'