BSD 4_4_Lite1 development
authorCSRG <csrg@ucbvax.Berkeley.EDU>
Fri, 30 Apr 1993 05:57:54 +0000 (21:57 -0800)
committerCSRG <csrg@ucbvax.Berkeley.EDU>
Fri, 30 Apr 1993 05:57:54 +0000 (21:57 -0800)
Work on file usr/src/contrib/rc-1.4/glom.c

Synthesized-from: CSRG/cd2/4.4BSD-Lite1

usr/src/contrib/rc-1.4/glom.c [new file with mode: 0644]

diff --git a/usr/src/contrib/rc-1.4/glom.c b/usr/src/contrib/rc-1.4/glom.c
new file mode 100644 (file)
index 0000000..bc2fb1b
--- /dev/null
@@ -0,0 +1,375 @@
+/* glom.c: builds an argument list out of words, variables, etc. */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include "rc.h"
+
+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)
+                               clear(r->m, x);
+                       else
+                               memcpy(r->m, s1->m, x);
+                       if (s2->m == NULL)
+                               clear(&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 */
+
+       clear(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;
+                       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;
+                               }
+                       } 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) {
+               setsigdefaults(FALSE);
+               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);
+       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;
+}
+
+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;
+}
+
+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));
+               }
+       }
+}