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