aboutsummaryrefslogtreecommitdiffstats
path: root/c/sh.c
diff options
context:
space:
mode:
authoruser <user@clank>2026-07-16 12:49:19 +0200
committeruser <user@clank>2026-07-16 12:49:19 +0200
commit5fefd233769a56caefdb2ffecaa9fb8b9ec6db86 (patch)
tree99f5b285a45c7b3792bb64e79fe58f70a6d01cab /c/sh.c
parentfs rewrite stage 2: inodes + root directory (block-based, persistent) (diff)
downloadgbos-5fefd233769a56caefdb2ffecaa9fb8b9ec6db86.tar.gz
gbos-5fefd233769a56caefdb2ffecaa9fb8b9ec6db86.tar.xz
gbos-5fefd233769a56caefdb2ffecaa9fb8b9ec6db86.zip
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 <dir>' 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.
Diffstat (limited to '')
-rw-r--r--c/sh.c38
1 files changed, 36 insertions, 2 deletions
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;