<feed xmlns='http://www.w3.org/2005/Atom'>
<title>gbos.git/c/sh.c, branch master</title>
<subtitle>gbos - a tiny Unix-flavored OS for the Game Boy Color (kernel, shell, coreutils in C, RAM filesystem)</subtitle>
<id>https://git.sl0p.foo/gbos.git/atom/c/sh.c?h=master</id>
<link rel='self' href='https://git.sl0p.foo/gbos.git/atom/c/sh.c?h=master'/>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/gbos.git/'/>
<updated>2026-07-17T22:38:38Z</updated>
<entry>
<title>refactor: c/ -&gt; usr/, compiled program blobs out of the source tree</title>
<updated>2026-07-17T22:38:38Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-07-17T22:38:38Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/gbos.git/commit/?id=ba2d7ae1d7b319645b10aaa31a7f664f9f80c25c'/>
<id>urn:sha1:ba2d7ae1d7b319645b10aaa31a7f664f9f80c25c</id>
<content type='text'>
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.
</content>
</entry>
<entry>
<title>net: DHCP client - lease the IP at boot instead of hardcoding it</title>
<updated>2026-07-17T12:11:22Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-07-17T12:11:22Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/gbos.git/commit/?id=a2cb756693229c7880d926d2cdde2f838c697415'/>
<id>urn:sha1:a2cb756693229c7880d926d2cdde2f838c697415</id>
<content type='text'>
The address is no longer baked in. net_init starts at 0.0.0.0; a DHCP client
runs as the first thing on boot (init/shell forks it and waits), and only once
it has a lease (or gives up) does the prompt appear.

Kernel:
- IP is configurable: 0.0.0.0 until leased; NET_SETIP op stores it.
- 16-bit frame length. DHCP/BOOTP packets are ~272 bytes, over the old 255-byte
  frame cap, so net_slip_send takes a 16-bit length, net_pump assembles into a
  320-byte buffer with a 16-bit wNetRxLen, and udp_send writes a 16-bit IP total.
  Payloads stay &lt;=255 (kept small on purpose) so the per-protocol datalen math
  is unchanged. wNetTx/wNetRxBuf 256-&gt;320, SK_RXBUF 208-&gt;288.

Userland:
- c/dhcp.c: DISCOVER-&gt;OFFER-&gt;REQUEST-&gt;ACK over a UDP socket, then net_setip();
  times out gracefully (shell still boots) if there's no server. sh.c runs it
  before the prompt.

Bridge (self-contained DHCP server, no dnsmasq):
- tunbridge.py + netboot intercept UDP-&gt;:67 and answer OFFER/ACK leasing
  10.0.0.2 (gateway 10.0.0.1); everything else is bridged/NATed as before.

Regression-tested ICMP/UDP/TCP after the 16-bit change. Verified end to end:
    dhcp: discovering
    dhcp: leased 10.0.0.2
    /# ping 10.0.0.1   -&gt; 4/4 (traffic from the leased address)
</content>
</entry>
<entry>
<title>kernel+sh: real anonymous pipes (concurrent, streaming, SIGPIPE)</title>
<updated>2026-07-16T23:04:16Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-07-16T23:04:16Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/gbos.git/commit/?id=73295e7acc1e5ec3ee8814fd4ccc45f7cee63392'/>
<id>urn:sha1:73295e7acc1e5ec3ee8814fd4ccc45f7cee63392</id>
<content type='text'>
Replace the shell's temp-file pipe hack with proper in-kernel FIFOs.

Kernel (src/pipe.asm, new):
- A small pool of bounded ring buffers (PIPE_MAX=2, 64 B each) with
  writers/readers refcounts. Pipe fds are $F0+idx*2 (read) / +1 (write);
  $FF stays "console".
- SYS_PIPE allocates one (writers=readers=1) and returns the read fd
  (write = read+1). getb/putb/close dispatch pipe fds here; sys_exit drops
  the refcounts held as PROC_STDIN/PROC_STDOUT.
- Blocking with SchedYield, which is the flow control: read blocks while
  empty with a writer (EOF once writers hit 0), write blocks while full
  with a reader, and if the last reader is gone the writer is killed
  (SIGPIPE -&gt; exit 141). Cooperative-scheduler friendly.

Shell (c/sh.c):
- run_pipeline(): split on '|', make a pipe between adjacent stages, and
  fork ALL stages concurrently (no wait between), wiring stdin/stdout;
  then wait for all. Per-stage &gt;/&lt; still honored; orphaned pipe ends are
  closed on a lookup miss so EOF/EPIPE propagate.
- Drop the __pipe temp file and its 2 KB / serialized limits.

libc: pipe(). New c/ptest.c exercises the FIFO (write, read back, EOF).

