diff options
| author | user <user@clank> | 2026-07-18 00:38:38 +0200 |
|---|---|---|
| committer | user <user@clank> | 2026-07-18 00:38:38 +0200 |
| commit | ba2d7ae1d7b319645b10aaa31a7f664f9f80c25c (patch) | |
| tree | e01e6c7c710a661defe2515ff9657f08cddcb283 /c/sh.c | |
| parent | tools: gbtype prints hub errors to stderr and exits 1 (diff) | |
| download | gbos-ba2d7ae1d7b319645b10aaa31a7f664f9f80c25c.tar.gz gbos-ba2d7ae1d7b319645b10aaa31a7f664f9f80c25c.tar.xz gbos-ba2d7ae1d7b319645b10aaa31a7f664f9f80c25c.zip | |
refactor: c/ -> usr/, compiled program blobs out of the source tree
Userland sources live in usr/ (fits the Unix theme better than 'c').
SDCC output .bin blobs land in build/usr/ with the other build artifacts
instead of littering the source dir; programs.asm INCBINs them from there.
Byte-identical ROM.
Diffstat (limited to 'c/sh.c')
| -rw-r--r-- | c/sh.c | 200 |
1 files changed, 0 insertions, 200 deletions
@@ -1,200 +0,0 @@ -#include "gbos.h" -/* gbos shell: prompt -> read a line -> parse -> run, with I/O redirection - ( > file, < file ) and pipes ( cmd1 | cmd2, via a temp file ). - Operators must be space-separated (e.g. cat readme > out ). */ - -#define ARGV0 ((char *)0xA000) /* where a child reads its command line */ - -/* split s into space-separated tokens (NUL-terminated in place). */ -static unsigned char tokenize(char *s, char **tok, unsigned char max) { - unsigned char n = 0; - for (;;) { - while (*s == ' ') *s++ = 0; - if (*s == 0) break; - if (n < max) tok[n++] = s; - while (*s && *s != ' ') s++; - } - return n; -} - -static unsigned char isop(char *t, char c) { return t[0] == c && t[1] == 0; } -static unsigned char iscmd(char *t, char a, char b) { - return t[0] == a && t[1] == b && t[2] == 0; -} - -/* keep the prompt's path string roughly in sync with chdir(). */ -static void set_cwd(char *cwd, char *arg) { - char *d, *s, *last; - if (arg[0] == '/') { /* absolute */ - d = cwd; s = arg; - while (*s) *d++ = *s++; - *d = 0; - } else if (arg[0] == '.' && arg[1] == '.' && arg[2] == 0) { - last = cwd; d = cwd; - while (*d) { if (*d == '/') last = d; d++; } - if (last == cwd) { cwd[0] = '/'; cwd[1] = 0; } else *last = 0; - } else if (arg[0] == '.' && arg[1] == 0) { - /* stay */ - } else { /* relative: append */ - d = cwd; while (*d) d++; - if (!(cwd[0] == '/' && cwd[1] == 0)) *d++ = '/'; - s = arg; while (*s) *d++ = *s++; - *d = 0; - } -} - -/* build the child command line "name\0arg1 arg2\0" at 0xA000 */ -static void set_cmdline(char **tok, unsigned char start, unsigned char end) { - char *p = ARGV0, *t; - unsigned char i; - t = tok[start]; - while (*t) *p++ = *t++; - *p++ = 0; /* NUL after the command word */ - for (i = start + 1; i < end; i++) { - if (i > start + 1) *p++ = ' '; - t = tok[i]; - while (*t) *p++ = *t++; - } - *p = 0; -} - -/* run tok[start..end): parse its own >/< redirects, honor forced in/out. - If bg, launch in the background (don't wait; leave fds to the child). */ -static void run(char **tok, unsigned char start, unsigned char end, - unsigned char infd, unsigned char outfd, unsigned char bg) { - unsigned char i, cmdend = end, myin = NOFD, myout = NOFD, id, pid; - for (i = start; i < end; i++) { - if (isop(tok[i], '>')) { - if (i + 1 < end) myout = open(tok[i + 1], O_WRITE); - if (i < cmdend) cmdend = i; - } else if (isop(tok[i], '<')) { - if (i + 1 < end) myin = open(tok[i + 1], O_READ); - if (i < cmdend) cmdend = i; - } - } - id = lookup(tok[start]); - if (id == NOFD) { puts(tok[start]); puts(": not found"); nl(); goto done; } - set_cmdline(tok, start, cmdend); - pid = fork(); - if (pid == 0) { - if (myin != NOFD) setin(myin); - else if (infd != NOFD) setin(infd); - if (myout != NOFD) setout(myout); - else if (outfd != NOFD) setout(outfd); - exec(id); - } - if (bg) { putc('['); putu(pid); puts("]"); nl(); return; } /* background */ - /* wait for THIS child; report any background jobs that finish meanwhile */ - for (;;) { - unsigned char r = wait(); - if (r == pid || r == NOFD) break; - putc('['); putu(r); puts(" done]"); nl(); - } -done: - if (myin != NOFD) close(myin); - if (myout != NOFD) close(myout); -} - -/* run a multi-stage pipeline (a | b | c): wire stages together with real - kernel pipes, launch them ALL concurrently, then wait for them. */ -static void run_pipeline(char **tok, unsigned char nt) { - unsigned char pids[8], npid = 0; - unsigned char cfd[8], ncfd = 0; /* file-redirect fds; closed after all exit */ - unsigned char start = 0, prev_r = NOFD; - for (;;) { - unsigned char end = start, last, i, cmdend, fin = NOFD, fout = NOFD; - unsigned char my_out = NOFD, next_r = NOFD, id, pid; - while (end < nt && !isop(tok[end], '|')) end++; - last = (end >= nt); - if (!last) { /* pipe from this stage to the next */ - unsigned char pr = pipe(); - if (pr != NOFD) { next_r = pr; my_out = pr + 1; } - } - cmdend = end; /* this stage's own >/< redirects */ - for (i = start; i < end; i++) { - if (isop(tok[i], '>')) { if (i + 1 < end) fout = open(tok[i+1], O_WRITE); if (i < cmdend) cmdend = i; } - else if (isop(tok[i], '<')) { if (i + 1 < end) fin = open(tok[i+1], O_READ); if (i < cmdend) cmdend = i; } - } - id = lookup(tok[start]); - if (id == NOFD) { - puts(tok[start]); puts(": not found"); nl(); - if (prev_r != NOFD) close(prev_r); /* orphaned pipe ends -> EOF/EPIPE */ - if (my_out != NOFD) close(my_out); - if (fin != NOFD) close(fin); - if (fout != NOFD) close(fout); - } else { - set_cmdline(tok, start, cmdend); - pid = fork(); - if (pid == 0) { - if (fin != NOFD) setin(fin); else if (prev_r != NOFD) setin(prev_r); - if (fout != NOFD) setout(fout); else if (my_out != NOFD) setout(my_out); - exec(id); - } - if (npid < 8) pids[npid++] = pid; - if (fin != NOFD && ncfd < 8) cfd[ncfd++] = fin; - if (fout != NOFD && ncfd < 8) cfd[ncfd++] = fout; - } - prev_r = next_r; - if (last) break; - start = end + 1; - } - { unsigned char got = 0; /* wait for all stages */ - while (got < npid) { - unsigned char r = wait(), j, mine = 0; - if (r == NOFD) break; - for (j = 0; j < npid; j++) if (pids[j] == r) { mine = 1; break; } - if (mine) got++; - else { putc('['); putu(r); puts(" done]"); nl(); } - } - } - { unsigned char k; for (k = 0; k < ncfd; k++) close(cfd[k]); } -} - -void main(void) { - char line[80]; - char *tok[16]; - char cwd[40]; - cwd[0] = '/'; cwd[1] = 0; - /* bring up networking first: run the DHCP client and wait for it to finish - (got a lease, or gave up). Only then drop to the prompt. */ - { - unsigned char d = lookup("dhcp"); - if (d != NOFD) { if (fork() == 0) exec(d); else wait(); } - } - for (;;) { - unsigned char nt, i, pipepos, c, bg; - /* reap finished background jobs */ - { unsigned char p; while ((p = reap())) { putc('['); putu(p); puts(" done]"); nl(); } } - puts(cwd); puts("# "); - /* read a line (echoing), stop at newline; exit on EOF */ - i = 0; - for (;;) { - c = readc(); - if (c == EOF) poweroff(); - if (c == '\r' || c == '\n') { nl(); break; } - if (c == 8 || c == 127) { /* backspace: drop last char */ - if (i > 0) { i--; putc(8); } - continue; - } - if (i < 79) { line[i++] = c; putc(c); } - } - line[i] = 0; - nt = tokenize(line, tok, 16); - if (nt == 0) continue; - if (iscmd(tok[0], 'c', 'd')) { /* cd builtin */ - char *arg = (nt >= 2) ? tok[1] : "/"; - if (chdir(arg) == 0) set_cwd(cwd, arg); - else { puts("cd: no such directory"); nl(); } - continue; - } - if ((tok[0][0] == 'e' && tok[0][1] == 'x') || - (tok[0][0] == 'q' && tok[0][1] == 'u')) poweroff(); - bg = 0; - if (isop(tok[nt - 1], '&')) { bg = 1; nt--; if (nt == 0) continue; } - pipepos = 0; - for (i = 1; i < nt; i++) - if (isop(tok[i], '|')) { pipepos = i; break; } - if (pipepos) run_pipeline(tok, nt); - else run(tok, 0, nt, NOFD, NOFD, bg); - } -} |
