aboutsummaryrefslogtreecommitdiffstats
path: root/c/sh.c
blob: c24ed9fd48a1473ce6d543160f9f1df81a98788d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#include "gbos.h"
/* gbos shell: prompt -> 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);
        }
    }
}