diff options
| author | user <user@clank> | 2026-07-18 00:38:38 +0200 |
|---|---|---|
| committer | user <user@clank> | 2026-07-18 00:38:38 +0200 |
| commit | ba2d7ae1d7b319645b10aaa31a7f664f9f80c25c (patch) | |
| tree | e01e6c7c710a661defe2515ff9657f08cddcb283 /c | |
| parent | tools: gbtype prints hub errors to stderr and exits 1 (diff) | |
| download | gbos-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.c | 12 | ||||
| -rw-r--r-- | c/blk.c | 13 | ||||
| -rwxr-xr-x | c/build.sh | 21 | ||||
| -rw-r--r-- | c/cat.c | 17 | ||||
| -rw-r--r-- | c/chat.c | 57 | ||||
| -rw-r--r-- | c/chello.c | 9 | ||||
| -rw-r--r-- | c/count.c | 16 | ||||
| -rw-r--r-- | c/crt0.s | 11 | ||||
| -rw-r--r-- | c/dhcp.c | 72 | ||||
| -rw-r--r-- | c/echo.c | 5 | ||||
| -rw-r--r-- | c/false.c | 2 | ||||
| -rw-r--r-- | c/gbos.h | 64 | ||||
| -rw-r--r-- | c/head.c | 28 | ||||
| -rw-r--r-- | c/irc.c | 422 | ||||
| -rw-r--r-- | c/kill.c | 10 | ||||
| -rw-r--r-- | c/libc.c | 67 | ||||
| -rw-r--r-- | c/libc.s | 304 | ||||
| -rw-r--r-- | c/ls.c | 10 | ||||
| -rw-r--r-- | c/mkdir.c | 8 | ||||
| -rw-r--r-- | c/necho.c | 13 | ||||
| -rw-r--r-- | c/netd.c | 12 | ||||
| -rw-r--r-- | c/netlib.h | 39 | ||||
| -rw-r--r-- | c/nslookup.c | 23 | ||||
| -rw-r--r-- | c/pid.c | 2 | ||||
| -rw-r--r-- | c/ping.c | 61 | ||||
| -rw-r--r-- | c/ps.c | 14 | ||||
| -rw-r--r-- | c/ptest.c | 19 | ||||
| -rw-r--r-- | c/resolve.h | 81 | ||||
| -rw-r--r-- | c/rm.c | 7 | ||||
| -rw-r--r-- | c/save.c | 19 | ||||
| -rw-r--r-- | c/sh.c | 200 | ||||
| -rw-r--r-- | c/sock.h | 71 | ||||
| -rw-r--r-- | c/spin.c | 6 | ||||
| -rw-r--r-- | c/true.c | 2 | ||||
| -rw-r--r-- | c/uname.c | 2 | ||||
| -rw-r--r-- | c/wc.c | 32 | ||||
| -rw-r--r-- | c/wget.c | 43 |
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$ @@ -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); -} @@ -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 @@ -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); -} @@ -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(); } @@ -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); -} |
