From f26a280cda66032a4a9ea88aa140aed8a9c7e353 Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Tue, 3 Oct 2023 22:34:45 -0700 Subject: [PATCH] Implement basic canonical mode for Windows The `cat` command now works properly, when run by itself on the bash command prompt. It's working beautifully so far, and is only missing a few keystrokes for clearing words and lines. Definitely works more well than the one that ships with WIN32 :-) --- libc/calls/internal.h | 2 +- libc/calls/ioctl.c | 2 +- libc/calls/poll-nt.c | 2 +- libc/calls/read-nt.c | 277 +++++++++++++++++++----------- libc/calls/struct/fd.internal.h | 8 - libc/calls/tcgetattr-nt.c | 30 +--- libc/calls/tcsetattr-nt.c | 29 +--- libc/calls/write-nt.c | 4 +- libc/intrin/g_fds.c | 3 - libc/intrin/kprintf.greg.c | 2 +- libc/intrin/nomultics.c | 20 ++- libc/intrin/nomultics.internal.h | 54 ++++-- libc/runtime/printargs.c | 8 + libc/runtime/winmain.greg.c | 14 +- libc/stdio/fmt.c | 2 +- libc/sysv/consts.sh | 34 ++-- libc/sysv/consts/VDISCARD.S | 2 +- libc/sysv/consts/VEOF.S | 2 +- libc/sysv/consts/VEOL.S | 2 +- libc/sysv/consts/VEOL2.S | 2 +- libc/sysv/consts/VERASE.S | 2 +- libc/sysv/consts/VINTR.S | 2 +- libc/sysv/consts/VKILL.S | 2 +- libc/sysv/consts/VLNEXT.S | 2 +- libc/sysv/consts/VMIN.S | 2 +- libc/sysv/consts/VQUIT.S | 2 +- libc/sysv/consts/VREPRINT.S | 2 +- libc/sysv/consts/VSTART.S | 2 +- libc/sysv/consts/VSTOP.S | 2 +- libc/sysv/consts/VSUSP.S | 2 +- libc/sysv/consts/VSWTC.S | 2 +- libc/sysv/consts/VTIME.S | 2 +- libc/sysv/consts/VWERASE.S | 2 +- third_party/linenoise/linenoise.c | 12 +- third_party/lua/lrepl.c | 8 +- tool/net/redbean.c | 6 +- 36 files changed, 320 insertions(+), 231 deletions(-) diff --git a/libc/calls/internal.h b/libc/calls/internal.h index 59a159c1a..c50c6f6e6 100644 --- a/libc/calls/internal.h +++ b/libc/calls/internal.h @@ -27,7 +27,7 @@ void __printfds(void); uint32_t sys_getuid_nt(void); int __pause_thread(uint32_t); int IsWindowsExecutable(int64_t); -int CountConsoleInputBytes(int64_t); +int CountConsoleInputBytes(struct Fd *); int FlushConsoleInputBytes(int64_t); forceinline int64_t __getfdhandleactual(int fd) { diff --git a/libc/calls/ioctl.c b/libc/calls/ioctl.c index d2dab5cfa..0713f9047 100644 --- a/libc/calls/ioctl.c +++ b/libc/calls/ioctl.c @@ -114,7 +114,7 @@ static int ioctl_fionread(int fd, uint32_t *arg) { return __winerr(); } } else if (GetConsoleMode(handle, &cm)) { - int bytes = CountConsoleInputBytes(handle); + int bytes = CountConsoleInputBytes(g_fds.p + fd); return MAX(0, bytes); } else { return eopnotsupp(); diff --git a/libc/calls/poll-nt.c b/libc/calls/poll-nt.c index 563dcc36b..064a43072 100644 --- a/libc/calls/poll-nt.c +++ b/libc/calls/poll-nt.c @@ -155,7 +155,7 @@ textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint32_t *ms, pipefds[i].revents |= POLLERR; } } else if (GetConsoleMode(pipefds[i].handle, &cm)) { - if (CountConsoleInputBytes(pipefds[i].handle)) { + if (CountConsoleInputBytes(g_fds.p + fds[pipeindices[i]].fd)) { pipefds[i].revents |= POLLIN; } } else { diff --git a/libc/calls/read-nt.c b/libc/calls/read-nt.c index c683cd498..69289896f 100644 --- a/libc/calls/read-nt.c +++ b/libc/calls/read-nt.c @@ -26,12 +26,14 @@ #include "libc/fmt/itoa.h" #include "libc/intrin/atomic.h" #include "libc/intrin/dll.h" +#include "libc/intrin/kprintf.h" #include "libc/intrin/nomultics.internal.h" #include "libc/intrin/strace.internal.h" #include "libc/intrin/weaken.h" #include "libc/macros.internal.h" #include "libc/mem/mem.h" #include "libc/nt/console.h" +#include "libc/nt/enum/consolemodeflags.h" #include "libc/nt/enum/filetype.h" #include "libc/nt/enum/vk.h" #include "libc/nt/enum/wait.h" @@ -91,19 +93,20 @@ static const struct { #define KEYSTROKE_CONTAINER(e) DLL_CONTAINER(struct Keystroke, elem, e) struct Keystroke { - char buf[32]; - unsigned buflen; + char buf[23]; + unsigned char buflen; struct Dll elem; }; struct Keystrokes { struct Dll *list; + struct Dll *line; struct Dll *free; bool end_of_file; + unsigned char pc; uint16_t utf16hs; - unsigned allocated; pthread_mutex_t lock; - struct Keystroke pool[32]; + struct Keystroke pool[8]; }; static struct Keystrokes __keystroke; @@ -124,6 +127,11 @@ static textwindows void UnblockSignals(uint64_t mask) { atomic_store_explicit(&__get_tls()->tib_sigmask, mask, memory_order_release); } +static textwindows int RaiseSignal(int sig) { + __get_tls()->tib_sigpending |= 1ull << (sig - 1); + return 0; +} + static textwindows int GetVirtualKey(uint16_t vk, bool shift, bool ctrl) { for (int i = 0; i < ARRAYLEN(kVirtualKey); ++i) { if (kVirtualKey[i].vk == vk) { @@ -152,7 +160,7 @@ static textwindows int ProcessKeyEvent(const struct NtInputRecord *r, char *p) { return 0; } - // process virtual keys + // process arrow keys, function keys, etc. int n = 0; if (!c) { int w; @@ -184,7 +192,7 @@ static textwindows int ProcessKeyEvent(const struct NtInputRecord *r, char *p) { // enter sends \r in a raw terminals // make it a multics newline instead - if (c == '\r' && !(__ttymagic & kFdTtyNoCr2Nl)) { + if (c == '\r' && !(__ttyconf.magic & kTtyNoCr2Nl)) { c = '\n'; } @@ -200,25 +208,24 @@ static textwindows int ProcessKeyEvent(const struct NtInputRecord *r, char *p) { } // handle ctrl-c and ctrl-\, which tcsetattr() is able to remap - if (!(__ttymagic & kFdTtyNoIsigs)) { - if (c == __vintr && __vintr != _POSIX_VDISABLE) { - STRACE("encountered CTRL(%#c) c_cc[VINTR] will raise SIGINT", CTRL(c)); - __get_tls()->tib_sigpending |= 1ull << (SIGINT - 1); - return 0; - } else if (c == __vquit && __vquit != _POSIX_VDISABLE) { - STRACE("encountered CTRL(%#c) c_cc[VQUITR] will raise SIGQUIT", CTRL(c)); - __get_tls()->tib_sigpending |= 1ull << (SIGQUIT - 1); - return 0; + if (c && !(__ttyconf.magic & kTtyNoIsigs)) { + if (c == __ttyconf.vintr) { + return RaiseSignal(SIGINT); + } else if (c == __ttyconf.vquit) { + return RaiseSignal(SIGQUIT); } } - // handle ctrl-d the end of file keystroke - if (!(__ttymagic & kFdTtyUncanon)) { - if (c == __veof && __veof != _POSIX_VDISABLE) { - STRACE("encountered CTRL(%#c) c_cc[VEOF] closing console input", CTRL(c)); + // handle ctrl-d which generates end-of-file, unless pending line data + // is present, in which case we flush that without the newline instead + if (c && c == __ttyconf.veof && !(__ttyconf.magic & kTtyUncanon)) { + if (dll_is_empty(__keystroke.line)) { __keystroke.end_of_file = true; - return 0; + } else { + dll_make_last(&__keystroke.list, __keystroke.line); + __keystroke.line = 0; } + return 0; } // insert esc prefix when alt is held @@ -241,9 +248,9 @@ static textwindows int ProcessKeyEvent(const struct NtInputRecord *r, char *p) { // See o//examples/ttyinfo.com and o//tool/viz/life.com static textwindows int ProcessMouseEvent(const struct NtInputRecord *r, char *b) { - int e = 0; char *p = b; - uint32_t currentbs = __mousebuttons; + unsigned char e = 0; + uint32_t currentbs = __ttyconf.mousebs; uint32_t ev = r->Event.MouseEvent.dwEventFlags; uint32_t bs = r->Event.MouseEvent.dwButtonState; ev &= kNtMouseMoved | kNtMouseWheeled; @@ -254,7 +261,7 @@ static textwindows int ProcessMouseEvent(const struct NtInputRecord *r, (kNtShiftPressed | kNtLeftCtrlPressed | kNtRightCtrlPressed | kNtLeftAltPressed | kNtRightAltPressed))) { bool isup = ((int)r->Event.MouseEvent.dwButtonState >> 16) > 0; - if (__ttymagic & kFdTtyXtMouse) { + if (__ttyconf.magic & kTtyXtMouse) { e = isup ? 80 : 81; goto OutputXtermMouseEvent; } else { @@ -269,7 +276,7 @@ static textwindows int ProcessMouseEvent(const struct NtInputRecord *r, } } } - } else if ((bs || currentbs) && (__ttymagic & kFdTtyXtMouse)) { + } else if ((bs || currentbs) && (__ttyconf.magic & kTtyXtMouse)) { if (bs && (ev & kNtMouseMoved) && currentbs) { e |= 32; // dragging } @@ -282,30 +289,28 @@ static textwindows int ProcessMouseEvent(const struct NtInputRecord *r, *p++ = '<'; p = FormatInt32(p, e); *p++ = ';'; - p = FormatInt32(p, r->Event.MouseEvent.dwMousePosition.X + 1); + p = FormatInt32(p, (r->Event.MouseEvent.dwMousePosition.X + 1) & 0x7fff); *p++ = ';'; - p = FormatInt32(p, r->Event.MouseEvent.dwMousePosition.Y + 1); + p = FormatInt32(p, (r->Event.MouseEvent.dwMousePosition.Y + 1) & 0x7fff); if (!bs && currentbs) { *p++ = 'm'; // up } else { *p++ = 'M'; // down } - __mousebuttons = bs; + __ttyconf.mousebs = bs; } return p - b; } static textwindows int ConvertConsoleInputToAnsi(const struct NtInputRecord *r, - char p[hasatleast 32]) { + char p[hasatleast 23]) { switch (r->EventType) { case kNtKeyEvent: return ProcessKeyEvent(r, p); case kNtMouseEvent: return ProcessMouseEvent(r, p); case kNtWindowBufferSizeEvent: - STRACE("detected console resize will raise SIGWINCH"); - __get_tls()->tib_sigpending |= 1ull << (SIGWINCH - 1); - return 0; + return RaiseSignal(SIGWINCH); default: return 0; } @@ -315,8 +320,8 @@ static textwindows struct Keystroke *NewKeystroke(void) { struct Dll *e; struct Keystroke *k = 0; int i, n = ARRAYLEN(__keystroke.pool); - if (atomic_load_explicit(&__keystroke.allocated, memory_order_acquire) < n && - (i = atomic_fetch_add(&__keystroke.allocated, 1)) < n) { + if (atomic_load_explicit(&__keystroke.pc, memory_order_acquire) < n && + (i = atomic_fetch_add(&__keystroke.pc, 1)) < n) { k = __keystroke.pool + i; } else { if ((e = dll_first(__keystroke.free))) { @@ -339,41 +344,123 @@ static textwindows struct Keystroke *NewKeystroke(void) { return k; } -static textwindows void IngestConsoleInputRecord(struct NtInputRecord *r) { - int len; - struct Keystroke *k; - char buf[sizeof(k->buf)]; - if ((len = ConvertConsoleInputToAnsi(r, buf))) { - if ((k = NewKeystroke())) { - memcpy(k->buf, buf, sizeof(k->buf)); - k->buflen = len; - dll_make_last(&__keystroke.list, &k->elem); +static textwindows void WriteTty(struct Fd *f, const char *p, size_t n) { + int64_t hOutput; + uint32_t dwConsoleMode; + if (f->kind == kFdConsole) { + hOutput = f->extra; + } else if (g_fds.p[1].kind == kFdFile && + GetConsoleMode(g_fds.p[1].handle, &dwConsoleMode)) { + hOutput = g_fds.p[1].handle; + } else if (g_fds.p[2].kind == kFdFile && + GetConsoleMode(g_fds.p[2].handle, &dwConsoleMode)) { + hOutput = g_fds.p[2].handle; + } else { + hOutput = g_fds.p[1].handle; + } + WriteFile(hOutput, p, n, 0, 0); +} + +static textwindows bool IsCtl(int c) { + return isascii(c) && iscntrl(c) && c != '\n' && c != '\t'; +} + +static textwindows void WriteTtyCtl(struct Fd *f, const char *p, size_t n) { + size_t i; + for (i = 0; i < n; ++i) { + if (IsCtl(p[i])) { + char ctl[2]; + ctl[0] = '^'; + ctl[1] = p[i] ^ 0100; + WriteTty(f, ctl, 2); } else { - STRACE("ran out of memory to hold keystroke %#.*s", len, buf); + WriteTty(f, p + i, 1); } } } -static textwindows void IngestConsoleInput(int64_t handle) { +static textwindows void EchoTty(struct Fd *f, const char *p, size_t n) { + if (__ttyconf.magic & kTtyEchoRaw) { + WriteTty(f, p, n); + } else { + WriteTtyCtl(f, p, n); + } +} + +static textwindows void IngestConsoleInputRecord(struct Fd *f, + struct NtInputRecord *r) { + + // convert win32 console event into ansi + int len; + char buf[23]; + if (!(len = ConvertConsoleInputToAnsi(r, buf))) { + return; + } + + // handle backspace in canonical mode + if (len == 1 && buf[0] && // + (buf[0] & 255) == __ttyconf.verase && // + !(__ttyconf.magic & kTtyUncanon)) { + struct Dll *e; + if ((e = dll_last(__keystroke.line))) { + struct Keystroke *k = KEYSTROKE_CONTAINER(e); + dll_remove(&__keystroke.line, e); + dll_make_first(&__keystroke.free, e); + for (int i = k->buflen; i--;) { + if ((k->buf[i] & 0300) == 0200) continue; + WriteTty(f, "\b \b", 3); + if (!(__ttyconf.magic & kTtyEchoRaw) && IsCtl(k->buf[i])) { + WriteTty(f, "\b \b", 3); + } + } + } + return; + } + + // allocate an object to hold this keystroke + struct Keystroke *k; + if (!(k = NewKeystroke())) { + STRACE("ran out of memory to hold keystroke %#.*s", len, buf); + return; + } + memcpy(k->buf, buf, sizeof(k->buf)); + k->buflen = len; + + // echo input if it was successfully recorded + // assuming the win32 console isn't doing it already + if (!(__ttyconf.magic & kTtySilence)) { + EchoTty(f, buf, len); + } + + // save keystroke to appropriate list + if (__ttyconf.magic & kTtyUncanon) { + dll_make_last(&__keystroke.list, &k->elem); + } else { + dll_make_last(&__keystroke.line, &k->elem); + + // handle end-of-line in canonical mode + if (len == 1 && buf[0] && + ((buf[0] & 255) == '\n' || // + (buf[0] & 255) == __ttyconf.veol || // + (buf[0] & 255) == __ttyconf.veol2)) { + dll_make_last(&__keystroke.list, __keystroke.line); + __keystroke.line = 0; + return; + } + } +} + +static textwindows void IngestConsoleInput(struct Fd *f) { uint32_t i, n; struct NtInputRecord records[16]; if (!__keystroke.end_of_file) { do { - if (GetNumberOfConsoleInputEvents(handle, &n)) { - if (n) { - n = MIN(ARRAYLEN(records), n); - if (ReadConsoleInput(handle, records, n, &n)) { - for (i = 0; i < n && !__keystroke.end_of_file; ++i) { - IngestConsoleInputRecord(records + i); - } - } else { - STRACE("ReadConsoleInput failed w/ %d", GetLastError()); - __keystroke.end_of_file = true; - break; - } + if (ReadConsoleInput(f->handle, records, ARRAYLEN(records), &n)) { + for (i = 0; i < n && !__keystroke.end_of_file; ++i) { + IngestConsoleInputRecord(f, records + i); } } else { - STRACE("GetNumberOfConsoleInputRecords failed w/ %d", GetLastError()); + STRACE("ReadConsoleInput failed w/ %d", GetLastError()); __keystroke.end_of_file = true; break; } @@ -398,12 +485,12 @@ textwindows int FlushConsoleInputBytes(int64_t handle) { return rc; } -textwindows int CountConsoleInputBytes(int64_t handle) { +textwindows int CountConsoleInputBytes(struct Fd *f) { int count = 0; struct Dll *e; uint64_t m = BlockSignals(); LockKeystrokes(); - IngestConsoleInput(handle); + IngestConsoleInput(f); for (e = dll_first(__keystroke.list); e; e = dll_next(__keystroke.list, e)) { count += KEYSTROKE_CONTAINER(e)->buflen; } @@ -415,52 +502,45 @@ textwindows int CountConsoleInputBytes(int64_t handle) { return count; } -static textwindows bool DigestConsoleInput(void *data, size_t size, int *rc) { +static textwindows bool DigestConsoleInput(char *data, size_t size, int *rc) { + + // handle eof once available input is consumed + if (dll_is_empty(__keystroke.list) && __keystroke.end_of_file) { + *rc = 0; + return true; + } + + // copy keystroke(s) into user buffer + int toto = 0; struct Dll *e; - if ((e = dll_first(__keystroke.list))) { + while ((e = dll_first(__keystroke.list))) { struct Keystroke *k = KEYSTROKE_CONTAINER(e); uint32_t got = MIN(size, k->buflen); uint32_t remain = k->buflen - got; - if (got) memcpy(data, k->buf, got); - if (remain) memmove(k->buf, k->buf + got, remain); - if (!remain) { + if (got) { + memcpy(data, k->buf, got); + data += got; + size -= got; + toto += got; + } + if (remain) { + memmove(k->buf, k->buf + got, remain); + } else { dll_remove(&__keystroke.list, e); dll_make_first(&__keystroke.free, e); } k->buflen = remain; - if (got) { - *rc = got; - return true; + if ((__ttyconf.magic & kTtyUncanon) && toto >= __ttyconf.vmin) { + break; } - } else if (__keystroke.end_of_file) { - *rc = 0; - return true; } - return false; -} -// Manual CMD.EXE echoing for when !ICANON && ECHO is the case. -static textwindows void EchoTerminalInput(struct Fd *f, char *p, size_t n) { - int64_t hOutput; - if (f->kind == kFdConsole) { - hOutput = f->extra; + // return result + if (toto) { + *rc = toto; + return true; } else { - hOutput = g_fds.p[1].handle; - } - if (__ttymagic & kFdTtyEchoRaw) { - WriteFile(hOutput, p, n, 0, 0); - } else { - size_t i; - for (i = 0; i < n; ++i) { - if (isascii(p[i]) && iscntrl(p[i]) && p[i] != '\n' && p[i] != '\t') { - char ctl[2]; - ctl[0] = '^'; - ctl[1] = p[i] ^ 0100; - WriteFile(hOutput, ctl, 2, 0, 0); - } else { - WriteFile(hOutput, p + i, 1, 0, 0); - } - } + return false; } } @@ -472,26 +552,23 @@ static textwindows ssize_t ReadFromWindowsConsole(struct Fd *f, void *data, uint64_t m; m = BlockSignals(); LockKeystrokes(); - IngestConsoleInput(f->handle); + IngestConsoleInput(f); done = DigestConsoleInput(data, size, &rc); UnlockKeystrokes(); UnblockSignals(m); if (done) break; if (f->flags & O_NONBLOCK) return eagain(); uint32_t ms = __SIG_POLL_INTERVAL_MS; - if (__ttymagic & kFdTtyNoBlock) { - if (!__vtime) { + if (!__ttyconf.vmin) { + if (!__ttyconf.vtime) { return 0; } else { - ms = __vtime * 100; + ms = __ttyconf.vtime * 100; } } if (_check_interrupts(kSigOpRestartable)) return -1; if (__pause_thread(ms)) return -1; } - if (rc > 0 && (__ttymagic & kFdTtyEchoing)) { - EchoTerminalInput(f, data, size); - } return rc; } diff --git a/libc/calls/struct/fd.internal.h b/libc/calls/struct/fd.internal.h index 9677150c6..34542564c 100644 --- a/libc/calls/struct/fd.internal.h +++ b/libc/calls/struct/fd.internal.h @@ -19,14 +19,6 @@ COSMOPOLITAN_C_START_ #define kFdEpoll 7 #define kFdReserved 8 -#define kFdTtyEchoing 1 /* read()→write() (ECHO && !ICANON) */ -#define kFdTtyEchoRaw 2 /* don't ^X visualize control codes */ -#define kFdTtyUncanon 4 /* enables non-canonical (raw) mode */ -#define kFdTtyNoCr2Nl 8 /* don't map \r → \n (a.k.a !ICRNL) */ -#define kFdTtyNoIsigs 16 -#define kFdTtyNoBlock 32 -#define kFdTtyXtMouse 64 - struct Fd { char kind; bool eoftty; diff --git a/libc/calls/tcgetattr-nt.c b/libc/calls/tcgetattr-nt.c index 154d5b608..fff672e50 100644 --- a/libc/calls/tcgetattr-nt.c +++ b/libc/calls/tcgetattr-nt.c @@ -55,22 +55,7 @@ textwindows int tcgetattr_nt(int fd, struct termios *tio) { } bzero(tio, sizeof(*tio)); - - tio->c_cc[VMIN] = !(__ttymagic & kFdTtyNoBlock); - tio->c_cc[VEOF] = __veof; - tio->c_cc[VTIME] = __vtime; - tio->c_cc[VINTR] = __vintr; - tio->c_cc[VQUIT] = __vquit; - tio->c_cc[VERASE] = CTRL('?'); - tio->c_cc[VWERASE] = CTRL('W'); - tio->c_cc[VKILL] = CTRL('U'); - tio->c_cc[VMIN] = CTRL('A'); - tio->c_cc[VSTART] = _POSIX_VDISABLE; - tio->c_cc[VSTOP] = _POSIX_VDISABLE; - tio->c_cc[VSUSP] = _POSIX_VDISABLE; - tio->c_cc[VREPRINT] = CTRL('R'); - tio->c_cc[VDISCARD] = CTRL('O'); - tio->c_cc[VLNEXT] = CTRL('V'); + memcpy(tio->c_cc, __ttyconf.c_cc, NCCS); tio->c_iflag = IUTF8; tio->c_lflag = ECHOE; @@ -78,21 +63,24 @@ textwindows int tcgetattr_nt(int fd, struct termios *tio) { tio->_c_ispeed = B38400; tio->_c_ospeed = B38400; - if (inmode & kNtEnableLineInput) { + // kNtEnableLineInput and kNtEnableEchoInput only apply to programs + // that call ReadFile() or ReadConsole(). since we do not use them, + // the flags could serve the purpose of inter-process communication + if ((inmode & kNtEnableLineInput) || !(__ttyconf.magic & kTtyUncanon)) { tio->c_lflag |= ICANON; } // kNtEnableEchoInput only works with kNtEnableLineInput enabled. - if ((inmode & kNtEnableEchoInput) || (__ttymagic & kFdTtyEchoing)) { + if ((inmode & kNtEnableEchoInput) || !(__ttyconf.magic & kTtySilence)) { tio->c_lflag |= ECHO; } // The Windows console itself always echos control codes as ASCII. - if ((inmode & kNtEnableEchoInput) || !(__ttymagic & kFdTtyEchoRaw)) { + if ((inmode & kNtEnableEchoInput) || !(__ttyconf.magic & kTtyEchoRaw)) { tio->c_lflag |= ECHOCTL; } - if (!(__ttymagic & kFdTtyNoCr2Nl)) { + if (!(__ttyconf.magic & kTtyNoCr2Nl)) { tio->c_iflag |= ICRNL; } - if (!(__ttymagic & kFdTtyNoIsigs)) { + if (!(__ttyconf.magic & kTtyNoIsigs)) { tio->c_lflag |= ISIG; } if (inmode & kNtEnableProcessedInput) { diff --git a/libc/calls/tcsetattr-nt.c b/libc/calls/tcsetattr-nt.c index acba74e9e..60597ff9f 100644 --- a/libc/calls/tcsetattr-nt.c +++ b/libc/calls/tcsetattr-nt.c @@ -72,45 +72,34 @@ textwindows int tcsetattr_nt(int fd, int opt, const struct termios *tio) { inmode &= ~(kNtEnableLineInput | kNtEnableEchoInput | kNtEnableProcessedInput | kNtEnableVirtualTerminalInput); inmode |= kNtEnableWindowInput; - __ttymagic = 0; + __ttyconf.magic = 0; if (tio->c_lflag & ICANON) { inmode |= kNtEnableLineInput | kNtEnableProcessedInput | kNtEnableQuickEditMode; } else { inmode &= ~kNtEnableQuickEditMode; - __ttymagic |= kFdTtyUncanon; - if (!tio->c_cc[VMIN]) { - __ttymagic |= kFdTtyNoBlock; - } - __vtime = tio->c_cc[VTIME]; + __ttyconf.magic |= kTtyUncanon; } if (!(tio->c_iflag & ICRNL)) { - __ttymagic |= kFdTtyNoCr2Nl; + __ttyconf.magic |= kTtyNoCr2Nl; } if (!(tio->c_lflag & ECHOCTL)) { - __ttymagic |= kFdTtyEchoRaw; + __ttyconf.magic |= kTtyEchoRaw; } if (tio->c_lflag & ECHO) { // "kNtEnableEchoInput can be used only if the // kNtEnableLineInput mode is also enabled." -MSDN if (tio->c_lflag & ICANON) { inmode |= kNtEnableEchoInput; - } else { - // If ECHO is enabled in raw mode, then read(0) needs to - // magically write(1) to simulate echoing. This normally - // visualizes control codes, e.g. \r → ^M unless ECHOCTL - // hasn't been specified. - __ttymagic |= kFdTtyEchoing; } + } else { + __ttyconf.magic |= kTtySilence; } if (!(tio->c_lflag & ISIG)) { - __ttymagic |= kFdTtyNoIsigs; + __ttyconf.magic |= kTtyNoIsigs; } - __veof = tio->c_cc[VEOF]; - __vintr = tio->c_cc[VINTR]; - __vquit = tio->c_cc[VQUIT]; - if ((tio->c_lflag & ISIG) && // - tio->c_cc[VINTR] == CTRL('C')) { + memcpy(__ttyconf.c_cc, tio->c_cc, NCCS); + if ((tio->c_lflag & ISIG) && __ttyconf.vintr == CTRL('C')) { // allows ctrl-c to be delivered asynchronously via win32 inmode |= kNtEnableProcessedInput; } diff --git a/libc/calls/write-nt.c b/libc/calls/write-nt.c index 426a2036c..5f2ba43cf 100644 --- a/libc/calls/write-nt.c +++ b/libc/calls/write-nt.c @@ -135,11 +135,11 @@ static textwindows ssize_t sys_write_nt_impl(int fd, void *data, size_t size, } else { m |= IsMouseModeCommand(x); if (p[i] == 'h') { - __ttymagic |= kFdTtyXtMouse; + __ttyconf.magic |= kTtyXtMouse; cm2 |= kNtEnableMouseInput; cm2 &= kNtEnableQuickEditMode; // precludes mouse events } else if (p[i] == 'l') { - __ttymagic &= ~kFdTtyXtMouse; + __ttyconf.magic &= ~kTtyXtMouse; cm2 |= kNtEnableQuickEditMode; // disables mouse too } t = 0; diff --git a/libc/intrin/g_fds.c b/libc/intrin/g_fds.c index 2d26d3104..e531f585a 100644 --- a/libc/intrin/g_fds.c +++ b/libc/intrin/g_fds.c @@ -123,9 +123,6 @@ textstartup void __init_fds(int argc, char **argv, char **envp) { SetupWinStd(fds, 0, kNtStdInputHandle, sockset); SetupWinStd(fds, 1, kNtStdOutputHandle, sockset); SetupWinStd(fds, 2, kNtStdErrorHandle, sockset); - __veof = CTRL('D'); - __vintr = CTRL('C'); - __vquit = CTRL('\\'); } fds->p[1].flags = O_WRONLY | O_APPEND; fds->p[2].flags = O_WRONLY | O_APPEND; diff --git a/libc/intrin/kprintf.greg.c b/libc/intrin/kprintf.greg.c index 05d7d654f..3e1f6da00 100644 --- a/libc/intrin/kprintf.greg.c +++ b/libc/intrin/kprintf.greg.c @@ -800,7 +800,7 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt, // undocumented %r specifier // used for good carriage return // helps integrate loggers with repls - if (!__replstderr || __nocolor) { + if (!__ttyconf.replstderr || __nocolor) { break; } else { s = "\r\e[K"; diff --git a/libc/intrin/nomultics.c b/libc/intrin/nomultics.c index 55e497bf9..f169fc60e 100644 --- a/libc/intrin/nomultics.c +++ b/libc/intrin/nomultics.c @@ -16,13 +16,17 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/ttydefaults.h" #include "libc/intrin/nomultics.internal.h" -unsigned char __replmode; -unsigned char __replstderr; -unsigned char __ttymagic; -unsigned char __veof; -unsigned char __vintr; -unsigned char __vquit; -unsigned char __vtime; -unsigned char __mousebuttons; +struct TtyConf __ttyconf = { + .vmin = 1, + .veof = CTRL('D'), + .vintr = CTRL('C'), + .vquit = CTRL('\\'), + .verase = CTRL('?'), + .vwerase = CTRL('W'), + .vkill = CTRL('U'), + .vreprint = CTRL('R'), + .vlnext = CTRL('V'), +}; diff --git a/libc/intrin/nomultics.internal.h b/libc/intrin/nomultics.internal.h index 248cd3d45..9cd8d4595 100644 --- a/libc/intrin/nomultics.internal.h +++ b/libc/intrin/nomultics.internal.h @@ -1,18 +1,48 @@ -#ifndef COSMOPOLITAN_LIBC_INTRIN_NOMULTICS_INTERNAL_H_ -#define COSMOPOLITAN_LIBC_INTRIN_NOMULTICS_INTERNAL_H_ -#include "libc/calls/struct/timespec.h" +#ifndef COSMOPOLITAN_NOMULTICS_H_ +#define COSMOPOLITAN_NOMULTICS_H_ + +#define kTtySilence 1 /* do not relay read() into write() */ +#define kTtyEchoRaw 2 /* don't ^X visualize control codes */ +#define kTtyUncanon 4 /* enables non-canonical (raw) mode */ +#define kTtyNoCr2Nl 8 /* don't map \r → \n (a.k.a !ICRNL) */ +#define kTtyNoIsigs 16 /* don't auto-raise signals on keys */ +#define kTtyXtMouse 32 /* enables eXtreme Xterm mouse mode */ + #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ -extern unsigned char __replmode; -extern unsigned char __replstderr; -extern unsigned char __ttymagic; -extern unsigned char __veof; -extern unsigned char __vintr; -extern unsigned char __vquit; -extern unsigned char __vtime; -extern unsigned char __mousebuttons; +struct TtyConf { + unsigned char magic; + unsigned char mousebs; + unsigned char replmode; + unsigned char replstderr; + union { + unsigned char c_cc[20]; + struct { + unsigned char vline; + unsigned char vintr; /* SIGINT keystroke (isigs) */ + unsigned char vquit; /* SIGQUIT keystroke (isigs) */ + unsigned char verase; /* backspace keystroke (canon) */ + unsigned char vkill; /* kill line back keystroke (canon) */ + unsigned char veof; /* EOF keystroke (canon) */ + unsigned char vtime; /* vtime*100ms can control read delay */ + unsigned char vmin; /* use 0 for special non-blocking mode */ + unsigned char vswtc; + unsigned char vstart; + unsigned char vstop; + unsigned char vsusp; /* keystroke for SIGTSTP (isigs) */ + unsigned char veol; + unsigned char vreprint; /* keystroke to print unread line (canon) */ + unsigned char vdiscard; + unsigned char vwerase; /* keystroke for kill word back (canon) */ + unsigned char vlnext; /* print next keystroke as ascii (canon) */ + unsigned char veol2; + }; + }; +}; + +extern struct TtyConf __ttyconf; COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#endif /* COSMOPOLITAN_LIBC_INTRIN_NOMULTICS_INTERNAL_H_ */ +#endif /* COSMOPOLITAN_NOMULTICS_H_ */ diff --git a/libc/runtime/printargs.c b/libc/runtime/printargs.c index 60b4f4488..7a4c18e33 100644 --- a/libc/runtime/printargs.c +++ b/libc/runtime/printargs.c @@ -38,6 +38,7 @@ #include "libc/nexgen32e/kcpuids.h" #include "libc/nexgen32e/x86feature.h" #include "libc/nexgen32e/x86info.h" +#include "libc/nt/console.h" #include "libc/nt/enum/startf.h" #include "libc/nt/runtime.h" #include "libc/nt/startupinfo.h" @@ -651,13 +652,20 @@ textstartup void __printargs(const char *prologue) { PRINT(" ☼ %s = %ld", "hStdError", startinfo.hStdError); PRINT(""); + uint32_t cm; PRINT("STANDARD HANDLES"); PRINT(" ☼ %s = %ld", "GetStdHandle(kNtStdInputHandle)", GetStdHandle(kNtStdInputHandle)); + if (GetConsoleMode(GetStdHandle(kNtStdInputHandle), &cm)) + PRINT(" %s", DescribeNtConsoleInFlags(cm)); PRINT(" ☼ %s = %ld", "GetStdHandle(kNtStdOutputHandle)", GetStdHandle(kNtStdOutputHandle)); + if (GetConsoleMode(GetStdHandle(kNtStdOutputHandle), &cm)) + PRINT(" %s", DescribeNtConsoleOutFlags(cm)); PRINT(" ☼ %s = %ld", "GetStdHandle(kNtStdErrorHandle)", GetStdHandle(kNtStdErrorHandle)); + if (GetConsoleMode(GetStdHandle(kNtStdErrorHandle), &cm)) + PRINT(" %s", DescribeNtConsoleOutFlags(cm)); PRINT(""); PRINT("TEB"); diff --git a/libc/runtime/winmain.greg.c b/libc/runtime/winmain.greg.c index e06a6f000..7db5477a3 100644 --- a/libc/runtime/winmain.greg.c +++ b/libc/runtime/winmain.greg.c @@ -20,6 +20,7 @@ #include "libc/calls/internal.h" #include "libc/calls/syscall_support-nt.internal.h" #include "libc/intrin/bits.h" +#include "libc/intrin/nomultics.internal.h" #include "libc/intrin/weaken.h" #include "libc/limits.h" #include "libc/log/libfatal.internal.h" @@ -136,13 +137,14 @@ static abi wontreturn void WinInit(const char16_t *cmdline) { for (int i = 0; i <= 2; ++i) { uint32_t m; intptr_t h = __imp_GetStdHandle(kNtStdio[i]); - __imp_GetConsoleMode(h, &m); - if (!i) { - m |= kNtEnableMouseInput | kNtEnableWindowInput; - } else { - m |= kNtEnableVirtualTerminalProcessing; + if (__imp_GetConsoleMode(h, &m)) { + if (!i) { + m |= kNtEnableMouseInput | kNtEnableWindowInput; + } else { + m |= kNtEnableVirtualTerminalProcessing; + } + __imp_SetConsoleMode(h, m); } - __imp_SetConsoleMode(h, m); } } diff --git a/libc/stdio/fmt.c b/libc/stdio/fmt.c index 7e2d91bf0..d208a008f 100644 --- a/libc/stdio/fmt.c +++ b/libc/stdio/fmt.c @@ -1048,7 +1048,7 @@ int __fmt(void *fn, void *arg, const char *format, va_list va) { // undocumented %r specifier // used for good carriage return // helps integrate loggers with repls - if (!__replstderr) { + if (!__ttyconf.replstderr) { break; } else { p = "\r\e[K"; diff --git a/libc/sysv/consts.sh b/libc/sysv/consts.sh index f2d8ab620..d32003295 100755 --- a/libc/sysv/consts.sh +++ b/libc/sysv/consts.sh @@ -1275,23 +1275,23 @@ syscon termios FF1 0b1000000000000000 0b1000000000000000 0b000100000000000 # Teletypewriter Special Control Character Assignments # # group name GNU/Systemd GNU/Systemd (Aarch64) XNU's Not UNIX! MacOS (Arm64) FreeBSD OpenBSD NetBSD The New Technology Commentary -syscon termios VMIN 6+1 6+1 16 16 16 16 16 6 # termios.c_cc[VMIN]=𝑥 in non-canonical mode can be set to 0 for non-blocking reads, 1 for single character raw mode reads, or higher to buffer -syscon termios VTIME 5+1 5+1 17 17 17 17 17 5 # termios.c_cc[VTIME]=𝑥 sets non-canonical read timeout to 𝑥×𝟷𝟶𝟶ms which is needed when entering escape sequences manually with the escape key -syscon termios VINTR 0+1 0+1 8 8 8 8 8 0 # termios.c_cc[VINTR]=𝑥 -syscon termios VQUIT 1+1 1+1 9 9 9 9 9 1 # termios.c_cc[VQUIT]=𝑥 -syscon termios VERASE 2+1 2+1 3 3 3 3 3 2 # termios.c_cc[VERASE]=𝑥 -syscon termios VKILL 3+1 3+1 5 5 5 5 5 3 # termios.c_cc[VKILL]=𝑥 -syscon termios VEOF 4+1 4+1 0 0 0 0 0 4 # termios.c_cc[VEOF]=𝑥 -syscon termios VSWTC 7+1 7+1 0 0 0 0 0 7 # termios.c_cc[VSWTC]=𝑥 -syscon termios VSTART 8+1 8+1 12 12 12 12 12 8 # termios.c_cc[VSTART]=𝑥 -syscon termios VSTOP 9+1 9+1 13 13 13 13 13 9 # termios.c_cc[VSTOP]=𝑥 -syscon termios VSUSP 10+1 10+1 10 10 10 10 10 10 # termios.c_cc[VSUSP]=𝑥 defines suspend, i.e. Ctrl-Z (a.k.a. →, ^Z, SUB, 26, 032, 0x1A, ord('Z')^0b01000000); unix consensus -syscon termios VEOL 11+1 11+1 1 1 1 1 1 11 # termios.c_cc[VEOL]=𝑥 -syscon termios VREPRINT 12+1 12+1 6 6 6 6 6 12 # termios.c_cc[VREPRINT]=𝑥 -syscon termios VDISCARD 13+1 13+1 15 15 15 15 15 13 # termios.c_cc[VDISCARD]=𝑥 -syscon termios VWERASE 14+1 14+1 4 4 4 4 4 14 # termios.c_cc[VWERASE]=𝑥 -syscon termios VLNEXT 15+1 15+1 14 14 14 14 14 15 # termios.c_cc[VLNEXT]=𝑥 -syscon termios VEOL2 16+1 16+1 2 2 2 2 2 16 # termios.c_cc[VEOL2]=𝑥 +syscon termios VMIN 6+1 6+1 16 16 16 16 16 6+1 # termios.c_cc[VMIN]=𝑥 in non-canonical mode can be set to 0 for non-blocking reads, 1 for single character raw mode reads, or higher to buffer +syscon termios VTIME 5+1 5+1 17 17 17 17 17 5+1 # termios.c_cc[VTIME]=𝑥 sets non-canonical read timeout to 𝑥×𝟷𝟶𝟶ms which is needed when entering escape sequences manually with the escape key +syscon termios VINTR 0+1 0+1 8 8 8 8 8 0+1 # termios.c_cc[VINTR]=𝑥 +syscon termios VQUIT 1+1 1+1 9 9 9 9 9 1+1 # termios.c_cc[VQUIT]=𝑥 +syscon termios VERASE 2+1 2+1 3 3 3 3 3 2+1 # termios.c_cc[VERASE]=𝑥 +syscon termios VKILL 3+1 3+1 5 5 5 5 5 3+1 # termios.c_cc[VKILL]=𝑥 +syscon termios VEOF 4+1 4+1 0 0 0 0 0 4+1 # termios.c_cc[VEOF]=𝑥 +syscon termios VSWTC 7+1 7+1 0 0 0 0 0 7+1 # termios.c_cc[VSWTC]=𝑥 +syscon termios VSTART 8+1 8+1 12 12 12 12 12 8+1 # termios.c_cc[VSTART]=𝑥 +syscon termios VSTOP 9+1 9+1 13 13 13 13 13 9+1 # termios.c_cc[VSTOP]=𝑥 +syscon termios VSUSP 10+1 10+1 10 10 10 10 10 10+1 # termios.c_cc[VSUSP]=𝑥 defines suspend, i.e. Ctrl-Z (a.k.a. →, ^Z, SUB, 26, 032, 0x1A, ord('Z')^0b01000000); unix consensus +syscon termios VEOL 11+1 11+1 1 1 1 1 1 11+1 # termios.c_cc[VEOL]=𝑥 +syscon termios VREPRINT 12+1 12+1 6 6 6 6 6 12+1 # termios.c_cc[VREPRINT]=𝑥 +syscon termios VDISCARD 13+1 13+1 15 15 15 15 15 13+1 # termios.c_cc[VDISCARD]=𝑥 +syscon termios VWERASE 14+1 14+1 4 4 4 4 4 14+1 # termios.c_cc[VWERASE]=𝑥 +syscon termios VLNEXT 15+1 15+1 14 14 14 14 14 15+1 # termios.c_cc[VLNEXT]=𝑥 +syscon termios VEOL2 16+1 16+1 2 2 2 2 2 16+1 # termios.c_cc[VEOL2]=𝑥 syscon termios _POSIX_VDISABLE 0 0 255 255 255 255 255 0 # termios.c_cc tombstone value # tcflush() magic numbers diff --git a/libc/sysv/consts/VDISCARD.S b/libc/sysv/consts/VDISCARD.S index 6d936e841..07671b49e 100644 --- a/libc/sysv/consts/VDISCARD.S +++ b/libc/sysv/consts/VDISCARD.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon termios,VDISCARD,13+1,13+1,15,15,15,15,15,13 +.syscon termios,VDISCARD,13+1,13+1,15,15,15,15,15,13+1 diff --git a/libc/sysv/consts/VEOF.S b/libc/sysv/consts/VEOF.S index caa506591..c07d5ade0 100644 --- a/libc/sysv/consts/VEOF.S +++ b/libc/sysv/consts/VEOF.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon termios,VEOF,4+1,4+1,0,0,0,0,0,4 +.syscon termios,VEOF,4+1,4+1,0,0,0,0,0,4+1 diff --git a/libc/sysv/consts/VEOL.S b/libc/sysv/consts/VEOL.S index c6e5b847a..cf2d2131a 100644 --- a/libc/sysv/consts/VEOL.S +++ b/libc/sysv/consts/VEOL.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon termios,VEOL,11+1,11+1,1,1,1,1,1,11 +.syscon termios,VEOL,11+1,11+1,1,1,1,1,1,11+1 diff --git a/libc/sysv/consts/VEOL2.S b/libc/sysv/consts/VEOL2.S index a64ca629c..e82a6a60e 100644 --- a/libc/sysv/consts/VEOL2.S +++ b/libc/sysv/consts/VEOL2.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon termios,VEOL2,16+1,16+1,2,2,2,2,2,16 +.syscon termios,VEOL2,16+1,16+1,2,2,2,2,2,16+1 diff --git a/libc/sysv/consts/VERASE.S b/libc/sysv/consts/VERASE.S index 8ab3a92b9..e4d994d81 100644 --- a/libc/sysv/consts/VERASE.S +++ b/libc/sysv/consts/VERASE.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon termios,VERASE,2+1,2+1,3,3,3,3,3,2 +.syscon termios,VERASE,2+1,2+1,3,3,3,3,3,2+1 diff --git a/libc/sysv/consts/VINTR.S b/libc/sysv/consts/VINTR.S index 1981d46ac..0c9e3ded3 100644 --- a/libc/sysv/consts/VINTR.S +++ b/libc/sysv/consts/VINTR.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon termios,VINTR,0+1,0+1,8,8,8,8,8,0 +.syscon termios,VINTR,0+1,0+1,8,8,8,8,8,0+1 diff --git a/libc/sysv/consts/VKILL.S b/libc/sysv/consts/VKILL.S index a0b1fabd5..b47cacde2 100644 --- a/libc/sysv/consts/VKILL.S +++ b/libc/sysv/consts/VKILL.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon termios,VKILL,3+1,3+1,5,5,5,5,5,3 +.syscon termios,VKILL,3+1,3+1,5,5,5,5,5,3+1 diff --git a/libc/sysv/consts/VLNEXT.S b/libc/sysv/consts/VLNEXT.S index 6ad7d46ff..7853a5960 100644 --- a/libc/sysv/consts/VLNEXT.S +++ b/libc/sysv/consts/VLNEXT.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon termios,VLNEXT,15+1,15+1,14,14,14,14,14,15 +.syscon termios,VLNEXT,15+1,15+1,14,14,14,14,14,15+1 diff --git a/libc/sysv/consts/VMIN.S b/libc/sysv/consts/VMIN.S index a76e7e83e..c70ffd19d 100644 --- a/libc/sysv/consts/VMIN.S +++ b/libc/sysv/consts/VMIN.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon termios,VMIN,6+1,6+1,16,16,16,16,16,6 +.syscon termios,VMIN,6+1,6+1,16,16,16,16,16,6+1 diff --git a/libc/sysv/consts/VQUIT.S b/libc/sysv/consts/VQUIT.S index 9298f5905..06cf571d1 100644 --- a/libc/sysv/consts/VQUIT.S +++ b/libc/sysv/consts/VQUIT.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon termios,VQUIT,1+1,1+1,9,9,9,9,9,1 +.syscon termios,VQUIT,1+1,1+1,9,9,9,9,9,1+1 diff --git a/libc/sysv/consts/VREPRINT.S b/libc/sysv/consts/VREPRINT.S index 2fbf88a13..ceafce671 100644 --- a/libc/sysv/consts/VREPRINT.S +++ b/libc/sysv/consts/VREPRINT.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon termios,VREPRINT,12+1,12+1,6,6,6,6,6,12 +.syscon termios,VREPRINT,12+1,12+1,6,6,6,6,6,12+1 diff --git a/libc/sysv/consts/VSTART.S b/libc/sysv/consts/VSTART.S index 644ca33ac..621b998ce 100644 --- a/libc/sysv/consts/VSTART.S +++ b/libc/sysv/consts/VSTART.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon termios,VSTART,8+1,8+1,12,12,12,12,12,8 +.syscon termios,VSTART,8+1,8+1,12,12,12,12,12,8+1 diff --git a/libc/sysv/consts/VSTOP.S b/libc/sysv/consts/VSTOP.S index 95d20ebbe..7e2ec27cf 100644 --- a/libc/sysv/consts/VSTOP.S +++ b/libc/sysv/consts/VSTOP.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon termios,VSTOP,9+1,9+1,13,13,13,13,13,9 +.syscon termios,VSTOP,9+1,9+1,13,13,13,13,13,9+1 diff --git a/libc/sysv/consts/VSUSP.S b/libc/sysv/consts/VSUSP.S index f4c0c8793..937da1a44 100644 --- a/libc/sysv/consts/VSUSP.S +++ b/libc/sysv/consts/VSUSP.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon termios,VSUSP,10+1,10+1,10,10,10,10,10,10 +.syscon termios,VSUSP,10+1,10+1,10,10,10,10,10,10+1 diff --git a/libc/sysv/consts/VSWTC.S b/libc/sysv/consts/VSWTC.S index 4196944cd..9e4ab0b01 100644 --- a/libc/sysv/consts/VSWTC.S +++ b/libc/sysv/consts/VSWTC.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon termios,VSWTC,7+1,7+1,0,0,0,0,0,7 +.syscon termios,VSWTC,7+1,7+1,0,0,0,0,0,7+1 diff --git a/libc/sysv/consts/VTIME.S b/libc/sysv/consts/VTIME.S index a45ef23a5..f8b36c23f 100644 --- a/libc/sysv/consts/VTIME.S +++ b/libc/sysv/consts/VTIME.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon termios,VTIME,5+1,5+1,17,17,17,17,17,5 +.syscon termios,VTIME,5+1,5+1,17,17,17,17,17,5+1 diff --git a/libc/sysv/consts/VWERASE.S b/libc/sysv/consts/VWERASE.S index 076b75b26..3446ac979 100644 --- a/libc/sysv/consts/VWERASE.S +++ b/libc/sysv/consts/VWERASE.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon termios,VWERASE,14+1,14+1,4,4,4,4,4,14 +.syscon termios,VWERASE,14+1,14+1,4,4,4,4,4,14+1 diff --git a/third_party/linenoise/linenoise.c b/third_party/linenoise/linenoise.c index f579dd7e4..1f66e8dcc 100644 --- a/third_party/linenoise/linenoise.c +++ b/third_party/linenoise/linenoise.c @@ -2485,13 +2485,13 @@ char *linenoise(const char *prompt) { if (linenoiseFallback(prompt, &res)) return res; fflush(stdout); fflush(stdout); - rm = __replmode; - rs = __replstderr; - __replmode = true; - if (isatty(2)) __replstderr = true; + rm = __ttyconf.replmode; + rs = __ttyconf.replstderr; + __ttyconf.replmode = true; + if (isatty(2)) __ttyconf.replstderr = true; res = linenoiseRaw(prompt, fileno(stdin), fileno(stdout)); - __replstderr = rs; - __replmode = rm; + __ttyconf.replstderr = rs; + __ttyconf.replmode = rm; return res; } diff --git a/third_party/lua/lrepl.c b/third_party/lua/lrepl.c index 3ec453164..89d9659b8 100644 --- a/third_party/lua/lrepl.c +++ b/third_party/lua/lrepl.c @@ -347,8 +347,10 @@ void lua_initrepl(lua_State *L) { } lua_repl_linenoise = linenoiseBegin(prompt, 0, 1); lua_pop(L, 1); /* remove prompt */ - __replmode = true; - if (isatty(2)) __replstderr = true; + __ttyconf.replmode = true; + if (isatty(2)) { + __ttyconf.replstderr = true; + } } lua_repl_unlock(); } @@ -356,7 +358,7 @@ void lua_initrepl(lua_State *L) { void lua_freerepl(void) { lua_repl_lock(); - __replmode = false; + __ttyconf.replmode = false; linenoiseEnd(lua_repl_linenoise); free(g_historypath); lua_repl_unlock(); diff --git a/tool/net/redbean.c b/tool/net/redbean.c index c1529689e..c716d350f 100644 --- a/tool/net/redbean.c +++ b/tool/net/redbean.c @@ -2614,14 +2614,14 @@ static int LuaCallWithYield(lua_State *L) { // the second set of headers is not going to be sent struct sigaction sa, saold; lua_State *co = lua_newthread(L); - if (__replmode) { + if (__ttyconf.replmode) { sa.sa_flags = SA_RESETHAND; sa.sa_handler = OnLuaServerPageCtrlc; sigemptyset(&sa.sa_mask); sigaction(SIGINT, &sa, &saold); } status = LuaCallWithTrace(L, 0, 0, co); - if (__replmode) { + if (__ttyconf.replmode) { sigaction(SIGINT, &saold, 0); } if (status == LUA_YIELD) { @@ -7002,7 +7002,7 @@ static int HandlePoll(int ms) { } } #ifndef STATIC - } else if (__replmode) { + } else if (__ttyconf.replmode) { // handle refresh repl line rc = HandleReadline(); if (rc < 0) return rc;