home *** CD-ROM | disk | FTP | other *** search
- /* heredoc.c: heredoc slurping is done here */
-
- #include "rc.h"
- #include "lex.h"
- #include "utils.h"
- #include "nalloc.h"
- #include "heredoc.h"
- #include "tree.h"
- #include "input.h"
- #include "hash.h"
- #include "glom.h"
-
- struct Hq {
- Node *doc;
- char *name;
- Hq *n;
- } *hq;
-
- static SIZE_T j, bufsize;
-
- /* a stupid realloc for nalloc */
-
- static char *renalloc(char *buf, SIZE_T n) {
-
- while (n >= bufsize - 2)
- bufsize *= 2;
-
- return memcpy(nalloc(bufsize), buf, j);
- }
-
- /*
- read in a heredocument. A clever trick: skip over any partially matched end-of-file
- marker storing only the number of characters matched. If the whole marker is matched,
- return from readheredoc(). If only part of the marker is matched, copy that part into
- the heredocument.
- */
-
- static char *readheredoc(char *eof) {
- int c;
- SIZE_T i, markerlen, varsize = 0;
- char *buf, *varname = NULL, *newvarname;
- boolean quoted = FALSE;
- List *var;
-
- if (*eof == '\'') {
- quoted = TRUE;
- eof++;
- }
-
- markerlen = strlen(eof);
-
- buf = nalloc(bufsize = 512);
- j = 0;
-
- while (1) {
- print_prompt2();
-
- for (i = 0, c = gchar(); eof[i] == c && i < markerlen; i++) /* match the eof marker */
- c = gchar();
-
- if (i == markerlen && c == '\n') { /* if the whole marker was matched, return */
- buf[j] = 0;
- return buf;
- }
-
- if (i > 0) { /* else copy the partially matched marker into the heredocument */
- if (i + j >= bufsize - 2)
- buf = renalloc(buf, i + j);
- memcpy(buf + j, eof, i);
- j += i;
- }
-
- for (; c != '\n'; c = gchar()) {
- if (c == EOF)
- scanerror("EOF inside heredoc");
- if (j >= bufsize - 2)
- buf = renalloc(buf, j);
- if (quoted || c != '$') {
- buf[j++] = c;
- continue; /* avoid an extra level of indentation */
- }
- if ((c = gchar()) == '$' || dnw[c]) {
- if (c != '$') /* $$ quotes $, but $<nonalnum> is transcribed literally */
- buf[j++] = '$';
- buf[j++] = c;
- } else {
- if (varsize == 0)
- varname = nalloc(varsize = 16);
- for (i = 0; !dnw[c]; i++, c = gchar()) {
- if (i >= varsize - 1) {
- newvarname = nalloc(varsize *= 4);
- memcpy(newvarname, varname, i);
- varname = newvarname;
- }
- varname[i] = c;
- }
- varname[i] = '\0';
- if (c != '^')
- ugchar(c);
- var = varlookup(varname);
- if (varname[0] == '*' && varname[1] == '\0') /* skip $0 */
- var = var->n;
- if ((var = flatten(var)) != NULL) {
- i = strlen(var->w);
- while (j + i >= bufsize - 2)
- buf = renalloc(buf, i + j);
- memcpy(buf + j, var->w, i);
- j += i;
- }
- }
- }
- buf[j++] = c;
- }
- }
-
- /* read in heredocs when yyparse hits a newline. called from yyparse */
-
- void heredoc(int end) {
- if (end && hq != NULL)
- rc_error("EOF on command line with heredoc");
-
- for (; hq != NULL; hq = hq->n) {
- hq->doc->u[0].i = HERESTRING;
- hq->doc->u[2].p = newnode(rWORD,readheredoc(hq->name), NULL);
- }
- }
-
- /* queue pending heredocs into a queue. called from yyparse */
-
- void qdoc(Node *name, Node *n) {
- Hq *new;
-
- if (name->type != rWORD)
- scanerror("eof-marker must be a single word");
-
- if (hq == NULL) {
- new = hq = nnew(Hq);
- } else {
- for (new = hq; new->n != NULL; new = new->n)
- ;
- new->n = nnew(Hq);
- new = new->n;
- }
-
- new->name = name->u[0].s;
- new->doc = n;
- new->n = NULL;
- }
-