diff options
| author | user <user@clank> | 2026-07-16 07:53:19 +0200 |
|---|---|---|
| committer | user <user@clank> | 2026-07-16 07:53:19 +0200 |
| commit | 7b5c532625a864a3fbaf76f44df6aa99b0d6861e (patch) | |
| tree | 6a6d67644993ccaea4b71bdc0881798887a6d1aa /c | |
| parent | libc: option parsing (hasflag/optval); wc -l/-w/-c, head -n N (diff) | |
| download | gbos-7b5c532625a864a3fbaf76f44df6aa99b0d6861e.tar.gz gbos-7b5c532625a864a3fbaf76f44df6aa99b0d6861e.tar.xz gbos-7b5c532625a864a3fbaf76f44df6aa99b0d6861e.zip | |
filesystem: a RAM FS (WRAMX) + ls/cat/save/rm; wc/head read files
- fs.asm: 8-slot RAM filesystem in WRAMX ($D000-$DFFF), name[8]+len[2]+data[502];
syscalls open/close/getb/putb/list/remove, seeded with a 'readme' at boot.
- libc: open/close/fgetc/fputc/flist/fremove wrappers + O_READ/O_WRITE/NOFD.
- tools: ls, save (stdin->file, one line), rm; cat/wc/head now take a file arg.
- fix: syscall dispatch clobbers A, so putb takes its byte in E (was reading the
handler's low address byte, 0xDC); ls NUL-terminates 8-char names.
- verified: save/cat/ls/rm cycle; wc readme -> '2 7 38'; head -n 1 readme.
- README: document the filesystem + the A-clobber ABI note.
Diffstat (limited to '')
| -rw-r--r-- | c/cat.c | 18 | ||||
| -rw-r--r-- | c/gbos.h | 11 | ||||
| -rw-r--r-- | c/head.c | 27 | ||||
| -rw-r--r-- | c/libc.s | 48 | ||||
| -rw-r--r-- | c/ls.c | 9 | ||||
| -rw-r--r-- | c/rm.c | 7 | ||||
| -rw-r--r-- | c/save.c | 19 | ||||
| -rw-r--r-- | c/wc.c | 21 |
8 files changed, 139 insertions, 21 deletions
@@ -1,10 +1,16 @@ #include "gbos.h" -/* cat: copy stdin to stdout until EOF (Ctrl-D / pipe end). */ +/* cat [file]: print a file, or copy stdin to stdout until EOF. */ void main(void) { - char c; - for (;;) { - c = readc(); - if (c == EOF) break; - putc(c); + char *argv[4]; + unsigned char argc = argv_parse(argv, 4); + if (argc > 0) { + unsigned char fd = open(argv[0], O_READ); + int ch; + if (fd == NOFD) { puts("cat: no such file"); nl(); return; } + while ((ch = fgetc(fd)) >= 0) putc((char)ch); + close(fd); + } else { + char c; + for (;;) { c = readc(); if (c == EOF) break; putc(c); } } } @@ -19,4 +19,15 @@ unsigned char atou(const char *s); /* parse decimal */ unsigned char argv_parse(char **argv, unsigned char maxv); /* argc/argv */ unsigned char hasflag(char **argv, unsigned char argc, char f); /* -x flag */ char *optval(char **argv, unsigned char argc, char opt); /* -x VALUE */ + +/* filesystem (c/libc.s -> kernel syscalls) */ +unsigned char open(const char *name, unsigned char mode); /* 0=read 1=write */ +void close(unsigned char fd); +int fgetc(unsigned char fd); /* a byte, or -1 at EOF */ +void fputc(unsigned char fd, char ch); +unsigned char flist(unsigned char slot, char *namebuf); /* 1 if slot used */ +void fremove(const char *name); +#define O_READ 0 +#define O_WRITE 1 +#define NOFD 0xFF #endif @@ -1,17 +1,28 @@ #include "gbos.h" -/* head [-n N] [N]: print the first N lines of stdin (default 10). */ +/* head [-n N] [N] [file]: first N lines of a file or stdin (default 10). */ void main(void) { char *argv[8]; unsigned char argc = argv_parse(argv, 8); char *nv = optval(argv, argc, 'n'); - unsigned char n = 10, lines = 0; - char c; + unsigned char n = 10, lines = 0, i, fd = NOFD; + char *fname = 0; + int ch; if (nv) n = atou(nv); - else if (argc > 0 && argv[0][0] >= '0' && argv[0][0] <= '9') n = atou(argv[0]); + for (i = 0; i < argc; i++) { + if (argv[i][0] == '-') continue; + if (nv == argv[i]) continue; + if (!nv && argv[i][0] >= '0' && argv[i][0] <= '9') { n = atou(argv[i]); continue; } + fname = argv[i]; break; + } + if (fname) { + fd = open(fname, O_READ); + if (fd == NOFD) { puts("head: no such file"); nl(); return; } + } for (;;) { - c = readc(); - if (c == EOF) break; - if (lines < n) putc(c); - if (c == '\n') lines++; + if (fd == NOFD) { char c = readc(); if (c == EOF) break; ch = c; } + else { ch = fgetc(fd); if (ch < 0) break; } + if (lines < n) putc((char)ch); + if (ch == '\n') lines++; } + if (fd != NOFD) close(fd); } @@ -1,5 +1,6 @@ .module libc .globl _writes, _putc, _puts, _nl, _strlen, _readc, _sexit, _getpid, _getargs + .globl _open, _close, _fgetc, _fputc, _flist, _fremove ;; SDCC sm83 sdcccall(1): 1st arg -> A (byte) or DE (pointer); ret A / BC. ;; rst $30 (the trap) clobbers BC/DE/HL; SDCC treats them caller-saved, so ;; wrappers need not preserve them - but we compute cleanly regardless. @@ -84,3 +85,50 @@ _getpid: ld c, #8 ; SYS_GETPID rst #0x30 ret + + ;; unsigned char open(const char *name /*DE*/, unsigned char mode /*A*/) -> A(fd) +_open: + ld b, a ; B = mode + ld c, #4 ; SYS_OPEN + rst #0x30 + ret + + ;; void close(unsigned char fd /*A*/) +_close: + ld b, a + ld c, #5 ; SYS_CLOSE + rst #0x30 + ret + + ;; int fgetc(unsigned char fd /*A*/) -> BC (byte, or -1 at EOF) +_fgetc: + ld b, a + ld c, #12 ; SYS_GETB + rst #0x30 + jr c, 1$ + ld c, a + ld b, #0 + ret +1$: ld bc, #0xffff + ret + + ;; void fputc(unsigned char fd /*A*/, char ch /*E*/) + ;; byte goes to the kernel in E (the trap clobbers A during dispatch) +_fputc: + ld b, a ; B = fd (ch stays in E) + ld c, #13 ; SYS_PUTB + rst #0x30 + ret + + ;; unsigned char flist(unsigned char slot /*A*/, char *namebuf /*DE*/) -> A +_flist: + ld b, a + ld c, #14 ; SYS_LIST + rst #0x30 + ret + + ;; void fremove(const char *name /*DE*/) +_fremove: + ld c, #15 ; SYS_REMOVE + rst #0x30 + ret @@ -0,0 +1,9 @@ +#include "gbos.h" +/* ls: list files in the RAM filesystem. */ +void main(void) { + char name[9]; + unsigned char i; + for (i = 0; i < 8; i++) { + if (flist(i, name)) { name[8] = 0; puts(name); nl(); } + } +} @@ -0,0 +1,7 @@ +#include "gbos.h" +/* rm <name>: delete a file. */ +void main(void) { + char *argv[4]; + unsigned char argc = argv_parse(argv, 4); + if (argc > 0) fremove(argv[0]); +} diff --git a/c/save.c b/c/save.c new file mode 100644 index 0000000..dd2b8cd --- /dev/null +++ b/c/save.c @@ -0,0 +1,19 @@ +#include "gbos.h" +/* save <name>: read one line from stdin and store it as a file. */ +void main(void) { + char *argv[4]; + unsigned char argc = argv_parse(argv, 4); + unsigned char fd; + char c; + if (argc < 1) { puts("usage: save <name>"); nl(); return; } + fd = open(argv[0], O_WRITE); + if (fd == NOFD) { puts("save: cannot create"); nl(); return; } + for (;;) { + c = readc(); + if (c == EOF) break; + putc(c); /* echo */ + fputc(fd, c); + if (c == '\n') break; + } + close(fd); +} @@ -1,5 +1,5 @@ #include "gbos.h" -/* wc [-l] [-w] [-c]: count lines, words, chars of stdin (default: all). */ +/* wc [-l][-w][-c] [file]: count lines/words/chars of a file or stdin. */ void main(void) { char *argv[8]; unsigned char argc = argv_parse(argv, 8); @@ -7,17 +7,24 @@ void main(void) { unsigned char ww = hasflag(argv, argc, 'w'); unsigned char wch = hasflag(argv, argc, 'c'); unsigned int lines = 0, words = 0, chars = 0; - unsigned char inword = 0, first = 1; - char c; + unsigned char inword = 0, first = 1, i, fd = NOFD; + char *fname = 0; + int ch; if (!wl && !ww && !wch) { wl = ww = wch = 1; } + for (i = 0; i < argc; i++) if (argv[i][0] != '-') { fname = argv[i]; break; } + if (fname) { + fd = open(fname, O_READ); + if (fd == NOFD) { puts("wc: no such file"); nl(); return; } + } for (;;) { - c = readc(); - if (c == EOF) break; + if (fd == NOFD) { char c = readc(); if (c == EOF) break; ch = c; } + else { ch = fgetc(fd); if (ch < 0) break; } chars++; - if (c == '\n') lines++; - if (c == ' ' || c == '\n' || c == '\r' || c == '\t') inword = 0; + if (ch == '\n') lines++; + if (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t') inword = 0; else if (!inword) { inword = 1; words++; } } + if (fd != NOFD) close(fd); if (wl) { putu(lines); first = 0; } if (ww) { if (!first) putc(' '); putu(words); first = 0; } if (wch) { if (!first) putc(' '); putu(chars); } |
