diff --git a/examples/getrandom.c b/examples/getrandom.c index 10c3593e5..a53f14313 100644 --- a/examples/getrandom.c +++ b/examples/getrandom.c @@ -16,6 +16,7 @@ #include "libc/macros.internal.h" #include "libc/nexgen32e/x86feature.h" #include "libc/rand/rand.h" +#include "libc/rand/xorshift.h" #include "libc/stdio/stdio.h" #include "libc/str/str.h" #include "libc/sysv/consts/ex.h" @@ -25,6 +26,12 @@ #include "libc/testlib/hyperion.h" #include "third_party/getopt/getopt.h" +#define B 4096 + +bool isdone; +bool isbinary; +unsigned long count = -1; + uint64_t bcast(uint64_t f(void)) { unsigned i; uint64_t x; @@ -95,6 +102,28 @@ uint64_t vigna(void) { return z ^ (z >> 31); } +uint64_t rngset64(void) { + static unsigned i; + static uint64_t s; + if (!i) { + s = rand64(); + i = (s + 1) & (511); + } + return MarsagliaXorshift64(&s); +} + +uint64_t xorshift64(void) { + static uint64_t s = kMarsagliaXorshift64Seed; + return MarsagliaXorshift64(&s); +} + +uint64_t xorshift32(void) { + static uint32_t s = kMarsagliaXorshift32Seed; + uint64_t a = MarsagliaXorshift32(&s); + uint64_t b = MarsagliaXorshift32(&s); + return (uint64_t)a << 32 | b; +} + uint64_t libc(void) { uint64_t x; CHECK_EQ(8, getrandom(&x, 8, 0)); @@ -151,27 +180,26 @@ const struct Function { const char *s; uint64_t (*f)(void); } kFunctions[] = { - {"ape", ape}, // - {"hardware", hardware}, // - {"inc", inc}, // - {"kernel", kernel}, // - {"knuth", knuth}, // - {"libc", libc}, // - {"moby", moby}, // - {"rand64", rand64}, // - {"rdrand", rdrnd}, // - {"rdrnd", rdrnd}, // - {"rdseed", rdseed}, // - {"unixv6", unixv6}, // - {"unixv7", unixv7}, // - {"vigna", vigna}, // - {"zero", zero}, // + {"ape", ape}, // + {"hardware", hardware}, // + {"inc", inc}, // + {"kernel", kernel}, // + {"knuth", knuth}, // + {"libc", libc}, // + {"moby", moby}, // + {"rand64", rand64}, // + {"rdrand", rdrnd}, // + {"rdrnd", rdrnd}, // + {"rdseed", rdseed}, // + {"rngset64", rngset64}, // + {"unixv6", unixv6}, // + {"unixv7", unixv7}, // + {"vigna", vigna}, // + {"xorshift32", xorshift32}, // + {"xorshift64", xorshift64}, // + {"zero", zero}, // }; -bool isdone; -bool isbinary; -unsigned long count = -1; - void OnInt(int sig) { isdone = true; } @@ -182,16 +210,19 @@ wontreturn void PrintUsage(FILE *f, int rc) { } int main(int argc, char *argv[]) { + char *p; int i, opt; ssize_t rc; uint64_t x; + static char buf[B]; uint64_t (*f)(void); - while ((opt = getopt(argc, argv, "hbn:")) != -1) { + while ((opt = getopt(argc, argv, "hbc:n:")) != -1) { switch (opt) { case 'b': isbinary = true; break; + case 'c': case 'n': count = strtoul(optarg, 0, 0); break; @@ -235,10 +266,23 @@ int main(int argc, char *argv[]) { } while (count && !isdone) { - x = f(); - rc = write(1, &x, MIN(8, count)); + if (count >= B) { + for (i = 0; i < B / 8; ++i) { + x = f(); + p = buf + i * 8; + WRITE64LE(p, x); + } + for (i = 0; i < B; i += rc) { + rc = write(1, buf + i, B - i); + if (rc == -1 && errno == EPIPE) exit(1); + if (rc == -1) perror("write"), exit(1); + } + } else { + x = f(); + rc = write(1, &x, MIN(8, count)); + } if (!rc) break; - if (rc == -1 && errno == EPIPE) return 1; + if (rc == -1 && errno == EPIPE) exit(1); if (rc == -1) perror("write"), exit(1); count -= rc; } diff --git a/examples/kilo.c b/examples/kilo.c index 3ca4cebbe..5a01c4ba4 100644 --- a/examples/kilo.c +++ b/examples/kilo.c @@ -267,8 +267,12 @@ int editorReadKey(int64_t fd) { if (read(fd, seq + 2, 1) == 0) return CTRL('['); if (seq[2] == '~') { switch (seq[1]) { + case '1': + return HOME_KEY; case '3': return DEL_KEY; + case '4': + return END_KEY; case '5': return PAGE_UP; case '6': diff --git a/libc/calls/ioctl_tcgets-nt.c b/libc/calls/ioctl_tcgets-nt.c index 17fc30609..e3012dd6b 100644 --- a/libc/calls/ioctl_tcgets-nt.c +++ b/libc/calls/ioctl_tcgets-nt.c @@ -41,7 +41,8 @@ textwindows int ioctl_tcgets_nt(int ignored, struct termios *tio) { if (inmode & kNtEnableProcessedInput) tio->c_lflag |= IEXTEN | ISIG; } if (outok) { - if (inmode & kNtEnableProcessedInput) tio->c_lflag |= IEXTEN | ISIG; + if (outmode & kNtEnableProcessedOutput) tio->c_oflag |= OPOST; + if (!(outmode & kNtDisableNewlineAutoReturn)) tio->c_oflag |= ONLCR; } return 0; } else { diff --git a/libc/calls/ioctl_tcsets-nt.c b/libc/calls/ioctl_tcsets-nt.c index 98d0af630..ba52c2a80 100644 --- a/libc/calls/ioctl_tcsets-nt.c +++ b/libc/calls/ioctl_tcsets-nt.c @@ -51,8 +51,8 @@ textwindows int ioctl_tcsets_nt(int ignored, uint64_t request, } if (outok) { outmode |= kNtEnableWrapAtEolOutput; - outmode |= kNtEnableProcessedOutput; - if (!(tio->c_oflag & OPOST)) outmode |= kNtDisableNewlineAutoReturn; + if (tio->c_oflag & OPOST) outmode |= kNtEnableProcessedOutput; + if (!(tio->c_oflag & ONLCR)) outmode |= kNtDisableNewlineAutoReturn; if (NtGetVersion() >= kNtVersionWindows10) { outmode |= kNtEnableVirtualTerminalProcessing; } diff --git a/libc/calls/readansi.c b/libc/calls/readansi.c index d802b824d..73aae7a81 100644 --- a/libc/calls/readansi.c +++ b/libc/calls/readansi.c @@ -102,6 +102,7 @@ ssize_t readansi(int fd, char *buf, size_t size) { break; case kCsi: switch (c) { + case '[': case ':': case ';': case '<': diff --git a/libc/log/die.c b/libc/log/die.c index 998598564..e03b50fa1 100644 --- a/libc/log/die.c +++ b/libc/log/die.c @@ -19,6 +19,7 @@ #include "libc/bits/bits.h" #include "libc/dce.h" #include "libc/log/backtrace.internal.h" +#include "libc/log/internal.h" #include "libc/log/log.h" /** @@ -29,6 +30,7 @@ relegated wontreturn void __die(void) { static bool once; if (cmpxchg(&once, false, true)) { + __restore_tty(); if (IsDebuggerPresent(false)) DebugBreak(); ShowBacktrace(2, NULL); } diff --git a/libc/log/internal.h b/libc/log/internal.h index eba7db65e..7c4757e82 100644 --- a/libc/log/internal.h +++ b/libc/log/internal.h @@ -2,16 +2,19 @@ #define COSMOPOLITAN_LIBC_LOG_INTERNAL_H_ #include "libc/calls/struct/sigaction.h" #include "libc/calls/struct/siginfo.h" +#include "libc/calls/struct/termios.h" #include "libc/calls/ucontext.h" #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ extern int kCrashSigs[8] hidden; +extern struct termios g_oldtermios hidden; extern struct sigaction g_oldcrashacts[8] hidden; void __start_fatal(const char *, int) hidden; void __start_fatal_ndebug(void) hidden; void __oncrash(int, struct siginfo *, struct ucontext *) relegated; +void __restore_tty(void); COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/libc/log/oldtermios.c b/libc/log/oldtermios.c new file mode 100644 index 000000000..ab38ad334 --- /dev/null +++ b/libc/log/oldtermios.c @@ -0,0 +1,45 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" +#include "libc/calls/termios.h" +#include "libc/log/internal.h" +#include "libc/str/str.h" + +#define SHOW_CURSOR "\e[?25h" +#define DISABLE_MOUSE "\e[?1000;1002;1015;1006l" +#define ANSI_RESTORE SHOW_CURSOR DISABLE_MOUSE + +struct termios g_oldtermios; + +static textstartup void g_oldtermios_init() { + if (isatty(1)) { + tcgetattr(1, &g_oldtermios); + } +} + +const void *const g_oldtermios_ctor[] initarray = { + g_oldtermios_init, +}; + +void __restore_tty(void) { + if (isatty(1)) { + write(1, ANSI_RESTORE, strlen(ANSI_RESTORE)); + tcsetattr(1, TCSAFLUSH, &g_oldtermios); + } +} diff --git a/libc/log/oncrash.c b/libc/log/oncrash.c index 75f8c3798..ebadc154d 100644 --- a/libc/log/oncrash.c +++ b/libc/log/oncrash.c @@ -20,7 +20,9 @@ #include "libc/calls/sigbits.h" #include "libc/calls/struct/sigaction.h" #include "libc/calls/struct/siginfo.h" +#include "libc/calls/struct/termios.h" #include "libc/calls/struct/utsname.h" +#include "libc/calls/termios.h" #include "libc/calls/ucontext.h" #include "libc/dce.h" #include "libc/errno.h" @@ -41,6 +43,7 @@ #include "libc/sysv/consts/fileno.h" #include "libc/sysv/consts/o.h" #include "libc/sysv/consts/sig.h" +#include "libc/sysv/consts/termios.h" /** * @fileoverview Abnormal termination handling & GUI debugging. @@ -262,6 +265,7 @@ relegated void __oncrash(int sig, struct siginfo *si, ucontext_t *ctx) { : 0); } if (gdbpid > 0 && (sig == SIGTRAP || sig == SIGQUIT)) return; + __restore_tty(); ShowCrashReport(err, STDERR_FILENO, sig, si, ctx); exit(128 + sig); unreachable; diff --git a/libc/log/showcrashreports.c b/libc/log/showcrashreports.c index d9eae94bb..d314d1478 100644 --- a/libc/log/showcrashreports.c +++ b/libc/log/showcrashreports.c @@ -20,6 +20,7 @@ #include "libc/bits/bits.h" #include "libc/calls/calls.h" #include "libc/calls/sigbits.h" +#include "libc/calls/termios.h" #include "libc/calls/typedef/sigaction_f.h" #include "libc/dce.h" #include "libc/log/check.h" diff --git a/libc/log/startfatal.c b/libc/log/startfatal.c index ad8eadd30..b86c1d395 100644 --- a/libc/log/startfatal.c +++ b/libc/log/startfatal.c @@ -32,6 +32,7 @@ relegated void __start_fatal(const char *file, int line) { bool colorful; char s[16 + 16 + 16 + 16 + PATH_MAX + 16 + NAME_MAX + 16], *p = s; + __restore_tty(); colorful = cancolor(); *p++ = '\r'; if (colorful) p = stpcpy(p, "\e[J\e[30;101m"); diff --git a/libc/log/startfatal_ndebug.c b/libc/log/startfatal_ndebug.c index 6a7d96540..c8af1cb46 100644 --- a/libc/log/startfatal_ndebug.c +++ b/libc/log/startfatal_ndebug.c @@ -29,6 +29,7 @@ */ relegated void __start_fatal_ndebug(void) { char s[16 + 16 + 16 + 16 + PATH_MAX + 16], *p = s; + __restore_tty(); *p++ = '\r'; if (cancolor()) p = stpcpy(p, "\e[J"); p = stpcpy(p, "error:"); diff --git a/libc/rand/getrandom.c b/libc/rand/getrandom.c index 9c8262bc9..927c21f2e 100644 --- a/libc/rand/getrandom.c +++ b/libc/rand/getrandom.c @@ -45,10 +45,11 @@ static bool have_getrandom; * This random number seed generator blends information from: * * - getrandom() on Linux + * - RtlGenRandom() on Windows * - getentropy() on XNU and OpenBSD * - sysctl(KERN_ARND) on FreeBSD and NetBSD * - RDSEED on Broadwell+ and Xen+ unless GRND_NORDRND - * - RDRAND on Ivybridge+ and Xen+ unless GRND_NORDRND|GRND_RANDOM + * - RDRAND on Ivybridge+ and Xen+ unless GRND_NORDRND * * The following flags may be specified: * @@ -75,7 +76,9 @@ ssize_t getrandom(void *p, size_t n, unsigned f) { sigset_t neu, old; if (n > 256) n = 256; if (!IsTiny() && - (f & ~(GRND_RANDOM | GRND_NONBLOCK | GRND_NORDRND | GRND_NOSYSTEM))) { + ((f & ~(GRND_RANDOM | GRND_NONBLOCK | GRND_NORDRND | GRND_NOSYSTEM)) || + (f & (GRND_NORDRND | GRND_NOSYSTEM)) == + (GRND_NORDRND | GRND_NOSYSTEM))) { return einval(); } if (!(f & GRND_NOSYSTEM)) { diff --git a/libc/rand/rngset.c b/libc/rand/rngset.c index bf7a782ac..d603f8b99 100644 --- a/libc/rand/rngset.c +++ b/libc/rand/rngset.c @@ -23,8 +23,8 @@ /** * Fills memory with random bytes, e.g. * - * char buf[1024]; - * rngset(buf, sizeof(buf), rand64, -1); + * char buf[1024]; + * rngset(buf, sizeof(buf), rand64, -1); * * @param seed can be rand64() and is always called at least once * @param reseed is bytes between seed() calls and -1 disables it diff --git a/libc/x/x.h b/libc/x/x.h index 0a02fd3d4..5e604fac4 100644 --- a/libc/x/x.h +++ b/libc/x/x.h @@ -53,6 +53,7 @@ void *xunbinga(size_t, const char16_t *) attributeallocalign((1)) _XMAL _XRET; void *xunbing(const char16_t *) _XMAL _XRET; char16_t *utf8toutf16(const char *, size_t, size_t *) nodiscard; char *utf16toutf8(const char16_t *, size_t, size_t *) nodiscard; +char *xhomedir(void) nodiscard; /*───────────────────────────────────────────────────────────────────────────│─╗ │ cosmopolitan § eXtended apis » files ─╬─│┼ diff --git a/libc/x/xhomedir.c b/libc/x/xhomedir.c new file mode 100644 index 000000000..751678cff --- /dev/null +++ b/libc/x/xhomedir.c @@ -0,0 +1,43 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/dce.h" +#include "libc/runtime/runtime.h" +#include "libc/x/x.h" + +/** + * Returns home directory. + */ +char *xhomedir(void) { + int fd; + const char *a, *b; + if ((a = getenv("HOME"))) { + b = ""; + } else if (IsWindows()) { + a = getenv("HOMEDRIVE"); + b = getenv("HOMEPATH"); + if (!a || !b) { + a = "C:"; + b = ""; + } + } else { + a = "."; + b = ""; + } + return xasprintf("%s%s", a, b); +} diff --git a/third_party/linenoise/linenoise.c b/third_party/linenoise/linenoise.c index 456db18fe..ac7e9977c 100644 --- a/third_party/linenoise/linenoise.c +++ b/third_party/linenoise/linenoise.c @@ -15,6 +15,7 @@ │ │ │ Copyright (c) 2010-2016, Salvatore Sanfilippo │ │ Copyright (c) 2010-2013, Pieter Noordhuis │ +│ Copyright (c) 2018-2020, Justine Tunney │ │ │ │ All rights reserved. │ │ │ @@ -43,67 +44,22 @@ │ │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ │ -│ Todo list: │ -│ - Filter bogus Ctrl+ combinations. │ -│ - Win32 support │ +│ CHANGES │ │ │ -│ Bloat: [say what?!] MUST DO: │ -│ - History search like Ctrl+r in readline? │ +│ - Remove bell │ +│ - Windows support │ +│ - Filters out unsupported control sequences │ +│ - Filters out Thompson-Pike input sequences │ │ │ -│ List of escape sequences used by this program, we do everything just │ -│ with three sequences. In order to be so cheap we may have some │ -│ flickering effect with some slow terminal, but the lesser sequences │ -│ the more compatible. │ +│ TODO │ │ │ -│ EL (Erase Line) │ -│ Sequence: ESC [ n K │ -│ Effect: if n is 0 or missing, clear from cursor to end of line │ -│ Effect: if n is 1, clear from beginning of line to cursor │ -│ Effect: if n is 2, clear entire line │ -│ │ -│ CUF (CUrsor Forward) │ -│ Sequence: ESC [ n C │ -│ Effect: moves cursor forward n chars │ -│ │ -│ CUB (CUrsor Backward) │ -│ Sequence: ESC [ n D │ -│ Effect: moves cursor backward n chars │ -│ │ -│ The following is used to get the terminal width if getting │ -│ the width with the TIOCGWINSZ ioctl fails │ -│ │ -│ DSR (Device Status Report) │ -│ Sequence: ESC [ 6 n │ -│ Effect: reports the current cusor position as ESC [ n ; m R │ -│ where n is the row and m is the column │ -│ │ -│ When multi line mode is enabled, we also use an additional escape │ -│ sequence. However multi line editing is disabled by default. │ -│ │ -│ CUU (Cursor Up) │ -│ Sequence: ESC [ n A │ -│ Effect: moves cursor up of n chars. │ -│ │ -│ CUD (Cursor Down) │ -│ Sequence: ESC [ n B │ -│ Effect: moves cursor down of n chars. │ -│ │ -│ When linenoiseClearScreen() is called, two additional escape sequences │ -│ are used in order to clear the screen and position the cursor at home │ -│ position. │ -│ │ -│ CUP (Cursor position) │ -│ Sequence: ESC [ H │ -│ Effect: moves the cursor to upper left corner │ -│ │ -│ ED (Erase display) │ -│ Sequence: ESC [ 2 J │ -│ Effect: clear the whole screen │ -│ │ -╞══════════════════════════════════════════════════════════════════════════════╡ +│ - Kill ring │ +│ - History search │ +│ - Thompson-Pike Encoding │ │ │ │ REFERENCE │ -│ the big scary coding you 𝘮𝘶𝘴𝘵 use curses to abstract │ +│ │ +│ The big scary coding you 𝘮𝘶𝘴𝘵 use curses to abstract. │ │ │ │ \t TAB │ │ \a BELL │ @@ -221,6 +177,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" #include "libc/calls/termios.h" +#include "libc/calls/ttydefaults.h" #include "libc/calls/weirdtypes.h" #include "libc/errno.h" #include "libc/fmt/fmt.h" @@ -267,28 +224,6 @@ struct linenoiseState { int history_index; /* The history index we are currently editing. */ }; -enum KEY_ACTION{ - KEY_NULL = 0, /* NULL */ - CTRL_A = 1, /* Ctrl+a */ - CTRL_B = 2, /* Ctrl-b */ - CTRL_C = 3, /* Ctrl-c */ - CTRL_D = 4, /* Ctrl-d */ - CTRL_E = 5, /* Ctrl-e */ - CTRL_F = 6, /* Ctrl-f */ - CTRL_H = 8, /* Ctrl-h */ - TAB = 9, /* Tab */ - CTRL_K = 11, /* Ctrl+k */ - CTRL_L = 12, /* Ctrl+l */ - ENTER = 13, /* Enter */ - CTRL_N = 14, /* Ctrl-n */ - CTRL_P = 16, /* Ctrl-p */ - CTRL_T = 20, /* Ctrl-t */ - CTRL_U = 21, /* Ctrl+u */ - CTRL_W = 23, /* Ctrl+w */ - ESC = 27, /* Escape */ - BACKSPACE = 127 /* Backspace */ -}; - static void linenoiseAtExit(void); static void refreshLine(struct linenoiseState *); @@ -362,7 +297,7 @@ static int enableRawMode(int fd) { raw.c_oflag &= ~(OPOST); /* control modes - set 8 bit chars */ raw.c_cflag |= (CS8); - /* local modes - choing off, canonical off, no extended functions, + /* local modes - echoing off, canonical off, no extended functions, * no signal chars (^Z,^C) */ raw.c_lflag &= ~(ECHO | ICANON | IEXTEN); /* control chars - set return condition: min number of bytes and timer. @@ -391,7 +326,7 @@ static int getCursorPosition(int ifd, int ofd) { int cols, rows; unsigned int i = 0; /* Report cursor location */ - if (write(ofd, "\x1b[6n", 4) != 4) return -1; + if (write(ofd, "\e[6n", 4) != 4) return -1; /* Read the response: ESC [ rows ; cols R */ while (i < sizeof(buf)-1) { if (read(ifd,buf+i,1) != 1) break; @@ -400,7 +335,7 @@ static int getCursorPosition(int ifd, int ofd) { } buf[i] = '\0'; /* Parse it. */ - if (buf[0] != ESC || buf[1] != '[') return -1; + if (buf[0] != '\e' || buf[1] != '[') return -1; if (sscanf(buf+2,"%d;%d",&rows,&cols) != 2) return -1; return cols; } @@ -416,13 +351,13 @@ static int getColumns(int ifd, int ofd) { start = getCursorPosition(ifd,ofd); if (start == -1) goto failed; /* Go to right margin and get position. */ - if (write(ofd,"\x1b[999C",6) != 6) goto failed; + if (write(ofd,"\e[999C",6) != 6) goto failed; cols = getCursorPosition(ifd,ofd); if (cols == -1) goto failed; /* Restore position. */ if (cols > start) { char seq[32]; - snprintf(seq,32,"\x1b[%dD",cols-start); + snprintf(seq,32,"\e[%dD",cols-start); if (write(ofd,seq,strlen(seq)) == -1) { /* Can't recover... */ } @@ -437,7 +372,7 @@ failed: /* Clear the screen. Used to handle ctrl+l */ void linenoiseClearScreen(void) { - if (write(STDOUT_FILENO,"\x1b[H\x1b[2J",7) <= 0) { + if (write(STDOUT_FILENO,"\e[H\e[2J",7) <= 0) { /* nothing to do, just to avoid warning. */ } } @@ -445,7 +380,8 @@ void linenoiseClearScreen(void) { /* Beep, used for completion when there is nothing to complete or when all * the choices were already shown. */ static void linenoiseBeep(void) { - fprintf(stderr, "\x7"); + /* NOOOO */ + /* fprintf(stderr, "\x7"); */ fflush(stderr); } @@ -494,11 +430,11 @@ static int completeLine(struct linenoiseState *ls) { return -1; } switch(c) { - case 9: /* tab */ + case '\t': i = (i+1) % (lc.len+1); if (i == lc.len) linenoiseBeep(); break; - case 27: /* escape */ + case '\e': /* Re-show original buffer */ if (i < lc.len) refreshLine(ls); stop = 1; @@ -595,13 +531,13 @@ void refreshShowHints(struct abuf *ab, struct linenoiseState *l, int plen) { if (hintlen > hintmaxlen) hintlen = hintmaxlen; if (bold == 1 && color == -1) color = 37; if (color != -1 || bold != 0) - snprintf(seq,64,"\033[%d;%d;49m",bold,color); + snprintf(seq,64,"\e[%d;%d;49m",bold,color); else seq[0] = '\0'; abAppend(ab,seq,strlen(seq)); abAppend(ab,hint,hintlen); if (color != -1 || bold != 0) - abAppend(ab,"\033[0m",4); + abAppend(ab,"\e[0m",4); /* Call the function to free the hint returned. */ if (freeHintsCallback) freeHintsCallback(hint); } @@ -642,10 +578,10 @@ static void refreshSingleLine(struct linenoiseState *l) { /* Show hits if any. */ refreshShowHints(&ab,l,plen); /* Erase to right */ - snprintf(seq,64,"\x1b[0K"); + snprintf(seq,64,"\e[0K"); abAppend(&ab,seq,strlen(seq)); /* Move cursor to original position. */ - snprintf(seq,64,"\r\x1b[%dC", (int)(pos+plen)); + snprintf(seq,64,"\r\e[%dC", (int)(pos+plen)); abAppend(&ab,seq,strlen(seq)); if (write(fd,ab.b,ab.len) == -1) {} /* Can't recover from write error. */ abFree(&ab); @@ -672,18 +608,18 @@ static void refreshMultiLine(struct linenoiseState *l) { abInit(&ab); if (old_rows-rpos > 0) { lndebug("go down %d", old_rows-rpos); - snprintf(seq,64,"\x1b[%dB", old_rows-rpos); + snprintf(seq,64,"\e[%dB", old_rows-rpos); abAppend(&ab,seq,strlen(seq)); } /* Now for every row clear it, go up. */ for (j = 0; j < old_rows-1; j++) { lndebug("clear+up"); - snprintf(seq,64,"\r\x1b[0K\x1b[1A"); + snprintf(seq,64,"\r\e[0K\e[1A"); abAppend(&ab,seq,strlen(seq)); } /* Clean the top line. */ lndebug("clear"); - snprintf(seq,64,"\r\x1b[0K"); + snprintf(seq,64,"\r\e[0K"); abAppend(&ab,seq,strlen(seq)); /* Write the prompt and the current buffer content */ abAppend(&ab,l->prompt,strlen(l->prompt)); @@ -714,14 +650,14 @@ static void refreshMultiLine(struct linenoiseState *l) { /* Go up till we reach the expected positon. */ if (rows-rpos2 > 0) { lndebug("go-up %d", rows-rpos2); - snprintf(seq,64,"\x1b[%dA", rows-rpos2); + snprintf(seq,64,"\e[%dA", rows-rpos2); abAppend(&ab,seq,strlen(seq)); } /* Set column. */ col = (plen+(int)l->pos) % (int)l->cols; lndebug("set col %d", 1+col); if (col) - snprintf(seq,64,"\r\x1b[%dC", col); + snprintf(seq,64,"\r\e[%dC", col); else snprintf(seq,64,"\r"); abAppend(&ab,seq,strlen(seq)); @@ -778,6 +714,28 @@ void linenoiseEditMoveLeft(struct linenoiseState *l) { } } +/* Move cursor on the left. */ +void linenoiseEditMoveLeftWord(struct linenoiseState *l) { + if (l->pos > 0) { + while (l->pos > 0 && l->buf[l->pos-1] == ' ') + l->pos--; + while (l->pos > 0 && l->buf[l->pos-1] != ' ') + l->pos--; + refreshLine(l); + } +} + +/* Move cursor on the right. */ +void linenoiseEditMoveRightWord(struct linenoiseState *l) { + if (l->pos != l->len) { + while (l->pos < l->len && l->buf[l->pos] == ' ') + l->pos++; + while (l->pos < l->len && l->buf[l->pos] != ' ') + l->pos++; + refreshLine(l); + } +} + /* Move cursor on the right. */ void linenoiseEditMoveRight(struct linenoiseState *l) { if (l->pos != l->len) { @@ -896,15 +854,17 @@ static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen, linenoiseHistoryAdd(""); if (write(l.ofd,prompt,l.plen) == -1) return -1; while(1) { - char c; + int i; + int c; int nread; - char seq[3]; - nread = read(l.ifd,&c,1); + char seq[32]; + nread = readansi(l.ifd,seq,sizeof(seq)); if (nread <= 0) return l.len; + c = seq[0]; /* Only autocomplete when the callback is set. It returns < 0 when * there was an error reading from fd. Otherwise it will return the * character that should be handled next. */ - if (c == 9 && completionCallback != NULL) { + if (c == '\t' && completionCallback) { c = completeLine(&l); /* Return on errors */ if (c < 0) return l.len; @@ -912,7 +872,7 @@ static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen, if (c == 0) continue; } switch(c) { - case ENTER: /* enter */ + case '\r': /* enter */ history_len--; free(history[history_len]); if (mlmode) linenoiseEditMoveEnd(&l); @@ -925,15 +885,15 @@ static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen, hintsCallback = hc; } return (int)l.len; - case CTRL_C: /* ctrl-c */ + case CTRL('C'): errno = EAGAIN; return -1; - case BACKSPACE: /* backspace */ - case 8: /* ctrl-h */ + case CTRL('?'): /* backspace a.k.a. 0177 a.k.a. 127 */ + case CTRL('H'): linenoiseEditBackspace(&l); break; - case CTRL_D: /* ctrl-d, remove char at right of cursor, or if the - line is empty, act as end-of-file. */ + case CTRL('D'): /* remove char at right of cursor, or if the + line is empty, act as end-of-file. */ if (l.len > 0) { linenoiseEditDelete(&l); } else { @@ -942,7 +902,7 @@ static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen, return -1; } break; - case CTRL_T: /* ctrl-t, swaps current character with previous. */ + case CTRL('T'): /* swaps current character with previous. */ if (l.pos > 0 && l.pos < l.len) { int aux = buf[l.pos-1]; buf[l.pos-1] = buf[l.pos]; @@ -951,95 +911,110 @@ static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen, refreshLine(&l); } break; - case CTRL_B: /* ctrl-b */ + case CTRL('B'): linenoiseEditMoveLeft(&l); break; - case CTRL_F: /* ctrl-f */ + case CTRL('F'): linenoiseEditMoveRight(&l); break; - case CTRL_P: /* ctrl-p */ + case CTRL('P'): linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV); break; - case CTRL_N: /* ctrl-n */ + case CTRL('N'): linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT); break; - case ESC: /* escape sequence */ + case '\e': /* escape sequence */ /* Read the next two bytes representing the escape sequence. * Use two calls to handle slow terminals returning the two * chars at different times. */ - if (read(l.ifd,seq,1) == -1) break; - if (read(l.ifd,seq+1,1) == -1) break; - /* ESC [ sequences. */ - if (seq[0] == '[') { - if (seq[1] >= '0' && seq[1] <= '9') { - /* Extended escape, read additional byte. */ - if (read(l.ifd,seq+2,1) == -1) break; - if (seq[2] == '~') { - switch(seq[1]) { - case '3': /* Delete key. */ + if (nread < 2) break; + if (seq[1] == '[') { + if (nread < 3) break; + if (seq[2] >= '0' && seq[2] <= '9') { + if (nread < 4) break; + if (seq[3] == '~') { + switch(seq[2]) { + case '1': /* "\e[1~" is home */ + linenoiseEditMoveHome(&l); + break; + case '3': /* "\e[3~" is delete */ linenoiseEditDelete(&l); break; + case '4': /* "\e[4~" is end */ + linenoiseEditMoveEnd(&l); + break; } } } else { - switch(seq[1]) { - case 'A': /* Up */ + switch(seq[2]) { + case 'A': /* "\e[A" is up */ linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV); break; - case 'B': /* Down */ + case 'B': /* "\e[B" is down */ linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT); break; - case 'C': /* Right */ + case 'C': /* "\e[C" is right */ linenoiseEditMoveRight(&l); break; - case 'D': /* Left */ + case 'D': /* "\e[D" is left */ linenoiseEditMoveLeft(&l); break; - case 'H': /* Home */ + case 'H': /* "\e[H" is home */ linenoiseEditMoveHome(&l); break; - case 'F': /* End*/ + case 'F': /* "\e[F" is end */ linenoiseEditMoveEnd(&l); break; } } } - /* ESC O sequences. */ - else if (seq[0] == 'O') { - switch(seq[1]) { - case 'H': /* Home */ + else if (seq[1] == 'O') { + if (nread < 3) break; + switch(seq[2]) { + case 'H': /* "\eOH" is home */ linenoiseEditMoveHome(&l); break; - case 'F': /* End*/ + case 'F': /* "\eOF" is end */ linenoiseEditMoveEnd(&l); break; } } + else if (seq[1] == 'b') { /* "\eb" is alt-b */ + linenoiseEditMoveLeftWord(&l); + } else if (seq[1] == 'f') { /* "\ef" is alt-f */ + linenoiseEditMoveRightWord(&l); + } break; default: - if (linenoiseEditInsert(&l,c)) return -1; + if (32 <= seq[0] && seq[0] < 127) { + if (linenoiseEditInsert(&l,seq[0])==-1) { + return -1; + } + } break; - case CTRL_U: /* Ctrl+u, delete the whole line. */ + case CTRL('U'): /* delete the whole line */ + /* TODO(jart): delete backwards */ buf[0] = '\0'; l.pos = l.len = 0; refreshLine(&l); break; - case CTRL_K: /* Ctrl+k, delete from current to end of line. */ + case CTRL('K'): /* delete from current to end of line */ + /* TODO(jart): add to kill ring */ buf[l.pos] = '\0'; l.len = l.pos; refreshLine(&l); break; - case CTRL_A: /* Ctrl+a, go to the start of the line */ + case CTRL('A'): /* go to the start of the line */ linenoiseEditMoveHome(&l); break; - case CTRL_E: /* ctrl+e, go to the end of the line */ + case CTRL('E'): /* go to the end of the line */ linenoiseEditMoveEnd(&l); break; - case CTRL_L: /* ctrl+l, clear screen */ + case CTRL('L'): /* clear screen */ linenoiseClearScreen(); refreshLine(&l); break; - case CTRL_W: /* ctrl+w, delete previous word */ + case CTRL('W'): /* delete previous word */ linenoiseEditDeletePrevWord(&l); break; } @@ -1083,7 +1058,7 @@ static int linenoiseRaw(char *buf, size_t buflen, const char *prompt) { if (enableRawMode(STDIN_FILENO) == -1) return -1; count = linenoiseEdit(STDIN_FILENO, STDOUT_FILENO, buf, buflen, prompt); linenoiseDisableRawMode(STDIN_FILENO); - printf("\n"); + if (count != -1) printf("\n"); return count; } @@ -1154,8 +1129,6 @@ void linenoiseFree(void *ptr) { free(ptr); } -/* ================================ History ================================= */ - /* Free the history, but does not reset it. Only used when we have to * exit() to avoid memory leaks are reported by valgrind & co. */ static void freeHistory(void) { diff --git a/third_party/python/Modules/getbuildinfo.c b/third_party/python/Modules/getbuildinfo.c index 426f7ec7c..adad3bea9 100644 --- a/third_party/python/Modules/getbuildinfo.c +++ b/third_party/python/Modules/getbuildinfo.c @@ -38,18 +38,7 @@ const char * Py_GetBuildInfo(void) { - static char buildinfo[50 + sizeof(GITVERSION) + - ((sizeof(GITTAG) > sizeof(GITBRANCH)) ? - sizeof(GITTAG) : sizeof(GITBRANCH))]; - const char *revision = _Py_gitversion(); - const char *sep = *revision ? ":" : ""; - const char *gitid = _Py_gitidentifier(); - if (!(*gitid)) - gitid = "default"; - PyOS_snprintf(buildinfo, sizeof(buildinfo), - "%s%s%s, %.20s, %.9s", gitid, sep, revision, - DATE, TIME); - return buildinfo; + return "cosmopolitan"; } const char * diff --git a/third_party/python/Modules/getpath.c b/third_party/python/Modules/getpath.c index 46b6d0214..697d079bd 100644 --- a/third_party/python/Modules/getpath.c +++ b/third_party/python/Modules/getpath.c @@ -492,7 +492,6 @@ calculate_path(void) if(IsWindows()) { - fprintf(stderr, "python APE on Windows\n"); delimiter[0] = L';'; separator[0] = L'\\'; } diff --git a/third_party/python/Programs/python.c b/third_party/python/Programs/python.c index 7b88f8c56..082feb1dd 100644 --- a/third_party/python/Programs/python.c +++ b/third_party/python/Programs/python.c @@ -7,17 +7,24 @@ #include "libc/calls/calls.h" #include "libc/errno.h" #include "libc/log/check.h" +#include "libc/log/log.h" +#include "libc/mem/mem.h" #include "libc/runtime/runtime.h" #include "libc/stdio/stdio.h" +#include "libc/str/str.h" #include "libc/sysv/consts/fileno.h" #include "libc/sysv/consts/sig.h" #include "libc/unicode/locale.h" #include "third_party/linenoise/linenoise.h" +#include "third_party/python/Include/ceval.h" +#include "third_party/python/Include/dictobject.h" #include "third_party/python/Include/fileutils.h" +#include "third_party/python/Include/import.h" #include "third_party/python/Include/pylifecycle.h" #include "third_party/python/Include/pymem.h" #include "third_party/python/Include/pyport.h" #include "third_party/python/Include/pythonrun.h" +#include "third_party/python/Include/unicodeobject.h" /* clang-format off */ static jmp_buf jbuf; @@ -28,6 +35,77 @@ OnKeyboardInterrupt(int sig) longjmp(jbuf, 1); } +static PyObject * +GetMember(const char *s, Py_ssize_t n, PyObject *o) +{ + const char *t; + PyObject *k, *v; + Py_ssize_t i, m; + if (!o) return 0; + for (i = 0; PyDict_Next(o, &i, &k, &v);) { + if (v != Py_None && PyUnicode_Check(k)) { + t = PyUnicode_AsUTF8AndSize(k, &m); + printf("\r%`'.*s vs. %`'.*s\n", n, s, m, t); + if (n == m && !memcmp(s, t, n)) { + Py_INCREF(v); + return v; + } + } + } + return 0; +} + +static PyObject * +GetVar(const char *s, Py_ssize_t n) +{ + PyObject *o; + /* + * TODO: Why doesn't PyEval_GetLocals() work? + */ + if ((o = GetMember(s, n, PyEval_GetLocals()))) return o; + if ((o = GetMember(s, n, PyEval_GetGlobals()))) return o; + if ((o = GetMember(s, n, PyEval_GetBuiltins()))) return o; + return 0; +} + +static void +TerminalComplete(const char *s, linenoiseCompletions *c, PyObject *o) +{ + const char *t; + PyObject *k, *v; + Py_ssize_t i, n, m; + if (!o) return; + for (n = strlen(s), i = 0; PyDict_Next(o, &i, &k, &v);) { + if (v != Py_None && PyUnicode_Check(k)) { + t = PyUnicode_AsUTF8AndSize(k, &m); + if (m > n && !memcmp(t, s, n)) { + c->cvec = realloc(c->cvec, ++c->len * sizeof(*c->cvec)); + c->cvec[c->len - 1] = strdup(t); + } + } + } +} + +static void +TerminalCompletion(const char *s, linenoiseCompletions *c) +{ + const char *p; + PyObject *o, *q; + if ((p = strchr(s, '.'))) { + if (!(o = GetVar(s, p - s))) return; + for (s = p + 1; (p = strchr(s, '.')); o = q) { + if ((q = GetMember(s, p - s, o))) return; + Py_DECREF(o); + } + TerminalComplete(s, c, o); + Py_DECREF(o); + } else { + TerminalComplete(s, c, PyEval_GetLocals()); + TerminalComplete(s, c, PyEval_GetGlobals()); + TerminalComplete(s, c, PyEval_GetBuiltins()); + } +} + char * TerminalReadline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt) { @@ -66,6 +144,8 @@ main(int argc, char **argv) int i, res; char *oldloc; + showcrashreports(); + linenoiseSetCompletionCallback(TerminalCompletion); PyOS_ReadlineFunctionPointer = TerminalReadline; /* Force malloc() allocator to bootstrap Python */ diff --git a/third_party/python/Python/pylifecycle.c b/third_party/python/Python/pylifecycle.c index ec5e5bcc5..1847c3b68 100644 --- a/third_party/python/Python/pylifecycle.c +++ b/third_party/python/Python/pylifecycle.c @@ -14,6 +14,7 @@ #include "libc/log/log.h" #include "libc/runtime/runtime.h" #include "libc/stdio/stdio.h" +#include "libc/sysv/consts/sig.h" #include "libc/unicode/locale.h" #include "third_party/python/Include/Python-ast.h" #include "third_party/python/Include/abstract.h" diff --git a/tool/build/lib/psk.c b/tool/build/lib/psk.c index 5c2d84186..b1b08b6a0 100644 --- a/tool/build/lib/psk.c +++ b/tool/build/lib/psk.c @@ -16,15 +16,11 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/calls.h" #include "libc/calls/struct/stat.h" -#include "libc/dce.h" -#include "libc/fmt/fmt.h" #include "libc/log/check.h" -#include "libc/mem/mem.h" -#include "libc/runtime/runtime.h" -#include "libc/stdio/stdio.h" +#include "libc/runtime/gc.internal.h" #include "libc/sysv/consts/o.h" +#include "libc/x/x.h" #include "tool/build/lib/psk.h" /** @@ -32,23 +28,9 @@ */ void *GetRunitPsk(void) { int fd; + char *r, *p; struct stat st; - const char *a, *b; - char *r, p[PATH_MAX + 1]; - if ((a = getenv("HOME"))) { - b = ""; - } else if (IsWindows()) { - a = getenv("HOMEDRIVE"); - b = getenv("HOMEPATH"); - if (!a || !b) { - a = "C:"; - b = ""; - } - } else { - fprintf(stderr, "need $HOME\n"); - exit(1); - } - snprintf(p, sizeof(p), "%s%s/.runit.psk", a, b); + p = gc(xasprintf("%s/.runit.psk", gc(xhomedir()))); if (stat(p, &st) == -1 || st.st_size != 32) { fprintf(stderr, "need o//examples/getrandom.com -bn32 >~/.runit.psk\n"); exit(1); diff --git a/tool/viz/printvideo.c b/tool/viz/printvideo.c index 9da3fefd9..b899349c6 100644 --- a/tool/viz/printvideo.c +++ b/tool/viz/printvideo.c @@ -1216,6 +1216,27 @@ static optimizesize void ReadKeyboard(void) { case 'S': /* \eOS is F4 */ pf4_ = !pf4_; break; + case 'T': /* \eOT is F5 */ + pf5_ = !pf5_; + break; + case 'U': /* \eOU is F6 */ + pf6_ = !pf6_; + break; + case 'V': /* \eOV is F7 */ + pf7_ = !pf7_; + break; + case 'W': /* \eOW is F8 */ + pf8_ = !pf8_; + break; + case 'Y': /* \eOY is F10 */ + pf10_ = !pf10_; + break; + case 'Z': /* \eOZ is F11 */ + pf11_ = !pf11_; + break; + case '[': /* \eO[ is F12 */ + pf12_ = !pf12_; + break; default: break; }