#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. 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]; 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("$ "); /* 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; 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); } } }