Fix console copy/paste issue

Fixes #936
This commit is contained in:
Justine Tunney 2023-11-08 09:29:45 -08:00
parent 956e68be59
commit ac125d3e1f
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
4 changed files with 49 additions and 60 deletions

View file

@ -16,8 +16,6 @@
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/assert.h"
#include "libc/atomic.h"
#include "libc/calls/createfileflags.internal.h" #include "libc/calls/createfileflags.internal.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h" #include "libc/calls/sig.internal.h"
@ -29,14 +27,11 @@
#include "libc/cosmo.h" #include "libc/cosmo.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/fmt/itoa.h" #include "libc/fmt/itoa.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/describeflags.internal.h" #include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/dll.h" #include "libc/intrin/dll.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/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/mem/mem.h"
#include "libc/nt/console.h" #include "libc/nt/console.h"
#include "libc/nt/createfile.h" #include "libc/nt/createfile.h"
#include "libc/nt/enum/accessmask.h" #include "libc/nt/enum/accessmask.h"
@ -51,6 +46,7 @@
#include "libc/nt/synchronization.h" #include "libc/nt/synchronization.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/str/utf16.h" #include "libc/str/utf16.h"
#include "libc/sysv/consts/limits.h"
#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/sicode.h" #include "libc/sysv/consts/sicode.h"
#include "libc/sysv/consts/sig.h" #include "libc/sysv/consts/sig.h"
@ -134,7 +130,7 @@ struct Keystrokes {
bool end_of_file; bool end_of_file;
bool ohno_decckm; bool ohno_decckm;
uint16_t utf16hs; uint16_t utf16hs;
atomic_int_fast16_t used; int16_t freekeys;
int64_t cin, cot; int64_t cin, cot;
struct Dll *list; struct Dll *list;
struct Dll *line; struct Dll *line;
@ -150,12 +146,42 @@ textwindows void __keystroke_wipe(void) {
bzero(&__keystroke, sizeof(__keystroke)); bzero(&__keystroke, sizeof(__keystroke));
} }
static textwindows void FreeKeystrokeImpl(struct Dll *key) {
dll_make_first(&__keystroke.free, key);
++__keystroke.freekeys;
}
static textwindows struct Keystroke *NewKeystroke(void) {
struct Dll *e = dll_first(__keystroke.free);
struct Keystroke *k = KEYSTROKE_CONTAINER(e);
dll_remove(&__keystroke.free, &k->elem);
--__keystroke.freekeys;
k->buflen = 0;
return k;
}
static textwindows void FreeKeystroke(struct Dll **list, struct Dll *key) {
dll_remove(list, key);
FreeKeystrokeImpl(key);
}
static textwindows void FreeKeystrokes(struct Dll **list) {
struct Dll *key;
while ((key = dll_first(*list))) {
FreeKeystroke(list, key);
}
}
static textwindows void OpenConsole(void) { static textwindows void OpenConsole(void) {
__keystroke.vkt = kVirtualKey; __keystroke.vkt = kVirtualKey;
__keystroke.cin = CreateFile(u"CONIN$", kNtGenericRead | kNtGenericWrite, __keystroke.cin = CreateFile(u"CONIN$", kNtGenericRead | kNtGenericWrite,
kNtFileShareRead, 0, kNtOpenExisting, 0, 0); kNtFileShareRead, 0, kNtOpenExisting, 0, 0);
__keystroke.cot = CreateFile(u"CONOUT$", kNtGenericRead | kNtGenericWrite, __keystroke.cot = CreateFile(u"CONOUT$", kNtGenericRead | kNtGenericWrite,
kNtFileShareWrite, 0, kNtOpenExisting, 0, 0); kNtFileShareWrite, 0, kNtOpenExisting, 0, 0);
for (int i = 0; i < ARRAYLEN(__keystroke.pool); ++i) {
dll_init(&__keystroke.pool[i].elem);
FreeKeystrokeImpl(&__keystroke.pool[i].elem);
}
} }
static textwindows int AddSignal(int sig) { static textwindows int AddSignal(int sig) {
@ -413,34 +439,6 @@ static textwindows int ConvertConsoleInputToAnsi(const struct NtInputRecord *r,
} }
} }
static textwindows struct Keystroke *NewKeystroke(void) {
struct Dll *e;
struct Keystroke *k = 0;
int i, n = ARRAYLEN(__keystroke.pool);
if (atomic_load_explicit(&__keystroke.used, memory_order_acquire) < n &&
(i = atomic_fetch_add(&__keystroke.used, 1)) < n) {
k = __keystroke.pool + i;
} else {
if ((e = dll_first(__keystroke.free))) {
k = KEYSTROKE_CONTAINER(e);
dll_remove(&__keystroke.free, &k->elem);
}
if (!k) {
if (_weaken(malloc)) {
k = _weaken(malloc)(sizeof(struct Keystroke));
} else {
enomem();
return 0;
}
}
}
if (k) {
bzero(k, sizeof(*k));
dll_init(&k->elem);
}
return k;
}
static textwindows void WriteTty(const char *p, size_t n) { static textwindows void WriteTty(const char *p, size_t n) {
WriteFile(__keystroke.cot, p, n, 0, 0); WriteFile(__keystroke.cot, p, n, 0, 0);
} }
@ -479,8 +477,7 @@ static textwindows bool EraseKeystroke(void) {
struct Dll *e; struct Dll *e;
if ((e = dll_last(__keystroke.line))) { if ((e = dll_last(__keystroke.line))) {
struct Keystroke *k = KEYSTROKE_CONTAINER(e); struct Keystroke *k = KEYSTROKE_CONTAINER(e);
dll_remove(&__keystroke.line, e); FreeKeystroke(&__keystroke.line, e);
dll_make_first(&__keystroke.free, e);
for (int i = k->buflen; i--;) { for (int i = k->buflen; i--;) {
if ((k->buf[i] & 0300) == 0200) continue; // utf-8 cont if ((k->buf[i] & 0300) == 0200) continue; // utf-8 cont
EraseCharacter(); EraseCharacter();
@ -521,11 +518,7 @@ static textwindows void IngestConsoleInputRecord(struct NtInputRecord *r) {
} }
// allocate object to hold keystroke // allocate object to hold keystroke
struct Keystroke *k; struct Keystroke *k = NewKeystroke();
if (!(k = NewKeystroke())) {
STRACE("out of keystroke memory");
return;
}
memcpy(k->buf, buf, sizeof(k->buf)); memcpy(k->buf, buf, sizeof(k->buf));
k->buflen = len; k->buflen = len;
@ -541,11 +534,11 @@ static textwindows void IngestConsoleInputRecord(struct NtInputRecord *r) {
} else { } else {
dll_make_last(&__keystroke.line, &k->elem); dll_make_last(&__keystroke.line, &k->elem);
// handle enter in canonical mode // flush canonical mode line if oom or enter
if (len == 1 && buf[0] && if (!__keystroke.freekeys || (len == 1 && buf[0] &&
((buf[0] & 255) == '\n' || // ((buf[0] & 255) == '\n' || //
(buf[0] & 255) == __ttyconf.veol || // (buf[0] & 255) == __ttyconf.veol || //
(buf[0] & 255) == __ttyconf.veol2)) { (buf[0] & 255) == __ttyconf.veol2))) {
dll_make_last(&__keystroke.list, __keystroke.line); dll_make_last(&__keystroke.list, __keystroke.line);
__keystroke.line = 0; __keystroke.line = 0;
} }
@ -556,12 +549,13 @@ static textwindows void IngestConsoleInput(void) {
uint32_t i, n; uint32_t i, n;
struct NtInputRecord records[16]; struct NtInputRecord records[16];
for (;;) { for (;;) {
if (!__keystroke.freekeys) return;
if (__keystroke.end_of_file) return; if (__keystroke.end_of_file) return;
if (!GetNumberOfConsoleInputEvents(__keystroke.cin, &n)) { if (!GetNumberOfConsoleInputEvents(__keystroke.cin, &n)) {
goto UnexpectedEof; goto UnexpectedEof;
} }
if (!n) return; if (!n) return;
n = MIN(ARRAYLEN(records), n); n = MIN(__keystroke.freekeys, MIN(ARRAYLEN(records), n));
if (!ReadConsoleInput(__keystroke.cin, records, n, &n)) { if (!ReadConsoleInput(__keystroke.cin, records, n, &n)) {
goto UnexpectedEof; goto UnexpectedEof;
} }
@ -576,19 +570,15 @@ UnexpectedEof:
// Discards all unread stdin bytes. // Discards all unread stdin bytes.
textwindows int FlushConsoleInputBytes(void) { textwindows int FlushConsoleInputBytes(void) {
int rc;
BLOCK_SIGNALS; BLOCK_SIGNALS;
InitConsole(); InitConsole();
LockKeystrokes(); LockKeystrokes();
FlushConsoleInputBuffer(__keystroke.cin); FlushConsoleInputBuffer(__keystroke.cin);
dll_make_first(&__keystroke.free, __keystroke.list); FreeKeystrokes(&__keystroke.list);
__keystroke.list = 0; FreeKeystrokes(&__keystroke.line);
dll_make_first(&__keystroke.free, __keystroke.line);
__keystroke.line = 0;
rc = 0;
UnlockKeystrokes(); UnlockKeystrokes();
ALLOW_SIGNALS; ALLOW_SIGNALS;
return rc; return 0;
} }
// Returns number of stdin bytes that may be read without blocking. // Returns number of stdin bytes that may be read without blocking.
@ -700,11 +690,10 @@ static textwindows bool DigestConsoleInput(char *data, size_t size, int *rc) {
} }
if (remain) { if (remain) {
memmove(k->buf, k->buf + got, remain); memmove(k->buf, k->buf + got, remain);
k->buflen = remain;
} else { } else {
dll_remove(&__keystroke.list, e); FreeKeystroke(&__keystroke.list, e);
dll_make_first(&__keystroke.free, e);
} }
k->buflen = remain;
if ((__ttyconf.magic & kTtyUncanon) && toto >= __ttyconf.vmin) { if ((__ttyconf.magic & kTtyUncanon) && toto >= __ttyconf.vmin) {
break; break;
} }

View file

@ -59,7 +59,7 @@ static textwindows ssize_t sys_write_nt_impl(int fd, void *data, size_t size,
} }
// intercept ansi tty configuration sequences // intercept ansi tty configuration sequences
if (isconsole && _weaken(InterceptTerminalCommands)) { if (isconsole && _weaken(GetConsoleOutputHandle)) {
_weaken(InterceptTerminalCommands)(data, size); _weaken(InterceptTerminalCommands)(data, size);
} }

View file

@ -1044,7 +1044,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 512 # bsd consensus syscon limits PIPE_BUF 4096 4096 512 512 512 512 512 4096 # 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

View file

@ -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,512 .syscon limits,PIPE_BUF,4096,4096,512,512,512,512,512,4096