From 6c64d97e70984c77be3cd8d4e03e9adf717e02fb Mon Sep 17 00:00:00 2001 From: user Date: Thu, 16 Jul 2026 08:25:35 +0200 Subject: shell: I/O redirection (>/<) and pipes (|); rewrite shell in C - 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 > / < / |, and drives fork+setin/setout+exec+wait. Pipes run as 'a > __pipe ; b < __pipe' (temp file). asm shell + cmdtab removed; StrEqual/SkipName kept for sys_lookup. - libc: fork/exec/wait/setin/setout/lookup wrappers. - verified: echo>file, cat file, wc 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; } + +/* 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. */ +static void run(char **tok, unsigned char start, unsigned char end, + unsigned char infd, unsigned char outfd) { + 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); + } + wait(); +done: + if (myin != NOFD) close(myin); + if (myout != NOFD) close(myout); +} + +void main(void) { + char line[80]; + char *tok[16]; + for (;;) { + unsigned char nt, i, pipepos, c; + puts("$ "); + /* read a line (echoing), stop at newline; exit on EOF */ + i = 0; + for (;;) { + c = readc(); + if (c == EOF) return; + 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; + pipepos = 0; + for (i = 1; i < nt; i++) + if (isop(tok[i], '|')) { pipepos = i; break; } + if (pipepos) { + unsigned char pw = open("__pipe", O_WRITE); + run(tok, 0, pipepos, NOFD, pw); + close(pw); + { unsigned char pr = open("__pipe", O_READ); + run(tok, pipepos + 1, nt, pr, NOFD); + close(pr); } + fremove("__pipe"); + } else { + run(tok, 0, nt, NOFD, NOFD); + } + } +} -- cgit v1.3.1-sl0p