Fix some additional Windows TTY issues

This commit is contained in:
Justine Tunney 2023-10-03 23:53:59 -07:00
parent f26a280cda
commit 1694edf85c
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
12 changed files with 107 additions and 43 deletions

View file

@ -58,7 +58,16 @@ int main(int argc, char *argv[]) {
// 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
// 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
//
@ -109,7 +118,7 @@ int main(int argc, char *argv[]) {
// it's usually safe to ignore the return code of write. the
// operating system will send SIGPIPE if there's any problem
// which kills the process by default
write(1, "got: ", 5);
write(1, buf, got);
write(1, "\n", 1);
}
}

View file

@ -92,7 +92,7 @@ int EnableRawMode(void) {
perror("tcsetattr");
}
WRITE(outfd, ENABLE_MOUSE_TRACKING);
/* WRITE(outfd, ENABLE_MOUSE_TRACKING); */
/* WRITE(outfd, ENABLE_SAFE_PASTE); */
/* WRITE(outfd, PROBE_DISPLAY_SIZE); */
return 0;

View file

@ -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)) {
g_fds.p[newfd].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 {
g_fds.p[newfd].extra = g_fds.p[oldfd].extra;
}

View file

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

View file

@ -20,13 +20,17 @@
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/macros.internal.h"
#include "libc/nt/enum/fileflagandattributes.h"
#include "libc/nt/files.h"
#include "libc/nt/thunk/msabi.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/errfuns.h"
int __mkntpathat(int dirfd, const char *path, int flags,
char16_t file[hasatleast PATH_MAX]) {
__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 dir[PATH_MAX];
uint32_t dirlen, filelen;
if (!isutf8(path, -1)) return eilseq(); // thwart overlong nul in conversion
@ -49,3 +53,30 @@ int __mkntpathat(int dirfd, const char *path, int flags,
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;
}

View file

@ -53,16 +53,6 @@ static textwindows int64_t sys_open_nt_impl(int dirfd, const char *path,
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
// you can't open symlinks; use readlink
// this flag only applies to the final path component

View file

@ -106,7 +106,7 @@ struct Keystrokes {
unsigned char pc;
uint16_t utf16hs;
pthread_mutex_t lock;
struct Keystroke pool[8];
struct Keystroke pool[512];
};
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 (^?)
if (c == kNtVkBack) {
if (c == kNtVkBack && !(cks & (kNtLeftCtrlPressed | kNtRightCtrlPressed))) {
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,
struct NtInputRecord *r) {
@ -401,18 +420,15 @@ static textwindows void IngestConsoleInputRecord(struct Fd *f,
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);
}
}
EraseKeystroke(f);
return;
}
// handle kill in canonical mode
if (len == 1 && buf[0] && //
(buf[0] & 255) == __ttyconf.vkill && //
!(__ttyconf.magic & kTtyUncanon)) {
while (EraseKeystroke(f)) {
}
return;
}
@ -455,12 +471,21 @@ static textwindows void IngestConsoleInput(struct Fd *f) {
struct NtInputRecord records[16];
if (!__keystroke.end_of_file) {
do {
if (ReadConsoleInput(f->handle, records, ARRAYLEN(records), &n)) {
for (i = 0; i < n && !__keystroke.end_of_file; ++i) {
IngestConsoleInputRecord(f, records + i);
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) {
IngestConsoleInputRecord(f, records + i);
}
} else {
STRACE("ReadConsoleInput failed w/ %d", GetLastError());
__keystroke.end_of_file = true;
break;
}
}
} else {
STRACE("ReadConsoleInput failed w/ %d", GetLastError());
STRACE("GetNumberOfConsoleInputRecords failed w/ %d", GetLastError());
__keystroke.end_of_file = true;
break;
}
@ -513,7 +538,7 @@ static textwindows bool DigestConsoleInput(char *data, size_t size, int *rc) {
// copy keystroke(s) into user buffer
int toto = 0;
struct Dll *e;
while ((e = dll_first(__keystroke.list))) {
while (size && (e = dll_first(__keystroke.list))) {
struct Keystroke *k = KEYSTROKE_CONTAINER(e);
uint32_t got = MIN(size, k->buflen);
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 (__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;
}

View file

@ -34,7 +34,6 @@
#include "libc/fmt/itoa.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/describebacktrace.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/popcnt.h"
#include "libc/intrin/strace.internal.h"
#include "libc/intrin/weaken.h"

View file

@ -74,8 +74,7 @@ textwindows int tcsetattr_nt(int fd, int opt, const struct termios *tio) {
inmode |= kNtEnableWindowInput;
__ttyconf.magic = 0;
if (tio->c_lflag & ICANON) {
inmode |=
kNtEnableLineInput | kNtEnableProcessedInput | kNtEnableQuickEditMode;
inmode |= kNtEnableLineInput | kNtEnableQuickEditMode;
} else {
inmode &= ~kNtEnableQuickEditMode;
__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);
if ((tio->c_lflag & ISIG) && __ttyconf.vintr == CTRL('C')) {
// allows ctrl-c to be delivered asynchronously via win32
inmode |= kNtEnableProcessedInput;
// TODO(jart): Fix up sig.c more.
// inmode |= kNtEnableProcessedInput;
}
ok = SetConsoleMode(hInput, inmode);
(void)ok;

View file

@ -3,7 +3,7 @@
#include "libc/intrin/likely.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 _DATATRACE 1 /* not configurable w/ flag yet */
#define _LOCKTRACE 0 /* not configurable w/ flag yet */

View file

@ -1045,7 +1045,7 @@ syscon mount MNT_SNAPSHOT 0 0 0x40000000 0x40000000 0x01000000 0 0
# limits
#
# 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 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

View file

@ -1,2 +1,2 @@
#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