From 5fefd233769a56caefdb2ffecaa9fb8b9ec6db86 Mon Sep 17 00:00:00 2001 From: user Date: Thu, 16 Jul 2026 12:49:19 +0200 Subject: fs rewrite stage 3: nested directories, paths, cwd (cd/mkdir/ls) - 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 ' tools; 'exit'/'quit' and EOF call poweroff() (clean shutdown via the $ED opcode -> 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. --- c/sh.c | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) (limited to 'c/sh.c') diff --git a/c/sh.c b/c/sh.c index 8aa619e..b1bf630 100644 --- a/c/sh.c +++ b/c/sh.c @@ -18,6 +18,30 @@ static unsigned char tokenize(char *s, char **tok, unsigned char max) { } 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) { @@ -74,22 +98,32 @@ done: void main(void) { char line[80]; char *tok[16]; + char cwd[40]; + cwd[0] = '/'; cwd[1] = 0; 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("$ "); + puts(cwd); puts("$ "); /* read a line (echoing), stop at newline; exit on EOF */ i = 0; for (;;) { c = readc(); - if (c == EOF) return; + if (c == EOF) poweroff(); if (c == '\r' || c == '\n') { nl(); break; } 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; -- cgit v1.3.1-sl0p