home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume30 / rc / part04 / glom.c < prev    next >
C/C++ Source or Header  |  1992-05-30  |  9KB  |  421 lines

  1. /* glom.c: builds an argument list out of words, variables, etc. */
  2.  
  3. #include <sys/types.h>
  4. #include <sys/stat.h>
  5. #include <signal.h>
  6. #include "rc.h"
  7. #if !defined(S_IFIFO) && !defined(DEVFD)
  8. #define NOCMDARG
  9. #endif
  10.  
  11. static List *backq(Node *, Node *);
  12. static List *bqinput(List *, int);
  13. static List *count(List *);
  14. static List *mkcmdarg(Node *);
  15.  
  16. Rq *redirq = NULL;
  17.  
  18. extern List *word(char *w, char *m) {
  19.     List *s = NULL;
  20.     if (w != NULL) {
  21.         s = nnew(List);
  22.         s->w = w;
  23.         s->m = m;
  24.         s->n = NULL;
  25.     }
  26.     return s;
  27. }
  28.  
  29. /*
  30.    Append list s2 to list s1 by copying s1 and making the new copy
  31.    point at s2.
  32. */
  33.  
  34. extern List *append(List *s1, List *s2) {
  35.     List *r, *top;
  36.     if (s1 == NULL)
  37.         return s2;
  38.     if (s2 == NULL)
  39.         return s1;
  40.     for (r = top = nnew(List); 1; r = r->n = nnew(List)) {
  41.         r->w = s1->w;
  42.         r->m = s1->m;
  43.         if ((s1 = s1->n) == NULL)
  44.             break;
  45.     }
  46.     r->n = s2;
  47.     return top;
  48. }
  49.  
  50. extern List *concat(List *s1, List *s2) {
  51.     int n1, n2;
  52.     List *r, *top;
  53.     if (s1 == NULL)
  54.         return s2;
  55.     if (s2 == NULL)
  56.         return s1;
  57.     if ((n1 = listnel(s1)) != (n2 = listnel(s2)) && n1 != 1 && n2 != 1)
  58.         rc_error("bad concatenation");
  59.     for (r = top = nnew(List); 1; r = r->n = nnew(List)) {
  60.         SIZE_T x = strlen(s1->w);
  61.         SIZE_T y = strlen(s2->w);
  62.         SIZE_T z = x + y + 1;
  63.         r->w = nalloc(z);
  64.         strcpy(r->w, s1->w);
  65.         strcat(r->w, s2->w);
  66.         if (s1->m == NULL && s2->m == NULL) {
  67.             r->m = NULL;
  68.         } else {
  69.             r->m = nalloc(z);
  70.             if (s1->m == NULL)
  71.                 clear(r->m, x);
  72.             else
  73.                 memcpy(r->m, s1->m, x);
  74.             if (s2->m == NULL)
  75.                 clear(&r->m[x], y);
  76.             else
  77.                 memcpy(&r->m[x], s2->m, y);
  78.             r->m[z] = 0;
  79.         }
  80.         if (n1 > 1)
  81.             s1 = s1->n;
  82.         if (n2 > 1)
  83.             s2 = s2->n;
  84.         if (s1 == NULL || s2 == NULL || (n1 == 1 && n2 == 1))
  85.             break;
  86.     }
  87.     r->n = NULL;
  88.     return top;
  89. }
  90.  
  91. extern List *varsub(List *var, List *subs) {
  92.     List *r, *top;
  93.     int n = listnel(var);
  94.     for (top = r = NULL; subs != NULL; subs = subs->n) {
  95.         int i = a2u(subs->w);
  96.         if (i < 1)
  97.             rc_error("bad subscript");
  98.         if (i <= n) {
  99.             List *sub = var;
  100.             while (--i)
  101.                 sub = sub->n; /* loop until sub == var(i) */
  102.             if (top == NULL)
  103.                 top = r = nnew(List);
  104.             else
  105.                 r = r->n = nnew(List);
  106.             r->w = sub->w;
  107.             r->m = sub->m;
  108.         }
  109.     }
  110.     if (top != NULL)
  111.         r->n = NULL;
  112.     return top;
  113. }
  114.  
  115. extern List *flatten(List *s) {
  116.     List *r;
  117.     SIZE_T step;
  118.     char *f;
  119.     if (s == NULL || s->n == NULL)
  120.         return s;
  121.     r = nnew(List);
  122.     f = r->w = nalloc(listlen(s) + 1);
  123.     r->m = NULL; /* flattened lists come from variables, so no meta */
  124.     r->n = NULL;
  125.     strcpy(f, s->w);
  126.     f += strlen(s->w);
  127.     do {
  128.         *f++ = ' ';
  129.         s = s->n;
  130.         step = strlen(s->w);
  131.         memcpy(f, s->w, step);
  132.         f += step;
  133.     } while (s->n != NULL);
  134.     *f = '\0';
  135.     return r;
  136. }
  137.  
  138. static List *count(List *l) {
  139.     List *s = nnew(List);
  140.     s->w = nprint("%d", listnel(l));
  141.     s->n = NULL;
  142.     s->m = NULL;
  143.     return s;
  144. }
  145.  
  146. extern void assign(List *s1, List *s2, bool stack) {
  147.     List *val = s2;
  148.     if (s1 == NULL)
  149.         rc_error("null variable name");
  150.     if (s1->n != NULL)
  151.         rc_error("multi-word variable name");
  152.     if (*s1->w == '\0')
  153.         rc_error("zero-length variable name");
  154.     if (a2u(s1->w) != -1)
  155.         rc_error("numeric variable name");
  156.     if (strchr(s1->w, '=') != NULL)
  157.         rc_error("'=' in variable name");
  158.     if (*s1->w == '*' && s1->w[1] == '\0')
  159.         val = append(varlookup("0"), s2); /* preserve $0 when * is assigned explicitly */
  160.     if (s2 != NULL || stack) {
  161.         if (dashex)
  162.             prettyprint_var(2, s1->w, val);
  163.         varassign(s1->w, val, stack);
  164.         alias(s1->w, varlookup(s1->w), stack);
  165.     } else {
  166.         if (dashex)
  167.             prettyprint_var(2, s1->w, NULL);
  168.         varrm(s1->w, stack);
  169.     }
  170. }
  171.  
  172. /*
  173.    The following two functions are by the courtesy of Paul Haahr,
  174.    who could not stand the incompetence of my own backquote implementation.
  175. */
  176.  
  177. #define BUFSIZE    ((SIZE_T) 1000)
  178.  
  179. static List *bqinput(List *ifs, int fd) {
  180.     char *end, *bufend, *s;
  181.     List *r, *top, *prev;
  182.     SIZE_T remain, bufsize;
  183.     char isifs[256];
  184.     int n, state; /* a simple FSA is used to read in data */
  185.  
  186.     clear(isifs, sizeof isifs);
  187.     for (isifs['\0'] = TRUE; ifs != NULL; ifs = ifs->n)
  188.         for (s = ifs->w; *s != '\0'; s++)
  189.             isifs[*(unsigned char *)s] = TRUE;
  190.     remain = bufsize = BUFSIZE;
  191.     top = r = nnew(List);
  192.     r->w = end = nalloc(bufsize + 1);
  193.     r->m = NULL;
  194.     state = 0;
  195.     prev = NULL;
  196.  
  197.     while (1) {
  198.         if (remain == 0) { /* is the string bigger than the buffer? */
  199.             SIZE_T m = end - r->w;
  200.             char *buf;
  201.             while (bufsize < m + BUFSIZE)
  202.                 bufsize *= 2;
  203.             buf = nalloc(bufsize + 1);
  204.             memcpy(buf, r->w, m);
  205.             r->w = buf;
  206.             end = &buf[m];
  207.             remain = bufsize - m;
  208.         }
  209.         if ((n = rc_read(fd, end, remain)) <= 0) {
  210.             if (n == 0)
  211.     /* break */        break;
  212.             uerror("backquote read");
  213.             rc_error(NULL);
  214.         }
  215.         remain -= n;
  216.         for (bufend = &end[n]; end < bufend; end++)
  217.             if (state == 0) {
  218.                 if (!isifs[*(unsigned char *)end]) {
  219.                     state = 1;
  220.                     r->w = end;
  221.                 }
  222.             } else {
  223.                 if (isifs[*(unsigned char *)end]) {
  224.                     state = 0;
  225.                     *end = '\0';
  226.                     prev = r;
  227.                     r = r->n = nnew(List);
  228.                     r->w = end+1;
  229.                     r->m = NULL;
  230.                 }
  231.             }
  232.     }
  233.     if (state == 1) { /* terminate last string */
  234.         *end = '\0';
  235.         r->n = NULL;
  236.     } else {
  237.         if (prev == NULL) /* no input at all? */
  238.             top = NULL;
  239.         else
  240.             prev->n = NULL; /* else terminate list */
  241.     }
  242.     return top;
  243. }
  244.  
  245. static List *backq(Node *ifs, Node *n) {
  246.     int p[2], pid, sp;
  247.     List *bq;
  248.     if (n == NULL)
  249.         return NULL;
  250.     if (pipe(p) < 0) {
  251.         uerror("pipe");
  252.         rc_error(NULL);
  253.     }
  254.     if ((pid = rc_fork()) == 0) {
  255.         setsigdefaults(FALSE);
  256.         mvfd(p[1], 1);
  257.         close(p[0]);
  258.         redirq = NULL;
  259.         walk(n, FALSE);
  260.         exit(getstatus());
  261.     }
  262.     close(p[1]);
  263.     bq = bqinput(glom(ifs), p[0]);
  264.     close(p[0]);
  265.     rc_wait4(pid, &sp, TRUE);
  266.     statprint(-1, sp);
  267.     SIGCHK;
  268.     return bq;
  269. }
  270.  
  271. extern void qredir(Node *n) {
  272.     Rq *next;
  273.     if (redirq == NULL) {
  274.         next = redirq = nnew(Rq);
  275.     } else {
  276.         for (next = redirq; next->n != NULL; next = next->n)
  277.             ;
  278.         next->n = nnew(Rq);
  279.         next = next->n;
  280.     }
  281.     next->r = n;
  282.     next->n = NULL;
  283. }
  284.  
  285. #ifdef NOCMDARG
  286. static List *mkcmdarg(Node *n) {
  287.     rc_error("named pipes are not supported");
  288.     return NULL;
  289. }
  290. #else
  291. #ifndef DEVFD
  292. static List *mkcmdarg(Node *n) {
  293.     int fd;
  294.     char *name;
  295.     Edata efifo;
  296.     Estack *e = enew(Estack);
  297.     List *ret = nnew(List);
  298.     static int fifonumber = 0;
  299.     name = nprint("%s/rc%d.%d", TMPDIR, getpid(), fifonumber++);
  300.     if (mknod(name, S_IFIFO | 0666, 0) < 0) {
  301.         uerror("mknod");
  302.         return NULL;
  303.     }
  304.     if (rc_fork() == 0) {
  305.         setsigdefaults(FALSE);
  306.         fd = rc_open(name, (n->u[0].i != rFrom) ? rFrom : rCreate); /* stupid hack */
  307.         if (fd < 0) {
  308.             uerror("open");
  309.             exit(1);
  310.         }
  311.         if (mvfd(fd, (n->u[0].i == rFrom)) < 0) /* same stupid hack */
  312.             exit(1);
  313.         redirq = NULL;
  314.         walk(n->u[2].p, FALSE);
  315.         exit(getstatus());
  316.     }
  317.     efifo.name = name;
  318.     except(eFifo, efifo, e);
  319.     ret->w = name;
  320.     ret->m = NULL;
  321.     ret->n = NULL;
  322.     return ret;
  323. }
  324. #else
  325. static List *mkcmdarg(Node *n) {
  326.     char *name;
  327.     List *ret = nnew(List);
  328.     Estack *e = nnew(Estack);
  329.     Edata efd;
  330.     int p[2];
  331.     if (pipe(p) < 0) {
  332.         uerror("pipe");
  333.         return NULL;
  334.     }
  335.     if (rc_fork() == 0) {
  336.         setsigdefaults(FALSE);
  337.         if (mvfd(p[n->u[0].i == rFrom], n->u[0].i == rFrom) < 0) /* stupid hack */
  338.             exit(1);
  339.         close(p[n->u[0].i != rFrom]);
  340.         redirq = NULL;
  341.         walk(n->u[2].p, FALSE);
  342.         exit(getstatus());
  343.     }
  344.     name = nprint("/dev/fd/%d", p[n->u[0].i != rFrom]);
  345.     efd.fd = p[n->u[0].i != rFrom];
  346.     except(eFd, efd, e);
  347.     close(p[n->u[0].i == rFrom]);
  348.     ret->w = name;
  349.     ret->m = NULL;
  350.     ret->n = NULL;
  351.     return ret;
  352. }
  353. #endif /* DEVFD */
  354. #endif /* !NOCMDARG */
  355.  
  356. extern List *glom(Node *n) {
  357.     List *v, *head, *tail;
  358.     Node *words;
  359.     if (n == NULL)
  360.         return NULL;
  361.     switch (n->type) {
  362.     case nArgs:
  363.     case nLappend:
  364.         words = n->u[0].p;
  365.         tail = NULL;
  366.         while (words != NULL && (words->type == nArgs || words->type == nLappend)) {
  367.             if (words->u[1].p != NULL && words->u[1].p->type != nWord && words->u[1].p->type != nQword)
  368.                 break;
  369.             head = glom(words->u[1].p);
  370.             if (head != NULL) {
  371.                 head->n = tail;
  372.                 tail = head;
  373.             }
  374.             words = words->u[0].p;
  375.         }
  376.         v = append(glom(words), tail); /* force left to right evaluation */
  377.         return append(v, glom(n->u[1].p));
  378.     case nBackq:
  379.         return backq(n->u[0].p, n->u[1].p);
  380.     case nConcat:
  381.         head = glom(n->u[0].p); /* force left-to-right evaluation */
  382.         return concat(head, glom(n->u[1].p));
  383.     case nDup:
  384.     case nRedir:
  385.         qredir(n);
  386.         return NULL;
  387.     case nWord:
  388.     case nQword:
  389.         return word(n->u[0].s, n->u[1].s);
  390.     case nNmpipe:
  391.         return mkcmdarg(n);
  392.     default:
  393.         /*
  394.            The next four operations depend on the left-child of glom
  395.            to be a variable name. Therefore the variable is looked up
  396.            here.
  397.         */
  398.         if ((v = glom(n->u[0].p)) == NULL)
  399.             rc_error("null variable name");
  400.         if (v->n != NULL)
  401.             rc_error("multi-word variable name");
  402.         if (*v->w == '\0')
  403.             rc_error("zero-length variable name");
  404.         v = (*v->w == '*' && v->w[1] == '\0') ? varlookup(v->w)->n : varlookup(v->w);
  405.         switch (n->type) {
  406.         default:
  407.             panic("unexpected node in glom");
  408.             exit(1);
  409.             /* NOTREACHED */
  410.         case nCount:
  411.             return count(v);
  412.         case nFlat:
  413.             return flatten(v);
  414.         case nVar:
  415.             return v;
  416.         case nVarsub:
  417.             return varsub(v, glom(n->u[1].p));
  418.         }
  419.     }
  420. }
  421.