diff options
Diffstat (limited to 'c')
| -rw-r--r-- | c/gbos.h | 8 | ||||
| -rw-r--r-- | c/libc.s | 67 | ||||
| -rw-r--r-- | c/sh.c | 99 |
3 files changed, 158 insertions, 16 deletions
@@ -30,4 +30,12 @@ void fremove(const char *name); #define O_READ 0 #define O_WRITE 1 #define NOFD 0xFF + +/* process control (c/libc.s) */ +unsigned char fork(void); +void exec(unsigned char id); /* replace image; never returns */ +unsigned char wait(void); +void setin(unsigned char fd); /* redirect stdin ($FF=console) */ +void setout(unsigned char fd); /* redirect stdout ($FF=console) */ +unsigned char lookup(const char *name); /* command name -> program id */ #endif @@ -25,11 +25,11 @@ _getargs: ld c, l ret - ;; void putc(char c /*A*/) + ;; void putc(char c /*A*/) -> stdout via SYS_PUTC _putc: - ld (0xff01), a - ld a, #0x81 - ld (0xff02), a + ld e, a + ld c, #16 ; SYS_PUTC + rst #0x30 ret ;; void puts(const char *s /*DE*/) - write until NUL (no newline) @@ -37,22 +37,22 @@ _puts: 1$: ld a, (de) or a ret z - ld (0xff01), a - ld a, #0x81 - ld (0xff02), a + push de + ld e, a + ld c, #16 ; SYS_PUTC + rst #0x30 + pop de inc de jr 1$ - ;; void nl(void) - CRLF + ;; void nl(void) - CRLF via stdout _nl: - ld a, #0x0d - ld (0xff01), a - ld a, #0x81 - ld (0xff02), a - ld a, #0x0a - ld (0xff01), a - ld a, #0x81 - ld (0xff02), a + ld e, #0x0d + ld c, #16 ; SYS_PUTC + rst #0x30 + ld e, #0x0a + ld c, #16 + rst #0x30 ret ;; unsigned char strlen(const char *s /*DE*/) -> A @@ -132,3 +132,38 @@ _fremove: ld c, #15 ; SYS_REMOVE rst #0x30 ret + + .globl _fork, _exec, _wait, _setin, _setout, _lookup + ;; unsigned char fork(void) -> A (child pid in parent, 0 in child) +_fork: + ld c, #1 ; SYS_FORK + rst #0x30 + ret + ;; void exec(unsigned char id /*A*/) - never returns +_exec: + ld b, a + ld c, #6 ; SYS_EXEC + rst #0x30 + ret + ;; unsigned char wait(void) -> A (reaped pid) +_wait: + ld c, #7 ; SYS_WAIT + rst #0x30 + ret + ;; void setin(unsigned char fd /*A*/) +_setin: + ld b, a + ld c, #17 ; SYS_SETIN + rst #0x30 + ret + ;; void setout(unsigned char fd /*A*/) +_setout: + ld b, a + ld c, #18 ; SYS_SETOUT + rst #0x30 + ret + ;; unsigned char lookup(const char *name /*DE*/) -> A (prog id or $FF) +_lookup: + ld c, #19 ; SYS_LOOKUP + rst #0x30 + ret @@ -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); + } + } +} |
