1 /* heredoc.c -- in-line files (here documents) ($Revision: 1.1.1.1 $) */
2 
3 #include "es.h"
4 #include "gc.h"
5 #include "input.h"
6 #include "syntax.h"
7 
8 typedef struct Here Here;
9 struct Here {
10 	Here *next;
11 	Tree *marker;
12 };
13 
14 static Here *hereq;
15 
16 /* getherevar -- read a variable from a here doc */
getherevar(void)17 extern Tree *getherevar(void) {
18 	int c;
19 	char *s;
20 	Buffer *buf = openbuffer(0);
21 	while (!dnw[c = GETC()])
22 		buf = bufputc(buf, c);
23 	s = sealcountedbuffer(buf);
24 	if (buf->len == 0) {
25 		yyerror("null variable name in here document");
26 		return NULL;
27 	}
28 	if (c != '^')
29 		UNGETC(c);
30 	return flatten(mk(nVar, mk(nWord, s)), " ");
31 }
32 
33 /* snarfheredoc -- read a heredoc until the eof marker */
snarfheredoc(const char * eof,Boolean quoted)34 extern Tree *snarfheredoc(const char *eof, Boolean quoted) {
35 	Tree *tree, **tailp;
36 	Buffer *buf;
37 	unsigned char *s;
38 
39 	assert(quoted || strchr(eof, '$') == NULL);	/* can never be typed (whew!) */
40 	if (strchr(eof, '\n') != NULL) {
41 		yyerror("here document eof-marker contains a newline");
42 		return NULL;
43 	}
44 	disablehistory = TRUE;
45 
46 	for (tree = NULL, tailp = &tree, buf = openbuffer(0);;) {
47 		int c;
48 		print_prompt2();
49 		for (s = (unsigned char *) eof; (c = GETC()) == *s; s++)
50 			;
51 		if (*s == '\0' && (c == '\n' || c == EOF)) {
52 			if (buf->current == 0 && tree != NULL)
53 				freebuffer(buf);
54 			else
55 				*tailp = treecons(mk(nQword, sealcountedbuffer(buf)), NULL);
56 			break;
57 		}
58 		if (s != (unsigned char *) eof)
59 			buf = bufncat(buf, eof, s - (unsigned char *) eof);
60 		for (;; c = GETC()) {
61 			if (c == EOF) {
62 				yyerror("incomplete here document");
63 				freebuffer(buf);
64 				disablehistory = FALSE;
65 				return NULL;
66 			}
67 			if (c == '$' && !quoted && (c = GETC()) != '$') {
68 				Tree *var;
69 				UNGETC(c);
70 				if (buf->current == 0)
71 					freebuffer(buf);
72 				else {
73 					*tailp = treecons(mk(nQword, sealcountedbuffer(buf)), NULL);
74 					tailp = &(*tailp)->CDR;
75 				}
76 				var = getherevar();
77 				if (var == NULL) {
78 					freebuffer(buf);
79 					disablehistory = FALSE;
80 					return NULL;
81 				}
82 				*tailp = treecons(var, NULL);
83 				tailp = &(*tailp)->CDR;
84 				buf = openbuffer(0);
85 				continue;
86 			}
87 			buf = bufputc(buf, c);
88 			if (c == '\n')
89 				break;
90 		}
91 	}
92 
93 	disablehistory = FALSE;
94 	return tree->CDR == NULL ? tree->CAR : tree;
95 }
96 
97 /* readheredocs -- read all the heredocs at the end of a line (or fail if at end of file) */
readheredocs(Boolean endfile)98 extern Boolean readheredocs(Boolean endfile) {
99 	for (; hereq != NULL; hereq = hereq->next) {
100 		Tree *marker, *eof;
101 		if (endfile) {
102 			yyerror("end of file with pending here documents");
103 			return FALSE;
104 		}
105 		marker = hereq->marker;
106 		eof = marker->CAR;
107 		marker->CAR = snarfheredoc(eof->u[0].s, eof->kind == nQword);
108 		if (marker->CAR == NULL)
109 			return FALSE;
110 	}
111 	return TRUE;
112 }
113 
114 /* queueheredoc -- add a heredoc to the queue to process at the end of the line */
queueheredoc(Tree * t)115 extern Boolean queueheredoc(Tree *t) {
116 	Tree *eof;
117 	Here *here;
118 
119 	assert(hereq == NULL || hereq->marker->kind == nList);
120 	assert(t->kind == nList);
121 	assert(t->CAR->kind == nWord);
122 #if !REISER_CPP
123 	assert(streq(t->CAR->u[0].s, "%heredoc"));
124 #endif
125 	t->CAR->u[0].s = "%here";
126 	assert(t->CDR->kind == nList);
127 	eof = t->CDR->CDR;
128 	assert(eof->kind == nList);
129 	if (eof->CAR->kind != nWord && eof->CAR->kind != nQword) {
130 		yyerror("here document eof-marker not a single literal word");
131 		return FALSE;
132 	}
133 
134 	here = gcalloc(sizeof (Here), NULL);
135 	here->next = hereq;
136 	here->marker = eof;
137 	hereq = here;
138 	return TRUE;
139 }
140 
emptyherequeue(void)141 extern void emptyherequeue(void) {
142 	hereq = NULL;
143 	disablehistory = FALSE;
144 }
145