aboutsummaryrefslogtreecommitdiffstats
path: root/c
diff options
context:
space:
mode:
Diffstat (limited to 'c')
-rw-r--r--c/gbos.h8
-rw-r--r--c/libc.s67
-rw-r--r--c/sh.c99
3 files changed, 158 insertions, 16 deletions
diff --git a/c/gbos.h b/c/gbos.h
index d8c8eb3..fa926fd 100644
--- a/c/gbos.h
+++ b/c/gbos.h
@@ -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
diff --git a/c/libc.s b/c/libc.s
index a26042e..857a16d 100644
--- a/c/libc.s
+++ b/c/libc.s
@@ -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
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);
+ }
+ }
+}