home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume30 / rc / part05 / heredoc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-05-30  |  3.4 KB  |  157 lines

  1. /* heredoc.c: heredoc slurping is done here */
  2.  
  3. #include "rc.h"
  4.  
  5. struct Hq {
  6.     Node *doc;
  7.     char *name;
  8.     Hq *n;
  9.     bool quoted;
  10. } *hq;
  11.  
  12. static bool dead = FALSE;
  13.  
  14. /*
  15.  * read in a heredocument. A clever trick: skip over any partially matched end-of-file
  16.  * marker storing only the number of characters matched. If the whole marker is matched,
  17.  * return from readheredoc(). If only part of the marker is matched, copy that part into
  18.  * the heredocument.
  19.  *
  20.  * BUG: if the eof string contains a newline, the state can get confused, and the
  21.  * heredoc may continue past where it should.  on the other hand, /bin/sh seems to
  22.  * never get out of its readheredoc() when the heredoc string contains a newline
  23.  */
  24.  
  25. static char *readheredoc(char *eof) {
  26.     int c;
  27.     char *t, *buf, *bufend;
  28.     unsigned char *s;
  29.     SIZE_T bufsize;
  30.     t = buf = nalloc(bufsize = 512);
  31.     bufend = &buf[bufsize];
  32.     dead = FALSE;
  33. #define    RESIZE(extra) { \
  34.         char *nbuf; \
  35.         bufsize = bufsize * 2 + extra; \
  36.         nbuf = nalloc(bufsize); \
  37.         memcpy(nbuf, buf, (SIZE_T) (t - buf)); \
  38.         t = nbuf + (t - buf); \
  39.         buf = nbuf; \
  40.         bufend = &buf[bufsize]; \
  41.     }
  42.     for (;;) {
  43.         print_prompt2();
  44.         for (s = (unsigned char *) eof; (c = gchar()) == *s; s++)
  45.             ;
  46.         if (*s == '\0' && (c == '\n' || c == EOF)) {
  47.             *t++ = '\0';
  48.             return buf;
  49.         }
  50.         if (s != (unsigned char *) eof) {
  51.             SIZE_T len = s - (unsigned char *) eof;
  52.             if (t + len >= bufend)
  53.                 RESIZE(len);
  54.             memcpy(t, eof, len);
  55.             t += len;
  56.         }
  57.         for (;; c = gchar()) {
  58.             if (c == EOF) {
  59.                 yyerror("heredoc incomplete");
  60.                 dead = TRUE;
  61.                 return NULL;
  62.             }
  63.             if (t + 1 >= bufend)
  64.                 RESIZE(0);
  65.             *t++ = c;
  66.             if (c == '\n')
  67.                 break;
  68.         }
  69.     }
  70. }
  71.  
  72. /* parseheredoc -- turn a heredoc with variable references into a node chain */
  73.  
  74. static Node *parseheredoc(char *s) {
  75.     int c = *s;
  76.     Node *result = NULL;
  77.     while (TRUE) {
  78.         Node *node;
  79.         switch (c) {
  80.         default: {
  81.             char *begin = s;
  82.             while ((c = *s++) != '\0' && c != '$')
  83.                 ;
  84.             *--s = '\0';
  85.             node = mk(nQword, begin, NULL);
  86.             break;
  87.         }
  88.         case '$': {
  89.             char *begin = ++s, *var;
  90.             c = *s++;
  91.             if (c == '$') {
  92.                 node = mk(nQword, "$", NULL);
  93.                 c = *s;
  94.             } else {
  95.                 SIZE_T len = 0;
  96.                 do
  97.                     len++;
  98.                 while (!dnw[c = *(unsigned char *) s++]);
  99.                 if (c == '^')
  100.                     c = *s;
  101.                 else
  102.                     s--;
  103.                 var = nalloc(len + 1);
  104.                 var[len] = '\0';
  105.                 memcpy(var, begin, len);
  106.                 node = mk(nFlat, mk(nWord, var, NULL));
  107.             }
  108.             break;
  109.         }
  110.         case '\0':
  111.             return result;
  112.         }
  113.         result = (result == NULL) ? node : mk(nConcat, result, node);
  114.     }
  115. }
  116.  
  117. /* read in heredocs when yyparse hits a newline. called from yyparse */
  118.  
  119. extern int heredoc(int end) {
  120.     Hq *here;
  121.     if ((here = hq) != NULL) {
  122.         hq = NULL;
  123.         if (end) {
  124.             yyerror("heredoc incomplete");
  125.             return FALSE;
  126.         }
  127.         do {
  128.             Node *n = here->doc;
  129.             char *s = readheredoc(here->name);
  130.             if (dead)
  131.                 return FALSE;
  132.             n->u[2].p = here->quoted ? mk(nQword, s, NULL) : parseheredoc(s);
  133.             n->u[0].i = rHerestring;
  134.         } while ((here = here->n) != NULL);
  135.     }
  136.     return TRUE;
  137. }
  138.  
  139. /* queue pending heredocs into a queue. called from yyparse */
  140.  
  141. extern int qdoc(Node *name, Node *n) {
  142.     Hq *new, **prev;
  143.     if (name->type != nWord && name->type != nQword) {
  144.         yyerror("eof-marker not a single literal word");
  145.         flushu();
  146.         return FALSE;
  147.     }
  148.     for (prev = &hq; (new = *prev) != NULL; prev = &new->n)
  149.         ;
  150.     *prev = new = nnew(Hq);
  151.     new->name = name->u[0].s;
  152.     new->quoted = (name->type == nQword);
  153.     new->doc = n;
  154.     new->n = NULL;
  155.     return TRUE;
  156. }
  157.