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