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 :-)
This commit is contained in:
Justine Tunney 2023-10-03 22:34:45 -07:00
parent 4825737509
commit f26a280cda
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
36 changed files with 320 additions and 231 deletions

View file

@ -27,7 +27,7 @@ void __printfds(void);
uint32_t sys_getuid_nt(void); uint32_t sys_getuid_nt(void);
int __pause_thread(uint32_t); int __pause_thread(uint32_t);
int IsWindowsExecutable(int64_t); int IsWindowsExecutable(int64_t);
int CountConsoleInputBytes(int64_t); int CountConsoleInputBytes(struct Fd *);
int FlushConsoleInputBytes(int64_t); int FlushConsoleInputBytes(int64_t);
forceinline int64_t __getfdhandleactual(int fd) { forceinline int64_t __getfdhandleactual(int fd) {

View file

@ -114,7 +114,7 @@ static int ioctl_fionread(int fd, uint32_t *arg) {
return __winerr(); return __winerr();
} }
} else if (GetConsoleMode(handle, &cm)) { } else if (GetConsoleMode(handle, &cm)) {
int bytes = CountConsoleInputBytes(handle); int bytes = CountConsoleInputBytes(g_fds.p + fd);
return MAX(0, bytes); return MAX(0, bytes);
} else { } else {
return eopnotsupp(); return eopnotsupp();

View file

@ -155,7 +155,7 @@ textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint32_t *ms,
pipefds[i].revents |= POLLERR; pipefds[i].revents |= POLLERR;
} }
} else if (GetConsoleMode(pipefds[i].handle, &cm)) { } 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; pipefds[i].revents |= POLLIN;
} }
} else { } else {

View file

@ -26,12 +26,14 @@
#include "libc/fmt/itoa.h" #include "libc/fmt/itoa.h"
#include "libc/intrin/atomic.h" #include "libc/intrin/atomic.h"
#include "libc/intrin/dll.h" #include "libc/intrin/dll.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/nomultics.internal.h" #include "libc/intrin/nomultics.internal.h"
#include "libc/intrin/strace.internal.h" #include "libc/intrin/strace.internal.h"
#include "libc/intrin/weaken.h" #include "libc/intrin/weaken.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/nt/console.h" #include "libc/nt/console.h"
#include "libc/nt/enum/consolemodeflags.h"
#include "libc/nt/enum/filetype.h" #include "libc/nt/enum/filetype.h"
#include "libc/nt/enum/vk.h" #include "libc/nt/enum/vk.h"
#include "libc/nt/enum/wait.h" #include "libc/nt/enum/wait.h"
@ -91,19 +93,20 @@ static const struct {
#define KEYSTROKE_CONTAINER(e) DLL_CONTAINER(struct Keystroke, elem, e) #define KEYSTROKE_CONTAINER(e) DLL_CONTAINER(struct Keystroke, elem, e)
struct Keystroke { struct Keystroke {
char buf[32]; char buf[23];
unsigned buflen; unsigned char buflen;
struct Dll elem; struct Dll elem;
}; };
struct Keystrokes { struct Keystrokes {
struct Dll *list; struct Dll *list;
struct Dll *line;
struct Dll *free; struct Dll *free;
bool end_of_file; bool end_of_file;
unsigned char pc;
uint16_t utf16hs; uint16_t utf16hs;
unsigned allocated;
pthread_mutex_t lock; pthread_mutex_t lock;
struct Keystroke pool[32]; struct Keystroke pool[8];
}; };
static struct Keystrokes __keystroke; 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); 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) { static textwindows int GetVirtualKey(uint16_t vk, bool shift, bool ctrl) {
for (int i = 0; i < ARRAYLEN(kVirtualKey); ++i) { for (int i = 0; i < ARRAYLEN(kVirtualKey); ++i) {
if (kVirtualKey[i].vk == vk) { if (kVirtualKey[i].vk == vk) {
@ -152,7 +160,7 @@ static textwindows int ProcessKeyEvent(const struct NtInputRecord *r, char *p) {
return 0; return 0;
} }
// process virtual keys // process arrow keys, function keys, etc.
int n = 0; int n = 0;
if (!c) { if (!c) {
int w; int w;
@ -184,7 +192,7 @@ static textwindows int ProcessKeyEvent(const struct NtInputRecord *r, char *p) {
// enter sends \r in a raw terminals // enter sends \r in a raw terminals
// make it a multics newline instead // make it a multics newline instead
if (c == '\r' && !(__ttymagic & kFdTtyNoCr2Nl)) { if (c == '\r' && !(__ttyconf.magic & kTtyNoCr2Nl)) {
c = '\n'; 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 // handle ctrl-c and ctrl-\, which tcsetattr() is able to remap
if (!(__ttymagic & kFdTtyNoIsigs)) { if (c && !(__ttyconf.magic & kTtyNoIsigs)) {
if (c == __vintr && __vintr != _POSIX_VDISABLE) { if (c == __ttyconf.vintr) {
STRACE("encountered CTRL(%#c) c_cc[VINTR] will raise SIGINT", CTRL(c)); return RaiseSignal(SIGINT);
__get_tls()->tib_sigpending |= 1ull << (SIGINT - 1); } else if (c == __ttyconf.vquit) {
return 0; return RaiseSignal(SIGQUIT);
} 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;
} }
} }
// handle ctrl-d the end of file keystroke // handle ctrl-d which generates end-of-file, unless pending line data
if (!(__ttymagic & kFdTtyUncanon)) { // is present, in which case we flush that without the newline instead
if (c == __veof && __veof != _POSIX_VDISABLE) { if (c && c == __ttyconf.veof && !(__ttyconf.magic & kTtyUncanon)) {
STRACE("encountered CTRL(%#c) c_cc[VEOF] closing console input", CTRL(c)); if (dll_is_empty(__keystroke.line)) {
__keystroke.end_of_file = true; __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 // 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 // See o//examples/ttyinfo.com and o//tool/viz/life.com
static textwindows int ProcessMouseEvent(const struct NtInputRecord *r, static textwindows int ProcessMouseEvent(const struct NtInputRecord *r,
char *b) { char *b) {
int e = 0;
char *p = b; 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 ev = r->Event.MouseEvent.dwEventFlags;
uint32_t bs = r->Event.MouseEvent.dwButtonState; uint32_t bs = r->Event.MouseEvent.dwButtonState;
ev &= kNtMouseMoved | kNtMouseWheeled; ev &= kNtMouseMoved | kNtMouseWheeled;
@ -254,7 +261,7 @@ static textwindows int ProcessMouseEvent(const struct NtInputRecord *r,
(kNtShiftPressed | kNtLeftCtrlPressed | kNtRightCtrlPressed | (kNtShiftPressed | kNtLeftCtrlPressed | kNtRightCtrlPressed |
kNtLeftAltPressed | kNtRightAltPressed))) { kNtLeftAltPressed | kNtRightAltPressed))) {
bool isup = ((int)r->Event.MouseEvent.dwButtonState >> 16) > 0; bool isup = ((int)r->Event.MouseEvent.dwButtonState >> 16) > 0;
if (__ttymagic & kFdTtyXtMouse) { if (__ttyconf.magic & kTtyXtMouse) {
e = isup ? 80 : 81; e = isup ? 80 : 81;
goto OutputXtermMouseEvent; goto OutputXtermMouseEvent;
} else { } 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) { if (bs && (ev & kNtMouseMoved) && currentbs) {
e |= 32; // dragging e |= 32; // dragging
} }
@ -282,30 +289,28 @@ static textwindows int ProcessMouseEvent(const struct NtInputRecord *r,
*p++ = '<'; *p++ = '<';
p = FormatInt32(p, e); p = FormatInt32(p, e);
*p++ = ';'; *p++ = ';';
p = FormatInt32(p, r->Event.MouseEvent.dwMousePosition.X + 1); p = FormatInt32(p, (r->Event.MouseEvent.dwMousePosition.X + 1) & 0x7fff);
*p++ = ';'; *p++ = ';';
p = FormatInt32(p, r->Event.MouseEvent.dwMousePosition.Y + 1); p = FormatInt32(p, (r->Event.MouseEvent.dwMousePosition.Y + 1) & 0x7fff);
if (!bs && currentbs) { if (!bs && currentbs) {
*p++ = 'm'; // up *p++ = 'm'; // up
} else { } else {
*p++ = 'M'; // down *p++ = 'M'; // down
} }
__mousebuttons = bs; __ttyconf.mousebs = bs;
} }
return p - b; return p - b;
} }
static textwindows int ConvertConsoleInputToAnsi(const struct NtInputRecord *r, static textwindows int ConvertConsoleInputToAnsi(const struct NtInputRecord *r,
char p[hasatleast 32]) { char p[hasatleast 23]) {
switch (r->EventType) { switch (r->EventType) {
case kNtKeyEvent: case kNtKeyEvent:
return ProcessKeyEvent(r, p); return ProcessKeyEvent(r, p);
case kNtMouseEvent: case kNtMouseEvent:
return ProcessMouseEvent(r, p); return ProcessMouseEvent(r, p);
case kNtWindowBufferSizeEvent: case kNtWindowBufferSizeEvent:
STRACE("detected console resize will raise SIGWINCH"); return RaiseSignal(SIGWINCH);
__get_tls()->tib_sigpending |= 1ull << (SIGWINCH - 1);
return 0;
default: default:
return 0; return 0;
} }
@ -315,8 +320,8 @@ static textwindows struct Keystroke *NewKeystroke(void) {
struct Dll *e; struct Dll *e;
struct Keystroke *k = 0; struct Keystroke *k = 0;
int i, n = ARRAYLEN(__keystroke.pool); int i, n = ARRAYLEN(__keystroke.pool);
if (atomic_load_explicit(&__keystroke.allocated, memory_order_acquire) < n && if (atomic_load_explicit(&__keystroke.pc, memory_order_acquire) < n &&
(i = atomic_fetch_add(&__keystroke.allocated, 1)) < n) { (i = atomic_fetch_add(&__keystroke.pc, 1)) < n) {
k = __keystroke.pool + i; k = __keystroke.pool + i;
} else { } else {
if ((e = dll_first(__keystroke.free))) { if ((e = dll_first(__keystroke.free))) {
@ -339,41 +344,123 @@ static textwindows struct Keystroke *NewKeystroke(void) {
return k; return k;
} }
static textwindows void IngestConsoleInputRecord(struct NtInputRecord *r) { static textwindows void WriteTty(struct Fd *f, const char *p, size_t n) {
int len; int64_t hOutput;
struct Keystroke *k; uint32_t dwConsoleMode;
char buf[sizeof(k->buf)]; if (f->kind == kFdConsole) {
if ((len = ConvertConsoleInputToAnsi(r, buf))) { hOutput = f->extra;
if ((k = NewKeystroke())) { } else if (g_fds.p[1].kind == kFdFile &&
memcpy(k->buf, buf, sizeof(k->buf)); GetConsoleMode(g_fds.p[1].handle, &dwConsoleMode)) {
k->buflen = len; hOutput = g_fds.p[1].handle;
dll_make_last(&__keystroke.list, &k->elem); } 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 { } 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; uint32_t i, n;
struct NtInputRecord records[16]; struct NtInputRecord records[16];
if (!__keystroke.end_of_file) { if (!__keystroke.end_of_file) {
do { do {
if (GetNumberOfConsoleInputEvents(handle, &n)) { if (ReadConsoleInput(f->handle, records, ARRAYLEN(records), &n)) {
if (n) { for (i = 0; i < n && !__keystroke.end_of_file; ++i) {
n = MIN(ARRAYLEN(records), n); IngestConsoleInputRecord(f, records + i);
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;
}
} }
} else { } else {
STRACE("GetNumberOfConsoleInputRecords failed w/ %d", GetLastError()); STRACE("ReadConsoleInput failed w/ %d", GetLastError());
__keystroke.end_of_file = true; __keystroke.end_of_file = true;
break; break;
} }
@ -398,12 +485,12 @@ textwindows int FlushConsoleInputBytes(int64_t handle) {
return rc; return rc;
} }
textwindows int CountConsoleInputBytes(int64_t handle) { textwindows int CountConsoleInputBytes(struct Fd *f) {
int count = 0; int count = 0;
struct Dll *e; struct Dll *e;
uint64_t m = BlockSignals(); uint64_t m = BlockSignals();
LockKeystrokes(); LockKeystrokes();
IngestConsoleInput(handle); IngestConsoleInput(f);
for (e = dll_first(__keystroke.list); e; e = dll_next(__keystroke.list, e)) { for (e = dll_first(__keystroke.list); e; e = dll_next(__keystroke.list, e)) {
count += KEYSTROKE_CONTAINER(e)->buflen; count += KEYSTROKE_CONTAINER(e)->buflen;
} }
@ -415,52 +502,45 @@ textwindows int CountConsoleInputBytes(int64_t handle) {
return count; 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; struct Dll *e;
if ((e = dll_first(__keystroke.list))) { while ((e = dll_first(__keystroke.list))) {
struct Keystroke *k = KEYSTROKE_CONTAINER(e); struct Keystroke *k = KEYSTROKE_CONTAINER(e);
uint32_t got = MIN(size, k->buflen); uint32_t got = MIN(size, k->buflen);
uint32_t remain = k->buflen - got; uint32_t remain = k->buflen - got;
if (got) memcpy(data, k->buf, got); if (got) {
if (remain) memmove(k->buf, k->buf + got, remain); memcpy(data, k->buf, got);
if (!remain) { data += got;
size -= got;
toto += got;
}
if (remain) {
memmove(k->buf, k->buf + got, remain);
} else {
dll_remove(&__keystroke.list, e); dll_remove(&__keystroke.list, e);
dll_make_first(&__keystroke.free, e); dll_make_first(&__keystroke.free, e);
} }
k->buflen = remain; k->buflen = remain;
if (got) { if ((__ttyconf.magic & kTtyUncanon) && toto >= __ttyconf.vmin) {
*rc = got; break;
return true;
} }
} else if (__keystroke.end_of_file) {
*rc = 0;
return true;
} }
return false;
}
// Manual CMD.EXE echoing for when !ICANON && ECHO is the case. // return result
static textwindows void EchoTerminalInput(struct Fd *f, char *p, size_t n) { if (toto) {
int64_t hOutput; *rc = toto;
if (f->kind == kFdConsole) { return true;
hOutput = f->extra;
} else { } else {
hOutput = g_fds.p[1].handle; return false;
}
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);
}
}
} }
} }
@ -472,26 +552,23 @@ static textwindows ssize_t ReadFromWindowsConsole(struct Fd *f, void *data,
uint64_t m; uint64_t m;
m = BlockSignals(); m = BlockSignals();
LockKeystrokes(); LockKeystrokes();
IngestConsoleInput(f->handle); IngestConsoleInput(f);
done = DigestConsoleInput(data, size, &rc); done = DigestConsoleInput(data, size, &rc);
UnlockKeystrokes(); UnlockKeystrokes();
UnblockSignals(m); UnblockSignals(m);
if (done) break; if (done) break;
if (f->flags & O_NONBLOCK) return eagain(); if (f->flags & O_NONBLOCK) return eagain();
uint32_t ms = __SIG_POLL_INTERVAL_MS; uint32_t ms = __SIG_POLL_INTERVAL_MS;
if (__ttymagic & kFdTtyNoBlock) { if (!__ttyconf.vmin) {
if (!__vtime) { if (!__ttyconf.vtime) {
return 0; return 0;
} else { } else {
ms = __vtime * 100; ms = __ttyconf.vtime * 100;
} }
} }
if (_check_interrupts(kSigOpRestartable)) return -1; if (_check_interrupts(kSigOpRestartable)) return -1;
if (__pause_thread(ms)) return -1; if (__pause_thread(ms)) return -1;
} }
if (rc > 0 && (__ttymagic & kFdTtyEchoing)) {
EchoTerminalInput(f, data, size);
}
return rc; return rc;
} }

View file

@ -19,14 +19,6 @@ COSMOPOLITAN_C_START_
#define kFdEpoll 7 #define kFdEpoll 7
#define kFdReserved 8 #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 { struct Fd {
char kind; char kind;
bool eoftty; bool eoftty;

View file

@ -55,22 +55,7 @@ textwindows int tcgetattr_nt(int fd, struct termios *tio) {
} }
bzero(tio, sizeof(*tio)); bzero(tio, sizeof(*tio));
memcpy(tio->c_cc, __ttyconf.c_cc, NCCS);
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');
tio->c_iflag = IUTF8; tio->c_iflag = IUTF8;
tio->c_lflag = ECHOE; tio->c_lflag = ECHOE;
@ -78,21 +63,24 @@ textwindows int tcgetattr_nt(int fd, struct termios *tio) {
tio->_c_ispeed = B38400; tio->_c_ispeed = B38400;
tio->_c_ospeed = 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; tio->c_lflag |= ICANON;
} }
// kNtEnableEchoInput only works with kNtEnableLineInput enabled. // kNtEnableEchoInput only works with kNtEnableLineInput enabled.
if ((inmode & kNtEnableEchoInput) || (__ttymagic & kFdTtyEchoing)) { if ((inmode & kNtEnableEchoInput) || !(__ttyconf.magic & kTtySilence)) {
tio->c_lflag |= ECHO; tio->c_lflag |= ECHO;
} }
// The Windows console itself always echos control codes as ASCII. // 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; tio->c_lflag |= ECHOCTL;
} }
if (!(__ttymagic & kFdTtyNoCr2Nl)) { if (!(__ttyconf.magic & kTtyNoCr2Nl)) {
tio->c_iflag |= ICRNL; tio->c_iflag |= ICRNL;
} }
if (!(__ttymagic & kFdTtyNoIsigs)) { if (!(__ttyconf.magic & kTtyNoIsigs)) {
tio->c_lflag |= ISIG; tio->c_lflag |= ISIG;
} }
if (inmode & kNtEnableProcessedInput) { if (inmode & kNtEnableProcessedInput) {

View file

@ -72,45 +72,34 @@ textwindows int tcsetattr_nt(int fd, int opt, const struct termios *tio) {
inmode &= ~(kNtEnableLineInput | kNtEnableEchoInput | inmode &= ~(kNtEnableLineInput | kNtEnableEchoInput |
kNtEnableProcessedInput | kNtEnableVirtualTerminalInput); kNtEnableProcessedInput | kNtEnableVirtualTerminalInput);
inmode |= kNtEnableWindowInput; inmode |= kNtEnableWindowInput;
__ttymagic = 0; __ttyconf.magic = 0;
if (tio->c_lflag & ICANON) { if (tio->c_lflag & ICANON) {
inmode |= inmode |=
kNtEnableLineInput | kNtEnableProcessedInput | kNtEnableQuickEditMode; kNtEnableLineInput | kNtEnableProcessedInput | kNtEnableQuickEditMode;
} else { } else {
inmode &= ~kNtEnableQuickEditMode; inmode &= ~kNtEnableQuickEditMode;
__ttymagic |= kFdTtyUncanon; __ttyconf.magic |= kTtyUncanon;
if (!tio->c_cc[VMIN]) {
__ttymagic |= kFdTtyNoBlock;
}
__vtime = tio->c_cc[VTIME];
} }
if (!(tio->c_iflag & ICRNL)) { if (!(tio->c_iflag & ICRNL)) {
__ttymagic |= kFdTtyNoCr2Nl; __ttyconf.magic |= kTtyNoCr2Nl;
} }
if (!(tio->c_lflag & ECHOCTL)) { if (!(tio->c_lflag & ECHOCTL)) {
__ttymagic |= kFdTtyEchoRaw; __ttyconf.magic |= kTtyEchoRaw;
} }
if (tio->c_lflag & ECHO) { if (tio->c_lflag & ECHO) {
// "kNtEnableEchoInput can be used only if the // "kNtEnableEchoInput can be used only if the
// kNtEnableLineInput mode is also enabled." -MSDN // kNtEnableLineInput mode is also enabled." -MSDN
if (tio->c_lflag & ICANON) { if (tio->c_lflag & ICANON) {
inmode |= kNtEnableEchoInput; 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)) { if (!(tio->c_lflag & ISIG)) {
__ttymagic |= kFdTtyNoIsigs; __ttyconf.magic |= kTtyNoIsigs;
} }
__veof = tio->c_cc[VEOF]; memcpy(__ttyconf.c_cc, tio->c_cc, NCCS);
__vintr = tio->c_cc[VINTR]; if ((tio->c_lflag & ISIG) && __ttyconf.vintr == CTRL('C')) {
__vquit = tio->c_cc[VQUIT];
if ((tio->c_lflag & ISIG) && //
tio->c_cc[VINTR] == CTRL('C')) {
// allows ctrl-c to be delivered asynchronously via win32 // allows ctrl-c to be delivered asynchronously via win32
inmode |= kNtEnableProcessedInput; inmode |= kNtEnableProcessedInput;
} }

View file

@ -135,11 +135,11 @@ static textwindows ssize_t sys_write_nt_impl(int fd, void *data, size_t size,
} else { } else {
m |= IsMouseModeCommand(x); m |= IsMouseModeCommand(x);
if (p[i] == 'h') { if (p[i] == 'h') {
__ttymagic |= kFdTtyXtMouse; __ttyconf.magic |= kTtyXtMouse;
cm2 |= kNtEnableMouseInput; cm2 |= kNtEnableMouseInput;
cm2 &= kNtEnableQuickEditMode; // precludes mouse events cm2 &= kNtEnableQuickEditMode; // precludes mouse events
} else if (p[i] == 'l') { } else if (p[i] == 'l') {
__ttymagic &= ~kFdTtyXtMouse; __ttyconf.magic &= ~kTtyXtMouse;
cm2 |= kNtEnableQuickEditMode; // disables mouse too cm2 |= kNtEnableQuickEditMode; // disables mouse too
} }
t = 0; t = 0;

View file

@ -123,9 +123,6 @@ textstartup void __init_fds(int argc, char **argv, char **envp) {
SetupWinStd(fds, 0, kNtStdInputHandle, sockset); SetupWinStd(fds, 0, kNtStdInputHandle, sockset);
SetupWinStd(fds, 1, kNtStdOutputHandle, sockset); SetupWinStd(fds, 1, kNtStdOutputHandle, sockset);
SetupWinStd(fds, 2, kNtStdErrorHandle, sockset); SetupWinStd(fds, 2, kNtStdErrorHandle, sockset);
__veof = CTRL('D');
__vintr = CTRL('C');
__vquit = CTRL('\\');
} }
fds->p[1].flags = O_WRONLY | O_APPEND; fds->p[1].flags = O_WRONLY | O_APPEND;
fds->p[2].flags = O_WRONLY | O_APPEND; fds->p[2].flags = O_WRONLY | O_APPEND;

View file

@ -800,7 +800,7 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt,
// undocumented %r specifier // undocumented %r specifier
// used for good carriage return // used for good carriage return
// helps integrate loggers with repls // helps integrate loggers with repls
if (!__replstderr || __nocolor) { if (!__ttyconf.replstderr || __nocolor) {
break; break;
} else { } else {
s = "\r\e[K"; s = "\r\e[K";

View file

@ -16,13 +16,17 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/ttydefaults.h"
#include "libc/intrin/nomultics.internal.h" #include "libc/intrin/nomultics.internal.h"
unsigned char __replmode; struct TtyConf __ttyconf = {
unsigned char __replstderr; .vmin = 1,
unsigned char __ttymagic; .veof = CTRL('D'),
unsigned char __veof; .vintr = CTRL('C'),
unsigned char __vintr; .vquit = CTRL('\\'),
unsigned char __vquit; .verase = CTRL('?'),
unsigned char __vtime; .vwerase = CTRL('W'),
unsigned char __mousebuttons; .vkill = CTRL('U'),
.vreprint = CTRL('R'),
.vlnext = CTRL('V'),
};

View file

@ -1,18 +1,48 @@
#ifndef COSMOPOLITAN_LIBC_INTRIN_NOMULTICS_INTERNAL_H_ #ifndef COSMOPOLITAN_NOMULTICS_H_
#define COSMOPOLITAN_LIBC_INTRIN_NOMULTICS_INTERNAL_H_ #define COSMOPOLITAN_NOMULTICS_H_
#include "libc/calls/struct/timespec.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) #if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
extern unsigned char __replmode; struct TtyConf {
extern unsigned char __replstderr; unsigned char magic;
extern unsigned char __ttymagic; unsigned char mousebs;
extern unsigned char __veof; unsigned char replmode;
extern unsigned char __vintr; unsigned char replstderr;
extern unsigned char __vquit; union {
extern unsigned char __vtime; unsigned char c_cc[20];
extern unsigned char __mousebuttons; 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_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_INTRIN_NOMULTICS_INTERNAL_H_ */ #endif /* COSMOPOLITAN_NOMULTICS_H_ */

View file

@ -38,6 +38,7 @@
#include "libc/nexgen32e/kcpuids.h" #include "libc/nexgen32e/kcpuids.h"
#include "libc/nexgen32e/x86feature.h" #include "libc/nexgen32e/x86feature.h"
#include "libc/nexgen32e/x86info.h" #include "libc/nexgen32e/x86info.h"
#include "libc/nt/console.h"
#include "libc/nt/enum/startf.h" #include "libc/nt/enum/startf.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/nt/startupinfo.h" #include "libc/nt/startupinfo.h"
@ -651,13 +652,20 @@ textstartup void __printargs(const char *prologue) {
PRINT(" ☼ %s = %ld", "hStdError", startinfo.hStdError); PRINT(" ☼ %s = %ld", "hStdError", startinfo.hStdError);
PRINT(""); PRINT("");
uint32_t cm;
PRINT("STANDARD HANDLES"); PRINT("STANDARD HANDLES");
PRINT(" ☼ %s = %ld", "GetStdHandle(kNtStdInputHandle)", PRINT(" ☼ %s = %ld", "GetStdHandle(kNtStdInputHandle)",
GetStdHandle(kNtStdInputHandle)); GetStdHandle(kNtStdInputHandle));
if (GetConsoleMode(GetStdHandle(kNtStdInputHandle), &cm))
PRINT(" %s", DescribeNtConsoleInFlags(cm));
PRINT(" ☼ %s = %ld", "GetStdHandle(kNtStdOutputHandle)", PRINT(" ☼ %s = %ld", "GetStdHandle(kNtStdOutputHandle)",
GetStdHandle(kNtStdOutputHandle)); GetStdHandle(kNtStdOutputHandle));
if (GetConsoleMode(GetStdHandle(kNtStdOutputHandle), &cm))
PRINT(" %s", DescribeNtConsoleOutFlags(cm));
PRINT(" ☼ %s = %ld", "GetStdHandle(kNtStdErrorHandle)", PRINT(" ☼ %s = %ld", "GetStdHandle(kNtStdErrorHandle)",
GetStdHandle(kNtStdErrorHandle)); GetStdHandle(kNtStdErrorHandle));
if (GetConsoleMode(GetStdHandle(kNtStdErrorHandle), &cm))
PRINT(" %s", DescribeNtConsoleOutFlags(cm));
PRINT(""); PRINT("");
PRINT("TEB"); PRINT("TEB");

View file

@ -20,6 +20,7 @@
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/syscall_support-nt.internal.h" #include "libc/calls/syscall_support-nt.internal.h"
#include "libc/intrin/bits.h" #include "libc/intrin/bits.h"
#include "libc/intrin/nomultics.internal.h"
#include "libc/intrin/weaken.h" #include "libc/intrin/weaken.h"
#include "libc/limits.h" #include "libc/limits.h"
#include "libc/log/libfatal.internal.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) { for (int i = 0; i <= 2; ++i) {
uint32_t m; uint32_t m;
intptr_t h = __imp_GetStdHandle(kNtStdio[i]); intptr_t h = __imp_GetStdHandle(kNtStdio[i]);
__imp_GetConsoleMode(h, &m); if (__imp_GetConsoleMode(h, &m)) {
if (!i) { if (!i) {
m |= kNtEnableMouseInput | kNtEnableWindowInput; m |= kNtEnableMouseInput | kNtEnableWindowInput;
} else { } else {
m |= kNtEnableVirtualTerminalProcessing; m |= kNtEnableVirtualTerminalProcessing;
}
__imp_SetConsoleMode(h, m);
} }
__imp_SetConsoleMode(h, m);
} }
} }

View file

@ -1048,7 +1048,7 @@ int __fmt(void *fn, void *arg, const char *format, va_list va) {
// undocumented %r specifier // undocumented %r specifier
// used for good carriage return // used for good carriage return
// helps integrate loggers with repls // helps integrate loggers with repls
if (!__replstderr) { if (!__ttyconf.replstderr) {
break; break;
} else { } else {
p = "\r\e[K"; p = "\r\e[K";

View file

@ -1275,23 +1275,23 @@ syscon termios FF1 0b1000000000000000 0b1000000000000000 0b000100000000000
# Teletypewriter Special Control Character Assignments # 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 # 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 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 # 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 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 # termios.c_cc[VINTR]=𝑥 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 # termios.c_cc[VQUIT]=𝑥 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 # termios.c_cc[VERASE]=𝑥 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 # termios.c_cc[VKILL]=𝑥 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 # termios.c_cc[VEOF]=𝑥 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 # termios.c_cc[VSWTC]=𝑥 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 # termios.c_cc[VSTART]=𝑥 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 # termios.c_cc[VSTOP]=𝑥 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 # 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 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 # termios.c_cc[VEOL]=𝑥 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 # termios.c_cc[VREPRINT]=𝑥 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 # termios.c_cc[VDISCARD]=𝑥 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 # termios.c_cc[VWERASE]=𝑥 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 # termios.c_cc[VLNEXT]=𝑥 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 # termios.c_cc[VEOL2]=𝑥 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 syscon termios _POSIX_VDISABLE 0 0 255 255 255 255 255 0 # termios.c_cc tombstone value
# tcflush() magic numbers # tcflush() magic numbers

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h" #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

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h" #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

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h" #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

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h" #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

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h" #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

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h" #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

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h" #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

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h" #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

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h" #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

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h" #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

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h" #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

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h" #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

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h" #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

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h" #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

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h" #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

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h" #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

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h" #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

View file

@ -2485,13 +2485,13 @@ char *linenoise(const char *prompt) {
if (linenoiseFallback(prompt, &res)) return res; if (linenoiseFallback(prompt, &res)) return res;
fflush(stdout); fflush(stdout);
fflush(stdout); fflush(stdout);
rm = __replmode; rm = __ttyconf.replmode;
rs = __replstderr; rs = __ttyconf.replstderr;
__replmode = true; __ttyconf.replmode = true;
if (isatty(2)) __replstderr = true; if (isatty(2)) __ttyconf.replstderr = true;
res = linenoiseRaw(prompt, fileno(stdin), fileno(stdout)); res = linenoiseRaw(prompt, fileno(stdin), fileno(stdout));
__replstderr = rs; __ttyconf.replstderr = rs;
__replmode = rm; __ttyconf.replmode = rm;
return res; return res;
} }

View file

@ -347,8 +347,10 @@ void lua_initrepl(lua_State *L) {
} }
lua_repl_linenoise = linenoiseBegin(prompt, 0, 1); lua_repl_linenoise = linenoiseBegin(prompt, 0, 1);
lua_pop(L, 1); /* remove prompt */ lua_pop(L, 1); /* remove prompt */
__replmode = true; __ttyconf.replmode = true;
if (isatty(2)) __replstderr = true; if (isatty(2)) {
__ttyconf.replstderr = true;
}
} }
lua_repl_unlock(); lua_repl_unlock();
} }
@ -356,7 +358,7 @@ void lua_initrepl(lua_State *L) {
void lua_freerepl(void) { void lua_freerepl(void) {
lua_repl_lock(); lua_repl_lock();
__replmode = false; __ttyconf.replmode = false;
linenoiseEnd(lua_repl_linenoise); linenoiseEnd(lua_repl_linenoise);
free(g_historypath); free(g_historypath);
lua_repl_unlock(); lua_repl_unlock();

View file

@ -2614,14 +2614,14 @@ static int LuaCallWithYield(lua_State *L) {
// the second set of headers is not going to be sent // the second set of headers is not going to be sent
struct sigaction sa, saold; struct sigaction sa, saold;
lua_State *co = lua_newthread(L); lua_State *co = lua_newthread(L);
if (__replmode) { if (__ttyconf.replmode) {
sa.sa_flags = SA_RESETHAND; sa.sa_flags = SA_RESETHAND;
sa.sa_handler = OnLuaServerPageCtrlc; sa.sa_handler = OnLuaServerPageCtrlc;
sigemptyset(&sa.sa_mask); sigemptyset(&sa.sa_mask);
sigaction(SIGINT, &sa, &saold); sigaction(SIGINT, &sa, &saold);
} }
status = LuaCallWithTrace(L, 0, 0, co); status = LuaCallWithTrace(L, 0, 0, co);
if (__replmode) { if (__ttyconf.replmode) {
sigaction(SIGINT, &saold, 0); sigaction(SIGINT, &saold, 0);
} }
if (status == LUA_YIELD) { if (status == LUA_YIELD) {
@ -7002,7 +7002,7 @@ static int HandlePoll(int ms) {
} }
} }
#ifndef STATIC #ifndef STATIC
} else if (__replmode) { } else if (__ttyconf.replmode) {
// handle refresh repl line // handle refresh repl line
rc = HandleReadline(); rc = HandleReadline();
if (rc < 0) return rc; if (rc < 0) return rc;