aboutsummaryrefslogtreecommitdiffstats
path: root/c
diff options
context:
space:
mode:
authoruser <user@clank>2026-07-18 00:38:38 +0200
committeruser <user@clank>2026-07-18 00:38:38 +0200
commitba2d7ae1d7b319645b10aaa31a7f664f9f80c25c (patch)
treee01e6c7c710a661defe2515ff9657f08cddcb283 /c
parenttools: gbtype prints hub errors to stderr and exits 1 (diff)
downloadgbos-ba2d7ae1d7b319645b10aaa31a7f664f9f80c25c.tar.gz
gbos-ba2d7ae1d7b319645b10aaa31a7f664f9f80c25c.tar.xz
gbos-ba2d7ae1d7b319645b10aaa31a7f664f9f80c25c.zip
refactor: c/ -> usr/, compiled program blobs out of the source tree
Userland sources live in usr/ (fits the Unix theme better than 'c'). SDCC output .bin blobs land in build/usr/ with the other build artifacts instead of littering the source dir; programs.asm INCBINs them from there. Byte-identical ROM.
Diffstat (limited to 'c')
-rw-r--r--c/args.c12
-rw-r--r--c/blk.c13
-rwxr-xr-xc/build.sh21
-rw-r--r--c/cat.c17
-rw-r--r--c/chat.c57
-rw-r--r--c/chello.c9
-rw-r--r--c/count.c16
-rw-r--r--c/crt0.s11
-rw-r--r--c/dhcp.c72
-rw-r--r--c/echo.c5
-rw-r--r--c/false.c2
-rw-r--r--c/gbos.h64
-rw-r--r--c/head.c28
-rw-r--r--c/irc.c422
-rw-r--r--c/kill.c10
-rw-r--r--c/libc.c67
-rw-r--r--c/libc.s304
-rw-r--r--c/ls.c10
-rw-r--r--c/mkdir.c8
-rw-r--r--c/necho.c13
-rw-r--r--c/netd.c12
-rw-r--r--c/netlib.h39
-rw-r--r--c/nslookup.c23
-rw-r--r--c/pid.c2
-rw-r--r--c/ping.c61
-rw-r--r--c/ps.c14
-rw-r--r--c/ptest.c19
-rw-r--r--c/resolve.h81
-rw-r--r--c/rm.c7
-rw-r--r--c/save.c19
-rw-r--r--c/sh.c200
-rw-r--r--c/sock.h71
-rw-r--r--c/spin.c6
-rw-r--r--c/true.c2
-rw-r--r--c/uname.c2
-rw-r--r--c/wc.c32
-rw-r--r--c/wget.c43
37 files changed, 0 insertions, 1794 deletions
diff --git a/c/args.c b/c/args.c
deleted file mode 100644
index c6f4db3..0000000
--- a/c/args.c
+++ /dev/null
@@ -1,12 +0,0 @@
-#include "gbos.h"
-/* args: an argc/argv demo. Splits its argument string into argv[] and prints
- argc plus each argument. Try: `args one two three` */
-void main(void) {
- char *argv[8];
- unsigned char argc = argv_parse(argv, 8);
- unsigned char i;
- puts("argc="); putu(argc); nl();
- for (i = 0; i < argc; i++) {
- puts("argv["); putu(i); puts("]="); puts(argv[i]); nl();
- }
-}
diff --git a/c/blk.c b/c/blk.c
deleted file mode 100644
index 36839c0..0000000
--- a/c/blk.c
+++ /dev/null
@@ -1,13 +0,0 @@
-#include "gbos.h"
-/* blk: exercise the block device. blk fill <n> <v> | blk peek <n> */
-void main(void) {
- char *argv[4];
- unsigned char argc = argv_parse(argv, 4);
- if (argc >= 3 && argv[0][0] == 'f') {
- bfill(atou(argv[1]), atou(argv[2]));
- } else if (argc >= 2 && argv[0][0] == 'p') {
- putu(bpeek2(atou(argv[1]), argc>=3?atou(argv[2]):0)); nl();
- } else {
- puts("usage: blk fill <n> <v> | blk peek <n>"); nl();
- }
-}
diff --git a/c/build.sh b/c/build.sh
deleted file mode 100755
index 8034d87..0000000
--- a/c/build.sh
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/bin/sh
-# Build a gbos C program into a self-contained 16 KiB ROM-bank image.
-# SDCC native toolchain; crt0 linked FIRST so _start is the $4000 entry.
-# usage: c/build.sh <prog.c> <out.bin>
-set -e
-SRC="$1"; OUT="$2"; B=build/c
-LIBDIR=/usr/share/sdcc/lib/sm83
-mkdir -p "$B"
-sdasgb -o "$B/crt0.rel" c/crt0.s
-sdasgb -o "$B/libc.rel" c/libc.s
-sdcc -msm83 -c -Ic c/libc.c -o "$B/libc_c.rel"
-sdcc -msm83 -c -Ic "$SRC" -o "$B/prog.rel"
-# link: crt0 first (=> _start at 0x4000), then libc, program, and sm83 lib
-sdldgb -n -m -w -j -i "$B/prog.ihx" \
- -b _CODE=0x4000 -b _DATA=0xa000 \
- -k "$LIBDIR" -l sm83 \
- "$B/crt0.rel" "$B/libc.rel" "$B/libc_c.rel" "$B/prog.rel"
-makebin -Z -p "$B/prog.ihx" "$B/prog.bin"
-dd if="$B/prog.bin" of="$OUT" bs=1024 skip=16 count=16 2>/dev/null
-echo "wrote $OUT ($(wc -c < "$OUT") bytes); entry:"
-grep -iE ' _start| _main' "$B/prog.map" | head -2
diff --git a/c/cat.c b/c/cat.c
deleted file mode 100644
index 790cb88..0000000
--- a/c/cat.c
+++ /dev/null
@@ -1,17 +0,0 @@
-#include "gbos.h"
-/* cat [file]: print a file, or copy stdin to stdout until EOF. */
-void main(void) {
- 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 == EISDIR) { puts("cat: is a directory"); nl(); return; }
- 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/chat.c b/c/chat.c
deleted file mode 100644
index 987b336..0000000
--- a/c/chat.c
+++ /dev/null
@@ -1,57 +0,0 @@
-#include "netlib.h"
-/* chat: a link-port chat client. Incoming SLIP frames from the host gateway
- print as messages; SELECT brings up the on-screen keyboard, type a line and
- press START to send it. A poll loop interleaves receiving and typing so
- messages arrive while you're not mid-line. */
-
-static char rxbuf[96];
-static unsigned char rxlen, rxin, rxesc;
-
-/* feed one non-blocking byte to the SLIP receiver; returns a frame length when
- a whole frame has arrived (copied into out), else 0. */
-static unsigned char slip_poll(char *out) {
- int b = srecv_nb();
- unsigned char c, i, n;
- if (b < 0) return 0;
- c = (unsigned char)b;
- if (c == SLIP_END) {
- if (rxin && rxlen) {
- n = rxlen;
- for (i = 0; i < n; i++) out[i] = rxbuf[i];
- rxlen = 0; rxin = 0; rxesc = 0;
- return n;
- }
- rxin = 1; rxlen = 0; rxesc = 0;
- return 0;
- }
- if (!rxin) return 0;
- if (rxesc) {
- if (c == SLIP_ESC_END) c = SLIP_END;
- else if (c == SLIP_ESC_ESC) c = SLIP_ESC;
- rxesc = 0;
- } else if (c == SLIP_ESC) { rxesc = 1; return 0; }
- if (rxlen < 96) rxbuf[rxlen++] = (char)c;
- return 0;
-}
-
-void main(void) {
- char line[64], frame[96];
- unsigned char linelen = 0, n, i, c;
- puts("chat: SELECT=keyboard START=send"); nl();
- for (;;) {
- n = slip_poll(frame); /* incoming message? */
- if (n) {
- for (i = 0; i < n; i++) putc(frame[i]);
- nl();
- }
- c = pollin(); /* typed a key? */
- if (c == '\n') {
- if (linelen) { slip_send(line, linelen); linelen = 0; }
- } else if (c == 8) {
- if (linelen) { linelen--; putc(8); }
- } else if (c) {
- if (linelen < 63) { line[linelen++] = (char)c; putc((char)c); }
- }
- yield();
- }
-}
diff --git a/c/chello.c b/c/chello.c
deleted file mode 100644
index f570b61..0000000
--- a/c/chello.c
+++ /dev/null
@@ -1,9 +0,0 @@
-#include "gbos.h"
-void main(void) {
- writes("hello from C on gbos!", 21);
- nl();
- writes("my pid is ", 10);
- /* print pid as a digit */
- { unsigned char c = getpid() + '0'; char d = c; writes(&d, 1); }
- nl();
-}
diff --git a/c/count.c b/c/count.c
deleted file mode 100644
index 37cdcce..0000000
--- a/c/count.c
+++ /dev/null
@@ -1,16 +0,0 @@
-#include "gbos.h"
-/* count [n]: print n numbered lines (default 25) to observe terminal scrolling
- and the OSK scroll-region. Each line is tagged so you can tell which lines
- are visible after scrolling. */
-void main(void) {
- char *argv[4];
- unsigned char argc = argv_parse(argv, 4);
- unsigned char n = 25, i;
- if (argc >= 1) n = atou(argv[0]);
- for (i = 1; i <= n; i++) {
- puts("line ");
- putu(i);
- puts(" ------------------");
- nl();
- }
-}
diff --git a/c/crt0.s b/c/crt0.s
deleted file mode 100644
index 0d8371f..0000000
--- a/c/crt0.s
+++ /dev/null
@@ -1,11 +0,0 @@
- .module crt0
- .globl _main
- ;; gbos C entry. exec() maps our ROM bank and jumps here ($4000).
- ;; Call main(), then exit(0). (Args are fetched on demand via getargs().)
- .area _CODE
-_start::
- call _main
- ld b, #0
- ld c, #0 ; SYS_EXIT
- rst #0x30
-1$: jr 1$
diff --git a/c/dhcp.c b/c/dhcp.c
deleted file mode 100644
index e4186f4..0000000
--- a/c/dhcp.c
+++ /dev/null
@@ -1,72 +0,0 @@
-#include "sock.h"
-/* dhcp - a minimal DHCP client. DISCOVER -> OFFER -> REQUEST -> ACK over UDP
- (kernel owns UDP; this owns BOOTP/DHCP), then hands the leased address to the
- kernel with net_setip(). Run at boot before the shell. Times out gracefully
- if there's no server (the shell then comes up unconfigured). */
-
-static unsigned char pkt[288]; /* BOOTP is ~240B + options (frames > 255) */
-static unsigned char ip[4];
-static unsigned char bcast[4];
-
-/* fill the fixed BOOTP request header + magic cookie; options start at 240 */
-static void bootp(void) {
- unsigned int i;
- for (i = 0; i < 240; i++) pkt[i] = 0;
- pkt[0] = 1; pkt[1] = 1; pkt[2] = 6; /* op=request htype=eth hlen=6 */
- pkt[4] = 0x12; pkt[5] = 0x34; pkt[6] = 0x56; pkt[7] = 0x78; /* xid */
- pkt[10] = 0x80; /* flags: broadcast reply */
- pkt[28] = 0x02; pkt[29] = 0x47; pkt[30] = 0x42; pkt[33] = 0x01; /* client MAC */
- pkt[236] = 0x63; pkt[237] = 0x82; pkt[238] = 0x53; pkt[239] = 0x63; /* magic */
-}
-
-/* DHCP message type from the received packet (option 53), or 0 */
-static unsigned char mtype(void) {
- unsigned int p = 240;
- while (p < 280 && pkt[p] != 255) {
- if (pkt[p] == 0) { p++; continue; } /* pad */
- if (pkt[p] == 53) return pkt[p + 2];
- p += 2 + pkt[p + 1];
- }
- return 0;
-}
-
-void main(void) {
- unsigned char s, i, n;
- unsigned int p;
- bcast[0] = 255; bcast[1] = 255; bcast[2] = 255; bcast[3] = 255;
-
- puts("dhcp: discovering"); nl();
- s = net_socket(SOCK_UDP);
- if (s == 0xFF) { puts("dhcp: no socket"); nl(); return; }
- net_bind(s, 68);
- net_connect(s, bcast, 67);
-
- /* DISCOVER -> OFFER (retry a few times for startup timing) */
- bootp();
- p = 240;
- pkt[p++] = 53; pkt[p++] = 1; pkt[p++] = 1; /* DHCPDISCOVER */
- pkt[p++] = 255;
- n = 0xFF;
- for (i = 0; i < 3 && n == 0xFF; i++) {
- net_send(s, pkt, (unsigned char)p);
- n = net_recv(s, pkt, 255);
- }
- if (n == 0xFF || mtype() != 2) { puts("dhcp: no offer"); nl(); net_close(s); return; }
- ip[0] = pkt[16]; ip[1] = pkt[17]; ip[2] = pkt[18]; ip[3] = pkt[19]; /* yiaddr */
-
- /* REQUEST -> ACK */
- bootp();
- p = 240;
- pkt[p++] = 53; pkt[p++] = 1; pkt[p++] = 3; /* DHCPREQUEST */
- pkt[p++] = 50; pkt[p++] = 4; /* requested IP */
- pkt[p++] = ip[0]; pkt[p++] = ip[1]; pkt[p++] = ip[2]; pkt[p++] = ip[3];
- pkt[p++] = 255;
- net_send(s, pkt, (unsigned char)p);
- n = net_recv(s, pkt, 255);
- net_close(s);
- if (n == 0xFF || mtype() != 5) { puts("dhcp: request failed"); nl(); return; }
- ip[0] = pkt[16]; ip[1] = pkt[17]; ip[2] = pkt[18]; ip[3] = pkt[19];
-
- net_setip(ip);
- puts("dhcp: leased "); for (i = 0; i < 4; i++) { putu(ip[i]); if (i < 3) putc('.'); } nl();
-}
diff --git a/c/echo.c b/c/echo.c
deleted file mode 100644
index f8d5125..0000000
--- a/c/echo.c
+++ /dev/null
@@ -1,5 +0,0 @@
-#include "gbos.h"
-void main(void) {
- puts(getargs());
- nl();
-}
diff --git a/c/false.c b/c/false.c
deleted file mode 100644
index a124951..0000000
--- a/c/false.c
+++ /dev/null
@@ -1,2 +0,0 @@
-#include "gbos.h"
-void main(void) { sexit(1); }
diff --git a/c/gbos.h b/c/gbos.h
deleted file mode 100644
index 2350665..0000000
--- a/c/gbos.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/* gbos userland C API (thin wrappers over rst $30 syscalls; see c/libc.s) */
-#ifndef GBOS_H
-#define GBOS_H
-#define EOF 4 /* readc() returns this at end of input */
-
-void writes(const char *buf, unsigned char len);
-void putc(char c);
-void puts(const char *s); /* write a NUL-terminated string */
-void nl(void); /* newline (CRLF) */
-unsigned char strlen(const char *s);
-char *getargs(void); /* this program's argument string */
-char readc(void); /* one input byte, EOF at end */
-void sexit(unsigned char code);
-unsigned char getpid(void);
-unsigned char pipe(void); /* -> read fd; write end is read+1 */
-void ssend(unsigned char b); /* link-port: transmit one byte */
-unsigned char srecv(void); /* link-port: receive one byte (blocks) */
-int srecv_nb(void); /* link-port: receive, or -1 if none */
-unsigned char pollin(void); /* poll OSK for a typed char, or 0 */
-unsigned char pollcon(void); /* poll console ring (link-injected
- input, filled by net pumps), or 0 */
-unsigned char sys_net(void *req); /* socket layer trap (see sock.h) */
-void gsleep(unsigned char units); /* delay units*(1/64)s (raw trap) */
-void msleep(unsigned int ms); /* delay ~ms milliseconds */
-
-/* helpers (c/libc.c) */
-void putu(unsigned int n); /* print decimal */
-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);
-unsigned char mkdir(const char *path);
-unsigned char chdir(const char *path);
-unsigned char opendir(const char *path);
-void poweroff(void); /* clean emulator shutdown (saves) */
-#define O_READ 0
-#define O_WRITE 1
-#define NOFD 0xFF
-#define EISDIR 0xFE /* open() failed: path is a directory */
-
-/* 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 */
-unsigned char kill(unsigned char pid); /* terminate a pid (1 is immortal)*/
-unsigned char psget(unsigned char slot, unsigned char *buf); /* {pid,state,prog}*/
-void progname(unsigned char id, char *buf); /* id -> name */
-void yield(void);
-unsigned char reap(void); /* reap a finished bg job, or 0 */
-void bfill(unsigned char block, unsigned char byte); /* [debug] disk */
-unsigned char bpeek(unsigned char block); /* [debug] disk */
-unsigned char bpeek2(unsigned char block, unsigned char off);
-#endif
diff --git a/c/head.c b/c/head.c
deleted file mode 100644
index 3298e54..0000000
--- a/c/head.c
+++ /dev/null
@@ -1,28 +0,0 @@
-#include "gbos.h"
-/* 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, i, fd = NOFD;
- char *fname = 0;
- int ch;
- if (nv) n = atou(nv);
- 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 > 3) { puts("head: no such file"); nl(); return; }
- }
- for (;;) {
- if (fd > 3) { 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/irc.c b/c/irc.c
deleted file mode 100644
index 250738a..0000000
--- a/c/irc.c
+++ /dev/null
@@ -1,422 +0,0 @@
-#include "resolve.h"
-/* irc HOST [NICK] - a bitchx/irssi-flavored IRC client on 40x18 columns.
- The kernel owns TCP; this owns the protocol and the screen.
-
- UI: messages scroll above; the bottom line is an irssi-style input line
- "[#chan] text_" redrawn in place with \r (the terminal has no cursor
- addressing - \r + overprint is the entire trick). Long input scrolls
- horizontally like irssi. Keys come from the OSK (SELECT toggles it) and
- from the console ring (pollcon), so a hub can type into the client too.
-
- Formats, straight from the elders:
- <nick> text channel message * nick text CTCP ACTION
- <nick:#c> text msg to a non-current channel
- *nick* text private msg >target< text outbound /msg
- -nick- text notice -!- text server/status */
-
-/* seg first + large: the arg string lives at 0xA000 and the first static
- lands on it; args are copied out in main() before seg is ever written. */
-static unsigned char seg[220]; /* one TCP segment from the kernel */
-static char line[240]; /* server line accumulator */
-static unsigned char llen;
-static char input[140]; /* the input line being typed */
-static unsigned char inlen;
-static unsigned char drawn; /* chars currently drawn on input row */
-static char nick[16];
-static char target[32]; /* current channel/query, "" = none */
-static char sbuf[200]; /* outgoing IRC line builder */
-static unsigned char slen;
-static unsigned char namebuf[64];
-static unsigned char dst[4];
-static unsigned char sock;
-static unsigned char quitting;
-/* A WRITABLE empty string for parse defaults. handle() writes terminators
- into pfx (bang) and txt (strip_fmt); a read-only "" literal lives in ROM
- ($4000-$5FFF), where a write is an MBC5 *RAM-bank-select* - it would swap
- the whole $A000 data bank out from under every static (instant garbage).
- A prefix-less or empty-trailing server line is enough to trigger it. */
-static char empty[1];
-
-/* ---- tiny string helpers (SDCC libc is us) ------------------------------- */
-static unsigned char sceq(const char *a, const char *b) { /* case-insens. */
- unsigned char ca, cb;
- for (;;) {
- ca = (unsigned char)*a++; cb = (unsigned char)*b++;
- if (ca >= 'a' && ca <= 'z') ca -= 32;
- if (cb >= 'a' && cb <= 'z') cb -= 32;
- if (ca != cb) return 0;
- if (!ca) return 1;
- }
-}
-static void scpy(char *d, const char *s, unsigned char max) {
- unsigned char i;
- for (i = 0; s[i] && i < (unsigned char)(max - 1); i++) d[i] = s[i];
- d[i] = 0;
-}
-
-/* ---- outgoing IRC lines --------------------------------------------------- */
-static void sc(const char *s) { /* append to sbuf */
- while (*s && slen < 197) sbuf[slen++] = *s++;
-}
-static void sfin(void) { /* CRLF + send */
- sbuf[slen++] = '\r'; sbuf[slen++] = '\n';
- net_send(sock, sbuf, slen);
- slen = 0;
-}
-
-/* ---- the input line ------------------------------------------------------- */
-/* erase what's drawn on the bottom row, park at col 0 */
-static void row_clear(void) {
- unsigned char i;
- putc('\r');
- for (i = 0; i < drawn; i++) putc(' ');
- putc('\r');
- drawn = 0;
-}
-/* redraw "[target] tail-of-input_"; keep total < 40 so it never wraps */
-static void row_draw(void) {
- unsigned char pl, vis, i;
- const char *t = target[0] ? target : "(status)";
- row_clear();
- putc('[');
- for (pl = 0; t[pl] && pl < 12; pl++) putc(t[pl]);
- putc(']'); putc(' ');
- pl += 3; /* prompt width */
- vis = 39 - pl - 1; /* room for text (cursor gets 1) */
- i = (inlen > vis) ? (unsigned char)(inlen - vis) : 0;
- for (; i < inlen; i++) putc(input[i]);
- drawn = pl + ((inlen > vis) ? vis : inlen);
-}
-/* print a message line above the input line */
-static void say(const char *s) {
- row_clear();
- puts(s); nl();
- row_draw();
-}
-static void say2(const char *a, const char *b) {
- row_clear();
- puts(a); puts(b); nl();
- row_draw();
-}
-static void say3(const char *a, const char *b, const char *c) {
- row_clear();
- puts(a); puts(b); puts(c); nl();
- row_draw();
-}
-
-/* ---- server line parsing -------------------------------------------------- */
-/* split "pfx!user@host" -> pfx nick only (in place) */
-static void bang(char *p) {
- while (*p && *p != '!') p++;
- *p = 0;
-}
-static unsigned char isnum(const char *c) {
- return c[0] >= '0' && c[0] <= '9';
-}
-static unsigned char ishex(char c) {
- return (c>='0'&&c<='9')||(c>='a'&&c<='f')||(c>='A'&&c<='F');
-}
-
-/* Strip mIRC/IRC formatting in place - crucially their *arguments*, or a
- color logo (a real MOTD!) leaves its \x03 color numbers on screen as digit
- soup. \x03 = color (up to 2 digits[,up to 2 digits]); \x04 = hex color
- (up to 6 hex[,6 hex]); \x02 bold \x0f reset \x11 mono \x16 reverse
- \x1d italic \x1e strike \x1f underline are lone toggles. Leaves \x01
- (CTCP) intact for the PRIVMSG path. */
-static void strip_fmt(char *s) {
- char *w = s, *r = s;
- unsigned char c, d;
- while (*r) {
- c = (unsigned char)*r;
- if (c == 3) {
- r++; d = 0;
- while (*r>='0'&&*r<='9'&&d<2) { r++; d++; }
- if (*r==','&&r[1]>='0'&&r[1]<='9') { r++; d=0; while(*r>='0'&&*r<='9'&&d<2){r++;d++;} }
- continue;
- }
- if (c == 4) {
- r++; d = 0;
- while (ishex(*r)&&d<6) { r++; d++; }
- if (*r==','&&ishex(r[1])) { r++; d=0; while(ishex(*r)&&d<6){r++;d++;} }
- continue;
- }
- if (c==2||c==15||c==17||c==22||c==29||c==30||c==31) { r++; continue; }
- *w++ = *r++;
- }
- *w = 0;
-}
-
-static void handle(char *l) {
- char *pfx = empty, *cmd, *arg, *txt = empty;
- char *p = l;
-
- if (*p == ':') { /* :prefix */
- pfx = ++p;
- while (*p && *p != ' ') p++;
- if (*p) *p++ = 0;
- }
- cmd = p; /* command */
- while (*p && *p != ' ') p++;
- if (*p) *p++ = 0;
- arg = p; /* params, then :trailing */
- while (*p) {
- if (*p == ':' && (p == arg || p[-1] == 0)) { txt = p + 1; p[-1] = 0; break; }
- if (*p == ' ') *p = 0;
- p++;
- }
- /* arg = first param (NUL-joined list), txt = trailing */
- strip_fmt(txt); /* kill color/format codes + args */
-
- if (sceq(cmd, "PING")) {
- slen = 0; sc("PONG :"); sc(txt[0] ? txt : arg); sfin();
- say("-!- Ping? Pong!");
- return;
- }
- bang(pfx);
- if (sceq(cmd, "PRIVMSG")) {
- char *dest = arg;
- unsigned char act = 0;
- if (txt[0] == 1) { /* CTCP */
- char *e = txt + 1;
- while (*e && *e != 1) e++;
- *e = 0; txt++;
- if (txt[0]=='A'&&txt[1]=='C'&&txt[2]=='T'&&txt[3]=='I'&&txt[4]=='O'&&txt[5]=='N'&&txt[6]==' ') {
- act = 1; txt += 7;
- } else if (txt[0]=='V') { /* VERSION */
- slen = 0; sc("NOTICE "); sc(pfx); sc(" :\001VERSION gbos:sl0pboy:GameBoyColor\001"); sfin();
- return;
- } else return;
- }
- row_clear();
- if (act) { puts("* "); puts(pfx); putc(' '); }
- else if (sceq(dest, nick)) { putc('*'); puts(pfx); puts("* "); }
- else if (sceq(dest, target)) { putc('<'); puts(pfx); puts("> "); }
- else { putc('<'); puts(pfx); putc(':'); puts(dest); puts("> "); }
- puts(txt); nl();
- row_draw();
- return;
- }
- if (sceq(cmd, "NOTICE")) {
- row_clear();
- putc('-'); puts(pfx[0] ? pfx : "server"); puts("- "); puts(txt); nl();
- row_draw();
- return;
- }
- if (sceq(cmd, "JOIN")) {
- char *ch = txt[0] ? txt : arg;
- if (sceq(pfx, nick)) {
- scpy(target, ch, sizeof(target));
- say2("-!- now talking in ", target);
- } else say3("-!- ", pfx, " has joined");
- return;
- }
- if (sceq(cmd, "PART")) {
- if (sceq(pfx, nick)) { target[0] = 0; say("-!- you left"); }
- else say3("-!- ", pfx, " has left");
- return;
- }
- if (sceq(cmd, "QUIT")) { say3("-!- ", pfx, " has quit"); return; }
- if (sceq(cmd, "KICK")) {
- char *ch = arg, *who = arg;
- while (*who) who++;
- who++; /* param 2: the victim */
- if (sceq(who, nick)) { target[0] = 0; say2("-!- you were kicked from ", ch); }
- else say3("-!- ", who, " was kicked");
- return;
- }
- if (sceq(cmd, "NICK")) {
- char *nn = txt[0] ? txt : arg;
- if (sceq(pfx, nick)) scpy(nick, nn, sizeof(nick));
- row_clear();
- puts("-!- "); puts(pfx); puts(" is now known as "); puts(nn); nl();
- row_draw();
- return;
- }
- if (isnum(cmd)) {
- if (cmd[0]=='4'&&cmd[1]=='3'&&cmd[2]=='3') { /* nick in use */
- unsigned char n = strlen(nick);
- if (n < 14) { nick[n] = '_'; nick[n+1] = 0; }
- slen = 0; sc("NICK "); sc(nick); sfin();
- say2("-!- nick in use, trying ", nick);
- return;
- }
- if (cmd[0]=='3'&&cmd[1]=='3'&&cmd[2]=='2') { /* topic */
- say2("-!- topic: ", txt);
- return;
- }
- if (cmd[0]=='3'&&cmd[1]=='5'&&cmd[2]=='3') { /* names */
- say2("-!- users: ", txt);
- return;
- }
- if (cmd[1]=='3'&&cmd[0]=='3') return; /* 333 topic-by: skip */
- if (cmd[0]=='0'&&cmd[1]=='0'&&(cmd[2]=='4'||cmd[2]=='5')) return; /* MYINFO/ISUPPORT noise */
- if (txt[0]) say2("-!- ", txt); /* motd & friends */
- return;
- }
- /* anything else: show it raw-ish, bitchx would too */
- if (txt[0]) say3(cmd, " ", txt);
-}
-
-/* accumulate TCP bytes into lines */
-static void feed(unsigned char *b, unsigned char n) {
- unsigned char i;
- for (i = 0; i < n; i++) {
- char c = (char)b[i];
- if (c == '\r') continue;
- if (c == '\n') { line[llen] = 0; if (llen) handle(line); llen = 0; }
- else if (llen < 239) line[llen++] = c;
- }
-}
-
-/* ---- typed input ---------------------------------------------------------- */
-static void run_cmd(char *t) {
- char *a = t;
- while (*a && *a != ' ') a++;
- if (*a) *a++ = 0; /* t = /cmd, a = rest */
-
- if (sceq(t, "/join") || sceq(t, "/j")) {
- if (!*a) { say("-!- join what?"); return; }
- slen = 0; sc("JOIN "); sc(a); sfin();
- return;
- }
- if (sceq(t, "/part") || sceq(t, "/p")) {
- slen = 0; sc("PART "); sc(*a ? a : target); sfin();
- return;
- }
- if (sceq(t, "/msg")) {
- char *m = a;
- while (*m && *m != ' ') m++;
- if (*m) *m++ = 0;
- if (!*a || !*m) { say("-!- /msg nick text"); return; }
- slen = 0; sc("PRIVMSG "); sc(a); sc(" :"); sc(m); sfin();
- row_clear();
- putc('>'); puts(a); puts("< "); puts(m); nl();
- row_draw();
- return;
- }
- if (sceq(t, "/me")) {
- if (!target[0]) { say("-!- no channel"); return; }
- slen = 0; sc("PRIVMSG "); sc(target); sc(" :\001ACTION "); sc(a); sc("\001"); sfin();
- row_clear();
- puts("* "); puts(nick); putc(' '); puts(a); nl();
- row_draw();
- return;
- }
- if (sceq(t, "/nick")) {
- if (!*a) { say("-!- /nick newnick"); return; }
- slen = 0; sc("NICK "); sc(a); sfin();
- return;
- }
- if (sceq(t, "/quit")) {
- slen = 0; sc("QUIT :"); sc(*a ? a : "sl0pboy out"); sfin();
- quitting = 1;
- return;
- }
- if (sceq(t, "/raw") || sceq(t, "/quote")) {
- slen = 0; sc(a); sfin();
- return;
- }
- say("-!- commands: /join /part /msg /me /nick /quit /raw");
-}
-
-static void submit(void) {
- input[inlen] = 0;
- if (!inlen) return;
- if (input[0] == '/') {
- inlen = 0;
- run_cmd(input);
- row_draw();
- return;
- }
- if (!target[0]) { inlen = 0; say("-!- join a channel first (/join #gb)"); return; }
- slen = 0; sc("PRIVMSG "); sc(target); sc(" :"); sc(input); sfin();
- row_clear();
- putc('<'); puts(nick); puts("> "); puts(input); nl();
- inlen = 0;
- row_draw();
-}
-
-static void key(unsigned char c) {
- if (c == '\n' || c == '\r') { submit(); return; }
- if (c == 8 || c == 127) {
- if (inlen) { inlen--; row_draw(); }
- return;
- }
- if (c < 32) return;
- if (inlen < 139) { input[inlen++] = (char)c; row_draw(); }
-}
-
-/* ---- main ----------------------------------------------------------------- */
-void main(void) {
- char *argp;
- unsigned char i, n, idle;
-
- /* gbos does not zero C statics (crt0 zeroes nothing; fork inherits the
- parent's RAM bank) - initialize every piece of state explicitly */
- llen = inlen = drawn = slen = quitting = 0;
- target[0] = 0;
- empty[0] = 0; /* gbos doesn't zero BSS */
-
- argp = getargs(); /* copy args before seg is used */
- for (i = 0; argp[i] && i < 63; i++) namebuf[i] = (unsigned char)argp[i];
- namebuf[i] = 0;
-
- /* split "HOST [NICK]" */
- scpy(nick, "sl0pboy", sizeof(nick));
- for (i = 0; namebuf[i]; i++)
- if (namebuf[i] == ' ') {
- namebuf[i] = 0;
- if (namebuf[i+1]) scpy(nick, (char *)namebuf + i + 1, sizeof(nick));
- break;
- }
- if (!namebuf[0]) {
- puts("usage: irc HOST [NICK] (port 6667)"); nl();
- puts(" then: /join #chan, SELECT = keyboard"); nl();
- sexit(1);
- }
-
- if (!resolve((char *)namebuf, dst)) {
- puts("irc: cannot resolve "); puts((char *)namebuf); nl(); sexit(1);
- }
-
- sock = net_socket(SOCK_TCP);
- if (sock == 0xFF) { puts("irc: no socket"); nl(); sexit(1); }
- /* vary the local port per run (DIV timer noise): a fixed port can hit a
- stale half-dead connection at the server after an unclean exit */
- net_bind(sock, 41000 + ((unsigned int)*(volatile unsigned char *)0xFF04 << 2) + getpid());
- puts("-!- connecting to "); puts((char *)namebuf); puts(":6667"); nl();
- if (net_connect(sock, dst, 6667) == 0xFF) {
- puts("irc: connect failed"); nl(); net_close(sock); sexit(1);
- }
-
- slen = 0; sc("NICK "); sc(nick); sfin();
- slen = 0; sc("USER gbos 0 * :sl0pboy on gbos"); sfin();
- puts("-!- registering as "); puts(nick);
- puts(" (SELECT = keyboard)"); nl();
- row_draw();
-
- idle = 0;
- for (;;) {
- n = net_recv_nb(sock, seg, (unsigned char)sizeof(seg));
- if (n == 0) { say("-!- disconnected"); break; }
- if (n != 0xFE && n != 0xFF) feed(seg, n); /* render a segment if any */
- if (quitting) { say("-!- quit"); break; }
-
- /* Poll input EVERY pass, even mid-flood: otherwise a big MOTD (or a
- * busy channel) starves the keyboard for its whole duration - the OSK
- * won't even open, and keystrokes are dropped. That's what made
- * '/join #sl0p right after connect' look broken. */
- i = pollin(); /* OSK */
- if (!i) i = pollcon(); /* hub-injected console bytes */
- if (i) key(i);
-
- if (n == 0xFE || n == 0xFF) { /* nothing received this pass */
- if (!i && ++idle >= 4) { msleep(20); idle = 4; }
- } else {
- idle = 0; /* actively receiving; don't sleep */
- }
- }
- net_close(sock);
- row_clear();
- sexit(0);
-}
diff --git a/c/kill.c b/c/kill.c
deleted file mode 100644
index e524627..0000000
--- a/c/kill.c
+++ /dev/null
@@ -1,10 +0,0 @@
-#include "gbos.h"
-/* kill <pid>: terminate a process (pid 1 is immortal). */
-void main(void) {
- char *argv[4];
- unsigned char argc = argv_parse(argv, 4);
- unsigned char pid;
- if (argc < 1) { puts("usage: kill <pid>"); nl(); return; }
- pid = atou(argv[0]);
- if (kill(pid)) { puts("kill: no such pid (or immortal)"); nl(); }
-}
diff --git a/c/libc.c b/c/libc.c
deleted file mode 100644
index a48a64c..0000000
--- a/c/libc.c
+++ /dev/null
@@ -1,67 +0,0 @@
-/* gbos libc C helpers (compiled once, linked into every program). */
-#include "gbos.h"
-
-/* sleep for approximately 'ms' milliseconds (cooperative; other procs run).
- The kernel counts in 1/64-second units (~15.6 ms), so we round ms to that. */
-void msleep(unsigned int ms) {
- unsigned int u = ms >> 4; /* ~ms/15.6, close enough for a delay */
- if (u > 255) u = 255;
- if (u == 0 && ms) u = 1;
- gsleep((unsigned char)u);
-}
-
-/* print an unsigned int in decimal */
-void putu(unsigned int n) {
- char buf[5];
- unsigned char i = 0;
- if (n == 0) { putc('0'); return; }
- while (n) { buf[i++] = '0' + (n % 10); n = n / 10; }
- while (i) putc(buf[--i]);
-}
-
-/* parse a decimal number (stops at the first non-digit) */
-unsigned char atou(const char *s) {
- unsigned char n = 0;
- while (*s >= '0' && *s <= '9') { n = n * 10 + (*s - '0'); s++; }
- return n;
-}
-
-/* tokenize the argument string in place into argv[]; returns argc.
- (replaces the spaces in the arg string with NULs) */
-unsigned char argv_parse(char **argv, unsigned char maxv) {
- char *p = getargs();
- unsigned char argc = 0;
- for (;;) {
- while (*p == ' ') p++;
- if (*p == 0) break;
- if (argc < maxv) argv[argc] = p;
- argc++;
- while (*p != 0 && *p != ' ') p++;
- if (*p == ' ') *p++ = 0;
- }
- return argc;
-}
-
-/* return nonzero if single-char flag `f` appears (as -f or within -abc) */
-unsigned char hasflag(char **argv, unsigned char argc, char f) {
- unsigned char i, j;
- for (i = 0; i < argc; i++) {
- if (argv[i][0] != '-') continue;
- for (j = 1; argv[i][j]; j++)
- if (argv[i][j] == f) return 1;
- }
- return 0;
-}
-
-/* return the value for option -<opt> ("-n 5" or "-n5"), or 0 if absent */
-char *optval(char **argv, unsigned char argc, char opt) {
- unsigned char i;
- for (i = 0; i < argc; i++) {
- if (argv[i][0] == '-' && argv[i][1] == opt) {
- if (argv[i][2]) return &argv[i][2];
- if (i + 1 < argc) return argv[i+1];
- return 0;
- }
- }
- return 0;
-}
diff --git a/c/libc.s b/c/libc.s
deleted file mode 100644
index 5b176d9..0000000
--- a/c/libc.s
+++ /dev/null
@@ -1,304 +0,0 @@
- .module libc
- .globl _writes, _putc, _puts, _nl, _strlen, _readc, _sexit, _getpid, _getargs
- .globl _open, _close, _fgetc, _fputc, _flist, _fremove, _pipe, _ssend, _srecv, _srecv_nb, _pollin, _pollcon
- .globl _sys_net, _gsleep
- ;; 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.
- .area _CODE
-
- ;; void writes(const char *buf /*DE*/, unsigned char len /*A*/)
-_writes:
- ld b, a
- ld c, #3 ; SYS_WRITE
- rst #0x30
- ret
-
- ;; char *getargs(void) -> BC : the arg string (command line past word 1).
- ;; The shell leaves "cmd\0args\0" at 0xA000, inherited by the child via fork.
-_getargs:
- ld hl, #0xa000
-1$: ld a, (hl)
- inc hl
- or a
- jr nz, 1$
- ld b, h
- ld c, l
- ret
-
- ;; void putc(char c /*A*/) -> stdout via SYS_PUTC
-_putc:
- ld e, a
- ld c, #16 ; SYS_PUTC
- rst #0x30
- ret
-
- ;; void puts(const char *s /*DE*/) - write until NUL (no newline)
-_puts:
-1$: ld a, (de)
- or a
- ret z
- push de
- ld e, a
- ld c, #16 ; SYS_PUTC
- rst #0x30
- pop de
- inc de
- jr 1$
-
- ;; void nl(void) - CRLF via stdout
-_nl:
- 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
-_strlen:
- ld c, #0
-1$: ld a, (de)
- or a
- jr z, 2$
- inc c
- inc de
- jr 1$
-2$: ld a, c
- ret
-
- ;; char readc(void) -> A (4 = EOF)
-_readc:
- ld c, #2 ; SYS_READ
- rst #0x30
- ret
-
- ;; void sexit(unsigned char code /*A*/) - never returns
-_sexit:
- ld b, a
- ld c, #0 ; SYS_EXIT
- rst #0x30
- ret
-
- ;; unsigned char getpid(void) -> A
-_getpid:
- ld c, #8 ; SYS_GETPID
- rst #0x30
- ret
-
- ;; unsigned char pipe(void) -> A (read fd; write end is read+1)
-_pipe:
- ld c, #28 ; SYS_PIPE
- rst #0x30
- ret
-
- ;; void ssend(unsigned char b /*A*/) -- link-port transmit
-_ssend:
- ld e, a
- ld c, #29 ; SYS_SSEND
- rst #0x30
- ret
-
- ;; unsigned char srecv(void) -> A -- link-port receive (blocks)
-_srecv:
- ld c, #30 ; SYS_SRECV
- rst #0x30
- ret
-
- ;; int srecv_nb(void) -> byte, or -1 if none (non-blocking)
-_srecv_nb:
- ld c, #31 ; SYS_SRECVNB
- rst #0x30
- jr c, 1$
- ld c, a
- ld b, #0
- ret
-1$: ld bc, #0xffff
- ret
-
- ;; unsigned char sys_net(void *req /*DE*/) -> A -- socket layer trap
-_sys_net:
- ld c, #33 ; SYS_NET (DE already = &netreq)
- rst #0x30
- ret
-
- ;; void gsleep(unsigned char units /*A*/) - delay units*(1/64)s
-_gsleep:
- ld b, a
- ld c, #34 ; SYS_SLEEP
- rst #0x30
- ret
-
- ;; unsigned char pollin(void) -> A (typed OSK char, or 0)
-_pollin:
- ld c, #32 ; SYS_POLLIN
- rst #0x30
- ret
-
- ;; unsigned char pollcon(void) -> A (queued console byte, or 0)
-_pollcon:
- ld c, #35 ; SYS_POLLCON
- 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
-
- .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
-
- .globl _kill, _psget, _progname
- ;; unsigned char kill(unsigned char pid /*A*/) -> A (0 ok, $FF fail)
-_kill:
- ld b, a
- ld c, #9 ; SYS_KILL
- rst #0x30
- ret
- ;; unsigned char psget(unsigned char slot /*A*/, unsigned char *buf /*DE*/) -> A
-_psget:
- ld b, a
- ld c, #20 ; SYS_PS
- rst #0x30
- ret
- ;; void progname(unsigned char id /*A*/, char *buf /*DE*/)
-_progname:
- ld b, a
- ld c, #21 ; SYS_PROGNAME
- rst #0x30
- ret
-
- .globl _yield, _reap
- ;; void yield(void)
-_yield:
- ld c, #11 ; SYS_YIELD
- rst #0x30
- ret
- ;; unsigned char reap(void) -> A (reaped pid, or 0)
-_reap:
- ld c, #22 ; SYS_REAP
- rst #0x30
- ret
-
- .globl _bfill, _bpeek, _bpeek2
- ;; void bfill(unsigned char block /*A*/, unsigned char byte /*E*/)
-_bfill:
- ld b, a
- ld c, #23 ; SYS_BFILL
- rst #0x30
- ret
- ;; unsigned char bpeek(unsigned char block /*A*/) -> A
-_bpeek:
- ld b, a
- ld e, #0
- ld c, #24 ; SYS_BPEEK
- rst #0x30
- ret
- ;; unsigned char bpeek2(unsigned char block /*A*/, unsigned char off /*E*/) -> A
-_bpeek2:
- ld b, a
- ld c, #24 ; SYS_BPEEK (off already in E)
- rst #0x30
- ret
-
-
- .globl _mkdir, _chdir
- ;; unsigned char mkdir(const char *path /*DE*/) -> A (0 ok / $FF)
-_mkdir:
- ld c, #25 ; SYS_MKDIR
- rst #0x30
- ret
- ;; unsigned char chdir(const char *path /*DE*/) -> A (0 ok / $FF)
-_chdir:
- ld c, #26 ; SYS_CHDIR
- rst #0x30
- ret
-
- .globl _opendir
- ;; unsigned char opendir(const char *path /*DE*/) -> A (0 ok / $FF)
-_opendir:
- ld c, #27 ; SYS_OPENDIR
- rst #0x30
- ret
-
- .globl _poweroff
- ;; void poweroff(void) - execute the emulator's clean-exit opcode ($ED)
-_poweroff:
- .db 0xED
-1$: jr 1$
diff --git a/c/ls.c b/c/ls.c
deleted file mode 100644
index 0e2e01f..0000000
--- a/c/ls.c
+++ /dev/null
@@ -1,10 +0,0 @@
-#include "gbos.h"
-/* ls [dir]: list a directory (default: current). */
-void main(void) {
- char *argv[4];
- char name[16];
- unsigned char argc = argv_parse(argv, 4);
- unsigned char i;
- if (opendir(argc > 0 ? argv[0] : ".")) { puts("ls: no such directory"); nl(); return; }
- for (i = 0; flist(i, name); i++) { name[15] = 0; puts(name); nl(); }
-}
diff --git a/c/mkdir.c b/c/mkdir.c
deleted file mode 100644
index c907518..0000000
--- a/c/mkdir.c
+++ /dev/null
@@ -1,8 +0,0 @@
-#include "gbos.h"
-/* mkdir <path>: create a directory. */
-void main(void) {
- char *argv[4];
- unsigned char argc = argv_parse(argv, 4);
- if (argc < 1) { puts("usage: mkdir <name>"); nl(); return; }
- if (mkdir(argv[0])) { puts("mkdir: failed"); nl(); }
-}
diff --git a/c/necho.c b/c/necho.c
deleted file mode 100644
index 99551d4..0000000
--- a/c/necho.c
+++ /dev/null
@@ -1,13 +0,0 @@
-#include "netlib.h"
-/* necho: send a SLIP-framed packet over the link port and print the reply.
- Talks to a host gateway (tools/gateway.py) that echoes frames back. */
-
-void main(void) {
- char buf[64];
- unsigned char len;
- puts("net: send 'hello from gbos'"); nl();
- slip_send("hello from gbos", 15);
- len = slip_recv(buf, 63);
- buf[len] = 0;
- puts("net: recv '"); puts(buf); puts("'"); nl();
-}
diff --git a/c/netd.c b/c/netd.c
deleted file mode 100644
index b07abd2..0000000
--- a/c/netd.c
+++ /dev/null
@@ -1,12 +0,0 @@
-#include "sock.h"
-/* netd - the network daemon. It just pumps the kernel RX path; the kernel's
- socket layer owns SLIP/IP and auto-answers inbound ICMP echo requests, so
- running netd makes the Game Boy respond to pings. No SLIP/IP here anymore. */
-
-void main(void) {
- puts("netd: up (10.0.0.2)"); nl();
- for (;;) {
- net_poll(); /* drain RX, answer pings */
- yield();
- }
-}
diff --git a/c/netlib.h b/c/netlib.h
deleted file mode 100644
index ec98eac..0000000
--- a/c/netlib.h
+++ /dev/null
@@ -1,39 +0,0 @@
-#ifndef NETLIB_H
-#define NETLIB_H
-/* SLIP (RFC 1055) framing over the link port. Header-only so each program gets
- its own copy (the C build links one translation unit per program). */
-#include "gbos.h"
-
-#define SLIP_END 0xC0
-#define SLIP_ESC 0xDB
-#define SLIP_ESC_END 0xDC
-#define SLIP_ESC_ESC 0xDD
-
-/* send a framed packet (len up to 255) */
-static void slip_send(const char *buf, unsigned char len) {
- unsigned char i, c;
- ssend(SLIP_END);
- for (i = 0; i < len; i++) {
- c = (unsigned char)buf[i];
- if (c == SLIP_END) { ssend(SLIP_ESC); ssend(SLIP_ESC_END); }
- else if (c == SLIP_ESC) { ssend(SLIP_ESC); ssend(SLIP_ESC_ESC); }
- else ssend(c);
- }
- ssend(SLIP_END);
-}
-
-/* receive one framed packet into buf (max), returns its length */
-static unsigned char slip_recv(char *buf, unsigned char max) {
- unsigned char len = 0, c;
- for (;;) {
- c = srecv();
- if (c == SLIP_END) { if (len) return len; continue; }
- if (c == SLIP_ESC) {
- c = srecv();
- if (c == SLIP_ESC_END) c = SLIP_END;
- else if (c == SLIP_ESC_ESC) c = SLIP_ESC;
- }
- if (len < max) buf[len++] = (char)c;
- }
-}
-#endif
diff --git a/c/nslookup.c b/c/nslookup.c
deleted file mode 100644
index 6a531b8..0000000
--- a/c/nslookup.c
+++ /dev/null
@@ -1,23 +0,0 @@
-#include "resolve.h"
-/* nslookup HOST - resolve a hostname to an IPv4 address via DNS over UDP.
- All the DNS logic lives in resolve.h (shared with wget). */
-
-static unsigned char namebuf[64]; /* first so it lands past the arg at 0xA000 */
-static unsigned char ip[4];
-
-void main(void) {
- char *host;
- unsigned char i;
- host = getargs();
- if (!host || !*host) { puts("usage: nslookup HOST"); nl(); sexit(1); }
- for (i = 0; host[i] && i < 63; i++) namebuf[i] = (unsigned char)host[i];
- namebuf[i] = 0;
-
- if (resolve((char *)namebuf, ip)) {
- puts((char *)namebuf); puts(" -> ");
- for (i = 0; i < 4; i++) { putu(ip[i]); if (i < 3) putc('.'); }
- nl();
- } else {
- puts("nslookup: cannot resolve "); puts((char *)namebuf); nl();
- }
-}
diff --git a/c/pid.c b/c/pid.c
deleted file mode 100644
index 9e4e792..0000000
--- a/c/pid.c
+++ /dev/null
@@ -1,2 +0,0 @@
-#include "gbos.h"
-void main(void) { putu(getpid()); nl(); }
diff --git a/c/ping.c b/c/ping.c
deleted file mode 100644
index 8671318..0000000
--- a/c/ping.c
+++ /dev/null
@@ -1,61 +0,0 @@
-#include "resolve.h"
-/* ping HOST|IP - originate ICMP echo requests via the kernel socket layer.
- Resolves a hostname via DNS first (resolve.h); default target 10.0.0.1. No
- SLIP/IP/checksums here - the kernel owns all of that. */
-
-/* rbuf is first + large so namebuf/dst land past the arg string at 0xA000 */
-static unsigned char rbuf[96];
-static unsigned char namebuf[64];
-static unsigned char dst[4];
-static unsigned char payload[4];
-
-static void put_ip(unsigned char *ip) {
- unsigned char i;
- for (i = 0; i < 4; i++) { putu(ip[i]); if (i < 3) putc('.'); }
-}
-
-/* wait up to ~2s for an echo reply without blocking in the kernel: a lost
- reply (some hosts rate-limit ICMP) must cost one "timeout" line, not
- minutes wedged inside net_recv's pump-counted wait. */
-static unsigned char wait_reply(unsigned char s) {
- unsigned char t, r;
- for (t = 0; t < 40; t++) {
- r = net_recv_nb(s, rbuf, (unsigned char)sizeof(rbuf));
- if (r != 0xFE) return r; /* reply (or error) */
- msleep(50);
- }
- return 0xFF; /* ~2s with no reply */
-}
-
-void main(void) {
- char *arg;
- unsigned char s, seq, got = 0, i;
- arg = getargs();
- if (!arg || !*arg) { dst[0] = 10; dst[1] = 0; dst[2] = 0; dst[3] = 1; }
- else {
- for (i = 0; arg[i] && i < 63; i++) namebuf[i] = (unsigned char)arg[i];
- namebuf[i] = 0;
- if (!resolve((char *)namebuf, dst)) {
- puts("ping: cannot resolve "); puts((char *)namebuf); nl(); sexit(1);
- }
- }
-
- payload[0] = 'g'; payload[1] = 'b'; payload[2] = 'o'; payload[3] = 's';
- s = net_socket(SOCK_ICMP);
- if (s == 0xFF) { puts("ping: no socket"); nl(); sexit(1); }
- net_connect(s, dst, 0);
-
- puts("PING "); put_ip(dst); nl();
- for (seq = 1; seq <= 4; seq++) {
- net_send(s, payload, 4);
- if (wait_reply(s) != 0xFF) {
- got++;
- puts(" reply from "); put_ip(dst); puts(" seq="); putu(seq); nl();
- } else {
- puts(" seq="); putu(seq); puts(" timeout"); nl();
- }
- if (seq < 4) msleep(800); /* pace like real ping */
- }
- puts("-- "); putu(got); puts("/4 received"); nl();
- net_close(s);
-}
diff --git a/c/ps.c b/c/ps.c
deleted file mode 100644
index 7bfc0de..0000000
--- a/c/ps.c
+++ /dev/null
@@ -1,14 +0,0 @@
-#include "gbos.h"
-/* ps: list live processes (pid, state, command). */
-void main(void) {
- unsigned char i, buf[3];
- char name[9];
- for (i = 0; i < 8; i++) {
- if (psget(i, buf)) { /* buf = {pid, state, prog} */
- putu(buf[0]); putc(' ');
- putc("-RrBZ"[buf[1]]); putc(' ');
- progname(buf[2], name);
- puts(name); nl();
- }
- }
-}
diff --git a/c/ptest.c b/c/ptest.c
deleted file mode 100644
index 88b7d30..0000000
--- a/c/ptest.c
+++ /dev/null
@@ -1,19 +0,0 @@
-#include "gbos.h"
-/* ptest: exercise the kernel pipe in one process - write some bytes, read them
- back, then close the write end and confirm the reader sees EOF. */
-void main(void) {
- unsigned char pr = pipe();
- unsigned char pw = pr + 1;
- int c;
- if (pr == NOFD) { puts("pipe: none free"); nl(); return; }
- fputc(pw, 'H'); fputc(pw, 'i'); fputc(pw, '!');
- c = fgetc(pr); putc(c);
- c = fgetc(pr); putc(c);
- c = fgetc(pr); putc(c);
- nl();
- close(pw); /* last writer gone */
- c = fgetc(pr);
- if (c < 0) puts("EOF"); else { puts("got "); putc(c); }
- nl();
- close(pr);
-}
diff --git a/c/resolve.h b/c/resolve.h
deleted file mode 100644
index 9aaccc1..0000000
--- a/c/resolve.h
+++ /dev/null
@@ -1,81 +0,0 @@
-#ifndef RESOLVE_H
-#define RESOLVE_H
-/* resolve.h - turn a dotted-quad OR a hostname into an IPv4 address. Hostname
- lookups go out as a DNS A query over a UDP socket to 1.1.1.1:53; the kernel
- owns UDP, this owns DNS. Header-only (one copy per program). */
-#include "sock.h"
-
-static unsigned char _dnsbuf[200];
-static unsigned char _dnssrv[4];
-
-/* parse "A.B.C.D" into out[4]; return 1 on success */
-static unsigned char parse_ip(char *s, unsigned char *out) {
- unsigned char i, v;
- for (i = 0; i < 4; i++) {
- if (*s < '0' || *s > '9') return 0;
- v = 0;
- while (*s >= '0' && *s <= '9') { v = (unsigned char)(v * 10 + (*s - '0')); s++; }
- out[i] = v;
- if (i < 3) { if (*s != '.') return 0; s++; }
- }
- return 1;
-}
-
-static unsigned char _dns_query(char *host) {
- unsigned char i = 0, p = 12, lblpos, len;
- _dnsbuf[0] = 0x12; _dnsbuf[1] = 0x34; _dnsbuf[2] = 0x01; _dnsbuf[3] = 0x00;
- _dnsbuf[4] = 0; _dnsbuf[5] = 1;
- _dnsbuf[6] = 0; _dnsbuf[7] = 0; _dnsbuf[8] = 0; _dnsbuf[9] = 0; _dnsbuf[10] = 0; _dnsbuf[11] = 0;
- while (host[i]) {
- lblpos = p++; len = 0;
- while (host[i] && host[i] != '.') { _dnsbuf[p++] = host[i]; i++; len++; }
- _dnsbuf[lblpos] = len;
- if (host[i] == '.') i++;
- }
- _dnsbuf[p++] = 0; _dnsbuf[p++] = 0; _dnsbuf[p++] = 1; _dnsbuf[p++] = 0; _dnsbuf[p++] = 1;
- return p;
-}
-static unsigned int _dns_skip(unsigned int p) {
- for (;;) {
- if (_dnsbuf[p] == 0) return p + 1;
- if ((_dnsbuf[p] & 0xC0) == 0xC0) return p + 2;
- p += _dnsbuf[p] + 1;
- }
-}
-static unsigned char _dns_answer(unsigned char *ip) {
- unsigned int p, a, an, type, rdlen;
- an = ((unsigned int)_dnsbuf[6] << 8) | _dnsbuf[7];
- if (an == 0) return 0;
- p = _dns_skip(12) + 4;
- for (a = 0; a < an; a++) {
- p = _dns_skip(p);
- type = ((unsigned int)_dnsbuf[p] << 8) | _dnsbuf[p + 1];
- p += 8;
- rdlen = ((unsigned int)_dnsbuf[p] << 8) | _dnsbuf[p + 1];
- p += 2;
- if (type == 1 && rdlen == 4) {
- ip[0] = _dnsbuf[p]; ip[1] = _dnsbuf[p + 1]; ip[2] = _dnsbuf[p + 2]; ip[3] = _dnsbuf[p + 3];
- return 1;
- }
- p += rdlen;
- }
- return 0;
-}
-
-/* resolve a dotted-quad or hostname into ip[4]; return 1 on success */
-static unsigned char resolve(char *host, unsigned char *ip) {
- unsigned char s, n;
- if (parse_ip(host, ip)) return 1; /* already an address */
- _dnssrv[0] = 1; _dnssrv[1] = 1; _dnssrv[2] = 1; _dnssrv[3] = 1;
- s = net_socket(SOCK_UDP);
- if (s == 0xFF) return 0;
- net_bind(s, 40000);
- net_connect(s, _dnssrv, 53);
- n = _dns_query(host);
- net_send(s, _dnsbuf, n);
- n = net_recv(s, _dnsbuf, 200);
- net_close(s);
- if (n == 0xFF) return 0;
- return _dns_answer(ip);
-}
-#endif
diff --git a/c/rm.c b/c/rm.c
deleted file mode 100644
index 25f3004..0000000
--- a/c/rm.c
+++ /dev/null
@@ -1,7 +0,0 @@
-#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
deleted file mode 100644
index 1755fea..0000000
--- a/c/save.c
+++ /dev/null
@@ -1,19 +0,0 @@
-#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 > 3) { 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/sh.c b/c/sh.c
deleted file mode 100644
index 3178894..0000000
--- a/c/sh.c
+++ /dev/null
@@ -1,200 +0,0 @@
-#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; }
-static unsigned char iscmd(char *t, char a, char b) {
- return t[0] == a && t[1] == b && t[2] == 0;
-}
-
-/* keep the prompt's path string roughly in sync with chdir(). */
-static void set_cwd(char *cwd, char *arg) {
- char *d, *s, *last;
- if (arg[0] == '/') { /* absolute */
- d = cwd; s = arg;
- while (*s) *d++ = *s++;
- *d = 0;
- } else if (arg[0] == '.' && arg[1] == '.' && arg[2] == 0) {
- last = cwd; d = cwd;
- while (*d) { if (*d == '/') last = d; d++; }
- if (last == cwd) { cwd[0] = '/'; cwd[1] = 0; } else *last = 0;
- } else if (arg[0] == '.' && arg[1] == 0) {
- /* stay */
- } else { /* relative: append */
- d = cwd; while (*d) d++;
- if (!(cwd[0] == '/' && cwd[1] == 0)) *d++ = '/';
- s = arg; while (*s) *d++ = *s++;
- *d = 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.
- If bg, launch in the background (don't wait; leave fds to the child). */
-static void run(char **tok, unsigned char start, unsigned char end,
- unsigned char infd, unsigned char outfd, unsigned char bg) {
- 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);
- }
- if (bg) { putc('['); putu(pid); puts("]"); nl(); return; } /* background */
- /* wait for THIS child; report any background jobs that finish meanwhile */
- for (;;) {
- unsigned char r = wait();
- if (r == pid || r == NOFD) break;
- putc('['); putu(r); puts(" done]"); nl();
- }
-done:
- if (myin != NOFD) close(myin);
- if (myout != NOFD) close(myout);
-}
-
-/* run a multi-stage pipeline (a | b | c): wire stages together with real
- kernel pipes, launch them ALL concurrently, then wait for them. */
-static void run_pipeline(char **tok, unsigned char nt) {
- unsigned char pids[8], npid = 0;
- unsigned char cfd[8], ncfd = 0; /* file-redirect fds; closed after all exit */
- unsigned char start = 0, prev_r = NOFD;
- for (;;) {
- unsigned char end = start, last, i, cmdend, fin = NOFD, fout = NOFD;
- unsigned char my_out = NOFD, next_r = NOFD, id, pid;
- while (end < nt && !isop(tok[end], '|')) end++;
- last = (end >= nt);
- if (!last) { /* pipe from this stage to the next */
- unsigned char pr = pipe();
- if (pr != NOFD) { next_r = pr; my_out = pr + 1; }
- }
- cmdend = end; /* this stage's own >/< redirects */
- for (i = start; i < end; i++) {
- if (isop(tok[i], '>')) { if (i + 1 < end) fout = open(tok[i+1], O_WRITE); if (i < cmdend) cmdend = i; }
- else if (isop(tok[i], '<')) { if (i + 1 < end) fin = 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();
- if (prev_r != NOFD) close(prev_r); /* orphaned pipe ends -> EOF/EPIPE */
- if (my_out != NOFD) close(my_out);
- if (fin != NOFD) close(fin);
- if (fout != NOFD) close(fout);
- } else {
- set_cmdline(tok, start, cmdend);
- pid = fork();
- if (pid == 0) {
- if (fin != NOFD) setin(fin); else if (prev_r != NOFD) setin(prev_r);
- if (fout != NOFD) setout(fout); else if (my_out != NOFD) setout(my_out);
- exec(id);
- }
- if (npid < 8) pids[npid++] = pid;
- if (fin != NOFD && ncfd < 8) cfd[ncfd++] = fin;
- if (fout != NOFD && ncfd < 8) cfd[ncfd++] = fout;
- }
- prev_r = next_r;
- if (last) break;
- start = end + 1;
- }
- { unsigned char got = 0; /* wait for all stages */
- while (got < npid) {
- unsigned char r = wait(), j, mine = 0;
- if (r == NOFD) break;
- for (j = 0; j < npid; j++) if (pids[j] == r) { mine = 1; break; }
- if (mine) got++;
- else { putc('['); putu(r); puts(" done]"); nl(); }
- }
- }
- { unsigned char k; for (k = 0; k < ncfd; k++) close(cfd[k]); }
-}
-
-void main(void) {
- char line[80];
- char *tok[16];
- char cwd[40];
- cwd[0] = '/'; cwd[1] = 0;
- /* bring up networking first: run the DHCP client and wait for it to finish
- (got a lease, or gave up). Only then drop to the prompt. */
- {
- unsigned char d = lookup("dhcp");
- if (d != NOFD) { if (fork() == 0) exec(d); else wait(); }
- }
- for (;;) {
- unsigned char nt, i, pipepos, c, bg;
- /* reap finished background jobs */
- { unsigned char p; while ((p = reap())) { putc('['); putu(p); puts(" done]"); nl(); } }
- puts(cwd); puts("# ");
- /* read a line (echoing), stop at newline; exit on EOF */
- i = 0;
- for (;;) {
- c = readc();
- if (c == EOF) poweroff();
- if (c == '\r' || c == '\n') { nl(); break; }
- if (c == 8 || c == 127) { /* backspace: drop last char */
- if (i > 0) { i--; putc(8); }
- continue;
- }
- if (i < 79) { line[i++] = c; putc(c); }
- }
- line[i] = 0;
- nt = tokenize(line, tok, 16);
- if (nt == 0) continue;
- if (iscmd(tok[0], 'c', 'd')) { /* cd builtin */
- char *arg = (nt >= 2) ? tok[1] : "/";
- if (chdir(arg) == 0) set_cwd(cwd, arg);
- else { puts("cd: no such directory"); nl(); }
- continue;
- }
- if ((tok[0][0] == 'e' && tok[0][1] == 'x') ||
- (tok[0][0] == 'q' && tok[0][1] == 'u')) poweroff();
- bg = 0;
- if (isop(tok[nt - 1], '&')) { bg = 1; nt--; if (nt == 0) continue; }
- pipepos = 0;
- for (i = 1; i < nt; i++)
- if (isop(tok[i], '|')) { pipepos = i; break; }
- if (pipepos) run_pipeline(tok, nt);
- else run(tok, 0, nt, NOFD, NOFD, bg);
- }
-}
diff --git a/c/sock.h b/c/sock.h
deleted file mode 100644
index 876e85c..0000000
--- a/c/sock.h
+++ /dev/null
@@ -1,71 +0,0 @@
-#ifndef SOCK_H
-#define SOCK_H
-/* gbos socket API - the kernel owns SLIP/IP/ICMP/UDP/TCP; programs just do
- socket()/connect()/send()/recv()/close(). Header-only: one copy per program.
- The netreq layout must match include/gbos.inc (NR_* / NET_* / SOCK_*). */
-#include "gbos.h"
-
-#define SOCK_ICMP 1
-#define SOCK_UDP 2
-#define SOCK_TCP 3
-
-struct netreq {
- unsigned char op;
- unsigned char sock;
- unsigned char *buf;
- unsigned char len;
- unsigned char ip[4];
- unsigned char port_hi, port_lo;
-};
-static struct netreq _nr;
-
-/* -> socket id, or 0xFF if the table is full */
-static unsigned char net_socket(unsigned char type) {
- _nr.op = 0; _nr.sock = type;
- return sys_net(&_nr);
-}
-/* set the remote address/port for send()/recv() */
-static unsigned char net_connect(unsigned char s, const unsigned char *ip, unsigned int port) {
- unsigned char i;
- _nr.op = 1; _nr.sock = s;
- for (i = 0; i < 4; i++) _nr.ip[i] = ip[i];
- _nr.port_hi = (unsigned char)(port >> 8); _nr.port_lo = (unsigned char)port;
- return sys_net(&_nr);
-}
-/* send 'len' payload bytes to the connected peer -> 0 ok / 0xFF error */
-static unsigned char net_send(unsigned char s, void *buf, unsigned char len) {
- _nr.op = 2; _nr.sock = s; _nr.buf = (unsigned char *)buf; _nr.len = len;
- return sys_net(&_nr);
-}
-/* receive up to 'max' payload bytes -> length, or 0xFF on timeout */
-static unsigned char net_recv(unsigned char s, void *buf, unsigned char max) {
- _nr.op = 3; _nr.sock = s; _nr.buf = (unsigned char *)buf; _nr.len = max;
- return sys_net(&_nr);
-}
-/* non-blocking recv: one RX pump -> length, 0xFE if nothing buffered yet,
- 0 on TCP EOF. Loop it with msleep() to own your timeout (see ping). */
-static unsigned char net_recv_nb(unsigned char s, void *buf, unsigned char max) {
- _nr.op = 8; _nr.sock = s; _nr.buf = (unsigned char *)buf; _nr.len = max;
- return sys_net(&_nr);
-}
-/* set the local (source) port - needed so UDP replies demux back to us */
-static unsigned char net_bind(unsigned char s, unsigned int port) {
- _nr.op = 5; _nr.sock = s;
- _nr.port_hi = (unsigned char)(port >> 8); _nr.port_lo = (unsigned char)port;
- return sys_net(&_nr);
-}
-static void net_close(unsigned char s) {
- _nr.op = 4; _nr.sock = s; sys_net(&_nr);
-}
-/* pump the RX path once (answers inbound pings) without blocking */
-static void net_poll(void) {
- _nr.op = 6; sys_net(&_nr);
-}
-/* set our IPv4 address (the DHCP client calls this once it has a lease) */
-static void net_setip(const unsigned char *ip) {
- unsigned char i;
- _nr.op = 7;
- for (i = 0; i < 4; i++) _nr.ip[i] = ip[i];
- sys_net(&_nr);
-}
-#endif
diff --git a/c/spin.c b/c/spin.c
deleted file mode 100644
index 2a3d4e8..0000000
--- a/c/spin.c
+++ /dev/null
@@ -1,6 +0,0 @@
-#include "gbos.h"
-/* spin: a harmless long-running process that just yields forever.
- Useful as a target for `ps` and `kill`. */
-void main(void) {
- for (;;) yield();
-}
diff --git a/c/true.c b/c/true.c
deleted file mode 100644
index 4cf437e..0000000
--- a/c/true.c
+++ /dev/null
@@ -1,2 +0,0 @@
-#include "gbos.h"
-void main(void) { sexit(0); }
diff --git a/c/uname.c b/c/uname.c
deleted file mode 100644
index 511501d..0000000
--- a/c/uname.c
+++ /dev/null
@@ -1,2 +0,0 @@
-#include "gbos.h"
-void main(void) { puts("gbos sm83 (Game Boy Color)"); nl(); }
diff --git a/c/wc.c b/c/wc.c
deleted file mode 100644
index 4fa48ee..0000000
--- a/c/wc.c
+++ /dev/null
@@ -1,32 +0,0 @@
-#include "gbos.h"
-/* 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);
- unsigned char wl = hasflag(argv, argc, 'l');
- 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, 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 > 3) { puts("wc: no such file"); nl(); return; }
- }
- for (;;) {
- if (fd > 3) { char c = readc(); if (c == EOF) break; ch = c; }
- else { ch = fgetc(fd); if (ch < 0) break; }
- chars++;
- 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); }
- nl();
-}
diff --git a/c/wget.c b/c/wget.c
deleted file mode 100644
index aafbae0..0000000
--- a/c/wget.c
+++ /dev/null
@@ -1,43 +0,0 @@
-#include "resolve.h"
-/* wget HOST|IP - fetch http://HOST/ over the kernel TCP socket layer and print
- it. Resolves a hostname via DNS first (resolve.h), then connect()/send()/
- recv() over TCP - all the SLIP/IP/UDP/TCP lives in the kernel. */
-
-static unsigned char buf[220]; /* first + large so namebuf/dst land arg-safe */
-static unsigned char namebuf[64];
-static unsigned char dst[4];
-
-void main(void) {
- char *arg, *r;
- unsigned char s, n, i;
- arg = getargs();
- if (!arg || !*arg) { puts("usage: wget HOST|IP"); nl(); sexit(1); }
- for (i = 0; arg[i] && i < 63; i++) namebuf[i] = (unsigned char)arg[i];
- namebuf[i] = 0;
-
- if (!resolve((char *)namebuf, dst)) {
- puts("wget: cannot resolve "); puts((char *)namebuf); nl(); sexit(1);
- }
- puts("connecting "); for (i = 0; i < 4; i++) { putu(dst[i]); if (i < 3) putc('.'); } nl();
-
- s = net_socket(SOCK_TCP);
- if (s == 0xFF) { puts("wget: no socket"); nl(); sexit(1); }
- net_bind(s, 40001);
- if (net_connect(s, dst, 80) == 0xFF) { puts("wget: connect failed"); nl(); net_close(s); sexit(1); }
-
- /* GET / HTTP/1.0 with the requested host as the Host header */
- r = "GET / HTTP/1.0\r\nHost: ";
- n = 0;
- while (r[n]) { buf[n] = (unsigned char)r[n]; n++; }
- for (i = 0; namebuf[i]; i++) buf[n++] = namebuf[i];
- buf[n++] = '\r'; buf[n++] = '\n'; buf[n++] = '\r'; buf[n++] = '\n';
- net_send(s, buf, n);
-
- for (;;) {
- n = net_recv(s, buf, (unsigned char)sizeof(buf));
- if (n == 0xFF) { nl(); puts("[timeout]"); nl(); break; }
- if (n == 0) { nl(); puts("[eof]"); nl(); break; }
- for (i = 0; i < n; i++) putc((char)buf[i]);
- }
- net_close(s);
-}