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