home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume20 / rc / part02 / glom.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-05-22  |  8.2 KB  |  469 lines

  1. /* glom.c: builds an argument list out of words, variables, etc. */
  2.  
  3. #ifndef NONMPIPES
  4. #include <sys/types.h>
  5. #include <sys/stat.h>
  6. #endif
  7. #include "rc.h"
  8. #include "utils.h"
  9. #include "nalloc.h"
  10. #include "glom.h"
  11. #include "hash.h"
  12. #include "walk.h"
  13. #include "status.h"
  14. #include "exec.h"
  15. #include "lex.h"
  16. #include "open.h"
  17. #include "list.h"
  18.  
  19. static List *backq(Node *, Node *);
  20. static List *bqinput(List *, int);
  21. static List *count(List *);
  22. static List *mknmpipe(Node *);
  23.  
  24. Rq *redirq = NULL;
  25. List *fifoq = NULL;
  26.  
  27. List *word(char *w, char *m) {
  28.     List *s;
  29.  
  30.     if (w == NULL)
  31.         return NULL;
  32.     if (*w == '\'') {
  33.         m = NULL; /* m is null, or had better be! */
  34.         w++;
  35.     }
  36.  
  37.     s = nnew(List);
  38.     s->w = w;
  39.     s->m = m;
  40.     s->n = NULL;
  41.     return s;
  42. }
  43.  
  44. /*
  45.    Append list s2 to list s1 by copying s1 and making the new copy
  46.    point at s2.
  47. */
  48.  
  49. List *append(List *s1, List *s2) {
  50.     List *r, *top;
  51.  
  52.     if (s1 == NULL)
  53.         return s2;
  54.     if (s2 == NULL)
  55.         return s1;
  56.  
  57.     r = top = nnew(List);
  58.     while (1) {
  59.         r->w = s1->w;
  60.         r->m = s1->m;
  61.         if ((s1 = s1->n) == NULL)
  62.             break;
  63.         r = r->n = nnew(List);
  64.     }
  65.  
  66.     r->n = s2;
  67.  
  68.     return top;
  69. }
  70.  
  71. List *concat(List *s1, List *s2) {
  72.     int n1, n2;
  73.     SIZE_T y,z;
  74.     List *n, *s;
  75.  
  76.     if (s1 == NULL)
  77.         return s2;
  78.     if (s2 == NULL)
  79.         return s1;
  80.  
  81.     n1 = listnel(s1);
  82.     n2 = listnel(s2);
  83.  
  84.     if (n1 != n2 && n1 != 1 && n2 != 1)
  85.         rc_error("bad concatenation");
  86.  
  87.     n = s = nnew(List);
  88.  
  89.     while (1) {
  90.         z = strlen(s1->w) + strlen(s2->w) + 1;
  91.         n->w = nalloc(z);
  92.         strcpy(n->w,s1->w);
  93.         strcat(n->w,s2->w);
  94.         if (s1->m == NULL && s2->m == NULL) {
  95.             n->m = NULL;
  96.         } else {
  97.             n->m = nalloc(z);
  98.             y = strlen(s1->w);
  99.             if (s1->m == NULL)
  100.                 clear(n->m, y);
  101.             else
  102.                 memcpy(n->m, s1->m, y);
  103.             if (s2->m == NULL)
  104.                 clear(n->m + y, strlen(s2->w));
  105.             else
  106.                 memcpy(n->m + y, s2->m, strlen(s2->w));
  107.             n->m[z] = 0;
  108.         }
  109.         if (n1 > 1)
  110.             s1 = s1->n;
  111.         if (n2 > 1)
  112.             s2 = s2->n;
  113.         if (s1 == NULL || s2 == NULL || (n1 == 1  && n2 == 1)) {
  114.             n->n = NULL;
  115.             return s;
  116.         }
  117.         n->n = nnew(List);
  118.         n = n->n;
  119.     }
  120. }
  121.  
  122. List *varsub(List *v, List *subs) {
  123.     int i,j;
  124.     int n;
  125.     List *r,*s;
  126.     List *top,*cat;
  127.  
  128.     n = listnel(v);
  129.  
  130.     top = cat = NULL;
  131.  
  132.     for (s = subs; s != NULL; s = s->n) {
  133.         i = a2u(s->w);
  134.         if (i < 1)
  135.             rc_error("bad subscript");
  136.         if (i <= n) {
  137.             for (j = 1, r = v; j != i; j++, r = r->n)
  138.                 ; /* loop until r == v(i) */
  139.             if (top == NULL) {
  140.                 top = cat = nnew(List);
  141.             } else {
  142.                 cat->n = nnew(List);
  143.                 cat = cat->n;
  144.             }
  145.             cat->w = r->w;
  146.             cat->m = r->m;
  147.         }
  148.     }
  149.  
  150.     if (top == NULL)
  151.         return NULL;
  152.  
  153.     cat->n = NULL;
  154.     return top;
  155. }
  156.  
  157. List *flatten(List *s) {
  158.     List *r;
  159.  
  160.     if (s == NULL || s->n == NULL)
  161.         return s;
  162.  
  163.     r = nnew(List);
  164.     r->w = nalloc(listlen(s) + 1);
  165.     r->m = NULL; /* flattened lists come from variables, so no meta */
  166.     r->n = NULL;
  167.  
  168.     strcpy(r->w, s->w);
  169.  
  170.     do {
  171.         s = s->n;
  172.         strcat(r->w, " ");
  173.         strcat(r->w, s->w);
  174.     } while (s->n != NULL);
  175.  
  176.     return r;
  177. }
  178.  
  179. static List *count(List *l) {
  180.     List *s = nnew(List);
  181.     char buf[16];
  182.  
  183.     s->w = ncpy(sprint(buf, "%d", listnel(l)));
  184.     s->n = NULL;
  185.     s->m = NULL;
  186.     return s;
  187. }
  188.  
  189. void assign(List *s1, List *s2, boolean stack) {
  190.     List *val = s2;
  191.  
  192.     if (s1 == NULL)
  193.         rc_error("null variable name");
  194.     if (s1->n != NULL)
  195.         rc_error("multi-word variable name");
  196.     if (*s1->w == '\0')
  197.         rc_error("zero-length variable name");
  198.     if (a2u(s1->w) != -1)
  199.         rc_error("numeric variable name");
  200.     if (s1->w[0] == '*' && s1->w[1] == '\0')
  201.         val = append(varlookup("0"), s2); /* preserve $0 when * is assigned explicitly */
  202.  
  203.     if (s2 != NULL || stack) {
  204.         varassign(s1->w, val, stack);
  205.         alias(s1->w, val, stack);
  206.     } else
  207.         varrm(s1->w, stack);
  208. }
  209.  
  210. /*
  211.    The following two functions are by the courtesy of Paul Haahr,
  212.    who could not stand the incompetence of my own backquote implementation.
  213. */
  214.  
  215. #define BUFSIZE    ((SIZE_T) 1000)
  216.  
  217. static List *bqinput(List *list, int fd) {
  218.     char *s, *bufend;
  219.     List *lp, *prev;
  220.     SIZE_T nremain, bufsize;
  221.     static char isifs[256];
  222.  
  223.     clear(isifs, sizeof isifs);
  224.     isifs['\0'] = 1;
  225.     for (lp = list; list != NULL; list = list->n)
  226.         for (s = list->w; *s != '\0'; s++)
  227.             isifs[*(unsigned char *)s] = 1;
  228.  
  229.     nremain = bufsize = BUFSIZE;
  230.     lp = list = nnew(List);
  231.     s  = list->w = nalloc(bufsize + 1);
  232.     list->m = NULL;
  233.     prev = NULL;
  234.     while (1) {
  235.         int n;
  236.  
  237.         if (nremain == 0) {
  238.             SIZE_T m = s - lp->w;
  239.             char *buf;
  240.  
  241.             while (bufsize < m + BUFSIZE)
  242.                 bufsize *= 2;
  243.             buf = nalloc(bufsize + 1);
  244.             memcpy(buf, lp->w, m);
  245.             lp->w = buf;
  246.             lp->m = NULL;
  247.             s = &buf[m];
  248.             nremain = bufsize - m;
  249.         }
  250.         n = read(fd, s, nremain);
  251.         if (n <= 0) {
  252.             if (n == -1) {
  253.                 uerror("backquote read");
  254.                 rc_error(NULL);
  255.             }
  256.     /* break */    break;
  257.         }
  258.         nremain -= n;
  259.         for (bufend = &s[n]; s < bufend; s++)
  260.             if (isifs[*(unsigned char *)s]) {
  261.                 *s = '\0';
  262.                 prev = lp;
  263.                 lp = nnew(List);
  264.                 lp->w = s + 1;
  265.                 lp->m = NULL;
  266.                 prev->n = lp;
  267.             }
  268.     }
  269.  
  270.     if (s == lp->w) {
  271.         if (prev == NULL)
  272.             list = NULL;
  273.         else
  274.             prev->n = NULL;
  275.     } else {
  276.         lp->n = NULL;
  277.         *s = '\0';
  278.     }
  279.  
  280.     return list;
  281. }
  282.  
  283. static List *backq(Node *ifsnode, Node *n) {
  284.     int p[2], pid, sp;
  285.     List *result, *ifs;
  286.  
  287.     if (n == NULL)
  288.         return NULL;
  289.  
  290.     if (pipe(p) < 0) {
  291.         uerror("pipe");
  292.         rc_error(NULL);
  293.     }
  294.  
  295.     switch (pid = fork()) {
  296.     case -1:
  297.         uerror("fork");
  298.         rc_error(NULL);
  299.         /* NOTREACHED */
  300.     case 0:
  301.         setsigdefaults();
  302.         dup2(p[1],1);
  303.         close(p[0]);
  304.         close(p[1]);
  305.         redirq = NULL;
  306.         fifoq = NULL;
  307.         walk(n, FALSE);
  308.         exit(getstatus());
  309.         /* NOTREACHED */
  310.     default:
  311.         ifs = glom(ifsnode);
  312.         close(p[1]);
  313.         result = bqinput(ifs, p[0]);
  314.         close(p[0]);
  315.         while (pid != wait(&sp))
  316.             ;
  317.         statprint(sp);
  318.         return result;
  319.     }
  320. }
  321.  
  322. void qredir(Node *n) {
  323.     Rq *next;
  324.  
  325.     if (redirq == NULL) {
  326.         next = redirq = nnew(Rq);
  327.     } else {
  328.         for (next = redirq; next->n != NULL; next = next->n)
  329.             ;
  330.         next->n = nnew(Rq);
  331.         next = next->n;
  332.     }
  333.  
  334.     next->r = n;
  335.     next->n = NULL;
  336. }
  337.  
  338. static List *mknmpipe(Node *n) {
  339. #ifdef NONMPIPES
  340.     rc_error("named pipes are not supported");
  341.     return NULL;
  342. #else
  343.     int fd;
  344.     char *fifoname, buf[32];
  345.     List *fifolist = nnew(List);
  346.     List *f = nnew(List);
  347.     static int fifonumber = 0;
  348.  
  349.     fifoname = ncpy(sprint(buf,"/tmp/rc%d.%d", getpid(), fifonumber++));
  350.  
  351.     if (mknod(fifoname, S_IFIFO | 0644, 0) < 0) {
  352.         uerror("mknod");
  353.         return NULL;
  354.     }
  355.  
  356.     switch (fork()) {
  357.     case -1:
  358.         uerror("fork");
  359.         rc_error(NULL);
  360.         /* NOTREACHED */
  361.     case 0:
  362.         setsigdefaults();
  363.         fd = rc_open(fifoname, CREATE);
  364.         if (fd < 0) {
  365.             uerror("open");
  366.             exit(1);
  367.         }
  368.         if (dup2(fd, (n->u[0].i == FROM)) < 0) { /* stupid hack */
  369.             uerror("dup2");
  370.             exit(1);
  371.         }
  372.         close(fd);
  373.         redirq = NULL;
  374.         fifoq = NULL;
  375.         walk(n->u[2].p, FALSE);
  376.         exit(getstatus());
  377.         /* NOTREACHED */
  378.     default:
  379.         f->w = fifoname;
  380.         f->n = fifoq;
  381.         fifoq = f;
  382.  
  383.         fifolist->w = fifoname;
  384.         fifolist->m = NULL;
  385.         fifolist->n = NULL;
  386.  
  387.         return fifolist;
  388.     }
  389. #endif
  390. }
  391.  
  392. List *glom(Node *n) {
  393.     Node *words;
  394.     List *v, *first, *last;
  395.     boolean dollarstar;
  396.  
  397.     if (n == NULL)
  398.         return NULL;
  399.  
  400.     switch (n->type) {
  401.     case ARGS:
  402.     case LAPPEND:
  403.         words = n->u[0].p;
  404.         last = NULL;
  405.         while (words != NULL && (words->type == ARGS || words->type == LAPPEND)) {
  406.             if (words->u[1].p != NULL && words->u[1].p->type != rWORD)
  407.                 break;
  408.             first = glom(words->u[1].p);
  409.             if (first != NULL) {
  410.                 first->n = last;
  411.                 last = first;
  412.             }
  413.             words = words->u[0].p;
  414.         }
  415.         return append(append(glom(words), last), glom(n->u[1].p));
  416.     case BACKQ:
  417.         return backq(n->u[0].p,n->u[1].p);
  418.     case CONCAT:
  419.         first = glom(n->u[0].p); /* force left-to-right evaluation */
  420.         return concat(first, glom(n->u[1].p));
  421.     case rDUP:
  422.     case rREDIR:
  423.         qredir(n);
  424.         return NULL;
  425.     case rWORD:
  426.         return word(n->u[0].s,n->u[1].s);
  427.     case NMPIPE:
  428.         return mknmpipe(n);
  429.     default:
  430.         break;
  431.     }
  432.  
  433.     /*
  434.            the next three operations depend on the left-child of glom
  435.        to be a variable name. Therefore they are all treated here.
  436.        (previously each function looked up and checked the validity
  437.        of a variable name)
  438.     */
  439.  
  440.     v = glom(n->u[0].p);
  441.     if (v == NULL)
  442.         rc_error("null variable name");
  443.     if (v->n != NULL)
  444.         rc_error("multi-word variable name");
  445.     if (*v->w == '\0')
  446.         rc_error("zero-length variable name");
  447.  
  448.     dollarstar = (v->w[0] == '*' && v->w[1] == '\0');
  449.     v = varlookup(v->w);
  450.     if (dollarstar)
  451.         v = v->n;
  452.  
  453.     switch (n->type) {
  454.     default:
  455.         fprint(2,"glom: this can't happen\n");
  456.         exit(1);
  457.         /* NOTREACHED */
  458.     case rCOUNT:
  459.         return count(v);
  460.     case rFLAT:
  461.         return flatten(v);
  462.     case VAR:
  463.         return v;
  464.     case VARSUB:
  465.         return varsub(v, glom(n->u[1].p));
  466.     }
  467.  
  468. }
  469.