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

  1. /* heredoc.c: heredoc slurping is done here */
  2.  
  3. #include "rc.h"
  4. #include "lex.h"
  5. #include "utils.h"
  6. #include "nalloc.h"
  7. #include "heredoc.h"
  8. #include "tree.h"
  9. #include "input.h"
  10. #include "hash.h"
  11. #include "glom.h"
  12.  
  13. struct Hq {
  14.     Node *doc;
  15.     char *name;
  16.     Hq *n;
  17. } *hq;
  18.  
  19. static SIZE_T j, bufsize;
  20.  
  21. /* a stupid realloc for nalloc */
  22.  
  23. static char *renalloc(char *buf, SIZE_T n) {
  24.  
  25.     while (n >= bufsize - 2)
  26.         bufsize *= 2;
  27.  
  28.     return memcpy(nalloc(bufsize), buf, j);
  29. }
  30.  
  31. /*
  32.    read in a heredocument. A clever trick: skip over any partially matched end-of-file
  33.    marker storing only the number of characters matched. If the whole marker is matched,
  34.    return from readheredoc(). If only part of the marker is matched, copy that part into
  35.    the heredocument.
  36. */
  37.  
  38. static char *readheredoc(char *eof) {
  39.     int c;
  40.     SIZE_T i, markerlen, varsize = 0;
  41.     char *buf, *varname = NULL, *newvarname;
  42.     boolean quoted = FALSE;
  43.     List *var;
  44.  
  45.     if (*eof == '\'') {
  46.         quoted = TRUE;
  47.         eof++;
  48.     }
  49.  
  50.     markerlen = strlen(eof);
  51.  
  52.     buf = nalloc(bufsize = 512);
  53.     j = 0;
  54.  
  55.     while (1) {
  56.         print_prompt2();
  57.  
  58.         for (i = 0, c = gchar(); eof[i] == c && i < markerlen; i++) /* match the eof marker */
  59.             c = gchar();
  60.  
  61.         if (i == markerlen && c == '\n') { /* if the whole marker was matched, return */
  62.             buf[j] = 0;
  63.             return buf;
  64.         }
  65.  
  66.         if (i > 0) { /* else copy the partially matched marker into the heredocument */
  67.             if (i + j >= bufsize - 2)
  68.                 buf = renalloc(buf, i + j);
  69.             memcpy(buf + j, eof, i);
  70.             j += i;
  71.         }
  72.  
  73.         for (; c != '\n'; c = gchar()) {
  74.             if (c == EOF)
  75.                 scanerror("EOF inside heredoc");
  76.             if (j >= bufsize - 2)
  77.                 buf = renalloc(buf, j);
  78.             if (quoted || c != '$') {
  79.                 buf[j++] = c;
  80.                 continue; /* avoid an extra level of indentation */
  81.             }
  82.             if ((c = gchar()) == '$' || dnw[c]) {
  83.                 if (c != '$') /* $$ quotes $, but $<nonalnum> is transcribed literally */
  84.                     buf[j++] = '$';
  85.                 buf[j++] = c;
  86.             } else {
  87.                 if (varsize == 0)
  88.                     varname = nalloc(varsize = 16);
  89.                 for (i = 0; !dnw[c]; i++, c = gchar()) {
  90.                     if (i >= varsize - 1) {
  91.                         newvarname = nalloc(varsize *= 4);
  92.                         memcpy(newvarname, varname, i);
  93.                         varname = newvarname;
  94.                     }
  95.                     varname[i] = c;
  96.                 }
  97.                 varname[i] = '\0';
  98.                 if (c != '^')
  99.                     ugchar(c);
  100.                 var = varlookup(varname);
  101.                 if (varname[0] == '*' && varname[1] == '\0') /* skip $0 */
  102.                     var = var->n;
  103.                 if ((var = flatten(var)) != NULL) {
  104.                     i = strlen(var->w);
  105.                     while (j + i >= bufsize - 2)
  106.                         buf = renalloc(buf, i + j);
  107.                     memcpy(buf + j, var->w, i);
  108.                     j += i;
  109.                 }
  110.             }
  111.         }
  112.         buf[j++] = c;
  113.     }
  114. }
  115.  
  116. /* read in heredocs when yyparse hits a newline. called from yyparse */
  117.  
  118. void heredoc(int end) {
  119.     if (end && hq != NULL)
  120.         rc_error("EOF on command line with heredoc");
  121.  
  122.     for (; hq != NULL; hq = hq->n) {
  123.         hq->doc->u[0].i = HERESTRING;
  124.         hq->doc->u[2].p = newnode(rWORD,readheredoc(hq->name), NULL);
  125.     }
  126. }
  127.  
  128. /* queue pending heredocs into a queue. called from yyparse */
  129.  
  130. void qdoc(Node *name, Node *n) {
  131.     Hq *new;
  132.  
  133.     if (name->type != rWORD)
  134.         scanerror("eof-marker must be a single word");
  135.  
  136.     if (hq == NULL) {
  137.         new = hq = nnew(Hq);
  138.     } else {
  139.         for (new = hq; new->n != NULL; new = new->n)
  140.             ;
  141.         new->n = nnew(Hq);
  142.         new = new->n;
  143.     }
  144.  
  145.     new->name = name->u[0].s;
  146.     new->doc = n;
  147.     new->n = NULL;
  148. }
  149.