diff options
Diffstat (limited to 'c/sh.c')
| -rw-r--r-- | c/sh.c | 99 |
1 files changed, 99 insertions, 0 deletions
@@ -0,0 +1,99 @@ +#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; } + +/* 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. */ +static void run(char **tok, unsigned char start, unsigned char end, + unsigned char infd, unsigned char outfd) { + 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); + } + wait(); +done: + if (myin != NOFD) close(myin); + if (myout != NOFD) close(myout); +} + +void main(void) { + char line[80]; + char *tok[16]; + for (;;) { + unsigned char nt, i, pipepos, c; + puts("$ "); + /* read a line (echoing), stop at newline; exit on EOF */ + i = 0; + for (;;) { + c = readc(); + if (c == EOF) return; + if (c == '\r' || c == '\n') { nl(); break; } + if (i < 79) { line[i++] = c; putc(c); } + } + line[i] = 0; + nt = tokenize(line, tok, 16); + if (nt == 0) continue; + pipepos = 0; + for (i = 1; i < nt; i++) + if (isop(tok[i], '|')) { pipepos = i; break; } + if (pipepos) { + unsigned char pw = open("__pipe", O_WRITE); + run(tok, 0, pipepos, NOFD, pw); + close(pw); + { unsigned char pr = open("__pipe", O_READ); + run(tok, pipepos + 1, nt, pr, NOFD); + close(pr); } + fremove("__pipe"); + } else { + run(tok, 0, nt, NOFD, NOFD); + } + } +} |
