#if 0 // simple example code error cd(Args args) { switch (args.len) { case 0: errorf("reached cd with no arguments!"); return 1; case 1: one: errorf("sh: expected argument to command 'cd'"); return 1; case 2: if (args.a[1] == nil) goto one; break; default: errorf("sh: too many arguments to command 'cd'"); return 1; } if (chdir(args.a[1])) errorf("cd fail: %s", strerror(errno)); return 0; } error quit(Args args) { exit(0); } Builtin builtins[] = { { "cd", cd }, { "exit", quit }, }; void clear(Header *arr) { arr->len = 0; } int readline(Code *code) { int n, b; n = code->len; getchar: if (code->len >= code->cap) { code->cap += 100; code->s = realloc(code->s, code->cap); } /* TODO: unicode? */ switch ((b = getchar())) { case EOF: n = -1; goto null; case '\n': n = code->len - n; null: code->s[code->len] = '\0'; break; default: code->s[code->len++] = b; goto getchar; } return n; } /* TODO: unicode */ int readargs(Code code, Args *args) { if (args->a) clear(&args->hdr); else { args->cap += 20; args->a = realloc(args->a, args->cap); } args->a[args->len++] = code.s; while (*code.s) { if (!isspace(*code.s++)) continue; code.s[-1] = '\0'; /* consume all remaining space */ while (isspace(*code.s)) code.s++; if (args->len >= args->cap-1) { args->cap += 20; args->a = realloc(args->a, args->cap); } args->a[args->len++] = code.s; } /* nil acts as a sentinel value */ args->a[args->len] = nil; return args->len; } error execute(Args args) { int i, status; pid_t cid, wid; for (i = 0; i < arrlen(builtins); i++) { if (strcmp(args.a[0], builtins[i].cmd) == 0) return builtins[i].func(args); } if ((cid = fork()) == 0) { if (execvp(args.a[0], args.a) == -1) errorf("exec failed: %s", strerror(errno)); exit(1); } else if (cid > 0) do wid = waitpid(cid, &status, WUNTRACED); while (!WIFEXITED(status) && !WIFSIGNALED(status)); else errorf("fork failed: %s", strerror(errno)); return status; } static void flush(void) { io·flush(stdout); } static void prompt(void) { printf(";"); flush(); } int main(int argc, char *argv[]) { int i, err, n; Code code = {0}; Args args = {0}; ARGBEGIN { } ARGEND; do { clear(&code.hdr); prompt(); n = readline(&code); readargs(code, &args); err = execute(args); } while (!err && n > 0); } #endif