mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-12 09:17:53 +00:00
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:
parent
4825737509
commit
f26a280cda
36 changed files with 320 additions and 231 deletions
|
@ -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) {
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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";
|
||||||
|
|
|
@ -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'),
|
||||||
|
};
|
||||||
|
|
|
@ -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_ */
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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";
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
12
third_party/linenoise/linenoise.c
vendored
12
third_party/linenoise/linenoise.c
vendored
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
8
third_party/lua/lrepl.c
vendored
8
third_party/lua/lrepl.c
vendored
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue