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