mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-04-21 14:24:43 +00:00
Fix some additional Windows TTY issues
This commit is contained in:
parent
f26a280cda
commit
1694edf85c
12 changed files with 107 additions and 43 deletions
|
@ -58,7 +58,16 @@ int main(int argc, char *argv[]) {
|
||||||
// posix guarantees atomic i/o if you use pipe_buf sized buffers
|
// posix guarantees atomic i/o if you use pipe_buf sized buffers
|
||||||
// that way we don't need to worry about things like looping and
|
// that way we don't need to worry about things like looping and
|
||||||
// we can also be assured that multiple actors wont have tearing
|
// we can also be assured that multiple actors wont have tearing
|
||||||
char buf[4];
|
// 512 is the minimum permissible value for PIPE_BUF for all the
|
||||||
|
// platforms. when stdin is a terminal there are more guarantees
|
||||||
|
// about exactly how many bytes will be returned. in ICANON mode
|
||||||
|
// which is the default you can count on it returning one single
|
||||||
|
// line, including its \n (or VEOL, or VEOL2) per read. if using
|
||||||
|
// non-canonical raw mode, then a single logical keystroke shall
|
||||||
|
// be returned per read, so long as has VMIN characters or more,
|
||||||
|
// and the default VMIN is 1. you can also set VMIN w/ tcsetattr
|
||||||
|
// to 0 for a special kind of non-blocking mode.
|
||||||
|
char buf[512];
|
||||||
|
|
||||||
// read data from standard input
|
// read data from standard input
|
||||||
//
|
//
|
||||||
|
@ -109,7 +118,7 @@ int main(int argc, char *argv[]) {
|
||||||
// it's usually safe to ignore the return code of write. the
|
// it's usually safe to ignore the return code of write. the
|
||||||
// operating system will send SIGPIPE if there's any problem
|
// operating system will send SIGPIPE if there's any problem
|
||||||
// which kills the process by default
|
// which kills the process by default
|
||||||
|
write(1, "got: ", 5);
|
||||||
write(1, buf, got);
|
write(1, buf, got);
|
||||||
write(1, "\n", 1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,7 +92,7 @@ int EnableRawMode(void) {
|
||||||
perror("tcsetattr");
|
perror("tcsetattr");
|
||||||
}
|
}
|
||||||
|
|
||||||
WRITE(outfd, ENABLE_MOUSE_TRACKING);
|
/* WRITE(outfd, ENABLE_MOUSE_TRACKING); */
|
||||||
/* WRITE(outfd, ENABLE_SAFE_PASTE); */
|
/* WRITE(outfd, ENABLE_SAFE_PASTE); */
|
||||||
/* WRITE(outfd, PROBE_DISPLAY_SIZE); */
|
/* WRITE(outfd, PROBE_DISPLAY_SIZE); */
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -71,6 +71,10 @@ textwindows int sys_dup_nt(int oldfd, int newfd, int flags, int start) {
|
||||||
if (g_fds.p[oldfd].kind == kFdSocket && _weaken(_dupsockfd)) {
|
if (g_fds.p[oldfd].kind == kFdSocket && _weaken(_dupsockfd)) {
|
||||||
g_fds.p[newfd].extra =
|
g_fds.p[newfd].extra =
|
||||||
(intptr_t)_weaken(_dupsockfd)((struct SockFd *)g_fds.p[oldfd].extra);
|
(intptr_t)_weaken(_dupsockfd)((struct SockFd *)g_fds.p[oldfd].extra);
|
||||||
|
} else if (g_fds.p[oldfd].kind == kFdConsole) {
|
||||||
|
unassert(DuplicateHandle(proc, g_fds.p[oldfd].extra, proc,
|
||||||
|
&g_fds.p[newfd].extra, 0, false,
|
||||||
|
kNtDuplicateSameAccess));
|
||||||
} else {
|
} else {
|
||||||
g_fds.p[newfd].extra = g_fds.p[oldfd].extra;
|
g_fds.p[newfd].extra = g_fds.p[oldfd].extra;
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,7 +115,8 @@ static int ioctl_fionread(int fd, uint32_t *arg) {
|
||||||
}
|
}
|
||||||
} else if (GetConsoleMode(handle, &cm)) {
|
} else if (GetConsoleMode(handle, &cm)) {
|
||||||
int bytes = CountConsoleInputBytes(g_fds.p + fd);
|
int bytes = CountConsoleInputBytes(g_fds.p + fd);
|
||||||
return MAX(0, bytes);
|
*arg = MAX(0, bytes);
|
||||||
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
return eopnotsupp();
|
return eopnotsupp();
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,12 +20,16 @@
|
||||||
#include "libc/calls/syscall_support-nt.internal.h"
|
#include "libc/calls/syscall_support-nt.internal.h"
|
||||||
#include "libc/intrin/strace.internal.h"
|
#include "libc/intrin/strace.internal.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
|
#include "libc/nt/enum/fileflagandattributes.h"
|
||||||
#include "libc/nt/files.h"
|
#include "libc/nt/files.h"
|
||||||
|
#include "libc/nt/thunk/msabi.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/sysv/consts/at.h"
|
#include "libc/sysv/consts/at.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
int __mkntpathat(int dirfd, const char *path, int flags,
|
__msabi extern typeof(GetFileAttributes) *const __imp_GetFileAttributesW;
|
||||||
|
|
||||||
|
static int __mkntpathat_impl(int dirfd, const char *path, int flags,
|
||||||
char16_t file[hasatleast PATH_MAX]) {
|
char16_t file[hasatleast PATH_MAX]) {
|
||||||
char16_t dir[PATH_MAX];
|
char16_t dir[PATH_MAX];
|
||||||
uint32_t dirlen, filelen;
|
uint32_t dirlen, filelen;
|
||||||
|
@ -49,3 +53,30 @@ int __mkntpathat(int dirfd, const char *path, int flags,
|
||||||
return filelen;
|
return filelen;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int __mkntpathat(int dirfd, const char *path, int flags,
|
||||||
|
char16_t file[hasatleast PATH_MAX]) {
|
||||||
|
|
||||||
|
// convert the path.
|
||||||
|
int len;
|
||||||
|
if ((len = __mkntpathat_impl(dirfd, path, flags, file)) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if path ends with a slash, then we need to manually do what linux
|
||||||
|
// does and check to make sure it's a directory, and return ENOTDIR,
|
||||||
|
// since WIN32 will reject the path with EINVAL if we don't do this.
|
||||||
|
if (len && file[len - 1] == '\\') {
|
||||||
|
uint32_t fattr;
|
||||||
|
if (len > 1 && !(len == 3 && file[1] == ':')) {
|
||||||
|
file[--len] = 0;
|
||||||
|
}
|
||||||
|
if ((fattr = __imp_GetFileAttributesW(file)) != -1u &&
|
||||||
|
!(fattr & kNtFileAttributeReparsePoint) &&
|
||||||
|
!(fattr & kNtFileAttributeDirectory)) {
|
||||||
|
return enotdir();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
|
@ -53,16 +53,6 @@ static textwindows int64_t sys_open_nt_impl(int dirfd, const char *path,
|
||||||
return kNtInvalidHandleValue;
|
return kNtInvalidHandleValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// strip trailing slash
|
|
||||||
size_t n = strlen16(path16);
|
|
||||||
if (n > 1 && path16[n - 1] == '\\') {
|
|
||||||
// path denormalization only goes so far. when a trailing / or /.
|
|
||||||
// exists the kernel interprets that as having O_DIRECTORY intent
|
|
||||||
// furthermore, windows will throw an error on unc paths with it!
|
|
||||||
flags |= O_DIRECTORY;
|
|
||||||
path16[--n] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// implement no follow flag
|
// implement no follow flag
|
||||||
// you can't open symlinks; use readlink
|
// you can't open symlinks; use readlink
|
||||||
// this flag only applies to the final path component
|
// this flag only applies to the final path component
|
||||||
|
|
|
@ -106,7 +106,7 @@ struct Keystrokes {
|
||||||
unsigned char pc;
|
unsigned char pc;
|
||||||
uint16_t utf16hs;
|
uint16_t utf16hs;
|
||||||
pthread_mutex_t lock;
|
pthread_mutex_t lock;
|
||||||
struct Keystroke pool[8];
|
struct Keystroke pool[512];
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct Keystrokes __keystroke;
|
static struct Keystrokes __keystroke;
|
||||||
|
@ -203,7 +203,7 @@ static textwindows int ProcessKeyEvent(const struct NtInputRecord *r, char *p) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// make it possible to distinguish ctrl-h (^H) from backspace (^?)
|
// make it possible to distinguish ctrl-h (^H) from backspace (^?)
|
||||||
if (c == kNtVkBack) {
|
if (c == kNtVkBack && !(cks & (kNtLeftCtrlPressed | kNtRightCtrlPressed))) {
|
||||||
c = 0177;
|
c = 0177;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -387,6 +387,25 @@ static textwindows void EchoTty(struct Fd *f, const char *p, size_t n) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static textwindows bool EraseKeystroke(struct Fd *f) {
|
||||||
|
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 true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static textwindows void IngestConsoleInputRecord(struct Fd *f,
|
static textwindows void IngestConsoleInputRecord(struct Fd *f,
|
||||||
struct NtInputRecord *r) {
|
struct NtInputRecord *r) {
|
||||||
|
|
||||||
|
@ -401,18 +420,15 @@ static textwindows void IngestConsoleInputRecord(struct Fd *f,
|
||||||
if (len == 1 && buf[0] && //
|
if (len == 1 && buf[0] && //
|
||||||
(buf[0] & 255) == __ttyconf.verase && //
|
(buf[0] & 255) == __ttyconf.verase && //
|
||||||
!(__ttyconf.magic & kTtyUncanon)) {
|
!(__ttyconf.magic & kTtyUncanon)) {
|
||||||
struct Dll *e;
|
EraseKeystroke(f);
|
||||||
if ((e = dll_last(__keystroke.line))) {
|
return;
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// handle kill in canonical mode
|
||||||
|
if (len == 1 && buf[0] && //
|
||||||
|
(buf[0] & 255) == __ttyconf.vkill && //
|
||||||
|
!(__ttyconf.magic & kTtyUncanon)) {
|
||||||
|
while (EraseKeystroke(f)) {
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -455,7 +471,10 @@ static textwindows void IngestConsoleInput(struct Fd *f) {
|
||||||
struct NtInputRecord records[16];
|
struct NtInputRecord records[16];
|
||||||
if (!__keystroke.end_of_file) {
|
if (!__keystroke.end_of_file) {
|
||||||
do {
|
do {
|
||||||
if (ReadConsoleInput(f->handle, records, ARRAYLEN(records), &n)) {
|
if (GetNumberOfConsoleInputEvents(f->handle, &n)) {
|
||||||
|
if (n) {
|
||||||
|
n = MIN(ARRAYLEN(records), n);
|
||||||
|
if (ReadConsoleInput(f->handle, records, n, &n)) {
|
||||||
for (i = 0; i < n && !__keystroke.end_of_file; ++i) {
|
for (i = 0; i < n && !__keystroke.end_of_file; ++i) {
|
||||||
IngestConsoleInputRecord(f, records + i);
|
IngestConsoleInputRecord(f, records + i);
|
||||||
}
|
}
|
||||||
|
@ -464,6 +483,12 @@ static textwindows void IngestConsoleInput(struct Fd *f) {
|
||||||
__keystroke.end_of_file = true;
|
__keystroke.end_of_file = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
STRACE("GetNumberOfConsoleInputRecords failed w/ %d", GetLastError());
|
||||||
|
__keystroke.end_of_file = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
} while (n == ARRAYLEN(records));
|
} while (n == ARRAYLEN(records));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -513,7 +538,7 @@ static textwindows bool DigestConsoleInput(char *data, size_t size, int *rc) {
|
||||||
// copy keystroke(s) into user buffer
|
// copy keystroke(s) into user buffer
|
||||||
int toto = 0;
|
int toto = 0;
|
||||||
struct Dll *e;
|
struct Dll *e;
|
||||||
while ((e = dll_first(__keystroke.list))) {
|
while (size && (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;
|
||||||
|
@ -567,7 +592,12 @@ static textwindows ssize_t ReadFromWindowsConsole(struct Fd *f, void *data,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (_check_interrupts(kSigOpRestartable)) return -1;
|
if (_check_interrupts(kSigOpRestartable)) return -1;
|
||||||
if (__pause_thread(ms)) return -1;
|
if (__pause_thread(ms)) {
|
||||||
|
if (errno == EAGAIN) {
|
||||||
|
errno = EINTR; // TODO(jart): Why do we need it?
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,6 @@
|
||||||
#include "libc/fmt/itoa.h"
|
#include "libc/fmt/itoa.h"
|
||||||
#include "libc/intrin/atomic.h"
|
#include "libc/intrin/atomic.h"
|
||||||
#include "libc/intrin/describebacktrace.internal.h"
|
#include "libc/intrin/describebacktrace.internal.h"
|
||||||
#include "libc/intrin/kprintf.h"
|
|
||||||
#include "libc/intrin/popcnt.h"
|
#include "libc/intrin/popcnt.h"
|
||||||
#include "libc/intrin/strace.internal.h"
|
#include "libc/intrin/strace.internal.h"
|
||||||
#include "libc/intrin/weaken.h"
|
#include "libc/intrin/weaken.h"
|
||||||
|
|
|
@ -74,8 +74,7 @@ textwindows int tcsetattr_nt(int fd, int opt, const struct termios *tio) {
|
||||||
inmode |= kNtEnableWindowInput;
|
inmode |= kNtEnableWindowInput;
|
||||||
__ttyconf.magic = 0;
|
__ttyconf.magic = 0;
|
||||||
if (tio->c_lflag & ICANON) {
|
if (tio->c_lflag & ICANON) {
|
||||||
inmode |=
|
inmode |= kNtEnableLineInput | kNtEnableQuickEditMode;
|
||||||
kNtEnableLineInput | kNtEnableProcessedInput | kNtEnableQuickEditMode;
|
|
||||||
} else {
|
} else {
|
||||||
inmode &= ~kNtEnableQuickEditMode;
|
inmode &= ~kNtEnableQuickEditMode;
|
||||||
__ttyconf.magic |= kTtyUncanon;
|
__ttyconf.magic |= kTtyUncanon;
|
||||||
|
@ -101,7 +100,8 @@ textwindows int tcsetattr_nt(int fd, int opt, const struct termios *tio) {
|
||||||
memcpy(__ttyconf.c_cc, tio->c_cc, NCCS);
|
memcpy(__ttyconf.c_cc, tio->c_cc, NCCS);
|
||||||
if ((tio->c_lflag & ISIG) && __ttyconf.vintr == CTRL('C')) {
|
if ((tio->c_lflag & ISIG) && __ttyconf.vintr == CTRL('C')) {
|
||||||
// allows ctrl-c to be delivered asynchronously via win32
|
// allows ctrl-c to be delivered asynchronously via win32
|
||||||
inmode |= kNtEnableProcessedInput;
|
// TODO(jart): Fix up sig.c more.
|
||||||
|
// inmode |= kNtEnableProcessedInput;
|
||||||
}
|
}
|
||||||
ok = SetConsoleMode(hInput, inmode);
|
ok = SetConsoleMode(hInput, inmode);
|
||||||
(void)ok;
|
(void)ok;
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
#include "libc/intrin/likely.h"
|
#include "libc/intrin/likely.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
|
||||||
#define _NTTRACE 0 /* not configurable w/ flag yet */
|
#define _NTTRACE 1 /* not configurable w/ flag yet */
|
||||||
#define _POLLTRACE 0 /* not configurable w/ flag yet */
|
#define _POLLTRACE 0 /* not configurable w/ flag yet */
|
||||||
#define _DATATRACE 1 /* not configurable w/ flag yet */
|
#define _DATATRACE 1 /* not configurable w/ flag yet */
|
||||||
#define _LOCKTRACE 0 /* not configurable w/ flag yet */
|
#define _LOCKTRACE 0 /* not configurable w/ flag yet */
|
||||||
|
|
|
@ -1045,7 +1045,7 @@ syscon mount MNT_SNAPSHOT 0 0 0x40000000 0x40000000 0x01000000 0 0
|
||||||
# limits
|
# limits
|
||||||
#
|
#
|
||||||
# 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 limits PIPE_BUF 4096 4096 512 512 512 512 512 4096 # bsd consensus
|
syscon limits PIPE_BUF 4096 4096 512 512 512 512 512 512 # bsd consensus
|
||||||
syscon limits NGROUPS_MAX 65536 65536 16 16 1023 16 16 0 #
|
syscon limits NGROUPS_MAX 65536 65536 16 16 1023 16 16 0 #
|
||||||
syscon limits LINK_MAX 127 127 32767 32767 32767 32767 32767 64 # freebsd/windows are educated guesses
|
syscon limits LINK_MAX 127 127 32767 32767 32767 32767 32767 64 # freebsd/windows are educated guesses
|
||||||
syscon limits MAX_CANON 255 255 1024 1024 255 255 255 255 # windows is guessed
|
syscon limits MAX_CANON 255 255 1024 1024 255 255 255 255 # windows is guessed
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
#include "libc/sysv/consts/syscon.internal.h"
|
||||||
.syscon limits,PIPE_BUF,4096,4096,512,512,512,512,512,4096
|
.syscon limits,PIPE_BUF,4096,4096,512,512,512,512,512,512
|
||||||
|
|
Loading…
Add table
Reference in a new issue