1*6eef5f0cSAntonio Huete Jimenez /* $NetBSD: parse.c,v 1.688 2022/09/27 17:46:58 rillig Exp $ */
201e196c8SJohn Marino
301e196c8SJohn Marino /*
401e196c8SJohn Marino * Copyright (c) 1988, 1989, 1990, 1993
501e196c8SJohn Marino * The Regents of the University of California. All rights reserved.
601e196c8SJohn Marino *
701e196c8SJohn Marino * This code is derived from software contributed to Berkeley by
801e196c8SJohn Marino * Adam de Boor.
901e196c8SJohn Marino *
1001e196c8SJohn Marino * Redistribution and use in source and binary forms, with or without
1101e196c8SJohn Marino * modification, are permitted provided that the following conditions
1201e196c8SJohn Marino * are met:
1301e196c8SJohn Marino * 1. Redistributions of source code must retain the above copyright
1401e196c8SJohn Marino * notice, this list of conditions and the following disclaimer.
1501e196c8SJohn Marino * 2. Redistributions in binary form must reproduce the above copyright
1601e196c8SJohn Marino * notice, this list of conditions and the following disclaimer in the
1701e196c8SJohn Marino * documentation and/or other materials provided with the distribution.
1801e196c8SJohn Marino * 3. Neither the name of the University nor the names of its contributors
1901e196c8SJohn Marino * may be used to endorse or promote products derived from this software
2001e196c8SJohn Marino * without specific prior written permission.
2101e196c8SJohn Marino *
2201e196c8SJohn Marino * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2301e196c8SJohn Marino * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2401e196c8SJohn Marino * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2501e196c8SJohn Marino * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2601e196c8SJohn Marino * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2701e196c8SJohn Marino * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2801e196c8SJohn Marino * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2901e196c8SJohn Marino * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3001e196c8SJohn Marino * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3101e196c8SJohn Marino * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3201e196c8SJohn Marino * SUCH DAMAGE.
3301e196c8SJohn Marino */
3401e196c8SJohn Marino
3501e196c8SJohn Marino /*
3601e196c8SJohn Marino * Copyright (c) 1989 by Berkeley Softworks
3701e196c8SJohn Marino * All rights reserved.
3801e196c8SJohn Marino *
3901e196c8SJohn Marino * This code is derived from software contributed to Berkeley by
4001e196c8SJohn Marino * Adam de Boor.
4101e196c8SJohn Marino *
4201e196c8SJohn Marino * Redistribution and use in source and binary forms, with or without
4301e196c8SJohn Marino * modification, are permitted provided that the following conditions
4401e196c8SJohn Marino * are met:
4501e196c8SJohn Marino * 1. Redistributions of source code must retain the above copyright
4601e196c8SJohn Marino * notice, this list of conditions and the following disclaimer.
4701e196c8SJohn Marino * 2. Redistributions in binary form must reproduce the above copyright
4801e196c8SJohn Marino * notice, this list of conditions and the following disclaimer in the
4901e196c8SJohn Marino * documentation and/or other materials provided with the distribution.
5001e196c8SJohn Marino * 3. All advertising materials mentioning features or use of this software
5101e196c8SJohn Marino * must display the following acknowledgement:
5201e196c8SJohn Marino * This product includes software developed by the University of
5301e196c8SJohn Marino * California, Berkeley and its contributors.
5401e196c8SJohn Marino * 4. Neither the name of the University nor the names of its contributors
5501e196c8SJohn Marino * may be used to endorse or promote products derived from this software
5601e196c8SJohn Marino * without specific prior written permission.
5701e196c8SJohn Marino *
5801e196c8SJohn Marino * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
5901e196c8SJohn Marino * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
6001e196c8SJohn Marino * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
6101e196c8SJohn Marino * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
6201e196c8SJohn Marino * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
6301e196c8SJohn Marino * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
6401e196c8SJohn Marino * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
6501e196c8SJohn Marino * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
6601e196c8SJohn Marino * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
6701e196c8SJohn Marino * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
6801e196c8SJohn Marino * SUCH DAMAGE.
6901e196c8SJohn Marino */
7001e196c8SJohn Marino
71a34d5fb1SAntonio Huete Jimenez /*
72a34d5fb1SAntonio Huete Jimenez * Parsing of makefiles.
7301e196c8SJohn Marino *
74a34d5fb1SAntonio Huete Jimenez * Parse_File is the main entry point and controls most of the other
75a34d5fb1SAntonio Huete Jimenez * functions in this module.
7601e196c8SJohn Marino *
7701e196c8SJohn Marino * Interface:
78a34d5fb1SAntonio Huete Jimenez * Parse_Init Initialize the module
7901e196c8SJohn Marino *
8001e196c8SJohn Marino * Parse_End Clean up the module
8101e196c8SJohn Marino *
82a34d5fb1SAntonio Huete Jimenez * Parse_File Parse a top-level makefile. Included files are
83a34d5fb1SAntonio Huete Jimenez * handled by IncludeFile instead.
8401e196c8SJohn Marino *
85*6eef5f0cSAntonio Huete Jimenez * Parse_VarAssign
86*6eef5f0cSAntonio Huete Jimenez * Try to parse the given line as a variable assignment.
87*6eef5f0cSAntonio Huete Jimenez * Used by MainParseArgs to determine if an argument is
88*6eef5f0cSAntonio Huete Jimenez * a target or a variable assignment. Used internally
89*6eef5f0cSAntonio Huete Jimenez * for pretty much the same thing.
9001e196c8SJohn Marino *
91a34d5fb1SAntonio Huete Jimenez * Parse_Error Report a parse error, a warning or an informational
92a34d5fb1SAntonio Huete Jimenez * message.
93a34d5fb1SAntonio Huete Jimenez *
94*6eef5f0cSAntonio Huete Jimenez * Parse_MainName Returns a list of the single main target to create.
9501e196c8SJohn Marino */
9601e196c8SJohn Marino
9701e196c8SJohn Marino #include <sys/types.h>
9801e196c8SJohn Marino #include <sys/stat.h>
9901e196c8SJohn Marino #include <errno.h>
10001e196c8SJohn Marino #include <stdarg.h>
10101e196c8SJohn Marino
10201e196c8SJohn Marino #include "make.h"
10301e196c8SJohn Marino
104ca58f742SDaniel Fojt #ifdef HAVE_STDINT_H
105ca58f742SDaniel Fojt #include <stdint.h>
106ca58f742SDaniel Fojt #endif
107ca58f742SDaniel Fojt
10801e196c8SJohn Marino #ifdef HAVE_MMAP
10901e196c8SJohn Marino #include <sys/mman.h>
11001e196c8SJohn Marino
11101e196c8SJohn Marino #ifndef MAP_COPY
11201e196c8SJohn Marino #define MAP_COPY MAP_PRIVATE
11301e196c8SJohn Marino #endif
11401e196c8SJohn Marino #ifndef MAP_FILE
11501e196c8SJohn Marino #define MAP_FILE 0
11601e196c8SJohn Marino #endif
11701e196c8SJohn Marino #endif
11801e196c8SJohn Marino
119a34d5fb1SAntonio Huete Jimenez #include "dir.h"
120a34d5fb1SAntonio Huete Jimenez #include "job.h"
121a34d5fb1SAntonio Huete Jimenez #include "pathnames.h"
122a34d5fb1SAntonio Huete Jimenez
123a34d5fb1SAntonio Huete Jimenez /* "@(#)parse.c 8.3 (Berkeley) 3/19/94" */
124*6eef5f0cSAntonio Huete Jimenez MAKE_RCSID("$NetBSD: parse.c,v 1.688 2022/09/27 17:46:58 rillig Exp $");
12501e196c8SJohn Marino
12601e196c8SJohn Marino /*
127*6eef5f0cSAntonio Huete Jimenez * A file being read.
12801e196c8SJohn Marino */
129*6eef5f0cSAntonio Huete Jimenez typedef struct IncludedFile {
130*6eef5f0cSAntonio Huete Jimenez FStr name; /* absolute or relative to the cwd */
131*6eef5f0cSAntonio Huete Jimenez unsigned lineno; /* 1-based */
132*6eef5f0cSAntonio Huete Jimenez unsigned readLines; /* the number of physical lines that have
133*6eef5f0cSAntonio Huete Jimenez * been read from the file */
134*6eef5f0cSAntonio Huete Jimenez unsigned forHeadLineno; /* 1-based */
135*6eef5f0cSAntonio Huete Jimenez unsigned forBodyReadLines; /* the number of physical lines that have
136*6eef5f0cSAntonio Huete Jimenez * been read from the file above the body of
137*6eef5f0cSAntonio Huete Jimenez * the .for loop */
138*6eef5f0cSAntonio Huete Jimenez unsigned int condMinDepth; /* depth of nested 'if' directives, at the
139*6eef5f0cSAntonio Huete Jimenez * beginning of the file */
140*6eef5f0cSAntonio Huete Jimenez bool depending; /* state of doing_depend on EOF */
141a34d5fb1SAntonio Huete Jimenez
142*6eef5f0cSAntonio Huete Jimenez Buffer buf; /* the file's content or the body of the .for
143*6eef5f0cSAntonio Huete Jimenez * loop; either empty or ends with '\n' */
144a34d5fb1SAntonio Huete Jimenez char *buf_ptr; /* next char to be read */
145*6eef5f0cSAntonio Huete Jimenez char *buf_end; /* buf_end[-1] == '\n' */
146a34d5fb1SAntonio Huete Jimenez
147*6eef5f0cSAntonio Huete Jimenez struct ForLoop *forLoop;
148*6eef5f0cSAntonio Huete Jimenez } IncludedFile;
149a34d5fb1SAntonio Huete Jimenez
150*6eef5f0cSAntonio Huete Jimenez /* Special attributes for target nodes. */
151a34d5fb1SAntonio Huete Jimenez typedef enum ParseSpecial {
152a34d5fb1SAntonio Huete Jimenez SP_ATTRIBUTE, /* Generic attribute */
153a34d5fb1SAntonio Huete Jimenez SP_BEGIN, /* .BEGIN */
154a34d5fb1SAntonio Huete Jimenez SP_DEFAULT, /* .DEFAULT */
155a34d5fb1SAntonio Huete Jimenez SP_DELETE_ON_ERROR, /* .DELETE_ON_ERROR */
156a34d5fb1SAntonio Huete Jimenez SP_END, /* .END */
157a34d5fb1SAntonio Huete Jimenez SP_ERROR, /* .ERROR */
158a34d5fb1SAntonio Huete Jimenez SP_IGNORE, /* .IGNORE */
159a34d5fb1SAntonio Huete Jimenez SP_INCLUDES, /* .INCLUDES; not mentioned in the manual page */
160a34d5fb1SAntonio Huete Jimenez SP_INTERRUPT, /* .INTERRUPT */
161a34d5fb1SAntonio Huete Jimenez SP_LIBS, /* .LIBS; not mentioned in the manual page */
162*6eef5f0cSAntonio Huete Jimenez SP_MAIN, /* .MAIN and no user-specified targets to make */
163a34d5fb1SAntonio Huete Jimenez SP_META, /* .META */
164a34d5fb1SAntonio Huete Jimenez SP_MFLAGS, /* .MFLAGS or .MAKEFLAGS */
165a34d5fb1SAntonio Huete Jimenez SP_NOMETA, /* .NOMETA */
166a34d5fb1SAntonio Huete Jimenez SP_NOMETA_CMP, /* .NOMETA_CMP */
167a34d5fb1SAntonio Huete Jimenez SP_NOPATH, /* .NOPATH */
168a34d5fb1SAntonio Huete Jimenez SP_NOT, /* Not special */
169a34d5fb1SAntonio Huete Jimenez SP_NOTPARALLEL, /* .NOTPARALLEL or .NO_PARALLEL */
170a34d5fb1SAntonio Huete Jimenez SP_NULL, /* .NULL; not mentioned in the manual page */
171a34d5fb1SAntonio Huete Jimenez SP_OBJDIR, /* .OBJDIR */
172a34d5fb1SAntonio Huete Jimenez SP_ORDER, /* .ORDER */
173a34d5fb1SAntonio Huete Jimenez SP_PARALLEL, /* .PARALLEL; not mentioned in the manual page */
174a34d5fb1SAntonio Huete Jimenez SP_PATH, /* .PATH or .PATH.suffix */
175a34d5fb1SAntonio Huete Jimenez SP_PHONY, /* .PHONY */
17601e196c8SJohn Marino #ifdef POSIX
177a34d5fb1SAntonio Huete Jimenez SP_POSIX, /* .POSIX; not mentioned in the manual page */
17801e196c8SJohn Marino #endif
179a34d5fb1SAntonio Huete Jimenez SP_PRECIOUS, /* .PRECIOUS */
180a34d5fb1SAntonio Huete Jimenez SP_SHELL, /* .SHELL */
181a34d5fb1SAntonio Huete Jimenez SP_SILENT, /* .SILENT */
182a34d5fb1SAntonio Huete Jimenez SP_SINGLESHELL, /* .SINGLESHELL; not mentioned in the manual page */
183a34d5fb1SAntonio Huete Jimenez SP_STALE, /* .STALE */
184a34d5fb1SAntonio Huete Jimenez SP_SUFFIXES, /* .SUFFIXES */
185a34d5fb1SAntonio Huete Jimenez SP_WAIT /* .WAIT */
18601e196c8SJohn Marino } ParseSpecial;
18701e196c8SJohn Marino
188a34d5fb1SAntonio Huete Jimenez typedef List SearchPathList;
189a34d5fb1SAntonio Huete Jimenez typedef ListNode SearchPathListNode;
19001e196c8SJohn Marino
191*6eef5f0cSAntonio Huete Jimenez
192*6eef5f0cSAntonio Huete Jimenez typedef enum VarAssignOp {
193*6eef5f0cSAntonio Huete Jimenez VAR_NORMAL, /* = */
194*6eef5f0cSAntonio Huete Jimenez VAR_APPEND, /* += */
195*6eef5f0cSAntonio Huete Jimenez VAR_DEFAULT, /* ?= */
196*6eef5f0cSAntonio Huete Jimenez VAR_SUBST, /* := */
197*6eef5f0cSAntonio Huete Jimenez VAR_SHELL /* != or :sh= */
198*6eef5f0cSAntonio Huete Jimenez } VarAssignOp;
199*6eef5f0cSAntonio Huete Jimenez
200*6eef5f0cSAntonio Huete Jimenez typedef struct VarAssign {
201*6eef5f0cSAntonio Huete Jimenez char *varname; /* unexpanded */
202*6eef5f0cSAntonio Huete Jimenez VarAssignOp op;
203*6eef5f0cSAntonio Huete Jimenez const char *value; /* unexpanded */
204*6eef5f0cSAntonio Huete Jimenez } VarAssign;
205*6eef5f0cSAntonio Huete Jimenez
206*6eef5f0cSAntonio Huete Jimenez static bool Parse_IsVar(const char *, VarAssign *);
207*6eef5f0cSAntonio Huete Jimenez static void Parse_Var(VarAssign *, GNode *);
20801e196c8SJohn Marino
20901e196c8SJohn Marino /*
210*6eef5f0cSAntonio Huete Jimenez * The target to be made if no targets are specified in the command line.
211*6eef5f0cSAntonio Huete Jimenez * This is the first target defined in any of the makefiles.
21201e196c8SJohn Marino */
213*6eef5f0cSAntonio Huete Jimenez GNode *mainNode;
21401e196c8SJohn Marino
21501e196c8SJohn Marino /*
216a34d5fb1SAntonio Huete Jimenez * During parsing, the targets from the left-hand side of the currently
217a34d5fb1SAntonio Huete Jimenez * active dependency line, or NULL if the current line does not belong to a
218a34d5fb1SAntonio Huete Jimenez * dependency line, for example because it is a variable assignment.
219a34d5fb1SAntonio Huete Jimenez *
220a34d5fb1SAntonio Huete Jimenez * See unit-tests/deptgt.mk, keyword "parse.c:targets".
22101e196c8SJohn Marino */
222a34d5fb1SAntonio Huete Jimenez static GNodeList *targets;
223a34d5fb1SAntonio Huete Jimenez
224a34d5fb1SAntonio Huete Jimenez #ifdef CLEANUP
225a34d5fb1SAntonio Huete Jimenez /*
226a34d5fb1SAntonio Huete Jimenez * All shell commands for all targets, in no particular order and possibly
227a34d5fb1SAntonio Huete Jimenez * with duplicates. Kept in a separate list since the commands from .USE or
228a34d5fb1SAntonio Huete Jimenez * .USEBEFORE nodes are shared with other GNodes, thereby giving up the
229a34d5fb1SAntonio Huete Jimenez * easily understandable ownership over the allocated strings.
230a34d5fb1SAntonio Huete Jimenez */
231a34d5fb1SAntonio Huete Jimenez static StringList targCmds = LST_INIT;
232a34d5fb1SAntonio Huete Jimenez #endif
23301e196c8SJohn Marino
23401e196c8SJohn Marino /*
23501e196c8SJohn Marino * Predecessor node for handling .ORDER. Initialized to NULL when .ORDER
236*6eef5f0cSAntonio Huete Jimenez * is seen, then set to each successive source on the line.
23701e196c8SJohn Marino */
238a34d5fb1SAntonio Huete Jimenez static GNode *order_pred;
23901e196c8SJohn Marino
240*6eef5f0cSAntonio Huete Jimenez static int parseErrors = 0;
24101e196c8SJohn Marino
242a34d5fb1SAntonio Huete Jimenez /*
243a34d5fb1SAntonio Huete Jimenez * The include chain of makefiles. At index 0 is the top-level makefile from
244a34d5fb1SAntonio Huete Jimenez * the command line, followed by the included files or .for loops, up to and
245a34d5fb1SAntonio Huete Jimenez * including the current file.
246a34d5fb1SAntonio Huete Jimenez *
247a34d5fb1SAntonio Huete Jimenez * See PrintStackTrace for how to interpret the data.
248a34d5fb1SAntonio Huete Jimenez */
249*6eef5f0cSAntonio Huete Jimenez static Vector /* of IncludedFile */ includes;
25001e196c8SJohn Marino
251a34d5fb1SAntonio Huete Jimenez SearchPath *parseIncPath; /* directories for "..." includes */
252a34d5fb1SAntonio Huete Jimenez SearchPath *sysIncPath; /* directories for <...> includes */
253a34d5fb1SAntonio Huete Jimenez SearchPath *defSysIncPath; /* default for sysIncPath */
254a34d5fb1SAntonio Huete Jimenez
25501e196c8SJohn Marino /*
25601e196c8SJohn Marino * The parseKeywords table is searched using binary search when deciding
25701e196c8SJohn Marino * if a target or source is special. The 'spec' field is the ParseSpecial
258a34d5fb1SAntonio Huete Jimenez * type of the keyword (SP_NOT if the keyword isn't special as a target) while
25901e196c8SJohn Marino * the 'op' field is the operator to apply to the list of targets if the
26001e196c8SJohn Marino * keyword is used as a source ("0" if the keyword isn't special as a source)
26101e196c8SJohn Marino */
26201e196c8SJohn Marino static const struct {
263*6eef5f0cSAntonio Huete Jimenez const char name[17];
264*6eef5f0cSAntonio Huete Jimenez ParseSpecial special; /* when used as a target */
265*6eef5f0cSAntonio Huete Jimenez GNodeType targetAttr; /* when used as a source */
26601e196c8SJohn Marino } parseKeywords[] = {
267a34d5fb1SAntonio Huete Jimenez { ".BEGIN", SP_BEGIN, OP_NONE },
268a34d5fb1SAntonio Huete Jimenez { ".DEFAULT", SP_DEFAULT, OP_NONE },
269a34d5fb1SAntonio Huete Jimenez { ".DELETE_ON_ERROR", SP_DELETE_ON_ERROR, OP_NONE },
270a34d5fb1SAntonio Huete Jimenez { ".END", SP_END, OP_NONE },
271a34d5fb1SAntonio Huete Jimenez { ".ERROR", SP_ERROR, OP_NONE },
272a34d5fb1SAntonio Huete Jimenez { ".EXEC", SP_ATTRIBUTE, OP_EXEC },
273a34d5fb1SAntonio Huete Jimenez { ".IGNORE", SP_IGNORE, OP_IGNORE },
274a34d5fb1SAntonio Huete Jimenez { ".INCLUDES", SP_INCLUDES, OP_NONE },
275a34d5fb1SAntonio Huete Jimenez { ".INTERRUPT", SP_INTERRUPT, OP_NONE },
276a34d5fb1SAntonio Huete Jimenez { ".INVISIBLE", SP_ATTRIBUTE, OP_INVISIBLE },
277a34d5fb1SAntonio Huete Jimenez { ".JOIN", SP_ATTRIBUTE, OP_JOIN },
278a34d5fb1SAntonio Huete Jimenez { ".LIBS", SP_LIBS, OP_NONE },
279a34d5fb1SAntonio Huete Jimenez { ".MADE", SP_ATTRIBUTE, OP_MADE },
280a34d5fb1SAntonio Huete Jimenez { ".MAIN", SP_MAIN, OP_NONE },
281a34d5fb1SAntonio Huete Jimenez { ".MAKE", SP_ATTRIBUTE, OP_MAKE },
282a34d5fb1SAntonio Huete Jimenez { ".MAKEFLAGS", SP_MFLAGS, OP_NONE },
283a34d5fb1SAntonio Huete Jimenez { ".META", SP_META, OP_META },
284a34d5fb1SAntonio Huete Jimenez { ".MFLAGS", SP_MFLAGS, OP_NONE },
285a34d5fb1SAntonio Huete Jimenez { ".NOMETA", SP_NOMETA, OP_NOMETA },
286a34d5fb1SAntonio Huete Jimenez { ".NOMETA_CMP", SP_NOMETA_CMP, OP_NOMETA_CMP },
287a34d5fb1SAntonio Huete Jimenez { ".NOPATH", SP_NOPATH, OP_NOPATH },
288a34d5fb1SAntonio Huete Jimenez { ".NOTMAIN", SP_ATTRIBUTE, OP_NOTMAIN },
289a34d5fb1SAntonio Huete Jimenez { ".NOTPARALLEL", SP_NOTPARALLEL, OP_NONE },
290a34d5fb1SAntonio Huete Jimenez { ".NO_PARALLEL", SP_NOTPARALLEL, OP_NONE },
291a34d5fb1SAntonio Huete Jimenez { ".NULL", SP_NULL, OP_NONE },
292a34d5fb1SAntonio Huete Jimenez { ".OBJDIR", SP_OBJDIR, OP_NONE },
293a34d5fb1SAntonio Huete Jimenez { ".OPTIONAL", SP_ATTRIBUTE, OP_OPTIONAL },
294a34d5fb1SAntonio Huete Jimenez { ".ORDER", SP_ORDER, OP_NONE },
295a34d5fb1SAntonio Huete Jimenez { ".PARALLEL", SP_PARALLEL, OP_NONE },
296a34d5fb1SAntonio Huete Jimenez { ".PATH", SP_PATH, OP_NONE },
297a34d5fb1SAntonio Huete Jimenez { ".PHONY", SP_PHONY, OP_PHONY },
29801e196c8SJohn Marino #ifdef POSIX
299a34d5fb1SAntonio Huete Jimenez { ".POSIX", SP_POSIX, OP_NONE },
30001e196c8SJohn Marino #endif
301a34d5fb1SAntonio Huete Jimenez { ".PRECIOUS", SP_PRECIOUS, OP_PRECIOUS },
302a34d5fb1SAntonio Huete Jimenez { ".RECURSIVE", SP_ATTRIBUTE, OP_MAKE },
303a34d5fb1SAntonio Huete Jimenez { ".SHELL", SP_SHELL, OP_NONE },
304a34d5fb1SAntonio Huete Jimenez { ".SILENT", SP_SILENT, OP_SILENT },
305a34d5fb1SAntonio Huete Jimenez { ".SINGLESHELL", SP_SINGLESHELL, OP_NONE },
306a34d5fb1SAntonio Huete Jimenez { ".STALE", SP_STALE, OP_NONE },
307a34d5fb1SAntonio Huete Jimenez { ".SUFFIXES", SP_SUFFIXES, OP_NONE },
308a34d5fb1SAntonio Huete Jimenez { ".USE", SP_ATTRIBUTE, OP_USE },
309a34d5fb1SAntonio Huete Jimenez { ".USEBEFORE", SP_ATTRIBUTE, OP_USEBEFORE },
310a34d5fb1SAntonio Huete Jimenez { ".WAIT", SP_WAIT, OP_NONE },
31101e196c8SJohn Marino };
31201e196c8SJohn Marino
313*6eef5f0cSAntonio Huete Jimenez enum PosixState posix_state = PS_NOT_YET;
31401e196c8SJohn Marino
315*6eef5f0cSAntonio Huete Jimenez static IncludedFile *
GetInclude(size_t i)316*6eef5f0cSAntonio Huete Jimenez GetInclude(size_t i)
31701e196c8SJohn Marino {
318*6eef5f0cSAntonio Huete Jimenez assert(i < includes.len);
319*6eef5f0cSAntonio Huete Jimenez return Vector_Get(&includes, i);
32001e196c8SJohn Marino }
32101e196c8SJohn Marino
322*6eef5f0cSAntonio Huete Jimenez /* The file that is currently being read. */
323*6eef5f0cSAntonio Huete Jimenez static IncludedFile *
CurFile(void)324*6eef5f0cSAntonio Huete Jimenez CurFile(void)
32501e196c8SJohn Marino {
326*6eef5f0cSAntonio Huete Jimenez return GetInclude(includes.len - 1);
32701e196c8SJohn Marino }
32801e196c8SJohn Marino
329*6eef5f0cSAntonio Huete Jimenez unsigned int
CurFile_CondMinDepth(void)330*6eef5f0cSAntonio Huete Jimenez CurFile_CondMinDepth(void)
33101e196c8SJohn Marino {
332*6eef5f0cSAntonio Huete Jimenez return CurFile()->condMinDepth;
33301e196c8SJohn Marino }
33401e196c8SJohn Marino
335*6eef5f0cSAntonio Huete Jimenez static Buffer
LoadFile(const char * path,int fd)336*6eef5f0cSAntonio Huete Jimenez LoadFile(const char *path, int fd)
33701e196c8SJohn Marino {
338a34d5fb1SAntonio Huete Jimenez ssize_t n;
339a34d5fb1SAntonio Huete Jimenez Buffer buf;
340*6eef5f0cSAntonio Huete Jimenez size_t bufSize;
341*6eef5f0cSAntonio Huete Jimenez struct stat st;
34201e196c8SJohn Marino
343*6eef5f0cSAntonio Huete Jimenez bufSize = fstat(fd, &st) == 0 && S_ISREG(st.st_mode) &&
344*6eef5f0cSAntonio Huete Jimenez st.st_size > 0 && st.st_size < 1024 * 1024 * 1024
345*6eef5f0cSAntonio Huete Jimenez ? (size_t)st.st_size : 1024;
346*6eef5f0cSAntonio Huete Jimenez Buf_InitSize(&buf, bufSize);
34701e196c8SJohn Marino
348a34d5fb1SAntonio Huete Jimenez for (;;) {
349a34d5fb1SAntonio Huete Jimenez if (buf.len == buf.cap) {
350*6eef5f0cSAntonio Huete Jimenez if (buf.cap >= 512 * 1024 * 1024) {
351ca58f742SDaniel Fojt Error("%s: file too large", path);
352a34d5fb1SAntonio Huete Jimenez exit(2); /* Not 1 so -q can distinguish error */
353ca58f742SDaniel Fojt }
354a34d5fb1SAntonio Huete Jimenez Buf_Expand(&buf);
35501e196c8SJohn Marino }
356a34d5fb1SAntonio Huete Jimenez assert(buf.len < buf.cap);
357a34d5fb1SAntonio Huete Jimenez n = read(fd, buf.data + buf.len, buf.cap - buf.len);
358a34d5fb1SAntonio Huete Jimenez if (n < 0) {
35901e196c8SJohn Marino Error("%s: read error: %s", path, strerror(errno));
360a34d5fb1SAntonio Huete Jimenez exit(2); /* Not 1 so -q can distinguish error */
36101e196c8SJohn Marino }
362a34d5fb1SAntonio Huete Jimenez if (n == 0)
36301e196c8SJohn Marino break;
36401e196c8SJohn Marino
365a34d5fb1SAntonio Huete Jimenez buf.len += (size_t)n;
36601e196c8SJohn Marino }
367a34d5fb1SAntonio Huete Jimenez assert(buf.len <= buf.cap);
36801e196c8SJohn Marino
369a34d5fb1SAntonio Huete Jimenez if (!Buf_EndsWith(&buf, '\n'))
370a34d5fb1SAntonio Huete Jimenez Buf_AddByte(&buf, '\n');
371a34d5fb1SAntonio Huete Jimenez
372*6eef5f0cSAntonio Huete Jimenez return buf; /* may not be null-terminated */
373a34d5fb1SAntonio Huete Jimenez }
37401e196c8SJohn Marino
375*6eef5f0cSAntonio Huete Jimenez /*
376*6eef5f0cSAntonio Huete Jimenez * Print the current chain of .include and .for directives. In Parse_Fatal
377*6eef5f0cSAntonio Huete Jimenez * or other functions that already print the location, includingInnermost
378*6eef5f0cSAntonio Huete Jimenez * would be redundant, but in other cases like Error or Fatal it needs to be
379*6eef5f0cSAntonio Huete Jimenez * included.
380*6eef5f0cSAntonio Huete Jimenez */
381*6eef5f0cSAntonio Huete Jimenez void
PrintStackTrace(bool includingInnermost)382*6eef5f0cSAntonio Huete Jimenez PrintStackTrace(bool includingInnermost)
383a34d5fb1SAntonio Huete Jimenez {
384*6eef5f0cSAntonio Huete Jimenez const IncludedFile *entries;
385a34d5fb1SAntonio Huete Jimenez size_t i, n;
38601e196c8SJohn Marino
387a34d5fb1SAntonio Huete Jimenez n = includes.len;
388a34d5fb1SAntonio Huete Jimenez if (n == 0)
389a34d5fb1SAntonio Huete Jimenez return;
390a34d5fb1SAntonio Huete Jimenez
391*6eef5f0cSAntonio Huete Jimenez entries = GetInclude(0);
392*6eef5f0cSAntonio Huete Jimenez if (!includingInnermost && entries[n - 1].forLoop == NULL)
393*6eef5f0cSAntonio Huete Jimenez n--; /* already in the diagnostic */
394a34d5fb1SAntonio Huete Jimenez
395a34d5fb1SAntonio Huete Jimenez for (i = n; i-- > 0;) {
396*6eef5f0cSAntonio Huete Jimenez const IncludedFile *entry = entries + i;
397*6eef5f0cSAntonio Huete Jimenez const char *fname = entry->name.str;
398a34d5fb1SAntonio Huete Jimenez char dirbuf[MAXPATHLEN + 1];
399a34d5fb1SAntonio Huete Jimenez
400a34d5fb1SAntonio Huete Jimenez if (fname[0] != '/' && strcmp(fname, "(stdin)") != 0)
401a34d5fb1SAntonio Huete Jimenez fname = realpath(fname, dirbuf);
402a34d5fb1SAntonio Huete Jimenez
403*6eef5f0cSAntonio Huete Jimenez if (entry->forLoop != NULL) {
404*6eef5f0cSAntonio Huete Jimenez char *details = ForLoop_Details(entry->forLoop);
405*6eef5f0cSAntonio Huete Jimenez debug_printf("\tin .for loop from %s:%u with %s\n",
406*6eef5f0cSAntonio Huete Jimenez fname, entry->forHeadLineno, details);
407*6eef5f0cSAntonio Huete Jimenez free(details);
408*6eef5f0cSAntonio Huete Jimenez } else if (i + 1 < n && entries[i + 1].forLoop != NULL) {
409*6eef5f0cSAntonio Huete Jimenez /* entry->lineno is not a useful line number */
410*6eef5f0cSAntonio Huete Jimenez } else
411*6eef5f0cSAntonio Huete Jimenez debug_printf("\tin %s:%u\n", fname, entry->lineno);
412a34d5fb1SAntonio Huete Jimenez }
413a34d5fb1SAntonio Huete Jimenez }
414a34d5fb1SAntonio Huete Jimenez
415a34d5fb1SAntonio Huete Jimenez /* Check if the current character is escaped on the current line. */
416*6eef5f0cSAntonio Huete Jimenez static bool
IsEscaped(const char * line,const char * p)417*6eef5f0cSAntonio Huete Jimenez IsEscaped(const char *line, const char *p)
41801e196c8SJohn Marino {
419*6eef5f0cSAntonio Huete Jimenez bool escaped = false;
420*6eef5f0cSAntonio Huete Jimenez while (p > line && *--p == '\\')
421*6eef5f0cSAntonio Huete Jimenez escaped = !escaped;
422*6eef5f0cSAntonio Huete Jimenez return escaped;
42301e196c8SJohn Marino }
42401e196c8SJohn Marino
425a34d5fb1SAntonio Huete Jimenez /*
426a34d5fb1SAntonio Huete Jimenez * Add the filename and lineno to the GNode so that we remember where it
427a34d5fb1SAntonio Huete Jimenez * was first defined.
428a34d5fb1SAntonio Huete Jimenez */
429a34d5fb1SAntonio Huete Jimenez static void
RememberLocation(GNode * gn)430*6eef5f0cSAntonio Huete Jimenez RememberLocation(GNode *gn)
431a34d5fb1SAntonio Huete Jimenez {
432*6eef5f0cSAntonio Huete Jimenez IncludedFile *curFile = CurFile();
433*6eef5f0cSAntonio Huete Jimenez gn->fname = Str_Intern(curFile->name.str);
434a34d5fb1SAntonio Huete Jimenez gn->lineno = curFile->lineno;
435a34d5fb1SAntonio Huete Jimenez }
436a34d5fb1SAntonio Huete Jimenez
437a34d5fb1SAntonio Huete Jimenez /*
43801e196c8SJohn Marino * Look in the table of keywords for one matching the given string.
439a34d5fb1SAntonio Huete Jimenez * Return the index of the keyword, or -1 if it isn't there.
44001e196c8SJohn Marino */
44101e196c8SJohn Marino static int
FindKeyword(const char * str)442*6eef5f0cSAntonio Huete Jimenez FindKeyword(const char *str)
44301e196c8SJohn Marino {
444a34d5fb1SAntonio Huete Jimenez int start = 0;
445a34d5fb1SAntonio Huete Jimenez int end = sizeof parseKeywords / sizeof parseKeywords[0] - 1;
44601e196c8SJohn Marino
447*6eef5f0cSAntonio Huete Jimenez while (start <= end) {
448a34d5fb1SAntonio Huete Jimenez int curr = start + (end - start) / 2;
449a34d5fb1SAntonio Huete Jimenez int diff = strcmp(str, parseKeywords[curr].name);
45001e196c8SJohn Marino
451a34d5fb1SAntonio Huete Jimenez if (diff == 0)
452a34d5fb1SAntonio Huete Jimenez return curr;
453a34d5fb1SAntonio Huete Jimenez if (diff < 0)
454a34d5fb1SAntonio Huete Jimenez end = curr - 1;
455a34d5fb1SAntonio Huete Jimenez else
456a34d5fb1SAntonio Huete Jimenez start = curr + 1;
457*6eef5f0cSAntonio Huete Jimenez }
458a34d5fb1SAntonio Huete Jimenez
459ca58f742SDaniel Fojt return -1;
46001e196c8SJohn Marino }
46101e196c8SJohn Marino
462*6eef5f0cSAntonio Huete Jimenez void
PrintLocation(FILE * f,bool useVars,const GNode * gn)463*6eef5f0cSAntonio Huete Jimenez PrintLocation(FILE *f, bool useVars, const GNode *gn)
464a34d5fb1SAntonio Huete Jimenez {
465a34d5fb1SAntonio Huete Jimenez char dirbuf[MAXPATHLEN + 1];
466a34d5fb1SAntonio Huete Jimenez FStr dir, base;
467*6eef5f0cSAntonio Huete Jimenez const char *fname;
468*6eef5f0cSAntonio Huete Jimenez unsigned lineno;
469a34d5fb1SAntonio Huete Jimenez
470*6eef5f0cSAntonio Huete Jimenez if (gn != NULL) {
471*6eef5f0cSAntonio Huete Jimenez fname = gn->fname;
472*6eef5f0cSAntonio Huete Jimenez lineno = gn->lineno;
473*6eef5f0cSAntonio Huete Jimenez } else if (includes.len > 0) {
474*6eef5f0cSAntonio Huete Jimenez IncludedFile *curFile = CurFile();
475*6eef5f0cSAntonio Huete Jimenez fname = curFile->name.str;
476*6eef5f0cSAntonio Huete Jimenez lineno = curFile->lineno;
477*6eef5f0cSAntonio Huete Jimenez } else
478*6eef5f0cSAntonio Huete Jimenez return;
479*6eef5f0cSAntonio Huete Jimenez
480*6eef5f0cSAntonio Huete Jimenez if (!useVars || fname[0] == '/' || strcmp(fname, "(stdin)") == 0) {
481*6eef5f0cSAntonio Huete Jimenez (void)fprintf(f, "\"%s\" line %u: ", fname, lineno);
482a34d5fb1SAntonio Huete Jimenez return;
483a34d5fb1SAntonio Huete Jimenez }
484a34d5fb1SAntonio Huete Jimenez
485a34d5fb1SAntonio Huete Jimenez dir = Var_Value(SCOPE_GLOBAL, ".PARSEDIR");
486a34d5fb1SAntonio Huete Jimenez if (dir.str == NULL)
487a34d5fb1SAntonio Huete Jimenez dir.str = ".";
488a34d5fb1SAntonio Huete Jimenez if (dir.str[0] != '/')
489a34d5fb1SAntonio Huete Jimenez dir.str = realpath(dir.str, dirbuf);
490a34d5fb1SAntonio Huete Jimenez
491a34d5fb1SAntonio Huete Jimenez base = Var_Value(SCOPE_GLOBAL, ".PARSEFILE");
492a34d5fb1SAntonio Huete Jimenez if (base.str == NULL)
493a34d5fb1SAntonio Huete Jimenez base.str = str_basename(fname);
494a34d5fb1SAntonio Huete Jimenez
495*6eef5f0cSAntonio Huete Jimenez (void)fprintf(f, "\"%s/%s\" line %u: ", dir.str, base.str, lineno);
496a34d5fb1SAntonio Huete Jimenez
497a34d5fb1SAntonio Huete Jimenez FStr_Done(&base);
498a34d5fb1SAntonio Huete Jimenez FStr_Done(&dir);
499a34d5fb1SAntonio Huete Jimenez }
500a34d5fb1SAntonio Huete Jimenez
501*6eef5f0cSAntonio Huete Jimenez static void MAKE_ATTR_PRINTFLIKE(5, 0)
ParseVErrorInternal(FILE * f,bool useVars,const GNode * gn,ParseErrorLevel level,const char * fmt,va_list ap)502*6eef5f0cSAntonio Huete Jimenez ParseVErrorInternal(FILE *f, bool useVars, const GNode *gn,
503*6eef5f0cSAntonio Huete Jimenez ParseErrorLevel level, const char *fmt, va_list ap)
50401e196c8SJohn Marino {
505*6eef5f0cSAntonio Huete Jimenez static bool fatal_warning_error_printed = false;
50601e196c8SJohn Marino
50701e196c8SJohn Marino (void)fprintf(f, "%s: ", progname);
50801e196c8SJohn Marino
509*6eef5f0cSAntonio Huete Jimenez PrintLocation(f, useVars, gn);
510*6eef5f0cSAntonio Huete Jimenez if (level == PARSE_WARNING)
51101e196c8SJohn Marino (void)fprintf(f, "warning: ");
51201e196c8SJohn Marino (void)vfprintf(f, fmt, ap);
51301e196c8SJohn Marino (void)fprintf(f, "\n");
51401e196c8SJohn Marino (void)fflush(f);
515a34d5fb1SAntonio Huete Jimenez
516*6eef5f0cSAntonio Huete Jimenez if (level == PARSE_FATAL)
517*6eef5f0cSAntonio Huete Jimenez parseErrors++;
518*6eef5f0cSAntonio Huete Jimenez if (level == PARSE_WARNING && opts.parseWarnFatal) {
519*6eef5f0cSAntonio Huete Jimenez if (!fatal_warning_error_printed) {
52001e196c8SJohn Marino Error("parsing warnings being treated as errors");
521*6eef5f0cSAntonio Huete Jimenez fatal_warning_error_printed = true;
522*6eef5f0cSAntonio Huete Jimenez }
523*6eef5f0cSAntonio Huete Jimenez parseErrors++;
52401e196c8SJohn Marino }
525a34d5fb1SAntonio Huete Jimenez
526*6eef5f0cSAntonio Huete Jimenez if (DEBUG(PARSE))
527*6eef5f0cSAntonio Huete Jimenez PrintStackTrace(false);
52801e196c8SJohn Marino }
52901e196c8SJohn Marino
530*6eef5f0cSAntonio Huete Jimenez static void MAKE_ATTR_PRINTFLIKE(3, 4)
ParseErrorInternal(const GNode * gn,ParseErrorLevel level,const char * fmt,...)531*6eef5f0cSAntonio Huete Jimenez ParseErrorInternal(const GNode *gn,
532*6eef5f0cSAntonio Huete Jimenez ParseErrorLevel level, const char *fmt, ...)
53301e196c8SJohn Marino {
53401e196c8SJohn Marino va_list ap;
53501e196c8SJohn Marino
53601e196c8SJohn Marino (void)fflush(stdout);
53701e196c8SJohn Marino va_start(ap, fmt);
538*6eef5f0cSAntonio Huete Jimenez ParseVErrorInternal(stderr, false, gn, level, fmt, ap);
539a34d5fb1SAntonio Huete Jimenez va_end(ap);
540a34d5fb1SAntonio Huete Jimenez
541*6eef5f0cSAntonio Huete Jimenez if (opts.debug_file != stdout && opts.debug_file != stderr) {
542a34d5fb1SAntonio Huete Jimenez va_start(ap, fmt);
543*6eef5f0cSAntonio Huete Jimenez ParseVErrorInternal(opts.debug_file, false, gn,
544*6eef5f0cSAntonio Huete Jimenez level, fmt, ap);
54501e196c8SJohn Marino va_end(ap);
54601e196c8SJohn Marino }
54701e196c8SJohn Marino }
54801e196c8SJohn Marino
549a34d5fb1SAntonio Huete Jimenez /*
550a34d5fb1SAntonio Huete Jimenez * Print a parse error message, including location information.
55101e196c8SJohn Marino *
552a34d5fb1SAntonio Huete Jimenez * If the level is PARSE_FATAL, continue parsing until the end of the
553a34d5fb1SAntonio Huete Jimenez * current top-level makefile, then exit (see Parse_File).
55401e196c8SJohn Marino *
555a34d5fb1SAntonio Huete Jimenez * Fmt is given without a trailing newline.
55601e196c8SJohn Marino */
55701e196c8SJohn Marino void
Parse_Error(ParseErrorLevel level,const char * fmt,...)558*6eef5f0cSAntonio Huete Jimenez Parse_Error(ParseErrorLevel level, const char *fmt, ...)
55901e196c8SJohn Marino {
56001e196c8SJohn Marino va_list ap;
56101e196c8SJohn Marino
56201e196c8SJohn Marino (void)fflush(stdout);
563*6eef5f0cSAntonio Huete Jimenez va_start(ap, fmt);
564*6eef5f0cSAntonio Huete Jimenez ParseVErrorInternal(stderr, true, NULL, level, fmt, ap);
56501e196c8SJohn Marino va_end(ap);
56601e196c8SJohn Marino
567*6eef5f0cSAntonio Huete Jimenez if (opts.debug_file != stdout && opts.debug_file != stderr) {
56801e196c8SJohn Marino va_start(ap, fmt);
569*6eef5f0cSAntonio Huete Jimenez ParseVErrorInternal(opts.debug_file, true, NULL,
570*6eef5f0cSAntonio Huete Jimenez level, fmt, ap);
57101e196c8SJohn Marino va_end(ap);
57201e196c8SJohn Marino }
57301e196c8SJohn Marino }
57401e196c8SJohn Marino
57501e196c8SJohn Marino
57601e196c8SJohn Marino /*
577*6eef5f0cSAntonio Huete Jimenez * Handle an .info, .warning or .error directive. For an .error directive,
578*6eef5f0cSAntonio Huete Jimenez * exit immediately.
57901e196c8SJohn Marino */
580a34d5fb1SAntonio Huete Jimenez static void
HandleMessage(ParseErrorLevel level,const char * levelName,const char * umsg)581*6eef5f0cSAntonio Huete Jimenez HandleMessage(ParseErrorLevel level, const char *levelName, const char *umsg)
58201e196c8SJohn Marino {
583a34d5fb1SAntonio Huete Jimenez char *xmsg;
58401e196c8SJohn Marino
585a34d5fb1SAntonio Huete Jimenez if (umsg[0] == '\0') {
586a34d5fb1SAntonio Huete Jimenez Parse_Error(PARSE_FATAL, "Missing argument for \".%s\"",
587a34d5fb1SAntonio Huete Jimenez levelName);
588a34d5fb1SAntonio Huete Jimenez return;
58901e196c8SJohn Marino }
59001e196c8SJohn Marino
591a34d5fb1SAntonio Huete Jimenez (void)Var_Subst(umsg, SCOPE_CMDLINE, VARE_WANTRES, &xmsg);
592a34d5fb1SAntonio Huete Jimenez /* TODO: handle errors */
59301e196c8SJohn Marino
594a34d5fb1SAntonio Huete Jimenez Parse_Error(level, "%s", xmsg);
595a34d5fb1SAntonio Huete Jimenez free(xmsg);
59601e196c8SJohn Marino
597a34d5fb1SAntonio Huete Jimenez if (level == PARSE_FATAL) {
598*6eef5f0cSAntonio Huete Jimenez PrintOnError(NULL, "\n");
59901e196c8SJohn Marino exit(1);
60001e196c8SJohn Marino }
60101e196c8SJohn Marino }
60201e196c8SJohn Marino
603a34d5fb1SAntonio Huete Jimenez /*
604*6eef5f0cSAntonio Huete Jimenez * Add the child to the parent's children, and for non-special targets, vice
605*6eef5f0cSAntonio Huete Jimenez * versa. Special targets such as .END do not need to be informed once the
606*6eef5f0cSAntonio Huete Jimenez * child target has been made.
60701e196c8SJohn Marino */
608a34d5fb1SAntonio Huete Jimenez static void
LinkSource(GNode * pgn,GNode * cgn,bool isSpecial)609*6eef5f0cSAntonio Huete Jimenez LinkSource(GNode *pgn, GNode *cgn, bool isSpecial)
61001e196c8SJohn Marino {
611a34d5fb1SAntonio Huete Jimenez if ((pgn->type & OP_DOUBLEDEP) && !Lst_IsEmpty(&pgn->cohorts))
612a34d5fb1SAntonio Huete Jimenez pgn = pgn->cohorts.last->datum;
61301e196c8SJohn Marino
614a34d5fb1SAntonio Huete Jimenez Lst_Append(&pgn->children, cgn);
615a34d5fb1SAntonio Huete Jimenez pgn->unmade++;
616a34d5fb1SAntonio Huete Jimenez
617a34d5fb1SAntonio Huete Jimenez /* Special targets like .END don't need any children. */
618a34d5fb1SAntonio Huete Jimenez if (!isSpecial)
619a34d5fb1SAntonio Huete Jimenez Lst_Append(&cgn->parents, pgn);
620a34d5fb1SAntonio Huete Jimenez
62101e196c8SJohn Marino if (DEBUG(PARSE)) {
622*6eef5f0cSAntonio Huete Jimenez debug_printf("# LinkSource: added child %s - %s\n",
623*6eef5f0cSAntonio Huete Jimenez pgn->name, cgn->name);
62401e196c8SJohn Marino Targ_PrintNode(pgn, 0);
62501e196c8SJohn Marino Targ_PrintNode(cgn, 0);
62601e196c8SJohn Marino }
62701e196c8SJohn Marino }
62801e196c8SJohn Marino
629a34d5fb1SAntonio Huete Jimenez /* Add the node to each target from the current dependency group. */
630a34d5fb1SAntonio Huete Jimenez static void
LinkToTargets(GNode * gn,bool isSpecial)631*6eef5f0cSAntonio Huete Jimenez LinkToTargets(GNode *gn, bool isSpecial)
63201e196c8SJohn Marino {
633a34d5fb1SAntonio Huete Jimenez GNodeListNode *ln;
634a34d5fb1SAntonio Huete Jimenez
635a34d5fb1SAntonio Huete Jimenez for (ln = targets->first; ln != NULL; ln = ln->next)
636a34d5fb1SAntonio Huete Jimenez LinkSource(ln->datum, gn, isSpecial);
63701e196c8SJohn Marino }
63801e196c8SJohn Marino
639*6eef5f0cSAntonio Huete Jimenez static bool
TryApplyDependencyOperator(GNode * gn,GNodeType op)640a34d5fb1SAntonio Huete Jimenez TryApplyDependencyOperator(GNode *gn, GNodeType op)
641a34d5fb1SAntonio Huete Jimenez {
64201e196c8SJohn Marino /*
643a34d5fb1SAntonio Huete Jimenez * If the node occurred on the left-hand side of a dependency and the
644a34d5fb1SAntonio Huete Jimenez * operator also defines a dependency, they must match.
645a34d5fb1SAntonio Huete Jimenez */
646a34d5fb1SAntonio Huete Jimenez if ((op & OP_OPMASK) && (gn->type & OP_OPMASK) &&
647a34d5fb1SAntonio Huete Jimenez ((op & OP_OPMASK) != (gn->type & OP_OPMASK))) {
648a34d5fb1SAntonio Huete Jimenez Parse_Error(PARSE_FATAL, "Inconsistent operator for %s",
649a34d5fb1SAntonio Huete Jimenez gn->name);
650*6eef5f0cSAntonio Huete Jimenez return false;
651a34d5fb1SAntonio Huete Jimenez }
652a34d5fb1SAntonio Huete Jimenez
653a34d5fb1SAntonio Huete Jimenez if (op == OP_DOUBLEDEP && (gn->type & OP_OPMASK) == OP_DOUBLEDEP) {
654a34d5fb1SAntonio Huete Jimenez /*
655a34d5fb1SAntonio Huete Jimenez * If the node was of the left-hand side of a '::' operator,
656a34d5fb1SAntonio Huete Jimenez * we need to create a new instance of it for the children
657a34d5fb1SAntonio Huete Jimenez * and commands on this dependency line since each of these
658a34d5fb1SAntonio Huete Jimenez * dependency groups has its own attributes and commands,
659a34d5fb1SAntonio Huete Jimenez * separate from the others.
660a34d5fb1SAntonio Huete Jimenez *
661a34d5fb1SAntonio Huete Jimenez * The new instance is placed on the 'cohorts' list of the
662a34d5fb1SAntonio Huete Jimenez * initial one (note the initial one is not on its own
663a34d5fb1SAntonio Huete Jimenez * cohorts list) and the new instance is linked to all
664a34d5fb1SAntonio Huete Jimenez * parents of the initial instance.
66501e196c8SJohn Marino */
66601e196c8SJohn Marino GNode *cohort;
66701e196c8SJohn Marino
66801e196c8SJohn Marino /*
669a34d5fb1SAntonio Huete Jimenez * Propagate copied bits to the initial node. They'll be
670a34d5fb1SAntonio Huete Jimenez * propagated back to the rest of the cohorts later.
67101e196c8SJohn Marino */
672*6eef5f0cSAntonio Huete Jimenez gn->type |= op & (unsigned)~OP_OPMASK;
67301e196c8SJohn Marino
674a34d5fb1SAntonio Huete Jimenez cohort = Targ_NewInternalNode(gn->name);
6755f1e34d9SAlexandre Perrin if (doing_depend)
676*6eef5f0cSAntonio Huete Jimenez RememberLocation(cohort);
67701e196c8SJohn Marino /*
678a34d5fb1SAntonio Huete Jimenez * Make the cohort invisible as well to avoid duplicating it
679a34d5fb1SAntonio Huete Jimenez * into other variables. True, parents of this target won't
680a34d5fb1SAntonio Huete Jimenez * tend to do anything with their local variables, but better
681a34d5fb1SAntonio Huete Jimenez * safe than sorry.
682a34d5fb1SAntonio Huete Jimenez *
683a34d5fb1SAntonio Huete Jimenez * (I think this is pointless now, since the relevant list
68401e196c8SJohn Marino * traversals will no longer see this node anyway. -mycroft)
68501e196c8SJohn Marino */
68601e196c8SJohn Marino cohort->type = op | OP_INVISIBLE;
687a34d5fb1SAntonio Huete Jimenez Lst_Append(&gn->cohorts, cohort);
68801e196c8SJohn Marino cohort->centurion = gn;
689a34d5fb1SAntonio Huete Jimenez gn->unmade_cohorts++;
69001e196c8SJohn Marino snprintf(cohort->cohort_num, sizeof cohort->cohort_num, "#%d",
691a34d5fb1SAntonio Huete Jimenez (unsigned int)gn->unmade_cohorts % 1000000);
69201e196c8SJohn Marino } else {
69301e196c8SJohn Marino /*
694a34d5fb1SAntonio Huete Jimenez * We don't want to nuke any previous flags (whatever they
695a34d5fb1SAntonio Huete Jimenez * were) so we just OR the new operator into the old.
69601e196c8SJohn Marino */
69701e196c8SJohn Marino gn->type |= op;
69801e196c8SJohn Marino }
69901e196c8SJohn Marino
700*6eef5f0cSAntonio Huete Jimenez return true;
70101e196c8SJohn Marino }
70201e196c8SJohn Marino
703a34d5fb1SAntonio Huete Jimenez static void
ApplyDependencyOperator(GNodeType op)704a34d5fb1SAntonio Huete Jimenez ApplyDependencyOperator(GNodeType op)
705a34d5fb1SAntonio Huete Jimenez {
706a34d5fb1SAntonio Huete Jimenez GNodeListNode *ln;
707a34d5fb1SAntonio Huete Jimenez
708a34d5fb1SAntonio Huete Jimenez for (ln = targets->first; ln != NULL; ln = ln->next)
709a34d5fb1SAntonio Huete Jimenez if (!TryApplyDependencyOperator(ln->datum, op))
710a34d5fb1SAntonio Huete Jimenez break;
711a34d5fb1SAntonio Huete Jimenez }
712a34d5fb1SAntonio Huete Jimenez
713a34d5fb1SAntonio Huete Jimenez /*
714a34d5fb1SAntonio Huete Jimenez * We add a .WAIT node in the dependency list. After any dynamic dependencies
715a34d5fb1SAntonio Huete Jimenez * (and filename globbing) have happened, it is given a dependency on each
716a34d5fb1SAntonio Huete Jimenez * previous child, back until the previous .WAIT node. The next child won't
717a34d5fb1SAntonio Huete Jimenez * be scheduled until the .WAIT node is built.
71801e196c8SJohn Marino *
719a34d5fb1SAntonio Huete Jimenez * We give each .WAIT node a unique name (mainly for diagnostics).
72001e196c8SJohn Marino */
72101e196c8SJohn Marino static void
ApplyDependencySourceWait(bool isSpecial)722*6eef5f0cSAntonio Huete Jimenez ApplyDependencySourceWait(bool isSpecial)
72301e196c8SJohn Marino {
724*6eef5f0cSAntonio Huete Jimenez static unsigned wait_number = 0;
725*6eef5f0cSAntonio Huete Jimenez char name[6 + 10 + 1];
726a34d5fb1SAntonio Huete Jimenez GNode *gn;
72701e196c8SJohn Marino
728*6eef5f0cSAntonio Huete Jimenez snprintf(name, sizeof name, ".WAIT_%u", ++wait_number);
729*6eef5f0cSAntonio Huete Jimenez gn = Targ_NewInternalNode(name);
7305f1e34d9SAlexandre Perrin if (doing_depend)
731*6eef5f0cSAntonio Huete Jimenez RememberLocation(gn);
73201e196c8SJohn Marino gn->type = OP_WAIT | OP_PHONY | OP_DEPENDS | OP_NOTMAIN;
733a34d5fb1SAntonio Huete Jimenez LinkToTargets(gn, isSpecial);
73401e196c8SJohn Marino }
73501e196c8SJohn Marino
736*6eef5f0cSAntonio Huete Jimenez static bool
ApplyDependencySourceKeyword(const char * src,ParseSpecial special)737*6eef5f0cSAntonio Huete Jimenez ApplyDependencySourceKeyword(const char *src, ParseSpecial special)
738a34d5fb1SAntonio Huete Jimenez {
739a34d5fb1SAntonio Huete Jimenez int keywd;
740*6eef5f0cSAntonio Huete Jimenez GNodeType targetAttr;
741a34d5fb1SAntonio Huete Jimenez
742a34d5fb1SAntonio Huete Jimenez if (*src != '.' || !ch_isupper(src[1]))
743*6eef5f0cSAntonio Huete Jimenez return false;
744a34d5fb1SAntonio Huete Jimenez
745*6eef5f0cSAntonio Huete Jimenez keywd = FindKeyword(src);
746a34d5fb1SAntonio Huete Jimenez if (keywd == -1)
747*6eef5f0cSAntonio Huete Jimenez return false;
748a34d5fb1SAntonio Huete Jimenez
749*6eef5f0cSAntonio Huete Jimenez targetAttr = parseKeywords[keywd].targetAttr;
750*6eef5f0cSAntonio Huete Jimenez if (targetAttr != OP_NONE) {
751*6eef5f0cSAntonio Huete Jimenez ApplyDependencyOperator(targetAttr);
752*6eef5f0cSAntonio Huete Jimenez return true;
753a34d5fb1SAntonio Huete Jimenez }
754*6eef5f0cSAntonio Huete Jimenez if (parseKeywords[keywd].special == SP_WAIT) {
755*6eef5f0cSAntonio Huete Jimenez ApplyDependencySourceWait(special != SP_NOT);
756*6eef5f0cSAntonio Huete Jimenez return true;
757a34d5fb1SAntonio Huete Jimenez }
758*6eef5f0cSAntonio Huete Jimenez return false;
759a34d5fb1SAntonio Huete Jimenez }
760a34d5fb1SAntonio Huete Jimenez
76101e196c8SJohn Marino /*
762*6eef5f0cSAntonio Huete Jimenez * In a line like ".MAIN: source1 source2", add all sources to the list of
763*6eef5f0cSAntonio Huete Jimenez * things to create, but only if the user didn't specify a target on the
764*6eef5f0cSAntonio Huete Jimenez * command line and .MAIN occurs for the first time.
765a34d5fb1SAntonio Huete Jimenez *
766*6eef5f0cSAntonio Huete Jimenez * See HandleDependencyTargetSpecial, branch SP_MAIN.
767a34d5fb1SAntonio Huete Jimenez * See unit-tests/cond-func-make-main.mk.
76801e196c8SJohn Marino */
769*6eef5f0cSAntonio Huete Jimenez static void
ApplyDependencySourceMain(const char * src)770*6eef5f0cSAntonio Huete Jimenez ApplyDependencySourceMain(const char *src)
771*6eef5f0cSAntonio Huete Jimenez {
772a34d5fb1SAntonio Huete Jimenez Lst_Append(&opts.create, bmake_strdup(src));
77301e196c8SJohn Marino /*
77401e196c8SJohn Marino * Add the name to the .TARGETS variable as well, so the user can
77501e196c8SJohn Marino * employ that, if desired.
77601e196c8SJohn Marino */
777a34d5fb1SAntonio Huete Jimenez Global_Append(".TARGETS", src);
778a34d5fb1SAntonio Huete Jimenez }
77901e196c8SJohn Marino
780*6eef5f0cSAntonio Huete Jimenez /*
781*6eef5f0cSAntonio Huete Jimenez * For the sources of a .ORDER target, create predecessor/successor links
782*6eef5f0cSAntonio Huete Jimenez * between the previous source and the current one.
783*6eef5f0cSAntonio Huete Jimenez */
784a34d5fb1SAntonio Huete Jimenez static void
ApplyDependencySourceOrder(const char * src)785*6eef5f0cSAntonio Huete Jimenez ApplyDependencySourceOrder(const char *src)
786a34d5fb1SAntonio Huete Jimenez {
787a34d5fb1SAntonio Huete Jimenez GNode *gn;
788*6eef5f0cSAntonio Huete Jimenez
789a34d5fb1SAntonio Huete Jimenez gn = Targ_GetNode(src);
7905f1e34d9SAlexandre Perrin if (doing_depend)
791*6eef5f0cSAntonio Huete Jimenez RememberLocation(gn);
792a34d5fb1SAntonio Huete Jimenez if (order_pred != NULL) {
793a34d5fb1SAntonio Huete Jimenez Lst_Append(&order_pred->order_succ, gn);
794a34d5fb1SAntonio Huete Jimenez Lst_Append(&gn->order_pred, order_pred);
79501e196c8SJohn Marino if (DEBUG(PARSE)) {
796*6eef5f0cSAntonio Huete Jimenez debug_printf(
797*6eef5f0cSAntonio Huete Jimenez "# .ORDER forces '%s' to be made before '%s'\n",
798*6eef5f0cSAntonio Huete Jimenez order_pred->name, gn->name);
799a34d5fb1SAntonio Huete Jimenez Targ_PrintNode(order_pred, 0);
80001e196c8SJohn Marino Targ_PrintNode(gn, 0);
80101e196c8SJohn Marino }
80201e196c8SJohn Marino }
80301e196c8SJohn Marino /*
80401e196c8SJohn Marino * The current source now becomes the predecessor for the next one.
80501e196c8SJohn Marino */
806a34d5fb1SAntonio Huete Jimenez order_pred = gn;
807a34d5fb1SAntonio Huete Jimenez }
80801e196c8SJohn Marino
809*6eef5f0cSAntonio Huete Jimenez /* The source is not an attribute, so find/create a node for it. */
810a34d5fb1SAntonio Huete Jimenez static void
ApplyDependencySourceOther(const char * src,GNodeType targetAttr,ParseSpecial special)811*6eef5f0cSAntonio Huete Jimenez ApplyDependencySourceOther(const char *src, GNodeType targetAttr,
812*6eef5f0cSAntonio Huete Jimenez ParseSpecial special)
813a34d5fb1SAntonio Huete Jimenez {
814a34d5fb1SAntonio Huete Jimenez GNode *gn;
815a34d5fb1SAntonio Huete Jimenez
816a34d5fb1SAntonio Huete Jimenez gn = Targ_GetNode(src);
8175f1e34d9SAlexandre Perrin if (doing_depend)
818*6eef5f0cSAntonio Huete Jimenez RememberLocation(gn);
819*6eef5f0cSAntonio Huete Jimenez if (targetAttr != OP_NONE)
820*6eef5f0cSAntonio Huete Jimenez gn->type |= targetAttr;
821a34d5fb1SAntonio Huete Jimenez else
822*6eef5f0cSAntonio Huete Jimenez LinkToTargets(gn, special != SP_NOT);
82301e196c8SJohn Marino }
82401e196c8SJohn Marino
825a34d5fb1SAntonio Huete Jimenez /*
826a34d5fb1SAntonio Huete Jimenez * Given the name of a source in a dependency line, figure out if it is an
827*6eef5f0cSAntonio Huete Jimenez * attribute (such as .SILENT) and if so, apply it to all targets. Otherwise
828a34d5fb1SAntonio Huete Jimenez * decide if there is some attribute which should be applied *to* the source
829a34d5fb1SAntonio Huete Jimenez * because of some special target (such as .PHONY) and apply it if so.
830*6eef5f0cSAntonio Huete Jimenez * Otherwise, make the source a child of the targets.
83101e196c8SJohn Marino */
83201e196c8SJohn Marino static void
ApplyDependencySource(GNodeType targetAttr,const char * src,ParseSpecial special)833*6eef5f0cSAntonio Huete Jimenez ApplyDependencySource(GNodeType targetAttr, const char *src,
834*6eef5f0cSAntonio Huete Jimenez ParseSpecial special)
83501e196c8SJohn Marino {
836*6eef5f0cSAntonio Huete Jimenez if (ApplyDependencySourceKeyword(src, special))
837a34d5fb1SAntonio Huete Jimenez return;
83801e196c8SJohn Marino
839*6eef5f0cSAntonio Huete Jimenez if (special == SP_MAIN)
840*6eef5f0cSAntonio Huete Jimenez ApplyDependencySourceMain(src);
841*6eef5f0cSAntonio Huete Jimenez else if (special == SP_ORDER)
842*6eef5f0cSAntonio Huete Jimenez ApplyDependencySourceOrder(src);
843a34d5fb1SAntonio Huete Jimenez else
844*6eef5f0cSAntonio Huete Jimenez ApplyDependencySourceOther(src, targetAttr, special);
845a34d5fb1SAntonio Huete Jimenez }
84601e196c8SJohn Marino
8476a91b982SJohn Marino /*
848a34d5fb1SAntonio Huete Jimenez * If we have yet to decide on a main target to make, in the absence of any
849a34d5fb1SAntonio Huete Jimenez * user input, we want the first target on the first dependency line that is
850a34d5fb1SAntonio Huete Jimenez * actually a real target (i.e. isn't a .USE or .EXEC rule) to be made.
8516a91b982SJohn Marino */
852a34d5fb1SAntonio Huete Jimenez static void
MaybeUpdateMainTarget(void)853*6eef5f0cSAntonio Huete Jimenez MaybeUpdateMainTarget(void)
854a34d5fb1SAntonio Huete Jimenez {
855a34d5fb1SAntonio Huete Jimenez GNodeListNode *ln;
8566a91b982SJohn Marino
857a34d5fb1SAntonio Huete Jimenez if (mainNode != NULL)
858a34d5fb1SAntonio Huete Jimenez return;
859a34d5fb1SAntonio Huete Jimenez
860a34d5fb1SAntonio Huete Jimenez for (ln = targets->first; ln != NULL; ln = ln->next) {
861a34d5fb1SAntonio Huete Jimenez GNode *gn = ln->datum;
862*6eef5f0cSAntonio Huete Jimenez if (GNode_IsMainCandidate(gn)) {
863a34d5fb1SAntonio Huete Jimenez DEBUG1(MAKE, "Setting main node to \"%s\"\n", gn->name);
864a34d5fb1SAntonio Huete Jimenez mainNode = gn;
865a34d5fb1SAntonio Huete Jimenez return;
866a34d5fb1SAntonio Huete Jimenez }
867a34d5fb1SAntonio Huete Jimenez }
868a34d5fb1SAntonio Huete Jimenez }
869a34d5fb1SAntonio Huete Jimenez
870a34d5fb1SAntonio Huete Jimenez static void
InvalidLineType(const char * line)871*6eef5f0cSAntonio Huete Jimenez InvalidLineType(const char *line)
872a34d5fb1SAntonio Huete Jimenez {
873*6eef5f0cSAntonio Huete Jimenez if (strncmp(line, "<<<<<<", 6) == 0 ||
874*6eef5f0cSAntonio Huete Jimenez strncmp(line, ">>>>>>", 6) == 0)
875a34d5fb1SAntonio Huete Jimenez Parse_Error(PARSE_FATAL,
876*6eef5f0cSAntonio Huete Jimenez "Makefile appears to contain unresolved CVS/RCS/??? merge conflicts");
877*6eef5f0cSAntonio Huete Jimenez else if (line[0] == '.') {
878*6eef5f0cSAntonio Huete Jimenez const char *dirstart = line + 1;
879a34d5fb1SAntonio Huete Jimenez const char *dirend;
880a34d5fb1SAntonio Huete Jimenez cpp_skip_whitespace(&dirstart);
881a34d5fb1SAntonio Huete Jimenez dirend = dirstart;
882a34d5fb1SAntonio Huete Jimenez while (ch_isalnum(*dirend) || *dirend == '-')
883a34d5fb1SAntonio Huete Jimenez dirend++;
884a34d5fb1SAntonio Huete Jimenez Parse_Error(PARSE_FATAL, "Unknown directive \"%.*s\"",
885a34d5fb1SAntonio Huete Jimenez (int)(dirend - dirstart), dirstart);
886a34d5fb1SAntonio Huete Jimenez } else
887a34d5fb1SAntonio Huete Jimenez Parse_Error(PARSE_FATAL, "Invalid line type");
888a34d5fb1SAntonio Huete Jimenez }
8896a91b982SJohn Marino
890a34d5fb1SAntonio Huete Jimenez static void
ParseDependencyTargetWord(char ** pp,const char * lstart)891*6eef5f0cSAntonio Huete Jimenez ParseDependencyTargetWord(char **pp, const char *lstart)
892a34d5fb1SAntonio Huete Jimenez {
893a34d5fb1SAntonio Huete Jimenez const char *cp = *pp;
894a34d5fb1SAntonio Huete Jimenez
895a34d5fb1SAntonio Huete Jimenez while (*cp != '\0') {
896a34d5fb1SAntonio Huete Jimenez if ((ch_isspace(*cp) || *cp == '!' || *cp == ':' ||
897a34d5fb1SAntonio Huete Jimenez *cp == '(') &&
898*6eef5f0cSAntonio Huete Jimenez !IsEscaped(lstart, cp))
899a34d5fb1SAntonio Huete Jimenez break;
900a34d5fb1SAntonio Huete Jimenez
90101e196c8SJohn Marino if (*cp == '$') {
90201e196c8SJohn Marino /*
90301e196c8SJohn Marino * Must be a dynamic source (would have been expanded
904*6eef5f0cSAntonio Huete Jimenez * otherwise).
9056a91b982SJohn Marino *
906a34d5fb1SAntonio Huete Jimenez * There should be no errors in this, as they would
907a34d5fb1SAntonio Huete Jimenez * have been discovered in the initial Var_Subst and
908a34d5fb1SAntonio Huete Jimenez * we wouldn't be here.
90901e196c8SJohn Marino */
910*6eef5f0cSAntonio Huete Jimenez FStr val;
911a34d5fb1SAntonio Huete Jimenez
912*6eef5f0cSAntonio Huete Jimenez (void)Var_Parse(&cp, SCOPE_CMDLINE,
913*6eef5f0cSAntonio Huete Jimenez VARE_PARSE_ONLY, &val);
914*6eef5f0cSAntonio Huete Jimenez FStr_Done(&val);
915a34d5fb1SAntonio Huete Jimenez } else
916a34d5fb1SAntonio Huete Jimenez cp++;
91701e196c8SJohn Marino }
9186a91b982SJohn Marino
919*6eef5f0cSAntonio Huete Jimenez *pp += cp - *pp;
92001e196c8SJohn Marino }
92101e196c8SJohn Marino
922*6eef5f0cSAntonio Huete Jimenez /*
923*6eef5f0cSAntonio Huete Jimenez * Handle special targets like .PATH, .DEFAULT, .BEGIN, .ORDER.
924*6eef5f0cSAntonio Huete Jimenez *
925*6eef5f0cSAntonio Huete Jimenez * See the tests deptgt-*.mk.
926*6eef5f0cSAntonio Huete Jimenez */
927a34d5fb1SAntonio Huete Jimenez static void
HandleDependencyTargetSpecial(const char * targetName,ParseSpecial * inout_special,SearchPathList ** inout_paths)928*6eef5f0cSAntonio Huete Jimenez HandleDependencyTargetSpecial(const char *targetName,
929*6eef5f0cSAntonio Huete Jimenez ParseSpecial *inout_special,
930a34d5fb1SAntonio Huete Jimenez SearchPathList **inout_paths)
931a34d5fb1SAntonio Huete Jimenez {
932*6eef5f0cSAntonio Huete Jimenez switch (*inout_special) {
933a34d5fb1SAntonio Huete Jimenez case SP_PATH:
934a34d5fb1SAntonio Huete Jimenez if (*inout_paths == NULL)
935a34d5fb1SAntonio Huete Jimenez *inout_paths = Lst_New();
936a34d5fb1SAntonio Huete Jimenez Lst_Append(*inout_paths, &dirSearchPath);
93701e196c8SJohn Marino break;
938a34d5fb1SAntonio Huete Jimenez case SP_MAIN:
939a34d5fb1SAntonio Huete Jimenez /*
940a34d5fb1SAntonio Huete Jimenez * Allow targets from the command line to override the
941a34d5fb1SAntonio Huete Jimenez * .MAIN node.
942a34d5fb1SAntonio Huete Jimenez */
943a34d5fb1SAntonio Huete Jimenez if (!Lst_IsEmpty(&opts.create))
944*6eef5f0cSAntonio Huete Jimenez *inout_special = SP_NOT;
94501e196c8SJohn Marino break;
946a34d5fb1SAntonio Huete Jimenez case SP_BEGIN:
947a34d5fb1SAntonio Huete Jimenez case SP_END:
948a34d5fb1SAntonio Huete Jimenez case SP_STALE:
949a34d5fb1SAntonio Huete Jimenez case SP_ERROR:
950a34d5fb1SAntonio Huete Jimenez case SP_INTERRUPT: {
951a34d5fb1SAntonio Huete Jimenez GNode *gn = Targ_GetNode(targetName);
9525f1e34d9SAlexandre Perrin if (doing_depend)
953*6eef5f0cSAntonio Huete Jimenez RememberLocation(gn);
95401e196c8SJohn Marino gn->type |= OP_NOTMAIN | OP_SPECIAL;
955a34d5fb1SAntonio Huete Jimenez Lst_Append(targets, gn);
95601e196c8SJohn Marino break;
957a34d5fb1SAntonio Huete Jimenez }
958a34d5fb1SAntonio Huete Jimenez case SP_DEFAULT: {
959a34d5fb1SAntonio Huete Jimenez /*
960a34d5fb1SAntonio Huete Jimenez * Need to create a node to hang commands on, but we don't
961a34d5fb1SAntonio Huete Jimenez * want it in the graph, nor do we want it to be the Main
962a34d5fb1SAntonio Huete Jimenez * Target. We claim the node is a transformation rule to make
963a34d5fb1SAntonio Huete Jimenez * life easier later, when we'll use Make_HandleUse to
964a34d5fb1SAntonio Huete Jimenez * actually apply the .DEFAULT commands.
965a34d5fb1SAntonio Huete Jimenez */
966a34d5fb1SAntonio Huete Jimenez GNode *gn = GNode_New(".DEFAULT");
967a34d5fb1SAntonio Huete Jimenez gn->type |= OP_NOTMAIN | OP_TRANSFORM;
968a34d5fb1SAntonio Huete Jimenez Lst_Append(targets, gn);
969a34d5fb1SAntonio Huete Jimenez defaultNode = gn;
97001e196c8SJohn Marino break;
971a34d5fb1SAntonio Huete Jimenez }
972a34d5fb1SAntonio Huete Jimenez case SP_DELETE_ON_ERROR:
973*6eef5f0cSAntonio Huete Jimenez deleteOnError = true;
974ca58f742SDaniel Fojt break;
975a34d5fb1SAntonio Huete Jimenez case SP_NOTPARALLEL:
976a34d5fb1SAntonio Huete Jimenez opts.maxJobs = 1;
97701e196c8SJohn Marino break;
978a34d5fb1SAntonio Huete Jimenez case SP_SINGLESHELL:
979*6eef5f0cSAntonio Huete Jimenez opts.compatMake = true;
98001e196c8SJohn Marino break;
981a34d5fb1SAntonio Huete Jimenez case SP_ORDER:
982a34d5fb1SAntonio Huete Jimenez order_pred = NULL;
98301e196c8SJohn Marino break;
98401e196c8SJohn Marino default:
98501e196c8SJohn Marino break;
98601e196c8SJohn Marino }
987a34d5fb1SAntonio Huete Jimenez }
988a34d5fb1SAntonio Huete Jimenez
989*6eef5f0cSAntonio Huete Jimenez static bool
HandleDependencyTargetPath(const char * suffixName,SearchPathList ** inout_paths)990*6eef5f0cSAntonio Huete Jimenez HandleDependencyTargetPath(const char *suffixName,
991a34d5fb1SAntonio Huete Jimenez SearchPathList **inout_paths)
992a34d5fb1SAntonio Huete Jimenez {
993a34d5fb1SAntonio Huete Jimenez SearchPath *path;
99401e196c8SJohn Marino
995a34d5fb1SAntonio Huete Jimenez path = Suff_GetPath(suffixName);
99601e196c8SJohn Marino if (path == NULL) {
99701e196c8SJohn Marino Parse_Error(PARSE_FATAL,
998a34d5fb1SAntonio Huete Jimenez "Suffix '%s' not defined (yet)", suffixName);
999*6eef5f0cSAntonio Huete Jimenez return false;
100001e196c8SJohn Marino }
1001a34d5fb1SAntonio Huete Jimenez
1002a34d5fb1SAntonio Huete Jimenez if (*inout_paths == NULL)
1003a34d5fb1SAntonio Huete Jimenez *inout_paths = Lst_New();
1004a34d5fb1SAntonio Huete Jimenez Lst_Append(*inout_paths, path);
1005a34d5fb1SAntonio Huete Jimenez
1006*6eef5f0cSAntonio Huete Jimenez return true;
100701e196c8SJohn Marino }
100801e196c8SJohn Marino
1009*6eef5f0cSAntonio Huete Jimenez /* See if it's a special target and if so set inout_special to match it. */
1010*6eef5f0cSAntonio Huete Jimenez static bool
HandleDependencyTarget(const char * targetName,ParseSpecial * inout_special,GNodeType * inout_targetAttr,SearchPathList ** inout_paths)1011*6eef5f0cSAntonio Huete Jimenez HandleDependencyTarget(const char *targetName,
1012*6eef5f0cSAntonio Huete Jimenez ParseSpecial *inout_special,
1013*6eef5f0cSAntonio Huete Jimenez GNodeType *inout_targetAttr,
1014*6eef5f0cSAntonio Huete Jimenez SearchPathList **inout_paths)
1015a34d5fb1SAntonio Huete Jimenez {
1016a34d5fb1SAntonio Huete Jimenez int keywd;
1017a34d5fb1SAntonio Huete Jimenez
1018a34d5fb1SAntonio Huete Jimenez if (!(targetName[0] == '.' && ch_isupper(targetName[1])))
1019*6eef5f0cSAntonio Huete Jimenez return true;
1020a34d5fb1SAntonio Huete Jimenez
1021a34d5fb1SAntonio Huete Jimenez /*
1022a34d5fb1SAntonio Huete Jimenez * See if the target is a special target that must have it
1023a34d5fb1SAntonio Huete Jimenez * or its sources handled specially.
1024a34d5fb1SAntonio Huete Jimenez */
1025*6eef5f0cSAntonio Huete Jimenez keywd = FindKeyword(targetName);
1026a34d5fb1SAntonio Huete Jimenez if (keywd != -1) {
1027*6eef5f0cSAntonio Huete Jimenez if (*inout_special == SP_PATH &&
1028*6eef5f0cSAntonio Huete Jimenez parseKeywords[keywd].special != SP_PATH) {
1029a34d5fb1SAntonio Huete Jimenez Parse_Error(PARSE_FATAL, "Mismatched special targets");
1030*6eef5f0cSAntonio Huete Jimenez return false;
1031a34d5fb1SAntonio Huete Jimenez }
1032a34d5fb1SAntonio Huete Jimenez
1033*6eef5f0cSAntonio Huete Jimenez *inout_special = parseKeywords[keywd].special;
1034*6eef5f0cSAntonio Huete Jimenez *inout_targetAttr = parseKeywords[keywd].targetAttr;
1035a34d5fb1SAntonio Huete Jimenez
1036*6eef5f0cSAntonio Huete Jimenez HandleDependencyTargetSpecial(targetName, inout_special,
1037a34d5fb1SAntonio Huete Jimenez inout_paths);
1038a34d5fb1SAntonio Huete Jimenez
1039a34d5fb1SAntonio Huete Jimenez } else if (strncmp(targetName, ".PATH", 5) == 0) {
1040*6eef5f0cSAntonio Huete Jimenez *inout_special = SP_PATH;
1041*6eef5f0cSAntonio Huete Jimenez if (!HandleDependencyTargetPath(targetName + 5, inout_paths))
1042*6eef5f0cSAntonio Huete Jimenez return false;
1043a34d5fb1SAntonio Huete Jimenez }
1044*6eef5f0cSAntonio Huete Jimenez return true;
1045a34d5fb1SAntonio Huete Jimenez }
1046a34d5fb1SAntonio Huete Jimenez
1047a34d5fb1SAntonio Huete Jimenez static void
HandleSingleDependencyTargetMundane(const char * name)1048*6eef5f0cSAntonio Huete Jimenez HandleSingleDependencyTargetMundane(const char *name)
1049a34d5fb1SAntonio Huete Jimenez {
1050*6eef5f0cSAntonio Huete Jimenez GNode *gn = Suff_IsTransform(name)
1051*6eef5f0cSAntonio Huete Jimenez ? Suff_AddTransform(name)
1052*6eef5f0cSAntonio Huete Jimenez : Targ_GetNode(name);
10535f1e34d9SAlexandre Perrin if (doing_depend)
1054*6eef5f0cSAntonio Huete Jimenez RememberLocation(gn);
105501e196c8SJohn Marino
1056a34d5fb1SAntonio Huete Jimenez Lst_Append(targets, gn);
105701e196c8SJohn Marino }
1058*6eef5f0cSAntonio Huete Jimenez
1059*6eef5f0cSAntonio Huete Jimenez static void
HandleDependencyTargetMundane(const char * targetName)1060*6eef5f0cSAntonio Huete Jimenez HandleDependencyTargetMundane(const char *targetName)
1061*6eef5f0cSAntonio Huete Jimenez {
1062*6eef5f0cSAntonio Huete Jimenez if (Dir_HasWildcards(targetName)) {
1063*6eef5f0cSAntonio Huete Jimenez StringList targetNames = LST_INIT;
1064*6eef5f0cSAntonio Huete Jimenez
1065*6eef5f0cSAntonio Huete Jimenez SearchPath *emptyPath = SearchPath_New();
1066*6eef5f0cSAntonio Huete Jimenez SearchPath_Expand(emptyPath, targetName, &targetNames);
1067*6eef5f0cSAntonio Huete Jimenez SearchPath_Free(emptyPath);
1068*6eef5f0cSAntonio Huete Jimenez
1069*6eef5f0cSAntonio Huete Jimenez while (!Lst_IsEmpty(&targetNames)) {
1070*6eef5f0cSAntonio Huete Jimenez char *targName = Lst_Dequeue(&targetNames);
1071*6eef5f0cSAntonio Huete Jimenez HandleSingleDependencyTargetMundane(targName);
1072*6eef5f0cSAntonio Huete Jimenez free(targName);
1073*6eef5f0cSAntonio Huete Jimenez }
1074*6eef5f0cSAntonio Huete Jimenez } else
1075*6eef5f0cSAntonio Huete Jimenez HandleSingleDependencyTargetMundane(targetName);
107601e196c8SJohn Marino }
107701e196c8SJohn Marino
1078a34d5fb1SAntonio Huete Jimenez static void
SkipExtraTargets(char ** pp,const char * lstart)1079*6eef5f0cSAntonio Huete Jimenez SkipExtraTargets(char **pp, const char *lstart)
1080a34d5fb1SAntonio Huete Jimenez {
1081*6eef5f0cSAntonio Huete Jimenez bool warning = false;
1082*6eef5f0cSAntonio Huete Jimenez const char *p = *pp;
108301e196c8SJohn Marino
1084*6eef5f0cSAntonio Huete Jimenez while (*p != '\0') {
1085*6eef5f0cSAntonio Huete Jimenez if (!IsEscaped(lstart, p) && (*p == '!' || *p == ':'))
1086a34d5fb1SAntonio Huete Jimenez break;
1087*6eef5f0cSAntonio Huete Jimenez if (IsEscaped(lstart, p) || (*p != ' ' && *p != '\t'))
1088*6eef5f0cSAntonio Huete Jimenez warning = true;
1089*6eef5f0cSAntonio Huete Jimenez p++;
109001e196c8SJohn Marino }
1091a34d5fb1SAntonio Huete Jimenez if (warning)
109201e196c8SJohn Marino Parse_Error(PARSE_WARNING, "Extra target ignored");
109301e196c8SJohn Marino
1094*6eef5f0cSAntonio Huete Jimenez *pp += p - *pp;
1095a34d5fb1SAntonio Huete Jimenez }
109601e196c8SJohn Marino
1097a34d5fb1SAntonio Huete Jimenez static void
CheckSpecialMundaneMixture(ParseSpecial special)1098*6eef5f0cSAntonio Huete Jimenez CheckSpecialMundaneMixture(ParseSpecial special)
1099a34d5fb1SAntonio Huete Jimenez {
1100*6eef5f0cSAntonio Huete Jimenez switch (special) {
1101a34d5fb1SAntonio Huete Jimenez case SP_DEFAULT:
1102a34d5fb1SAntonio Huete Jimenez case SP_STALE:
1103a34d5fb1SAntonio Huete Jimenez case SP_BEGIN:
1104a34d5fb1SAntonio Huete Jimenez case SP_END:
1105a34d5fb1SAntonio Huete Jimenez case SP_ERROR:
1106a34d5fb1SAntonio Huete Jimenez case SP_INTERRUPT:
110701e196c8SJohn Marino /*
1108a34d5fb1SAntonio Huete Jimenez * These create nodes on which to hang commands, so targets
1109a34d5fb1SAntonio Huete Jimenez * shouldn't be empty.
111001e196c8SJohn Marino */
1111a34d5fb1SAntonio Huete Jimenez case SP_NOT:
1112*6eef5f0cSAntonio Huete Jimenez /* Nothing special here -- targets may be empty. */
1113*6eef5f0cSAntonio Huete Jimenez break;
1114*6eef5f0cSAntonio Huete Jimenez default:
1115*6eef5f0cSAntonio Huete Jimenez Parse_Error(PARSE_WARNING,
1116*6eef5f0cSAntonio Huete Jimenez "Special and mundane targets don't mix. "
1117*6eef5f0cSAntonio Huete Jimenez "Mundane ones ignored");
111801e196c8SJohn Marino break;
111901e196c8SJohn Marino }
112001e196c8SJohn Marino }
112101e196c8SJohn Marino
1122*6eef5f0cSAntonio Huete Jimenez /*
1123*6eef5f0cSAntonio Huete Jimenez * In a dependency line like 'targets: sources' or 'targets! sources', parse
1124*6eef5f0cSAntonio Huete Jimenez * the operator ':', '::' or '!' from between the targets and the sources.
1125*6eef5f0cSAntonio Huete Jimenez */
1126*6eef5f0cSAntonio Huete Jimenez static GNodeType
ParseDependencyOp(char ** pp)1127*6eef5f0cSAntonio Huete Jimenez ParseDependencyOp(char **pp)
1128a34d5fb1SAntonio Huete Jimenez {
1129*6eef5f0cSAntonio Huete Jimenez if (**pp == '!')
1130*6eef5f0cSAntonio Huete Jimenez return (*pp)++, OP_FORCE;
1131*6eef5f0cSAntonio Huete Jimenez if (**pp == ':' && (*pp)[1] == ':')
1132*6eef5f0cSAntonio Huete Jimenez return *pp += 2, OP_DOUBLEDEP;
1133*6eef5f0cSAntonio Huete Jimenez else if (**pp == ':')
1134*6eef5f0cSAntonio Huete Jimenez return (*pp)++, OP_DEPENDS;
1135*6eef5f0cSAntonio Huete Jimenez else
1136*6eef5f0cSAntonio Huete Jimenez return OP_NONE;
1137a34d5fb1SAntonio Huete Jimenez }
113801e196c8SJohn Marino
1139a34d5fb1SAntonio Huete Jimenez static void
ClearPaths(SearchPathList * paths)1140a34d5fb1SAntonio Huete Jimenez ClearPaths(SearchPathList *paths)
1141a34d5fb1SAntonio Huete Jimenez {
1142a34d5fb1SAntonio Huete Jimenez if (paths != NULL) {
1143a34d5fb1SAntonio Huete Jimenez SearchPathListNode *ln;
1144a34d5fb1SAntonio Huete Jimenez for (ln = paths->first; ln != NULL; ln = ln->next)
1145a34d5fb1SAntonio Huete Jimenez SearchPath_Clear(ln->datum);
1146a34d5fb1SAntonio Huete Jimenez }
1147a34d5fb1SAntonio Huete Jimenez
1148a34d5fb1SAntonio Huete Jimenez Dir_SetPATH();
1149a34d5fb1SAntonio Huete Jimenez }
1150a34d5fb1SAntonio Huete Jimenez
1151*6eef5f0cSAntonio Huete Jimenez static char *
FindInDirOfIncludingFile(const char * file)1152*6eef5f0cSAntonio Huete Jimenez FindInDirOfIncludingFile(const char *file)
1153a34d5fb1SAntonio Huete Jimenez {
1154*6eef5f0cSAntonio Huete Jimenez char *fullname, *incdir, *slash, *newName;
1155*6eef5f0cSAntonio Huete Jimenez int i;
1156*6eef5f0cSAntonio Huete Jimenez
1157*6eef5f0cSAntonio Huete Jimenez fullname = NULL;
1158*6eef5f0cSAntonio Huete Jimenez incdir = bmake_strdup(CurFile()->name.str);
1159*6eef5f0cSAntonio Huete Jimenez slash = strrchr(incdir, '/');
1160*6eef5f0cSAntonio Huete Jimenez if (slash != NULL) {
1161*6eef5f0cSAntonio Huete Jimenez *slash = '\0';
1162*6eef5f0cSAntonio Huete Jimenez /*
1163*6eef5f0cSAntonio Huete Jimenez * Now do lexical processing of leading "../" on the
1164*6eef5f0cSAntonio Huete Jimenez * filename.
1165*6eef5f0cSAntonio Huete Jimenez */
1166*6eef5f0cSAntonio Huete Jimenez for (i = 0; strncmp(file + i, "../", 3) == 0; i += 3) {
1167*6eef5f0cSAntonio Huete Jimenez slash = strrchr(incdir + 1, '/');
1168*6eef5f0cSAntonio Huete Jimenez if (slash == NULL || strcmp(slash, "/..") == 0)
1169*6eef5f0cSAntonio Huete Jimenez break;
1170*6eef5f0cSAntonio Huete Jimenez *slash = '\0';
1171*6eef5f0cSAntonio Huete Jimenez }
1172*6eef5f0cSAntonio Huete Jimenez newName = str_concat3(incdir, "/", file + i);
1173*6eef5f0cSAntonio Huete Jimenez fullname = Dir_FindFile(newName, parseIncPath);
1174*6eef5f0cSAntonio Huete Jimenez if (fullname == NULL)
1175*6eef5f0cSAntonio Huete Jimenez fullname = Dir_FindFile(newName, &dirSearchPath);
1176*6eef5f0cSAntonio Huete Jimenez free(newName);
1177*6eef5f0cSAntonio Huete Jimenez }
1178*6eef5f0cSAntonio Huete Jimenez free(incdir);
1179*6eef5f0cSAntonio Huete Jimenez return fullname;
1180*6eef5f0cSAntonio Huete Jimenez }
1181*6eef5f0cSAntonio Huete Jimenez
1182*6eef5f0cSAntonio Huete Jimenez static char *
FindInQuotPath(const char * file)1183*6eef5f0cSAntonio Huete Jimenez FindInQuotPath(const char *file)
1184*6eef5f0cSAntonio Huete Jimenez {
1185*6eef5f0cSAntonio Huete Jimenez const char *suff;
1186*6eef5f0cSAntonio Huete Jimenez SearchPath *suffPath;
1187*6eef5f0cSAntonio Huete Jimenez char *fullname;
1188*6eef5f0cSAntonio Huete Jimenez
1189*6eef5f0cSAntonio Huete Jimenez fullname = FindInDirOfIncludingFile(file);
1190*6eef5f0cSAntonio Huete Jimenez if (fullname == NULL &&
1191*6eef5f0cSAntonio Huete Jimenez (suff = strrchr(file, '.')) != NULL &&
1192*6eef5f0cSAntonio Huete Jimenez (suffPath = Suff_GetPath(suff)) != NULL)
1193*6eef5f0cSAntonio Huete Jimenez fullname = Dir_FindFile(file, suffPath);
1194*6eef5f0cSAntonio Huete Jimenez if (fullname == NULL)
1195*6eef5f0cSAntonio Huete Jimenez fullname = Dir_FindFile(file, parseIncPath);
1196*6eef5f0cSAntonio Huete Jimenez if (fullname == NULL)
1197*6eef5f0cSAntonio Huete Jimenez fullname = Dir_FindFile(file, &dirSearchPath);
1198*6eef5f0cSAntonio Huete Jimenez return fullname;
1199*6eef5f0cSAntonio Huete Jimenez }
1200*6eef5f0cSAntonio Huete Jimenez
1201*6eef5f0cSAntonio Huete Jimenez /*
1202*6eef5f0cSAntonio Huete Jimenez * Handle one of the .[-ds]include directives by remembering the current file
1203*6eef5f0cSAntonio Huete Jimenez * and pushing the included file on the stack. After the included file has
1204*6eef5f0cSAntonio Huete Jimenez * finished, parsing continues with the including file; see Parse_PushInput
1205*6eef5f0cSAntonio Huete Jimenez * and ParseEOF.
1206*6eef5f0cSAntonio Huete Jimenez *
1207*6eef5f0cSAntonio Huete Jimenez * System includes are looked up in sysIncPath, any other includes are looked
1208*6eef5f0cSAntonio Huete Jimenez * up in the parsedir and then in the directories specified by the -I command
1209*6eef5f0cSAntonio Huete Jimenez * line options.
1210*6eef5f0cSAntonio Huete Jimenez */
1211*6eef5f0cSAntonio Huete Jimenez static void
IncludeFile(const char * file,bool isSystem,bool depinc,bool silent)1212*6eef5f0cSAntonio Huete Jimenez IncludeFile(const char *file, bool isSystem, bool depinc, bool silent)
1213*6eef5f0cSAntonio Huete Jimenez {
1214*6eef5f0cSAntonio Huete Jimenez Buffer buf;
1215*6eef5f0cSAntonio Huete Jimenez char *fullname; /* full pathname of file */
1216*6eef5f0cSAntonio Huete Jimenez int fd;
1217*6eef5f0cSAntonio Huete Jimenez
1218*6eef5f0cSAntonio Huete Jimenez fullname = file[0] == '/' ? bmake_strdup(file) : NULL;
1219*6eef5f0cSAntonio Huete Jimenez
1220*6eef5f0cSAntonio Huete Jimenez if (fullname == NULL && !isSystem)
1221*6eef5f0cSAntonio Huete Jimenez fullname = FindInQuotPath(file);
1222*6eef5f0cSAntonio Huete Jimenez
1223*6eef5f0cSAntonio Huete Jimenez if (fullname == NULL) {
1224*6eef5f0cSAntonio Huete Jimenez SearchPath *path = Lst_IsEmpty(&sysIncPath->dirs)
1225*6eef5f0cSAntonio Huete Jimenez ? defSysIncPath : sysIncPath;
1226*6eef5f0cSAntonio Huete Jimenez fullname = Dir_FindFile(file, path);
1227*6eef5f0cSAntonio Huete Jimenez }
1228*6eef5f0cSAntonio Huete Jimenez
1229*6eef5f0cSAntonio Huete Jimenez if (fullname == NULL) {
1230*6eef5f0cSAntonio Huete Jimenez if (!silent)
1231*6eef5f0cSAntonio Huete Jimenez Parse_Error(PARSE_FATAL, "Could not find %s", file);
1232*6eef5f0cSAntonio Huete Jimenez return;
1233*6eef5f0cSAntonio Huete Jimenez }
1234*6eef5f0cSAntonio Huete Jimenez
1235*6eef5f0cSAntonio Huete Jimenez if ((fd = open(fullname, O_RDONLY)) == -1) {
1236*6eef5f0cSAntonio Huete Jimenez if (!silent)
1237*6eef5f0cSAntonio Huete Jimenez Parse_Error(PARSE_FATAL, "Cannot open %s", fullname);
1238*6eef5f0cSAntonio Huete Jimenez free(fullname);
1239*6eef5f0cSAntonio Huete Jimenez return;
1240*6eef5f0cSAntonio Huete Jimenez }
1241*6eef5f0cSAntonio Huete Jimenez
1242*6eef5f0cSAntonio Huete Jimenez buf = LoadFile(fullname, fd);
1243*6eef5f0cSAntonio Huete Jimenez (void)close(fd);
1244*6eef5f0cSAntonio Huete Jimenez
1245*6eef5f0cSAntonio Huete Jimenez Parse_PushInput(fullname, 1, 0, buf, NULL);
1246*6eef5f0cSAntonio Huete Jimenez if (depinc)
1247*6eef5f0cSAntonio Huete Jimenez doing_depend = depinc; /* only turn it on */
1248*6eef5f0cSAntonio Huete Jimenez free(fullname);
1249*6eef5f0cSAntonio Huete Jimenez }
1250*6eef5f0cSAntonio Huete Jimenez
1251*6eef5f0cSAntonio Huete Jimenez /* Handle a "dependency" line like '.SPECIAL:' without any sources. */
1252*6eef5f0cSAntonio Huete Jimenez static void
HandleDependencySourcesEmpty(ParseSpecial special,SearchPathList * paths)1253*6eef5f0cSAntonio Huete Jimenez HandleDependencySourcesEmpty(ParseSpecial special, SearchPathList *paths)
1254*6eef5f0cSAntonio Huete Jimenez {
1255*6eef5f0cSAntonio Huete Jimenez switch (special) {
1256a34d5fb1SAntonio Huete Jimenez case SP_SUFFIXES:
125701e196c8SJohn Marino Suff_ClearSuffixes();
125801e196c8SJohn Marino break;
1259a34d5fb1SAntonio Huete Jimenez case SP_PRECIOUS:
1260*6eef5f0cSAntonio Huete Jimenez allPrecious = true;
126101e196c8SJohn Marino break;
1262a34d5fb1SAntonio Huete Jimenez case SP_IGNORE:
1263*6eef5f0cSAntonio Huete Jimenez opts.ignoreErrors = true;
126401e196c8SJohn Marino break;
1265a34d5fb1SAntonio Huete Jimenez case SP_SILENT:
1266*6eef5f0cSAntonio Huete Jimenez opts.silent = true;
126701e196c8SJohn Marino break;
1268a34d5fb1SAntonio Huete Jimenez case SP_PATH:
1269a34d5fb1SAntonio Huete Jimenez ClearPaths(paths);
127001e196c8SJohn Marino break;
127101e196c8SJohn Marino #ifdef POSIX
1272a34d5fb1SAntonio Huete Jimenez case SP_POSIX:
1273*6eef5f0cSAntonio Huete Jimenez if (posix_state == PS_NOW_OR_NEVER) {
1274*6eef5f0cSAntonio Huete Jimenez /*
1275*6eef5f0cSAntonio Huete Jimenez * With '-r', 'posix.mk' (if it exists)
1276*6eef5f0cSAntonio Huete Jimenez * can effectively substitute for 'sys.mk',
1277*6eef5f0cSAntonio Huete Jimenez * otherwise it is an extension.
1278*6eef5f0cSAntonio Huete Jimenez */
1279a34d5fb1SAntonio Huete Jimenez Global_Set("%POSIX", "1003.2");
1280*6eef5f0cSAntonio Huete Jimenez IncludeFile("posix.mk", true, false, true);
1281*6eef5f0cSAntonio Huete Jimenez }
128201e196c8SJohn Marino break;
128301e196c8SJohn Marino #endif
128401e196c8SJohn Marino default:
128501e196c8SJohn Marino break;
128601e196c8SJohn Marino }
128701e196c8SJohn Marino }
128801e196c8SJohn Marino
1289a34d5fb1SAntonio Huete Jimenez static void
AddToPaths(const char * dir,SearchPathList * paths)1290a34d5fb1SAntonio Huete Jimenez AddToPaths(const char *dir, SearchPathList *paths)
129101e196c8SJohn Marino {
1292a34d5fb1SAntonio Huete Jimenez if (paths != NULL) {
1293a34d5fb1SAntonio Huete Jimenez SearchPathListNode *ln;
1294a34d5fb1SAntonio Huete Jimenez for (ln = paths->first; ln != NULL; ln = ln->next)
1295a34d5fb1SAntonio Huete Jimenez (void)SearchPath_Add(ln->datum, dir);
1296a34d5fb1SAntonio Huete Jimenez }
1297a34d5fb1SAntonio Huete Jimenez }
1298a34d5fb1SAntonio Huete Jimenez
129901e196c8SJohn Marino /*
1300*6eef5f0cSAntonio Huete Jimenez * If the target was one that doesn't take files as its sources but takes
1301*6eef5f0cSAntonio Huete Jimenez * something like suffixes, we take each space-separated word on the line as
1302*6eef5f0cSAntonio Huete Jimenez * a something and deal with it accordingly.
130301e196c8SJohn Marino */
1304a34d5fb1SAntonio Huete Jimenez static void
ParseDependencySourceSpecial(ParseSpecial special,const char * word,SearchPathList * paths)1305*6eef5f0cSAntonio Huete Jimenez ParseDependencySourceSpecial(ParseSpecial special, const char *word,
1306a34d5fb1SAntonio Huete Jimenez SearchPathList *paths)
1307a34d5fb1SAntonio Huete Jimenez {
1308*6eef5f0cSAntonio Huete Jimenez switch (special) {
1309a34d5fb1SAntonio Huete Jimenez case SP_SUFFIXES:
1310*6eef5f0cSAntonio Huete Jimenez Suff_AddSuffix(word);
131101e196c8SJohn Marino break;
1312a34d5fb1SAntonio Huete Jimenez case SP_PATH:
1313a34d5fb1SAntonio Huete Jimenez AddToPaths(word, paths);
131401e196c8SJohn Marino break;
1315a34d5fb1SAntonio Huete Jimenez case SP_INCLUDES:
1316a34d5fb1SAntonio Huete Jimenez Suff_AddInclude(word);
131701e196c8SJohn Marino break;
1318a34d5fb1SAntonio Huete Jimenez case SP_LIBS:
1319a34d5fb1SAntonio Huete Jimenez Suff_AddLib(word);
132001e196c8SJohn Marino break;
1321a34d5fb1SAntonio Huete Jimenez case SP_NULL:
1322a34d5fb1SAntonio Huete Jimenez Suff_SetNull(word);
132301e196c8SJohn Marino break;
1324a34d5fb1SAntonio Huete Jimenez case SP_OBJDIR:
1325*6eef5f0cSAntonio Huete Jimenez Main_SetObjdir(false, "%s", word);
132601e196c8SJohn Marino break;
132701e196c8SJohn Marino default:
132801e196c8SJohn Marino break;
132901e196c8SJohn Marino }
1330a34d5fb1SAntonio Huete Jimenez }
1331a34d5fb1SAntonio Huete Jimenez
1332*6eef5f0cSAntonio Huete Jimenez static bool
ApplyDependencyTarget(char * name,char * nameEnd,ParseSpecial * inout_special,GNodeType * inout_targetAttr,SearchPathList ** inout_paths)1333*6eef5f0cSAntonio Huete Jimenez ApplyDependencyTarget(char *name, char *nameEnd, ParseSpecial *inout_special,
1334*6eef5f0cSAntonio Huete Jimenez GNodeType *inout_targetAttr,
1335*6eef5f0cSAntonio Huete Jimenez SearchPathList **inout_paths)
1336a34d5fb1SAntonio Huete Jimenez {
1337*6eef5f0cSAntonio Huete Jimenez char savec = *nameEnd;
1338*6eef5f0cSAntonio Huete Jimenez *nameEnd = '\0';
1339*6eef5f0cSAntonio Huete Jimenez
1340*6eef5f0cSAntonio Huete Jimenez if (!HandleDependencyTarget(name, inout_special,
1341*6eef5f0cSAntonio Huete Jimenez inout_targetAttr, inout_paths))
1342*6eef5f0cSAntonio Huete Jimenez return false;
1343*6eef5f0cSAntonio Huete Jimenez
1344*6eef5f0cSAntonio Huete Jimenez if (*inout_special == SP_NOT && *name != '\0')
1345*6eef5f0cSAntonio Huete Jimenez HandleDependencyTargetMundane(name);
1346*6eef5f0cSAntonio Huete Jimenez else if (*inout_special == SP_PATH && *name != '.' && *name != '\0')
1347*6eef5f0cSAntonio Huete Jimenez Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", name);
1348*6eef5f0cSAntonio Huete Jimenez
1349*6eef5f0cSAntonio Huete Jimenez *nameEnd = savec;
1350*6eef5f0cSAntonio Huete Jimenez return true;
1351*6eef5f0cSAntonio Huete Jimenez }
1352*6eef5f0cSAntonio Huete Jimenez
1353*6eef5f0cSAntonio Huete Jimenez static bool
ParseDependencyTargets(char ** inout_cp,const char * lstart,ParseSpecial * inout_special,GNodeType * inout_targetAttr,SearchPathList ** inout_paths)1354*6eef5f0cSAntonio Huete Jimenez ParseDependencyTargets(char **inout_cp,
1355*6eef5f0cSAntonio Huete Jimenez const char *lstart,
1356*6eef5f0cSAntonio Huete Jimenez ParseSpecial *inout_special,
1357*6eef5f0cSAntonio Huete Jimenez GNodeType *inout_targetAttr,
1358*6eef5f0cSAntonio Huete Jimenez SearchPathList **inout_paths)
1359*6eef5f0cSAntonio Huete Jimenez {
1360*6eef5f0cSAntonio Huete Jimenez char *cp = *inout_cp;
1361a34d5fb1SAntonio Huete Jimenez
1362a34d5fb1SAntonio Huete Jimenez for (;;) {
1363*6eef5f0cSAntonio Huete Jimenez char *tgt = cp;
1364a34d5fb1SAntonio Huete Jimenez
1365*6eef5f0cSAntonio Huete Jimenez ParseDependencyTargetWord(&cp, lstart);
1366a34d5fb1SAntonio Huete Jimenez
1367a34d5fb1SAntonio Huete Jimenez /*
1368a34d5fb1SAntonio Huete Jimenez * If the word is followed by a left parenthesis, it's the
1369*6eef5f0cSAntonio Huete Jimenez * name of one or more files inside an archive.
1370a34d5fb1SAntonio Huete Jimenez */
1371*6eef5f0cSAntonio Huete Jimenez if (!IsEscaped(lstart, cp) && *cp == '(') {
1372*6eef5f0cSAntonio Huete Jimenez cp = tgt;
1373*6eef5f0cSAntonio Huete Jimenez if (!Arch_ParseArchive(&cp, targets, SCOPE_CMDLINE)) {
1374a34d5fb1SAntonio Huete Jimenez Parse_Error(PARSE_FATAL,
1375a34d5fb1SAntonio Huete Jimenez "Error in archive specification: \"%s\"",
1376a34d5fb1SAntonio Huete Jimenez tgt);
1377*6eef5f0cSAntonio Huete Jimenez return false;
1378a34d5fb1SAntonio Huete Jimenez }
1379a34d5fb1SAntonio Huete Jimenez continue;
1380a34d5fb1SAntonio Huete Jimenez }
1381a34d5fb1SAntonio Huete Jimenez
1382a34d5fb1SAntonio Huete Jimenez if (*cp == '\0') {
1383*6eef5f0cSAntonio Huete Jimenez InvalidLineType(lstart);
1384*6eef5f0cSAntonio Huete Jimenez return false;
1385a34d5fb1SAntonio Huete Jimenez }
1386a34d5fb1SAntonio Huete Jimenez
1387*6eef5f0cSAntonio Huete Jimenez if (!ApplyDependencyTarget(tgt, cp, inout_special,
1388*6eef5f0cSAntonio Huete Jimenez inout_targetAttr, inout_paths))
1389*6eef5f0cSAntonio Huete Jimenez return false;
1390a34d5fb1SAntonio Huete Jimenez
1391*6eef5f0cSAntonio Huete Jimenez if (*inout_special != SP_NOT && *inout_special != SP_PATH)
1392*6eef5f0cSAntonio Huete Jimenez SkipExtraTargets(&cp, lstart);
1393a34d5fb1SAntonio Huete Jimenez else
1394a34d5fb1SAntonio Huete Jimenez pp_skip_whitespace(&cp);
1395a34d5fb1SAntonio Huete Jimenez
1396*6eef5f0cSAntonio Huete Jimenez if (*cp == '\0')
1397a34d5fb1SAntonio Huete Jimenez break;
1398*6eef5f0cSAntonio Huete Jimenez if ((*cp == '!' || *cp == ':') && !IsEscaped(lstart, cp))
1399a34d5fb1SAntonio Huete Jimenez break;
140001e196c8SJohn Marino }
1401a34d5fb1SAntonio Huete Jimenez
1402a34d5fb1SAntonio Huete Jimenez *inout_cp = cp;
1403*6eef5f0cSAntonio Huete Jimenez return true;
140401e196c8SJohn Marino }
1405a34d5fb1SAntonio Huete Jimenez
1406a34d5fb1SAntonio Huete Jimenez static void
ParseDependencySourcesSpecial(char * start,ParseSpecial special,SearchPathList * paths)1407*6eef5f0cSAntonio Huete Jimenez ParseDependencySourcesSpecial(char *start,
1408*6eef5f0cSAntonio Huete Jimenez ParseSpecial special, SearchPathList *paths)
1409a34d5fb1SAntonio Huete Jimenez {
1410a34d5fb1SAntonio Huete Jimenez char savec;
1411a34d5fb1SAntonio Huete Jimenez
1412a34d5fb1SAntonio Huete Jimenez while (*start != '\0') {
1413*6eef5f0cSAntonio Huete Jimenez char *end = start;
1414a34d5fb1SAntonio Huete Jimenez while (*end != '\0' && !ch_isspace(*end))
1415a34d5fb1SAntonio Huete Jimenez end++;
1416a34d5fb1SAntonio Huete Jimenez savec = *end;
1417a34d5fb1SAntonio Huete Jimenez *end = '\0';
1418*6eef5f0cSAntonio Huete Jimenez ParseDependencySourceSpecial(special, start, paths);
1419a34d5fb1SAntonio Huete Jimenez *end = savec;
1420a34d5fb1SAntonio Huete Jimenez if (savec != '\0')
1421a34d5fb1SAntonio Huete Jimenez end++;
1422a34d5fb1SAntonio Huete Jimenez pp_skip_whitespace(&end);
1423a34d5fb1SAntonio Huete Jimenez start = end;
142401e196c8SJohn Marino }
142501e196c8SJohn Marino }
1426a34d5fb1SAntonio Huete Jimenez
1427*6eef5f0cSAntonio Huete Jimenez static void
LinkVarToTargets(VarAssign * var)1428*6eef5f0cSAntonio Huete Jimenez LinkVarToTargets(VarAssign *var)
1429*6eef5f0cSAntonio Huete Jimenez {
1430*6eef5f0cSAntonio Huete Jimenez GNodeListNode *ln;
1431*6eef5f0cSAntonio Huete Jimenez
1432*6eef5f0cSAntonio Huete Jimenez for (ln = targets->first; ln != NULL; ln = ln->next)
1433*6eef5f0cSAntonio Huete Jimenez Parse_Var(var, ln->datum);
1434*6eef5f0cSAntonio Huete Jimenez }
1435*6eef5f0cSAntonio Huete Jimenez
1436*6eef5f0cSAntonio Huete Jimenez static bool
ParseDependencySourcesMundane(char * start,ParseSpecial special,GNodeType targetAttr)1437*6eef5f0cSAntonio Huete Jimenez ParseDependencySourcesMundane(char *start,
1438*6eef5f0cSAntonio Huete Jimenez ParseSpecial special, GNodeType targetAttr)
1439a34d5fb1SAntonio Huete Jimenez {
1440a34d5fb1SAntonio Huete Jimenez while (*start != '\0') {
1441*6eef5f0cSAntonio Huete Jimenez char *end = start;
1442*6eef5f0cSAntonio Huete Jimenez VarAssign var;
1443*6eef5f0cSAntonio Huete Jimenez
1444*6eef5f0cSAntonio Huete Jimenez /*
1445*6eef5f0cSAntonio Huete Jimenez * Check for local variable assignment,
1446*6eef5f0cSAntonio Huete Jimenez * rest of the line is the value.
1447*6eef5f0cSAntonio Huete Jimenez */
1448*6eef5f0cSAntonio Huete Jimenez if (Parse_IsVar(start, &var)) {
1449*6eef5f0cSAntonio Huete Jimenez /*
1450*6eef5f0cSAntonio Huete Jimenez * Check if this makefile has disabled
1451*6eef5f0cSAntonio Huete Jimenez * setting local variables.
1452*6eef5f0cSAntonio Huete Jimenez */
1453*6eef5f0cSAntonio Huete Jimenez bool target_vars = GetBooleanExpr(
1454*6eef5f0cSAntonio Huete Jimenez "${.MAKE.TARGET_LOCAL_VARIABLES}", true);
1455*6eef5f0cSAntonio Huete Jimenez
1456*6eef5f0cSAntonio Huete Jimenez if (target_vars)
1457*6eef5f0cSAntonio Huete Jimenez LinkVarToTargets(&var);
1458*6eef5f0cSAntonio Huete Jimenez free(var.varname);
1459*6eef5f0cSAntonio Huete Jimenez if (target_vars)
1460*6eef5f0cSAntonio Huete Jimenez return true;
1461*6eef5f0cSAntonio Huete Jimenez }
1462*6eef5f0cSAntonio Huete Jimenez
146301e196c8SJohn Marino /*
146401e196c8SJohn Marino * The targets take real sources, so we must beware of archive
146501e196c8SJohn Marino * specifications (i.e. things with left parentheses in them)
146601e196c8SJohn Marino * and handle them accordingly.
146701e196c8SJohn Marino */
1468a34d5fb1SAntonio Huete Jimenez for (; *end != '\0' && !ch_isspace(*end); end++) {
1469a34d5fb1SAntonio Huete Jimenez if (*end == '(' && end > start && end[-1] != '$') {
147001e196c8SJohn Marino /*
1471a34d5fb1SAntonio Huete Jimenez * Only stop for a left parenthesis if it
1472a34d5fb1SAntonio Huete Jimenez * isn't at the start of a word (that'll be
1473a34d5fb1SAntonio Huete Jimenez * for variable changes later) and isn't
1474a34d5fb1SAntonio Huete Jimenez * preceded by a dollar sign (a dynamic
147501e196c8SJohn Marino * source).
147601e196c8SJohn Marino */
147701e196c8SJohn Marino break;
147801e196c8SJohn Marino }
147901e196c8SJohn Marino }
148001e196c8SJohn Marino
1481a34d5fb1SAntonio Huete Jimenez if (*end == '(') {
1482a34d5fb1SAntonio Huete Jimenez GNodeList sources = LST_INIT;
1483a34d5fb1SAntonio Huete Jimenez if (!Arch_ParseArchive(&start, &sources,
1484a34d5fb1SAntonio Huete Jimenez SCOPE_CMDLINE)) {
148501e196c8SJohn Marino Parse_Error(PARSE_FATAL,
1486a34d5fb1SAntonio Huete Jimenez "Error in source archive spec \"%s\"",
1487a34d5fb1SAntonio Huete Jimenez start);
1488*6eef5f0cSAntonio Huete Jimenez return false;
1489a34d5fb1SAntonio Huete Jimenez }
1490a34d5fb1SAntonio Huete Jimenez
1491a34d5fb1SAntonio Huete Jimenez while (!Lst_IsEmpty(&sources)) {
1492a34d5fb1SAntonio Huete Jimenez GNode *gn = Lst_Dequeue(&sources);
1493*6eef5f0cSAntonio Huete Jimenez ApplyDependencySource(targetAttr, gn->name,
1494*6eef5f0cSAntonio Huete Jimenez special);
1495a34d5fb1SAntonio Huete Jimenez }
1496a34d5fb1SAntonio Huete Jimenez Lst_Done(&sources);
1497a34d5fb1SAntonio Huete Jimenez end = start;
1498a34d5fb1SAntonio Huete Jimenez } else {
1499a34d5fb1SAntonio Huete Jimenez if (*end != '\0') {
1500a34d5fb1SAntonio Huete Jimenez *end = '\0';
1501a34d5fb1SAntonio Huete Jimenez end++;
1502a34d5fb1SAntonio Huete Jimenez }
1503a34d5fb1SAntonio Huete Jimenez
1504*6eef5f0cSAntonio Huete Jimenez ApplyDependencySource(targetAttr, start, special);
1505a34d5fb1SAntonio Huete Jimenez }
1506a34d5fb1SAntonio Huete Jimenez pp_skip_whitespace(&end);
1507a34d5fb1SAntonio Huete Jimenez start = end;
1508a34d5fb1SAntonio Huete Jimenez }
1509*6eef5f0cSAntonio Huete Jimenez return true;
1510*6eef5f0cSAntonio Huete Jimenez }
1511*6eef5f0cSAntonio Huete Jimenez
1512*6eef5f0cSAntonio Huete Jimenez /*
1513*6eef5f0cSAntonio Huete Jimenez * From a dependency line like 'targets: sources', parse the sources.
1514*6eef5f0cSAntonio Huete Jimenez *
1515*6eef5f0cSAntonio Huete Jimenez * See the tests depsrc-*.mk.
1516*6eef5f0cSAntonio Huete Jimenez */
1517*6eef5f0cSAntonio Huete Jimenez static void
ParseDependencySources(char * p,GNodeType targetAttr,ParseSpecial special,SearchPathList ** inout_paths)1518*6eef5f0cSAntonio Huete Jimenez ParseDependencySources(char *p, GNodeType targetAttr,
1519*6eef5f0cSAntonio Huete Jimenez ParseSpecial special, SearchPathList **inout_paths)
1520*6eef5f0cSAntonio Huete Jimenez {
1521*6eef5f0cSAntonio Huete Jimenez if (*p == '\0') {
1522*6eef5f0cSAntonio Huete Jimenez HandleDependencySourcesEmpty(special, *inout_paths);
1523*6eef5f0cSAntonio Huete Jimenez } else if (special == SP_MFLAGS) {
1524*6eef5f0cSAntonio Huete Jimenez Main_ParseArgLine(p);
1525*6eef5f0cSAntonio Huete Jimenez return;
1526*6eef5f0cSAntonio Huete Jimenez } else if (special == SP_SHELL) {
1527*6eef5f0cSAntonio Huete Jimenez if (!Job_ParseShell(p)) {
1528*6eef5f0cSAntonio Huete Jimenez Parse_Error(PARSE_FATAL,
1529*6eef5f0cSAntonio Huete Jimenez "improper shell specification");
1530*6eef5f0cSAntonio Huete Jimenez return;
1531*6eef5f0cSAntonio Huete Jimenez }
1532*6eef5f0cSAntonio Huete Jimenez return;
1533*6eef5f0cSAntonio Huete Jimenez } else if (special == SP_NOTPARALLEL || special == SP_SINGLESHELL ||
1534*6eef5f0cSAntonio Huete Jimenez special == SP_DELETE_ON_ERROR) {
1535*6eef5f0cSAntonio Huete Jimenez return;
1536*6eef5f0cSAntonio Huete Jimenez }
1537*6eef5f0cSAntonio Huete Jimenez
1538*6eef5f0cSAntonio Huete Jimenez /* Now go for the sources. */
1539*6eef5f0cSAntonio Huete Jimenez if (special == SP_SUFFIXES || special == SP_PATH ||
1540*6eef5f0cSAntonio Huete Jimenez special == SP_INCLUDES || special == SP_LIBS ||
1541*6eef5f0cSAntonio Huete Jimenez special == SP_NULL || special == SP_OBJDIR) {
1542*6eef5f0cSAntonio Huete Jimenez ParseDependencySourcesSpecial(p, special, *inout_paths);
1543*6eef5f0cSAntonio Huete Jimenez if (*inout_paths != NULL) {
1544*6eef5f0cSAntonio Huete Jimenez Lst_Free(*inout_paths);
1545*6eef5f0cSAntonio Huete Jimenez *inout_paths = NULL;
1546*6eef5f0cSAntonio Huete Jimenez }
1547*6eef5f0cSAntonio Huete Jimenez if (special == SP_PATH)
1548*6eef5f0cSAntonio Huete Jimenez Dir_SetPATH();
1549*6eef5f0cSAntonio Huete Jimenez } else {
1550*6eef5f0cSAntonio Huete Jimenez assert(*inout_paths == NULL);
1551*6eef5f0cSAntonio Huete Jimenez if (!ParseDependencySourcesMundane(p, special, targetAttr))
1552*6eef5f0cSAntonio Huete Jimenez return;
1553*6eef5f0cSAntonio Huete Jimenez }
1554*6eef5f0cSAntonio Huete Jimenez
1555*6eef5f0cSAntonio Huete Jimenez MaybeUpdateMainTarget();
1556a34d5fb1SAntonio Huete Jimenez }
1557a34d5fb1SAntonio Huete Jimenez
1558a34d5fb1SAntonio Huete Jimenez /*
1559a34d5fb1SAntonio Huete Jimenez * Parse a dependency line consisting of targets, followed by a dependency
1560a34d5fb1SAntonio Huete Jimenez * operator, optionally followed by sources.
1561a34d5fb1SAntonio Huete Jimenez *
1562a34d5fb1SAntonio Huete Jimenez * The nodes of the sources are linked as children to the nodes of the
1563a34d5fb1SAntonio Huete Jimenez * targets. Nodes are created as necessary.
1564a34d5fb1SAntonio Huete Jimenez *
1565a34d5fb1SAntonio Huete Jimenez * The operator is applied to each node in the global 'targets' list,
1566*6eef5f0cSAntonio Huete Jimenez * which is where the nodes found for the targets are kept.
1567a34d5fb1SAntonio Huete Jimenez *
1568a34d5fb1SAntonio Huete Jimenez * The sources are parsed in much the same way as the targets, except
1569a34d5fb1SAntonio Huete Jimenez * that they are expanded using the wildcarding scheme of the C-Shell,
1570a34d5fb1SAntonio Huete Jimenez * and a target is created for each expanded word. Each of the resulting
1571a34d5fb1SAntonio Huete Jimenez * nodes is then linked to each of the targets as one of its children.
1572a34d5fb1SAntonio Huete Jimenez *
1573a34d5fb1SAntonio Huete Jimenez * Certain targets and sources such as .PHONY or .PRECIOUS are handled
1574*6eef5f0cSAntonio Huete Jimenez * specially, see ParseSpecial.
1575a34d5fb1SAntonio Huete Jimenez *
1576*6eef5f0cSAntonio Huete Jimenez * Transformation rules such as '.c.o' are also handled here, see
1577*6eef5f0cSAntonio Huete Jimenez * Suff_AddTransform.
1578a34d5fb1SAntonio Huete Jimenez *
1579a34d5fb1SAntonio Huete Jimenez * Upon return, the value of the line is unspecified.
1580a34d5fb1SAntonio Huete Jimenez */
1581a34d5fb1SAntonio Huete Jimenez static void
ParseDependency(char * line)1582*6eef5f0cSAntonio Huete Jimenez ParseDependency(char *line)
1583a34d5fb1SAntonio Huete Jimenez {
1584*6eef5f0cSAntonio Huete Jimenez char *p;
1585*6eef5f0cSAntonio Huete Jimenez SearchPathList *paths; /* search paths to alter when parsing a list
1586*6eef5f0cSAntonio Huete Jimenez * of .PATH targets */
1587*6eef5f0cSAntonio Huete Jimenez GNodeType targetAttr; /* from special sources */
1588*6eef5f0cSAntonio Huete Jimenez ParseSpecial special; /* in special targets, the children are
1589*6eef5f0cSAntonio Huete Jimenez * linked as children of the parent but not
1590*6eef5f0cSAntonio Huete Jimenez * vice versa */
1591*6eef5f0cSAntonio Huete Jimenez GNodeType op;
1592a34d5fb1SAntonio Huete Jimenez
1593*6eef5f0cSAntonio Huete Jimenez DEBUG1(PARSE, "ParseDependency(%s)\n", line);
1594*6eef5f0cSAntonio Huete Jimenez p = line;
1595a34d5fb1SAntonio Huete Jimenez paths = NULL;
1596*6eef5f0cSAntonio Huete Jimenez targetAttr = OP_NONE;
1597*6eef5f0cSAntonio Huete Jimenez special = SP_NOT;
1598a34d5fb1SAntonio Huete Jimenez
1599*6eef5f0cSAntonio Huete Jimenez if (!ParseDependencyTargets(&p, line, &special, &targetAttr, &paths))
1600a34d5fb1SAntonio Huete Jimenez goto out;
1601a34d5fb1SAntonio Huete Jimenez
1602a34d5fb1SAntonio Huete Jimenez if (!Lst_IsEmpty(targets))
1603*6eef5f0cSAntonio Huete Jimenez CheckSpecialMundaneMixture(special);
1604a34d5fb1SAntonio Huete Jimenez
1605*6eef5f0cSAntonio Huete Jimenez op = ParseDependencyOp(&p);
1606*6eef5f0cSAntonio Huete Jimenez if (op == OP_NONE) {
1607*6eef5f0cSAntonio Huete Jimenez InvalidLineType(line);
1608a34d5fb1SAntonio Huete Jimenez goto out;
1609*6eef5f0cSAntonio Huete Jimenez }
1610a34d5fb1SAntonio Huete Jimenez ApplyDependencyOperator(op);
1611a34d5fb1SAntonio Huete Jimenez
1612*6eef5f0cSAntonio Huete Jimenez pp_skip_whitespace(&p);
1613a34d5fb1SAntonio Huete Jimenez
1614*6eef5f0cSAntonio Huete Jimenez ParseDependencySources(p, targetAttr, special, &paths);
161501e196c8SJohn Marino
161601e196c8SJohn Marino out:
1617a34d5fb1SAntonio Huete Jimenez if (paths != NULL)
1618a34d5fb1SAntonio Huete Jimenez Lst_Free(paths);
161901e196c8SJohn Marino }
162001e196c8SJohn Marino
162101e196c8SJohn Marino /*
1622a34d5fb1SAntonio Huete Jimenez * Determine the assignment operator and adjust the end of the variable
1623a34d5fb1SAntonio Huete Jimenez * name accordingly.
162401e196c8SJohn Marino */
1625*6eef5f0cSAntonio Huete Jimenez static VarAssign
AdjustVarassignOp(const char * name,const char * nameEnd,const char * op,const char * value)1626*6eef5f0cSAntonio Huete Jimenez AdjustVarassignOp(const char *name, const char *nameEnd, const char *op,
1627*6eef5f0cSAntonio Huete Jimenez const char *value)
1628a34d5fb1SAntonio Huete Jimenez {
1629a34d5fb1SAntonio Huete Jimenez VarAssignOp type;
1630*6eef5f0cSAntonio Huete Jimenez VarAssign va;
163101e196c8SJohn Marino
1632a34d5fb1SAntonio Huete Jimenez if (op > name && op[-1] == '+') {
1633a34d5fb1SAntonio Huete Jimenez op--;
1634*6eef5f0cSAntonio Huete Jimenez type = VAR_APPEND;
1635a34d5fb1SAntonio Huete Jimenez
1636a34d5fb1SAntonio Huete Jimenez } else if (op > name && op[-1] == '?') {
1637a34d5fb1SAntonio Huete Jimenez op--;
1638a34d5fb1SAntonio Huete Jimenez type = VAR_DEFAULT;
1639a34d5fb1SAntonio Huete Jimenez
1640a34d5fb1SAntonio Huete Jimenez } else if (op > name && op[-1] == ':') {
1641a34d5fb1SAntonio Huete Jimenez op--;
1642a34d5fb1SAntonio Huete Jimenez type = VAR_SUBST;
1643a34d5fb1SAntonio Huete Jimenez
1644a34d5fb1SAntonio Huete Jimenez } else if (op > name && op[-1] == '!') {
1645a34d5fb1SAntonio Huete Jimenez op--;
1646a34d5fb1SAntonio Huete Jimenez type = VAR_SHELL;
1647a34d5fb1SAntonio Huete Jimenez
1648a34d5fb1SAntonio Huete Jimenez } else {
1649a34d5fb1SAntonio Huete Jimenez type = VAR_NORMAL;
1650a34d5fb1SAntonio Huete Jimenez #ifdef SUNSHCMD
1651a34d5fb1SAntonio Huete Jimenez while (op > name && ch_isspace(op[-1]))
1652a34d5fb1SAntonio Huete Jimenez op--;
1653a34d5fb1SAntonio Huete Jimenez
1654*6eef5f0cSAntonio Huete Jimenez if (op - name >= 3 && memcmp(op - 3, ":sh", 3) == 0) {
1655a34d5fb1SAntonio Huete Jimenez op -= 3;
1656*6eef5f0cSAntonio Huete Jimenez type = VAR_SHELL;
1657a34d5fb1SAntonio Huete Jimenez }
1658a34d5fb1SAntonio Huete Jimenez #endif
1659a34d5fb1SAntonio Huete Jimenez }
1660a34d5fb1SAntonio Huete Jimenez
1661*6eef5f0cSAntonio Huete Jimenez va.varname = bmake_strsedup(name, nameEnd < op ? nameEnd : op);
1662*6eef5f0cSAntonio Huete Jimenez va.op = type;
1663*6eef5f0cSAntonio Huete Jimenez va.value = value;
1664*6eef5f0cSAntonio Huete Jimenez return va;
1665a34d5fb1SAntonio Huete Jimenez }
1666a34d5fb1SAntonio Huete Jimenez
1667a34d5fb1SAntonio Huete Jimenez /*
1668a34d5fb1SAntonio Huete Jimenez * Parse a variable assignment, consisting of a single-word variable name,
1669a34d5fb1SAntonio Huete Jimenez * optional whitespace, an assignment operator, optional whitespace and the
1670a34d5fb1SAntonio Huete Jimenez * variable value.
1671a34d5fb1SAntonio Huete Jimenez *
1672a34d5fb1SAntonio Huete Jimenez * Note: There is a lexical ambiguity with assignment modifier characters
1673a34d5fb1SAntonio Huete Jimenez * in variable names. This routine interprets the character before the =
1674a34d5fb1SAntonio Huete Jimenez * as a modifier. Therefore, an assignment like
1675a34d5fb1SAntonio Huete Jimenez * C++=/usr/bin/CC
1676a34d5fb1SAntonio Huete Jimenez * is interpreted as "C+ +=" instead of "C++ =".
1677a34d5fb1SAntonio Huete Jimenez *
1678a34d5fb1SAntonio Huete Jimenez * Used for both lines in a file and command line arguments.
1679a34d5fb1SAntonio Huete Jimenez */
1680*6eef5f0cSAntonio Huete Jimenez static bool
Parse_IsVar(const char * p,VarAssign * out_var)1681a34d5fb1SAntonio Huete Jimenez Parse_IsVar(const char *p, VarAssign *out_var)
1682a34d5fb1SAntonio Huete Jimenez {
1683*6eef5f0cSAntonio Huete Jimenez const char *nameStart, *nameEnd, *firstSpace, *eq;
1684a34d5fb1SAntonio Huete Jimenez int level = 0;
1685a34d5fb1SAntonio Huete Jimenez
1686a34d5fb1SAntonio Huete Jimenez cpp_skip_hspace(&p); /* Skip to variable name */
1687a34d5fb1SAntonio Huete Jimenez
1688a34d5fb1SAntonio Huete Jimenez /*
1689*6eef5f0cSAntonio Huete Jimenez * During parsing, the '+' of the operator '+=' is initially parsed
1690a34d5fb1SAntonio Huete Jimenez * as part of the variable name. It is later corrected, as is the
1691*6eef5f0cSAntonio Huete Jimenez * ':sh' modifier. Of these two (nameEnd and eq), the earlier one
1692a34d5fb1SAntonio Huete Jimenez * determines the actual end of the variable name.
1693a34d5fb1SAntonio Huete Jimenez */
1694*6eef5f0cSAntonio Huete Jimenez
1695*6eef5f0cSAntonio Huete Jimenez nameStart = p;
1696*6eef5f0cSAntonio Huete Jimenez firstSpace = NULL;
1697a34d5fb1SAntonio Huete Jimenez
1698a34d5fb1SAntonio Huete Jimenez /*
1699a34d5fb1SAntonio Huete Jimenez * Scan for one of the assignment operators outside a variable
1700a34d5fb1SAntonio Huete Jimenez * expansion.
1701a34d5fb1SAntonio Huete Jimenez */
1702a34d5fb1SAntonio Huete Jimenez while (*p != '\0') {
1703a34d5fb1SAntonio Huete Jimenez char ch = *p++;
170401e196c8SJohn Marino if (ch == '(' || ch == '{') {
170501e196c8SJohn Marino level++;
170601e196c8SJohn Marino continue;
170701e196c8SJohn Marino }
170801e196c8SJohn Marino if (ch == ')' || ch == '}') {
170901e196c8SJohn Marino level--;
171001e196c8SJohn Marino continue;
171101e196c8SJohn Marino }
1712a34d5fb1SAntonio Huete Jimenez
171301e196c8SJohn Marino if (level != 0)
171401e196c8SJohn Marino continue;
1715a34d5fb1SAntonio Huete Jimenez
1716*6eef5f0cSAntonio Huete Jimenez if ((ch == ' ' || ch == '\t') && firstSpace == NULL)
1717a34d5fb1SAntonio Huete Jimenez firstSpace = p - 1;
1718a34d5fb1SAntonio Huete Jimenez while (ch == ' ' || ch == '\t')
1719a34d5fb1SAntonio Huete Jimenez ch = *p++;
1720a34d5fb1SAntonio Huete Jimenez
1721*6eef5f0cSAntonio Huete Jimenez if (ch == '\0')
1722*6eef5f0cSAntonio Huete Jimenez return false;
17235f1e34d9SAlexandre Perrin #ifdef SUNSHCMD
1724a34d5fb1SAntonio Huete Jimenez if (ch == ':' && p[0] == 's' && p[1] == 'h') {
1725a34d5fb1SAntonio Huete Jimenez p += 2;
17265f1e34d9SAlexandre Perrin continue;
17275f1e34d9SAlexandre Perrin }
17285f1e34d9SAlexandre Perrin #endif
1729*6eef5f0cSAntonio Huete Jimenez if (ch == '=')
1730*6eef5f0cSAntonio Huete Jimenez eq = p - 1;
1731*6eef5f0cSAntonio Huete Jimenez else if (*p == '=' &&
1732*6eef5f0cSAntonio Huete Jimenez (ch == '+' || ch == ':' || ch == '?' || ch == '!'))
1733*6eef5f0cSAntonio Huete Jimenez eq = p;
1734*6eef5f0cSAntonio Huete Jimenez else if (firstSpace != NULL)
1735*6eef5f0cSAntonio Huete Jimenez return false;
1736*6eef5f0cSAntonio Huete Jimenez else
1737*6eef5f0cSAntonio Huete Jimenez continue;
1738*6eef5f0cSAntonio Huete Jimenez
1739*6eef5f0cSAntonio Huete Jimenez nameEnd = firstSpace != NULL ? firstSpace : eq;
1740*6eef5f0cSAntonio Huete Jimenez p = eq + 1;
1741a34d5fb1SAntonio Huete Jimenez cpp_skip_whitespace(&p);
1742*6eef5f0cSAntonio Huete Jimenez *out_var = AdjustVarassignOp(nameStart, nameEnd, eq, p);
1743*6eef5f0cSAntonio Huete Jimenez return true;
174401e196c8SJohn Marino }
174501e196c8SJohn Marino
1746*6eef5f0cSAntonio Huete Jimenez return false;
174701e196c8SJohn Marino }
174801e196c8SJohn Marino
1749a34d5fb1SAntonio Huete Jimenez /*
1750a34d5fb1SAntonio Huete Jimenez * Check for syntax errors such as unclosed expressions or unknown modifiers.
175101e196c8SJohn Marino */
1752a34d5fb1SAntonio Huete Jimenez static void
VarCheckSyntax(VarAssignOp type,const char * uvalue,GNode * scope)1753a34d5fb1SAntonio Huete Jimenez VarCheckSyntax(VarAssignOp type, const char *uvalue, GNode *scope)
175401e196c8SJohn Marino {
1755a34d5fb1SAntonio Huete Jimenez if (opts.strict) {
1756a34d5fb1SAntonio Huete Jimenez if (type != VAR_SUBST && strchr(uvalue, '$') != NULL) {
1757a34d5fb1SAntonio Huete Jimenez char *expandedValue;
175801e196c8SJohn Marino
1759*6eef5f0cSAntonio Huete Jimenez (void)Var_Subst(uvalue, scope, VARE_PARSE_ONLY,
1760a34d5fb1SAntonio Huete Jimenez &expandedValue);
1761a34d5fb1SAntonio Huete Jimenez /* TODO: handle errors */
1762a34d5fb1SAntonio Huete Jimenez free(expandedValue);
176301e196c8SJohn Marino }
176401e196c8SJohn Marino }
176501e196c8SJohn Marino }
176601e196c8SJohn Marino
1767*6eef5f0cSAntonio Huete Jimenez /* Perform a variable assignment that uses the operator ':='. */
1768a34d5fb1SAntonio Huete Jimenez static void
VarAssign_EvalSubst(GNode * scope,const char * name,const char * uvalue,FStr * out_avalue)1769a34d5fb1SAntonio Huete Jimenez VarAssign_EvalSubst(GNode *scope, const char *name, const char *uvalue,
1770a34d5fb1SAntonio Huete Jimenez FStr *out_avalue)
1771a34d5fb1SAntonio Huete Jimenez {
1772a34d5fb1SAntonio Huete Jimenez char *evalue;
177301e196c8SJohn Marino
177401e196c8SJohn Marino /*
177501e196c8SJohn Marino * make sure that we set the variable the first time to nothing
1776a34d5fb1SAntonio Huete Jimenez * so that it gets substituted.
1777a34d5fb1SAntonio Huete Jimenez *
1778a34d5fb1SAntonio Huete Jimenez * TODO: Add a test that demonstrates why this code is needed,
1779a34d5fb1SAntonio Huete Jimenez * apart from making the debug log longer.
1780*6eef5f0cSAntonio Huete Jimenez *
1781*6eef5f0cSAntonio Huete Jimenez * XXX: The variable name is expanded up to 3 times.
178201e196c8SJohn Marino */
1783a34d5fb1SAntonio Huete Jimenez if (!Var_ExistsExpand(scope, name))
1784a34d5fb1SAntonio Huete Jimenez Var_SetExpand(scope, name, "");
178501e196c8SJohn Marino
1786*6eef5f0cSAntonio Huete Jimenez (void)Var_Subst(uvalue, scope, VARE_KEEP_DOLLAR_UNDEF, &evalue);
1787a34d5fb1SAntonio Huete Jimenez /* TODO: handle errors */
178801e196c8SJohn Marino
1789a34d5fb1SAntonio Huete Jimenez Var_SetExpand(scope, name, evalue);
179001e196c8SJohn Marino
1791a34d5fb1SAntonio Huete Jimenez *out_avalue = FStr_InitOwn(evalue);
179201e196c8SJohn Marino }
179301e196c8SJohn Marino
1794*6eef5f0cSAntonio Huete Jimenez /* Perform a variable assignment that uses the operator '!='. */
1795a34d5fb1SAntonio Huete Jimenez static void
VarAssign_EvalShell(const char * name,const char * uvalue,GNode * scope,FStr * out_avalue)1796a34d5fb1SAntonio Huete Jimenez VarAssign_EvalShell(const char *name, const char *uvalue, GNode *scope,
1797a34d5fb1SAntonio Huete Jimenez FStr *out_avalue)
1798a34d5fb1SAntonio Huete Jimenez {
1799a34d5fb1SAntonio Huete Jimenez FStr cmd;
1800*6eef5f0cSAntonio Huete Jimenez char *output, *error;
180101e196c8SJohn Marino
1802a34d5fb1SAntonio Huete Jimenez cmd = FStr_InitRefer(uvalue);
1803*6eef5f0cSAntonio Huete Jimenez Var_Expand(&cmd, SCOPE_CMDLINE, VARE_UNDEFERR);
1804*6eef5f0cSAntonio Huete Jimenez
1805*6eef5f0cSAntonio Huete Jimenez output = Cmd_Exec(cmd.str, &error);
1806*6eef5f0cSAntonio Huete Jimenez Var_SetExpand(scope, name, output);
1807*6eef5f0cSAntonio Huete Jimenez *out_avalue = FStr_InitOwn(output);
1808*6eef5f0cSAntonio Huete Jimenez if (error != NULL) {
1809*6eef5f0cSAntonio Huete Jimenez Parse_Error(PARSE_WARNING, "%s", error);
1810*6eef5f0cSAntonio Huete Jimenez free(error);
181101e196c8SJohn Marino }
181201e196c8SJohn Marino
1813a34d5fb1SAntonio Huete Jimenez FStr_Done(&cmd);
1814a34d5fb1SAntonio Huete Jimenez }
181501e196c8SJohn Marino
18166a91b982SJohn Marino /*
1817a34d5fb1SAntonio Huete Jimenez * Perform a variable assignment.
1818a34d5fb1SAntonio Huete Jimenez *
1819*6eef5f0cSAntonio Huete Jimenez * The actual value of the variable is returned in *out_true_avalue.
1820a34d5fb1SAntonio Huete Jimenez * Especially for VAR_SUBST and VAR_SHELL this can differ from the literal
1821a34d5fb1SAntonio Huete Jimenez * value.
1822a34d5fb1SAntonio Huete Jimenez *
1823a34d5fb1SAntonio Huete Jimenez * Return whether the assignment was actually performed, which is usually
1824a34d5fb1SAntonio Huete Jimenez * the case. It is only skipped if the operator is '?=' and the variable
1825a34d5fb1SAntonio Huete Jimenez * already exists.
18266a91b982SJohn Marino */
1827*6eef5f0cSAntonio Huete Jimenez static bool
VarAssign_Eval(const char * name,VarAssignOp op,const char * uvalue,GNode * scope,FStr * out_true_avalue)1828a34d5fb1SAntonio Huete Jimenez VarAssign_Eval(const char *name, VarAssignOp op, const char *uvalue,
1829*6eef5f0cSAntonio Huete Jimenez GNode *scope, FStr *out_true_avalue)
18306a91b982SJohn Marino {
1831a34d5fb1SAntonio Huete Jimenez FStr avalue = FStr_InitRefer(uvalue);
1832a34d5fb1SAntonio Huete Jimenez
1833a34d5fb1SAntonio Huete Jimenez if (op == VAR_APPEND)
1834a34d5fb1SAntonio Huete Jimenez Var_AppendExpand(scope, name, uvalue);
1835a34d5fb1SAntonio Huete Jimenez else if (op == VAR_SUBST)
1836a34d5fb1SAntonio Huete Jimenez VarAssign_EvalSubst(scope, name, uvalue, &avalue);
1837a34d5fb1SAntonio Huete Jimenez else if (op == VAR_SHELL)
1838a34d5fb1SAntonio Huete Jimenez VarAssign_EvalShell(name, uvalue, scope, &avalue);
1839a34d5fb1SAntonio Huete Jimenez else {
1840*6eef5f0cSAntonio Huete Jimenez /* XXX: The variable name is expanded up to 2 times. */
1841a34d5fb1SAntonio Huete Jimenez if (op == VAR_DEFAULT && Var_ExistsExpand(scope, name))
1842*6eef5f0cSAntonio Huete Jimenez return false;
1843a34d5fb1SAntonio Huete Jimenez
1844a34d5fb1SAntonio Huete Jimenez /* Normal assignment -- just do it. */
1845a34d5fb1SAntonio Huete Jimenez Var_SetExpand(scope, name, uvalue);
1846a34d5fb1SAntonio Huete Jimenez }
1847a34d5fb1SAntonio Huete Jimenez
1848*6eef5f0cSAntonio Huete Jimenez *out_true_avalue = avalue;
1849*6eef5f0cSAntonio Huete Jimenez return true;
1850a34d5fb1SAntonio Huete Jimenez }
1851a34d5fb1SAntonio Huete Jimenez
1852a34d5fb1SAntonio Huete Jimenez static void
VarAssignSpecial(const char * name,const char * avalue)1853a34d5fb1SAntonio Huete Jimenez VarAssignSpecial(const char *name, const char *avalue)
1854a34d5fb1SAntonio Huete Jimenez {
1855a34d5fb1SAntonio Huete Jimenez if (strcmp(name, MAKEOVERRIDES) == 0)
1856*6eef5f0cSAntonio Huete Jimenez Main_ExportMAKEFLAGS(false); /* re-export MAKEFLAGS */
1857a34d5fb1SAntonio Huete Jimenez else if (strcmp(name, ".CURDIR") == 0) {
1858a34d5fb1SAntonio Huete Jimenez /*
1859a34d5fb1SAntonio Huete Jimenez * Someone is being (too?) clever...
1860a34d5fb1SAntonio Huete Jimenez * Let's pretend they know what they are doing and
1861a34d5fb1SAntonio Huete Jimenez * re-initialize the 'cur' CachedDir.
1862a34d5fb1SAntonio Huete Jimenez */
1863a34d5fb1SAntonio Huete Jimenez Dir_InitCur(avalue);
1864a34d5fb1SAntonio Huete Jimenez Dir_SetPATH();
1865a34d5fb1SAntonio Huete Jimenez } else if (strcmp(name, MAKE_JOB_PREFIX) == 0)
1866a34d5fb1SAntonio Huete Jimenez Job_SetPrefix();
1867a34d5fb1SAntonio Huete Jimenez else if (strcmp(name, MAKE_EXPORTED) == 0)
1868a34d5fb1SAntonio Huete Jimenez Var_ExportVars(avalue);
1869a34d5fb1SAntonio Huete Jimenez }
1870a34d5fb1SAntonio Huete Jimenez
1871*6eef5f0cSAntonio Huete Jimenez /* Perform the variable assignment in the given scope. */
1872*6eef5f0cSAntonio Huete Jimenez static void
Parse_Var(VarAssign * var,GNode * scope)1873*6eef5f0cSAntonio Huete Jimenez Parse_Var(VarAssign *var, GNode *scope)
1874a34d5fb1SAntonio Huete Jimenez {
1875a34d5fb1SAntonio Huete Jimenez FStr avalue; /* actual value (maybe expanded) */
1876a34d5fb1SAntonio Huete Jimenez
1877a34d5fb1SAntonio Huete Jimenez VarCheckSyntax(var->op, var->value, scope);
1878a34d5fb1SAntonio Huete Jimenez if (VarAssign_Eval(var->varname, var->op, var->value, scope, &avalue)) {
1879a34d5fb1SAntonio Huete Jimenez VarAssignSpecial(var->varname, avalue.str);
1880a34d5fb1SAntonio Huete Jimenez FStr_Done(&avalue);
1881a34d5fb1SAntonio Huete Jimenez }
1882a34d5fb1SAntonio Huete Jimenez }
1883a34d5fb1SAntonio Huete Jimenez
1884a34d5fb1SAntonio Huete Jimenez
1885a34d5fb1SAntonio Huete Jimenez /*
1886a34d5fb1SAntonio Huete Jimenez * See if the command possibly calls a sub-make by using the variable
1887a34d5fb1SAntonio Huete Jimenez * expressions ${.MAKE}, ${MAKE} or the plain word "make".
1888a34d5fb1SAntonio Huete Jimenez */
1889*6eef5f0cSAntonio Huete Jimenez static bool
MaybeSubMake(const char * cmd)1890a34d5fb1SAntonio Huete Jimenez MaybeSubMake(const char *cmd)
1891a34d5fb1SAntonio Huete Jimenez {
1892a34d5fb1SAntonio Huete Jimenez const char *start;
1893a34d5fb1SAntonio Huete Jimenez
1894a34d5fb1SAntonio Huete Jimenez for (start = cmd; *start != '\0'; start++) {
1895a34d5fb1SAntonio Huete Jimenez const char *p = start;
1896a34d5fb1SAntonio Huete Jimenez char endc;
1897a34d5fb1SAntonio Huete Jimenez
1898a34d5fb1SAntonio Huete Jimenez /* XXX: What if progname != "make"? */
1899*6eef5f0cSAntonio Huete Jimenez if (strncmp(p, "make", 4) == 0)
1900a34d5fb1SAntonio Huete Jimenez if (start == cmd || !ch_isalnum(p[-1]))
1901a34d5fb1SAntonio Huete Jimenez if (!ch_isalnum(p[4]))
1902*6eef5f0cSAntonio Huete Jimenez return true;
1903a34d5fb1SAntonio Huete Jimenez
1904a34d5fb1SAntonio Huete Jimenez if (*p != '$')
19056a91b982SJohn Marino continue;
1906a34d5fb1SAntonio Huete Jimenez p++;
1907a34d5fb1SAntonio Huete Jimenez
1908a34d5fb1SAntonio Huete Jimenez if (*p == '{')
1909a34d5fb1SAntonio Huete Jimenez endc = '}';
1910a34d5fb1SAntonio Huete Jimenez else if (*p == '(')
1911a34d5fb1SAntonio Huete Jimenez endc = ')';
1912a34d5fb1SAntonio Huete Jimenez else
1913a34d5fb1SAntonio Huete Jimenez continue;
1914a34d5fb1SAntonio Huete Jimenez p++;
1915a34d5fb1SAntonio Huete Jimenez
1916a34d5fb1SAntonio Huete Jimenez if (*p == '.') /* Accept either ${.MAKE} or ${MAKE}. */
1917a34d5fb1SAntonio Huete Jimenez p++;
1918a34d5fb1SAntonio Huete Jimenez
1919*6eef5f0cSAntonio Huete Jimenez if (strncmp(p, "MAKE", 4) == 0 && p[4] == endc)
1920*6eef5f0cSAntonio Huete Jimenez return true;
19216a91b982SJohn Marino }
1922*6eef5f0cSAntonio Huete Jimenez return false;
19236a91b982SJohn Marino }
19246a91b982SJohn Marino
1925a34d5fb1SAntonio Huete Jimenez /*
1926a34d5fb1SAntonio Huete Jimenez * Append the command to the target node.
192701e196c8SJohn Marino *
1928a34d5fb1SAntonio Huete Jimenez * The node may be marked as a submake node if the command is determined to
1929a34d5fb1SAntonio Huete Jimenez * be that.
193001e196c8SJohn Marino */
1931a34d5fb1SAntonio Huete Jimenez static void
GNode_AddCommand(GNode * gn,char * cmd)1932*6eef5f0cSAntonio Huete Jimenez GNode_AddCommand(GNode *gn, char *cmd)
193301e196c8SJohn Marino {
193401e196c8SJohn Marino /* Add to last (ie current) cohort for :: targets */
1935a34d5fb1SAntonio Huete Jimenez if ((gn->type & OP_DOUBLEDEP) && gn->cohorts.last != NULL)
1936a34d5fb1SAntonio Huete Jimenez gn = gn->cohorts.last->datum;
193701e196c8SJohn Marino
193801e196c8SJohn Marino /* if target already supplied, ignore commands */
193901e196c8SJohn Marino if (!(gn->type & OP_HAS_COMMANDS)) {
1940a34d5fb1SAntonio Huete Jimenez Lst_Append(&gn->commands, cmd);
1941a34d5fb1SAntonio Huete Jimenez if (MaybeSubMake(cmd))
19426a91b982SJohn Marino gn->type |= OP_SUBMAKE;
1943*6eef5f0cSAntonio Huete Jimenez RememberLocation(gn);
194401e196c8SJohn Marino } else {
1945a34d5fb1SAntonio Huete Jimenez #if 0
194601e196c8SJohn Marino /* XXX: We cannot do this until we fix the tree */
1947a34d5fb1SAntonio Huete Jimenez Lst_Append(&gn->commands, cmd);
194801e196c8SJohn Marino Parse_Error(PARSE_WARNING,
194901e196c8SJohn Marino "overriding commands for target \"%s\"; "
1950*6eef5f0cSAntonio Huete Jimenez "previous commands defined at %s: %u ignored",
195101e196c8SJohn Marino gn->name, gn->fname, gn->lineno);
195201e196c8SJohn Marino #else
195301e196c8SJohn Marino Parse_Error(PARSE_WARNING,
195401e196c8SJohn Marino "duplicate script for target \"%s\" ignored",
195501e196c8SJohn Marino gn->name);
1956*6eef5f0cSAntonio Huete Jimenez ParseErrorInternal(gn, PARSE_WARNING,
195701e196c8SJohn Marino "using previous script for \"%s\" defined here",
195801e196c8SJohn Marino gn->name);
195901e196c8SJohn Marino #endif
196001e196c8SJohn Marino }
196101e196c8SJohn Marino }
196201e196c8SJohn Marino
1963a34d5fb1SAntonio Huete Jimenez /*
1964a34d5fb1SAntonio Huete Jimenez * Add a directory to the path searched for included makefiles bracketed
1965a34d5fb1SAntonio Huete Jimenez * by double-quotes.
196601e196c8SJohn Marino */
196701e196c8SJohn Marino void
Parse_AddIncludeDir(const char * dir)1968a34d5fb1SAntonio Huete Jimenez Parse_AddIncludeDir(const char *dir)
196901e196c8SJohn Marino {
1970a34d5fb1SAntonio Huete Jimenez (void)SearchPath_Add(parseIncPath, dir);
197101e196c8SJohn Marino }
197201e196c8SJohn Marino
1973*6eef5f0cSAntonio Huete Jimenez
1974a34d5fb1SAntonio Huete Jimenez /*
1975*6eef5f0cSAntonio Huete Jimenez * Parse a directive like '.include' or '.-include'.
197601e196c8SJohn Marino *
1977*6eef5f0cSAntonio Huete Jimenez * .include "user-makefile.mk"
1978*6eef5f0cSAntonio Huete Jimenez * .include <system-makefile.mk>
197901e196c8SJohn Marino */
198001e196c8SJohn Marino static void
ParseInclude(char * directive)1981*6eef5f0cSAntonio Huete Jimenez ParseInclude(char *directive)
198201e196c8SJohn Marino {
1983*6eef5f0cSAntonio Huete Jimenez char endc; /* '>' or '"' */
1984*6eef5f0cSAntonio Huete Jimenez char *p;
1985*6eef5f0cSAntonio Huete Jimenez bool silent = directive[0] != 'i';
1986*6eef5f0cSAntonio Huete Jimenez FStr file;
198701e196c8SJohn Marino
1988*6eef5f0cSAntonio Huete Jimenez p = directive + (silent ? 8 : 7);
1989*6eef5f0cSAntonio Huete Jimenez pp_skip_hspace(&p);
199001e196c8SJohn Marino
1991*6eef5f0cSAntonio Huete Jimenez if (*p != '"' && *p != '<') {
199201e196c8SJohn Marino Parse_Error(PARSE_FATAL,
199301e196c8SJohn Marino ".include filename must be delimited by '\"' or '<'");
199401e196c8SJohn Marino return;
199501e196c8SJohn Marino }
199601e196c8SJohn Marino
1997*6eef5f0cSAntonio Huete Jimenez if (*p++ == '<')
199801e196c8SJohn Marino endc = '>';
1999a34d5fb1SAntonio Huete Jimenez else
200001e196c8SJohn Marino endc = '"';
2001*6eef5f0cSAntonio Huete Jimenez file = FStr_InitRefer(p);
200201e196c8SJohn Marino
200301e196c8SJohn Marino /* Skip to matching delimiter */
2004*6eef5f0cSAntonio Huete Jimenez while (*p != '\0' && *p != endc)
2005*6eef5f0cSAntonio Huete Jimenez p++;
200601e196c8SJohn Marino
2007*6eef5f0cSAntonio Huete Jimenez if (*p != endc) {
200801e196c8SJohn Marino Parse_Error(PARSE_FATAL,
2009a34d5fb1SAntonio Huete Jimenez "Unclosed .include filename. '%c' expected", endc);
201001e196c8SJohn Marino return;
201101e196c8SJohn Marino }
2012a34d5fb1SAntonio Huete Jimenez
2013*6eef5f0cSAntonio Huete Jimenez *p = '\0';
201401e196c8SJohn Marino
2015*6eef5f0cSAntonio Huete Jimenez Var_Expand(&file, SCOPE_CMDLINE, VARE_WANTRES);
2016*6eef5f0cSAntonio Huete Jimenez IncludeFile(file.str, endc == '>', directive[0] == 'd', silent);
2017*6eef5f0cSAntonio Huete Jimenez FStr_Done(&file);
201801e196c8SJohn Marino }
201901e196c8SJohn Marino
2020a34d5fb1SAntonio Huete Jimenez /*
2021a34d5fb1SAntonio Huete Jimenez * Split filename into dirname + basename, then assign these to the
2022a34d5fb1SAntonio Huete Jimenez * given variables.
20236a91b982SJohn Marino */
20246a91b982SJohn Marino static void
SetFilenameVars(const char * filename,const char * dirvar,const char * filevar)2025a34d5fb1SAntonio Huete Jimenez SetFilenameVars(const char *filename, const char *dirvar, const char *filevar)
20266a91b982SJohn Marino {
2027ec533708SSascha Wildner const char *slash, *basename;
2028ec533708SSascha Wildner FStr dirname;
202901e196c8SJohn Marino
203001e196c8SJohn Marino slash = strrchr(filename, '/');
203101e196c8SJohn Marino if (slash == NULL) {
2032ec533708SSascha Wildner dirname = FStr_InitRefer(curdir);
2033a34d5fb1SAntonio Huete Jimenez basename = filename;
203401e196c8SJohn Marino } else {
2035ec533708SSascha Wildner dirname = FStr_InitOwn(bmake_strsedup(filename, slash));
2036a34d5fb1SAntonio Huete Jimenez basename = slash + 1;
203701e196c8SJohn Marino }
2038a34d5fb1SAntonio Huete Jimenez
2039*6eef5f0cSAntonio Huete Jimenez Global_Set(dirvar, dirname.str);
2040*6eef5f0cSAntonio Huete Jimenez Global_Set(filevar, basename);
2041a34d5fb1SAntonio Huete Jimenez
2042*6eef5f0cSAntonio Huete Jimenez DEBUG4(PARSE, "SetFilenameVars: ${%s} = `%s' ${%s} = `%s'\n",
2043*6eef5f0cSAntonio Huete Jimenez dirvar, dirname.str, filevar, basename);
2044ec533708SSascha Wildner FStr_Done(&dirname);
204501e196c8SJohn Marino }
204601e196c8SJohn Marino
204701e196c8SJohn Marino /*
2048a34d5fb1SAntonio Huete Jimenez * Return the immediately including file.
2049a34d5fb1SAntonio Huete Jimenez *
2050a34d5fb1SAntonio Huete Jimenez * This is made complicated since the .for loop is implemented as a special
2051a34d5fb1SAntonio Huete Jimenez * kind of .include; see For_Run.
205201e196c8SJohn Marino */
2053a34d5fb1SAntonio Huete Jimenez static const char *
GetActuallyIncludingFile(void)2054a34d5fb1SAntonio Huete Jimenez GetActuallyIncludingFile(void)
2055a34d5fb1SAntonio Huete Jimenez {
2056a34d5fb1SAntonio Huete Jimenez size_t i;
2057*6eef5f0cSAntonio Huete Jimenez const IncludedFile *incs = GetInclude(0);
205801e196c8SJohn Marino
2059a34d5fb1SAntonio Huete Jimenez for (i = includes.len; i >= 2; i--)
2060*6eef5f0cSAntonio Huete Jimenez if (incs[i - 1].forLoop == NULL)
2061*6eef5f0cSAntonio Huete Jimenez return incs[i - 2].name.str;
2062a34d5fb1SAntonio Huete Jimenez return NULL;
2063a34d5fb1SAntonio Huete Jimenez }
2064a34d5fb1SAntonio Huete Jimenez
2065a34d5fb1SAntonio Huete Jimenez /* Set .PARSEDIR, .PARSEFILE, .INCLUDEDFROMDIR and .INCLUDEDFROMFILE. */
2066a34d5fb1SAntonio Huete Jimenez static void
SetParseFile(const char * filename)2067*6eef5f0cSAntonio Huete Jimenez SetParseFile(const char *filename)
2068a34d5fb1SAntonio Huete Jimenez {
2069a34d5fb1SAntonio Huete Jimenez const char *including;
2070a34d5fb1SAntonio Huete Jimenez
2071a34d5fb1SAntonio Huete Jimenez SetFilenameVars(filename, ".PARSEDIR", ".PARSEFILE");
2072a34d5fb1SAntonio Huete Jimenez
2073a34d5fb1SAntonio Huete Jimenez including = GetActuallyIncludingFile();
2074a34d5fb1SAntonio Huete Jimenez if (including != NULL) {
2075a34d5fb1SAntonio Huete Jimenez SetFilenameVars(including,
2076a34d5fb1SAntonio Huete Jimenez ".INCLUDEDFROMDIR", ".INCLUDEDFROMFILE");
2077a34d5fb1SAntonio Huete Jimenez } else {
2078a34d5fb1SAntonio Huete Jimenez Global_Delete(".INCLUDEDFROMDIR");
2079a34d5fb1SAntonio Huete Jimenez Global_Delete(".INCLUDEDFROMFILE");
2080a34d5fb1SAntonio Huete Jimenez }
2081a34d5fb1SAntonio Huete Jimenez }
2082a34d5fb1SAntonio Huete Jimenez
2083*6eef5f0cSAntonio Huete Jimenez static bool
StrContainsWord(const char * str,const char * word)2084a34d5fb1SAntonio Huete Jimenez StrContainsWord(const char *str, const char *word)
2085a34d5fb1SAntonio Huete Jimenez {
2086a34d5fb1SAntonio Huete Jimenez size_t strLen = strlen(str);
2087a34d5fb1SAntonio Huete Jimenez size_t wordLen = strlen(word);
2088*6eef5f0cSAntonio Huete Jimenez const char *p;
2089a34d5fb1SAntonio Huete Jimenez
2090a34d5fb1SAntonio Huete Jimenez if (strLen < wordLen)
2091*6eef5f0cSAntonio Huete Jimenez return false;
2092a34d5fb1SAntonio Huete Jimenez
2093a34d5fb1SAntonio Huete Jimenez for (p = str; p != NULL; p = strchr(p, ' ')) {
2094a34d5fb1SAntonio Huete Jimenez if (*p == ' ')
2095a34d5fb1SAntonio Huete Jimenez p++;
2096*6eef5f0cSAntonio Huete Jimenez if (p > str + strLen - wordLen)
2097*6eef5f0cSAntonio Huete Jimenez return false;
2098a34d5fb1SAntonio Huete Jimenez
2099a34d5fb1SAntonio Huete Jimenez if (memcmp(p, word, wordLen) == 0 &&
2100a34d5fb1SAntonio Huete Jimenez (p[wordLen] == '\0' || p[wordLen] == ' '))
2101*6eef5f0cSAntonio Huete Jimenez return true;
2102a34d5fb1SAntonio Huete Jimenez }
2103*6eef5f0cSAntonio Huete Jimenez return false;
2104a34d5fb1SAntonio Huete Jimenez }
2105a34d5fb1SAntonio Huete Jimenez
2106a34d5fb1SAntonio Huete Jimenez /*
2107a34d5fb1SAntonio Huete Jimenez * XXX: Searching through a set of words with this linear search is
2108a34d5fb1SAntonio Huete Jimenez * inefficient for variables that contain thousands of words.
2109a34d5fb1SAntonio Huete Jimenez *
2110a34d5fb1SAntonio Huete Jimenez * XXX: The paths in this list don't seem to be normalized in any way.
2111a34d5fb1SAntonio Huete Jimenez */
2112*6eef5f0cSAntonio Huete Jimenez static bool
VarContainsWord(const char * varname,const char * word)2113a34d5fb1SAntonio Huete Jimenez VarContainsWord(const char *varname, const char *word)
2114a34d5fb1SAntonio Huete Jimenez {
2115a34d5fb1SAntonio Huete Jimenez FStr val = Var_Value(SCOPE_GLOBAL, varname);
2116*6eef5f0cSAntonio Huete Jimenez bool found = val.str != NULL && StrContainsWord(val.str, word);
2117a34d5fb1SAntonio Huete Jimenez FStr_Done(&val);
2118a34d5fb1SAntonio Huete Jimenez return found;
2119a34d5fb1SAntonio Huete Jimenez }
2120a34d5fb1SAntonio Huete Jimenez
2121a34d5fb1SAntonio Huete Jimenez /*
2122a34d5fb1SAntonio Huete Jimenez * Track the makefiles we read - so makefiles can set dependencies on them.
2123a34d5fb1SAntonio Huete Jimenez * Avoid adding anything more than once.
2124a34d5fb1SAntonio Huete Jimenez *
2125a34d5fb1SAntonio Huete Jimenez * Time complexity: O(n) per call, in total O(n^2), where n is the number
2126a34d5fb1SAntonio Huete Jimenez * of makefiles that have been loaded.
2127a34d5fb1SAntonio Huete Jimenez */
212801e196c8SJohn Marino static void
TrackInput(const char * name)2129*6eef5f0cSAntonio Huete Jimenez TrackInput(const char *name)
213001e196c8SJohn Marino {
2131a34d5fb1SAntonio Huete Jimenez if (!VarContainsWord(MAKE_MAKEFILES, name))
2132a34d5fb1SAntonio Huete Jimenez Global_Append(MAKE_MAKEFILES, name);
213301e196c8SJohn Marino }
213401e196c8SJohn Marino
213501e196c8SJohn Marino
2136*6eef5f0cSAntonio Huete Jimenez /* Parse from the given buffer, later return to the current file. */
213701e196c8SJohn Marino void
Parse_PushInput(const char * name,unsigned lineno,unsigned readLines,Buffer buf,struct ForLoop * forLoop)2138*6eef5f0cSAntonio Huete Jimenez Parse_PushInput(const char *name, unsigned lineno, unsigned readLines,
2139*6eef5f0cSAntonio Huete Jimenez Buffer buf, struct ForLoop *forLoop)
214001e196c8SJohn Marino {
2141*6eef5f0cSAntonio Huete Jimenez IncludedFile *curFile;
214201e196c8SJohn Marino
2143*6eef5f0cSAntonio Huete Jimenez if (forLoop != NULL)
2144*6eef5f0cSAntonio Huete Jimenez name = CurFile()->name.str;
214501e196c8SJohn Marino else
2146*6eef5f0cSAntonio Huete Jimenez TrackInput(name);
214701e196c8SJohn Marino
2148*6eef5f0cSAntonio Huete Jimenez DEBUG3(PARSE, "Parse_PushInput: %s %s, line %u\n",
2149*6eef5f0cSAntonio Huete Jimenez forLoop != NULL ? ".for loop in": "file", name, lineno);
215001e196c8SJohn Marino
2151a34d5fb1SAntonio Huete Jimenez curFile = Vector_Push(&includes);
2152*6eef5f0cSAntonio Huete Jimenez curFile->name = FStr_InitOwn(bmake_strdup(name));
2153a34d5fb1SAntonio Huete Jimenez curFile->lineno = lineno;
2154*6eef5f0cSAntonio Huete Jimenez curFile->readLines = readLines;
2155*6eef5f0cSAntonio Huete Jimenez curFile->forHeadLineno = lineno;
2156*6eef5f0cSAntonio Huete Jimenez curFile->forBodyReadLines = readLines;
2157*6eef5f0cSAntonio Huete Jimenez curFile->buf = buf;
2158f445c897SJohn Marino curFile->depending = doing_depend; /* restore this on EOF */
2159*6eef5f0cSAntonio Huete Jimenez curFile->forLoop = forLoop;
216001e196c8SJohn Marino
2161*6eef5f0cSAntonio Huete Jimenez if (forLoop != NULL && !For_NextIteration(forLoop, &curFile->buf))
2162*6eef5f0cSAntonio Huete Jimenez abort(); /* see For_Run */
216301e196c8SJohn Marino
2164*6eef5f0cSAntonio Huete Jimenez curFile->buf_ptr = curFile->buf.data;
2165*6eef5f0cSAntonio Huete Jimenez curFile->buf_end = curFile->buf.data + curFile->buf.len;
2166*6eef5f0cSAntonio Huete Jimenez curFile->condMinDepth = cond_depth;
2167*6eef5f0cSAntonio Huete Jimenez SetParseFile(name);
216801e196c8SJohn Marino }
216901e196c8SJohn Marino
2170a34d5fb1SAntonio Huete Jimenez /* Check if the directive is an include directive. */
2171*6eef5f0cSAntonio Huete Jimenez static bool
IsInclude(const char * dir,bool sysv)2172*6eef5f0cSAntonio Huete Jimenez IsInclude(const char *dir, bool sysv)
2173ca58f742SDaniel Fojt {
2174a34d5fb1SAntonio Huete Jimenez if (dir[0] == 's' || dir[0] == '-' || (dir[0] == 'd' && !sysv))
2175a34d5fb1SAntonio Huete Jimenez dir++;
2176ca58f742SDaniel Fojt
2177a34d5fb1SAntonio Huete Jimenez if (strncmp(dir, "include", 7) != 0)
2178*6eef5f0cSAntonio Huete Jimenez return false;
2179ca58f742SDaniel Fojt
2180a34d5fb1SAntonio Huete Jimenez /* Space is not mandatory for BSD .include */
2181a34d5fb1SAntonio Huete Jimenez return !sysv || ch_isspace(dir[7]);
2182ca58f742SDaniel Fojt }
2183ca58f742SDaniel Fojt
2184ca58f742SDaniel Fojt
218501e196c8SJohn Marino #ifdef SYSVINCLUDE
2186a34d5fb1SAntonio Huete Jimenez /* Check if the line is a SYSV include directive. */
2187*6eef5f0cSAntonio Huete Jimenez static bool
IsSysVInclude(const char * line)2188ca58f742SDaniel Fojt IsSysVInclude(const char *line)
2189ca58f742SDaniel Fojt {
2190ca58f742SDaniel Fojt const char *p;
2191ca58f742SDaniel Fojt
2192*6eef5f0cSAntonio Huete Jimenez if (!IsInclude(line, true))
2193*6eef5f0cSAntonio Huete Jimenez return false;
2194ca58f742SDaniel Fojt
2195a34d5fb1SAntonio Huete Jimenez /* Avoid interpreting a dependency line as an include */
2196ca58f742SDaniel Fojt for (p = line; (p = strchr(p, ':')) != NULL;) {
2197a34d5fb1SAntonio Huete Jimenez
2198a34d5fb1SAntonio Huete Jimenez /* end of line -> it's a dependency */
2199a34d5fb1SAntonio Huete Jimenez if (*++p == '\0')
2200*6eef5f0cSAntonio Huete Jimenez return false;
2201a34d5fb1SAntonio Huete Jimenez
2202a34d5fb1SAntonio Huete Jimenez /* '::' operator or ': ' -> it's a dependency */
2203a34d5fb1SAntonio Huete Jimenez if (*p == ':' || ch_isspace(*p))
2204*6eef5f0cSAntonio Huete Jimenez return false;
2205ca58f742SDaniel Fojt }
2206*6eef5f0cSAntonio Huete Jimenez return true;
2207ca58f742SDaniel Fojt }
2208ca58f742SDaniel Fojt
2209a34d5fb1SAntonio Huete Jimenez /* Push to another file. The line points to the word "include". */
221001e196c8SJohn Marino static void
ParseTraditionalInclude(char * line)221101e196c8SJohn Marino ParseTraditionalInclude(char *line)
221201e196c8SJohn Marino {
221301e196c8SJohn Marino char *cp; /* current position in file spec */
2214*6eef5f0cSAntonio Huete Jimenez bool done = false;
2215*6eef5f0cSAntonio Huete Jimenez bool silent = line[0] != 'i';
2216a34d5fb1SAntonio Huete Jimenez char *file = line + (silent ? 8 : 7);
221701e196c8SJohn Marino char *all_files;
221801e196c8SJohn Marino
2219*6eef5f0cSAntonio Huete Jimenez DEBUG1(PARSE, "ParseTraditionalInclude: %s\n", file);
222001e196c8SJohn Marino
2221a34d5fb1SAntonio Huete Jimenez pp_skip_whitespace(&file);
222201e196c8SJohn Marino
2223a34d5fb1SAntonio Huete Jimenez (void)Var_Subst(file, SCOPE_CMDLINE, VARE_WANTRES, &all_files);
2224a34d5fb1SAntonio Huete Jimenez /* TODO: handle errors */
222501e196c8SJohn Marino
222601e196c8SJohn Marino for (file = all_files; !done; file = cp + 1) {
222701e196c8SJohn Marino /* Skip to end of line or next whitespace */
2228a34d5fb1SAntonio Huete Jimenez for (cp = file; *cp != '\0' && !ch_isspace(*cp); cp++)
222901e196c8SJohn Marino continue;
223001e196c8SJohn Marino
2231a34d5fb1SAntonio Huete Jimenez if (*cp != '\0')
223201e196c8SJohn Marino *cp = '\0';
223301e196c8SJohn Marino else
2234*6eef5f0cSAntonio Huete Jimenez done = true;
223501e196c8SJohn Marino
2236*6eef5f0cSAntonio Huete Jimenez IncludeFile(file, false, false, silent);
223701e196c8SJohn Marino }
2238*6eef5f0cSAntonio Huete Jimenez
223901e196c8SJohn Marino free(all_files);
224001e196c8SJohn Marino }
224101e196c8SJohn Marino #endif
224201e196c8SJohn Marino
224301e196c8SJohn Marino #ifdef GMAKEEXPORT
2244a34d5fb1SAntonio Huete Jimenez /* Parse "export <variable>=<value>", and actually export it. */
224501e196c8SJohn Marino static void
ParseGmakeExport(char * line)224601e196c8SJohn Marino ParseGmakeExport(char *line)
224701e196c8SJohn Marino {
2248a34d5fb1SAntonio Huete Jimenez char *variable = line + 6;
224901e196c8SJohn Marino char *value;
225001e196c8SJohn Marino
2251*6eef5f0cSAntonio Huete Jimenez DEBUG1(PARSE, "ParseGmakeExport: %s\n", variable);
225201e196c8SJohn Marino
2253a34d5fb1SAntonio Huete Jimenez pp_skip_whitespace(&variable);
225401e196c8SJohn Marino
2255a34d5fb1SAntonio Huete Jimenez for (value = variable; *value != '\0' && *value != '='; value++)
225601e196c8SJohn Marino continue;
225701e196c8SJohn Marino
225801e196c8SJohn Marino if (*value != '=') {
225901e196c8SJohn Marino Parse_Error(PARSE_FATAL,
226001e196c8SJohn Marino "Variable/Value missing from \"export\"");
226101e196c8SJohn Marino return;
226201e196c8SJohn Marino }
22635f1e34d9SAlexandre Perrin *value++ = '\0'; /* terminate variable */
226401e196c8SJohn Marino
226501e196c8SJohn Marino /*
226601e196c8SJohn Marino * Expand the value before putting it in the environment.
226701e196c8SJohn Marino */
2268a34d5fb1SAntonio Huete Jimenez (void)Var_Subst(value, SCOPE_CMDLINE, VARE_WANTRES, &value);
2269a34d5fb1SAntonio Huete Jimenez /* TODO: handle errors */
2270a34d5fb1SAntonio Huete Jimenez
227101e196c8SJohn Marino setenv(variable, value, 1);
2272ca58f742SDaniel Fojt free(value);
227301e196c8SJohn Marino }
227401e196c8SJohn Marino #endif
227501e196c8SJohn Marino
2276a34d5fb1SAntonio Huete Jimenez /*
2277a34d5fb1SAntonio Huete Jimenez * Called when EOF is reached in the current file. If we were reading an
2278a34d5fb1SAntonio Huete Jimenez * include file or a .for loop, the includes stack is popped and things set
2279a34d5fb1SAntonio Huete Jimenez * up to go back to reading the previous file at the previous location.
228001e196c8SJohn Marino *
228101e196c8SJohn Marino * Results:
2282*6eef5f0cSAntonio Huete Jimenez * true to continue parsing, i.e. it had only reached the end of an
2283*6eef5f0cSAntonio Huete Jimenez * included file, false if the main file has been parsed completely.
228401e196c8SJohn Marino */
2285*6eef5f0cSAntonio Huete Jimenez static bool
ParseEOF(void)228601e196c8SJohn Marino ParseEOF(void)
228701e196c8SJohn Marino {
2288*6eef5f0cSAntonio Huete Jimenez IncludedFile *curFile = CurFile();
228901e196c8SJohn Marino
2290*6eef5f0cSAntonio Huete Jimenez doing_depend = curFile->depending;
2291*6eef5f0cSAntonio Huete Jimenez if (curFile->forLoop != NULL &&
2292*6eef5f0cSAntonio Huete Jimenez For_NextIteration(curFile->forLoop, &curFile->buf)) {
2293*6eef5f0cSAntonio Huete Jimenez curFile->buf_ptr = curFile->buf.data;
2294*6eef5f0cSAntonio Huete Jimenez curFile->buf_end = curFile->buf.data + curFile->buf.len;
2295*6eef5f0cSAntonio Huete Jimenez curFile->readLines = curFile->forBodyReadLines;
2296*6eef5f0cSAntonio Huete Jimenez return true;
229701e196c8SJohn Marino }
229801e196c8SJohn Marino
2299*6eef5f0cSAntonio Huete Jimenez Cond_EndFile();
2300*6eef5f0cSAntonio Huete Jimenez
2301*6eef5f0cSAntonio Huete Jimenez FStr_Done(&curFile->name);
2302*6eef5f0cSAntonio Huete Jimenez Buf_Done(&curFile->buf);
2303*6eef5f0cSAntonio Huete Jimenez if (curFile->forLoop != NULL)
2304*6eef5f0cSAntonio Huete Jimenez ForLoop_Free(curFile->forLoop);
2305a34d5fb1SAntonio Huete Jimenez Vector_Pop(&includes);
230601e196c8SJohn Marino
2307a34d5fb1SAntonio Huete Jimenez if (includes.len == 0) {
230801e196c8SJohn Marino /* We've run out of input */
2309a34d5fb1SAntonio Huete Jimenez Global_Delete(".PARSEDIR");
2310a34d5fb1SAntonio Huete Jimenez Global_Delete(".PARSEFILE");
2311a34d5fb1SAntonio Huete Jimenez Global_Delete(".INCLUDEDFROMDIR");
2312a34d5fb1SAntonio Huete Jimenez Global_Delete(".INCLUDEDFROMFILE");
2313*6eef5f0cSAntonio Huete Jimenez return false;
231401e196c8SJohn Marino }
231501e196c8SJohn Marino
2316a34d5fb1SAntonio Huete Jimenez curFile = CurFile();
2317*6eef5f0cSAntonio Huete Jimenez DEBUG2(PARSE, "ParseEOF: returning to file %s, line %u\n",
2318*6eef5f0cSAntonio Huete Jimenez curFile->name.str, curFile->readLines + 1);
231901e196c8SJohn Marino
2320*6eef5f0cSAntonio Huete Jimenez SetParseFile(curFile->name.str);
2321*6eef5f0cSAntonio Huete Jimenez return true;
232201e196c8SJohn Marino }
232301e196c8SJohn Marino
2324a34d5fb1SAntonio Huete Jimenez typedef enum ParseRawLineResult {
2325a34d5fb1SAntonio Huete Jimenez PRLR_LINE,
2326a34d5fb1SAntonio Huete Jimenez PRLR_EOF,
2327a34d5fb1SAntonio Huete Jimenez PRLR_ERROR
2328a34d5fb1SAntonio Huete Jimenez } ParseRawLineResult;
232901e196c8SJohn Marino
233001e196c8SJohn Marino /*
2331a34d5fb1SAntonio Huete Jimenez * Parse until the end of a line, taking into account lines that end with
2332*6eef5f0cSAntonio Huete Jimenez * backslash-newline. The resulting line goes from out_line to out_line_end;
2333*6eef5f0cSAntonio Huete Jimenez * the line is not null-terminated.
233401e196c8SJohn Marino */
2335a34d5fb1SAntonio Huete Jimenez static ParseRawLineResult
ParseRawLine(IncludedFile * curFile,char ** out_line,char ** out_line_end,char ** out_firstBackslash,char ** out_commentLineEnd)2336*6eef5f0cSAntonio Huete Jimenez ParseRawLine(IncludedFile *curFile, char **out_line, char **out_line_end,
2337*6eef5f0cSAntonio Huete Jimenez char **out_firstBackslash, char **out_commentLineEnd)
2338a34d5fb1SAntonio Huete Jimenez {
2339a34d5fb1SAntonio Huete Jimenez char *line = curFile->buf_ptr;
2340*6eef5f0cSAntonio Huete Jimenez char *buf_end = curFile->buf_end;
2341a34d5fb1SAntonio Huete Jimenez char *p = line;
2342a34d5fb1SAntonio Huete Jimenez char *line_end = line;
2343a34d5fb1SAntonio Huete Jimenez char *firstBackslash = NULL;
2344*6eef5f0cSAntonio Huete Jimenez char *commentLineEnd = NULL;
2345a34d5fb1SAntonio Huete Jimenez ParseRawLineResult res = PRLR_LINE;
2346a34d5fb1SAntonio Huete Jimenez
2347*6eef5f0cSAntonio Huete Jimenez curFile->readLines++;
2348a34d5fb1SAntonio Huete Jimenez
2349a34d5fb1SAntonio Huete Jimenez for (;;) {
2350a34d5fb1SAntonio Huete Jimenez char ch;
2351a34d5fb1SAntonio Huete Jimenez
2352*6eef5f0cSAntonio Huete Jimenez if (p == buf_end) {
2353a34d5fb1SAntonio Huete Jimenez res = PRLR_EOF;
235401e196c8SJohn Marino break;
235501e196c8SJohn Marino }
2356a34d5fb1SAntonio Huete Jimenez
2357a34d5fb1SAntonio Huete Jimenez ch = *p;
2358*6eef5f0cSAntonio Huete Jimenez if (ch == '\0' || (ch == '\\' && p[1] == '\0')) {
235901e196c8SJohn Marino Parse_Error(PARSE_FATAL, "Zero byte read from file");
2360a34d5fb1SAntonio Huete Jimenez return PRLR_ERROR;
236101e196c8SJohn Marino }
236201e196c8SJohn Marino
2363a34d5fb1SAntonio Huete Jimenez /* Treat next character after '\' as literal. */
236401e196c8SJohn Marino if (ch == '\\') {
2365a34d5fb1SAntonio Huete Jimenez if (firstBackslash == NULL)
2366a34d5fb1SAntonio Huete Jimenez firstBackslash = p;
2367a34d5fb1SAntonio Huete Jimenez if (p[1] == '\n') {
2368*6eef5f0cSAntonio Huete Jimenez curFile->readLines++;
2369*6eef5f0cSAntonio Huete Jimenez if (p + 2 == buf_end) {
2370a34d5fb1SAntonio Huete Jimenez line_end = p;
2371a34d5fb1SAntonio Huete Jimenez *line_end = '\n';
2372a34d5fb1SAntonio Huete Jimenez p += 2;
237301e196c8SJohn Marino continue;
237401e196c8SJohn Marino }
237501e196c8SJohn Marino }
2376a34d5fb1SAntonio Huete Jimenez p += 2;
2377a34d5fb1SAntonio Huete Jimenez line_end = p;
2378*6eef5f0cSAntonio Huete Jimenez assert(p <= buf_end);
2379a34d5fb1SAntonio Huete Jimenez continue;
2380a34d5fb1SAntonio Huete Jimenez }
2381a34d5fb1SAntonio Huete Jimenez
2382a34d5fb1SAntonio Huete Jimenez /*
2383a34d5fb1SAntonio Huete Jimenez * Remember the first '#' for comment stripping, unless
2384a34d5fb1SAntonio Huete Jimenez * the previous char was '[', as in the modifier ':[#]'.
2385a34d5fb1SAntonio Huete Jimenez */
2386*6eef5f0cSAntonio Huete Jimenez if (ch == '#' && commentLineEnd == NULL &&
2387a34d5fb1SAntonio Huete Jimenez !(p > line && p[-1] == '['))
2388*6eef5f0cSAntonio Huete Jimenez commentLineEnd = line_end;
2389a34d5fb1SAntonio Huete Jimenez
2390a34d5fb1SAntonio Huete Jimenez p++;
239101e196c8SJohn Marino if (ch == '\n')
239201e196c8SJohn Marino break;
2393a34d5fb1SAntonio Huete Jimenez
2394a34d5fb1SAntonio Huete Jimenez /* We are not interested in trailing whitespace. */
2395a34d5fb1SAntonio Huete Jimenez if (!ch_isspace(ch))
2396a34d5fb1SAntonio Huete Jimenez line_end = p;
239701e196c8SJohn Marino }
239801e196c8SJohn Marino
2399a34d5fb1SAntonio Huete Jimenez curFile->buf_ptr = p;
2400*6eef5f0cSAntonio Huete Jimenez *out_line = line;
2401a34d5fb1SAntonio Huete Jimenez *out_line_end = line_end;
2402a34d5fb1SAntonio Huete Jimenez *out_firstBackslash = firstBackslash;
2403*6eef5f0cSAntonio Huete Jimenez *out_commentLineEnd = commentLineEnd;
2404a34d5fb1SAntonio Huete Jimenez return res;
2405a34d5fb1SAntonio Huete Jimenez }
240601e196c8SJohn Marino
2407a34d5fb1SAntonio Huete Jimenez /*
2408a34d5fb1SAntonio Huete Jimenez * Beginning at start, unescape '\#' to '#' and replace backslash-newline
2409a34d5fb1SAntonio Huete Jimenez * with a single space.
2410a34d5fb1SAntonio Huete Jimenez */
2411a34d5fb1SAntonio Huete Jimenez static void
UnescapeBackslash(char * line,char * start)2412a34d5fb1SAntonio Huete Jimenez UnescapeBackslash(char *line, char *start)
2413a34d5fb1SAntonio Huete Jimenez {
2414*6eef5f0cSAntonio Huete Jimenez const char *src = start;
2415a34d5fb1SAntonio Huete Jimenez char *dst = start;
2416a34d5fb1SAntonio Huete Jimenez char *spaceStart = line;
2417a34d5fb1SAntonio Huete Jimenez
2418a34d5fb1SAntonio Huete Jimenez for (;;) {
2419a34d5fb1SAntonio Huete Jimenez char ch = *src++;
2420a34d5fb1SAntonio Huete Jimenez if (ch != '\\') {
2421a34d5fb1SAntonio Huete Jimenez if (ch == '\0')
2422a34d5fb1SAntonio Huete Jimenez break;
2423a34d5fb1SAntonio Huete Jimenez *dst++ = ch;
2424a34d5fb1SAntonio Huete Jimenez continue;
2425a34d5fb1SAntonio Huete Jimenez }
2426a34d5fb1SAntonio Huete Jimenez
2427a34d5fb1SAntonio Huete Jimenez ch = *src++;
2428a34d5fb1SAntonio Huete Jimenez if (ch == '\0') {
2429*6eef5f0cSAntonio Huete Jimenez /* Delete '\\' at the end of the buffer. */
2430a34d5fb1SAntonio Huete Jimenez dst--;
2431a34d5fb1SAntonio Huete Jimenez break;
2432a34d5fb1SAntonio Huete Jimenez }
2433a34d5fb1SAntonio Huete Jimenez
2434*6eef5f0cSAntonio Huete Jimenez /* Delete '\\' from before '#' on non-command lines. */
2435*6eef5f0cSAntonio Huete Jimenez if (ch == '#' && line[0] != '\t')
2436a34d5fb1SAntonio Huete Jimenez *dst++ = ch;
2437*6eef5f0cSAntonio Huete Jimenez else if (ch == '\n') {
2438*6eef5f0cSAntonio Huete Jimenez cpp_skip_hspace(&src);
2439a34d5fb1SAntonio Huete Jimenez *dst++ = ' ';
2440*6eef5f0cSAntonio Huete Jimenez } else {
2441*6eef5f0cSAntonio Huete Jimenez /* Leave '\\' in the buffer for later. */
2442*6eef5f0cSAntonio Huete Jimenez *dst++ = '\\';
2443*6eef5f0cSAntonio Huete Jimenez *dst++ = ch;
2444*6eef5f0cSAntonio Huete Jimenez /* Keep an escaped ' ' at the line end. */
2445*6eef5f0cSAntonio Huete Jimenez spaceStart = dst;
2446*6eef5f0cSAntonio Huete Jimenez }
2447a34d5fb1SAntonio Huete Jimenez }
2448a34d5fb1SAntonio Huete Jimenez
2449a34d5fb1SAntonio Huete Jimenez /* Delete any trailing spaces - eg from empty continuations */
2450a34d5fb1SAntonio Huete Jimenez while (dst > spaceStart && ch_isspace(dst[-1]))
2451a34d5fb1SAntonio Huete Jimenez dst--;
2452a34d5fb1SAntonio Huete Jimenez *dst = '\0';
2453a34d5fb1SAntonio Huete Jimenez }
2454a34d5fb1SAntonio Huete Jimenez
2455*6eef5f0cSAntonio Huete Jimenez typedef enum LineKind {
2456a34d5fb1SAntonio Huete Jimenez /*
2457a34d5fb1SAntonio Huete Jimenez * Return the next line that is neither empty nor a comment.
2458a34d5fb1SAntonio Huete Jimenez * Backslash line continuations are folded into a single space.
2459a34d5fb1SAntonio Huete Jimenez * A trailing comment, if any, is discarded.
2460a34d5fb1SAntonio Huete Jimenez */
2461*6eef5f0cSAntonio Huete Jimenez LK_NONEMPTY,
2462a34d5fb1SAntonio Huete Jimenez
2463a34d5fb1SAntonio Huete Jimenez /*
2464a34d5fb1SAntonio Huete Jimenez * Return the next line, even if it is empty or a comment.
2465a34d5fb1SAntonio Huete Jimenez * Preserve backslash-newline to keep the line numbers correct.
2466a34d5fb1SAntonio Huete Jimenez *
2467a34d5fb1SAntonio Huete Jimenez * Used in .for loops to collect the body of the loop while waiting
2468a34d5fb1SAntonio Huete Jimenez * for the corresponding .endfor.
2469a34d5fb1SAntonio Huete Jimenez */
2470*6eef5f0cSAntonio Huete Jimenez LK_FOR_BODY,
2471a34d5fb1SAntonio Huete Jimenez
2472a34d5fb1SAntonio Huete Jimenez /*
2473a34d5fb1SAntonio Huete Jimenez * Return the next line that starts with a dot.
2474a34d5fb1SAntonio Huete Jimenez * Backslash line continuations are folded into a single space.
2475a34d5fb1SAntonio Huete Jimenez * A trailing comment, if any, is discarded.
2476a34d5fb1SAntonio Huete Jimenez *
2477a34d5fb1SAntonio Huete Jimenez * Used in .if directives to skip over irrelevant branches while
2478a34d5fb1SAntonio Huete Jimenez * waiting for the corresponding .endif.
2479a34d5fb1SAntonio Huete Jimenez */
2480*6eef5f0cSAntonio Huete Jimenez LK_DOT
2481*6eef5f0cSAntonio Huete Jimenez } LineKind;
2482a34d5fb1SAntonio Huete Jimenez
2483*6eef5f0cSAntonio Huete Jimenez /*
2484*6eef5f0cSAntonio Huete Jimenez * Return the next "interesting" logical line from the current file. The
2485*6eef5f0cSAntonio Huete Jimenez * returned string will be freed at the end of including the file.
2486*6eef5f0cSAntonio Huete Jimenez */
2487a34d5fb1SAntonio Huete Jimenez static char *
ReadLowLevelLine(LineKind kind)2488*6eef5f0cSAntonio Huete Jimenez ReadLowLevelLine(LineKind kind)
2489a34d5fb1SAntonio Huete Jimenez {
2490*6eef5f0cSAntonio Huete Jimenez IncludedFile *curFile = CurFile();
2491*6eef5f0cSAntonio Huete Jimenez ParseRawLineResult res;
2492a34d5fb1SAntonio Huete Jimenez char *line;
2493a34d5fb1SAntonio Huete Jimenez char *line_end;
2494a34d5fb1SAntonio Huete Jimenez char *firstBackslash;
2495*6eef5f0cSAntonio Huete Jimenez char *commentLineEnd;
2496a34d5fb1SAntonio Huete Jimenez
2497a34d5fb1SAntonio Huete Jimenez for (;;) {
2498*6eef5f0cSAntonio Huete Jimenez curFile->lineno = curFile->readLines + 1;
2499*6eef5f0cSAntonio Huete Jimenez res = ParseRawLine(curFile,
2500*6eef5f0cSAntonio Huete Jimenez &line, &line_end, &firstBackslash, &commentLineEnd);
2501a34d5fb1SAntonio Huete Jimenez if (res == PRLR_ERROR)
250201e196c8SJohn Marino return NULL;
2503a34d5fb1SAntonio Huete Jimenez
2504*6eef5f0cSAntonio Huete Jimenez if (line == line_end || line == commentLineEnd) {
2505a34d5fb1SAntonio Huete Jimenez if (res == PRLR_EOF)
2506a34d5fb1SAntonio Huete Jimenez return NULL;
2507*6eef5f0cSAntonio Huete Jimenez if (kind != LK_FOR_BODY)
250801e196c8SJohn Marino continue;
250901e196c8SJohn Marino }
251001e196c8SJohn Marino
251101e196c8SJohn Marino /* We now have a line of data */
2512a34d5fb1SAntonio Huete Jimenez assert(ch_isspace(*line_end));
2513a34d5fb1SAntonio Huete Jimenez *line_end = '\0';
251401e196c8SJohn Marino
2515*6eef5f0cSAntonio Huete Jimenez if (kind == LK_FOR_BODY)
2516a34d5fb1SAntonio Huete Jimenez return line; /* Don't join the physical lines. */
251701e196c8SJohn Marino
2518*6eef5f0cSAntonio Huete Jimenez if (kind == LK_DOT && line[0] != '.')
251901e196c8SJohn Marino continue;
252001e196c8SJohn Marino break;
252101e196c8SJohn Marino }
252201e196c8SJohn Marino
2523*6eef5f0cSAntonio Huete Jimenez if (commentLineEnd != NULL && line[0] != '\t')
2524*6eef5f0cSAntonio Huete Jimenez *commentLineEnd = '\0';
2525*6eef5f0cSAntonio Huete Jimenez if (firstBackslash != NULL)
2526a34d5fb1SAntonio Huete Jimenez UnescapeBackslash(line, firstBackslash);
252701e196c8SJohn Marino return line;
252801e196c8SJohn Marino }
252901e196c8SJohn Marino
2530*6eef5f0cSAntonio Huete Jimenez static bool
SkipIrrelevantBranches(void)2531*6eef5f0cSAntonio Huete Jimenez SkipIrrelevantBranches(void)
2532a34d5fb1SAntonio Huete Jimenez {
2533*6eef5f0cSAntonio Huete Jimenez const char *line;
2534a34d5fb1SAntonio Huete Jimenez
2535*6eef5f0cSAntonio Huete Jimenez while ((line = ReadLowLevelLine(LK_DOT)) != NULL) {
2536*6eef5f0cSAntonio Huete Jimenez if (Cond_EvalLine(line) == CR_TRUE)
2537*6eef5f0cSAntonio Huete Jimenez return true;
2538a34d5fb1SAntonio Huete Jimenez /*
2539*6eef5f0cSAntonio Huete Jimenez * TODO: Check for typos in .elif directives such as .elsif
2540*6eef5f0cSAntonio Huete Jimenez * or .elseif.
2541a34d5fb1SAntonio Huete Jimenez *
2542*6eef5f0cSAntonio Huete Jimenez * This check will probably duplicate some of the code in
2543*6eef5f0cSAntonio Huete Jimenez * ParseLine. Most of the code there cannot apply, only
2544*6eef5f0cSAntonio Huete Jimenez * ParseVarassign and ParseDependencyLine can, and to prevent
2545*6eef5f0cSAntonio Huete Jimenez * code duplication, these would need to be called with a
2546*6eef5f0cSAntonio Huete Jimenez * flag called onlyCheckSyntax.
2547a34d5fb1SAntonio Huete Jimenez *
2548a34d5fb1SAntonio Huete Jimenez * See directive-elif.mk for details.
2549a34d5fb1SAntonio Huete Jimenez */
2550a34d5fb1SAntonio Huete Jimenez }
2551a34d5fb1SAntonio Huete Jimenez
2552*6eef5f0cSAntonio Huete Jimenez return false;
2553a34d5fb1SAntonio Huete Jimenez }
2554a34d5fb1SAntonio Huete Jimenez
2555*6eef5f0cSAntonio Huete Jimenez static bool
ParseForLoop(const char * line)2556a34d5fb1SAntonio Huete Jimenez ParseForLoop(const char *line)
2557a34d5fb1SAntonio Huete Jimenez {
2558a34d5fb1SAntonio Huete Jimenez int rval;
2559*6eef5f0cSAntonio Huete Jimenez unsigned forHeadLineno;
2560*6eef5f0cSAntonio Huete Jimenez unsigned bodyReadLines;
2561*6eef5f0cSAntonio Huete Jimenez int forLevel;
2562a34d5fb1SAntonio Huete Jimenez
2563a34d5fb1SAntonio Huete Jimenez rval = For_Eval(line);
2564a34d5fb1SAntonio Huete Jimenez if (rval == 0)
2565*6eef5f0cSAntonio Huete Jimenez return false; /* Not a .for line */
2566a34d5fb1SAntonio Huete Jimenez if (rval < 0)
2567*6eef5f0cSAntonio Huete Jimenez return true; /* Syntax error - error printed, ignore line */
2568a34d5fb1SAntonio Huete Jimenez
2569*6eef5f0cSAntonio Huete Jimenez forHeadLineno = CurFile()->lineno;
2570*6eef5f0cSAntonio Huete Jimenez bodyReadLines = CurFile()->readLines;
2571a34d5fb1SAntonio Huete Jimenez
2572*6eef5f0cSAntonio Huete Jimenez /* Accumulate the loop body until the matching '.endfor'. */
2573*6eef5f0cSAntonio Huete Jimenez forLevel = 1;
2574a34d5fb1SAntonio Huete Jimenez do {
2575*6eef5f0cSAntonio Huete Jimenez line = ReadLowLevelLine(LK_FOR_BODY);
2576a34d5fb1SAntonio Huete Jimenez if (line == NULL) {
2577a34d5fb1SAntonio Huete Jimenez Parse_Error(PARSE_FATAL,
2578*6eef5f0cSAntonio Huete Jimenez "Unexpected end of file in .for loop");
2579a34d5fb1SAntonio Huete Jimenez break;
2580a34d5fb1SAntonio Huete Jimenez }
2581*6eef5f0cSAntonio Huete Jimenez } while (For_Accum(line, &forLevel));
2582a34d5fb1SAntonio Huete Jimenez
2583*6eef5f0cSAntonio Huete Jimenez For_Run(forHeadLineno, bodyReadLines);
2584*6eef5f0cSAntonio Huete Jimenez return true;
2585a34d5fb1SAntonio Huete Jimenez }
2586a34d5fb1SAntonio Huete Jimenez
2587a34d5fb1SAntonio Huete Jimenez /*
2588a34d5fb1SAntonio Huete Jimenez * Read an entire line from the input file.
2589a34d5fb1SAntonio Huete Jimenez *
2590a34d5fb1SAntonio Huete Jimenez * Empty lines, .if and .for are completely handled by this function,
2591a34d5fb1SAntonio Huete Jimenez * leaving only variable assignments, other directives, dependency lines
2592a34d5fb1SAntonio Huete Jimenez * and shell commands to the caller.
259301e196c8SJohn Marino *
2594*6eef5f0cSAntonio Huete Jimenez * Return a line without trailing whitespace, or NULL for EOF. The returned
2595*6eef5f0cSAntonio Huete Jimenez * string will be freed at the end of including the file.
259601e196c8SJohn Marino */
259701e196c8SJohn Marino static char *
ReadHighLevelLine(void)2598*6eef5f0cSAntonio Huete Jimenez ReadHighLevelLine(void)
259901e196c8SJohn Marino {
2600a34d5fb1SAntonio Huete Jimenez char *line;
260101e196c8SJohn Marino
260201e196c8SJohn Marino for (;;) {
2603*6eef5f0cSAntonio Huete Jimenez line = ReadLowLevelLine(LK_NONEMPTY);
2604*6eef5f0cSAntonio Huete Jimenez if (posix_state == PS_MAYBE_NEXT_LINE)
2605*6eef5f0cSAntonio Huete Jimenez posix_state = PS_NOW_OR_NEVER;
2606*6eef5f0cSAntonio Huete Jimenez else
2607*6eef5f0cSAntonio Huete Jimenez posix_state = PS_TOO_LATE;
260801e196c8SJohn Marino if (line == NULL)
260901e196c8SJohn Marino return NULL;
261001e196c8SJohn Marino
261101e196c8SJohn Marino if (line[0] != '.')
261201e196c8SJohn Marino return line;
261301e196c8SJohn Marino
2614a34d5fb1SAntonio Huete Jimenez switch (Cond_EvalLine(line)) {
2615*6eef5f0cSAntonio Huete Jimenez case CR_FALSE: /* May also mean a syntax error. */
2616*6eef5f0cSAntonio Huete Jimenez if (!SkipIrrelevantBranches())
2617a34d5fb1SAntonio Huete Jimenez return NULL;
261801e196c8SJohn Marino continue;
2619*6eef5f0cSAntonio Huete Jimenez case CR_TRUE:
262001e196c8SJohn Marino continue;
2621*6eef5f0cSAntonio Huete Jimenez case CR_ERROR: /* Not a conditional line */
2622a34d5fb1SAntonio Huete Jimenez if (ParseForLoop(line))
262301e196c8SJohn Marino continue;
262401e196c8SJohn Marino break;
262501e196c8SJohn Marino }
2626ca58f742SDaniel Fojt return line;
262701e196c8SJohn Marino }
262801e196c8SJohn Marino }
262901e196c8SJohn Marino
263001e196c8SJohn Marino static void
FinishDependencyGroup(void)2631a34d5fb1SAntonio Huete Jimenez FinishDependencyGroup(void)
263201e196c8SJohn Marino {
2633a34d5fb1SAntonio Huete Jimenez GNodeListNode *ln;
2634a34d5fb1SAntonio Huete Jimenez
2635a34d5fb1SAntonio Huete Jimenez if (targets == NULL)
2636a34d5fb1SAntonio Huete Jimenez return;
2637a34d5fb1SAntonio Huete Jimenez
2638a34d5fb1SAntonio Huete Jimenez for (ln = targets->first; ln != NULL; ln = ln->next) {
2639a34d5fb1SAntonio Huete Jimenez GNode *gn = ln->datum;
2640a34d5fb1SAntonio Huete Jimenez
2641a34d5fb1SAntonio Huete Jimenez Suff_EndTransform(gn);
2642a34d5fb1SAntonio Huete Jimenez
2643a34d5fb1SAntonio Huete Jimenez /*
2644a34d5fb1SAntonio Huete Jimenez * Mark the target as already having commands if it does, to
2645a34d5fb1SAntonio Huete Jimenez * keep from having shell commands on multiple dependency
2646a34d5fb1SAntonio Huete Jimenez * lines.
2647a34d5fb1SAntonio Huete Jimenez */
2648a34d5fb1SAntonio Huete Jimenez if (!Lst_IsEmpty(&gn->commands))
2649a34d5fb1SAntonio Huete Jimenez gn->type |= OP_HAS_COMMANDS;
2650a34d5fb1SAntonio Huete Jimenez }
2651a34d5fb1SAntonio Huete Jimenez
2652a34d5fb1SAntonio Huete Jimenez Lst_Free(targets);
265301e196c8SJohn Marino targets = NULL;
265401e196c8SJohn Marino }
265501e196c8SJohn Marino
2656a34d5fb1SAntonio Huete Jimenez /* Add the command to each target from the current dependency spec. */
2657a34d5fb1SAntonio Huete Jimenez static void
ParseLine_ShellCommand(const char * p)2658a34d5fb1SAntonio Huete Jimenez ParseLine_ShellCommand(const char *p)
265901e196c8SJohn Marino {
2660a34d5fb1SAntonio Huete Jimenez cpp_skip_whitespace(&p);
2661a34d5fb1SAntonio Huete Jimenez if (*p == '\0')
2662a34d5fb1SAntonio Huete Jimenez return; /* skip empty commands */
266301e196c8SJohn Marino
2664a34d5fb1SAntonio Huete Jimenez if (targets == NULL) {
266501e196c8SJohn Marino Parse_Error(PARSE_FATAL,
2666a34d5fb1SAntonio Huete Jimenez "Unassociated shell command \"%s\"", p);
2667a34d5fb1SAntonio Huete Jimenez return;
2668a34d5fb1SAntonio Huete Jimenez }
2669a34d5fb1SAntonio Huete Jimenez
2670a34d5fb1SAntonio Huete Jimenez {
2671a34d5fb1SAntonio Huete Jimenez char *cmd = bmake_strdup(p);
2672a34d5fb1SAntonio Huete Jimenez GNodeListNode *ln;
2673a34d5fb1SAntonio Huete Jimenez
2674a34d5fb1SAntonio Huete Jimenez for (ln = targets->first; ln != NULL; ln = ln->next) {
2675a34d5fb1SAntonio Huete Jimenez GNode *gn = ln->datum;
2676*6eef5f0cSAntonio Huete Jimenez GNode_AddCommand(gn, cmd);
2677a34d5fb1SAntonio Huete Jimenez }
267801e196c8SJohn Marino #ifdef CLEANUP
2679a34d5fb1SAntonio Huete Jimenez Lst_Append(&targCmds, cmd);
268001e196c8SJohn Marino #endif
268101e196c8SJohn Marino }
268201e196c8SJohn Marino }
2683a34d5fb1SAntonio Huete Jimenez
2684*6eef5f0cSAntonio Huete Jimenez static void
HandleBreak(void)2685*6eef5f0cSAntonio Huete Jimenez HandleBreak(void)
2686a34d5fb1SAntonio Huete Jimenez {
2687*6eef5f0cSAntonio Huete Jimenez IncludedFile *curFile = CurFile();
2688*6eef5f0cSAntonio Huete Jimenez
2689*6eef5f0cSAntonio Huete Jimenez if (curFile->forLoop != NULL) {
2690*6eef5f0cSAntonio Huete Jimenez /* pretend we reached EOF */
2691*6eef5f0cSAntonio Huete Jimenez For_Break(curFile->forLoop);
2692*6eef5f0cSAntonio Huete Jimenez cond_depth = CurFile_CondMinDepth();
2693*6eef5f0cSAntonio Huete Jimenez ParseEOF();
2694*6eef5f0cSAntonio Huete Jimenez } else
2695*6eef5f0cSAntonio Huete Jimenez Parse_Error(PARSE_FATAL, "break outside of for loop");
2696a34d5fb1SAntonio Huete Jimenez }
2697a34d5fb1SAntonio Huete Jimenez
2698a34d5fb1SAntonio Huete Jimenez /*
2699a34d5fb1SAntonio Huete Jimenez * See if the line starts with one of the known directives, and if so, handle
2700a34d5fb1SAntonio Huete Jimenez * the directive.
2701a34d5fb1SAntonio Huete Jimenez */
2702*6eef5f0cSAntonio Huete Jimenez static bool
ParseDirective(char * line)2703a34d5fb1SAntonio Huete Jimenez ParseDirective(char *line)
2704a34d5fb1SAntonio Huete Jimenez {
2705a34d5fb1SAntonio Huete Jimenez char *cp = line + 1;
2706*6eef5f0cSAntonio Huete Jimenez const char *arg;
2707*6eef5f0cSAntonio Huete Jimenez Substring dir;
2708a34d5fb1SAntonio Huete Jimenez
2709a34d5fb1SAntonio Huete Jimenez pp_skip_whitespace(&cp);
2710*6eef5f0cSAntonio Huete Jimenez if (IsInclude(cp, false)) {
2711*6eef5f0cSAntonio Huete Jimenez ParseInclude(cp);
2712*6eef5f0cSAntonio Huete Jimenez return true;
2713a34d5fb1SAntonio Huete Jimenez }
2714a34d5fb1SAntonio Huete Jimenez
2715*6eef5f0cSAntonio Huete Jimenez dir.start = cp;
2716*6eef5f0cSAntonio Huete Jimenez while (ch_islower(*cp) || *cp == '-')
2717a34d5fb1SAntonio Huete Jimenez cp++;
2718*6eef5f0cSAntonio Huete Jimenez dir.end = cp;
2719a34d5fb1SAntonio Huete Jimenez
2720a34d5fb1SAntonio Huete Jimenez if (*cp != '\0' && !ch_isspace(*cp))
2721*6eef5f0cSAntonio Huete Jimenez return false;
2722a34d5fb1SAntonio Huete Jimenez
2723a34d5fb1SAntonio Huete Jimenez pp_skip_whitespace(&cp);
2724a34d5fb1SAntonio Huete Jimenez arg = cp;
2725a34d5fb1SAntonio Huete Jimenez
2726*6eef5f0cSAntonio Huete Jimenez if (Substring_Equals(dir, "break"))
2727*6eef5f0cSAntonio Huete Jimenez HandleBreak();
2728*6eef5f0cSAntonio Huete Jimenez else if (Substring_Equals(dir, "undef"))
2729*6eef5f0cSAntonio Huete Jimenez Var_Undef(arg);
2730*6eef5f0cSAntonio Huete Jimenez else if (Substring_Equals(dir, "export"))
2731a34d5fb1SAntonio Huete Jimenez Var_Export(VEM_PLAIN, arg);
2732*6eef5f0cSAntonio Huete Jimenez else if (Substring_Equals(dir, "export-env"))
2733a34d5fb1SAntonio Huete Jimenez Var_Export(VEM_ENV, arg);
2734*6eef5f0cSAntonio Huete Jimenez else if (Substring_Equals(dir, "export-literal"))
2735a34d5fb1SAntonio Huete Jimenez Var_Export(VEM_LITERAL, arg);
2736*6eef5f0cSAntonio Huete Jimenez else if (Substring_Equals(dir, "unexport"))
2737*6eef5f0cSAntonio Huete Jimenez Var_UnExport(false, arg);
2738*6eef5f0cSAntonio Huete Jimenez else if (Substring_Equals(dir, "unexport-env"))
2739*6eef5f0cSAntonio Huete Jimenez Var_UnExport(true, arg);
2740*6eef5f0cSAntonio Huete Jimenez else if (Substring_Equals(dir, "info"))
2741*6eef5f0cSAntonio Huete Jimenez HandleMessage(PARSE_INFO, "info", arg);
2742*6eef5f0cSAntonio Huete Jimenez else if (Substring_Equals(dir, "warning"))
2743*6eef5f0cSAntonio Huete Jimenez HandleMessage(PARSE_WARNING, "warning", arg);
2744*6eef5f0cSAntonio Huete Jimenez else if (Substring_Equals(dir, "error"))
2745*6eef5f0cSAntonio Huete Jimenez HandleMessage(PARSE_FATAL, "error", arg);
2746*6eef5f0cSAntonio Huete Jimenez else
2747*6eef5f0cSAntonio Huete Jimenez return false;
2748*6eef5f0cSAntonio Huete Jimenez return true;
2749a34d5fb1SAntonio Huete Jimenez }
2750a34d5fb1SAntonio Huete Jimenez
2751*6eef5f0cSAntonio Huete Jimenez bool
Parse_VarAssign(const char * line,bool finishDependencyGroup,GNode * scope)2752*6eef5f0cSAntonio Huete Jimenez Parse_VarAssign(const char *line, bool finishDependencyGroup, GNode *scope)
2753a34d5fb1SAntonio Huete Jimenez {
2754a34d5fb1SAntonio Huete Jimenez VarAssign var;
2755a34d5fb1SAntonio Huete Jimenez
2756a34d5fb1SAntonio Huete Jimenez if (!Parse_IsVar(line, &var))
2757*6eef5f0cSAntonio Huete Jimenez return false;
2758*6eef5f0cSAntonio Huete Jimenez if (finishDependencyGroup)
2759a34d5fb1SAntonio Huete Jimenez FinishDependencyGroup();
2760*6eef5f0cSAntonio Huete Jimenez Parse_Var(&var, scope);
2761*6eef5f0cSAntonio Huete Jimenez free(var.varname);
2762*6eef5f0cSAntonio Huete Jimenez return true;
2763a34d5fb1SAntonio Huete Jimenez }
2764a34d5fb1SAntonio Huete Jimenez
2765a34d5fb1SAntonio Huete Jimenez static char *
FindSemicolon(char * p)2766a34d5fb1SAntonio Huete Jimenez FindSemicolon(char *p)
2767a34d5fb1SAntonio Huete Jimenez {
2768a34d5fb1SAntonio Huete Jimenez int level = 0;
2769a34d5fb1SAntonio Huete Jimenez
2770a34d5fb1SAntonio Huete Jimenez for (; *p != '\0'; p++) {
2771a34d5fb1SAntonio Huete Jimenez if (*p == '\\' && p[1] != '\0') {
2772a34d5fb1SAntonio Huete Jimenez p++;
277301e196c8SJohn Marino continue;
277401e196c8SJohn Marino }
277501e196c8SJohn Marino
2776a34d5fb1SAntonio Huete Jimenez if (*p == '$' && (p[1] == '(' || p[1] == '{'))
2777a34d5fb1SAntonio Huete Jimenez level++;
2778a34d5fb1SAntonio Huete Jimenez else if (level > 0 && (*p == ')' || *p == '}'))
2779a34d5fb1SAntonio Huete Jimenez level--;
2780a34d5fb1SAntonio Huete Jimenez else if (level == 0 && *p == ';')
2781a34d5fb1SAntonio Huete Jimenez break;
2782a34d5fb1SAntonio Huete Jimenez }
2783a34d5fb1SAntonio Huete Jimenez return p;
2784a34d5fb1SAntonio Huete Jimenez }
2785a34d5fb1SAntonio Huete Jimenez
2786a34d5fb1SAntonio Huete Jimenez /*
2787*6eef5f0cSAntonio Huete Jimenez * dependency -> [target...] op [source...] [';' command]
2788a34d5fb1SAntonio Huete Jimenez * op -> ':' | '::' | '!'
2789a34d5fb1SAntonio Huete Jimenez */
2790a34d5fb1SAntonio Huete Jimenez static void
ParseDependencyLine(char * line)2791*6eef5f0cSAntonio Huete Jimenez ParseDependencyLine(char *line)
2792a34d5fb1SAntonio Huete Jimenez {
2793*6eef5f0cSAntonio Huete Jimenez VarEvalMode emode;
2794a34d5fb1SAntonio Huete Jimenez char *expanded_line;
2795a34d5fb1SAntonio Huete Jimenez const char *shellcmd = NULL;
2796a34d5fb1SAntonio Huete Jimenez
2797a34d5fb1SAntonio Huete Jimenez /*
2798a34d5fb1SAntonio Huete Jimenez * For some reason - probably to make the parser impossible -
2799a34d5fb1SAntonio Huete Jimenez * a ';' can be used to separate commands from dependencies.
2800*6eef5f0cSAntonio Huete Jimenez * Attempt to skip over ';' inside substitution patterns.
2801a34d5fb1SAntonio Huete Jimenez */
2802a34d5fb1SAntonio Huete Jimenez {
2803a34d5fb1SAntonio Huete Jimenez char *semicolon = FindSemicolon(line);
2804a34d5fb1SAntonio Huete Jimenez if (*semicolon != '\0') {
2805a34d5fb1SAntonio Huete Jimenez /* Terminate the dependency list at the ';' */
2806a34d5fb1SAntonio Huete Jimenez *semicolon = '\0';
2807a34d5fb1SAntonio Huete Jimenez shellcmd = semicolon + 1;
2808a34d5fb1SAntonio Huete Jimenez }
2809a34d5fb1SAntonio Huete Jimenez }
2810a34d5fb1SAntonio Huete Jimenez
2811a34d5fb1SAntonio Huete Jimenez /*
2812a34d5fb1SAntonio Huete Jimenez * We now know it's a dependency line so it needs to have all
2813a34d5fb1SAntonio Huete Jimenez * variables expanded before being parsed.
2814a34d5fb1SAntonio Huete Jimenez *
2815a34d5fb1SAntonio Huete Jimenez * XXX: Ideally the dependency line would first be split into
2816a34d5fb1SAntonio Huete Jimenez * its left-hand side, dependency operator and right-hand side,
2817a34d5fb1SAntonio Huete Jimenez * and then each side would be expanded on its own. This would
2818a34d5fb1SAntonio Huete Jimenez * allow for the left-hand side to allow only defined variables
2819a34d5fb1SAntonio Huete Jimenez * and to allow variables on the right-hand side to be undefined
2820a34d5fb1SAntonio Huete Jimenez * as well.
2821a34d5fb1SAntonio Huete Jimenez *
2822a34d5fb1SAntonio Huete Jimenez * Parsing the line first would also prevent that targets
2823a34d5fb1SAntonio Huete Jimenez * generated from variable expressions are interpreted as the
2824a34d5fb1SAntonio Huete Jimenez * dependency operator, such as in "target${:U\:} middle: source",
2825a34d5fb1SAntonio Huete Jimenez * in which the middle is interpreted as a source, not a target.
2826a34d5fb1SAntonio Huete Jimenez */
2827a34d5fb1SAntonio Huete Jimenez
2828*6eef5f0cSAntonio Huete Jimenez /*
2829*6eef5f0cSAntonio Huete Jimenez * In lint mode, allow undefined variables to appear in dependency
2830*6eef5f0cSAntonio Huete Jimenez * lines.
2831a34d5fb1SAntonio Huete Jimenez *
2832*6eef5f0cSAntonio Huete Jimenez * Ideally, only the right-hand side would allow undefined variables
2833*6eef5f0cSAntonio Huete Jimenez * since it is common to have optional dependencies. Having undefined
2834*6eef5f0cSAntonio Huete Jimenez * variables on the left-hand side is more unusual though. Since
2835*6eef5f0cSAntonio Huete Jimenez * both sides are expanded in a single pass, there is not much choice
2836*6eef5f0cSAntonio Huete Jimenez * what to do here.
2837a34d5fb1SAntonio Huete Jimenez *
2838*6eef5f0cSAntonio Huete Jimenez * In normal mode, it does not matter whether undefined variables are
2839*6eef5f0cSAntonio Huete Jimenez * allowed or not since as of 2020-09-14, Var_Parse does not print
2840*6eef5f0cSAntonio Huete Jimenez * any parse errors in such a case. It simply returns the special
2841*6eef5f0cSAntonio Huete Jimenez * empty string var_Error, which cannot be detected in the result of
2842*6eef5f0cSAntonio Huete Jimenez * Var_Subst.
2843*6eef5f0cSAntonio Huete Jimenez */
2844*6eef5f0cSAntonio Huete Jimenez emode = opts.strict ? VARE_WANTRES : VARE_UNDEFERR;
2845*6eef5f0cSAntonio Huete Jimenez (void)Var_Subst(line, SCOPE_CMDLINE, emode, &expanded_line);
2846a34d5fb1SAntonio Huete Jimenez /* TODO: handle errors */
2847a34d5fb1SAntonio Huete Jimenez
2848a34d5fb1SAntonio Huete Jimenez /* Need a fresh list for the target nodes */
2849a34d5fb1SAntonio Huete Jimenez if (targets != NULL)
2850a34d5fb1SAntonio Huete Jimenez Lst_Free(targets);
2851a34d5fb1SAntonio Huete Jimenez targets = Lst_New();
2852a34d5fb1SAntonio Huete Jimenez
2853*6eef5f0cSAntonio Huete Jimenez ParseDependency(expanded_line);
2854a34d5fb1SAntonio Huete Jimenez free(expanded_line);
2855a34d5fb1SAntonio Huete Jimenez
2856a34d5fb1SAntonio Huete Jimenez if (shellcmd != NULL)
2857a34d5fb1SAntonio Huete Jimenez ParseLine_ShellCommand(shellcmd);
2858a34d5fb1SAntonio Huete Jimenez }
2859a34d5fb1SAntonio Huete Jimenez
2860a34d5fb1SAntonio Huete Jimenez static void
ParseLine(char * line)2861a34d5fb1SAntonio Huete Jimenez ParseLine(char *line)
2862a34d5fb1SAntonio Huete Jimenez {
2863a34d5fb1SAntonio Huete Jimenez /*
2864a34d5fb1SAntonio Huete Jimenez * Lines that begin with '.' can be pretty much anything:
2865a34d5fb1SAntonio Huete Jimenez * - directives like '.include' or '.if',
2866a34d5fb1SAntonio Huete Jimenez * - suffix rules like '.c.o:',
2867a34d5fb1SAntonio Huete Jimenez * - dependencies for filenames that start with '.',
2868a34d5fb1SAntonio Huete Jimenez * - variable assignments like '.tmp=value'.
2869a34d5fb1SAntonio Huete Jimenez */
2870a34d5fb1SAntonio Huete Jimenez if (line[0] == '.' && ParseDirective(line))
2871a34d5fb1SAntonio Huete Jimenez return;
2872a34d5fb1SAntonio Huete Jimenez
2873a34d5fb1SAntonio Huete Jimenez if (line[0] == '\t') {
2874a34d5fb1SAntonio Huete Jimenez ParseLine_ShellCommand(line + 1);
2875a34d5fb1SAntonio Huete Jimenez return;
2876a34d5fb1SAntonio Huete Jimenez }
2877a34d5fb1SAntonio Huete Jimenez
287801e196c8SJohn Marino #ifdef SYSVINCLUDE
2879ca58f742SDaniel Fojt if (IsSysVInclude(line)) {
288001e196c8SJohn Marino /*
288101e196c8SJohn Marino * It's an S3/S5-style "include".
288201e196c8SJohn Marino */
288301e196c8SJohn Marino ParseTraditionalInclude(line);
2884a34d5fb1SAntonio Huete Jimenez return;
288501e196c8SJohn Marino }
288601e196c8SJohn Marino #endif
2887a34d5fb1SAntonio Huete Jimenez
288801e196c8SJohn Marino #ifdef GMAKEEXPORT
2889a34d5fb1SAntonio Huete Jimenez if (strncmp(line, "export", 6) == 0 && ch_isspace(line[6]) &&
289001e196c8SJohn Marino strchr(line, ':') == NULL) {
289101e196c8SJohn Marino /*
289201e196c8SJohn Marino * It's a Gmake "export".
289301e196c8SJohn Marino */
289401e196c8SJohn Marino ParseGmakeExport(line);
2895a34d5fb1SAntonio Huete Jimenez return;
289601e196c8SJohn Marino }
289701e196c8SJohn Marino #endif
2898a34d5fb1SAntonio Huete Jimenez
2899*6eef5f0cSAntonio Huete Jimenez if (Parse_VarAssign(line, true, SCOPE_GLOBAL))
2900a34d5fb1SAntonio Huete Jimenez return;
2901a34d5fb1SAntonio Huete Jimenez
2902a34d5fb1SAntonio Huete Jimenez FinishDependencyGroup();
2903a34d5fb1SAntonio Huete Jimenez
2904*6eef5f0cSAntonio Huete Jimenez ParseDependencyLine(line);
290501e196c8SJohn Marino }
290601e196c8SJohn Marino
290701e196c8SJohn Marino /*
2908a34d5fb1SAntonio Huete Jimenez * Parse a top-level makefile, incorporating its content into the global
2909a34d5fb1SAntonio Huete Jimenez * dependency graph.
291001e196c8SJohn Marino */
2911a34d5fb1SAntonio Huete Jimenez void
Parse_File(const char * name,int fd)2912a34d5fb1SAntonio Huete Jimenez Parse_File(const char *name, int fd)
291301e196c8SJohn Marino {
2914*6eef5f0cSAntonio Huete Jimenez char *line;
2915*6eef5f0cSAntonio Huete Jimenez Buffer buf;
291601e196c8SJohn Marino
2917*6eef5f0cSAntonio Huete Jimenez buf = LoadFile(name, fd != -1 ? fd : STDIN_FILENO);
2918*6eef5f0cSAntonio Huete Jimenez if (fd != -1)
2919*6eef5f0cSAntonio Huete Jimenez (void)close(fd);
292001e196c8SJohn Marino
2921a34d5fb1SAntonio Huete Jimenez assert(targets == NULL);
292201e196c8SJohn Marino
2923*6eef5f0cSAntonio Huete Jimenez Parse_PushInput(name, 1, 0, buf, NULL);
292401e196c8SJohn Marino
2925a34d5fb1SAntonio Huete Jimenez do {
2926*6eef5f0cSAntonio Huete Jimenez while ((line = ReadHighLevelLine()) != NULL) {
2927*6eef5f0cSAntonio Huete Jimenez DEBUG2(PARSE, "Parsing line %u: %s\n",
2928a34d5fb1SAntonio Huete Jimenez CurFile()->lineno, line);
2929a34d5fb1SAntonio Huete Jimenez ParseLine(line);
293001e196c8SJohn Marino }
2931a34d5fb1SAntonio Huete Jimenez /* Reached EOF, but it may be just EOF of an include file. */
2932a34d5fb1SAntonio Huete Jimenez } while (ParseEOF());
293301e196c8SJohn Marino
2934a34d5fb1SAntonio Huete Jimenez FinishDependencyGroup();
2935a34d5fb1SAntonio Huete Jimenez
2936*6eef5f0cSAntonio Huete Jimenez if (parseErrors != 0) {
293701e196c8SJohn Marino (void)fflush(stdout);
293801e196c8SJohn Marino (void)fprintf(stderr,
2939*6eef5f0cSAntonio Huete Jimenez "%s: Fatal errors encountered -- cannot continue\n",
294001e196c8SJohn Marino progname);
2941*6eef5f0cSAntonio Huete Jimenez PrintOnError(NULL, "");
294201e196c8SJohn Marino exit(1);
294301e196c8SJohn Marino }
294401e196c8SJohn Marino }
294501e196c8SJohn Marino
2946a34d5fb1SAntonio Huete Jimenez /* Initialize the parsing module. */
294701e196c8SJohn Marino void
Parse_Init(void)294801e196c8SJohn Marino Parse_Init(void)
294901e196c8SJohn Marino {
295001e196c8SJohn Marino mainNode = NULL;
2951a34d5fb1SAntonio Huete Jimenez parseIncPath = SearchPath_New();
2952a34d5fb1SAntonio Huete Jimenez sysIncPath = SearchPath_New();
2953a34d5fb1SAntonio Huete Jimenez defSysIncPath = SearchPath_New();
2954*6eef5f0cSAntonio Huete Jimenez Vector_Init(&includes, sizeof(IncludedFile));
295501e196c8SJohn Marino }
295601e196c8SJohn Marino
2957a34d5fb1SAntonio Huete Jimenez /* Clean up the parsing module. */
295801e196c8SJohn Marino void
Parse_End(void)295901e196c8SJohn Marino Parse_End(void)
296001e196c8SJohn Marino {
296101e196c8SJohn Marino #ifdef CLEANUP
2962a34d5fb1SAntonio Huete Jimenez Lst_DoneCall(&targCmds, free);
2963a34d5fb1SAntonio Huete Jimenez assert(targets == NULL);
2964a34d5fb1SAntonio Huete Jimenez SearchPath_Free(defSysIncPath);
2965a34d5fb1SAntonio Huete Jimenez SearchPath_Free(sysIncPath);
2966a34d5fb1SAntonio Huete Jimenez SearchPath_Free(parseIncPath);
2967a34d5fb1SAntonio Huete Jimenez assert(includes.len == 0);
2968a34d5fb1SAntonio Huete Jimenez Vector_Done(&includes);
296901e196c8SJohn Marino #endif
297001e196c8SJohn Marino }
297101e196c8SJohn Marino
297201e196c8SJohn Marino
2973a34d5fb1SAntonio Huete Jimenez /*
2974a34d5fb1SAntonio Huete Jimenez * Return a list containing the single main target to create.
2975a34d5fb1SAntonio Huete Jimenez * If no such target exists, we Punt with an obnoxious error message.
297601e196c8SJohn Marino */
2977a34d5fb1SAntonio Huete Jimenez void
Parse_MainName(GNodeList * mainList)2978a34d5fb1SAntonio Huete Jimenez Parse_MainName(GNodeList *mainList)
297901e196c8SJohn Marino {
2980a34d5fb1SAntonio Huete Jimenez if (mainNode == NULL)
298101e196c8SJohn Marino Punt("no target to make.");
2982a34d5fb1SAntonio Huete Jimenez
2983a34d5fb1SAntonio Huete Jimenez Lst_Append(mainList, mainNode);
2984a34d5fb1SAntonio Huete Jimenez if (mainNode->type & OP_DOUBLEDEP)
2985a34d5fb1SAntonio Huete Jimenez Lst_AppendAll(mainList, &mainNode->cohorts);
2986a34d5fb1SAntonio Huete Jimenez
2987a34d5fb1SAntonio Huete Jimenez Global_Append(".TARGETS", mainNode->name);
298801e196c8SJohn Marino }
298901e196c8SJohn Marino
2990a34d5fb1SAntonio Huete Jimenez int
Parse_NumErrors(void)2991*6eef5f0cSAntonio Huete Jimenez Parse_NumErrors(void)
299201e196c8SJohn Marino {
2993*6eef5f0cSAntonio Huete Jimenez return parseErrors;
299401e196c8SJohn Marino }
2995