1#include <assert.h>
2#include <ctype.h>
3#include <errno.h>
4#include <limits.h>
5#include <stdarg.h>
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9
10#include "make.h"
11
12#define MAXREPL 30
13#define TABSIZ 64
14#define MAXTOKEN FILENAME_MAX
15#define ITEM 128
16
17typedef struct macro Macro;
18
19enum inputype {
20 FTFILE,
21 FTEXPAN,
22};
23
24enum {
25 STBEGIN,
26 STINTERNAL,
27 STREPLACE,
28 STTO,
29 STEND,
30};
31
32struct input {
33 int siz;
34 int type;
35
36 FILE *fp;
37 struct loc loc;
38
39 int pos;
40 char *buf;
41
42 struct input *prev;
43};
44
45struct macro {
46 char *name;
47 char *value;
48 int where;
49
50 struct macro *next;
51};
52
53static struct input *input;
54static char token[MAXTOKEN];
55static int tok;
56static Macro *htab[TABSIZ];
57
58void
59dumpmacros(void)
60{
61 Macro **pp, *p;
62
63 for (pp = htab; pp < &htab[TABSIZ]; ++pp) {
64 for (p = *pp; p; p = p->next)
65 printf("%s = %s\n", p->name, getmacro(p->name));
66 }
67}
68
69static Macro *
70lookup(char *name)
71{
72 Macro *mp;
73 int h = hash(name) & (TABSIZ - 1);
74
75 for (mp = htab[h]; mp && strcmp(mp->name, name); mp = mp->next)
76 ;
77
78 if (mp)
79 return mp;
80
81 mp = emalloc(sizeof(*mp));
82 mp->name = estrdup(name);
83 mp->value = estrdup("");
84 mp->next = htab[h];
85 mp->where = UNDEF;
86 htab[h] = mp;
87
88 return mp;
89}
90
91static char *
92macroinfo(char *name, int *pwhere, Macro **mpp)
93{
94 char *s, *t;
95 int hide, where;
96 Macro *mp = lookup(name);
97
98 hide = 0;
99 if (!strcmp(name, "SHELL") || !strcmp(name, "MAKEFLAGS"))
100 hide = 1;
101
102 s = mp->value;
103 where = mp->where;
104
105 if (!hide && (where == UNDEF || where == INTERNAL || eflag)) {
106 t = getenv(name);
107 if (t) {
108 where = ENVIRON;
109 s = t;
110 }
111 }
112
113 if (pwhere)
114 *pwhere = where;
115 if (mpp)
116 *mpp = mp;
117
118 return s;
119}
120
121char *
122getmacro(char *name)
123{
124 return macroinfo(name, NULL, NULL);
125}
126
127void
128setmacro(char *name, char *val, int where, int export)
129{
130 int owhere, set;
131 char *s;
132 Macro *mp;
133
134 assert(where != ENVIRON);
135
136 s = macroinfo(name, &owhere, &mp);
137
138 /*
139 * Default values are defined before anything else, and marked
140 * as INTERNAL because they are injected as parseable text, and
141 * MAKEFILE and INTERNAL variables are always overriden. ENVIRON
142 * macros are generated in macroinfo() and this is why this function
143 * should not receive a where == ENVIRON ever.
144 */
145 switch (owhere) {
146 case UNDEF:
147 case INTERNAL:
148 case MAKEFILE:
149 set = 1;
150 break;
151 case ENVIRON:
152 set = (where == MAKEFLAGS || where == CMDLINE);
153 set |= (where == MAKEFILE && !eflag);
154 break;
155 case MAKEFLAGS:
156 set = (where == CMDLINE || where == MAKEFLAGS);
157 break;
158 case CMDLINE:
159 set = (where == CMDLINE);
160 break;
161 default:
162 abort();
163 }
164
165 if (!set) {
166 debug("hidding override of %s from '%s' to '%s'", name, s, val);
167 } else {
168 debug("override %s from '%s' to '%s'", name, s, val);
169 free(mp->value);
170 mp->value = estrdup(val);
171 mp->where = where;
172
173 if (export && strcmp(name, "SHELL") != 0) {
174 debug("exporting macro %s", name);
175 exportvar(name, val);
176 }
177 }
178}
179
180void
181freeloc(struct loc *loc)
182{
183 free(loc->fname);
184}
185
186static struct loc *
187getloc(void)
188{
189 struct input *ip;
190
191 for (ip = input; ip && ip->type != FTFILE; ip = ip->prev)
192 ;
193 if (!ip)
194 return NULL;
195
196 return &ip->loc;
197}
198
199void
200error(char *fmt, ...)
201{
202 va_list va;
203 struct loc *loc;
204
205 fprintf(stderr, "make: error: ");
206 if ((loc = getloc()) != NULL)
207 fprintf(stderr, "%s:%d: ", loc->fname, loc->lineno);
208
209 va_start(va, fmt);
210 vfprintf(stderr, fmt, va);
211 va_end(va);
212 putc('\n', stderr);
213
214 exit(EXIT_FAILURE);
215}
216
217void
218warning(char *fmt, ...)
219{
220 va_list va;
221 struct loc *loc;
222
223 fprintf(stderr, "make: warning: ");
224 if ((loc = getloc()) != NULL)
225 fprintf(stderr, "%s:%d: ", loc->fname, loc->lineno);
226
227 va_start(va, fmt);
228 vfprintf(stderr, fmt, va);
229 va_end(va);
230 putc('\n', stderr);
231}
232
233static void
234pop(void)
235{
236 struct input *ip = input->prev;
237
238 if (input->type == FTFILE) {
239 if (input->fp)
240 fclose(input->fp);
241 freeloc(&input->loc);
242 }
243 free(input->buf);
244 free(input);
245
246 input = ip;
247}
248
249static void
250push(int type, ...)
251{
252 int line, len, pos;
253 FILE *fp = NULL;
254 char *buf, *s, *fname = NULL;
255 va_list va;
256 struct input *ip;
257
258 va_start(va, type);
259 switch (type) {
260 case FTFILE:
261 fp = va_arg(va, FILE *);
262 s = va_arg(va, char *);
263 line = va_arg(va, int);
264 fname = estrdup(s);
265 buf = emalloc(BUFSIZ);
266 pos = len = BUFSIZ;
267 break;
268 case FTEXPAN:
269 s = va_arg(va, char *);
270 buf = estrdup(s);
271 line = pos = 0;
272 len = strlen(s);
273 break;
274 }
275 va_end(va);
276
277 ip = emalloc(sizeof(*ip));
278 ip->siz = len;
279 ip->buf = buf;
280 ip->type = type;
281 ip->fp = fp;
282 ip->loc.fname = fname;
283 ip->loc.lineno = line;
284 ip->pos = pos;
285 ip->prev = input;
286
287 input = ip;
288}
289
290static char *
291trim(char *s)
292{
293 size_t len;
294
295 while (isspace(*s))
296 s++;
297
298 for (len = strlen(s); len > 0 && isspace(s[len - 1]); --len)
299 s[len - 1] = '\0';
300
301 return s;
302}
303
304static void
305include(char *s)
306{
307 FILE *fp;
308 char *fil, *t, *end;
309
310 s = trim(s);
311 if (*s == '<' || *s == '"') {
312 char delim = (*s == '<') ? '>' : '"';
313 s++;
314 end = strchr(s, delim);
315 if (end)
316 *end = '\0';
317 }
318 fil = expandstring(s, NULL, getloc());
319
320 t = trim(fil);
321 if (strlen(t) != 0) {
322 debug("including '%s'", t);
323 if ((fp = fopen(t, "r")) == NULL)
324 error("opening %s:%s", t, strerror(errno));
325 push(FTFILE, fp, t, 0);
326 }
327
328 free(fil);
329}
330
331static void
332sinclude(char *s)
333{
334 FILE *fp;
335 char *fil, *t, *end;
336
337 s = trim(s);
338 if (*s == '<' || *s == '"') {
339 char delim = (*s == '<') ? '>' : '"';
340 s++;
341 end = strchr(s, delim);
342 if (end)
343 *end = '\0';
344 }
345 fil = expandstring(s, NULL, getloc());
346
347 t = trim(fil);
348 if (strlen(t) != 0) {
349 debug("trying to include '%s'", t);
350 if ((fp = fopen(t, "r")) != NULL)
351 push(FTFILE, fp, t, 0);
352 else
353 debug("skipping missing include %s", t);
354 }
355
356 free(fil);
357}
358
359#define MAXCOND 32
360static struct {
361 int active;
362 int matched;
363 int parent_active;
364} condstack[MAXCOND];
365static int conddepth = 0;
366
367static int
368cond_active(void)
369{
370 if (conddepth == 0)
371 return 1;
372 return condstack[conddepth].active && condstack[conddepth].parent_active;
373}
374
375static void
376cond_if(int truth)
377{
378 int parent;
379 if (conddepth >= MAXCOND)
380 error("too many nested .if directives");
381 parent = cond_active();
382 conddepth++;
383 condstack[conddepth].parent_active = parent;
384 condstack[conddepth].matched = truth;
385 condstack[conddepth].active = truth;
386}
387
388static void
389cond_elif(int truth)
390{
391 if (conddepth == 0)
392 error(".elif without .if");
393 if (condstack[conddepth].matched)
394 condstack[conddepth].active = 0;
395 else {
396 condstack[conddepth].matched = condstack[conddepth].matched || truth;
397 condstack[conddepth].active = truth;
398 }
399}
400
401static void
402cond_else(void)
403{
404 if (conddepth == 0)
405 error(".else without .if");
406 condstack[conddepth].active = !condstack[conddepth].matched;
407 condstack[conddepth].matched = 1;
408}
409
410static void
411cond_endif(void)
412{
413 if (conddepth == 0)
414 error(".endif without .if");
415 conddepth--;
416}
417
418static int
419eval_if(char *expr)
420{
421 char *s, *p, *var, *val, *end;
422 int neg = 0, result;
423
424 s = trim(expr);
425 if (!*s)
426 return 0;
427
428 while (*s == '(') {
429 end = s + strlen(s);
430 if (end > s && end[-1] == ')')
431 end[-1] = '\0';
432 s++;
433 s = trim(s);
434 }
435
436 if (*s == '!') {
437 neg = 1;
438 s++;
439 s = trim(s);
440 }
441
442 if (strncmp(s, "defined", 7) == 0 && (s[7] == '(' || s[7] == ' ')) {
443 var = trim(s + 7);
444 if (*var == '(')
445 var++;
446 end = var + strlen(var);
447 if (end > var && end[-1] == ')')
448 end[-1] = '\0';
449 var = trim(var);
450 result = getmacro(var)[0] != '\0';
451 return neg ? !result : result;
452 }
453
454 if (strncmp(s, "make", 4) == 0 && (s[4] == '(' || s[4] == ' ')) {
455 var = trim(s + 4);
456 if (*var == '(')
457 var++;
458 end = var + strlen(var);
459 if (end > var && end[-1] == ')')
460 end[-1] = '\0';
461 var = trim(var);
462 result = getmacro(var)[0] != '\0';
463 return neg ? !result : result;
464 }
465
466 {
467 char *expanded = expandstring(s, NULL, getloc());
468 s = expanded;
469 }
470
471 p = strstr(s, "==");
472 if (!p)
473 p = strstr(s, "!=");
474 if (p) {
475 int eq = (p[1] == '=');
476 *p = '\0';
477 val = trim(p + 2);
478 var = trim(s);
479 {
480 char *ev = expandstring(var, NULL, getloc());
481 result = strcmp(ev, val) == 0;
482 free(ev);
483 }
484 if (!eq)
485 result = !result;
486 free(s);
487 return neg ? !result : result;
488 }
489
490 /* bare expression: true if non-empty after expansion */
491 result = s[0] != '\0';
492 free(s);
493 return neg ? !result : result;
494}
495
496static char *
497nextline(void)
498{
499 int c;
500 FILE *fp;
501 char *s, *lim, d[BUFSIZ];
502
503 assert(input->type == FTFILE);
504
505repeat:
506 fp = input->fp;
507 if (!fp || feof(fp))
508 return NULL;
509
510 lim = &input->buf[input->siz];
511 for (s = input->buf; s < lim; *s++ = c) {
512 c = getc(fp);
513 if (c == '\n' || c == EOF) {
514 input->loc.lineno++;
515 *s++ = '\n';
516 break;
517 }
518 if (c > UCHAR_MAX || c < 0)
519 error("invalid character '%c' (%d)", c, c);
520 }
521
522 if (s == lim)
523 error("too long line");
524 if (ferror(fp))
525 error(strerror(errno));
526 *s = '\0';
527
528 if (!strcmp(input->buf, ""))
529 goto repeat;
530
531 /* bmake style .include / .sinclude / .-include */
532 if (input->buf[0] == '.') {
533 size_t dl;
534 /* copy and strip trailing whitespace/newline so strcmp works */
535 strncpy(d, input->buf + 1, sizeof(d) - 1);
536 d[sizeof(d) - 1] = '\0';
537 dl = strlen(d);
538 while (dl > 0 && isspace((unsigned char)d[dl - 1]))
539 d[--dl] = '\0';
540 if (strncmp(d, "include", 7) == 0 && isblank(d[7])) {
541 input->pos = input->siz;
542 if (cond_active())
543 include(d + 7);
544 goto repeat;
545 }
546 if (strncmp(d, "sinclude", 8) == 0 && isblank(d[8])) {
547 input->pos = input->siz;
548 if (cond_active())
549 sinclude(d + 8);
550 goto repeat;
551 }
552 if (strncmp(d, "-include", 8) == 0 && isblank(d[8])) {
553 input->pos = input->siz;
554 if (cond_active())
555 sinclude(d + 8);
556 goto repeat;
557 }
558 if (strncmp(d, "optinclude", 10) == 0 && isblank(d[10])) {
559 input->pos = input->siz;
560 if (cond_active())
561 sinclude(d + 10);
562 goto repeat;
563 }
564 /* conditionals */
565 if (strncmp(d, "if", 2) == 0 && (isblank(d[2]) || d[2] == '\0')) {
566 if (cond_active()) {
567 if (d[2] == '\0')
568 cond_if(eval_if(""));
569 else
570 cond_if(eval_if(d + 3));
571 } else {
572 cond_if(0);
573 }
574 goto repeat;
575 }
576 if (strncmp(d, "ifdef", 5) == 0 && (isblank(d[5]) || d[5] == '\0')) {
577 if (cond_active()) {
578 char *v = trim(d[5] ? d + 6 : "");
579 cond_if(getmacro(v)[0] != '\0');
580 } else {
581 cond_if(0);
582 }
583 goto repeat;
584 }
585 if (strncmp(d, "ifndef", 6) == 0 && (isblank(d[6]) || d[6] == '\0')) {
586 if (cond_active()) {
587 char *v = trim(d[6] ? d + 7 : "");
588 cond_if(getmacro(v)[0] == '\0');
589 } else {
590 cond_if(0);
591 }
592 goto repeat;
593 }
594 if (strncmp(d, "elif", 4) == 0 && (isblank(d[4]) || d[4] == '\0')) {
595 if (condstack[conddepth].parent_active)
596 cond_elif(eval_if(d[4] ? d + 5 : ""));
597 else
598 cond_elif(0);
599 goto repeat;
600 }
601 if (strcmp(d, "else") == 0) {
602 cond_else();
603 goto repeat;
604 }
605 if (strcmp(d, "endif") == 0) {
606 cond_endif();
607 goto repeat;
608 }
609 if (strncmp(d, "error", 5) == 0 && isblank(d[5])) {
610 if (cond_active())
611 error("%s", trim(d + 6));
612 goto repeat;
613 }
614 if (strncmp(d, "warning", 7) == 0 && isblank(d[7])) {
615 if (cond_active())
616 warning("%s", trim(d + 8));
617 goto repeat;
618 }
619 }
620
621 /* POSIX include */
622 if (!strncmp(input->buf, "include", 7) && isblank(input->buf[7])) {
623 input->pos = input->siz;
624 if (cond_active())
625 include(input->buf + 7);
626 goto repeat;
627 }
628
629 /* sinclude / -include (GNU/POSIX style without dot) */
630 if ((!strncmp(input->buf, "sinclude", 8) && isblank(input->buf[8]))
631 || (!strncmp(input->buf, "-include", 8) && isblank(input->buf[8]))) {
632 input->pos = input->siz;
633 if (cond_active())
634 sinclude(input->buf + 8);
635 goto repeat;
636 }
637
638 /* if we are inside an inactive conditional branch, skip this line */
639 if (!cond_active()) {
640 input->pos = input->siz;
641 goto repeat;
642 }
643
644 input->pos = 0;
645
646 return input->buf;
647}
648
649static int
650empty(struct input *ip)
651{
652 return ip->pos == ip->siz || ip->buf[ip->pos] == '\0';
653}
654
655static int
656moreinput(void)
657{
658 while (input) {
659 if (!empty(input))
660 break;
661
662 switch (input->type) {
663 case FTEXPAN:
664 pop();
665 break;
666 case FTFILE:
667 if (!nextline())
668 pop();
669 break;
670 }
671 }
672
673 return input != NULL;
674}
675
676static int
677nextc(void)
678{
679 if (!moreinput())
680 return EOF;
681
682 return input->buf[input->pos++];
683}
684
685/*
686 * This function only can be called after a call to nextc
687 * that didn't return EOF. It can return '\0', but as
688 * it is used only to check against '$' then it is not
689 * a problem.
690 */
691static int
692ahead(void)
693{
694 return input->buf[input->pos];
695}
696
697static int
698back(int c)
699{
700 if (c == EOF)
701 return c;
702 assert(input->pos > 0);
703 return input->buf[--input->pos] = c;
704}
705
706static void
707comment(void)
708{
709 int c;
710
711 while ((c = nextc()) != EOF && c != '\n') {
712 if (c == '\\' && nextc() == EOF)
713 break;
714 }
715}
716
717static void
718skipspaces(void)
719{
720 int c;
721
722 for (c = nextc(); c == ' ' || c == '\t'; c = nextc())
723 ;
724 back(c);
725}
726
727static int
728validchar(int c)
729{
730 if (c == EOF)
731 return 0;
732 return c == '.' || c == '/' || c == '_' || c == '-' || isalnum(c);
733}
734
735static char *
736expandmacro(char *name)
737{
738 char *s;
739
740 s = expandstring(getmacro(name), NULL, getloc());
741 debug("macro %s expanded to '%s'", name, s);
742
743 return s;
744}
745
746static void
747replace(char *line, char *repl, char *to)
748{
749 int siz, at, len, replsiz, tosiz, pos;
750 char *oline, *cur, *buf;
751
752 debug("replacing '%s', with '%s' to '%s'", line, repl, to);
753 oline = line;
754 tosiz = strlen(to);
755 replsiz = strlen(repl);
756
757 buf = NULL;
758 for (pos = 0; *line; pos += siz) {
759 cur = NULL;
760 siz = 0;
761
762 for (siz = 0; *line == ' ' || *line == '\t'; ++siz) {
763 cur = erealloc(cur, siz + 1);
764 cur[siz] = *line++;
765 }
766
767 len = strcspn(line, " \t");
768 at = len - replsiz;
769 if (at < 0 || memcmp(line + at, repl, replsiz)) {
770 cur = erealloc(cur, siz + len);
771 memcpy(cur + siz, line, len);
772 siz += len;
773 } else {
774 cur = erealloc(cur, siz + at + tosiz);
775 memcpy(cur + siz, line, at);
776 memcpy(cur + siz + at, to, tosiz);
777 siz += at + tosiz;
778 }
779
780 line += len;
781 buf = erealloc(buf, pos + siz);
782 memcpy(buf + pos, cur, siz);
783 free(cur);
784 }
785
786 if (pos > 0) {
787 buf = erealloc(buf, pos + 1);
788 buf[pos] = '\0';
789 debug("\treplace '%s' with '%s'", oline, buf);
790 push(FTEXPAN, buf);
791 }
792
793 free(buf);
794}
795
796static void
797expandsimple(Target *tp)
798{
799 char *s;
800 Target **p;
801 int len, c, first;
802
803 switch (c = nextc()) {
804 case '@':
805 if (!tp || !tp->target)
806 return;
807 push(FTEXPAN, tp->target);
808 break;
809 case '<':
810 if (!tp || !tp->req)
811 return;
812 push(FTEXPAN, tp->req);
813 break;
814 case '*':
815 if (!tp || !tp->target)
816 return;
817 s = strrchr(tp->target, '.');
818 if (!s) {
819 push(FTEXPAN, tp->target);
820 return;
821 }
822
823 len = s - tp->target;
824 s = emalloc(len + 1);
825 memcpy(s, tp->target, len);
826 s[len] = '\0';
827 push(FTEXPAN, s);
828 free(s);
829 break;
830 case '?':
831 if (!tp)
832 return;
833
834 if (tp->req && stamp(tp->req) > tp->stamp) {
835 push(FTEXPAN, " ");
836 push(FTEXPAN, tp->req);
837 }
838
839 for (p = tp->deps; p && *p; ++p) {
840 if (stamp((*p)->name) > tp->stamp) {
841 push(FTEXPAN, " ");
842 push(FTEXPAN, (*p)->name);
843 }
844 }
845 break;
846 case '>':
847 case '^':
848 if (!tp)
849 return;
850 first = 1;
851 if (tp->req) {
852 push(FTEXPAN, tp->req);
853 first = 0;
854 }
855 for (p = tp->deps; p && *p; ++p) {
856 if (!first)
857 push(FTEXPAN, " ");
858 push(FTEXPAN, (*p)->name);
859 first = 0;
860 }
861 break;
862 default:
863 token[0] = c;
864 token[1] = '\0';
865 s = expandmacro(token);
866 push(FTEXPAN, s);
867 free(s);
868 break;
869 }
870}
871
872static int
873internal(int ch)
874{
875 switch (ch) {
876 case '@':
877 case '?':
878 case '*':
879 case '<':
880 case '>':
881 case '^':
882 return 1;
883 default:
884 return 0;
885 }
886}
887
888static void
889expansion(Target *tp)
890{
891 int delim, c, repli, toi, namei, st;
892 char name[MAXTOKEN], repl[MAXREPL], to[MAXREPL];
893 char *s, *erepl;
894
895 c = nextc();
896 if (c == '(')
897 delim = ')';
898 else if (c == '{')
899 delim = '}';
900 else
901 delim = 0;
902
903 if (!delim) {
904 back(c);
905 expandsimple(tp);
906 return;
907 }
908
909 s = NULL;
910 namei = repli = toi = 0;
911 st = STBEGIN;
912
913 while (st != STEND && (c = nextc()) != EOF) {
914 switch (st) {
915 case STBEGIN:
916 if (c == ':') {
917 st = STREPLACE;
918 name[namei] = '\0';
919 s = expandmacro(name);
920 break;
921 }
922 if (c == delim) {
923 name[namei] = '\0';
924 s = expandmacro(name);
925 goto no_replace;
926 }
927 if (namei == MAXTOKEN - 1)
928 error("expansion text too long");
929
930 if (namei == 0 && internal(c)) {
931 name[namei++] = '$';
932 name[namei++] = c;
933 name[namei] = '\0';
934 st = STINTERNAL;
935 s = expandstring(name, tp, getloc());
936 break;
937 }
938
939 if (!validchar(c))
940 error("invalid macro name in expansion");
941 name[namei++] = c;
942 break;
943 case STINTERNAL:
944 if (c == delim)
945 goto no_replace;
946 if (c != ':')
947 error("invalid internal macro in expansion");
948 st = STREPLACE;
949 break;
950 case STREPLACE:
951 if (c == '=') {
952 st = STTO;
953 break;
954 }
955 if (c == delim)
956 error(
957 "invalid replacement pattern in "
958 "expansion"
959 );
960 if (repli == MAXREPL - 1)
961 error("macro replacement too big");
962 repl[repli++] = c;
963 break;
964 case STTO:
965 if (c == delim) {
966 st = STEND;
967 break;
968 }
969
970 if (toi == MAXREPL - 1)
971 error("macro substiturion too big");
972 to[toi++] = c;
973 break;
974 }
975 }
976
977 if (c == EOF)
978 error("found eof while parsing expansion");
979
980 repl[repli] = '\0';
981 to[toi] = '\0';
982
983 erepl = expandstring(repl, tp, getloc());
984 replace(s, erepl, to);
985
986 free(erepl);
987 free(s);
988 return;
989
990no_replace:
991 push(FTEXPAN, s);
992 free(s);
993}
994
995/*
996 * Horrible hack to do string expansion.
997 * We cannot use normal push and nextc because that
998 * would consume characters of the current file too.
999 * For that reason it cleans the input and it recovers
1000 * it later.
1001 */
1002char *
1003expandstring(char *line, Target *tp, struct loc *loc)
1004{
1005 int c, n;
1006 char *s;
1007 struct input *ip = input;
1008
1009 input = NULL;
1010 push(FTFILE, NULL, loc->fname, loc->lineno);
1011 push(FTEXPAN, line);
1012
1013 n = 0;
1014 s = NULL;
1015 while ((c = nextc()) != EOF) {
1016 if (c != '$') {
1017 s = erealloc(s, ++n);
1018 s[n - 1] = c;
1019 continue;
1020 }
1021
1022 if ((c = nextc()) == '$') {
1023 s = erealloc(s, n += 2);
1024 s[n - 2] = '$';
1025 s[n - 1] = '$';
1026 } else {
1027 back(c);
1028 expansion(tp);
1029 }
1030 }
1031
1032 s = erealloc(s, n + 1);
1033 s[n] = '\0';
1034 input = ip;
1035
1036 return s;
1037}
1038
1039static int
1040item(void)
1041{
1042 int c;
1043 char *s;
1044 char buf[MAXTOKEN];
1045
1046 for (s = buf; s < &buf[MAXTOKEN] - 1;) {
1047 c = nextc();
1048 if (c == '$' && ahead() != '$')
1049 expansion(NULL);
1050 else if (validchar(c))
1051 *s++ = c;
1052 else
1053 break;
1054 }
1055 back(c);
1056
1057 if (s >= &buf[MAXTOKEN] - 1)
1058 error("token too long");
1059 if (s == buf)
1060 error("invalid empty token");
1061 *s++ = '\0';
1062 memcpy(token, buf, s - buf);
1063
1064 return ITEM;
1065}
1066
1067static int
1068next(void)
1069{
1070 int c;
1071
1072repeat:
1073 /*
1074 * It is better to avoid skipspaces() here, because
1075 * it can generate the need for 2 calls to back(),
1076 * and we need the character anyway.
1077 */
1078 c = nextc();
1079 if (c == ' ' || c == '\t')
1080 goto repeat;
1081
1082 if (c == '\\') {
1083 if ((c = nextc()) == '\n')
1084 goto repeat;
1085 back(c);
1086 c = '\\';
1087 }
1088
1089 switch (c) {
1090 case EOF:
1091 strcpy(token, "<EOF>");
1092 tok = EOF;
1093 break;
1094 case '$':
1095 if ((c = nextc()) == '$')
1096 goto single;
1097 back(c);
1098 expansion(NULL);
1099 goto repeat;
1100 case '#':
1101 comment();
1102 c = '\n';
1103 /* fallthrough */
1104 case ';':
1105 case ':':
1106 case '=':
1107 case '\n':
1108 single:
1109 token[0] = c;
1110 token[1] = '\0';
1111 tok = c;
1112 break;
1113 case '+':
1114 if (nextc() == '=') {
1115 token[0] = '+';
1116 token[1] = '=';
1117 token[2] = '\0';
1118 tok = '+';
1119 break;
1120 }
1121 error("unexpected character '+'");
1122 case '!':
1123 if (nextc() == '=') {
1124 token[0] = '!';
1125 token[1] = '=';
1126 token[2] = '\0';
1127 tok = '!';
1128 break;
1129 }
1130 error("unexpected character '!'");
1131 default:
1132 if (!validchar(c))
1133 error("unexpected character '%c'", c);
1134 back(c);
1135 tok = item();
1136 break;
1137 }
1138
1139 return tok;
1140}
1141
1142static char *
1143readmacrodef(void)
1144{
1145 int n, c;
1146 char *line;
1147
1148 n = 0;
1149 line = NULL;
1150 while ((c = nextc()) != EOF) {
1151 line = erealloc(line, n + 1);
1152 if (c == '\n')
1153 break;
1154 if (c == '#') {
1155 comment();
1156 break;
1157 }
1158 if (c == '\\') {
1159 if ((c = nextc()) != '\n') {
1160 back(c);
1161 c = '\\';
1162 } else {
1163 skipspaces();
1164 c = ' ';
1165 }
1166 }
1167
1168 line[n++] = c;
1169 }
1170 if (c == EOF)
1171 error("EOF while looking for end of line");
1172 line[n] = '\0';
1173
1174 return line;
1175}
1176
1177static struct action
1178readcmd(void)
1179{
1180 int n, c;
1181 struct loc *loc;
1182 struct action act;
1183
1184 skipspaces();
1185
1186 loc = getloc();
1187 act.loc.fname = estrdup(loc->fname);
1188 act.loc.lineno = loc->lineno;
1189
1190 n = 0;
1191 act.line = NULL;
1192 while ((c = nextc()) != EOF) {
1193 act.line = erealloc(act.line, n + 1);
1194 if (c == '\n')
1195 break;
1196 if (c == '\\') {
1197 if ((c = nextc()) == '\n') {
1198 if ((c = nextc()) != '\t')
1199 back(c);
1200 continue;
1201 }
1202 back(c);
1203 c = '\\';
1204 }
1205 act.line[n++] = c;
1206 }
1207 if (c == EOF)
1208 error("EOF while looking for end of command");
1209 act.line[n] = '\0';
1210
1211 return act;
1212}
1213
1214static void
1215rule(char *targets[], int ntargets)
1216{
1217 int c, i, j, ndeps, nactions;
1218 struct action *acts;
1219 char **deps = NULL;
1220
1221 if (ntargets == 0)
1222 error("missing target");
1223
1224 for (ndeps = 0; next() == ITEM; ++ndeps) {
1225 deps = erealloc(deps, (ndeps + 1) * sizeof(char *));
1226 deps[ndeps] = estrdup(token);
1227 }
1228
1229 if (tok != '\n' && tok != ';')
1230 error("garbage at the end of the line");
1231
1232 nactions = 0;
1233 acts = NULL;
1234 if (tok == ';') {
1235 nactions++;
1236 acts = erealloc(acts, nactions * sizeof(*acts));
1237 acts[nactions - 1] = readcmd();
1238 }
1239
1240 for (;;) {
1241 if ((c = nextc()) == '#') {
1242 comment();
1243 continue;
1244 }
1245 if (c != '\t')
1246 break;
1247 nactions++;
1248 acts = erealloc(acts, nactions * sizeof(*acts));
1249 acts[nactions - 1] = readcmd();
1250 }
1251 back(c);
1252
1253 for (i = 0; i < ntargets; i++) {
1254 addtarget(targets[i], ndeps);
1255 for (j = 0; j < ndeps; j++)
1256 adddep(targets[i], deps[j]);
1257 if (nactions > 0)
1258 addrule(targets[i], acts, nactions);
1259 }
1260
1261 for (i = 0; i < ndeps; i++)
1262 free(deps[i]);
1263 free(deps);
1264
1265 for (i = 0; i < nactions; i++) {
1266 free(acts[i].line);
1267 freeloc(&acts[i].loc);
1268 }
1269 free(acts);
1270}
1271
1272static void
1273assign(char *macros[], int where, int n)
1274{
1275 char *defs;
1276
1277 if (n != 1)
1278 error("invalid macro definition");
1279
1280 skipspaces();
1281 defs = readmacrodef();
1282 setmacro(*macros, defs, where, NOEXPORT);
1283 free(defs);
1284}
1285
1286static void
1287assign_append(char *macros[], int where, int n)
1288{
1289 char *defs, *old, *new;
1290 size_t olen, dlen;
1291
1292 if (n != 1)
1293 error("invalid macro definition");
1294
1295 skipspaces();
1296 defs = readmacrodef();
1297 old = getmacro(*macros);
1298 olen = strlen(old);
1299 dlen = strlen(defs);
1300 /* old + " " + defs + '\0' */
1301 new = emalloc(olen + (olen > 0 ? 1 : 0) + dlen + 1);
1302 memcpy(new, old, olen);
1303 if (olen > 0)
1304 new[olen++] = ' ';
1305 memcpy(new + olen, defs, dlen);
1306 new[olen + dlen] = '\0';
1307 setmacro(*macros, new, where, NOEXPORT);
1308 free(new);
1309 free(defs);
1310}
1311
1312static void
1313assign_shell(char *macros[], int where, int n)
1314{
1315 char *cmd, *out;
1316 FILE *p;
1317 size_t cap, len;
1318 int c;
1319
1320 if (n != 1)
1321 error("invalid macro definition");
1322
1323 skipspaces();
1324 cmd = readmacrodef();
1325 {
1326 char *expanded = expandstring(cmd, NULL, getloc());
1327 free(cmd);
1328 cmd = expanded;
1329 }
1330 p = wpopen(cmd, NULL, "r");
1331 if (!p)
1332 error("popen: %s", strerror(errno));
1333 cap = 64;
1334 out = emalloc(cap);
1335 len = 0;
1336 while ((c = getc(p)) != EOF) {
1337 if (len + 1 >= cap) {
1338 cap *= 2;
1339 out = erealloc(out, cap);
1340 }
1341 if (c == '\n')
1342 break;
1343 out[len++] = c;
1344 }
1345 out[len] = '\0';
1346 wpclose(p);
1347 setmacro(*macros, out, where, NOEXPORT);
1348 free(out);
1349 free(cmd);
1350}
1351
1352void
1353parseinput(int where)
1354{
1355 int i, n;
1356 char **targets;
1357
1358 while (moreinput()) {
1359 n = 0;
1360 targets = NULL;
1361
1362 next();
1363 if (tok == '\n')
1364 continue;
1365
1366 while (tok == ITEM) {
1367 n++;
1368 targets = erealloc(targets, n * sizeof(char *));
1369 targets[n - 1] = estrdup(token);
1370 next();
1371 }
1372
1373 switch (tok) {
1374 case ':':
1375 rule(targets, n);
1376 break;
1377 case '=':
1378 assign(targets, where, n);
1379 break;
1380 case '+':
1381 assign_append(targets, where, n);
1382 break;
1383 case '!':
1384 assign_shell(targets, where, n);
1385 break;
1386 default:
1387 error("unexpected token '%s'(%d)", token, tok);
1388 }
1389
1390 for (i = 0; i < n; i++)
1391 free(targets[i]);
1392 free(targets);
1393 }
1394}
1395
1396int
1397parse(char *fname)
1398{
1399 FILE *fp;
1400
1401 if (!fname) {
1402 fp = stdin;
1403 fname = "<stdin>";
1404 } else if ((fp = fopen(fname, "r")) == NULL) {
1405 return 0;
1406 }
1407
1408 debug("parsing %s", fname);
1409 push(FTFILE, fp, fname, 0);
1410 parseinput(MAKEFILE);
1411
1412 return 1;
1413}
1414
1415void
1416inject(char *s)
1417{
1418 push(FTFILE, NULL, "<internal>", 0);
1419 push(FTEXPAN, s);
1420 parseinput(INTERNAL);
1421}