mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-31 09:42:27 +00:00
Make improvements
- Get threads working on NetBSD - Get threads working on OpenBSD - Fix Emacs config for Emacs v28 - Improve --strace logging of sigset_t - Improve --strace logging of struct stat - Improve memory safety of DescribeThing functions - Refactor auto stack allocation into LIBC_RUNTIME - Introduce shell.com example which works on Windows - Refactor __strace_thing into DescribeThing functions - Document the CHECK macros and improve them in NDEBUG mode - Rewrite MAP_STACK so it uses FreeBSD behavior across platforms - Deprecate and discourage the use of MAP_GROWSDOWN (it's weird)
This commit is contained in:
parent
dd9ab01d25
commit
e7611a8476
101 changed files with 967 additions and 464 deletions
172
examples/shell.c
Normal file
172
examples/shell.c
Normal file
|
@ -0,0 +1,172 @@
|
|||
#if 0
|
||||
/*─────────────────────────────────────────────────────────────────╗
|
||||
│ To the extent possible under law, Justine Tunney has waived │
|
||||
│ all copyright and related or neighboring rights to this file, │
|
||||
│ as it is written in the following disclaimers: │
|
||||
│ • http://unlicense.org/ │
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/sigbits.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/log/internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/dt.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "third_party/linenoise/linenoise.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Shell that works on Windows.
|
||||
*
|
||||
* This doesn't have script language features like UNBOURNE.COM but it
|
||||
* works on Windows and, unlike CMD.EXE, actually has CTRL-P and CTRL-R
|
||||
* which alone make it so much better.
|
||||
*
|
||||
* One day we'll have UNBOURNE.COM working on Windows but the code isn't
|
||||
* very maintainable sadly.
|
||||
*/
|
||||
|
||||
static void AddUniqueCompletion(linenoiseCompletions *c, char *s) {
|
||||
size_t i;
|
||||
if (!s) return;
|
||||
for (i = 0; i < c->len; ++i) {
|
||||
if (!strcmp(s, c->cvec[i])) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
c->cvec = realloc(c->cvec, ++c->len * sizeof(*c->cvec));
|
||||
c->cvec[c->len - 1] = s;
|
||||
}
|
||||
|
||||
static void CompleteFilename(const char *p, const char *q, const char *b,
|
||||
linenoiseCompletions *c) {
|
||||
DIR *d;
|
||||
char *buf;
|
||||
const char *g;
|
||||
struct dirent *e;
|
||||
if ((buf = malloc(512))) {
|
||||
if ((g = memrchr(p, '/', q - p))) {
|
||||
*(char *)mempcpy(buf, p, MIN(g - p, 511)) = 0;
|
||||
p = ++g;
|
||||
} else {
|
||||
strcpy(buf, ".");
|
||||
}
|
||||
if ((d = opendir(buf))) {
|
||||
while ((e = readdir(d))) {
|
||||
if (!strcmp(e->d_name, ".")) continue;
|
||||
if (!strcmp(e->d_name, "..")) continue;
|
||||
if (!strncmp(e->d_name, p, q - p)) {
|
||||
snprintf(buf, 512, "%.*s%s%s", p - b, b, e->d_name,
|
||||
e->d_type == DT_DIR ? "/" : "");
|
||||
AddUniqueCompletion(c, strdup(buf));
|
||||
}
|
||||
}
|
||||
closedir(d);
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
}
|
||||
|
||||
static void ShellCompletion(const char *p, linenoiseCompletions *c) {
|
||||
bool slashed;
|
||||
const char *q, *b;
|
||||
for (slashed = false, b = p, q = (p += strlen(p)); p > b; --p) {
|
||||
if (p[-1] == '/' && p[-1] == '\\') slashed = true;
|
||||
if (!isalnum(p[-1]) &&
|
||||
(p[-1] != '.' && p[-1] != '_' && p[-1] != '-' && p[-1] != '+' &&
|
||||
p[-1] != '[' && p[-1] != '/' && p[-1] != '\\')) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
CompleteFilename(p, q, b, c);
|
||||
}
|
||||
|
||||
static char *ShellHint(const char *p, const char **ansi1, const char **ansi2) {
|
||||
char *h = 0;
|
||||
linenoiseCompletions c = {0};
|
||||
ShellCompletion(p, &c);
|
||||
if (c.len == 1) {
|
||||
h = strdup(c.cvec[0] + strlen(p));
|
||||
}
|
||||
linenoiseFreeCompletions(&c);
|
||||
return h;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int n, ws, pid;
|
||||
char *prog, path[PATH_MAX];
|
||||
sigset_t chldmask, savemask;
|
||||
struct sigaction ignore, saveint, savequit;
|
||||
char *p, *line, **args, *arg, *start, *state, prompt[64];
|
||||
linenoiseSetFreeHintsCallback(free);
|
||||
linenoiseSetHintsCallback(ShellHint);
|
||||
linenoiseSetCompletionCallback(ShellCompletion);
|
||||
stpcpy(prompt, "$ ");
|
||||
while ((line = linenoiseWithHistory(prompt, "cmd"))) {
|
||||
n = 0;
|
||||
start = line;
|
||||
args = xcalloc(1, sizeof(*args));
|
||||
while ((arg = strtok_r(start, " \t\r\n", &state))) {
|
||||
args = xrealloc(args, (++n + 1) * sizeof(*args));
|
||||
args[n - 1] = arg;
|
||||
args[n - 0] = 0;
|
||||
start = 0;
|
||||
}
|
||||
if (n > 0) {
|
||||
if ((prog = commandv(args[0], path, sizeof(path)))) {
|
||||
ignore.sa_flags = 0;
|
||||
ignore.sa_handler = SIG_IGN;
|
||||
sigemptyset(&ignore.sa_mask);
|
||||
sigaction(SIGINT, &ignore, &saveint);
|
||||
sigaction(SIGQUIT, &ignore, &savequit);
|
||||
sigemptyset(&chldmask);
|
||||
sigaddset(&chldmask, SIGCHLD);
|
||||
sigprocmask(SIG_BLOCK, &chldmask, &savemask);
|
||||
|
||||
if (!fork()) {
|
||||
sigaction(SIGINT, &saveint, 0);
|
||||
sigaction(SIGQUIT, &savequit, 0);
|
||||
sigprocmask(SIG_SETMASK, &savemask, 0);
|
||||
execv(prog, args);
|
||||
_Exit(127);
|
||||
}
|
||||
|
||||
wait(&ws);
|
||||
p = prompt;
|
||||
if (WIFEXITED(ws)) {
|
||||
if (WEXITSTATUS(ws)) {
|
||||
if (!__nocolor) p = stpcpy(p, "\e[1;31m");
|
||||
p = stpcpy(p, "rc=");
|
||||
p = FormatInt32(p, WEXITSTATUS(ws));
|
||||
if (!__nocolor) p = stpcpy(p, "\e[0m");
|
||||
*p++ = ' ';
|
||||
}
|
||||
} else {
|
||||
if (!__nocolor) p = stpcpy(p, "\e[1;31m");
|
||||
p = stpcpy(p, "rc=");
|
||||
p = stpcpy(p, strsignal(WTERMSIG(ws)));
|
||||
if (!__nocolor) p = stpcpy(p, "\e[0m");
|
||||
*p++ = ' ';
|
||||
}
|
||||
p = stpcpy(p, "$ ");
|
||||
|
||||
sigaction(SIGINT, &saveint, 0);
|
||||
sigaction(SIGQUIT, &savequit, 0);
|
||||
sigprocmask(SIG_SETMASK, &savemask, 0);
|
||||
} else {
|
||||
fprintf(stderr, "%s: %s: command not found\n", argv[0], args[0]);
|
||||
}
|
||||
}
|
||||
free(line);
|
||||
free(args);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue