parse.c revision 1.687 1 /* $NetBSD: parse.c,v 1.687 2022/09/24 16:13:48 rillig Exp $ */
2
3 /*
4 * Copyright (c) 1988, 1989, 1990, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Adam de Boor.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 /*
36 * Copyright (c) 1989 by Berkeley Softworks
37 * All rights reserved.
38 *
39 * This code is derived from software contributed to Berkeley by
40 * Adam de Boor.
41 *
42 * Redistribution and use in source and binary forms, with or without
43 * modification, are permitted provided that the following conditions
44 * are met:
45 * 1. Redistributions of source code must retain the above copyright
46 * notice, this list of conditions and the following disclaimer.
47 * 2. Redistributions in binary form must reproduce the above copyright
48 * notice, this list of conditions and the following disclaimer in the
49 * documentation and/or other materials provided with the distribution.
50 * 3. All advertising materials mentioning features or use of this software
51 * must display the following acknowledgement:
52 * This product includes software developed by the University of
53 * California, Berkeley and its contributors.
54 * 4. Neither the name of the University nor the names of its contributors
55 * may be used to endorse or promote products derived from this software
56 * without specific prior written permission.
57 *
58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
68 * SUCH DAMAGE.
69 */
70
71 /*
72 * Parsing of makefiles.
73 *
74 * Parse_File is the main entry point and controls most of the other
75 * functions in this module.
76 *
77 * Interface:
78 * Parse_Init Initialize the module
79 *
80 * Parse_End Clean up the module
81 *
82 * Parse_File Parse a top-level makefile. Included files are
83 * handled by IncludeFile instead.
84 *
85 * Parse_VarAssign
86 * Try to parse the given line as a variable assignment.
87 * Used by MainParseArgs to determine if an argument is
88 * a target or a variable assignment. Used internally
89 * for pretty much the same thing.
90 *
91 * Parse_Error Report a parse error, a warning or an informational
92 * message.
93 *
94 * Parse_MainName Returns a list of the single main target to create.
95 */
96
97 #include <sys/types.h>
98 #include <sys/stat.h>
99 #include <errno.h>
100 #include <stdarg.h>
101
102 #include "make.h"
103 #include "dir.h"
104 #include "job.h"
105 #include "pathnames.h"
106
107 /* "@(#)parse.c 8.3 (Berkeley) 3/19/94" */
108 MAKE_RCSID("$NetBSD: parse.c,v 1.687 2022/09/24 16:13:48 rillig Exp $");
109
110 /*
111 * A file being read.
112 */
113 typedef struct IncludedFile {
114 FStr name; /* absolute or relative to the cwd */
115 unsigned lineno; /* 1-based */
116 unsigned readLines; /* the number of physical lines that have
117 * been read from the file */
118 unsigned forHeadLineno; /* 1-based */
119 unsigned forBodyReadLines; /* the number of physical lines that have
120 * been read from the file above the body of
121 * the .for loop */
122 unsigned int condMinDepth; /* depth of nested 'if' directives, at the
123 * beginning of the file */
124 bool depending; /* state of doing_depend on EOF */
125
126 Buffer buf; /* the file's content or the body of the .for
127 * loop; either empty or ends with '\n' */
128 char *buf_ptr; /* next char to be read */
129 char *buf_end; /* buf_end[-1] == '\n' */
130
131 struct ForLoop *forLoop;
132 } IncludedFile;
133
134 /* Special attributes for target nodes. */
135 typedef enum ParseSpecial {
136 SP_ATTRIBUTE, /* Generic attribute */
137 SP_BEGIN, /* .BEGIN */
138 SP_DEFAULT, /* .DEFAULT */
139 SP_DELETE_ON_ERROR, /* .DELETE_ON_ERROR */
140 SP_END, /* .END */
141 SP_ERROR, /* .ERROR */
142 SP_IGNORE, /* .IGNORE */
143 SP_INCLUDES, /* .INCLUDES; not mentioned in the manual page */
144 SP_INTERRUPT, /* .INTERRUPT */
145 SP_LIBS, /* .LIBS; not mentioned in the manual page */
146 SP_MAIN, /* .MAIN and no user-specified targets to make */
147 SP_META, /* .META */
148 SP_MFLAGS, /* .MFLAGS or .MAKEFLAGS */
149 SP_NOMETA, /* .NOMETA */
150 SP_NOMETA_CMP, /* .NOMETA_CMP */
151 SP_NOPATH, /* .NOPATH */
152 SP_NOT, /* Not special */
153 SP_NOTPARALLEL, /* .NOTPARALLEL or .NO_PARALLEL */
154 SP_NULL, /* .NULL; not mentioned in the manual page */
155 SP_OBJDIR, /* .OBJDIR */
156 SP_ORDER, /* .ORDER */
157 SP_PARALLEL, /* .PARALLEL; not mentioned in the manual page */
158 SP_PATH, /* .PATH or .PATH.suffix */
159 SP_PHONY, /* .PHONY */
160 #ifdef POSIX
161 SP_POSIX, /* .POSIX; not mentioned in the manual page */
162 #endif
163 SP_PRECIOUS, /* .PRECIOUS */
164 SP_SHELL, /* .SHELL */
165 SP_SILENT, /* .SILENT */
166 SP_SINGLESHELL, /* .SINGLESHELL; not mentioned in the manual page */
167 SP_STALE, /* .STALE */
168 SP_SUFFIXES, /* .SUFFIXES */
169 SP_WAIT /* .WAIT */
170 } ParseSpecial;
171
172 typedef List SearchPathList;
173 typedef ListNode SearchPathListNode;
174
175
176 typedef enum VarAssignOp {
177 VAR_NORMAL, /* = */
178 VAR_APPEND, /* += */
179 VAR_DEFAULT, /* ?= */
180 VAR_SUBST, /* := */
181 VAR_SHELL /* != or :sh= */
182 } VarAssignOp;
183
184 typedef struct VarAssign {
185 char *varname; /* unexpanded */
186 VarAssignOp op;
187 const char *value; /* unexpanded */
188 } VarAssign;
189
190 static bool Parse_IsVar(const char *, VarAssign *);
191 static void Parse_Var(VarAssign *, GNode *);
192
193 /*
194 * The target to be made if no targets are specified in the command line.
195 * This is the first target defined in any of the makefiles.
196 */
197 GNode *mainNode;
198
199 /*
200 * During parsing, the targets from the left-hand side of the currently
201 * active dependency line, or NULL if the current line does not belong to a
202 * dependency line, for example because it is a variable assignment.
203 *
204 * See unit-tests/deptgt.mk, keyword "parse.c:targets".
205 */
206 static GNodeList *targets;
207
208 #ifdef CLEANUP
209 /*
210 * All shell commands for all targets, in no particular order and possibly
211 * with duplicates. Kept in a separate list since the commands from .USE or
212 * .USEBEFORE nodes are shared with other GNodes, thereby giving up the
213 * easily understandable ownership over the allocated strings.
214 */
215 static StringList targCmds = LST_INIT;
216 #endif
217
218 /*
219 * Predecessor node for handling .ORDER. Initialized to NULL when .ORDER
220 * is seen, then set to each successive source on the line.
221 */
222 static GNode *order_pred;
223
224 static int parseErrors = 0;
225
226 /*
227 * The include chain of makefiles. At index 0 is the top-level makefile from
228 * the command line, followed by the included files or .for loops, up to and
229 * including the current file.
230 *
231 * See PrintStackTrace for how to interpret the data.
232 */
233 static Vector /* of IncludedFile */ includes;
234
235 SearchPath *parseIncPath; /* directories for "..." includes */
236 SearchPath *sysIncPath; /* directories for <...> includes */
237 SearchPath *defSysIncPath; /* default for sysIncPath */
238
239 /*
240 * The parseKeywords table is searched using binary search when deciding
241 * if a target or source is special. The 'spec' field is the ParseSpecial
242 * type of the keyword (SP_NOT if the keyword isn't special as a target) while
243 * the 'op' field is the operator to apply to the list of targets if the
244 * keyword is used as a source ("0" if the keyword isn't special as a source)
245 */
246 static const struct {
247 const char name[17];
248 ParseSpecial special; /* when used as a target */
249 GNodeType targetAttr; /* when used as a source */
250 } parseKeywords[] = {
251 { ".BEGIN", SP_BEGIN, OP_NONE },
252 { ".DEFAULT", SP_DEFAULT, OP_NONE },
253 { ".DELETE_ON_ERROR", SP_DELETE_ON_ERROR, OP_NONE },
254 { ".END", SP_END, OP_NONE },
255 { ".ERROR", SP_ERROR, OP_NONE },
256 { ".EXEC", SP_ATTRIBUTE, OP_EXEC },
257 { ".IGNORE", SP_IGNORE, OP_IGNORE },
258 { ".INCLUDES", SP_INCLUDES, OP_NONE },
259 { ".INTERRUPT", SP_INTERRUPT, OP_NONE },
260 { ".INVISIBLE", SP_ATTRIBUTE, OP_INVISIBLE },
261 { ".JOIN", SP_ATTRIBUTE, OP_JOIN },
262 { ".LIBS", SP_LIBS, OP_NONE },
263 { ".MADE", SP_ATTRIBUTE, OP_MADE },
264 { ".MAIN", SP_MAIN, OP_NONE },
265 { ".MAKE", SP_ATTRIBUTE, OP_MAKE },
266 { ".MAKEFLAGS", SP_MFLAGS, OP_NONE },
267 { ".META", SP_META, OP_META },
268 { ".MFLAGS", SP_MFLAGS, OP_NONE },
269 { ".NOMETA", SP_NOMETA, OP_NOMETA },
270 { ".NOMETA_CMP", SP_NOMETA_CMP, OP_NOMETA_CMP },
271 { ".NOPATH", SP_NOPATH, OP_NOPATH },
272 { ".NOTMAIN", SP_ATTRIBUTE, OP_NOTMAIN },
273 { ".NOTPARALLEL", SP_NOTPARALLEL, OP_NONE },
274 { ".NO_PARALLEL", SP_NOTPARALLEL, OP_NONE },
275 { ".NULL", SP_NULL, OP_NONE },
276 { ".OBJDIR", SP_OBJDIR, OP_NONE },
277 { ".OPTIONAL", SP_ATTRIBUTE, OP_OPTIONAL },
278 { ".ORDER", SP_ORDER, OP_NONE },
279 { ".PARALLEL", SP_PARALLEL, OP_NONE },
280 { ".PATH", SP_PATH, OP_NONE },
281 { ".PHONY", SP_PHONY, OP_PHONY },
282 #ifdef POSIX
283 { ".POSIX", SP_POSIX, OP_NONE },
284 #endif
285 { ".PRECIOUS", SP_PRECIOUS, OP_PRECIOUS },
286 { ".RECURSIVE", SP_ATTRIBUTE, OP_MAKE },
287 { ".SHELL", SP_SHELL, OP_NONE },
288 { ".SILENT", SP_SILENT, OP_SILENT },
289 { ".SINGLESHELL", SP_SINGLESHELL, OP_NONE },
290 { ".STALE", SP_STALE, OP_NONE },
291 { ".SUFFIXES", SP_SUFFIXES, OP_NONE },
292 { ".USE", SP_ATTRIBUTE, OP_USE },
293 { ".USEBEFORE", SP_ATTRIBUTE, OP_USEBEFORE },
294 { ".WAIT", SP_WAIT, OP_NONE },
295 };
296
297 enum PosixState posix_state = PS_NOT_YET;
298
299 static IncludedFile *
300 GetInclude(size_t i)
301 {
302 assert(i < includes.len);
303 return Vector_Get(&includes, i);
304 }
305
306 /* The file that is currently being read. */
307 static IncludedFile *
308 CurFile(void)
309 {
310 return GetInclude(includes.len - 1);
311 }
312
313 unsigned int
314 CurFile_CondMinDepth(void)
315 {
316 return CurFile()->condMinDepth;
317 }
318
319 static Buffer
320 LoadFile(const char *path, int fd)
321 {
322 ssize_t n;
323 Buffer buf;
324 size_t bufSize;
325 struct stat st;
326
327 bufSize = fstat(fd, &st) == 0 && S_ISREG(st.st_mode) &&
328 st.st_size > 0 && st.st_size < 1024 * 1024 * 1024
329 ? (size_t)st.st_size : 1024;
330 Buf_InitSize(&buf, bufSize);
331
332 for (;;) {
333 if (buf.len == buf.cap) {
334 if (buf.cap >= 512 * 1024 * 1024) {
335 Error("%s: file too large", path);
336 exit(2); /* Not 1 so -q can distinguish error */
337 }
338 Buf_Expand(&buf);
339 }
340 assert(buf.len < buf.cap);
341 n = read(fd, buf.data + buf.len, buf.cap - buf.len);
342 if (n < 0) {
343 Error("%s: read error: %s", path, strerror(errno));
344 exit(2); /* Not 1 so -q can distinguish error */
345 }
346 if (n == 0)
347 break;
348
349 buf.len += (size_t)n;
350 }
351 assert(buf.len <= buf.cap);
352
353 if (!Buf_EndsWith(&buf, '\n'))
354 Buf_AddByte(&buf, '\n');
355
356 return buf; /* may not be null-terminated */
357 }
358
359 /*
360 * Print the current chain of .include and .for directives. In Parse_Fatal
361 * or other functions that already print the location, includingInnermost
362 * would be redundant, but in other cases like Error or Fatal it needs to be
363 * included.
364 */
365 void
366 PrintStackTrace(bool includingInnermost)
367 {
368 const IncludedFile *entries;
369 size_t i, n;
370
371 n = includes.len;
372 if (n == 0)
373 return;
374
375 entries = GetInclude(0);
376 if (!includingInnermost && entries[n - 1].forLoop == NULL)
377 n--; /* already in the diagnostic */
378
379 for (i = n; i-- > 0;) {
380 const IncludedFile *entry = entries + i;
381 const char *fname = entry->name.str;
382 char dirbuf[MAXPATHLEN + 1];
383
384 if (fname[0] != '/' && strcmp(fname, "(stdin)") != 0)
385 fname = realpath(fname, dirbuf);
386
387 if (entry->forLoop != NULL) {
388 char *details = ForLoop_Details(entry->forLoop);
389 debug_printf("\tin .for loop from %s:%u with %s\n",
390 fname, entry->forHeadLineno, details);
391 free(details);
392 } else if (i + 1 < n && entries[i + 1].forLoop != NULL) {
393 /* entry->lineno is not a useful line number */
394 } else
395 debug_printf("\tin %s:%u\n", fname, entry->lineno);
396 }
397 }
398
399 /* Check if the current character is escaped on the current line. */
400 static bool
401 IsEscaped(const char *line, const char *p)
402 {
403 bool escaped = false;
404 while (p > line && *--p == '\\')
405 escaped = !escaped;
406 return escaped;
407 }
408
409 /*
410 * Add the filename and lineno to the GNode so that we remember where it
411 * was first defined.
412 */
413 static void
414 RememberLocation(GNode *gn)
415 {
416 IncludedFile *curFile = CurFile();
417 gn->fname = Str_Intern(curFile->name.str);
418 gn->lineno = curFile->lineno;
419 }
420
421 /*
422 * Look in the table of keywords for one matching the given string.
423 * Return the index of the keyword, or -1 if it isn't there.
424 */
425 static int
426 FindKeyword(const char *str)
427 {
428 int start = 0;
429 int end = sizeof parseKeywords / sizeof parseKeywords[0] - 1;
430
431 while (start <= end) {
432 int curr = start + (end - start) / 2;
433 int diff = strcmp(str, parseKeywords[curr].name);
434
435 if (diff == 0)
436 return curr;
437 if (diff < 0)
438 end = curr - 1;
439 else
440 start = curr + 1;
441 }
442
443 return -1;
444 }
445
446 void
447 PrintLocation(FILE *f, bool useVars, const GNode *gn)
448 {
449 char dirbuf[MAXPATHLEN + 1];
450 FStr dir, base;
451 const char *fname;
452 unsigned lineno;
453
454 if (gn != NULL) {
455 fname = gn->fname;
456 lineno = gn->lineno;
457 } else if (includes.len > 0) {
458 IncludedFile *curFile = CurFile();
459 fname = curFile->name.str;
460 lineno = curFile->lineno;
461 } else
462 return;
463
464 if (!useVars || fname[0] == '/' || strcmp(fname, "(stdin)") == 0) {
465 (void)fprintf(f, "\"%s\" line %u: ", fname, lineno);
466 return;
467 }
468
469 dir = Var_Value(SCOPE_GLOBAL, ".PARSEDIR");
470 if (dir.str == NULL)
471 dir.str = ".";
472 if (dir.str[0] != '/')
473 dir.str = realpath(dir.str, dirbuf);
474
475 base = Var_Value(SCOPE_GLOBAL, ".PARSEFILE");
476 if (base.str == NULL)
477 base.str = str_basename(fname);
478
479 (void)fprintf(f, "\"%s/%s\" line %u: ", dir.str, base.str, lineno);
480
481 FStr_Done(&base);
482 FStr_Done(&dir);
483 }
484
485 static void MAKE_ATTR_PRINTFLIKE(5, 0)
486 ParseVErrorInternal(FILE *f, bool useVars, const GNode *gn,
487 ParseErrorLevel level, const char *fmt, va_list ap)
488 {
489 static bool fatal_warning_error_printed = false;
490
491 (void)fprintf(f, "%s: ", progname);
492
493 PrintLocation(f, useVars, gn);
494 if (level == PARSE_WARNING)
495 (void)fprintf(f, "warning: ");
496 (void)vfprintf(f, fmt, ap);
497 (void)fprintf(f, "\n");
498 (void)fflush(f);
499
500 if (level == PARSE_FATAL)
501 parseErrors++;
502 if (level == PARSE_WARNING && opts.parseWarnFatal) {
503 if (!fatal_warning_error_printed) {
504 Error("parsing warnings being treated as errors");
505 fatal_warning_error_printed = true;
506 }
507 parseErrors++;
508 }
509
510 if (DEBUG(PARSE))
511 PrintStackTrace(false);
512 }
513
514 static void MAKE_ATTR_PRINTFLIKE(3, 4)
515 ParseErrorInternal(const GNode *gn,
516 ParseErrorLevel level, const char *fmt, ...)
517 {
518 va_list ap;
519
520 (void)fflush(stdout);
521 va_start(ap, fmt);
522 ParseVErrorInternal(stderr, false, gn, level, fmt, ap);
523 va_end(ap);
524
525 if (opts.debug_file != stdout && opts.debug_file != stderr) {
526 va_start(ap, fmt);
527 ParseVErrorInternal(opts.debug_file, false, gn,
528 level, fmt, ap);
529 va_end(ap);
530 }
531 }
532
533 /*
534 * Print a parse error message, including location information.
535 *
536 * If the level is PARSE_FATAL, continue parsing until the end of the
537 * current top-level makefile, then exit (see Parse_File).
538 *
539 * Fmt is given without a trailing newline.
540 */
541 void
542 Parse_Error(ParseErrorLevel level, const char *fmt, ...)
543 {
544 va_list ap;
545
546 (void)fflush(stdout);
547 va_start(ap, fmt);
548 ParseVErrorInternal(stderr, true, NULL, level, fmt, ap);
549 va_end(ap);
550
551 if (opts.debug_file != stdout && opts.debug_file != stderr) {
552 va_start(ap, fmt);
553 ParseVErrorInternal(opts.debug_file, true, NULL,
554 level, fmt, ap);
555 va_end(ap);
556 }
557 }
558
559
560 /*
561 * Handle an .info, .warning or .error directive. For an .error directive,
562 * exit immediately.
563 */
564 static void
565 HandleMessage(ParseErrorLevel level, const char *levelName, const char *umsg)
566 {
567 char *xmsg;
568
569 if (umsg[0] == '\0') {
570 Parse_Error(PARSE_FATAL, "Missing argument for \".%s\"",
571 levelName);
572 return;
573 }
574
575 (void)Var_Subst(umsg, SCOPE_CMDLINE, VARE_WANTRES, &xmsg);
576 /* TODO: handle errors */
577
578 Parse_Error(level, "%s", xmsg);
579 free(xmsg);
580
581 if (level == PARSE_FATAL) {
582 PrintOnError(NULL, "\n");
583 exit(1);
584 }
585 }
586
587 /*
588 * Add the child to the parent's children, and for non-special targets, vice
589 * versa. Special targets such as .END do not need to be informed once the
590 * child target has been made.
591 */
592 static void
593 LinkSource(GNode *pgn, GNode *cgn, bool isSpecial)
594 {
595 if ((pgn->type & OP_DOUBLEDEP) && !Lst_IsEmpty(&pgn->cohorts))
596 pgn = pgn->cohorts.last->datum;
597
598 Lst_Append(&pgn->children, cgn);
599 pgn->unmade++;
600
601 /* Special targets like .END don't need any children. */
602 if (!isSpecial)
603 Lst_Append(&cgn->parents, pgn);
604
605 if (DEBUG(PARSE)) {
606 debug_printf("# LinkSource: added child %s - %s\n",
607 pgn->name, cgn->name);
608 Targ_PrintNode(pgn, 0);
609 Targ_PrintNode(cgn, 0);
610 }
611 }
612
613 /* Add the node to each target from the current dependency group. */
614 static void
615 LinkToTargets(GNode *gn, bool isSpecial)
616 {
617 GNodeListNode *ln;
618
619 for (ln = targets->first; ln != NULL; ln = ln->next)
620 LinkSource(ln->datum, gn, isSpecial);
621 }
622
623 static bool
624 TryApplyDependencyOperator(GNode *gn, GNodeType op)
625 {
626 /*
627 * If the node occurred on the left-hand side of a dependency and the
628 * operator also defines a dependency, they must match.
629 */
630 if ((op & OP_OPMASK) && (gn->type & OP_OPMASK) &&
631 ((op & OP_OPMASK) != (gn->type & OP_OPMASK))) {
632 Parse_Error(PARSE_FATAL, "Inconsistent operator for %s",
633 gn->name);
634 return false;
635 }
636
637 if (op == OP_DOUBLEDEP && (gn->type & OP_OPMASK) == OP_DOUBLEDEP) {
638 /*
639 * If the node was of the left-hand side of a '::' operator,
640 * we need to create a new instance of it for the children
641 * and commands on this dependency line since each of these
642 * dependency groups has its own attributes and commands,
643 * separate from the others.
644 *
645 * The new instance is placed on the 'cohorts' list of the
646 * initial one (note the initial one is not on its own
647 * cohorts list) and the new instance is linked to all
648 * parents of the initial instance.
649 */
650 GNode *cohort;
651
652 /*
653 * Propagate copied bits to the initial node. They'll be
654 * propagated back to the rest of the cohorts later.
655 */
656 gn->type |= op & ~OP_OPMASK;
657
658 cohort = Targ_NewInternalNode(gn->name);
659 if (doing_depend)
660 RememberLocation(cohort);
661 /*
662 * Make the cohort invisible as well to avoid duplicating it
663 * into other variables. True, parents of this target won't
664 * tend to do anything with their local variables, but better
665 * safe than sorry.
666 *
667 * (I think this is pointless now, since the relevant list
668 * traversals will no longer see this node anyway. -mycroft)
669 */
670 cohort->type = op | OP_INVISIBLE;
671 Lst_Append(&gn->cohorts, cohort);
672 cohort->centurion = gn;
673 gn->unmade_cohorts++;
674 snprintf(cohort->cohort_num, sizeof cohort->cohort_num, "#%d",
675 (unsigned int)gn->unmade_cohorts % 1000000);
676 } else {
677 /*
678 * We don't want to nuke any previous flags (whatever they
679 * were) so we just OR the new operator into the old.
680 */
681 gn->type |= op;
682 }
683
684 return true;
685 }
686
687 static void
688 ApplyDependencyOperator(GNodeType op)
689 {
690 GNodeListNode *ln;
691
692 for (ln = targets->first; ln != NULL; ln = ln->next)
693 if (!TryApplyDependencyOperator(ln->datum, op))
694 break;
695 }
696
697 /*
698 * We add a .WAIT node in the dependency list. After any dynamic dependencies
699 * (and filename globbing) have happened, it is given a dependency on each
700 * previous child, back until the previous .WAIT node. The next child won't
701 * be scheduled until the .WAIT node is built.
702 *
703 * We give each .WAIT node a unique name (mainly for diagnostics).
704 */
705 static void
706 ApplyDependencySourceWait(bool isSpecial)
707 {
708 static unsigned wait_number = 0;
709 char name[6 + 10 + 1];
710 GNode *gn;
711
712 snprintf(name, sizeof name, ".WAIT_%u", ++wait_number);
713 gn = Targ_NewInternalNode(name);
714 if (doing_depend)
715 RememberLocation(gn);
716 gn->type = OP_WAIT | OP_PHONY | OP_DEPENDS | OP_NOTMAIN;
717 LinkToTargets(gn, isSpecial);
718 }
719
720 static bool
721 ApplyDependencySourceKeyword(const char *src, ParseSpecial special)
722 {
723 int keywd;
724 GNodeType targetAttr;
725
726 if (*src != '.' || !ch_isupper(src[1]))
727 return false;
728
729 keywd = FindKeyword(src);
730 if (keywd == -1)
731 return false;
732
733 targetAttr = parseKeywords[keywd].targetAttr;
734 if (targetAttr != OP_NONE) {
735 ApplyDependencyOperator(targetAttr);
736 return true;
737 }
738 if (parseKeywords[keywd].special == SP_WAIT) {
739 ApplyDependencySourceWait(special != SP_NOT);
740 return true;
741 }
742 return false;
743 }
744
745 /*
746 * In a line like ".MAIN: source1 source2", add all sources to the list of
747 * things to create, but only if the user didn't specify a target on the
748 * command line and .MAIN occurs for the first time.
749 *
750 * See HandleDependencyTargetSpecial, branch SP_MAIN.
751 * See unit-tests/cond-func-make-main.mk.
752 */
753 static void
754 ApplyDependencySourceMain(const char *src)
755 {
756 Lst_Append(&opts.create, bmake_strdup(src));
757 /*
758 * Add the name to the .TARGETS variable as well, so the user can
759 * employ that, if desired.
760 */
761 Global_Append(".TARGETS", src);
762 }
763
764 /*
765 * For the sources of a .ORDER target, create predecessor/successor links
766 * between the previous source and the current one.
767 */
768 static void
769 ApplyDependencySourceOrder(const char *src)
770 {
771 GNode *gn;
772
773 gn = Targ_GetNode(src);
774 if (doing_depend)
775 RememberLocation(gn);
776 if (order_pred != NULL) {
777 Lst_Append(&order_pred->order_succ, gn);
778 Lst_Append(&gn->order_pred, order_pred);
779 if (DEBUG(PARSE)) {
780 debug_printf(
781 "# .ORDER forces '%s' to be made before '%s'\n",
782 order_pred->name, gn->name);
783 Targ_PrintNode(order_pred, 0);
784 Targ_PrintNode(gn, 0);
785 }
786 }
787 /*
788 * The current source now becomes the predecessor for the next one.
789 */
790 order_pred = gn;
791 }
792
793 /* The source is not an attribute, so find/create a node for it. */
794 static void
795 ApplyDependencySourceOther(const char *src, GNodeType targetAttr,
796 ParseSpecial special)
797 {
798 GNode *gn;
799
800 gn = Targ_GetNode(src);
801 if (doing_depend)
802 RememberLocation(gn);
803 if (targetAttr != OP_NONE)
804 gn->type |= targetAttr;
805 else
806 LinkToTargets(gn, special != SP_NOT);
807 }
808
809 /*
810 * Given the name of a source in a dependency line, figure out if it is an
811 * attribute (such as .SILENT) and if so, apply it to all targets. Otherwise
812 * decide if there is some attribute which should be applied *to* the source
813 * because of some special target (such as .PHONY) and apply it if so.
814 * Otherwise, make the source a child of the targets.
815 */
816 static void
817 ApplyDependencySource(GNodeType targetAttr, const char *src,
818 ParseSpecial special)
819 {
820 if (ApplyDependencySourceKeyword(src, special))
821 return;
822
823 if (special == SP_MAIN)
824 ApplyDependencySourceMain(src);
825 else if (special == SP_ORDER)
826 ApplyDependencySourceOrder(src);
827 else
828 ApplyDependencySourceOther(src, targetAttr, special);
829 }
830
831 /*
832 * If we have yet to decide on a main target to make, in the absence of any
833 * user input, we want the first target on the first dependency line that is
834 * actually a real target (i.e. isn't a .USE or .EXEC rule) to be made.
835 */
836 static void
837 MaybeUpdateMainTarget(void)
838 {
839 GNodeListNode *ln;
840
841 if (mainNode != NULL)
842 return;
843
844 for (ln = targets->first; ln != NULL; ln = ln->next) {
845 GNode *gn = ln->datum;
846 if (GNode_IsMainCandidate(gn)) {
847 DEBUG1(MAKE, "Setting main node to \"%s\"\n", gn->name);
848 mainNode = gn;
849 return;
850 }
851 }
852 }
853
854 static void
855 InvalidLineType(const char *line)
856 {
857 if (strncmp(line, "<<<<<<", 6) == 0 ||
858 strncmp(line, ">>>>>>", 6) == 0)
859 Parse_Error(PARSE_FATAL,
860 "Makefile appears to contain unresolved CVS/RCS/??? merge conflicts");
861 else if (line[0] == '.') {
862 const char *dirstart = line + 1;
863 const char *dirend;
864 cpp_skip_whitespace(&dirstart);
865 dirend = dirstart;
866 while (ch_isalnum(*dirend) || *dirend == '-')
867 dirend++;
868 Parse_Error(PARSE_FATAL, "Unknown directive \"%.*s\"",
869 (int)(dirend - dirstart), dirstart);
870 } else
871 Parse_Error(PARSE_FATAL, "Invalid line type");
872 }
873
874 static void
875 ParseDependencyTargetWord(char **pp, const char *lstart)
876 {
877 const char *cp = *pp;
878
879 while (*cp != '\0') {
880 if ((ch_isspace(*cp) || *cp == '!' || *cp == ':' ||
881 *cp == '(') &&
882 !IsEscaped(lstart, cp))
883 break;
884
885 if (*cp == '$') {
886 /*
887 * Must be a dynamic source (would have been expanded
888 * otherwise).
889 *
890 * There should be no errors in this, as they would
891 * have been discovered in the initial Var_Subst and
892 * we wouldn't be here.
893 */
894 FStr val;
895
896 (void)Var_Parse(&cp, SCOPE_CMDLINE,
897 VARE_PARSE_ONLY, &val);
898 FStr_Done(&val);
899 } else
900 cp++;
901 }
902
903 *pp += cp - *pp;
904 }
905
906 /*
907 * Handle special targets like .PATH, .DEFAULT, .BEGIN, .ORDER.
908 *
909 * See the tests deptgt-*.mk.
910 */
911 static void
912 HandleDependencyTargetSpecial(const char *targetName,
913 ParseSpecial *inout_special,
914 SearchPathList **inout_paths)
915 {
916 switch (*inout_special) {
917 case SP_PATH:
918 if (*inout_paths == NULL)
919 *inout_paths = Lst_New();
920 Lst_Append(*inout_paths, &dirSearchPath);
921 break;
922 case SP_MAIN:
923 /*
924 * Allow targets from the command line to override the
925 * .MAIN node.
926 */
927 if (!Lst_IsEmpty(&opts.create))
928 *inout_special = SP_NOT;
929 break;
930 case SP_BEGIN:
931 case SP_END:
932 case SP_STALE:
933 case SP_ERROR:
934 case SP_INTERRUPT: {
935 GNode *gn = Targ_GetNode(targetName);
936 if (doing_depend)
937 RememberLocation(gn);
938 gn->type |= OP_NOTMAIN | OP_SPECIAL;
939 Lst_Append(targets, gn);
940 break;
941 }
942 case SP_DEFAULT: {
943 /*
944 * Need to create a node to hang commands on, but we don't
945 * want it in the graph, nor do we want it to be the Main
946 * Target. We claim the node is a transformation rule to make
947 * life easier later, when we'll use Make_HandleUse to
948 * actually apply the .DEFAULT commands.
949 */
950 GNode *gn = GNode_New(".DEFAULT");
951 gn->type |= OP_NOTMAIN | OP_TRANSFORM;
952 Lst_Append(targets, gn);
953 defaultNode = gn;
954 break;
955 }
956 case SP_DELETE_ON_ERROR:
957 deleteOnError = true;
958 break;
959 case SP_NOTPARALLEL:
960 opts.maxJobs = 1;
961 break;
962 case SP_SINGLESHELL:
963 opts.compatMake = true;
964 break;
965 case SP_ORDER:
966 order_pred = NULL;
967 break;
968 default:
969 break;
970 }
971 }
972
973 static bool
974 HandleDependencyTargetPath(const char *suffixName,
975 SearchPathList **inout_paths)
976 {
977 SearchPath *path;
978
979 path = Suff_GetPath(suffixName);
980 if (path == NULL) {
981 Parse_Error(PARSE_FATAL,
982 "Suffix '%s' not defined (yet)", suffixName);
983 return false;
984 }
985
986 if (*inout_paths == NULL)
987 *inout_paths = Lst_New();
988 Lst_Append(*inout_paths, path);
989
990 return true;
991 }
992
993 /* See if it's a special target and if so set inout_special to match it. */
994 static bool
995 HandleDependencyTarget(const char *targetName,
996 ParseSpecial *inout_special,
997 GNodeType *inout_targetAttr,
998 SearchPathList **inout_paths)
999 {
1000 int keywd;
1001
1002 if (!(targetName[0] == '.' && ch_isupper(targetName[1])))
1003 return true;
1004
1005 /*
1006 * See if the target is a special target that must have it
1007 * or its sources handled specially.
1008 */
1009 keywd = FindKeyword(targetName);
1010 if (keywd != -1) {
1011 if (*inout_special == SP_PATH &&
1012 parseKeywords[keywd].special != SP_PATH) {
1013 Parse_Error(PARSE_FATAL, "Mismatched special targets");
1014 return false;
1015 }
1016
1017 *inout_special = parseKeywords[keywd].special;
1018 *inout_targetAttr = parseKeywords[keywd].targetAttr;
1019
1020 HandleDependencyTargetSpecial(targetName, inout_special,
1021 inout_paths);
1022
1023 } else if (strncmp(targetName, ".PATH", 5) == 0) {
1024 *inout_special = SP_PATH;
1025 if (!HandleDependencyTargetPath(targetName + 5, inout_paths))
1026 return false;
1027 }
1028 return true;
1029 }
1030
1031 static void
1032 HandleSingleDependencyTargetMundane(const char *name)
1033 {
1034 GNode *gn = Suff_IsTransform(name)
1035 ? Suff_AddTransform(name)
1036 : Targ_GetNode(name);
1037 if (doing_depend)
1038 RememberLocation(gn);
1039
1040 Lst_Append(targets, gn);
1041 }
1042
1043 static void
1044 HandleDependencyTargetMundane(const char *targetName)
1045 {
1046 if (Dir_HasWildcards(targetName)) {
1047 StringList targetNames = LST_INIT;
1048
1049 SearchPath *emptyPath = SearchPath_New();
1050 SearchPath_Expand(emptyPath, targetName, &targetNames);
1051 SearchPath_Free(emptyPath);
1052
1053 while (!Lst_IsEmpty(&targetNames)) {
1054 char *targName = Lst_Dequeue(&targetNames);
1055 HandleSingleDependencyTargetMundane(targName);
1056 free(targName);
1057 }
1058 } else
1059 HandleSingleDependencyTargetMundane(targetName);
1060 }
1061
1062 static void
1063 SkipExtraTargets(char **pp, const char *lstart)
1064 {
1065 bool warning = false;
1066 const char *p = *pp;
1067
1068 while (*p != '\0') {
1069 if (!IsEscaped(lstart, p) && (*p == '!' || *p == ':'))
1070 break;
1071 if (IsEscaped(lstart, p) || (*p != ' ' && *p != '\t'))
1072 warning = true;
1073 p++;
1074 }
1075 if (warning)
1076 Parse_Error(PARSE_WARNING, "Extra target ignored");
1077
1078 *pp += p - *pp;
1079 }
1080
1081 static void
1082 CheckSpecialMundaneMixture(ParseSpecial special)
1083 {
1084 switch (special) {
1085 case SP_DEFAULT:
1086 case SP_STALE:
1087 case SP_BEGIN:
1088 case SP_END:
1089 case SP_ERROR:
1090 case SP_INTERRUPT:
1091 /*
1092 * These create nodes on which to hang commands, so targets
1093 * shouldn't be empty.
1094 */
1095 case SP_NOT:
1096 /* Nothing special here -- targets may be empty. */
1097 break;
1098 default:
1099 Parse_Error(PARSE_WARNING,
1100 "Special and mundane targets don't mix. "
1101 "Mundane ones ignored");
1102 break;
1103 }
1104 }
1105
1106 /*
1107 * In a dependency line like 'targets: sources' or 'targets! sources', parse
1108 * the operator ':', '::' or '!' from between the targets and the sources.
1109 */
1110 static GNodeType
1111 ParseDependencyOp(char **pp)
1112 {
1113 if (**pp == '!')
1114 return (*pp)++, OP_FORCE;
1115 if (**pp == ':' && (*pp)[1] == ':')
1116 return *pp += 2, OP_DOUBLEDEP;
1117 else if (**pp == ':')
1118 return (*pp)++, OP_DEPENDS;
1119 else
1120 return OP_NONE;
1121 }
1122
1123 static void
1124 ClearPaths(SearchPathList *paths)
1125 {
1126 if (paths != NULL) {
1127 SearchPathListNode *ln;
1128 for (ln = paths->first; ln != NULL; ln = ln->next)
1129 SearchPath_Clear(ln->datum);
1130 }
1131
1132 Dir_SetPATH();
1133 }
1134
1135 static char *
1136 FindInDirOfIncludingFile(const char *file)
1137 {
1138 char *fullname, *incdir, *slash, *newName;
1139 int i;
1140
1141 fullname = NULL;
1142 incdir = bmake_strdup(CurFile()->name.str);
1143 slash = strrchr(incdir, '/');
1144 if (slash != NULL) {
1145 *slash = '\0';
1146 /*
1147 * Now do lexical processing of leading "../" on the
1148 * filename.
1149 */
1150 for (i = 0; strncmp(file + i, "../", 3) == 0; i += 3) {
1151 slash = strrchr(incdir + 1, '/');
1152 if (slash == NULL || strcmp(slash, "/..") == 0)
1153 break;
1154 *slash = '\0';
1155 }
1156 newName = str_concat3(incdir, "/", file + i);
1157 fullname = Dir_FindFile(newName, parseIncPath);
1158 if (fullname == NULL)
1159 fullname = Dir_FindFile(newName, &dirSearchPath);
1160 free(newName);
1161 }
1162 free(incdir);
1163 return fullname;
1164 }
1165
1166 static char *
1167 FindInQuotPath(const char *file)
1168 {
1169 const char *suff;
1170 SearchPath *suffPath;
1171 char *fullname;
1172
1173 fullname = FindInDirOfIncludingFile(file);
1174 if (fullname == NULL &&
1175 (suff = strrchr(file, '.')) != NULL &&
1176 (suffPath = Suff_GetPath(suff)) != NULL)
1177 fullname = Dir_FindFile(file, suffPath);
1178 if (fullname == NULL)
1179 fullname = Dir_FindFile(file, parseIncPath);
1180 if (fullname == NULL)
1181 fullname = Dir_FindFile(file, &dirSearchPath);
1182 return fullname;
1183 }
1184
1185 /*
1186 * Handle one of the .[-ds]include directives by remembering the current file
1187 * and pushing the included file on the stack. After the included file has
1188 * finished, parsing continues with the including file; see Parse_PushInput
1189 * and ParseEOF.
1190 *
1191 * System includes are looked up in sysIncPath, any other includes are looked
1192 * up in the parsedir and then in the directories specified by the -I command
1193 * line options.
1194 */
1195 static void
1196 IncludeFile(const char *file, bool isSystem, bool depinc, bool silent)
1197 {
1198 Buffer buf;
1199 char *fullname; /* full pathname of file */
1200 int fd;
1201
1202 fullname = file[0] == '/' ? bmake_strdup(file) : NULL;
1203
1204 if (fullname == NULL && !isSystem)
1205 fullname = FindInQuotPath(file);
1206
1207 if (fullname == NULL) {
1208 SearchPath *path = Lst_IsEmpty(&sysIncPath->dirs)
1209 ? defSysIncPath : sysIncPath;
1210 fullname = Dir_FindFile(file, path);
1211 }
1212
1213 if (fullname == NULL) {
1214 if (!silent)
1215 Parse_Error(PARSE_FATAL, "Could not find %s", file);
1216 return;
1217 }
1218
1219 if ((fd = open(fullname, O_RDONLY)) == -1) {
1220 if (!silent)
1221 Parse_Error(PARSE_FATAL, "Cannot open %s", fullname);
1222 free(fullname);
1223 return;
1224 }
1225
1226 buf = LoadFile(fullname, fd);
1227 (void)close(fd);
1228
1229 Parse_PushInput(fullname, 1, 0, buf, NULL);
1230 if (depinc)
1231 doing_depend = depinc; /* only turn it on */
1232 free(fullname);
1233 }
1234
1235 /* Handle a "dependency" line like '.SPECIAL:' without any sources. */
1236 static void
1237 HandleDependencySourcesEmpty(ParseSpecial special, SearchPathList *paths)
1238 {
1239 switch (special) {
1240 case SP_SUFFIXES:
1241 Suff_ClearSuffixes();
1242 break;
1243 case SP_PRECIOUS:
1244 allPrecious = true;
1245 break;
1246 case SP_IGNORE:
1247 opts.ignoreErrors = true;
1248 break;
1249 case SP_SILENT:
1250 opts.silent = true;
1251 break;
1252 case SP_PATH:
1253 ClearPaths(paths);
1254 break;
1255 #ifdef POSIX
1256 case SP_POSIX:
1257 if (posix_state == PS_NOW_OR_NEVER) {
1258 /*
1259 * With '-r', 'posix.mk' (if it exists)
1260 * can effectively substitute for 'sys.mk',
1261 * otherwise it is an extension.
1262 */
1263 Global_Set("%POSIX", "1003.2");
1264 IncludeFile("posix.mk", true, false, true);
1265 }
1266 break;
1267 #endif
1268 default:
1269 break;
1270 }
1271 }
1272
1273 static void
1274 AddToPaths(const char *dir, SearchPathList *paths)
1275 {
1276 if (paths != NULL) {
1277 SearchPathListNode *ln;
1278 for (ln = paths->first; ln != NULL; ln = ln->next)
1279 (void)SearchPath_Add(ln->datum, dir);
1280 }
1281 }
1282
1283 /*
1284 * If the target was one that doesn't take files as its sources but takes
1285 * something like suffixes, we take each space-separated word on the line as
1286 * a something and deal with it accordingly.
1287 */
1288 static void
1289 ParseDependencySourceSpecial(ParseSpecial special, const char *word,
1290 SearchPathList *paths)
1291 {
1292 switch (special) {
1293 case SP_SUFFIXES:
1294 Suff_AddSuffix(word);
1295 break;
1296 case SP_PATH:
1297 AddToPaths(word, paths);
1298 break;
1299 case SP_INCLUDES:
1300 Suff_AddInclude(word);
1301 break;
1302 case SP_LIBS:
1303 Suff_AddLib(word);
1304 break;
1305 case SP_NULL:
1306 Suff_SetNull(word);
1307 break;
1308 case SP_OBJDIR:
1309 Main_SetObjdir(false, "%s", word);
1310 break;
1311 default:
1312 break;
1313 }
1314 }
1315
1316 static bool
1317 ApplyDependencyTarget(char *name, char *nameEnd, ParseSpecial *inout_special,
1318 GNodeType *inout_targetAttr,
1319 SearchPathList **inout_paths)
1320 {
1321 char savec = *nameEnd;
1322 *nameEnd = '\0';
1323
1324 if (!HandleDependencyTarget(name, inout_special,
1325 inout_targetAttr, inout_paths))
1326 return false;
1327
1328 if (*inout_special == SP_NOT && *name != '\0')
1329 HandleDependencyTargetMundane(name);
1330 else if (*inout_special == SP_PATH && *name != '.' && *name != '\0')
1331 Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", name);
1332
1333 *nameEnd = savec;
1334 return true;
1335 }
1336
1337 static bool
1338 ParseDependencyTargets(char **inout_cp,
1339 const char *lstart,
1340 ParseSpecial *inout_special,
1341 GNodeType *inout_targetAttr,
1342 SearchPathList **inout_paths)
1343 {
1344 char *cp = *inout_cp;
1345
1346 for (;;) {
1347 char *tgt = cp;
1348
1349 ParseDependencyTargetWord(&cp, lstart);
1350
1351 /*
1352 * If the word is followed by a left parenthesis, it's the
1353 * name of one or more files inside an archive.
1354 */
1355 if (!IsEscaped(lstart, cp) && *cp == '(') {
1356 cp = tgt;
1357 if (!Arch_ParseArchive(&cp, targets, SCOPE_CMDLINE)) {
1358 Parse_Error(PARSE_FATAL,
1359 "Error in archive specification: \"%s\"",
1360 tgt);
1361 return false;
1362 }
1363 continue;
1364 }
1365
1366 if (*cp == '\0') {
1367 InvalidLineType(lstart);
1368 return false;
1369 }
1370
1371 if (!ApplyDependencyTarget(tgt, cp, inout_special,
1372 inout_targetAttr, inout_paths))
1373 return false;
1374
1375 if (*inout_special != SP_NOT && *inout_special != SP_PATH)
1376 SkipExtraTargets(&cp, lstart);
1377 else
1378 pp_skip_whitespace(&cp);
1379
1380 if (*cp == '\0')
1381 break;
1382 if ((*cp == '!' || *cp == ':') && !IsEscaped(lstart, cp))
1383 break;
1384 }
1385
1386 *inout_cp = cp;
1387 return true;
1388 }
1389
1390 static void
1391 ParseDependencySourcesSpecial(char *start,
1392 ParseSpecial special, SearchPathList *paths)
1393 {
1394 char savec;
1395
1396 while (*start != '\0') {
1397 char *end = start;
1398 while (*end != '\0' && !ch_isspace(*end))
1399 end++;
1400 savec = *end;
1401 *end = '\0';
1402 ParseDependencySourceSpecial(special, start, paths);
1403 *end = savec;
1404 if (savec != '\0')
1405 end++;
1406 pp_skip_whitespace(&end);
1407 start = end;
1408 }
1409 }
1410
1411 static void
1412 LinkVarToTargets(VarAssign *var)
1413 {
1414 GNodeListNode *ln;
1415
1416 for (ln = targets->first; ln != NULL; ln = ln->next)
1417 Parse_Var(var, ln->datum);
1418 }
1419
1420 static bool
1421 ParseDependencySourcesMundane(char *start,
1422 ParseSpecial special, GNodeType targetAttr)
1423 {
1424 while (*start != '\0') {
1425 char *end = start;
1426 VarAssign var;
1427
1428 /*
1429 * Check for local variable assignment,
1430 * rest of the line is the value.
1431 */
1432 if (Parse_IsVar(start, &var)) {
1433 /*
1434 * Check if this makefile has disabled
1435 * setting local variables.
1436 */
1437 bool target_vars = GetBooleanExpr(
1438 "${.MAKE.TARGET_LOCAL_VARIABLES}", true);
1439
1440 if (target_vars)
1441 LinkVarToTargets(&var);
1442 free(var.varname);
1443 if (target_vars)
1444 return true;
1445 }
1446
1447 /*
1448 * The targets take real sources, so we must beware of archive
1449 * specifications (i.e. things with left parentheses in them)
1450 * and handle them accordingly.
1451 */
1452 for (; *end != '\0' && !ch_isspace(*end); end++) {
1453 if (*end == '(' && end > start && end[-1] != '$') {
1454 /*
1455 * Only stop for a left parenthesis if it
1456 * isn't at the start of a word (that'll be
1457 * for variable changes later) and isn't
1458 * preceded by a dollar sign (a dynamic
1459 * source).
1460 */
1461 break;
1462 }
1463 }
1464
1465 if (*end == '(') {
1466 GNodeList sources = LST_INIT;
1467 if (!Arch_ParseArchive(&start, &sources,
1468 SCOPE_CMDLINE)) {
1469 Parse_Error(PARSE_FATAL,
1470 "Error in source archive spec \"%s\"",
1471 start);
1472 return false;
1473 }
1474
1475 while (!Lst_IsEmpty(&sources)) {
1476 GNode *gn = Lst_Dequeue(&sources);
1477 ApplyDependencySource(targetAttr, gn->name,
1478 special);
1479 }
1480 Lst_Done(&sources);
1481 end = start;
1482 } else {
1483 if (*end != '\0') {
1484 *end = '\0';
1485 end++;
1486 }
1487
1488 ApplyDependencySource(targetAttr, start, special);
1489 }
1490 pp_skip_whitespace(&end);
1491 start = end;
1492 }
1493 return true;
1494 }
1495
1496 /*
1497 * From a dependency line like 'targets: sources', parse the sources.
1498 *
1499 * See the tests depsrc-*.mk.
1500 */
1501 static void
1502 ParseDependencySources(char *p, GNodeType targetAttr,
1503 ParseSpecial special, SearchPathList **inout_paths)
1504 {
1505 if (*p == '\0') {
1506 HandleDependencySourcesEmpty(special, *inout_paths);
1507 } else if (special == SP_MFLAGS) {
1508 Main_ParseArgLine(p);
1509 return;
1510 } else if (special == SP_SHELL) {
1511 if (!Job_ParseShell(p)) {
1512 Parse_Error(PARSE_FATAL,
1513 "improper shell specification");
1514 return;
1515 }
1516 return;
1517 } else if (special == SP_NOTPARALLEL || special == SP_SINGLESHELL ||
1518 special == SP_DELETE_ON_ERROR) {
1519 return;
1520 }
1521
1522 /* Now go for the sources. */
1523 if (special == SP_SUFFIXES || special == SP_PATH ||
1524 special == SP_INCLUDES || special == SP_LIBS ||
1525 special == SP_NULL || special == SP_OBJDIR) {
1526 ParseDependencySourcesSpecial(p, special, *inout_paths);
1527 if (*inout_paths != NULL) {
1528 Lst_Free(*inout_paths);
1529 *inout_paths = NULL;
1530 }
1531 if (special == SP_PATH)
1532 Dir_SetPATH();
1533 } else {
1534 assert(*inout_paths == NULL);
1535 if (!ParseDependencySourcesMundane(p, special, targetAttr))
1536 return;
1537 }
1538
1539 MaybeUpdateMainTarget();
1540 }
1541
1542 /*
1543 * Parse a dependency line consisting of targets, followed by a dependency
1544 * operator, optionally followed by sources.
1545 *
1546 * The nodes of the sources are linked as children to the nodes of the
1547 * targets. Nodes are created as necessary.
1548 *
1549 * The operator is applied to each node in the global 'targets' list,
1550 * which is where the nodes found for the targets are kept.
1551 *
1552 * The sources are parsed in much the same way as the targets, except
1553 * that they are expanded using the wildcarding scheme of the C-Shell,
1554 * and a target is created for each expanded word. Each of the resulting
1555 * nodes is then linked to each of the targets as one of its children.
1556 *
1557 * Certain targets and sources such as .PHONY or .PRECIOUS are handled
1558 * specially, see ParseSpecial.
1559 *
1560 * Transformation rules such as '.c.o' are also handled here, see
1561 * Suff_AddTransform.
1562 *
1563 * Upon return, the value of the line is unspecified.
1564 */
1565 static void
1566 ParseDependency(char *line)
1567 {
1568 char *p;
1569 SearchPathList *paths; /* search paths to alter when parsing a list
1570 * of .PATH targets */
1571 GNodeType targetAttr; /* from special sources */
1572 ParseSpecial special; /* in special targets, the children are
1573 * linked as children of the parent but not
1574 * vice versa */
1575 GNodeType op;
1576
1577 DEBUG1(PARSE, "ParseDependency(%s)\n", line);
1578 p = line;
1579 paths = NULL;
1580 targetAttr = OP_NONE;
1581 special = SP_NOT;
1582
1583 if (!ParseDependencyTargets(&p, line, &special, &targetAttr, &paths))
1584 goto out;
1585
1586 if (!Lst_IsEmpty(targets))
1587 CheckSpecialMundaneMixture(special);
1588
1589 op = ParseDependencyOp(&p);
1590 if (op == OP_NONE) {
1591 InvalidLineType(line);
1592 goto out;
1593 }
1594 ApplyDependencyOperator(op);
1595
1596 pp_skip_whitespace(&p);
1597
1598 ParseDependencySources(p, targetAttr, special, &paths);
1599
1600 out:
1601 if (paths != NULL)
1602 Lst_Free(paths);
1603 }
1604
1605 /*
1606 * Determine the assignment operator and adjust the end of the variable
1607 * name accordingly.
1608 */
1609 static VarAssign
1610 AdjustVarassignOp(const char *name, const char *nameEnd, const char *op,
1611 const char *value)
1612 {
1613 VarAssignOp type;
1614 VarAssign va;
1615
1616 if (op > name && op[-1] == '+') {
1617 op--;
1618 type = VAR_APPEND;
1619
1620 } else if (op > name && op[-1] == '?') {
1621 op--;
1622 type = VAR_DEFAULT;
1623
1624 } else if (op > name && op[-1] == ':') {
1625 op--;
1626 type = VAR_SUBST;
1627
1628 } else if (op > name && op[-1] == '!') {
1629 op--;
1630 type = VAR_SHELL;
1631
1632 } else {
1633 type = VAR_NORMAL;
1634 #ifdef SUNSHCMD
1635 while (op > name && ch_isspace(op[-1]))
1636 op--;
1637
1638 if (op - name >= 3 && memcmp(op - 3, ":sh", 3) == 0) {
1639 op -= 3;
1640 type = VAR_SHELL;
1641 }
1642 #endif
1643 }
1644
1645 va.varname = bmake_strsedup(name, nameEnd < op ? nameEnd : op);
1646 va.op = type;
1647 va.value = value;
1648 return va;
1649 }
1650
1651 /*
1652 * Parse a variable assignment, consisting of a single-word variable name,
1653 * optional whitespace, an assignment operator, optional whitespace and the
1654 * variable value.
1655 *
1656 * Note: There is a lexical ambiguity with assignment modifier characters
1657 * in variable names. This routine interprets the character before the =
1658 * as a modifier. Therefore, an assignment like
1659 * C++=/usr/bin/CC
1660 * is interpreted as "C+ +=" instead of "C++ =".
1661 *
1662 * Used for both lines in a file and command line arguments.
1663 */
1664 static bool
1665 Parse_IsVar(const char *p, VarAssign *out_var)
1666 {
1667 const char *nameStart, *nameEnd, *firstSpace, *eq;
1668 int level = 0;
1669
1670 cpp_skip_hspace(&p); /* Skip to variable name */
1671
1672 /*
1673 * During parsing, the '+' of the operator '+=' is initially parsed
1674 * as part of the variable name. It is later corrected, as is the
1675 * ':sh' modifier. Of these two (nameEnd and eq), the earlier one
1676 * determines the actual end of the variable name.
1677 */
1678
1679 nameStart = p;
1680 firstSpace = NULL;
1681
1682 /*
1683 * Scan for one of the assignment operators outside a variable
1684 * expansion.
1685 */
1686 while (*p != '\0') {
1687 char ch = *p++;
1688 if (ch == '(' || ch == '{') {
1689 level++;
1690 continue;
1691 }
1692 if (ch == ')' || ch == '}') {
1693 level--;
1694 continue;
1695 }
1696
1697 if (level != 0)
1698 continue;
1699
1700 if ((ch == ' ' || ch == '\t') && firstSpace == NULL)
1701 firstSpace = p - 1;
1702 while (ch == ' ' || ch == '\t')
1703 ch = *p++;
1704
1705 if (ch == '\0')
1706 return false;
1707 #ifdef SUNSHCMD
1708 if (ch == ':' && p[0] == 's' && p[1] == 'h') {
1709 p += 2;
1710 continue;
1711 }
1712 #endif
1713 if (ch == '=')
1714 eq = p - 1;
1715 else if (*p == '=' &&
1716 (ch == '+' || ch == ':' || ch == '?' || ch == '!'))
1717 eq = p;
1718 else if (firstSpace != NULL)
1719 return false;
1720 else
1721 continue;
1722
1723 nameEnd = firstSpace != NULL ? firstSpace : eq;
1724 p = eq + 1;
1725 cpp_skip_whitespace(&p);
1726 *out_var = AdjustVarassignOp(nameStart, nameEnd, eq, p);
1727 return true;
1728 }
1729
1730 return false;
1731 }
1732
1733 /*
1734 * Check for syntax errors such as unclosed expressions or unknown modifiers.
1735 */
1736 static void
1737 VarCheckSyntax(VarAssignOp type, const char *uvalue, GNode *scope)
1738 {
1739 if (opts.strict) {
1740 if (type != VAR_SUBST && strchr(uvalue, '$') != NULL) {
1741 char *expandedValue;
1742
1743 (void)Var_Subst(uvalue, scope, VARE_PARSE_ONLY,
1744 &expandedValue);
1745 /* TODO: handle errors */
1746 free(expandedValue);
1747 }
1748 }
1749 }
1750
1751 /* Perform a variable assignment that uses the operator ':='. */
1752 static void
1753 VarAssign_EvalSubst(GNode *scope, const char *name, const char *uvalue,
1754 FStr *out_avalue)
1755 {
1756 char *evalue;
1757
1758 /*
1759 * make sure that we set the variable the first time to nothing
1760 * so that it gets substituted.
1761 *
1762 * TODO: Add a test that demonstrates why this code is needed,
1763 * apart from making the debug log longer.
1764 *
1765 * XXX: The variable name is expanded up to 3 times.
1766 */
1767 if (!Var_ExistsExpand(scope, name))
1768 Var_SetExpand(scope, name, "");
1769
1770 (void)Var_Subst(uvalue, scope, VARE_KEEP_DOLLAR_UNDEF, &evalue);
1771 /* TODO: handle errors */
1772
1773 Var_SetExpand(scope, name, evalue);
1774
1775 *out_avalue = FStr_InitOwn(evalue);
1776 }
1777
1778 /* Perform a variable assignment that uses the operator '!='. */
1779 static void
1780 VarAssign_EvalShell(const char *name, const char *uvalue, GNode *scope,
1781 FStr *out_avalue)
1782 {
1783 FStr cmd;
1784 char *output, *error;
1785
1786 cmd = FStr_InitRefer(uvalue);
1787 Var_Expand(&cmd, SCOPE_CMDLINE, VARE_UNDEFERR);
1788
1789 output = Cmd_Exec(cmd.str, &error);
1790 Var_SetExpand(scope, name, output);
1791 *out_avalue = FStr_InitOwn(output);
1792 if (error != NULL) {
1793 Parse_Error(PARSE_WARNING, "%s", error);
1794 free(error);
1795 }
1796
1797 FStr_Done(&cmd);
1798 }
1799
1800 /*
1801 * Perform a variable assignment.
1802 *
1803 * The actual value of the variable is returned in *out_true_avalue.
1804 * Especially for VAR_SUBST and VAR_SHELL this can differ from the literal
1805 * value.
1806 *
1807 * Return whether the assignment was actually performed, which is usually
1808 * the case. It is only skipped if the operator is '?=' and the variable
1809 * already exists.
1810 */
1811 static bool
1812 VarAssign_Eval(const char *name, VarAssignOp op, const char *uvalue,
1813 GNode *scope, FStr *out_true_avalue)
1814 {
1815 FStr avalue = FStr_InitRefer(uvalue);
1816
1817 if (op == VAR_APPEND)
1818 Var_AppendExpand(scope, name, uvalue);
1819 else if (op == VAR_SUBST)
1820 VarAssign_EvalSubst(scope, name, uvalue, &avalue);
1821 else if (op == VAR_SHELL)
1822 VarAssign_EvalShell(name, uvalue, scope, &avalue);
1823 else {
1824 /* XXX: The variable name is expanded up to 2 times. */
1825 if (op == VAR_DEFAULT && Var_ExistsExpand(scope, name))
1826 return false;
1827
1828 /* Normal assignment -- just do it. */
1829 Var_SetExpand(scope, name, uvalue);
1830 }
1831
1832 *out_true_avalue = avalue;
1833 return true;
1834 }
1835
1836 static void
1837 VarAssignSpecial(const char *name, const char *avalue)
1838 {
1839 if (strcmp(name, MAKEOVERRIDES) == 0)
1840 Main_ExportMAKEFLAGS(false); /* re-export MAKEFLAGS */
1841 else if (strcmp(name, ".CURDIR") == 0) {
1842 /*
1843 * Someone is being (too?) clever...
1844 * Let's pretend they know what they are doing and
1845 * re-initialize the 'cur' CachedDir.
1846 */
1847 Dir_InitCur(avalue);
1848 Dir_SetPATH();
1849 } else if (strcmp(name, MAKE_JOB_PREFIX) == 0)
1850 Job_SetPrefix();
1851 else if (strcmp(name, MAKE_EXPORTED) == 0)
1852 Var_ExportVars(avalue);
1853 }
1854
1855 /* Perform the variable assignment in the given scope. */
1856 static void
1857 Parse_Var(VarAssign *var, GNode *scope)
1858 {
1859 FStr avalue; /* actual value (maybe expanded) */
1860
1861 VarCheckSyntax(var->op, var->value, scope);
1862 if (VarAssign_Eval(var->varname, var->op, var->value, scope, &avalue)) {
1863 VarAssignSpecial(var->varname, avalue.str);
1864 FStr_Done(&avalue);
1865 }
1866 }
1867
1868
1869 /*
1870 * See if the command possibly calls a sub-make by using the variable
1871 * expressions ${.MAKE}, ${MAKE} or the plain word "make".
1872 */
1873 static bool
1874 MaybeSubMake(const char *cmd)
1875 {
1876 const char *start;
1877
1878 for (start = cmd; *start != '\0'; start++) {
1879 const char *p = start;
1880 char endc;
1881
1882 /* XXX: What if progname != "make"? */
1883 if (strncmp(p, "make", 4) == 0)
1884 if (start == cmd || !ch_isalnum(p[-1]))
1885 if (!ch_isalnum(p[4]))
1886 return true;
1887
1888 if (*p != '$')
1889 continue;
1890 p++;
1891
1892 if (*p == '{')
1893 endc = '}';
1894 else if (*p == '(')
1895 endc = ')';
1896 else
1897 continue;
1898 p++;
1899
1900 if (*p == '.') /* Accept either ${.MAKE} or ${MAKE}. */
1901 p++;
1902
1903 if (strncmp(p, "MAKE", 4) == 0 && p[4] == endc)
1904 return true;
1905 }
1906 return false;
1907 }
1908
1909 /*
1910 * Append the command to the target node.
1911 *
1912 * The node may be marked as a submake node if the command is determined to
1913 * be that.
1914 */
1915 static void
1916 GNode_AddCommand(GNode *gn, char *cmd)
1917 {
1918 /* Add to last (ie current) cohort for :: targets */
1919 if ((gn->type & OP_DOUBLEDEP) && gn->cohorts.last != NULL)
1920 gn = gn->cohorts.last->datum;
1921
1922 /* if target already supplied, ignore commands */
1923 if (!(gn->type & OP_HAS_COMMANDS)) {
1924 Lst_Append(&gn->commands, cmd);
1925 if (MaybeSubMake(cmd))
1926 gn->type |= OP_SUBMAKE;
1927 RememberLocation(gn);
1928 } else {
1929 #if 0
1930 /* XXX: We cannot do this until we fix the tree */
1931 Lst_Append(&gn->commands, cmd);
1932 Parse_Error(PARSE_WARNING,
1933 "overriding commands for target \"%s\"; "
1934 "previous commands defined at %s: %u ignored",
1935 gn->name, gn->fname, gn->lineno);
1936 #else
1937 Parse_Error(PARSE_WARNING,
1938 "duplicate script for target \"%s\" ignored",
1939 gn->name);
1940 ParseErrorInternal(gn, PARSE_WARNING,
1941 "using previous script for \"%s\" defined here",
1942 gn->name);
1943 #endif
1944 }
1945 }
1946
1947 /*
1948 * Add a directory to the path searched for included makefiles bracketed
1949 * by double-quotes.
1950 */
1951 void
1952 Parse_AddIncludeDir(const char *dir)
1953 {
1954 (void)SearchPath_Add(parseIncPath, dir);
1955 }
1956
1957
1958 /*
1959 * Parse a directive like '.include' or '.-include'.
1960 *
1961 * .include "user-makefile.mk"
1962 * .include <system-makefile.mk>
1963 */
1964 static void
1965 ParseInclude(char *directive)
1966 {
1967 char endc; /* '>' or '"' */
1968 char *p;
1969 bool silent = directive[0] != 'i';
1970 FStr file;
1971
1972 p = directive + (silent ? 8 : 7);
1973 pp_skip_hspace(&p);
1974
1975 if (*p != '"' && *p != '<') {
1976 Parse_Error(PARSE_FATAL,
1977 ".include filename must be delimited by '\"' or '<'");
1978 return;
1979 }
1980
1981 if (*p++ == '<')
1982 endc = '>';
1983 else
1984 endc = '"';
1985 file = FStr_InitRefer(p);
1986
1987 /* Skip to matching delimiter */
1988 while (*p != '\0' && *p != endc)
1989 p++;
1990
1991 if (*p != endc) {
1992 Parse_Error(PARSE_FATAL,
1993 "Unclosed .include filename. '%c' expected", endc);
1994 return;
1995 }
1996
1997 *p = '\0';
1998
1999 Var_Expand(&file, SCOPE_CMDLINE, VARE_WANTRES);
2000 IncludeFile(file.str, endc == '>', directive[0] == 'd', silent);
2001 FStr_Done(&file);
2002 }
2003
2004 /*
2005 * Split filename into dirname + basename, then assign these to the
2006 * given variables.
2007 */
2008 static void
2009 SetFilenameVars(const char *filename, const char *dirvar, const char *filevar)
2010 {
2011 const char *slash, *basename;
2012 FStr dirname;
2013
2014 slash = strrchr(filename, '/');
2015 if (slash == NULL) {
2016 dirname = FStr_InitRefer(curdir);
2017 basename = filename;
2018 } else {
2019 dirname = FStr_InitOwn(bmake_strsedup(filename, slash));
2020 basename = slash + 1;
2021 }
2022
2023 Global_Set(dirvar, dirname.str);
2024 Global_Set(filevar, basename);
2025
2026 DEBUG4(PARSE, "SetFilenameVars: ${%s} = `%s' ${%s} = `%s'\n",
2027 dirvar, dirname.str, filevar, basename);
2028 FStr_Done(&dirname);
2029 }
2030
2031 /*
2032 * Return the immediately including file.
2033 *
2034 * This is made complicated since the .for loop is implemented as a special
2035 * kind of .include; see For_Run.
2036 */
2037 static const char *
2038 GetActuallyIncludingFile(void)
2039 {
2040 size_t i;
2041 const IncludedFile *incs = GetInclude(0);
2042
2043 for (i = includes.len; i >= 2; i--)
2044 if (incs[i - 1].forLoop == NULL)
2045 return incs[i - 2].name.str;
2046 return NULL;
2047 }
2048
2049 /* Set .PARSEDIR, .PARSEFILE, .INCLUDEDFROMDIR and .INCLUDEDFROMFILE. */
2050 static void
2051 SetParseFile(const char *filename)
2052 {
2053 const char *including;
2054
2055 SetFilenameVars(filename, ".PARSEDIR", ".PARSEFILE");
2056
2057 including = GetActuallyIncludingFile();
2058 if (including != NULL) {
2059 SetFilenameVars(including,
2060 ".INCLUDEDFROMDIR", ".INCLUDEDFROMFILE");
2061 } else {
2062 Global_Delete(".INCLUDEDFROMDIR");
2063 Global_Delete(".INCLUDEDFROMFILE");
2064 }
2065 }
2066
2067 static bool
2068 StrContainsWord(const char *str, const char *word)
2069 {
2070 size_t strLen = strlen(str);
2071 size_t wordLen = strlen(word);
2072 const char *p;
2073
2074 if (strLen < wordLen)
2075 return false;
2076
2077 for (p = str; p != NULL; p = strchr(p, ' ')) {
2078 if (*p == ' ')
2079 p++;
2080 if (p > str + strLen - wordLen)
2081 return false;
2082
2083 if (memcmp(p, word, wordLen) == 0 &&
2084 (p[wordLen] == '\0' || p[wordLen] == ' '))
2085 return true;
2086 }
2087 return false;
2088 }
2089
2090 /*
2091 * XXX: Searching through a set of words with this linear search is
2092 * inefficient for variables that contain thousands of words.
2093 *
2094 * XXX: The paths in this list don't seem to be normalized in any way.
2095 */
2096 static bool
2097 VarContainsWord(const char *varname, const char *word)
2098 {
2099 FStr val = Var_Value(SCOPE_GLOBAL, varname);
2100 bool found = val.str != NULL && StrContainsWord(val.str, word);
2101 FStr_Done(&val);
2102 return found;
2103 }
2104
2105 /*
2106 * Track the makefiles we read - so makefiles can set dependencies on them.
2107 * Avoid adding anything more than once.
2108 *
2109 * Time complexity: O(n) per call, in total O(n^2), where n is the number
2110 * of makefiles that have been loaded.
2111 */
2112 static void
2113 TrackInput(const char *name)
2114 {
2115 if (!VarContainsWord(MAKE_MAKEFILES, name))
2116 Global_Append(MAKE_MAKEFILES, name);
2117 }
2118
2119
2120 /* Parse from the given buffer, later return to the current file. */
2121 void
2122 Parse_PushInput(const char *name, unsigned lineno, unsigned readLines,
2123 Buffer buf, struct ForLoop *forLoop)
2124 {
2125 IncludedFile *curFile;
2126
2127 if (forLoop != NULL)
2128 name = CurFile()->name.str;
2129 else
2130 TrackInput(name);
2131
2132 DEBUG3(PARSE, "Parse_PushInput: %s %s, line %u\n",
2133 forLoop != NULL ? ".for loop in": "file", name, lineno);
2134
2135 curFile = Vector_Push(&includes);
2136 curFile->name = FStr_InitOwn(bmake_strdup(name));
2137 curFile->lineno = lineno;
2138 curFile->readLines = readLines;
2139 curFile->forHeadLineno = lineno;
2140 curFile->forBodyReadLines = readLines;
2141 curFile->buf = buf;
2142 curFile->depending = doing_depend; /* restore this on EOF */
2143 curFile->forLoop = forLoop;
2144
2145 if (forLoop != NULL && !For_NextIteration(forLoop, &curFile->buf))
2146 abort(); /* see For_Run */
2147
2148 curFile->buf_ptr = curFile->buf.data;
2149 curFile->buf_end = curFile->buf.data + curFile->buf.len;
2150 curFile->condMinDepth = cond_depth;
2151 SetParseFile(name);
2152 }
2153
2154 /* Check if the directive is an include directive. */
2155 static bool
2156 IsInclude(const char *dir, bool sysv)
2157 {
2158 if (dir[0] == 's' || dir[0] == '-' || (dir[0] == 'd' && !sysv))
2159 dir++;
2160
2161 if (strncmp(dir, "include", 7) != 0)
2162 return false;
2163
2164 /* Space is not mandatory for BSD .include */
2165 return !sysv || ch_isspace(dir[7]);
2166 }
2167
2168
2169 #ifdef SYSVINCLUDE
2170 /* Check if the line is a SYSV include directive. */
2171 static bool
2172 IsSysVInclude(const char *line)
2173 {
2174 const char *p;
2175
2176 if (!IsInclude(line, true))
2177 return false;
2178
2179 /* Avoid interpreting a dependency line as an include */
2180 for (p = line; (p = strchr(p, ':')) != NULL;) {
2181
2182 /* end of line -> it's a dependency */
2183 if (*++p == '\0')
2184 return false;
2185
2186 /* '::' operator or ': ' -> it's a dependency */
2187 if (*p == ':' || ch_isspace(*p))
2188 return false;
2189 }
2190 return true;
2191 }
2192
2193 /* Push to another file. The line points to the word "include". */
2194 static void
2195 ParseTraditionalInclude(char *line)
2196 {
2197 char *cp; /* current position in file spec */
2198 bool done = false;
2199 bool silent = line[0] != 'i';
2200 char *file = line + (silent ? 8 : 7);
2201 char *all_files;
2202
2203 DEBUG1(PARSE, "ParseTraditionalInclude: %s\n", file);
2204
2205 pp_skip_whitespace(&file);
2206
2207 (void)Var_Subst(file, SCOPE_CMDLINE, VARE_WANTRES, &all_files);
2208 /* TODO: handle errors */
2209
2210 for (file = all_files; !done; file = cp + 1) {
2211 /* Skip to end of line or next whitespace */
2212 for (cp = file; *cp != '\0' && !ch_isspace(*cp); cp++)
2213 continue;
2214
2215 if (*cp != '\0')
2216 *cp = '\0';
2217 else
2218 done = true;
2219
2220 IncludeFile(file, false, false, silent);
2221 }
2222
2223 free(all_files);
2224 }
2225 #endif
2226
2227 #ifdef GMAKEEXPORT
2228 /* Parse "export <variable>=<value>", and actually export it. */
2229 static void
2230 ParseGmakeExport(char *line)
2231 {
2232 char *variable = line + 6;
2233 char *value;
2234
2235 DEBUG1(PARSE, "ParseGmakeExport: %s\n", variable);
2236
2237 pp_skip_whitespace(&variable);
2238
2239 for (value = variable; *value != '\0' && *value != '='; value++)
2240 continue;
2241
2242 if (*value != '=') {
2243 Parse_Error(PARSE_FATAL,
2244 "Variable/Value missing from \"export\"");
2245 return;
2246 }
2247 *value++ = '\0'; /* terminate variable */
2248
2249 /*
2250 * Expand the value before putting it in the environment.
2251 */
2252 (void)Var_Subst(value, SCOPE_CMDLINE, VARE_WANTRES, &value);
2253 /* TODO: handle errors */
2254
2255 setenv(variable, value, 1);
2256 free(value);
2257 }
2258 #endif
2259
2260 /*
2261 * Called when EOF is reached in the current file. If we were reading an
2262 * include file or a .for loop, the includes stack is popped and things set
2263 * up to go back to reading the previous file at the previous location.
2264 *
2265 * Results:
2266 * true to continue parsing, i.e. it had only reached the end of an
2267 * included file, false if the main file has been parsed completely.
2268 */
2269 static bool
2270 ParseEOF(void)
2271 {
2272 IncludedFile *curFile = CurFile();
2273
2274 doing_depend = curFile->depending;
2275 if (curFile->forLoop != NULL &&
2276 For_NextIteration(curFile->forLoop, &curFile->buf)) {
2277 curFile->buf_ptr = curFile->buf.data;
2278 curFile->buf_end = curFile->buf.data + curFile->buf.len;
2279 curFile->readLines = curFile->forBodyReadLines;
2280 return true;
2281 }
2282
2283 Cond_EndFile();
2284
2285 FStr_Done(&curFile->name);
2286 Buf_Done(&curFile->buf);
2287 if (curFile->forLoop != NULL)
2288 ForLoop_Free(curFile->forLoop);
2289 Vector_Pop(&includes);
2290
2291 if (includes.len == 0) {
2292 /* We've run out of input */
2293 Global_Delete(".PARSEDIR");
2294 Global_Delete(".PARSEFILE");
2295 Global_Delete(".INCLUDEDFROMDIR");
2296 Global_Delete(".INCLUDEDFROMFILE");
2297 return false;
2298 }
2299
2300 curFile = CurFile();
2301 DEBUG2(PARSE, "ParseEOF: returning to file %s, line %u\n",
2302 curFile->name.str, curFile->readLines + 1);
2303
2304 SetParseFile(curFile->name.str);
2305 return true;
2306 }
2307
2308 typedef enum ParseRawLineResult {
2309 PRLR_LINE,
2310 PRLR_EOF,
2311 PRLR_ERROR
2312 } ParseRawLineResult;
2313
2314 /*
2315 * Parse until the end of a line, taking into account lines that end with
2316 * backslash-newline. The resulting line goes from out_line to out_line_end;
2317 * the line is not null-terminated.
2318 */
2319 static ParseRawLineResult
2320 ParseRawLine(IncludedFile *curFile, char **out_line, char **out_line_end,
2321 char **out_firstBackslash, char **out_commentLineEnd)
2322 {
2323 char *line = curFile->buf_ptr;
2324 char *buf_end = curFile->buf_end;
2325 char *p = line;
2326 char *line_end = line;
2327 char *firstBackslash = NULL;
2328 char *commentLineEnd = NULL;
2329 ParseRawLineResult res = PRLR_LINE;
2330
2331 curFile->readLines++;
2332
2333 for (;;) {
2334 char ch;
2335
2336 if (p == buf_end) {
2337 res = PRLR_EOF;
2338 break;
2339 }
2340
2341 ch = *p;
2342 if (ch == '\0' || (ch == '\\' && p[1] == '\0')) {
2343 Parse_Error(PARSE_FATAL, "Zero byte read from file");
2344 return PRLR_ERROR;
2345 }
2346
2347 /* Treat next character after '\' as literal. */
2348 if (ch == '\\') {
2349 if (firstBackslash == NULL)
2350 firstBackslash = p;
2351 if (p[1] == '\n') {
2352 curFile->readLines++;
2353 if (p + 2 == buf_end) {
2354 line_end = p;
2355 *line_end = '\n';
2356 p += 2;
2357 continue;
2358 }
2359 }
2360 p += 2;
2361 line_end = p;
2362 assert(p <= buf_end);
2363 continue;
2364 }
2365
2366 /*
2367 * Remember the first '#' for comment stripping, unless
2368 * the previous char was '[', as in the modifier ':[#]'.
2369 */
2370 if (ch == '#' && commentLineEnd == NULL &&
2371 !(p > line && p[-1] == '['))
2372 commentLineEnd = line_end;
2373
2374 p++;
2375 if (ch == '\n')
2376 break;
2377
2378 /* We are not interested in trailing whitespace. */
2379 if (!ch_isspace(ch))
2380 line_end = p;
2381 }
2382
2383 curFile->buf_ptr = p;
2384 *out_line = line;
2385 *out_line_end = line_end;
2386 *out_firstBackslash = firstBackslash;
2387 *out_commentLineEnd = commentLineEnd;
2388 return res;
2389 }
2390
2391 /*
2392 * Beginning at start, unescape '\#' to '#' and replace backslash-newline
2393 * with a single space.
2394 */
2395 static void
2396 UnescapeBackslash(char *line, char *start)
2397 {
2398 const char *src = start;
2399 char *dst = start;
2400 char *spaceStart = line;
2401
2402 for (;;) {
2403 char ch = *src++;
2404 if (ch != '\\') {
2405 if (ch == '\0')
2406 break;
2407 *dst++ = ch;
2408 continue;
2409 }
2410
2411 ch = *src++;
2412 if (ch == '\0') {
2413 /* Delete '\\' at the end of the buffer. */
2414 dst--;
2415 break;
2416 }
2417
2418 /* Delete '\\' from before '#' on non-command lines. */
2419 if (ch == '#' && line[0] != '\t')
2420 *dst++ = ch;
2421 else if (ch == '\n') {
2422 cpp_skip_hspace(&src);
2423 *dst++ = ' ';
2424 } else {
2425 /* Leave '\\' in the buffer for later. */
2426 *dst++ = '\\';
2427 *dst++ = ch;
2428 /* Keep an escaped ' ' at the line end. */
2429 spaceStart = dst;
2430 }
2431 }
2432
2433 /* Delete any trailing spaces - eg from empty continuations */
2434 while (dst > spaceStart && ch_isspace(dst[-1]))
2435 dst--;
2436 *dst = '\0';
2437 }
2438
2439 typedef enum LineKind {
2440 /*
2441 * Return the next line that is neither empty nor a comment.
2442 * Backslash line continuations are folded into a single space.
2443 * A trailing comment, if any, is discarded.
2444 */
2445 LK_NONEMPTY,
2446
2447 /*
2448 * Return the next line, even if it is empty or a comment.
2449 * Preserve backslash-newline to keep the line numbers correct.
2450 *
2451 * Used in .for loops to collect the body of the loop while waiting
2452 * for the corresponding .endfor.
2453 */
2454 LK_FOR_BODY,
2455
2456 /*
2457 * Return the next line that starts with a dot.
2458 * Backslash line continuations are folded into a single space.
2459 * A trailing comment, if any, is discarded.
2460 *
2461 * Used in .if directives to skip over irrelevant branches while
2462 * waiting for the corresponding .endif.
2463 */
2464 LK_DOT
2465 } LineKind;
2466
2467 /*
2468 * Return the next "interesting" logical line from the current file. The
2469 * returned string will be freed at the end of including the file.
2470 */
2471 static char *
2472 ReadLowLevelLine(LineKind kind)
2473 {
2474 IncludedFile *curFile = CurFile();
2475 ParseRawLineResult res;
2476 char *line;
2477 char *line_end;
2478 char *firstBackslash;
2479 char *commentLineEnd;
2480
2481 for (;;) {
2482 curFile->lineno = curFile->readLines + 1;
2483 res = ParseRawLine(curFile,
2484 &line, &line_end, &firstBackslash, &commentLineEnd);
2485 if (res == PRLR_ERROR)
2486 return NULL;
2487
2488 if (line == line_end || line == commentLineEnd) {
2489 if (res == PRLR_EOF)
2490 return NULL;
2491 if (kind != LK_FOR_BODY)
2492 continue;
2493 }
2494
2495 /* We now have a line of data */
2496 assert(ch_isspace(*line_end));
2497 *line_end = '\0';
2498
2499 if (kind == LK_FOR_BODY)
2500 return line; /* Don't join the physical lines. */
2501
2502 if (kind == LK_DOT && line[0] != '.')
2503 continue;
2504 break;
2505 }
2506
2507 if (commentLineEnd != NULL && line[0] != '\t')
2508 *commentLineEnd = '\0';
2509 if (firstBackslash != NULL)
2510 UnescapeBackslash(line, firstBackslash);
2511 return line;
2512 }
2513
2514 static bool
2515 SkipIrrelevantBranches(void)
2516 {
2517 const char *line;
2518
2519 while ((line = ReadLowLevelLine(LK_DOT)) != NULL) {
2520 if (Cond_EvalLine(line) == CR_TRUE)
2521 return true;
2522 /*
2523 * TODO: Check for typos in .elif directives such as .elsif
2524 * or .elseif.
2525 *
2526 * This check will probably duplicate some of the code in
2527 * ParseLine. Most of the code there cannot apply, only
2528 * ParseVarassign and ParseDependencyLine can, and to prevent
2529 * code duplication, these would need to be called with a
2530 * flag called onlyCheckSyntax.
2531 *
2532 * See directive-elif.mk for details.
2533 */
2534 }
2535
2536 return false;
2537 }
2538
2539 static bool
2540 ParseForLoop(const char *line)
2541 {
2542 int rval;
2543 unsigned forHeadLineno;
2544 unsigned bodyReadLines;
2545 int forLevel;
2546
2547 rval = For_Eval(line);
2548 if (rval == 0)
2549 return false; /* Not a .for line */
2550 if (rval < 0)
2551 return true; /* Syntax error - error printed, ignore line */
2552
2553 forHeadLineno = CurFile()->lineno;
2554 bodyReadLines = CurFile()->readLines;
2555
2556 /* Accumulate the loop body until the matching '.endfor'. */
2557 forLevel = 1;
2558 do {
2559 line = ReadLowLevelLine(LK_FOR_BODY);
2560 if (line == NULL) {
2561 Parse_Error(PARSE_FATAL,
2562 "Unexpected end of file in .for loop");
2563 break;
2564 }
2565 } while (For_Accum(line, &forLevel));
2566
2567 For_Run(forHeadLineno, bodyReadLines);
2568 return true;
2569 }
2570
2571 /*
2572 * Read an entire line from the input file.
2573 *
2574 * Empty lines, .if and .for are completely handled by this function,
2575 * leaving only variable assignments, other directives, dependency lines
2576 * and shell commands to the caller.
2577 *
2578 * Return a line without trailing whitespace, or NULL for EOF. The returned
2579 * string will be freed at the end of including the file.
2580 */
2581 static char *
2582 ReadHighLevelLine(void)
2583 {
2584 char *line;
2585
2586 for (;;) {
2587 line = ReadLowLevelLine(LK_NONEMPTY);
2588 if (posix_state == PS_MAYBE_NEXT_LINE)
2589 posix_state = PS_NOW_OR_NEVER;
2590 else
2591 posix_state = PS_TOO_LATE;
2592 if (line == NULL)
2593 return NULL;
2594
2595 if (line[0] != '.')
2596 return line;
2597
2598 switch (Cond_EvalLine(line)) {
2599 case CR_FALSE: /* May also mean a syntax error. */
2600 if (!SkipIrrelevantBranches())
2601 return NULL;
2602 continue;
2603 case CR_TRUE:
2604 continue;
2605 case CR_ERROR: /* Not a conditional line */
2606 if (ParseForLoop(line))
2607 continue;
2608 break;
2609 }
2610 return line;
2611 }
2612 }
2613
2614 static void
2615 FinishDependencyGroup(void)
2616 {
2617 GNodeListNode *ln;
2618
2619 if (targets == NULL)
2620 return;
2621
2622 for (ln = targets->first; ln != NULL; ln = ln->next) {
2623 GNode *gn = ln->datum;
2624
2625 Suff_EndTransform(gn);
2626
2627 /*
2628 * Mark the target as already having commands if it does, to
2629 * keep from having shell commands on multiple dependency
2630 * lines.
2631 */
2632 if (!Lst_IsEmpty(&gn->commands))
2633 gn->type |= OP_HAS_COMMANDS;
2634 }
2635
2636 Lst_Free(targets);
2637 targets = NULL;
2638 }
2639
2640 /* Add the command to each target from the current dependency spec. */
2641 static void
2642 ParseLine_ShellCommand(const char *p)
2643 {
2644 cpp_skip_whitespace(&p);
2645 if (*p == '\0')
2646 return; /* skip empty commands */
2647
2648 if (targets == NULL) {
2649 Parse_Error(PARSE_FATAL,
2650 "Unassociated shell command \"%s\"", p);
2651 return;
2652 }
2653
2654 {
2655 char *cmd = bmake_strdup(p);
2656 GNodeListNode *ln;
2657
2658 for (ln = targets->first; ln != NULL; ln = ln->next) {
2659 GNode *gn = ln->datum;
2660 GNode_AddCommand(gn, cmd);
2661 }
2662 #ifdef CLEANUP
2663 Lst_Append(&targCmds, cmd);
2664 #endif
2665 }
2666 }
2667
2668 static void
2669 HandleBreak(void)
2670 {
2671 IncludedFile *curFile = CurFile();
2672
2673 if (curFile->forLoop != NULL) {
2674 /* pretend we reached EOF */
2675 For_Break(curFile->forLoop);
2676 cond_depth = CurFile_CondMinDepth();
2677 ParseEOF();
2678 } else
2679 Parse_Error(PARSE_FATAL, "break outside of for loop");
2680 }
2681
2682 /*
2683 * See if the line starts with one of the known directives, and if so, handle
2684 * the directive.
2685 */
2686 static bool
2687 ParseDirective(char *line)
2688 {
2689 char *cp = line + 1;
2690 const char *arg;
2691 Substring dir;
2692
2693 pp_skip_whitespace(&cp);
2694 if (IsInclude(cp, false)) {
2695 ParseInclude(cp);
2696 return true;
2697 }
2698
2699 dir.start = cp;
2700 while (ch_islower(*cp) || *cp == '-')
2701 cp++;
2702 dir.end = cp;
2703
2704 if (*cp != '\0' && !ch_isspace(*cp))
2705 return false;
2706
2707 pp_skip_whitespace(&cp);
2708 arg = cp;
2709
2710 if (Substring_Equals(dir, "break"))
2711 HandleBreak();
2712 else if (Substring_Equals(dir, "undef"))
2713 Var_Undef(arg);
2714 else if (Substring_Equals(dir, "export"))
2715 Var_Export(VEM_PLAIN, arg);
2716 else if (Substring_Equals(dir, "export-env"))
2717 Var_Export(VEM_ENV, arg);
2718 else if (Substring_Equals(dir, "export-literal"))
2719 Var_Export(VEM_LITERAL, arg);
2720 else if (Substring_Equals(dir, "unexport"))
2721 Var_UnExport(false, arg);
2722 else if (Substring_Equals(dir, "unexport-env"))
2723 Var_UnExport(true, arg);
2724 else if (Substring_Equals(dir, "info"))
2725 HandleMessage(PARSE_INFO, "info", arg);
2726 else if (Substring_Equals(dir, "warning"))
2727 HandleMessage(PARSE_WARNING, "warning", arg);
2728 else if (Substring_Equals(dir, "error"))
2729 HandleMessage(PARSE_FATAL, "error", arg);
2730 else
2731 return false;
2732 return true;
2733 }
2734
2735 bool
2736 Parse_VarAssign(const char *line, bool finishDependencyGroup, GNode *scope)
2737 {
2738 VarAssign var;
2739
2740 if (!Parse_IsVar(line, &var))
2741 return false;
2742 if (finishDependencyGroup)
2743 FinishDependencyGroup();
2744 Parse_Var(&var, scope);
2745 free(var.varname);
2746 return true;
2747 }
2748
2749 static char *
2750 FindSemicolon(char *p)
2751 {
2752 int level = 0;
2753
2754 for (; *p != '\0'; p++) {
2755 if (*p == '\\' && p[1] != '\0') {
2756 p++;
2757 continue;
2758 }
2759
2760 if (*p == '$' && (p[1] == '(' || p[1] == '{'))
2761 level++;
2762 else if (level > 0 && (*p == ')' || *p == '}'))
2763 level--;
2764 else if (level == 0 && *p == ';')
2765 break;
2766 }
2767 return p;
2768 }
2769
2770 /*
2771 * dependency -> [target...] op [source...] [';' command]
2772 * op -> ':' | '::' | '!'
2773 */
2774 static void
2775 ParseDependencyLine(char *line)
2776 {
2777 VarEvalMode emode;
2778 char *expanded_line;
2779 const char *shellcmd = NULL;
2780
2781 /*
2782 * For some reason - probably to make the parser impossible -
2783 * a ';' can be used to separate commands from dependencies.
2784 * Attempt to skip over ';' inside substitution patterns.
2785 */
2786 {
2787 char *semicolon = FindSemicolon(line);
2788 if (*semicolon != '\0') {
2789 /* Terminate the dependency list at the ';' */
2790 *semicolon = '\0';
2791 shellcmd = semicolon + 1;
2792 }
2793 }
2794
2795 /*
2796 * We now know it's a dependency line so it needs to have all
2797 * variables expanded before being parsed.
2798 *
2799 * XXX: Ideally the dependency line would first be split into
2800 * its left-hand side, dependency operator and right-hand side,
2801 * and then each side would be expanded on its own. This would
2802 * allow for the left-hand side to allow only defined variables
2803 * and to allow variables on the right-hand side to be undefined
2804 * as well.
2805 *
2806 * Parsing the line first would also prevent that targets
2807 * generated from variable expressions are interpreted as the
2808 * dependency operator, such as in "target${:U\:} middle: source",
2809 * in which the middle is interpreted as a source, not a target.
2810 */
2811
2812 /*
2813 * In lint mode, allow undefined variables to appear in dependency
2814 * lines.
2815 *
2816 * Ideally, only the right-hand side would allow undefined variables
2817 * since it is common to have optional dependencies. Having undefined
2818 * variables on the left-hand side is more unusual though. Since
2819 * both sides are expanded in a single pass, there is not much choice
2820 * what to do here.
2821 *
2822 * In normal mode, it does not matter whether undefined variables are
2823 * allowed or not since as of 2020-09-14, Var_Parse does not print
2824 * any parse errors in such a case. It simply returns the special
2825 * empty string var_Error, which cannot be detected in the result of
2826 * Var_Subst.
2827 */
2828 emode = opts.strict ? VARE_WANTRES : VARE_UNDEFERR;
2829 (void)Var_Subst(line, SCOPE_CMDLINE, emode, &expanded_line);
2830 /* TODO: handle errors */
2831
2832 /* Need a fresh list for the target nodes */
2833 if (targets != NULL)
2834 Lst_Free(targets);
2835 targets = Lst_New();
2836
2837 ParseDependency(expanded_line);
2838 free(expanded_line);
2839
2840 if (shellcmd != NULL)
2841 ParseLine_ShellCommand(shellcmd);
2842 }
2843
2844 static void
2845 ParseLine(char *line)
2846 {
2847 /*
2848 * Lines that begin with '.' can be pretty much anything:
2849 * - directives like '.include' or '.if',
2850 * - suffix rules like '.c.o:',
2851 * - dependencies for filenames that start with '.',
2852 * - variable assignments like '.tmp=value'.
2853 */
2854 if (line[0] == '.' && ParseDirective(line))
2855 return;
2856
2857 if (line[0] == '\t') {
2858 ParseLine_ShellCommand(line + 1);
2859 return;
2860 }
2861
2862 #ifdef SYSVINCLUDE
2863 if (IsSysVInclude(line)) {
2864 /*
2865 * It's an S3/S5-style "include".
2866 */
2867 ParseTraditionalInclude(line);
2868 return;
2869 }
2870 #endif
2871
2872 #ifdef GMAKEEXPORT
2873 if (strncmp(line, "export", 6) == 0 && ch_isspace(line[6]) &&
2874 strchr(line, ':') == NULL) {
2875 /*
2876 * It's a Gmake "export".
2877 */
2878 ParseGmakeExport(line);
2879 return;
2880 }
2881 #endif
2882
2883 if (Parse_VarAssign(line, true, SCOPE_GLOBAL))
2884 return;
2885
2886 FinishDependencyGroup();
2887
2888 ParseDependencyLine(line);
2889 }
2890
2891 /*
2892 * Parse a top-level makefile, incorporating its content into the global
2893 * dependency graph.
2894 */
2895 void
2896 Parse_File(const char *name, int fd)
2897 {
2898 char *line;
2899 Buffer buf;
2900
2901 buf = LoadFile(name, fd != -1 ? fd : STDIN_FILENO);
2902 if (fd != -1)
2903 (void)close(fd);
2904
2905 assert(targets == NULL);
2906
2907 Parse_PushInput(name, 1, 0, buf, NULL);
2908
2909 do {
2910 while ((line = ReadHighLevelLine()) != NULL) {
2911 DEBUG2(PARSE, "Parsing line %u: %s\n",
2912 CurFile()->lineno, line);
2913 ParseLine(line);
2914 }
2915 /* Reached EOF, but it may be just EOF of an include file. */
2916 } while (ParseEOF());
2917
2918 FinishDependencyGroup();
2919
2920 if (parseErrors != 0) {
2921 (void)fflush(stdout);
2922 (void)fprintf(stderr,
2923 "%s: Fatal errors encountered -- cannot continue\n",
2924 progname);
2925 PrintOnError(NULL, "");
2926 exit(1);
2927 }
2928 }
2929
2930 /* Initialize the parsing module. */
2931 void
2932 Parse_Init(void)
2933 {
2934 mainNode = NULL;
2935 parseIncPath = SearchPath_New();
2936 sysIncPath = SearchPath_New();
2937 defSysIncPath = SearchPath_New();
2938 Vector_Init(&includes, sizeof(IncludedFile));
2939 }
2940
2941 /* Clean up the parsing module. */
2942 void
2943 Parse_End(void)
2944 {
2945 #ifdef CLEANUP
2946 Lst_DoneCall(&targCmds, free);
2947 assert(targets == NULL);
2948 SearchPath_Free(defSysIncPath);
2949 SearchPath_Free(sysIncPath);
2950 SearchPath_Free(parseIncPath);
2951 assert(includes.len == 0);
2952 Vector_Done(&includes);
2953 #endif
2954 }
2955
2956
2957 /*
2958 * Return a list containing the single main target to create.
2959 * If no such target exists, we Punt with an obnoxious error message.
2960 */
2961 void
2962 Parse_MainName(GNodeList *mainList)
2963 {
2964 if (mainNode == NULL)
2965 Punt("no target to make.");
2966
2967 Lst_Append(mainList, mainNode);
2968 if (mainNode->type & OP_DOUBLEDEP)
2969 Lst_AppendAll(mainList, &mainNode->cohorts);
2970
2971 Global_Append(".TARGETS", mainNode->name);
2972 }
2973
2974 int
2975 Parse_NumErrors(void)
2976 {
2977 return parseErrors;
2978 }
2979