#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); } void main(void) { char line[80]; char *tok[16]; char cwd[40]; cwd[0] = '/'; cwd[1] = 0; 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) { unsigned char pw = open("__pipe", O_WRITE); run(tok, 0, pipepos, NOFD, pw, 0); close(pw); { unsigned char pr = open("__pipe", O_READ); run(tok, pipepos + 1, nt, pr, NOFD, 0); close(pr); } fremove("__pipe"); } else { run(tok, 0, nt, NOFD, NOFD, bg); } } }