1 
2 /*
3  * INCLUDE.C
4  *
5  */
6 
7 #include "defs.h"
8 
9 Prototype void IncludeFile(const char *fileName);
10 Prototype INode	*CurINode;
11 
12 Prototype const char *getToken(INode *in, int expand);
13 Prototype const char *expToken(Depend *dep, INode *in, const char *ptr, int mode);
14 
15 char *extcolon(char **pp, char exdelim, char *pwe);
16 
17 INode	*CurINode;
18 
19 void
IncludeFile(const char * fileName)20 IncludeFile(const char *fileName)
21 {
22     INode *in = MakeNode(fileName, sizeof(INode), 0);
23     int vslen = VNodeStrSize(ExtDefs);
24     char *path = malloc(strlen(fileName) + sizeof(CPPCMD) + vslen + 8);
25 
26     in->in_Parent = CurINode;
27     in->in_Node.no_INode = in;
28     in->in_Node.no_ILine = 0;
29     in->in_LastNl = 1;
30     InitList(&in->in_EList);
31 
32     CurINode = in;
33 
34     {
35 	int l;
36 	Node *node;
37 
38 	strcpy(path, CPPCMD);
39 	l = strlen(path);
40 	for (node = GetHead(&ExtDefs->vn_List); node; node = GetNext(node)) {
41 	    sprintf(path + l, " %s", node->no_Name);
42 	    l += strlen(path + l);
43 	}
44 	sprintf(path + l, " %s", fileName);
45     }
46 
47     if ((in->in_Fi = popen(path, "r")) != NULL) {
48 	const char *s;
49 
50 	while ((s = getToken(in, EXP_FORCE)) != NULL) {
51 	    if (*s == '\n') {
52 		;
53 	    } else if (s[0] == '.' && s[1] != '.' && s[1] != '/') {
54 		if (strcmp(s, ".set") == 0) {
55 		    /*
56 		     * get variable name
57 		     */
58 		    VNode *vnode;
59 
60 		    if ((s = getToken(in, EXP_FORCE)) == NULL) {
61 			fatal(&in->in_Node, ".set - unexpected EOF\n");
62 			/* not reached */
63 		    }
64 		    vnode = MakeVNode(&VarList, s);
65 		    while ((s = getToken(in, EXP_NORMAL)) != NULL && *s != '\n') {
66 			AddTail(&vnode->vn_List, &MakeDNode(s)->dn_Node);
67 		    }
68 		    CommitVNode(vnode);
69 		} else {
70 		    fatal(&in->in_Node, "Unknown directive: %s\n", s);
71 		    /* not reached */
72 		}
73 	    } else {
74 		/*
75 		 * Parse a dependancy:
76 		 *
77 		 * d1 d2 ... dn : s1 s2 ... sn [ : a1 a2 ... an ]
78 		 * d1 : s1 s2 ... sn
79 		 */
80 		List *lhs = malloc(sizeof(List));
81 		List *rhs = malloc(sizeof(List));
82 		List *ahs = malloc(sizeof(List));
83 		List *xlist = malloc(sizeof(List));
84 		List *clist = lhs;
85 
86 		InitList(lhs);
87 		InitList(rhs);
88 		InitList(ahs);
89 		InitList(xlist);
90 
91 		/*
92 		 * Dependancies
93 		 */
94 
95 		while (s && *s != '\n') {
96 		    if (*s == ':') {
97 			if (clist == lhs)
98 			    clist = rhs;
99 			else if (clist == rhs)
100 			    clist = ahs;
101 			else
102 			    fatal(&in->in_Node, "Too many colons in dependancy line\n");
103 		    } else {
104 			AddTail(clist, &MakeDNode(s)->dn_Node);
105 		    }
106 		    if (clist == lhs)
107 			s = getToken(in, EXP_FORCE);
108 		    else
109 			s = getToken(in, EXP_FORCE);
110 		}
111 		if (s == NULL)
112 		    fatal(&in->in_Node, "Unexpected EOF\n");
113 
114 		/*
115 		 * s1 : d1 d2 d3 ... dn
116 		 */
117 
118 		if (lhs->li_Count == 1 && ahs->li_Count == 0) {
119 		    List *t = ahs;
120 		    ahs = rhs;
121 		    rhs = t;
122 		}
123 
124 		if (lhs->li_Count != rhs->li_Count && rhs->li_Count > 1) {
125 		    fatal(
126 			&in->in_Node,
127 			"lhs/rhs count mismatch for rule %s (%d,%d,%d)\n",
128 			((lhs->li_Count) ? lhs->li_Node.no_Next->no_Name : "?"),
129 			lhs->li_Count,
130 			rhs->li_Count,
131 			ahs->li_Count
132 		    );
133 		}
134 
135 		/*
136 		 * Body
137 		 */
138 
139 		{
140 		    int bcnt = 0;
141 		    int c;
142 
143 		    while ((c = getc(in->in_Fi)) != EOF) {
144 			char buf[MAXLINE];
145 
146 			++in->in_Node.no_ILine;
147 
148 			/*
149 			 * Handle end of command sequencing
150 			 */
151 
152 			if (c == '\n' && bcnt == 0)
153 			    break;
154 
155 			/*
156 			 * Handle . directive
157 			 */
158 
159 			if (c == '.') {
160 			    ungetc(c, in->in_Fi);
161 			    s = getToken(in, 0);
162 
163 			    if (strcmp(s, ".set") == 0) {
164 				/*
165 				 * get variable name
166 				 */
167 				VNode *vnode;
168 
169 				if ((s = getToken(in, 0)) == NULL) {
170 				    fatal(&in->in_Node, ".set - unexpected EOF\n");
171 				    /* not reached */
172 				}
173 				vnode = MakeVNode(xlist, s);
174 				while ((s = getToken(in, 0)) != NULL && *s != '\n') {
175 				    AddTail(&vnode->vn_List, &MakeDNode(s)->dn_Node);
176 				}
177 				CommitVNode(vnode);
178 			    } else if (strcmp(s, ".beg") == 0) {
179 				++bcnt;
180 			    } else if (strcmp(s, ".end") == 0) {
181 				if (--bcnt < 0)
182 				    fatal(&in->in_Node, "too many .end directives!\n");
183 			    } else {
184 				fatal(&in->in_Node, "Unknown directive in command sequence: %s\n", s);
185 			    }
186 			    while (s && *s != '\n')
187 				s = getToken(in, 0);
188 			    continue;
189 			}
190 
191 			/*
192 			 * Handle command line to execute
193 			 */
194 
195 			buf[0] = c;
196 			if (fgets(buf + 1, sizeof(buf) - 1, in->in_Fi) == NULL) {
197 			    fatal(&in->in_Node, "Unexpected EOF\n");
198 			}
199 
200 			if (buf[0] != '#') {
201 			    Node *node;
202 			    char *s = buf;
203 			    int l = strlen(buf);
204 
205 			    if (l && buf[l-1] == '\n')
206 				buf[--l] = 0;
207 			    while (*s && (*s == ' ' || *s == '\t'))
208 				++s;
209 
210 			    node = MakeNode(s, sizeof(Node), 0);
211 			    node->no_Type = TYPE_EXEC;
212 			    AddTail(xlist, node);
213 			}
214 		    }
215 		}
216 		in->in_LastNl = 1;
217 
218 		/*
219 		 * Create dependancy list
220 		 */
221 
222 		{
223 		    Node *lnode;
224 
225 		    for (lnode = GetHead(lhs); lnode; lnode = GetNext(lnode)) {
226 			Node *rnode;
227 
228 			if ((rnode = GetHead(rhs)) != NULL)
229 			    DelNode(rhs, rnode);
230 			MakeDepend(lnode->no_Name, rnode, ahs, xlist);
231 		    }
232 		}
233 	    }
234 	}
235 	pclose(in->in_Fi);
236 	in->in_Fi = NULL;
237     } else {
238 	fatal(&in->in_Node, "popen failed: %s\n", path);
239 	/* not reached */
240     }
241     CurINode = in->in_Parent;
242     free(path);
243 }
244 
245 /*
246  * getToken() - get token from FILE and possibly expand it
247  */
248 
249 const char *
getToken(INode * in,int expand)250 getToken(INode *in, int expand)
251 {
252     Node *node;
253     static char Buf[256];
254     static char *LBuf;
255     char *ptr;
256 
257 top:
258     if (LBuf) {
259 	free(LBuf);
260 	LBuf = NULL;
261     }
262 
263     if ((node = GetHead(&in->in_EList)) != NULL) {
264 	DelNode(&in->in_EList, node);
265 	ptr = node->no_Name;
266 	/* cannot set LBuf here, node's no_Name may be reused XXX */
267     } else {
268 	int c;
269 	int i = 0;
270 	int maxi = sizeof(Buf) - 1;
271 	int bqu = 0;
272 	int squ = 0;
273 	int dqu = 0;
274 	int paren = 0;
275 
276 	ptr = Buf;
277 
278 	while ((c = getc(in->in_Fi)) != EOF) {
279 	    if (c == '#') {
280 		if (in->in_LastNl) {
281 		    while ((c = getc(in->in_Fi)) != EOF && c != '\n')
282 			;
283 		    ++in->in_Node.no_ILine;
284 		    if (c == '\n')
285 			c = getc(in->in_Fi);
286 		}
287 	    }
288 
289 	    if (c == '\n') {
290 		/*
291 		 * break on newline
292 		 */
293 		if (paren + bqu + squ + dqu != 0)
294 		    fatal(&in->in_Node, "unterminated string\n");
295 		if (i == 0) {
296 		    ptr[i++] = c;
297 		    c = getc(in->in_Fi);
298 		    in->in_LastNl = 1;
299 		}
300 		break;
301 	    }
302 	    in->in_LastNl = 0;
303 
304 	    if ((c == ' ' || c == '\t') && (paren + bqu + squ + dqu == 0)) {
305 		/*
306 		 * skip leading white space
307 		 */
308 		if (i == 0)
309 		    continue;
310 		/*
311 		 * break on separator
312 		 */
313 		break;
314 	    }
315 
316 	    if (c == '`')
317 		bqu = 1 - bqu;
318 	    if (c == '\"')
319 		dqu = 1 - dqu;
320 	    if (c == '\'' )
321 		squ = 1 - squ;
322 	    if (c == '(' )
323 		++paren;
324 	    if (c == '{' )
325 		++paren;
326 	    if (c == ')' )
327 		--paren;
328 	    if (c == '}' )
329 		--paren;
330 
331 	    if (c == '\\') {
332 		c = getc(in->in_Fi);
333 		if (c == '\n') {
334 		    /*
335 		     * eat both
336 		     */
337 		    continue;
338 		}
339 		ungetc(c, in->in_Fi);
340 		c = '\\';
341 	    }
342 
343 	    /*
344 	     * store c
345 	     */
346 
347 	    if (i == maxi) {
348 		if (ptr == Buf) {
349 		    ptr = malloc(i * 2);
350 		    memmove(ptr, Buf, i);
351 		} else {
352 		    ptr = realloc(ptr, i * 2);
353 		}
354 		LBuf = ptr;
355 		maxi = i * 2 - 1;
356 	    }
357 
358 	    /*
359 	     * make : a delimeter as well
360 	     */
361 
362 	    if (paren + bqu + squ + dqu == 0) {
363 		if (c == ':' && i != 0)
364 		    break;
365 
366 		if (i && ptr[0] == ':')
367 		    break;
368 	    }
369 
370 	    ptr[i++] = c;
371 	}
372 	if (c != EOF)
373 	    ungetc(c, in->in_Fi);
374 	ptr[i] = 0;
375 	if (i == 0)
376 	    ptr = NULL;
377     }
378 
379     if (expand && ptr) {
380 	char *p;
381 	int use = 0;
382 
383 	for (p = ptr; *p; ++p) {
384 	    if ((((p[0] == '$' || p[0] == '%') &&
385 		(p[1] == '(' || (expand == EXP_FORCE && p[1] == '{')))) ||
386 		p[0] == '`'
387 	    ) {
388 		use = expand;
389 		break;
390 	    }
391 	}
392 	if (use) {
393 	    expToken(NULL, in, ptr, use);
394 	    goto top;
395 	}
396     }
397 
398     return(ptr);
399 }
400 
401 /*
402  * expToken() - expand token, pushing the result on in_EList
403  */
404 
405 const char *
expToken(Depend * dep,INode * in,const char * id,int mode)406 expToken(Depend *dep, INode *in, const char *id, int mode)
407 {
408     static char Buf[1024];
409     static char *LBuf;
410     char *ptr = Buf;
411     int i = 0;
412     int bqi = -1;
413     int vcount = 0;
414     int vstart[MAXVARIND];
415     int maxi = sizeof(Buf) - 1;
416 
417     if (LBuf) {
418 	free(LBuf);
419 	LBuf = NULL;
420     }
421 
422     while (*id) {
423 	/*
424 	 * $(VAR)			immediate expansion
425 	 * $(VAR:search:replace)
426 	 *
427 	 * ${VAR}			delayed expansion
428 	 * ${VAR:search:replace}
429 	 */
430 
431 	if ((id[0] == '$' || id[0] == '%') &&
432 	    (id[1] == '(' || (mode == EXP_FORCE && id[1] == '{'))
433 	) {
434 	    vstart[vcount++] = i;
435 	}
436 	if ((id[0] == ')' || (mode == EXP_FORCE && id[0] == '}')) && vcount) {
437 	    /*
438 	     * Expand the variable
439 	     */
440 	    int vqi = vstart[--vcount];
441 	    char type = ptr[vqi];
442 	    char we = 0;
443 	    char *vname;
444 	    char *wsrc = NULL;
445 	    char *wdst = NULL;
446 	    List *list;
447 	    Node *node;
448 
449 	    /*
450 	     * Terminate the variable expression
451 	     */
452 
453 	    ptr[i] = 0;
454 
455 	    /*
456 	     * Extract the name, source, and destination wildcards
457 	     */
458 
459 	    {
460 		char *p = ptr + vqi + 2;
461 		char dummy;
462 
463 		vname = extcolon(&p, '?', &we);
464 		if (*p == ':') {
465 		    wsrc = extcolon(&p, 0, &dummy);
466 		    if (*p == ':')
467 			wdst = extcolon(&p, 0, &dummy);
468 		    else
469 			wdst = wsrc;
470 		}
471 	    }
472 
473 	    /*
474 	     * Locate the variable.
475 	     */
476 
477 	    list = FindVar(type, dep, vname);
478 
479 #ifdef NOTDEF
480 	    if (we) {
481 		char *p = wdst;
482 		int plen;
483 
484 		if (list) {
485 		    p = wsrc;
486 		}
487 		i = vqi;
488 		plen = strlen(p);
489 		if (i + plen >= maxi) {
490 		    maxi = (i + plen) * 2;
491 
492 		    if (ptr == Buf) {
493 			ptr = malloc(maxi);
494 			memmove(ptr, Buf, i);
495 		    } else {
496 			ptr = realloc(ptr, maxi);
497 		    }
498 		}
499 		memmove(ptr + i, p, plen);
500 		i += plen;
501 		++id;
502 		continue;
503 	    }
504 #endif
505 
506 	    if (list == NULL && we != '?')
507 		fatal(&in->in_Node, "Variable(%s) not found\n", vname);
508 
509 	    /*
510 	     * Wildcard transformation
511 	     */
512 
513 	    for ((node= (list)?GetHead(list):NULL); node; node=GetNext(node)) {
514 		char *p = node->no_Name;
515 		char *dbuf = NULL;
516 
517 		if (wsrc != NULL) {
518 		    if (WildConvert(node->no_Name, &dbuf, wsrc, wdst) < 0) {
519 			p = "";
520 		    } else {
521 			p = dbuf;
522 		    }
523 		}
524 
525 		if (*p) {
526 		    /*
527 		     * replace buffer's end (@ i) with string @ vqi and commit.
528 		     * This means that we vectorize multi-entry variables:
529 		     *
530 		     * A=a b c
531 		     * B=d e f
532 		     *
533 		     * $(A)$(B) results in ad ae af bd be bf		REQUEUED
534 		     * $(A)$(B) results in a b cd e f			IN-PLACE
535 		     *
536 		     * if in is NULL, we are doing an in-place replacement  (e.g.
537 		     * for a shell command line)
538 		     *
539 		     * if in is not NULL, we are doing a requeued replacement.
540 		     */
541 		    int plen = strlen(p);
542 
543 		    if (in == NULL) {
544 			int l = vqi + plen + 1;
545 
546 			if (vqi + l >= maxi) {
547 			    maxi = (vqi + l) * 2;
548 			    if (ptr == Buf) {
549 				ptr = malloc(maxi + 1);
550 				memmove(ptr, Buf, vqi);
551 			    } else {
552 				ptr = realloc(ptr, maxi + 1);
553 			    }
554 			}
555 			if (node != list->li_Node.no_Next)
556 			    ptr[vqi++] = ' ';
557 			memmove(ptr + vqi, p, plen);
558 			vqi = vqi + plen;
559 		    } else {
560 			char xbuf[1024];
561 			char *cpy = xbuf;
562 			Node *n2;
563 			int idlen = strlen(id + 1);
564 			int l = vqi + plen + idlen;
565 
566 			if (l >= sizeof(xbuf)) {
567 			    cpy = malloc(l + 1);
568 			}
569 			memmove(cpy, ptr, vqi);
570 			memmove(cpy + vqi, p, plen);
571 			memmove(cpy + vqi + plen, id + 1, idlen);
572 			cpy[vqi+plen+idlen] = 0;
573 
574 			n2 = MakeNode(cpy, sizeof(Node), 0);
575 			AddTail(&in->in_EList, n2);
576 
577 			if (cpy != xbuf)
578 			    free(cpy);
579 		    }
580 		}
581 		if (dbuf)
582 		    free(dbuf);
583 	    }
584 	    if (in != NULL) {
585 		/*
586 		 * break out, because we have requeued the deepest
587 		 * variable expansion level.
588 		 */
589 		i = 0;
590 		break;
591 	    }
592 	    i = vqi;
593 	    ++id;
594 	    continue;
595 	}
596 
597 	if (*id == '`') {
598 	    if (bqi >= 0) {
599 		/*
600 		 * execute and replace, parse the result
601 		 * as a string of tokens
602 		 */
603 		INode *tin;
604 
605 		ptr[i] = 0;
606 		tin = MakeNode(ptr + bqi, sizeof(INode), 0);
607 		tin->in_Parent = CurINode;
608 		tin->in_Node.no_INode = tin;
609 		tin->in_Node.no_ILine = 0;
610 		InitList(&tin->in_EList);
611 
612 		if ((tin->in_Fi = popen(ptr + bqi, "r")) != NULL) {
613 		    const char *s;
614 
615 		    while ((s = getToken(tin, 1)) != NULL) {
616 			Node *node;
617 
618 			if (*s == '\n')
619 			    continue;
620 
621 			node = MakeNode(s, sizeof(Node), 0);
622 			AddTail(&in->in_EList, node);
623 		    }
624 		    pclose(tin->in_Fi);
625 		} else {
626 		    fatal(&in->in_Node, "popen('%s') failed\n", ptr + bqi);
627 		}
628 		i = 0;
629 		bqi = -1;
630 		++id;
631 		continue;
632 	    }
633 	    bqi = i + 1;
634 	    if (i != 0) {
635 		fatal(&in->in_Node, "I can't deal with embedded backticks!\n");
636 	    }
637 	    /* fall through */
638 	}
639 	if (i == maxi) {
640 	    if (ptr == Buf) {
641 		ptr = malloc(i * 2);
642 		memmove(ptr, Buf, i);
643 	    } else {
644 		ptr = realloc(ptr, i * 2);
645 	    }
646 	    maxi = i * 2 - 1;
647 	}
648 	ptr[i++] = *id;
649 	++id;
650     }
651     ptr[i] = 0;
652     if (i && in) {
653 	Node *node = MakeNode(ptr, sizeof(Node), 0);
654 	AddTail(&in->in_EList, node);
655     }
656     if (in == NULL) {
657 	if (ptr != Buf)
658 	    LBuf = ptr;
659 	return(ptr);
660     } else {
661 	if (ptr != Buf)
662 	    free(ptr);
663 	return(NULL);
664     }
665 }
666 
667 char *
extcolon(char ** pp,char exdelim,char * pwe)668 extcolon(char **pp, char exdelim, char *pwe)
669 {
670     char *p = *pp;
671     char *r;
672     int i;
673     int quo = 0;
674 
675     *pwe = 0;
676 
677     if (*p == ':')
678 	++p;
679 
680     if (*p == '\"') {
681 	++p;
682 	quo = 1;
683     }
684     for (i = 0; p[i] && (quo || (p[i] != ':' && p[i] != exdelim)); ++i) {
685 	if (p[i] == '\"') {
686 	    quo = 0;
687 	    break;
688 	}
689     }
690     r = malloc(i + 1);
691     memmove(r, p, i);
692     r[i] = 0;
693 
694     if (p[i] == '\"')
695 	++i;
696 
697     if (exdelim && p[i] == exdelim) {
698 	*pwe = exdelim;
699 	++i;
700     }
701     *pp = p + i;
702 
703     return(r);
704 }
705 
706