Now works (old version couldn't): multi-stage a|b|c; streaming beyond 2 KB
(count 120 | wc = 3372 bytes through a 64 B buffer); early-exit SIGPIPE
(count 200 | true kills count instead of hanging/overflowing a file).
</content>
</entry>
<entry>
<title>sh: handle backspace in readline; prompt is now '#'</title>
<updated>2026-07-16T14:17:02Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-07-16T14:17:02Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/gbos.git/commit/?id=30f3a65e2de99cdffd091289b4edb8e14be9032d'/>
<id>urn:sha1:30f3a65e2de99cdffd091289b4edb8e14be9032d</id>
<content type='text'>
readc() returning $08/$7F now drops the last char from the command buffer
(and emits one $08 so the terminal erases it) instead of storing the raw
byte. Previously "lz&lt;bksp&gt;s" left the buffer as "lz\x08s", so the command
"ls" was reported "not found" even though the screen showed "ls".
Also change the shell prompt from '$' to '#'.

osk: B button types the selected key SHIFTED (uppercase a-z). A types the
key as shown (lowercase/digit/symbol); B on a letter subtracts 32 for the
uppercase glyph (the font already has A-Z). Non-letters are unchanged.
</content>
</entry>
<entry>
<title>fs rewrite stage 3: nested directories, paths, cwd (cd/mkdir/ls)</title>
<updated>2026-07-16T10:49:19Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-07-16T10:49:19Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/gbos.git/commit/?id=5fefd233769a56caefdb2ffecaa9fb8b9ec6db86'/>
<id>urn:sha1:5fefd233769a56caefdb2ffecaa9fb8b9ec6db86</id>
<content type='text'>
- directories generalized: dir_find/dir_add/dir_remove take any dir inode;
  every dir carries '.'/'..'. Path resolution (resolve / resolve_parent) walks
  absolute or cwd-relative paths; open/mkdir/chdir/remove/opendir take paths.
- per-process cwd: PROC_CWD in the PCB (root by default, inherited on fork);
  sys_chdir sets it, sys_opendir points ls at any directory.
- shell: 'cd' builtin + cwd-aware prompt; 'mkdir'/'ls &lt;dir&gt;' tools; 'exit'/'quit'
  and EOF call poweroff() (clean shutdown via the $ED opcode -&gt; reliable save).
- three HL/buffer-clobber bugs fixed along the way: resolve didn't preserve the
  path cursor across dir_find; cur_cwd clobbered HL; resolve_parent set the final
  name before resolve() overwrote wFsNameBuf (now copied after).
- verified: nested mkdir/cd/save, multi-level paths (cat docs/sub/b), and the
  whole tree persists across a reboot.
- README: document directories + the poweroff opcode.
</content>
</entry>
<entry>
<title>jobs: background execution (&amp;), non-blocking reap, spin demo</title>
<updated>2026-07-16T09:15:12Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-07-16T09:15:12Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/gbos.git/commit/?id=bb4f468b73c8a888bec1e5b2ba7f1575ab7f8456'/>
<id>urn:sha1:bb4f468b73c8a888bec1e5b2ba7f1575ab7f8456</id>
<content type='text'>
- sys_reap: nohang reap of a finished zombie child (-&gt; pid or 0).
- shell: 'cmd &amp;' launches in the background (prints [pid], no wait); reaps
  finished jobs at the prompt ([pid done]). Foreground now waits for its own
  child specifically (loops wait(), reporting bg completions meanwhile) so kill
  reports the right pid.
- spin: a process that yields forever - a target for ps/kill.
- verified: spin &amp;; ps shows it; kill &lt;pid&gt; removes just that one; immortal
  init; self-finishing bg worker reaped with [pid done].
</content>
</entry>
<entry>
<title>shell: I/O redirection (&gt;/&lt;) and pipes (|); rewrite shell in C</title>
<updated>2026-07-16T06:25:35Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-07-16T06:25:35Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/gbos.git/commit/?id=6c64d97e70984c77be3cd8d4e03e9adf717e02fb'/>
<id>urn:sha1:6c64d97e70984c77be3cd8d4e03e9adf717e02fb</id>
<content type='text'>
- kernel I/O routing: PCB gains PROC_STDIN/PROC_STDOUT (default console $FF),
  inherited across fork. KGetc/KPutc route read/write/putc to the console or a
  file fd. New syscalls: putc(16), setin(17), setout(18), lookup(19).
  read/write now go through the routing; putc/puts/nl use SYS_PUTC.
- sys_lookup + NameTable move command-name resolution into the kernel.
- shell rewritten in C (c/sh.c): tokenizes a line, parses &gt; / &lt; / |, and drives
  fork+setin/setout+exec+wait. Pipes run as 'a &gt; __pipe ; b &lt; __pipe' (temp
  file). asm shell + cmdtab removed; StrEqual/SkipName kept for sys_lookup.
- libc: fork/exec/wait/setin/setout/lookup wrappers.
- verified: echo&gt;file, cat file, wc&lt;file, cat readme|wc -l, echo ...|wc.
</content>
</entry>
</feed>
