aboutsummaryrefslogtreecommitdiffstats
path: root/c/sh.c
diff options
context:
space:
mode:
Diffstat (limited to 'c/sh.c')
-rw-r--r--c/sh.c99
1 files changed, 99 insertions, 0 deletions
diff --git a/c/sh.c b/c/sh.c
new file mode 100644
index 0000000..c24ed9f
--- /dev/null
+++ b/c/sh.c
@@ -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);
+ }
+ }
+}