rc

[fork] interactive rc shell
Log | Files | Refs | README | LICENSE

commit ed998daafc3b46899a4c59419a9ac584d3a5e883
parent 960afa1642f23d71c07be587ccf25c1a41b2fe98
Author: tim <tim>
Date:   Wed, 14 May 1997 16:24:26 +0000

Initial revision

Diffstat:
Aglom.c | 426+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 426 insertions(+), 0 deletions(-)

diff --git a/glom.c b/glom.c @@ -0,0 +1,426 @@ +/* glom.c: builds an argument list out of words, variables, etc. */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <signal.h> +#include <errno.h> +#include "rc.h" +#if !defined(S_IFIFO) && !defined(DEVFD) +#define NOCMDARG +#endif + +static List *backq(Node *, Node *); +static List *bqinput(List *, int); +static List *count(List *); +static List *mkcmdarg(Node *); + +Rq *redirq = NULL; + +extern List *word(char *w, char *m) { + List *s = NULL; + if (w != NULL) { + s = nnew(List); + s->w = w; + s->m = m; + s->n = NULL; + } + return s; +} + +/* + Append list s2 to list s1 by copying s1 and making the new copy + point at s2. +*/ + +extern List *append(List *s1, List *s2) { + List *r, *top; + if (s1 == NULL) + return s2; + if (s2 == NULL) + return s1; + for (r = top = nnew(List); 1; r = r->n = nnew(List)) { + r->w = s1->w; + r->m = s1->m; + if ((s1 = s1->n) == NULL) + break; + } + r->n = s2; + return top; +} + +extern List *concat(List *s1, List *s2) { + int n1, n2; + List *r, *top; + if (s1 == NULL) + return s2; + if (s2 == NULL) + return s1; + if ((n1 = listnel(s1)) != (n2 = listnel(s2)) && n1 != 1 && n2 != 1) + rc_error("bad concatenation"); + for (r = top = nnew(List); 1; r = r->n = nnew(List)) { + SIZE_T x = strlen(s1->w); + SIZE_T y = strlen(s2->w); + SIZE_T z = x + y + 1; + r->w = nalloc(z); + strcpy(r->w, s1->w); + strcat(r->w, s2->w); + if (s1->m == NULL && s2->m == NULL) { + r->m = NULL; + } else { + r->m = nalloc(z); + if (s1->m == NULL) + memzero(r->m, x); + else + memcpy(r->m, s1->m, x); + if (s2->m == NULL) + memzero(&r->m[x], y); + else + memcpy(&r->m[x], s2->m, y); + r->m[z] = 0; + } + if (n1 > 1) + s1 = s1->n; + if (n2 > 1) + s2 = s2->n; + if (s1 == NULL || s2 == NULL || (n1 == 1 && n2 == 1)) + break; + } + r->n = NULL; + return top; +} + +extern List *varsub(List *var, List *subs) { + List *r, *top; + int n = listnel(var); + for (top = r = NULL; subs != NULL; subs = subs->n) { + int i = a2u(subs->w); + if (i < 1) + rc_error("bad subscript"); + if (i <= n) { + List *sub = var; + while (--i) + sub = sub->n; /* loop until sub == var(i) */ + if (top == NULL) + top = r = nnew(List); + else + r = r->n = nnew(List); + r->w = sub->w; + r->m = sub->m; + } + } + if (top != NULL) + r->n = NULL; + return top; +} + +extern List *flatten(List *s) { + List *r; + SIZE_T step; + char *f; + if (s == NULL || s->n == NULL) + return s; + r = nnew(List); + f = r->w = nalloc(listlen(s) + 1); + r->m = NULL; /* flattened lists come from variables, so no meta */ + r->n = NULL; + strcpy(f, s->w); + f += strlen(s->w); + do { + *f++ = ' '; + s = s->n; + step = strlen(s->w); + memcpy(f, s->w, step); + f += step; + } while (s->n != NULL); + *f = '\0'; + return r; +} + +static List *count(List *l) { + List *s = nnew(List); + s->w = nprint("%d", listnel(l)); + s->n = NULL; + s->m = NULL; + return s; +} + +extern void assign(List *s1, List *s2, bool stack) { + List *val = s2; + if (s1 == NULL) + rc_error("null variable name"); + if (s1->n != NULL) + rc_error("multi-word variable name"); + if (*s1->w == '\0') + rc_error("zero-length variable name"); + if (a2u(s1->w) != -1) + rc_error("numeric variable name"); + if (strchr(s1->w, '=') != NULL) + rc_error("'=' in variable name"); + if (*s1->w == '*' && s1->w[1] == '\0') + val = append(varlookup("0"), s2); /* preserve $0 when * is assigned explicitly */ + if (s2 != NULL || stack) { + if (dashex) + prettyprint_var(2, s1->w, val); + varassign(s1->w, val, stack); + alias(s1->w, varlookup(s1->w), stack); + } else { + if (dashex) + prettyprint_var(2, s1->w, NULL); + varrm(s1->w, stack); + } +} + +/* + The following two functions are by the courtesy of Paul Haahr, + who could not stand the incompetence of my own backquote implementation. +*/ + +#define BUFSIZE ((SIZE_T) 1000) + +static List *bqinput(List *ifs, int fd) { + char *end, *bufend, *s; + List *r, *top, *prev; + SIZE_T remain, bufsize; + char isifs[256]; + int n, state; /* a simple FSA is used to read in data */ + + memzero(isifs, sizeof isifs); + for (isifs['\0'] = TRUE; ifs != NULL; ifs = ifs->n) + for (s = ifs->w; *s != '\0'; s++) + isifs[*(unsigned char *)s] = TRUE; + remain = bufsize = BUFSIZE; + top = r = nnew(List); + r->w = end = nalloc(bufsize + 1); + r->m = NULL; + state = 0; + prev = NULL; + + while (1) { + if (remain == 0) { /* is the string bigger than the buffer? */ + SIZE_T m = end - r->w; + char *buf; + while (bufsize < m + BUFSIZE) + bufsize *= 2; + buf = nalloc(bufsize + 1); + memcpy(buf, r->w, m); + r->w = buf; + end = &buf[m]; + remain = bufsize - m; + } + if ((n = rc_read(fd, end, remain)) <= 0) { + if (n == 0) + /* break */ break; + else if (errno == EINTR) + return NULL; /* interrupted, wait for subproc */ + else { + uerror("backquote read"); + rc_error(NULL); + } + } + remain -= n; + for (bufend = &end[n]; end < bufend; end++) + if (state == 0) { + if (!isifs[*(unsigned char *)end]) { + state = 1; + r->w = end; + r->m = NULL; + } + } else { + if (isifs[*(unsigned char *)end]) { + state = 0; + *end = '\0'; + prev = r; + r = r->n = nnew(List); + r->w = end+1; + r->m = NULL; + } + } + } + if (state == 1) { /* terminate last string */ + *end = '\0'; + r->n = NULL; + } else { + if (prev == NULL) /* no input at all? */ + top = NULL; + else + prev->n = NULL; /* else terminate list */ + } + return top; +} + +static List *backq(Node *ifs, Node *n) { + int p[2], pid, sp; + List *bq; + if (n == NULL) + return NULL; + if (pipe(p) < 0) { + uerror("pipe"); + rc_error(NULL); + } + if ((pid = rc_fork()) == 0) { + mvfd(p[1], 1); + close(p[0]); + redirq = NULL; + walk(n, FALSE); + exit(getstatus()); + } + close(p[1]); + bq = bqinput(glom(ifs), p[0]); + close(p[0]); + rc_wait4(pid, &sp, TRUE); + statprint(-1, sp); + varassign("bqstatus", word(strstatus(sp), NULL), FALSE); + sigchk(); + return bq; +} + +extern void qredir(Node *n) { + Rq *next; + if (redirq == NULL) { + next = redirq = nnew(Rq); + } else { + for (next = redirq; next->n != NULL; next = next->n) + ; + next->n = nnew(Rq); + next = next->n; + } + next->r = n; + next->n = NULL; +} + +#ifdef NOCMDARG +static List *mkcmdarg(Node *n) { + rc_error("named pipes are not supported"); + return NULL; +} +#else +#ifndef DEVFD +static List *mkcmdarg(Node *n) { + int fd; + char *name; + Edata efifo; + Estack *e = enew(Estack); + List *ret = nnew(List); + static int fifonumber = 0; + name = nprint("%s/rc%d.%d", TMPDIR, getpid(), fifonumber++); + if (mknod(name, S_IFIFO | 0666, 0) < 0) { + uerror("mknod"); + return NULL; + } + if (rc_fork() == 0) { + setsigdefaults(FALSE); + fd = rc_open(name, (n->u[0].i != rFrom) ? rFrom : rCreate); /* stupid hack */ + if (fd < 0) { + uerror("open"); + exit(1); + } + if (mvfd(fd, (n->u[0].i == rFrom)) < 0) /* same stupid hack */ + exit(1); + redirq = NULL; + walk(n->u[2].p, FALSE); + exit(getstatus()); + } + efifo.name = name; + except(eFifo, efifo, e); + ret->w = name; + ret->m = NULL; + ret->n = NULL; + return ret; +} +#else +static List *mkcmdarg(Node *n) { + char *name; + List *ret = nnew(List); + Estack *e = nnew(Estack); + Edata efd; + int p[2]; + if (pipe(p) < 0) { + uerror("pipe"); + return NULL; + } + if (rc_fork() == 0) { + setsigdefaults(FALSE); + if (mvfd(p[n->u[0].i == rFrom], n->u[0].i == rFrom) < 0) /* stupid hack */ + exit(1); + close(p[n->u[0].i != rFrom]); + redirq = NULL; + walk(n->u[2].p, FALSE); + exit(getstatus()); + } + name = nprint("/dev/fd/%d", p[n->u[0].i != rFrom]); + efd.fd = p[n->u[0].i != rFrom]; + except(eFd, efd, e); + close(p[n->u[0].i == rFrom]); + ret->w = name; + ret->m = NULL; + ret->n = NULL; + return ret; +} +#endif /* DEVFD */ +#endif /* !NOCMDARG */ + +extern List *glom(Node *n) { + List *v, *head, *tail; + Node *words; + if (n == NULL) + return NULL; + switch (n->type) { + case nArgs: + case nLappend: + words = n->u[0].p; + tail = NULL; + while (words != NULL && (words->type == nArgs || words->type == nLappend)) { + if (words->u[1].p != NULL && words->u[1].p->type != nWord && words->u[1].p->type != nQword) + break; + head = glom(words->u[1].p); + if (head != NULL) { + head->n = tail; + tail = head; + } + words = words->u[0].p; + } + v = append(glom(words), tail); /* force left to right evaluation */ + return append(v, glom(n->u[1].p)); + case nBackq: + return backq(n->u[0].p, n->u[1].p); + case nConcat: + head = glom(n->u[0].p); /* force left-to-right evaluation */ + return concat(head, glom(n->u[1].p)); + case nDup: + case nRedir: + qredir(n); + return NULL; + case nWord: + case nQword: + return word(n->u[0].s, n->u[1].s); + case nNmpipe: + return mkcmdarg(n); + default: + /* + The next four operations depend on the left-child of glom + to be a variable name. Therefore the variable is looked up + here. + */ + if ((v = glom(n->u[0].p)) == NULL) + rc_error("null variable name"); + if (v->n != NULL) + rc_error("multi-word variable name"); + if (*v->w == '\0') + rc_error("zero-length variable name"); + v = (*v->w == '*' && v->w[1] == '\0') ? varlookup(v->w)->n : varlookup(v->w); + switch (n->type) { + default: + panic("unexpected node in glom"); + exit(1); + /* NOTREACHED */ + case nCount: + return count(v); + case nFlat: + return flatten(v); + case nVar: + return v; + case nVarsub: + return varsub(v, glom(n->u[1].p)); + } + } +}