xref: /inferno-os/utils/mk/parse.c (revision d0e1d143ef6f03c75c008c7ec648859dd260cbab)
1 #include	"mk.h"
2 
3 char *infile;
4 int mkinline;
5 static int rhead(char *, Word **, Word **, int *, char **);
6 static char *rbody(Biobuf*);
7 extern Word *target1;
8 
9 void
10 parse(char *f, int fd, int varoverride)
11 {
12 	int hline;
13 	char *body;
14 	Word *head, *tail;
15 	int attr, set, pid;
16 	char *prog, *p;
17 	int newfd;
18 	Biobuf in;
19 	Bufblock *buf;
20 
21 	if(fd < 0){
22 		perror(f);
23 		Exit();
24 	}
25 	ipush();
26 	infile = strdup(f);
27 	mkinline = 1;
28 	Binit(&in, fd, OREAD);
29 	buf = newbuf();
30 	while(assline(&in, buf)){
31 		hline = mkinline;
32 		switch(rhead(buf->start, &head, &tail, &attr, &prog))
33 		{
34 		case '<':
35 			p = wtos(tail, ' ');
36 			if(*p == 0){
37 				SYNERR(-1);
38 				fprint(2, "missing include file name\n");
39 				Exit();
40 			}
41 			newfd = open(p, OREAD);
42 			if(newfd < 0){
43 				fprint(2, "warning: skipping missing include file: ");
44 				perror(p);
45 			} else
46 				parse(p, newfd, 0);
47 			break;
48 		case '|':
49 			p = wtos(tail, ' ');
50 			if(*p == 0){
51 				SYNERR(-1);
52 				fprint(2, "missing include program name\n");
53 				Exit();
54 			}
55 			execinit();
56 			pid=pipecmd(p, envy, &newfd);
57 			if(newfd < 0){
58 				fprint(2, "warning: skipping missing program file: ");
59 				perror(p);
60 			} else
61 				parse(p, newfd, 0);
62 			while(waitup(-3, &pid) >= 0)
63 				;
64 			if(pid != 0){
65 				fprint(2, "bad include program status\n");
66 				Exit();
67 			}
68 			break;
69 		case ':':
70 			body = rbody(&in);
71 			addrules(head, tail, body, attr, hline, prog);
72 			break;
73 		case '=':
74 			if(head->next){
75 				SYNERR(-1);
76 				fprint(2, "multiple vars on left side of assignment\n");
77 				Exit();
78 			}
79 			if(symlook(head->s, S_OVERRIDE, 0)){
80 				set = varoverride;
81 			} else {
82 				set = 1;
83 				if(varoverride)
84 					symlook(head->s, S_OVERRIDE, (void *)"");
85 			}
86 			if(set){
87 /*
88 char *cp;
89 dumpw("tail", tail);
90 cp = wtos(tail, ' '); print("assign %s to %s\n", head->s, cp); free(cp);
91 */
92 				setvar(head->s, (void *) tail);
93 				symlook(head->s, S_WESET, (void *)"");
94 			}
95 			if(attr)
96 				symlook(head->s, S_NOEXPORT, (void *)"");
97 			break;
98 		default:
99 			SYNERR(hline);
100 			fprint(2, "expected one of :<=\n");
101 			Exit();
102 			break;
103 		}
104 	}
105 	close(fd);
106 	freebuf(buf);
107 	ipop();
108 }
109 
110 void
111 addrules(Word *head, Word *tail, char *body, int attr, int hline, char *prog)
112 {
113 	Word *w;
114 
115 	assert("addrules args", head && body);
116 		/* tuck away first non-meta rule as default target*/
117 	if(target1 == 0 && !(attr&REGEXP)){
118 		for(w = head; w; w = w->next)
119 			if(charin(w->s, "%&"))
120 				break;
121 		if(w == 0)
122 			target1 = wdup(head);
123 	}
124 	for(w = head; w; w = w->next)
125 		addrule(w->s, tail, body, head, attr, hline, prog);
126 }
127 
128 static int
129 rhead(char *line, Word **h, Word **t, int *attr, char **prog)
130 {
131 	char *p;
132 	char *pp;
133 	int sep;
134 	Rune r;
135 	int n;
136 	Word *w;
137 
138 	p = charin(line,":=<");
139 	if(p == 0)
140 		return('?');
141 	sep = *p;
142 	*p++ = 0;
143 	if(sep == '<' && *p == '|'){
144 		sep = '|';
145 		p++;
146 	}
147 	*attr = 0;
148 	*prog = 0;
149 	if(sep == '='){
150 		pp = charin(p, termchars);	/* termchars is shell-dependent */
151 		if (pp && *pp == '=') {
152 			while (p != pp) {
153 				n = chartorune(&r, p);
154 				switch(r)
155 				{
156 				default:
157 					SYNERR(-1);
158 					fprint(2, "unknown attribute '%c'\n",*p);
159 					Exit();
160 				case 'U':
161 					*attr = 1;
162 					break;
163 				}
164 				p += n;
165 			}
166 			p++;		/* skip trailing '=' */
167 		}
168 	}
169 	if((sep == ':') && *p && (*p != ' ') && (*p != '\t')){
170 		while (*p) {
171 			n = chartorune(&r, p);
172 			if (r == ':')
173 				break;
174 			p += n;
175 			switch(r)
176 			{
177 			default:
178 				SYNERR(-1);
179 				fprint(2, "unknown attribute '%c'\n", p[-1]);
180 				Exit();
181 			case 'D':
182 				*attr |= DEL;
183 				break;
184 			case 'E':
185 				*attr |= NOMINUSE;
186 				break;
187 			case 'n':
188 				*attr |= NOVIRT;
189 				break;
190 			case 'N':
191 				*attr |= NOREC;
192 				break;
193 			case 'P':
194 				pp = utfrune(p, ':');
195 				if (pp == 0 || *pp == 0)
196 					goto eos;
197 				*pp = 0;
198 				*prog = strdup(p);
199 				*pp = ':';
200 				p = pp;
201 				break;
202 			case 'Q':
203 				*attr |= QUIET;
204 				break;
205 			case 'R':
206 				*attr |= REGEXP;
207 				break;
208 			case 'U':
209 				*attr |= UPD;
210 				break;
211 			case 'V':
212 				*attr |= VIR;
213 				break;
214 			}
215 		}
216 		if (*p++ != ':') {
217 	eos:
218 			SYNERR(-1);
219 			fprint(2, "missing trailing :\n");
220 			Exit();
221 		}
222 	}
223 	*h = w = stow(line);
224 	if(*w->s == 0 && sep != '<' && sep != '|') {
225 		SYNERR(mkinline-1);
226 		fprint(2, "no var on left side of assignment/rule\n");
227 		Exit();
228 	}
229 	*t = stow(p);
230 	return(sep);
231 }
232 
233 static char *
234 rbody(Biobuf *in)
235 {
236 	Bufblock *buf;
237 	int r, lastr;
238 	char *p;
239 
240 	lastr = '\n';
241 	buf = newbuf();
242 	for(;;){
243 		r = Bgetrune(in);
244 		if (r < 0)
245 			break;
246 		if (lastr == '\n') {
247 			if (r == '#')
248 				rinsert(buf, r);
249 			else if (r != ' ' && r != '\t') {
250 				Bungetrune(in);
251 				break;
252 			}
253 		} else
254 			rinsert(buf, r);
255 		lastr = r;
256 		if (r == '\n')
257 			mkinline++;
258 	}
259 	insert(buf, 0);
260 	p = strdup(buf->start);
261 	freebuf(buf);
262 	return p;
263 }
264 
265 struct input
266 {
267 	char *file;
268 	int line;
269 	struct input *next;
270 };
271 static struct input *inputs = 0;
272 
273 void
274 ipush(void)
275 {
276 	struct input *in, *me;
277 
278 	me = (struct input *)Malloc(sizeof(*me));
279 	me->file = infile;
280 	me->line = mkinline;
281 	me->next = 0;
282 	if(inputs == 0)
283 		inputs = me;
284 	else {
285 		for(in = inputs; in->next; )
286 			in = in->next;
287 		in->next = me;
288 	}
289 }
290 
291 void
292 ipop(void)
293 {
294 	struct input *in, *me;
295 
296 	assert("pop input list", inputs != 0);
297 	if(inputs->next == 0){
298 		me = inputs;
299 		inputs = 0;
300 	} else {
301 		for(in = inputs; in->next->next; )
302 			in = in->next;
303 		me = in->next;
304 		in->next = 0;
305 	}
306 	infile = me->file;
307 	mkinline = me->line;
308 	free((char *)me);
309 }
310