aboutsummaryrefslogtreecommitdiffstats
path: root/c
diff options
context:
space:
mode:
Diffstat (limited to 'c')
-rw-r--r--c/cat.c18
-rw-r--r--c/gbos.h11
-rw-r--r--c/head.c27
-rw-r--r--c/libc.s48
-rw-r--r--c/ls.c9
-rw-r--r--c/rm.c7
-rw-r--r--c/save.c19
-rw-r--r--c/wc.c21
8 files changed, 139 insertions, 21 deletions
diff --git a/c/cat.c b/c/cat.c
index 4092778..dde58cd 100644
--- a/c/cat.c
+++ b/c/cat.c
@@ -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); }
}
}
diff --git a/c/gbos.h b/c/gbos.h
index 47f75ad..d8c8eb3 100644
--- a/c/gbos.h
+++ b/c/gbos.h
@@ -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
diff --git a/c/head.c b/c/head.c
index 952d4c5..e8bf846 100644
--- a/c/head.c
+++ b/c/head.c
@@ -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);
}
diff --git a/c/libc.s b/c/libc.s
index 29031e9..a26042e 100644
--- a/c/libc.s
+++ b/c/libc.s
@@ -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
diff --git a/c/ls.c b/c/ls.c
new file mode 100644
index 0000000..f7e5161
--- /dev/null
+++ b/c/ls.c
@@ -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(); }
+ }
+}
diff --git a/c/rm.c b/c/rm.c
new file mode 100644
index 0000000..25f3004
--- /dev/null
+++ b/c/rm.c
@@ -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);
+}
diff --git a/c/wc.c b/c/wc.c
index 86c3aed..424876d 100644
--- a/c/wc.c
+++ b/c/wc.c
@@ -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); }