Sat Oct 31 23:44:42 2020 UTC ()
make(1): clean up StrContainsWord


(rillig)
diff -r1.418 -r1.419 src/usr.bin/make/parse.c

cvs diff -r1.418 -r1.419 src/usr.bin/make/parse.c (switch to unified diff)

--- src/usr.bin/make/parse.c 2020/10/31 23:39:01 1.418
+++ src/usr.bin/make/parse.c 2020/10/31 23:44:42 1.419
@@ -1,1119 +1,1119 @@ @@ -1,1119 +1,1119 @@
1/* $NetBSD: parse.c,v 1.418 2020/10/31 23:39:01 rillig Exp $ */ 1/* $NetBSD: parse.c,v 1.419 2020/10/31 23:44:42 rillig Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 1988, 1989, 1990, 1993 4 * Copyright (c) 1988, 1989, 1990, 1993
5 * The Regents of the University of California. All rights reserved. 5 * The Regents of the University of California. All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to Berkeley by 7 * This code is derived from software contributed to Berkeley by
8 * Adam de Boor. 8 * Adam de Boor.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright 15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the 16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution. 17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors 18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software 19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission. 20 * without specific prior written permission.
21 * 21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE. 32 * SUCH DAMAGE.
33 */ 33 */
34 34
35/* 35/*
36 * Copyright (c) 1989 by Berkeley Softworks 36 * Copyright (c) 1989 by Berkeley Softworks
37 * All rights reserved. 37 * All rights reserved.
38 * 38 *
39 * This code is derived from software contributed to Berkeley by 39 * This code is derived from software contributed to Berkeley by
40 * Adam de Boor. 40 * Adam de Boor.
41 * 41 *
42 * Redistribution and use in source and binary forms, with or without 42 * Redistribution and use in source and binary forms, with or without
43 * modification, are permitted provided that the following conditions 43 * modification, are permitted provided that the following conditions
44 * are met: 44 * are met:
45 * 1. Redistributions of source code must retain the above copyright 45 * 1. Redistributions of source code must retain the above copyright
46 * notice, this list of conditions and the following disclaimer. 46 * notice, this list of conditions and the following disclaimer.
47 * 2. Redistributions in binary form must reproduce the above copyright 47 * 2. Redistributions in binary form must reproduce the above copyright
48 * notice, this list of conditions and the following disclaimer in the 48 * notice, this list of conditions and the following disclaimer in the
49 * documentation and/or other materials provided with the distribution. 49 * documentation and/or other materials provided with the distribution.
50 * 3. All advertising materials mentioning features or use of this software 50 * 3. All advertising materials mentioning features or use of this software
51 * must display the following acknowledgement: 51 * must display the following acknowledgement:
52 * This product includes software developed by the University of 52 * This product includes software developed by the University of
53 * California, Berkeley and its contributors. 53 * California, Berkeley and its contributors.
54 * 4. Neither the name of the University nor the names of its contributors 54 * 4. Neither the name of the University nor the names of its contributors
55 * may be used to endorse or promote products derived from this software 55 * may be used to endorse or promote products derived from this software
56 * without specific prior written permission. 56 * without specific prior written permission.
57 * 57 *
58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
68 * SUCH DAMAGE. 68 * SUCH DAMAGE.
69 */ 69 */
70 70
71/* 71/*
72 * Parsing of makefiles. 72 * Parsing of makefiles.
73 * 73 *
74 * Parse_File is the main entry point and controls most of the other 74 * Parse_File is the main entry point and controls most of the other
75 * functions in this module. 75 * functions in this module.
76 * 76 *
77 * The directories for the .include "..." directive are kept in 77 * The directories for the .include "..." directive are kept in
78 * 'parseIncPath', while those for .include <...> are kept in 'sysIncPath'. 78 * 'parseIncPath', while those for .include <...> are kept in 'sysIncPath'.
79 * The targets currently being defined are kept in 'targets'. 79 * The targets currently being defined are kept in 'targets'.
80 * 80 *
81 * Interface: 81 * Interface:
82 * Parse_Init Initialize the module 82 * Parse_Init Initialize the module
83 * 83 *
84 * Parse_End Clean up the module 84 * Parse_End Clean up the module
85 * 85 *
86 * Parse_File Parse a top-level makefile. Included files are 86 * Parse_File Parse a top-level makefile. Included files are
87 * handled by Parse_include_file though. 87 * handled by Parse_include_file though.
88 * 88 *
89 * Parse_IsVar Return TRUE if the given line is a variable 89 * Parse_IsVar Return TRUE if the given line is a variable
90 * assignment. Used by MainParseArgs to determine if 90 * assignment. Used by MainParseArgs to determine if
91 * an argument is a target or a variable assignment. 91 * an argument is a target or a variable assignment.
92 * Used internally for pretty much the same thing. 92 * Used internally for pretty much the same thing.
93 * 93 *
94 * Parse_Error Report a parse error, a warning or an informational 94 * Parse_Error Report a parse error, a warning or an informational
95 * message. 95 * message.
96 * 96 *
97 * Parse_MainName Returns a list of the main target to create. 97 * Parse_MainName Returns a list of the main target to create.
98 */ 98 */
99 99
100#include <sys/types.h> 100#include <sys/types.h>
101#include <sys/mman.h> 101#include <sys/mman.h>
102#include <sys/stat.h> 102#include <sys/stat.h>
103#include <errno.h> 103#include <errno.h>
104#include <stdarg.h> 104#include <stdarg.h>
105#include <stdint.h> 105#include <stdint.h>
106 106
107#ifndef MAP_FILE 107#ifndef MAP_FILE
108#define MAP_FILE 0 108#define MAP_FILE 0
109#endif 109#endif
110#ifndef MAP_COPY 110#ifndef MAP_COPY
111#define MAP_COPY MAP_PRIVATE 111#define MAP_COPY MAP_PRIVATE
112#endif 112#endif
113 113
114#include "make.h" 114#include "make.h"
115#include "dir.h" 115#include "dir.h"
116#include "job.h" 116#include "job.h"
117#include "pathnames.h" 117#include "pathnames.h"
118 118
119/* "@(#)parse.c 8.3 (Berkeley) 3/19/94" */ 119/* "@(#)parse.c 8.3 (Berkeley) 3/19/94" */
120MAKE_RCSID("$NetBSD: parse.c,v 1.418 2020/10/31 23:39:01 rillig Exp $"); 120MAKE_RCSID("$NetBSD: parse.c,v 1.419 2020/10/31 23:44:42 rillig Exp $");
121 121
122/* types and constants */ 122/* types and constants */
123 123
124/* 124/*
125 * Structure for a file being read ("included file") 125 * Structure for a file being read ("included file")
126 */ 126 */
127typedef struct IFile { 127typedef struct IFile {
128 char *fname; /* name of file */ 128 char *fname; /* name of file */
129 Boolean fromForLoop; /* simulated .include by the .for loop */ 129 Boolean fromForLoop; /* simulated .include by the .for loop */
130 int lineno; /* current line number in file */ 130 int lineno; /* current line number in file */
131 int first_lineno; /* line number of start of text */ 131 int first_lineno; /* line number of start of text */
132 unsigned int cond_depth; /* 'if' nesting when file opened */ 132 unsigned int cond_depth; /* 'if' nesting when file opened */
133 Boolean depending; /* state of doing_depend on EOF */ 133 Boolean depending; /* state of doing_depend on EOF */
134 134
135 /* The buffer from which the file's content is read. */ 135 /* The buffer from which the file's content is read. */
136 char *buf_freeIt; 136 char *buf_freeIt;
137 char *buf_ptr; /* next char to be read */ 137 char *buf_ptr; /* next char to be read */
138 char *buf_end; 138 char *buf_end;
139 139
140 char *(*nextbuf)(void *, size_t *); /* Function to get more data */ 140 char *(*nextbuf)(void *, size_t *); /* Function to get more data */
141 void *nextbuf_arg; /* Opaque arg for nextbuf() */ 141 void *nextbuf_arg; /* Opaque arg for nextbuf() */
142 struct loadedfile *lf; /* loadedfile object, if any */ 142 struct loadedfile *lf; /* loadedfile object, if any */
143} IFile; 143} IFile;
144 144
145/* 145/*
146 * Tokens for target attributes 146 * Tokens for target attributes
147 */ 147 */
148typedef enum ParseSpecial { 148typedef enum ParseSpecial {
149 SP_ATTRIBUTE, /* Generic attribute */ 149 SP_ATTRIBUTE, /* Generic attribute */
150 SP_BEGIN, /* .BEGIN */ 150 SP_BEGIN, /* .BEGIN */
151 SP_DEFAULT, /* .DEFAULT */ 151 SP_DEFAULT, /* .DEFAULT */
152 SP_DELETE_ON_ERROR, /* .DELETE_ON_ERROR */ 152 SP_DELETE_ON_ERROR, /* .DELETE_ON_ERROR */
153 SP_END, /* .END */ 153 SP_END, /* .END */
154 SP_ERROR, /* .ERROR */ 154 SP_ERROR, /* .ERROR */
155 SP_IGNORE, /* .IGNORE */ 155 SP_IGNORE, /* .IGNORE */
156 SP_INCLUDES, /* .INCLUDES; not mentioned in the manual page */ 156 SP_INCLUDES, /* .INCLUDES; not mentioned in the manual page */
157 SP_INTERRUPT, /* .INTERRUPT */ 157 SP_INTERRUPT, /* .INTERRUPT */
158 SP_LIBS, /* .LIBS; not mentioned in the manual page */ 158 SP_LIBS, /* .LIBS; not mentioned in the manual page */
159 SP_MAIN, /* .MAIN and we don't have anything user-specified to 159 SP_MAIN, /* .MAIN and we don't have anything user-specified to
160 * make */ 160 * make */
161 SP_META, /* .META */ 161 SP_META, /* .META */
162 SP_MFLAGS, /* .MFLAGS or .MAKEFLAGS */ 162 SP_MFLAGS, /* .MFLAGS or .MAKEFLAGS */
163 SP_NOMETA, /* .NOMETA */ 163 SP_NOMETA, /* .NOMETA */
164 SP_NOMETA_CMP, /* .NOMETA_CMP */ 164 SP_NOMETA_CMP, /* .NOMETA_CMP */
165 SP_NOPATH, /* .NOPATH */ 165 SP_NOPATH, /* .NOPATH */
166 SP_NOT, /* Not special */ 166 SP_NOT, /* Not special */
167 SP_NOTPARALLEL, /* .NOTPARALLEL or .NO_PARALLEL */ 167 SP_NOTPARALLEL, /* .NOTPARALLEL or .NO_PARALLEL */
168 SP_NULL, /* .NULL; not mentioned in the manual page */ 168 SP_NULL, /* .NULL; not mentioned in the manual page */
169 SP_OBJDIR, /* .OBJDIR */ 169 SP_OBJDIR, /* .OBJDIR */
170 SP_ORDER, /* .ORDER */ 170 SP_ORDER, /* .ORDER */
171 SP_PARALLEL, /* .PARALLEL; not mentioned in the manual page */ 171 SP_PARALLEL, /* .PARALLEL; not mentioned in the manual page */
172 SP_PATH, /* .PATH or .PATH.suffix */ 172 SP_PATH, /* .PATH or .PATH.suffix */
173 SP_PHONY, /* .PHONY */ 173 SP_PHONY, /* .PHONY */
174#ifdef POSIX 174#ifdef POSIX
175 SP_POSIX, /* .POSIX; not mentioned in the manual page */ 175 SP_POSIX, /* .POSIX; not mentioned in the manual page */
176#endif 176#endif
177 SP_PRECIOUS, /* .PRECIOUS */ 177 SP_PRECIOUS, /* .PRECIOUS */
178 SP_SHELL, /* .SHELL */ 178 SP_SHELL, /* .SHELL */
179 SP_SILENT, /* .SILENT */ 179 SP_SILENT, /* .SILENT */
180 SP_SINGLESHELL, /* .SINGLESHELL; not mentioned in the manual page */ 180 SP_SINGLESHELL, /* .SINGLESHELL; not mentioned in the manual page */
181 SP_STALE, /* .STALE */ 181 SP_STALE, /* .STALE */
182 SP_SUFFIXES, /* .SUFFIXES */ 182 SP_SUFFIXES, /* .SUFFIXES */
183 SP_WAIT /* .WAIT */ 183 SP_WAIT /* .WAIT */
184} ParseSpecial; 184} ParseSpecial;
185 185
186typedef List SearchPathList; 186typedef List SearchPathList;
187typedef ListNode SearchPathListNode; 187typedef ListNode SearchPathListNode;
188 188
189/* result data */ 189/* result data */
190 190
191/* 191/*
192 * The main target to create. This is the first target on the first 192 * The main target to create. This is the first target on the first
193 * dependency line in the first makefile. 193 * dependency line in the first makefile.
194 */ 194 */
195static GNode *mainNode; 195static GNode *mainNode;
196 196
197/* eval state */ 197/* eval state */
198 198
199/* During parsing, the targets from the left-hand side of the currently 199/* During parsing, the targets from the left-hand side of the currently
200 * active dependency line, or NULL if the current line does not belong to a 200 * active dependency line, or NULL if the current line does not belong to a
201 * dependency line, for example because it is a variable assignment. 201 * dependency line, for example because it is a variable assignment.
202 * 202 *
203 * See unit-tests/deptgt.mk, keyword "parse.c:targets". */ 203 * See unit-tests/deptgt.mk, keyword "parse.c:targets". */
204static GNodeList *targets; 204static GNodeList *targets;
205 205
206#ifdef CLEANUP 206#ifdef CLEANUP
207/* All shell commands for all targets, in no particular order and possibly 207/* All shell commands for all targets, in no particular order and possibly
208 * with duplicates. Kept in a separate list since the commands from .USE or 208 * with duplicates. Kept in a separate list since the commands from .USE or
209 * .USEBEFORE nodes are shared with other GNodes, thereby giving up the 209 * .USEBEFORE nodes are shared with other GNodes, thereby giving up the
210 * easily understandable ownership over the allocated strings. */ 210 * easily understandable ownership over the allocated strings. */
211static StringList *targCmds; 211static StringList *targCmds;
212#endif 212#endif
213 213
214/* 214/*
215 * Predecessor node for handling .ORDER. Initialized to NULL when .ORDER 215 * Predecessor node for handling .ORDER. Initialized to NULL when .ORDER
216 * seen, then set to each successive source on the line. 216 * seen, then set to each successive source on the line.
217 */ 217 */
218static GNode *order_pred; 218static GNode *order_pred;
219 219
220/* parser state */ 220/* parser state */
221 221
222/* number of fatal errors */ 222/* number of fatal errors */
223static int fatals = 0; 223static int fatals = 0;
224 224
225/* 225/*
226 * Variables for doing includes 226 * Variables for doing includes
227 */ 227 */
228 228
229/* The include chain of makefiles. At the bottom is the top-level makefile 229/* The include chain of makefiles. At the bottom is the top-level makefile
230 * from the command line, and on top of that, there are the included files or 230 * from the command line, and on top of that, there are the included files or
231 * .for loops, up to and including the current file. 231 * .for loops, up to and including the current file.
232 * 232 *
233 * This data could be used to print stack traces on parse errors. As of 233 * This data could be used to print stack traces on parse errors. As of
234 * 2020-09-14, this is not done though. It seems quite simple to print the 234 * 2020-09-14, this is not done though. It seems quite simple to print the
235 * tuples (fname:lineno:fromForLoop), from top to bottom. This simple idea is 235 * tuples (fname:lineno:fromForLoop), from top to bottom. This simple idea is
236 * made complicated by the fact that the .for loops also use this stack for 236 * made complicated by the fact that the .for loops also use this stack for
237 * storing information. 237 * storing information.
238 * 238 *
239 * The lineno fields of the IFiles with fromForLoop == TRUE look confusing, 239 * The lineno fields of the IFiles with fromForLoop == TRUE look confusing,
240 * which is demonstrated by the test 'include-main.mk'. They seem sorted 240 * which is demonstrated by the test 'include-main.mk'. They seem sorted
241 * backwards since they tell the number of completely parsed lines, which for 241 * backwards since they tell the number of completely parsed lines, which for
242 * a .for loop is right after the terminating .endfor. To compensate for this 242 * a .for loop is right after the terminating .endfor. To compensate for this
243 * confusion, there is another field first_lineno pointing at the start of the 243 * confusion, there is another field first_lineno pointing at the start of the
244 * .for loop, 1-based for human consumption. 244 * .for loop, 1-based for human consumption.
245 * 245 *
246 * To make the stack trace intuitive, the entry below the first .for loop must 246 * To make the stack trace intuitive, the entry below the first .for loop must
247 * be ignored completely since neither its lineno nor its first_lineno is 247 * be ignored completely since neither its lineno nor its first_lineno is
248 * useful. Instead, the topmost of each chain of .for loop needs to be 248 * useful. Instead, the topmost of each chain of .for loop needs to be
249 * printed twice, once with its first_lineno and once with its lineno. 249 * printed twice, once with its first_lineno and once with its lineno.
250 * 250 *
251 * As of 2020-10-28, using the above rules, the stack trace for the .info line 251 * As of 2020-10-28, using the above rules, the stack trace for the .info line
252 * in include-subsub.mk would be: 252 * in include-subsub.mk would be:
253 * 253 *
254 * includes[5]: include-subsub.mk:4 254 * includes[5]: include-subsub.mk:4
255 * (lineno, from an .include) 255 * (lineno, from an .include)
256 * includes[4]: include-sub.mk:32 256 * includes[4]: include-sub.mk:32
257 * (lineno, from a .for loop below an .include) 257 * (lineno, from a .for loop below an .include)
258 * includes[4]: include-sub.mk:31 258 * includes[4]: include-sub.mk:31
259 * (first_lineno, from a .for loop, lineno == 32) 259 * (first_lineno, from a .for loop, lineno == 32)
260 * includes[3]: include-sub.mk:30 260 * includes[3]: include-sub.mk:30
261 * (first_lineno, from a .for loop, lineno == 33) 261 * (first_lineno, from a .for loop, lineno == 33)
262 * includes[2]: include-sub.mk:29 262 * includes[2]: include-sub.mk:29
263 * (first_lineno, from a .for loop, lineno == 34) 263 * (first_lineno, from a .for loop, lineno == 34)
264 * includes[1]: include-sub.mk:35 264 * includes[1]: include-sub.mk:35
265 * (not printed since it is below a .for loop) 265 * (not printed since it is below a .for loop)
266 * includes[0]: include-main.mk:27 266 * includes[0]: include-main.mk:27
267 */ 267 */
268static Vector /* of IFile */ includes; 268static Vector /* of IFile */ includes;
269 269
270static IFile * 270static IFile *
271GetInclude(size_t i) 271GetInclude(size_t i)
272{ 272{
273 return Vector_Get(&includes, i); 273 return Vector_Get(&includes, i);
274} 274}
275 275
276/* The file that is currently being read. */ 276/* The file that is currently being read. */
277static IFile * 277static IFile *
278CurFile(void) 278CurFile(void)
279{ 279{
280 return GetInclude(includes.len - 1); 280 return GetInclude(includes.len - 1);
281} 281}
282 282
283/* include paths */ 283/* include paths */
284SearchPath *parseIncPath; /* dirs for "..." includes */ 284SearchPath *parseIncPath; /* dirs for "..." includes */
285SearchPath *sysIncPath; /* dirs for <...> includes */ 285SearchPath *sysIncPath; /* dirs for <...> includes */
286SearchPath *defSysIncPath; /* default for sysIncPath */ 286SearchPath *defSysIncPath; /* default for sysIncPath */
287 287
288/* parser tables */ 288/* parser tables */
289 289
290/* 290/*
291 * The parseKeywords table is searched using binary search when deciding 291 * The parseKeywords table is searched using binary search when deciding
292 * if a target or source is special. The 'spec' field is the ParseSpecial 292 * if a target or source is special. The 'spec' field is the ParseSpecial
293 * type of the keyword (SP_NOT if the keyword isn't special as a target) while 293 * type of the keyword (SP_NOT if the keyword isn't special as a target) while
294 * the 'op' field is the operator to apply to the list of targets if the 294 * the 'op' field is the operator to apply to the list of targets if the
295 * keyword is used as a source ("0" if the keyword isn't special as a source) 295 * keyword is used as a source ("0" if the keyword isn't special as a source)
296 */ 296 */
297static const struct { 297static const struct {
298 const char *name; /* Name of keyword */ 298 const char *name; /* Name of keyword */
299 ParseSpecial spec; /* Type when used as a target */ 299 ParseSpecial spec; /* Type when used as a target */
300 GNodeType op; /* Operator when used as a source */ 300 GNodeType op; /* Operator when used as a source */
301} parseKeywords[] = { 301} parseKeywords[] = {
302 { ".BEGIN", SP_BEGIN, 0 }, 302 { ".BEGIN", SP_BEGIN, 0 },
303 { ".DEFAULT", SP_DEFAULT, 0 }, 303 { ".DEFAULT", SP_DEFAULT, 0 },
304 { ".DELETE_ON_ERROR", SP_DELETE_ON_ERROR, 0 }, 304 { ".DELETE_ON_ERROR", SP_DELETE_ON_ERROR, 0 },
305 { ".END", SP_END, 0 }, 305 { ".END", SP_END, 0 },
306 { ".ERROR", SP_ERROR, 0 }, 306 { ".ERROR", SP_ERROR, 0 },
307 { ".EXEC", SP_ATTRIBUTE, OP_EXEC }, 307 { ".EXEC", SP_ATTRIBUTE, OP_EXEC },
308 { ".IGNORE", SP_IGNORE, OP_IGNORE }, 308 { ".IGNORE", SP_IGNORE, OP_IGNORE },
309 { ".INCLUDES", SP_INCLUDES, 0 }, 309 { ".INCLUDES", SP_INCLUDES, 0 },
310 { ".INTERRUPT", SP_INTERRUPT, 0 }, 310 { ".INTERRUPT", SP_INTERRUPT, 0 },
311 { ".INVISIBLE", SP_ATTRIBUTE, OP_INVISIBLE }, 311 { ".INVISIBLE", SP_ATTRIBUTE, OP_INVISIBLE },
312 { ".JOIN", SP_ATTRIBUTE, OP_JOIN }, 312 { ".JOIN", SP_ATTRIBUTE, OP_JOIN },
313 { ".LIBS", SP_LIBS, 0 }, 313 { ".LIBS", SP_LIBS, 0 },
314 { ".MADE", SP_ATTRIBUTE, OP_MADE }, 314 { ".MADE", SP_ATTRIBUTE, OP_MADE },
315 { ".MAIN", SP_MAIN, 0 }, 315 { ".MAIN", SP_MAIN, 0 },
316 { ".MAKE", SP_ATTRIBUTE, OP_MAKE }, 316 { ".MAKE", SP_ATTRIBUTE, OP_MAKE },
317 { ".MAKEFLAGS", SP_MFLAGS, 0 }, 317 { ".MAKEFLAGS", SP_MFLAGS, 0 },
318 { ".META", SP_META, OP_META }, 318 { ".META", SP_META, OP_META },
319 { ".MFLAGS", SP_MFLAGS, 0 }, 319 { ".MFLAGS", SP_MFLAGS, 0 },
320 { ".NOMETA", SP_NOMETA, OP_NOMETA }, 320 { ".NOMETA", SP_NOMETA, OP_NOMETA },
321 { ".NOMETA_CMP", SP_NOMETA_CMP, OP_NOMETA_CMP }, 321 { ".NOMETA_CMP", SP_NOMETA_CMP, OP_NOMETA_CMP },
322 { ".NOPATH", SP_NOPATH, OP_NOPATH }, 322 { ".NOPATH", SP_NOPATH, OP_NOPATH },
323 { ".NOTMAIN", SP_ATTRIBUTE, OP_NOTMAIN }, 323 { ".NOTMAIN", SP_ATTRIBUTE, OP_NOTMAIN },
324 { ".NOTPARALLEL", SP_NOTPARALLEL, 0 }, 324 { ".NOTPARALLEL", SP_NOTPARALLEL, 0 },
325 { ".NO_PARALLEL", SP_NOTPARALLEL, 0 }, 325 { ".NO_PARALLEL", SP_NOTPARALLEL, 0 },
326 { ".NULL", SP_NULL, 0 }, 326 { ".NULL", SP_NULL, 0 },
327 { ".OBJDIR", SP_OBJDIR, 0 }, 327 { ".OBJDIR", SP_OBJDIR, 0 },
328 { ".OPTIONAL", SP_ATTRIBUTE, OP_OPTIONAL }, 328 { ".OPTIONAL", SP_ATTRIBUTE, OP_OPTIONAL },
329 { ".ORDER", SP_ORDER, 0 }, 329 { ".ORDER", SP_ORDER, 0 },
330 { ".PARALLEL", SP_PARALLEL, 0 }, 330 { ".PARALLEL", SP_PARALLEL, 0 },
331 { ".PATH", SP_PATH, 0 }, 331 { ".PATH", SP_PATH, 0 },
332 { ".PHONY", SP_PHONY, OP_PHONY }, 332 { ".PHONY", SP_PHONY, OP_PHONY },
333#ifdef POSIX 333#ifdef POSIX
334 { ".POSIX", SP_POSIX, 0 }, 334 { ".POSIX", SP_POSIX, 0 },
335#endif 335#endif
336 { ".PRECIOUS", SP_PRECIOUS, OP_PRECIOUS }, 336 { ".PRECIOUS", SP_PRECIOUS, OP_PRECIOUS },
337 { ".RECURSIVE", SP_ATTRIBUTE, OP_MAKE }, 337 { ".RECURSIVE", SP_ATTRIBUTE, OP_MAKE },
338 { ".SHELL", SP_SHELL, 0 }, 338 { ".SHELL", SP_SHELL, 0 },
339 { ".SILENT", SP_SILENT, OP_SILENT }, 339 { ".SILENT", SP_SILENT, OP_SILENT },
340 { ".SINGLESHELL", SP_SINGLESHELL, 0 }, 340 { ".SINGLESHELL", SP_SINGLESHELL, 0 },
341 { ".STALE", SP_STALE, 0 }, 341 { ".STALE", SP_STALE, 0 },
342 { ".SUFFIXES", SP_SUFFIXES, 0 }, 342 { ".SUFFIXES", SP_SUFFIXES, 0 },
343 { ".USE", SP_ATTRIBUTE, OP_USE }, 343 { ".USE", SP_ATTRIBUTE, OP_USE },
344 { ".USEBEFORE", SP_ATTRIBUTE, OP_USEBEFORE }, 344 { ".USEBEFORE", SP_ATTRIBUTE, OP_USEBEFORE },
345 { ".WAIT", SP_WAIT, 0 }, 345 { ".WAIT", SP_WAIT, 0 },
346}; 346};
347 347
348/* file loader */ 348/* file loader */
349 349
350struct loadedfile { 350struct loadedfile {
351 const char *path; /* name, for error reports */ 351 const char *path; /* name, for error reports */
352 char *buf; /* contents buffer */ 352 char *buf; /* contents buffer */
353 size_t len; /* length of contents */ 353 size_t len; /* length of contents */
354 size_t maplen; /* length of mmap area, or 0 */ 354 size_t maplen; /* length of mmap area, or 0 */
355 Boolean used; /* XXX: have we used the data yet */ 355 Boolean used; /* XXX: have we used the data yet */
356}; 356};
357 357
358static struct loadedfile * 358static struct loadedfile *
359loadedfile_create(const char *path) 359loadedfile_create(const char *path)
360{ 360{
361 struct loadedfile *lf; 361 struct loadedfile *lf;
362 362
363 lf = bmake_malloc(sizeof(*lf)); 363 lf = bmake_malloc(sizeof(*lf));
364 lf->path = path == NULL ? "(stdin)" : path; 364 lf->path = path == NULL ? "(stdin)" : path;
365 lf->buf = NULL; 365 lf->buf = NULL;
366 lf->len = 0; 366 lf->len = 0;
367 lf->maplen = 0; 367 lf->maplen = 0;
368 lf->used = FALSE; 368 lf->used = FALSE;
369 return lf; 369 return lf;
370} 370}
371 371
372static void 372static void
373loadedfile_destroy(struct loadedfile *lf) 373loadedfile_destroy(struct loadedfile *lf)
374{ 374{
375 if (lf->buf != NULL) { 375 if (lf->buf != NULL) {
376 if (lf->maplen > 0) { 376 if (lf->maplen > 0) {
377 munmap(lf->buf, lf->maplen); 377 munmap(lf->buf, lf->maplen);
378 } else { 378 } else {
379 free(lf->buf); 379 free(lf->buf);
380 } 380 }
381 } 381 }
382 free(lf); 382 free(lf);
383} 383}
384 384
385/* 385/*
386 * nextbuf() operation for loadedfile, as needed by the weird and twisted 386 * nextbuf() operation for loadedfile, as needed by the weird and twisted
387 * logic below. Once that's cleaned up, we can get rid of lf->used... 387 * logic below. Once that's cleaned up, we can get rid of lf->used...
388 */ 388 */
389static char * 389static char *
390loadedfile_nextbuf(void *x, size_t *len) 390loadedfile_nextbuf(void *x, size_t *len)
391{ 391{
392 struct loadedfile *lf = x; 392 struct loadedfile *lf = x;
393 393
394 if (lf->used) { 394 if (lf->used) {
395 return NULL; 395 return NULL;
396 } 396 }
397 lf->used = TRUE; 397 lf->used = TRUE;
398 *len = lf->len; 398 *len = lf->len;
399 return lf->buf; 399 return lf->buf;
400} 400}
401 401
402/* 402/*
403 * Try to get the size of a file. 403 * Try to get the size of a file.
404 */ 404 */
405static Boolean 405static Boolean
406load_getsize(int fd, size_t *ret) 406load_getsize(int fd, size_t *ret)
407{ 407{
408 struct stat st; 408 struct stat st;
409 409
410 if (fstat(fd, &st) < 0) { 410 if (fstat(fd, &st) < 0) {
411 return FALSE; 411 return FALSE;
412 } 412 }
413 413
414 if (!S_ISREG(st.st_mode)) { 414 if (!S_ISREG(st.st_mode)) {
415 return FALSE; 415 return FALSE;
416 } 416 }
417 417
418 /* 418 /*
419 * st_size is an off_t, which is 64 bits signed; *ret is 419 * st_size is an off_t, which is 64 bits signed; *ret is
420 * size_t, which might be 32 bits unsigned or 64 bits 420 * size_t, which might be 32 bits unsigned or 64 bits
421 * unsigned. Rather than being elaborate, just punt on 421 * unsigned. Rather than being elaborate, just punt on
422 * files that are more than 2^31 bytes. We should never 422 * files that are more than 2^31 bytes. We should never
423 * see a makefile that size in practice... 423 * see a makefile that size in practice...
424 * 424 *
425 * While we're at it reject negative sizes too, just in case. 425 * While we're at it reject negative sizes too, just in case.
426 */ 426 */
427 if (st.st_size < 0 || st.st_size > 0x7fffffff) { 427 if (st.st_size < 0 || st.st_size > 0x7fffffff) {
428 return FALSE; 428 return FALSE;
429 } 429 }
430 430
431 *ret = (size_t)st.st_size; 431 *ret = (size_t)st.st_size;
432 return TRUE; 432 return TRUE;
433} 433}
434 434
435static Boolean 435static Boolean
436loadedfile_mmap(struct loadedfile *lf, int fd) 436loadedfile_mmap(struct loadedfile *lf, int fd)
437{ 437{
438 static unsigned long pagesize = 0; 438 static unsigned long pagesize = 0;
439 439
440 if (load_getsize(fd, &lf->len)) { 440 if (load_getsize(fd, &lf->len)) {
441 441
442 /* found a size, try mmap */ 442 /* found a size, try mmap */
443 if (pagesize == 0) 443 if (pagesize == 0)
444 pagesize = (unsigned long)sysconf(_SC_PAGESIZE); 444 pagesize = (unsigned long)sysconf(_SC_PAGESIZE);
445 if (pagesize == 0 || pagesize == (unsigned long)-1) { 445 if (pagesize == 0 || pagesize == (unsigned long)-1) {
446 pagesize = 0x1000; 446 pagesize = 0x1000;
447 } 447 }
448 /* round size up to a page */ 448 /* round size up to a page */
449 lf->maplen = pagesize * ((lf->len + pagesize - 1) / pagesize); 449 lf->maplen = pagesize * ((lf->len + pagesize - 1) / pagesize);
450 450
451 /* 451 /*
452 * XXX hack for dealing with empty files; remove when 452 * XXX hack for dealing with empty files; remove when
453 * we're no longer limited by interfacing to the old 453 * we're no longer limited by interfacing to the old
454 * logic elsewhere in this file. 454 * logic elsewhere in this file.
455 */ 455 */
456 if (lf->maplen == 0) { 456 if (lf->maplen == 0) {
457 lf->maplen = pagesize; 457 lf->maplen = pagesize;
458 } 458 }
459 459
460 /* 460 /*
461 * FUTURE: remove PROT_WRITE when the parser no longer 461 * FUTURE: remove PROT_WRITE when the parser no longer
462 * needs to scribble on the input. 462 * needs to scribble on the input.
463 */ 463 */
464 lf->buf = mmap(NULL, lf->maplen, PROT_READ|PROT_WRITE, 464 lf->buf = mmap(NULL, lf->maplen, PROT_READ|PROT_WRITE,
465 MAP_FILE|MAP_COPY, fd, 0); 465 MAP_FILE|MAP_COPY, fd, 0);
466 if (lf->buf != MAP_FAILED) { 466 if (lf->buf != MAP_FAILED) {
467 /* succeeded */ 467 /* succeeded */
468 if (lf->len == lf->maplen && lf->buf[lf->len - 1] != '\n') { 468 if (lf->len == lf->maplen && lf->buf[lf->len - 1] != '\n') {
469 char *b = bmake_malloc(lf->len + 1); 469 char *b = bmake_malloc(lf->len + 1);
470 b[lf->len] = '\n'; 470 b[lf->len] = '\n';
471 memcpy(b, lf->buf, lf->len++); 471 memcpy(b, lf->buf, lf->len++);
472 munmap(lf->buf, lf->maplen); 472 munmap(lf->buf, lf->maplen);
473 lf->maplen = 0; 473 lf->maplen = 0;
474 lf->buf = b; 474 lf->buf = b;
475 } 475 }
476 return TRUE; 476 return TRUE;
477 } 477 }
478 } 478 }
479 return FALSE; 479 return FALSE;
480} 480}
481 481
482/* 482/*
483 * Read in a file. 483 * Read in a file.
484 * 484 *
485 * Until the path search logic can be moved under here instead of 485 * Until the path search logic can be moved under here instead of
486 * being in the caller in another source file, we need to have the fd 486 * being in the caller in another source file, we need to have the fd
487 * passed in already open. Bleh. 487 * passed in already open. Bleh.
488 * 488 *
489 * If the path is NULL use stdin and (to insure against fd leaks) 489 * If the path is NULL use stdin and (to insure against fd leaks)
490 * assert that the caller passed in -1. 490 * assert that the caller passed in -1.
491 */ 491 */
492static struct loadedfile * 492static struct loadedfile *
493loadfile(const char *path, int fd) 493loadfile(const char *path, int fd)
494{ 494{
495 struct loadedfile *lf; 495 struct loadedfile *lf;
496 ssize_t result; 496 ssize_t result;
497 size_t bufpos; 497 size_t bufpos;
498 498
499 lf = loadedfile_create(path); 499 lf = loadedfile_create(path);
500 500
501 if (path == NULL) { 501 if (path == NULL) {
502 assert(fd == -1); 502 assert(fd == -1);
503 fd = STDIN_FILENO; 503 fd = STDIN_FILENO;
504 } else { 504 } else {
505#if 0 /* notyet */ 505#if 0 /* notyet */
506 fd = open(path, O_RDONLY); 506 fd = open(path, O_RDONLY);
507 if (fd < 0) { 507 if (fd < 0) {
508 ... 508 ...
509 Error("%s: %s", path, strerror(errno)); 509 Error("%s: %s", path, strerror(errno));
510 exit(1); 510 exit(1);
511 } 511 }
512#endif 512#endif
513 } 513 }
514 514
515 if (loadedfile_mmap(lf, fd)) 515 if (loadedfile_mmap(lf, fd))
516 goto done; 516 goto done;
517 517
518 /* cannot mmap; load the traditional way */ 518 /* cannot mmap; load the traditional way */
519 519
520 lf->maplen = 0; 520 lf->maplen = 0;
521 lf->len = 1024; 521 lf->len = 1024;
522 lf->buf = bmake_malloc(lf->len); 522 lf->buf = bmake_malloc(lf->len);
523 523
524 bufpos = 0; 524 bufpos = 0;
525 while (1) { 525 while (1) {
526 assert(bufpos <= lf->len); 526 assert(bufpos <= lf->len);
527 if (bufpos == lf->len) { 527 if (bufpos == lf->len) {
528 if (lf->len > SIZE_MAX/2) { 528 if (lf->len > SIZE_MAX/2) {
529 errno = EFBIG; 529 errno = EFBIG;
530 Error("%s: file too large", path); 530 Error("%s: file too large", path);
531 exit(1); 531 exit(1);
532 } 532 }
533 lf->len *= 2; 533 lf->len *= 2;
534 lf->buf = bmake_realloc(lf->buf, lf->len); 534 lf->buf = bmake_realloc(lf->buf, lf->len);
535 } 535 }
536 assert(bufpos < lf->len); 536 assert(bufpos < lf->len);
537 result = read(fd, lf->buf + bufpos, lf->len - bufpos); 537 result = read(fd, lf->buf + bufpos, lf->len - bufpos);
538 if (result < 0) { 538 if (result < 0) {
539 Error("%s: read error: %s", path, strerror(errno)); 539 Error("%s: read error: %s", path, strerror(errno));
540 exit(1); 540 exit(1);
541 } 541 }
542 if (result == 0) { 542 if (result == 0) {
543 break; 543 break;
544 } 544 }
545 bufpos += (size_t)result; 545 bufpos += (size_t)result;
546 } 546 }
547 assert(bufpos <= lf->len); 547 assert(bufpos <= lf->len);
548 lf->len = bufpos; 548 lf->len = bufpos;
549 549
550 /* truncate malloc region to actual length (maybe not useful) */ 550 /* truncate malloc region to actual length (maybe not useful) */
551 if (lf->len > 0) { 551 if (lf->len > 0) {
552 /* as for mmap case, ensure trailing \n */ 552 /* as for mmap case, ensure trailing \n */
553 if (lf->buf[lf->len - 1] != '\n') 553 if (lf->buf[lf->len - 1] != '\n')
554 lf->len++; 554 lf->len++;
555 lf->buf = bmake_realloc(lf->buf, lf->len); 555 lf->buf = bmake_realloc(lf->buf, lf->len);
556 lf->buf[lf->len - 1] = '\n'; 556 lf->buf[lf->len - 1] = '\n';
557 } 557 }
558 558
559done: 559done:
560 if (path != NULL) { 560 if (path != NULL) {
561 close(fd); 561 close(fd);
562 } 562 }
563 return lf; 563 return lf;
564} 564}
565 565
566/* old code */ 566/* old code */
567 567
568/* Check if the current character is escaped on the current line. */ 568/* Check if the current character is escaped on the current line. */
569static Boolean 569static Boolean
570ParseIsEscaped(const char *line, const char *c) 570ParseIsEscaped(const char *line, const char *c)
571{ 571{
572 Boolean active = FALSE; 572 Boolean active = FALSE;
573 for (;;) { 573 for (;;) {
574 if (line == c) 574 if (line == c)
575 return active; 575 return active;
576 if (*--c != '\\') 576 if (*--c != '\\')
577 return active; 577 return active;
578 active = !active; 578 active = !active;
579 } 579 }
580} 580}
581 581
582/* Add the filename and lineno to the GNode so that we remember where it 582/* Add the filename and lineno to the GNode so that we remember where it
583 * was first defined. */ 583 * was first defined. */
584static void 584static void
585ParseMark(GNode *gn) 585ParseMark(GNode *gn)
586{ 586{
587 IFile *curFile = CurFile(); 587 IFile *curFile = CurFile();
588 gn->fname = curFile->fname; 588 gn->fname = curFile->fname;
589 gn->lineno = curFile->lineno; 589 gn->lineno = curFile->lineno;
590} 590}
591 591
592/* Look in the table of keywords for one matching the given string. 592/* Look in the table of keywords for one matching the given string.
593 * Return the index of the keyword, or -1 if it isn't there. */ 593 * Return the index of the keyword, or -1 if it isn't there. */
594static int 594static int
595ParseFindKeyword(const char *str) 595ParseFindKeyword(const char *str)
596{ 596{
597 int start, end, cur; 597 int start, end, cur;
598 int diff; 598 int diff;
599 599
600 start = 0; 600 start = 0;
601 end = sizeof parseKeywords / sizeof parseKeywords[0] - 1; 601 end = sizeof parseKeywords / sizeof parseKeywords[0] - 1;
602 602
603 do { 603 do {
604 cur = start + (end - start) / 2; 604 cur = start + (end - start) / 2;
605 diff = strcmp(str, parseKeywords[cur].name); 605 diff = strcmp(str, parseKeywords[cur].name);
606 606
607 if (diff == 0) { 607 if (diff == 0) {
608 return cur; 608 return cur;
609 } else if (diff < 0) { 609 } else if (diff < 0) {
610 end = cur - 1; 610 end = cur - 1;
611 } else { 611 } else {
612 start = cur + 1; 612 start = cur + 1;
613 } 613 }
614 } while (start <= end); 614 } while (start <= end);
615 return -1; 615 return -1;
616} 616}
617 617
618static void 618static void
619PrintLocation(FILE *f, const char *filename, size_t lineno) 619PrintLocation(FILE *f, const char *filename, size_t lineno)
620{ 620{
621 char dirbuf[MAXPATHLEN+1]; 621 char dirbuf[MAXPATHLEN+1];
622 const char *dir, *base; 622 const char *dir, *base;
623 void *dir_freeIt, *base_freeIt; 623 void *dir_freeIt, *base_freeIt;
624 624
625 if (*filename == '/' || strcmp(filename, "(stdin)") == 0) { 625 if (*filename == '/' || strcmp(filename, "(stdin)") == 0) {
626 (void)fprintf(f, "\"%s\" line %zu: ", filename, lineno); 626 (void)fprintf(f, "\"%s\" line %zu: ", filename, lineno);
627 return; 627 return;
628 } 628 }
629 629
630 /* Find out which makefile is the culprit. 630 /* Find out which makefile is the culprit.
631 * We try ${.PARSEDIR} and apply realpath(3) if not absolute. */ 631 * We try ${.PARSEDIR} and apply realpath(3) if not absolute. */
632 632
633 dir = Var_Value(".PARSEDIR", VAR_GLOBAL, &dir_freeIt); 633 dir = Var_Value(".PARSEDIR", VAR_GLOBAL, &dir_freeIt);
634 if (dir == NULL) 634 if (dir == NULL)
635 dir = "."; 635 dir = ".";
636 if (*dir != '/') 636 if (*dir != '/')
637 dir = realpath(dir, dirbuf); 637 dir = realpath(dir, dirbuf);
638 638
639 base = Var_Value(".PARSEFILE", VAR_GLOBAL, &base_freeIt); 639 base = Var_Value(".PARSEFILE", VAR_GLOBAL, &base_freeIt);
640 if (base == NULL) { 640 if (base == NULL) {
641 const char *slash = strrchr(filename, '/'); 641 const char *slash = strrchr(filename, '/');
642 base = slash != NULL ? slash + 1 : filename; 642 base = slash != NULL ? slash + 1 : filename;
643 } 643 }
644 644
645 (void)fprintf(f, "\"%s/%s\" line %zu: ", dir, base, lineno); 645 (void)fprintf(f, "\"%s/%s\" line %zu: ", dir, base, lineno);
646 bmake_free(base_freeIt); 646 bmake_free(base_freeIt);
647 bmake_free(dir_freeIt); 647 bmake_free(dir_freeIt);
648} 648}
649 649
650/* Print a parse error message, including location information. 650/* Print a parse error message, including location information.
651 * 651 *
652 * Increment "fatals" if the level is PARSE_FATAL, and continue parsing 652 * Increment "fatals" if the level is PARSE_FATAL, and continue parsing
653 * until the end of the current top-level makefile, then exit (see 653 * until the end of the current top-level makefile, then exit (see
654 * Parse_File). */ 654 * Parse_File). */
655static void 655static void
656ParseVErrorInternal(FILE *f, const char *cfname, size_t clineno, 656ParseVErrorInternal(FILE *f, const char *cfname, size_t clineno,
657 ParseErrorLevel type, const char *fmt, va_list ap) 657 ParseErrorLevel type, const char *fmt, va_list ap)
658{ 658{
659 static Boolean fatal_warning_error_printed = FALSE; 659 static Boolean fatal_warning_error_printed = FALSE;
660 660
661 (void)fprintf(f, "%s: ", progname); 661 (void)fprintf(f, "%s: ", progname);
662 662
663 if (cfname != NULL) 663 if (cfname != NULL)
664 PrintLocation(f, cfname, clineno); 664 PrintLocation(f, cfname, clineno);
665 if (type == PARSE_WARNING) 665 if (type == PARSE_WARNING)
666 (void)fprintf(f, "warning: "); 666 (void)fprintf(f, "warning: ");
667 (void)vfprintf(f, fmt, ap); 667 (void)vfprintf(f, fmt, ap);
668 (void)fprintf(f, "\n"); 668 (void)fprintf(f, "\n");
669 (void)fflush(f); 669 (void)fflush(f);
670 670
671 if (type == PARSE_INFO) 671 if (type == PARSE_INFO)
672 return; 672 return;
673 if (type == PARSE_FATAL || opts.parseWarnFatal) 673 if (type == PARSE_FATAL || opts.parseWarnFatal)
674 fatals++; 674 fatals++;
675 if (opts.parseWarnFatal && !fatal_warning_error_printed) { 675 if (opts.parseWarnFatal && !fatal_warning_error_printed) {
676 Error("parsing warnings being treated as errors"); 676 Error("parsing warnings being treated as errors");
677 fatal_warning_error_printed = TRUE; 677 fatal_warning_error_printed = TRUE;
678 } 678 }
679} 679}
680 680
681static void 681static void
682ParseErrorInternal(const char *cfname, size_t clineno, ParseErrorLevel type, 682ParseErrorInternal(const char *cfname, size_t clineno, ParseErrorLevel type,
683 const char *fmt, ...) 683 const char *fmt, ...)
684{ 684{
685 va_list ap; 685 va_list ap;
686 686
687 va_start(ap, fmt); 687 va_start(ap, fmt);
688 (void)fflush(stdout); 688 (void)fflush(stdout);
689 ParseVErrorInternal(stderr, cfname, clineno, type, fmt, ap); 689 ParseVErrorInternal(stderr, cfname, clineno, type, fmt, ap);
690 va_end(ap); 690 va_end(ap);
691 691
692 if (opts.debug_file != stderr && opts.debug_file != stdout) { 692 if (opts.debug_file != stderr && opts.debug_file != stdout) {
693 va_start(ap, fmt); 693 va_start(ap, fmt);
694 ParseVErrorInternal(opts.debug_file, cfname, clineno, type, 694 ParseVErrorInternal(opts.debug_file, cfname, clineno, type,
695 fmt, ap); 695 fmt, ap);
696 va_end(ap); 696 va_end(ap);
697 } 697 }
698} 698}
699 699
700/* External interface to ParseErrorInternal; uses the default filename and 700/* External interface to ParseErrorInternal; uses the default filename and
701 * line number. 701 * line number.
702 * 702 *
703 * Fmt is given without a trailing newline. */ 703 * Fmt is given without a trailing newline. */
704void 704void
705Parse_Error(ParseErrorLevel type, const char *fmt, ...) 705Parse_Error(ParseErrorLevel type, const char *fmt, ...)
706{ 706{
707 va_list ap; 707 va_list ap;
708 const char *fname; 708 const char *fname;
709 size_t lineno; 709 size_t lineno;
710 710
711 if (includes.len == 0) { 711 if (includes.len == 0) {
712 fname = NULL; 712 fname = NULL;
713 lineno = 0; 713 lineno = 0;
714 } else { 714 } else {
715 IFile *curFile = CurFile(); 715 IFile *curFile = CurFile();
716 fname = curFile->fname; 716 fname = curFile->fname;
717 lineno = (size_t)curFile->lineno; 717 lineno = (size_t)curFile->lineno;
718 } 718 }
719 719
720 va_start(ap, fmt); 720 va_start(ap, fmt);
721 (void)fflush(stdout); 721 (void)fflush(stdout);
722 ParseVErrorInternal(stderr, fname, lineno, type, fmt, ap); 722 ParseVErrorInternal(stderr, fname, lineno, type, fmt, ap);
723 va_end(ap); 723 va_end(ap);
724 724
725 if (opts.debug_file != stderr && opts.debug_file != stdout) { 725 if (opts.debug_file != stderr && opts.debug_file != stdout) {
726 va_start(ap, fmt); 726 va_start(ap, fmt);
727 ParseVErrorInternal(opts.debug_file, fname, lineno, type, 727 ParseVErrorInternal(opts.debug_file, fname, lineno, type,
728 fmt, ap); 728 fmt, ap);
729 va_end(ap); 729 va_end(ap);
730 } 730 }
731} 731}
732 732
733 733
734/* Parse a .info .warning or .error directive. 734/* Parse a .info .warning or .error directive.
735 * 735 *
736 * The input is the line minus the ".". We substitute variables, print the 736 * The input is the line minus the ".". We substitute variables, print the
737 * message and exit(1) (for .error) or just print a warning if the directive 737 * message and exit(1) (for .error) or just print a warning if the directive
738 * is malformed. 738 * is malformed.
739 */ 739 */
740static Boolean 740static Boolean
741ParseMessage(const char *directive) 741ParseMessage(const char *directive)
742{ 742{
743 const char *p = directive; 743 const char *p = directive;
744 int mtype = *p == 'i' ? PARSE_INFO : 744 int mtype = *p == 'i' ? PARSE_INFO :
745 *p == 'w' ? PARSE_WARNING : PARSE_FATAL; 745 *p == 'w' ? PARSE_WARNING : PARSE_FATAL;
746 char *arg; 746 char *arg;
747 747
748 while (ch_isalpha(*p)) 748 while (ch_isalpha(*p))
749 p++; 749 p++;
750 if (!ch_isspace(*p)) 750 if (!ch_isspace(*p))
751 return FALSE; /* missing argument */ 751 return FALSE; /* missing argument */
752 752
753 cpp_skip_whitespace(&p); 753 cpp_skip_whitespace(&p);
754 (void)Var_Subst(p, VAR_CMDLINE, VARE_WANTRES, &arg); 754 (void)Var_Subst(p, VAR_CMDLINE, VARE_WANTRES, &arg);
755 /* TODO: handle errors */ 755 /* TODO: handle errors */
756 756
757 Parse_Error(mtype, "%s", arg); 757 Parse_Error(mtype, "%s", arg);
758 free(arg); 758 free(arg);
759 759
760 if (mtype == PARSE_FATAL) { 760 if (mtype == PARSE_FATAL) {
761 PrintOnError(NULL, NULL); 761 PrintOnError(NULL, NULL);
762 exit(1); 762 exit(1);
763 } 763 }
764 return TRUE; 764 return TRUE;
765} 765}
766 766
767/* Add the child to the parent's children. 767/* Add the child to the parent's children.
768 * 768 *
769 * Additionally, add the parent to the child's parents, but only if the 769 * Additionally, add the parent to the child's parents, but only if the
770 * target is not special. An example for such a special target is .END, 770 * target is not special. An example for such a special target is .END,
771 * which does not need to be informed once the child target has been made. */ 771 * which does not need to be informed once the child target has been made. */
772static void 772static void
773LinkSource(GNode *pgn, GNode *cgn, Boolean isSpecial) 773LinkSource(GNode *pgn, GNode *cgn, Boolean isSpecial)
774{ 774{
775 if ((pgn->type & OP_DOUBLEDEP) && !Lst_IsEmpty(pgn->cohorts)) 775 if ((pgn->type & OP_DOUBLEDEP) && !Lst_IsEmpty(pgn->cohorts))
776 pgn = pgn->cohorts->last->datum; 776 pgn = pgn->cohorts->last->datum;
777 777
778 Lst_Append(pgn->children, cgn); 778 Lst_Append(pgn->children, cgn);
779 pgn->unmade++; 779 pgn->unmade++;
780 780
781 /* Special targets like .END don't need any children. */ 781 /* Special targets like .END don't need any children. */
782 if (!isSpecial) 782 if (!isSpecial)
783 Lst_Append(cgn->parents, pgn); 783 Lst_Append(cgn->parents, pgn);
784 784
785 if (DEBUG(PARSE)) { 785 if (DEBUG(PARSE)) {
786 debug_printf("# %s: added child %s - %s\n", 786 debug_printf("# %s: added child %s - %s\n",
787 __func__, pgn->name, cgn->name); 787 __func__, pgn->name, cgn->name);
788 Targ_PrintNode(pgn, 0); 788 Targ_PrintNode(pgn, 0);
789 Targ_PrintNode(cgn, 0); 789 Targ_PrintNode(cgn, 0);
790 } 790 }
791} 791}
792 792
793/* Add the node to each target from the current dependency group. */ 793/* Add the node to each target from the current dependency group. */
794static void 794static void
795LinkToTargets(GNode *gn, Boolean isSpecial) 795LinkToTargets(GNode *gn, Boolean isSpecial)
796{ 796{
797 GNodeListNode *ln; 797 GNodeListNode *ln;
798 for (ln = targets->first; ln != NULL; ln = ln->next) 798 for (ln = targets->first; ln != NULL; ln = ln->next)
799 LinkSource(ln->datum, gn, isSpecial); 799 LinkSource(ln->datum, gn, isSpecial);
800} 800}
801 801
802static Boolean 802static Boolean
803TryApplyDependencyOperator(GNode *gn, GNodeType op) 803TryApplyDependencyOperator(GNode *gn, GNodeType op)
804{ 804{
805 /* 805 /*
806 * If the node occurred on the left-hand side of a dependency and the 806 * If the node occurred on the left-hand side of a dependency and the
807 * operator also defines a dependency, they must match. 807 * operator also defines a dependency, they must match.
808 */ 808 */
809 if ((op & OP_OPMASK) && (gn->type & OP_OPMASK) && 809 if ((op & OP_OPMASK) && (gn->type & OP_OPMASK) &&
810 ((op & OP_OPMASK) != (gn->type & OP_OPMASK))) 810 ((op & OP_OPMASK) != (gn->type & OP_OPMASK)))
811 { 811 {
812 Parse_Error(PARSE_FATAL, "Inconsistent operator for %s", gn->name); 812 Parse_Error(PARSE_FATAL, "Inconsistent operator for %s", gn->name);
813 return FALSE; 813 return FALSE;
814 } 814 }
815 815
816 if (op == OP_DOUBLEDEP && (gn->type & OP_OPMASK) == OP_DOUBLEDEP) { 816 if (op == OP_DOUBLEDEP && (gn->type & OP_OPMASK) == OP_DOUBLEDEP) {
817 /* 817 /*
818 * If the node was the object of a :: operator, we need to create a 818 * If the node was the object of a :: operator, we need to create a
819 * new instance of it for the children and commands on this dependency 819 * new instance of it for the children and commands on this dependency
820 * line. The new instance is placed on the 'cohorts' list of the 820 * line. The new instance is placed on the 'cohorts' list of the
821 * initial one (note the initial one is not on its own cohorts list) 821 * initial one (note the initial one is not on its own cohorts list)
822 * and the new instance is linked to all parents of the initial 822 * and the new instance is linked to all parents of the initial
823 * instance. 823 * instance.
824 */ 824 */
825 GNode *cohort; 825 GNode *cohort;
826 826
827 /* 827 /*
828 * Propagate copied bits to the initial node. They'll be propagated 828 * Propagate copied bits to the initial node. They'll be propagated
829 * back to the rest of the cohorts later. 829 * back to the rest of the cohorts later.
830 */ 830 */
831 gn->type |= op & ~OP_OPMASK; 831 gn->type |= op & ~OP_OPMASK;
832 832
833 cohort = Targ_NewInternalNode(gn->name); 833 cohort = Targ_NewInternalNode(gn->name);
834 if (doing_depend) 834 if (doing_depend)
835 ParseMark(cohort); 835 ParseMark(cohort);
836 /* 836 /*
837 * Make the cohort invisible as well to avoid duplicating it into 837 * Make the cohort invisible as well to avoid duplicating it into
838 * other variables. True, parents of this target won't tend to do 838 * other variables. True, parents of this target won't tend to do
839 * anything with their local variables, but better safe than 839 * anything with their local variables, but better safe than
840 * sorry. (I think this is pointless now, since the relevant list 840 * sorry. (I think this is pointless now, since the relevant list
841 * traversals will no longer see this node anyway. -mycroft) 841 * traversals will no longer see this node anyway. -mycroft)
842 */ 842 */
843 cohort->type = op | OP_INVISIBLE; 843 cohort->type = op | OP_INVISIBLE;
844 Lst_Append(gn->cohorts, cohort); 844 Lst_Append(gn->cohorts, cohort);
845 cohort->centurion = gn; 845 cohort->centurion = gn;
846 gn->unmade_cohorts++; 846 gn->unmade_cohorts++;
847 snprintf(cohort->cohort_num, sizeof cohort->cohort_num, "#%d", 847 snprintf(cohort->cohort_num, sizeof cohort->cohort_num, "#%d",
848 (unsigned int)gn->unmade_cohorts % 1000000); 848 (unsigned int)gn->unmade_cohorts % 1000000);
849 } else { 849 } else {
850 /* 850 /*
851 * We don't want to nuke any previous flags (whatever they were) so we 851 * We don't want to nuke any previous flags (whatever they were) so we
852 * just OR the new operator into the old 852 * just OR the new operator into the old
853 */ 853 */
854 gn->type |= op; 854 gn->type |= op;
855 } 855 }
856 856
857 return TRUE; 857 return TRUE;
858} 858}
859 859
860static void 860static void
861ApplyDependencyOperator(GNodeType op) 861ApplyDependencyOperator(GNodeType op)
862{ 862{
863 GNodeListNode *ln; 863 GNodeListNode *ln;
864 for (ln = targets->first; ln != NULL; ln = ln->next) 864 for (ln = targets->first; ln != NULL; ln = ln->next)
865 if (!TryApplyDependencyOperator(ln->datum, op)) 865 if (!TryApplyDependencyOperator(ln->datum, op))
866 break; 866 break;
867} 867}
868 868
869static Boolean 869static Boolean
870ParseDoSrcKeyword(const char *src, ParseSpecial specType) 870ParseDoSrcKeyword(const char *src, ParseSpecial specType)
871{ 871{
872 static int wait_number = 0; 872 static int wait_number = 0;
873 char wait_src[16]; 873 char wait_src[16];
874 GNode *gn; 874 GNode *gn;
875 875
876 if (*src == '.' && ch_isupper(src[1])) { 876 if (*src == '.' && ch_isupper(src[1])) {
877 int keywd = ParseFindKeyword(src); 877 int keywd = ParseFindKeyword(src);
878 if (keywd != -1) { 878 if (keywd != -1) {
879 int op = parseKeywords[keywd].op; 879 int op = parseKeywords[keywd].op;
880 if (op != 0) { 880 if (op != 0) {
881 ApplyDependencyOperator(op); 881 ApplyDependencyOperator(op);
882 return TRUE; 882 return TRUE;
883 } 883 }
884 if (parseKeywords[keywd].spec == SP_WAIT) { 884 if (parseKeywords[keywd].spec == SP_WAIT) {
885 /* 885 /*
886 * We add a .WAIT node in the dependency list. 886 * We add a .WAIT node in the dependency list.
887 * After any dynamic dependencies (and filename globbing) 887 * After any dynamic dependencies (and filename globbing)
888 * have happened, it is given a dependency on the each 888 * have happened, it is given a dependency on the each
889 * previous child back to and previous .WAIT node. 889 * previous child back to and previous .WAIT node.
890 * The next child won't be scheduled until the .WAIT node 890 * The next child won't be scheduled until the .WAIT node
891 * is built. 891 * is built.
892 * We give each .WAIT node a unique name (mainly for diag). 892 * We give each .WAIT node a unique name (mainly for diag).
893 */ 893 */
894 snprintf(wait_src, sizeof wait_src, ".WAIT_%u", ++wait_number); 894 snprintf(wait_src, sizeof wait_src, ".WAIT_%u", ++wait_number);
895 gn = Targ_NewInternalNode(wait_src); 895 gn = Targ_NewInternalNode(wait_src);
896 if (doing_depend) 896 if (doing_depend)
897 ParseMark(gn); 897 ParseMark(gn);
898 gn->type = OP_WAIT | OP_PHONY | OP_DEPENDS | OP_NOTMAIN; 898 gn->type = OP_WAIT | OP_PHONY | OP_DEPENDS | OP_NOTMAIN;
899 LinkToTargets(gn, specType != SP_NOT); 899 LinkToTargets(gn, specType != SP_NOT);
900 return TRUE; 900 return TRUE;
901 } 901 }
902 } 902 }
903 } 903 }
904 return FALSE; 904 return FALSE;
905} 905}
906 906
907static void 907static void
908ParseDoSrcMain(const char *src) 908ParseDoSrcMain(const char *src)
909{ 909{
910 /* 910 /*
911 * If we have noted the existence of a .MAIN, it means we need 911 * If we have noted the existence of a .MAIN, it means we need
912 * to add the sources of said target to the list of things 912 * to add the sources of said target to the list of things
913 * to create. The string 'src' is likely to be free, so we 913 * to create. The string 'src' is likely to be free, so we
914 * must make a new copy of it. Note that this will only be 914 * must make a new copy of it. Note that this will only be
915 * invoked if the user didn't specify a target on the command 915 * invoked if the user didn't specify a target on the command
916 * line. This is to allow #ifmake's to succeed, or something... 916 * line. This is to allow #ifmake's to succeed, or something...
917 */ 917 */
918 Lst_Append(opts.create, bmake_strdup(src)); 918 Lst_Append(opts.create, bmake_strdup(src));
919 /* 919 /*
920 * Add the name to the .TARGETS variable as well, so the user can 920 * Add the name to the .TARGETS variable as well, so the user can
921 * employ that, if desired. 921 * employ that, if desired.
922 */ 922 */
923 Var_Append(".TARGETS", src, VAR_GLOBAL); 923 Var_Append(".TARGETS", src, VAR_GLOBAL);
924} 924}
925 925
926static void 926static void
927ParseDoSrcOrder(const char *src) 927ParseDoSrcOrder(const char *src)
928{ 928{
929 GNode *gn; 929 GNode *gn;
930 /* 930 /*
931 * Create proper predecessor/successor links between the previous 931 * Create proper predecessor/successor links between the previous
932 * source and the current one. 932 * source and the current one.
933 */ 933 */
934 gn = Targ_GetNode(src); 934 gn = Targ_GetNode(src);
935 if (doing_depend) 935 if (doing_depend)
936 ParseMark(gn); 936 ParseMark(gn);
937 if (order_pred != NULL) { 937 if (order_pred != NULL) {
938 Lst_Append(order_pred->order_succ, gn); 938 Lst_Append(order_pred->order_succ, gn);
939 Lst_Append(gn->order_pred, order_pred); 939 Lst_Append(gn->order_pred, order_pred);
940 if (DEBUG(PARSE)) { 940 if (DEBUG(PARSE)) {
941 debug_printf("# %s: added Order dependency %s - %s\n", 941 debug_printf("# %s: added Order dependency %s - %s\n",
942 __func__, order_pred->name, gn->name); 942 __func__, order_pred->name, gn->name);
943 Targ_PrintNode(order_pred, 0); 943 Targ_PrintNode(order_pred, 0);
944 Targ_PrintNode(gn, 0); 944 Targ_PrintNode(gn, 0);
945 } 945 }
946 } 946 }
947 /* 947 /*
948 * The current source now becomes the predecessor for the next one. 948 * The current source now becomes the predecessor for the next one.
949 */ 949 */
950 order_pred = gn; 950 order_pred = gn;
951} 951}
952 952
953static void 953static void
954ParseDoSrcOther(const char *src, GNodeType tOp, ParseSpecial specType) 954ParseDoSrcOther(const char *src, GNodeType tOp, ParseSpecial specType)
955{ 955{
956 GNode *gn; 956 GNode *gn;
957 957
958 /* 958 /*
959 * If the source is not an attribute, we need to find/create 959 * If the source is not an attribute, we need to find/create
960 * a node for it. After that we can apply any operator to it 960 * a node for it. After that we can apply any operator to it
961 * from a special target or link it to its parents, as 961 * from a special target or link it to its parents, as
962 * appropriate. 962 * appropriate.
963 * 963 *
964 * In the case of a source that was the object of a :: operator, 964 * In the case of a source that was the object of a :: operator,
965 * the attribute is applied to all of its instances (as kept in 965 * the attribute is applied to all of its instances (as kept in
966 * the 'cohorts' list of the node) or all the cohorts are linked 966 * the 'cohorts' list of the node) or all the cohorts are linked
967 * to all the targets. 967 * to all the targets.
968 */ 968 */
969 969
970 /* Find/create the 'src' node and attach to all targets */ 970 /* Find/create the 'src' node and attach to all targets */
971 gn = Targ_GetNode(src); 971 gn = Targ_GetNode(src);
972 if (doing_depend) 972 if (doing_depend)
973 ParseMark(gn); 973 ParseMark(gn);
974 if (tOp) { 974 if (tOp) {
975 gn->type |= tOp; 975 gn->type |= tOp;
976 } else { 976 } else {
977 LinkToTargets(gn, specType != SP_NOT); 977 LinkToTargets(gn, specType != SP_NOT);
978 } 978 }
979} 979}
980 980
981/* Given the name of a source in a dependency line, figure out if it is an 981/* Given the name of a source in a dependency line, figure out if it is an
982 * attribute (such as .SILENT) and apply it to the targets if it is. Else 982 * attribute (such as .SILENT) and apply it to the targets if it is. Else
983 * decide if there is some attribute which should be applied *to* the source 983 * decide if there is some attribute which should be applied *to* the source
984 * because of some special target (such as .PHONY) and apply it if so. 984 * because of some special target (such as .PHONY) and apply it if so.
985 * Otherwise, make the source a child of the targets in the list 'targets'. 985 * Otherwise, make the source a child of the targets in the list 'targets'.
986 * 986 *
987 * Input: 987 * Input:
988 * tOp operator (if any) from special targets 988 * tOp operator (if any) from special targets
989 * src name of the source to handle 989 * src name of the source to handle
990 */ 990 */
991static void 991static void
992ParseDoSrc(GNodeType tOp, const char *src, ParseSpecial specType) 992ParseDoSrc(GNodeType tOp, const char *src, ParseSpecial specType)
993{ 993{
994 if (ParseDoSrcKeyword(src, specType)) 994 if (ParseDoSrcKeyword(src, specType))
995 return; 995 return;
996 996
997 if (specType == SP_MAIN) 997 if (specType == SP_MAIN)
998 ParseDoSrcMain(src); 998 ParseDoSrcMain(src);
999 else if (specType == SP_ORDER) 999 else if (specType == SP_ORDER)
1000 ParseDoSrcOrder(src); 1000 ParseDoSrcOrder(src);
1001 else 1001 else
1002 ParseDoSrcOther(src, tOp, specType); 1002 ParseDoSrcOther(src, tOp, specType);
1003} 1003}
1004 1004
1005/* If we have yet to decide on a main target to make, in the absence of any 1005/* If we have yet to decide on a main target to make, in the absence of any
1006 * user input, we want the first target on the first dependency line that is 1006 * user input, we want the first target on the first dependency line that is
1007 * actually a real target (i.e. isn't a .USE or .EXEC rule) to be made. */ 1007 * actually a real target (i.e. isn't a .USE or .EXEC rule) to be made. */
1008static void 1008static void
1009FindMainTarget(void) 1009FindMainTarget(void)
1010{ 1010{
1011 GNodeListNode *ln; 1011 GNodeListNode *ln;
1012 1012
1013 if (mainNode != NULL) 1013 if (mainNode != NULL)
1014 return; 1014 return;
1015 1015
1016 for (ln = targets->first; ln != NULL; ln = ln->next) { 1016 for (ln = targets->first; ln != NULL; ln = ln->next) {
1017 GNode *gn = ln->datum; 1017 GNode *gn = ln->datum;
1018 if (!(gn->type & OP_NOTARGET)) { 1018 if (!(gn->type & OP_NOTARGET)) {
1019 mainNode = gn; 1019 mainNode = gn;
1020 Targ_SetMain(gn); 1020 Targ_SetMain(gn);
1021 return; 1021 return;
1022 } 1022 }
1023 } 1023 }
1024} 1024}
1025 1025
1026/* 1026/*
1027 * We got to the end of the line while we were still looking at targets. 1027 * We got to the end of the line while we were still looking at targets.
1028 * 1028 *
1029 * Ending a dependency line without an operator is a Bozo no-no. As a 1029 * Ending a dependency line without an operator is a Bozo no-no. As a
1030 * heuristic, this is also often triggered by undetected conflicts from 1030 * heuristic, this is also often triggered by undetected conflicts from
1031 * cvs/rcs merges. 1031 * cvs/rcs merges.
1032 */ 1032 */
1033static void 1033static void
1034ParseErrorNoDependency(const char *lstart) 1034ParseErrorNoDependency(const char *lstart)
1035{ 1035{
1036 if ((strncmp(lstart, "<<<<<<", 6) == 0) || 1036 if ((strncmp(lstart, "<<<<<<", 6) == 0) ||
1037 (strncmp(lstart, "======", 6) == 0) || 1037 (strncmp(lstart, "======", 6) == 0) ||
1038 (strncmp(lstart, ">>>>>>", 6) == 0)) 1038 (strncmp(lstart, ">>>>>>", 6) == 0))
1039 Parse_Error(PARSE_FATAL, 1039 Parse_Error(PARSE_FATAL,
1040 "Makefile appears to contain unresolved cvs/rcs/??? merge conflicts"); 1040 "Makefile appears to contain unresolved cvs/rcs/??? merge conflicts");
1041 else if (lstart[0] == '.') { 1041 else if (lstart[0] == '.') {
1042 const char *dirstart = lstart + 1; 1042 const char *dirstart = lstart + 1;
1043 const char *dirend; 1043 const char *dirend;
1044 cpp_skip_whitespace(&dirstart); 1044 cpp_skip_whitespace(&dirstart);
1045 dirend = dirstart; 1045 dirend = dirstart;
1046 while (ch_isalnum(*dirend) || *dirend == '-') 1046 while (ch_isalnum(*dirend) || *dirend == '-')
1047 dirend++; 1047 dirend++;
1048 Parse_Error(PARSE_FATAL, "Unknown directive \"%.*s\"", 1048 Parse_Error(PARSE_FATAL, "Unknown directive \"%.*s\"",
1049 (int)(dirend - dirstart), dirstart); 1049 (int)(dirend - dirstart), dirstart);
1050 } else 1050 } else
1051 Parse_Error(PARSE_FATAL, "Need an operator"); 1051 Parse_Error(PARSE_FATAL, "Need an operator");
1052} 1052}
1053 1053
1054static void 1054static void
1055ParseDependencyTargetWord(/*const*/ char **pp, const char *lstart) 1055ParseDependencyTargetWord(/*const*/ char **pp, const char *lstart)
1056{ 1056{
1057 /*const*/ char *cp = *pp; 1057 /*const*/ char *cp = *pp;
1058 1058
1059 while (*cp != '\0') { 1059 while (*cp != '\0') {
1060 if ((ch_isspace(*cp) || *cp == '!' || *cp == ':' || *cp == '(') && 1060 if ((ch_isspace(*cp) || *cp == '!' || *cp == ':' || *cp == '(') &&
1061 !ParseIsEscaped(lstart, cp)) 1061 !ParseIsEscaped(lstart, cp))
1062 break; 1062 break;
1063 1063
1064 if (*cp == '$') { 1064 if (*cp == '$') {
1065 /* 1065 /*
1066 * Must be a dynamic source (would have been expanded 1066 * Must be a dynamic source (would have been expanded
1067 * otherwise), so call the Var module to parse the puppy 1067 * otherwise), so call the Var module to parse the puppy
1068 * so we can safely advance beyond it...There should be 1068 * so we can safely advance beyond it...There should be
1069 * no errors in this, as they would have been discovered 1069 * no errors in this, as they would have been discovered
1070 * in the initial Var_Subst and we wouldn't be here. 1070 * in the initial Var_Subst and we wouldn't be here.
1071 */ 1071 */
1072 const char *nested_p = cp; 1072 const char *nested_p = cp;
1073 const char *nested_val; 1073 const char *nested_val;
1074 void *freeIt; 1074 void *freeIt;
1075 1075
1076 (void)Var_Parse(&nested_p, VAR_CMDLINE, VARE_UNDEFERR|VARE_WANTRES, 1076 (void)Var_Parse(&nested_p, VAR_CMDLINE, VARE_UNDEFERR|VARE_WANTRES,
1077 &nested_val, &freeIt); 1077 &nested_val, &freeIt);
1078 /* TODO: handle errors */ 1078 /* TODO: handle errors */
1079 free(freeIt); 1079 free(freeIt);
1080 cp += nested_p - cp; 1080 cp += nested_p - cp;
1081 } else 1081 } else
1082 cp++; 1082 cp++;
1083 } 1083 }
1084 1084
1085 *pp = cp; 1085 *pp = cp;
1086} 1086}
1087 1087
1088/* 1088/*
1089 * Certain special targets have special semantics: 1089 * Certain special targets have special semantics:
1090 * .PATH Have to set the dirSearchPath 1090 * .PATH Have to set the dirSearchPath
1091 * variable too 1091 * variable too
1092 * .MAIN Its sources are only used if 1092 * .MAIN Its sources are only used if
1093 * nothing has been specified to 1093 * nothing has been specified to
1094 * create. 1094 * create.
1095 * .DEFAULT Need to create a node to hang 1095 * .DEFAULT Need to create a node to hang
1096 * commands on, but we don't want 1096 * commands on, but we don't want
1097 * it in the graph, nor do we want 1097 * it in the graph, nor do we want
1098 * it to be the Main Target, so we 1098 * it to be the Main Target, so we
1099 * create it, set OP_NOTMAIN and 1099 * create it, set OP_NOTMAIN and
1100 * add it to the list, setting 1100 * add it to the list, setting
1101 * DEFAULT to the new node for 1101 * DEFAULT to the new node for
1102 * later use. We claim the node is 1102 * later use. We claim the node is
1103 * A transformation rule to make 1103 * A transformation rule to make
1104 * life easier later, when we'll 1104 * life easier later, when we'll
1105 * use Make_HandleUse to actually 1105 * use Make_HandleUse to actually
1106 * apply the .DEFAULT commands. 1106 * apply the .DEFAULT commands.
1107 * .PHONY The list of targets 1107 * .PHONY The list of targets
1108 * .NOPATH Don't search for file in the path 1108 * .NOPATH Don't search for file in the path
1109 * .STALE 1109 * .STALE
1110 * .BEGIN 1110 * .BEGIN
1111 * .END 1111 * .END
1112 * .ERROR 1112 * .ERROR
1113 * .DELETE_ON_ERROR 1113 * .DELETE_ON_ERROR
1114 * .INTERRUPT Are not to be considered the 1114 * .INTERRUPT Are not to be considered the
1115 * main target. 1115 * main target.
1116 * .NOTPARALLEL Make only one target at a time. 1116 * .NOTPARALLEL Make only one target at a time.
1117 * .SINGLESHELL Create a shell for each command. 1117 * .SINGLESHELL Create a shell for each command.
1118 * .ORDER Must set initial predecessor to NULL 1118 * .ORDER Must set initial predecessor to NULL
1119 */ 1119 */
@@ -1358,1867 +1358,1866 @@ ClearPaths(SearchPathList *paths) @@ -1358,1867 +1358,1866 @@ ClearPaths(SearchPathList *paths)
1358static void 1358static void
1359ParseDoDependencySourcesEmpty(ParseSpecial specType, SearchPathList *paths) 1359ParseDoDependencySourcesEmpty(ParseSpecial specType, SearchPathList *paths)
1360{ 1360{
1361 switch (specType) { 1361 switch (specType) {
1362 case SP_SUFFIXES: 1362 case SP_SUFFIXES:
1363 Suff_ClearSuffixes(); 1363 Suff_ClearSuffixes();
1364 break; 1364 break;
1365 case SP_PRECIOUS: 1365 case SP_PRECIOUS:
1366 allPrecious = TRUE; 1366 allPrecious = TRUE;
1367 break; 1367 break;
1368 case SP_IGNORE: 1368 case SP_IGNORE:
1369 opts.ignoreErrors = TRUE; 1369 opts.ignoreErrors = TRUE;
1370 break; 1370 break;
1371 case SP_SILENT: 1371 case SP_SILENT:
1372 opts.beSilent = TRUE; 1372 opts.beSilent = TRUE;
1373 break; 1373 break;
1374 case SP_PATH: 1374 case SP_PATH:
1375 ClearPaths(paths); 1375 ClearPaths(paths);
1376 break; 1376 break;
1377#ifdef POSIX 1377#ifdef POSIX
1378 case SP_POSIX: 1378 case SP_POSIX:
1379 Var_Set("%POSIX", "1003.2", VAR_GLOBAL); 1379 Var_Set("%POSIX", "1003.2", VAR_GLOBAL);
1380 break; 1380 break;
1381#endif 1381#endif
1382 default: 1382 default:
1383 break; 1383 break;
1384 } 1384 }
1385} 1385}
1386 1386
1387static void 1387static void
1388AddToPaths(const char *dir, SearchPathList *paths) 1388AddToPaths(const char *dir, SearchPathList *paths)
1389{ 1389{
1390 if (paths != NULL) { 1390 if (paths != NULL) {
1391 SearchPathListNode *ln; 1391 SearchPathListNode *ln;
1392 for (ln = paths->first; ln != NULL; ln = ln->next) 1392 for (ln = paths->first; ln != NULL; ln = ln->next)
1393 (void)Dir_AddDir(ln->datum, dir); 1393 (void)Dir_AddDir(ln->datum, dir);
1394 } 1394 }
1395} 1395}
1396 1396
1397/* 1397/*
1398 * If the target was one that doesn't take files as its sources 1398 * If the target was one that doesn't take files as its sources
1399 * but takes something like suffixes, we take each 1399 * but takes something like suffixes, we take each
1400 * space-separated word on the line as a something and deal 1400 * space-separated word on the line as a something and deal
1401 * with it accordingly. 1401 * with it accordingly.
1402 * 1402 *
1403 * If the target was .SUFFIXES, we take each source as a 1403 * If the target was .SUFFIXES, we take each source as a
1404 * suffix and add it to the list of suffixes maintained by the 1404 * suffix and add it to the list of suffixes maintained by the
1405 * Suff module. 1405 * Suff module.
1406 * 1406 *
1407 * If the target was a .PATH, we add the source as a directory 1407 * If the target was a .PATH, we add the source as a directory
1408 * to search on the search path. 1408 * to search on the search path.
1409 * 1409 *
1410 * If it was .INCLUDES, the source is taken to be the suffix of 1410 * If it was .INCLUDES, the source is taken to be the suffix of
1411 * files which will be #included and whose search path should 1411 * files which will be #included and whose search path should
1412 * be present in the .INCLUDES variable. 1412 * be present in the .INCLUDES variable.
1413 * 1413 *
1414 * If it was .LIBS, the source is taken to be the suffix of 1414 * If it was .LIBS, the source is taken to be the suffix of
1415 * files which are considered libraries and whose search path 1415 * files which are considered libraries and whose search path
1416 * should be present in the .LIBS variable. 1416 * should be present in the .LIBS variable.
1417 * 1417 *
1418 * If it was .NULL, the source is the suffix to use when a file 1418 * If it was .NULL, the source is the suffix to use when a file
1419 * has no valid suffix. 1419 * has no valid suffix.
1420 * 1420 *
1421 * If it was .OBJDIR, the source is a new definition for .OBJDIR, 1421 * If it was .OBJDIR, the source is a new definition for .OBJDIR,
1422 * and will cause make to do a new chdir to that path. 1422 * and will cause make to do a new chdir to that path.
1423 */ 1423 */
1424static void 1424static void
1425ParseDoDependencySourceSpecial(ParseSpecial specType, char *word, 1425ParseDoDependencySourceSpecial(ParseSpecial specType, char *word,
1426 SearchPathList *paths) 1426 SearchPathList *paths)
1427{ 1427{
1428 switch (specType) { 1428 switch (specType) {
1429 case SP_SUFFIXES: 1429 case SP_SUFFIXES:
1430 Suff_AddSuffix(word, &mainNode); 1430 Suff_AddSuffix(word, &mainNode);
1431 break; 1431 break;
1432 case SP_PATH: 1432 case SP_PATH:
1433 AddToPaths(word, paths); 1433 AddToPaths(word, paths);
1434 break; 1434 break;
1435 case SP_INCLUDES: 1435 case SP_INCLUDES:
1436 Suff_AddInclude(word); 1436 Suff_AddInclude(word);
1437 break; 1437 break;
1438 case SP_LIBS: 1438 case SP_LIBS:
1439 Suff_AddLib(word); 1439 Suff_AddLib(word);
1440 break; 1440 break;
1441 case SP_NULL: 1441 case SP_NULL:
1442 Suff_SetNull(word); 1442 Suff_SetNull(word);
1443 break; 1443 break;
1444 case SP_OBJDIR: 1444 case SP_OBJDIR:
1445 Main_SetObjdir("%s", word); 1445 Main_SetObjdir("%s", word);
1446 break; 1446 break;
1447 default: 1447 default:
1448 break; 1448 break;
1449 } 1449 }
1450} 1450}
1451 1451
1452static Boolean 1452static Boolean
1453ParseDoDependencyTargets(char **inout_cp, 1453ParseDoDependencyTargets(char **inout_cp,
1454 char **inout_line, 1454 char **inout_line,
1455 const char *lstart, 1455 const char *lstart,
1456 ParseSpecial *inout_specType, 1456 ParseSpecial *inout_specType,
1457 GNodeType *inout_tOp, 1457 GNodeType *inout_tOp,
1458 SearchPathList **inout_paths, 1458 SearchPathList **inout_paths,
1459 StringList *curTargs) 1459 StringList *curTargs)
1460{ 1460{
1461 char *cp = *inout_cp; 1461 char *cp = *inout_cp;
1462 char *line = *inout_line; 1462 char *line = *inout_line;
1463 char savec; 1463 char savec;
1464 1464
1465 for (;;) { 1465 for (;;) {
1466 /* 1466 /*
1467 * Here LINE points to the beginning of the next word, and 1467 * Here LINE points to the beginning of the next word, and
1468 * LSTART points to the actual beginning of the line. 1468 * LSTART points to the actual beginning of the line.
1469 */ 1469 */
1470 1470
1471 /* Find the end of the next word. */ 1471 /* Find the end of the next word. */
1472 cp = line; 1472 cp = line;
1473 ParseDependencyTargetWord(&cp, lstart); 1473 ParseDependencyTargetWord(&cp, lstart);
1474 1474
1475 /* 1475 /*
1476 * If the word is followed by a left parenthesis, it's the 1476 * If the word is followed by a left parenthesis, it's the
1477 * name of an object file inside an archive (ar file). 1477 * name of an object file inside an archive (ar file).
1478 */ 1478 */
1479 if (!ParseIsEscaped(lstart, cp) && *cp == '(') { 1479 if (!ParseIsEscaped(lstart, cp) && *cp == '(') {
1480 /* 1480 /*
1481 * Archives must be handled specially to make sure the OP_ARCHV 1481 * Archives must be handled specially to make sure the OP_ARCHV
1482 * flag is set in their 'type' field, for one thing, and because 1482 * flag is set in their 'type' field, for one thing, and because
1483 * things like "archive(file1.o file2.o file3.o)" are permissible. 1483 * things like "archive(file1.o file2.o file3.o)" are permissible.
1484 * Arch_ParseArchive will set 'line' to be the first non-blank 1484 * Arch_ParseArchive will set 'line' to be the first non-blank
1485 * after the archive-spec. It creates/finds nodes for the members 1485 * after the archive-spec. It creates/finds nodes for the members
1486 * and places them on the given list, returning TRUE if all 1486 * and places them on the given list, returning TRUE if all
1487 * went well and FALSE if there was an error in the 1487 * went well and FALSE if there was an error in the
1488 * specification. On error, line should remain untouched. 1488 * specification. On error, line should remain untouched.
1489 */ 1489 */
1490 if (!Arch_ParseArchive(&line, targets, VAR_CMDLINE)) { 1490 if (!Arch_ParseArchive(&line, targets, VAR_CMDLINE)) {
1491 Parse_Error(PARSE_FATAL, 1491 Parse_Error(PARSE_FATAL,
1492 "Error in archive specification: \"%s\"", line); 1492 "Error in archive specification: \"%s\"", line);
1493 return FALSE; 1493 return FALSE;
1494 } else { 1494 } else {
1495 /* Done with this word; on to the next. */ 1495 /* Done with this word; on to the next. */
1496 cp = line; 1496 cp = line;
1497 continue; 1497 continue;
1498 } 1498 }
1499 } 1499 }
1500 1500
1501 if (!*cp) { 1501 if (!*cp) {
1502 ParseErrorNoDependency(lstart); 1502 ParseErrorNoDependency(lstart);
1503 return FALSE; 1503 return FALSE;
1504 } 1504 }
1505 1505
1506 /* Insert a null terminator. */ 1506 /* Insert a null terminator. */
1507 savec = *cp; 1507 savec = *cp;
1508 *cp = '\0'; 1508 *cp = '\0';
1509 1509
1510 if (!ParseDoDependencyTarget(line, inout_specType, inout_tOp, 1510 if (!ParseDoDependencyTarget(line, inout_specType, inout_tOp,
1511 inout_paths)) 1511 inout_paths))
1512 return FALSE; 1512 return FALSE;
1513 1513
1514 /* 1514 /*
1515 * Have word in line. Get or create its node and stick it at 1515 * Have word in line. Get or create its node and stick it at
1516 * the end of the targets list 1516 * the end of the targets list
1517 */ 1517 */
1518 if (*inout_specType == SP_NOT && *line != '\0') { 1518 if (*inout_specType == SP_NOT && *line != '\0') {
1519 ParseDoDependencyTargetMundane(line, curTargs); 1519 ParseDoDependencyTargetMundane(line, curTargs);
1520 } else if (*inout_specType == SP_PATH && *line != '.' && *line != '\0') { 1520 } else if (*inout_specType == SP_PATH && *line != '.' && *line != '\0') {
1521 Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", line); 1521 Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", line);
1522 } 1522 }
1523 1523
1524 /* Don't need the inserted null terminator any more. */ 1524 /* Don't need the inserted null terminator any more. */
1525 *cp = savec; 1525 *cp = savec;
1526 1526
1527 /* 1527 /*
1528 * If it is a special type and not .PATH, it's the only target we 1528 * If it is a special type and not .PATH, it's the only target we
1529 * allow on this line... 1529 * allow on this line...
1530 */ 1530 */
1531 if (*inout_specType != SP_NOT && *inout_specType != SP_PATH) { 1531 if (*inout_specType != SP_NOT && *inout_specType != SP_PATH) {
1532 ParseDoDependencyTargetExtraWarn(&cp, lstart); 1532 ParseDoDependencyTargetExtraWarn(&cp, lstart);
1533 } else { 1533 } else {
1534 pp_skip_whitespace(&cp); 1534 pp_skip_whitespace(&cp);
1535 } 1535 }
1536 line = cp; 1536 line = cp;
1537 if (*line == '\0') 1537 if (*line == '\0')
1538 break; 1538 break;
1539 if ((*line == '!' || *line == ':') && !ParseIsEscaped(lstart, line)) 1539 if ((*line == '!' || *line == ':') && !ParseIsEscaped(lstart, line))
1540 break; 1540 break;
1541 } 1541 }
1542 1542
1543 *inout_cp = cp; 1543 *inout_cp = cp;
1544 *inout_line = line; 1544 *inout_line = line;
1545 return TRUE; 1545 return TRUE;
1546} 1546}
1547 1547
1548static void 1548static void
1549ParseDoDependencySourcesSpecial(char *start, char *end, 1549ParseDoDependencySourcesSpecial(char *start, char *end,
1550 ParseSpecial specType, SearchPathList *paths) 1550 ParseSpecial specType, SearchPathList *paths)
1551{ 1551{
1552 char savec; 1552 char savec;
1553 1553
1554 while (*start) { 1554 while (*start) {
1555 while (*end && !ch_isspace(*end)) 1555 while (*end && !ch_isspace(*end))
1556 end++; 1556 end++;
1557 savec = *end; 1557 savec = *end;
1558 *end = '\0'; 1558 *end = '\0';
1559 ParseDoDependencySourceSpecial(specType, start, paths); 1559 ParseDoDependencySourceSpecial(specType, start, paths);
1560 *end = savec; 1560 *end = savec;
1561 if (savec != '\0') 1561 if (savec != '\0')
1562 end++; 1562 end++;
1563 pp_skip_whitespace(&end); 1563 pp_skip_whitespace(&end);
1564 start = end; 1564 start = end;
1565 } 1565 }
1566} 1566}
1567 1567
1568static Boolean 1568static Boolean
1569ParseDoDependencySourcesMundane(char *start, char *end, 1569ParseDoDependencySourcesMundane(char *start, char *end,
1570 ParseSpecial specType, GNodeType tOp) 1570 ParseSpecial specType, GNodeType tOp)
1571{ 1571{
1572 while (*start) { 1572 while (*start) {
1573 /* 1573 /*
1574 * The targets take real sources, so we must beware of archive 1574 * The targets take real sources, so we must beware of archive
1575 * specifications (i.e. things with left parentheses in them) 1575 * specifications (i.e. things with left parentheses in them)
1576 * and handle them accordingly. 1576 * and handle them accordingly.
1577 */ 1577 */
1578 for (; *end && !ch_isspace(*end); end++) { 1578 for (; *end && !ch_isspace(*end); end++) {
1579 if (*end == '(' && end > start && end[-1] != '$') { 1579 if (*end == '(' && end > start && end[-1] != '$') {
1580 /* 1580 /*
1581 * Only stop for a left parenthesis if it isn't at the 1581 * Only stop for a left parenthesis if it isn't at the
1582 * start of a word (that'll be for variable changes 1582 * start of a word (that'll be for variable changes
1583 * later) and isn't preceded by a dollar sign (a dynamic 1583 * later) and isn't preceded by a dollar sign (a dynamic
1584 * source). 1584 * source).
1585 */ 1585 */
1586 break; 1586 break;
1587 } 1587 }
1588 } 1588 }
1589 1589
1590 if (*end == '(') { 1590 if (*end == '(') {
1591 GNodeList *sources = Lst_New(); 1591 GNodeList *sources = Lst_New();
1592 if (!Arch_ParseArchive(&start, sources, VAR_CMDLINE)) { 1592 if (!Arch_ParseArchive(&start, sources, VAR_CMDLINE)) {
1593 Parse_Error(PARSE_FATAL, 1593 Parse_Error(PARSE_FATAL,
1594 "Error in source archive spec \"%s\"", start); 1594 "Error in source archive spec \"%s\"", start);
1595 return FALSE; 1595 return FALSE;
1596 } 1596 }
1597 1597
1598 while (!Lst_IsEmpty(sources)) { 1598 while (!Lst_IsEmpty(sources)) {
1599 GNode *gn = Lst_Dequeue(sources); 1599 GNode *gn = Lst_Dequeue(sources);
1600 ParseDoSrc(tOp, gn->name, specType); 1600 ParseDoSrc(tOp, gn->name, specType);
1601 } 1601 }
1602 Lst_Free(sources); 1602 Lst_Free(sources);
1603 end = start; 1603 end = start;
1604 } else { 1604 } else {
1605 if (*end) { 1605 if (*end) {
1606 *end = '\0'; 1606 *end = '\0';
1607 end++; 1607 end++;
1608 } 1608 }
1609 1609
1610 ParseDoSrc(tOp, start, specType); 1610 ParseDoSrc(tOp, start, specType);
1611 } 1611 }
1612 pp_skip_whitespace(&end); 1612 pp_skip_whitespace(&end);
1613 start = end; 1613 start = end;
1614 } 1614 }
1615 return TRUE; 1615 return TRUE;
1616} 1616}
1617 1617
1618/* Parse a dependency line consisting of targets, followed by a dependency 1618/* Parse a dependency line consisting of targets, followed by a dependency
1619 * operator, optionally followed by sources. 1619 * operator, optionally followed by sources.
1620 * 1620 *
1621 * The nodes of the sources are linked as children to the nodes of the 1621 * The nodes of the sources are linked as children to the nodes of the
1622 * targets. Nodes are created as necessary. 1622 * targets. Nodes are created as necessary.
1623 * 1623 *
1624 * The operator is applied to each node in the global 'targets' list, 1624 * The operator is applied to each node in the global 'targets' list,
1625 * which is where the nodes found for the targets are kept, by means of 1625 * which is where the nodes found for the targets are kept, by means of
1626 * the ParseDoOp function. 1626 * the ParseDoOp function.
1627 * 1627 *
1628 * The sources are parsed in much the same way as the targets, except 1628 * The sources are parsed in much the same way as the targets, except
1629 * that they are expanded using the wildcarding scheme of the C-Shell, 1629 * that they are expanded using the wildcarding scheme of the C-Shell,
1630 * and all instances of the resulting words in the list of all targets 1630 * and all instances of the resulting words in the list of all targets
1631 * are found. Each of the resulting nodes is then linked to each of the 1631 * are found. Each of the resulting nodes is then linked to each of the
1632 * targets as one of its children. 1632 * targets as one of its children.
1633 * 1633 *
1634 * Certain targets and sources such as .PHONY or .PRECIOUS are handled 1634 * Certain targets and sources such as .PHONY or .PRECIOUS are handled
1635 * specially. These are the ones detailed by the specType variable. 1635 * specially. These are the ones detailed by the specType variable.
1636 * 1636 *
1637 * The storing of transformation rules such as '.c.o' is also taken care of 1637 * The storing of transformation rules such as '.c.o' is also taken care of
1638 * here. A target is recognized as a transformation rule by calling 1638 * here. A target is recognized as a transformation rule by calling
1639 * Suff_IsTransform. If it is a transformation rule, its node is gotten 1639 * Suff_IsTransform. If it is a transformation rule, its node is gotten
1640 * from the suffix module via Suff_AddTransform rather than the standard 1640 * from the suffix module via Suff_AddTransform rather than the standard
1641 * Targ_FindNode in the target module. 1641 * Targ_FindNode in the target module.
1642 */ 1642 */
1643static void 1643static void
1644ParseDoDependency(char *line) 1644ParseDoDependency(char *line)
1645{ 1645{
1646 char *cp; /* our current position */ 1646 char *cp; /* our current position */
1647 GNodeType op; /* the operator on the line */ 1647 GNodeType op; /* the operator on the line */
1648 SearchPathList *paths; /* search paths to alter when parsing 1648 SearchPathList *paths; /* search paths to alter when parsing
1649 * a list of .PATH targets */ 1649 * a list of .PATH targets */
1650 int tOp; /* operator from special target */ 1650 int tOp; /* operator from special target */
1651 StringList *curTargs; /* target names to be found and added 1651 StringList *curTargs; /* target names to be found and added
1652 * to the targets list */ 1652 * to the targets list */
1653 char *lstart = line; 1653 char *lstart = line;
1654 1654
1655 /* 1655 /*
1656 * specType contains the SPECial TYPE of the current target. It is SP_NOT 1656 * specType contains the SPECial TYPE of the current target. It is SP_NOT
1657 * if the target is unspecial. If it *is* special, however, the children 1657 * if the target is unspecial. If it *is* special, however, the children
1658 * are linked as children of the parent but not vice versa. 1658 * are linked as children of the parent but not vice versa.
1659 */ 1659 */
1660 ParseSpecial specType = SP_NOT; 1660 ParseSpecial specType = SP_NOT;
1661 1661
1662 DEBUG1(PARSE, "ParseDoDependency(%s)\n", line); 1662 DEBUG1(PARSE, "ParseDoDependency(%s)\n", line);
1663 tOp = 0; 1663 tOp = 0;
1664 1664
1665 paths = NULL; 1665 paths = NULL;
1666 1666
1667 curTargs = Lst_New(); 1667 curTargs = Lst_New();
1668 1668
1669 /* 1669 /*
1670 * First, grind through the targets. 1670 * First, grind through the targets.
1671 */ 1671 */
1672 if (!ParseDoDependencyTargets(&cp, &line, lstart, &specType, &tOp, &paths, 1672 if (!ParseDoDependencyTargets(&cp, &line, lstart, &specType, &tOp, &paths,
1673 curTargs)) 1673 curTargs))
1674 goto out; 1674 goto out;
1675 1675
1676 /* 1676 /*
1677 * Don't need the list of target names anymore... 1677 * Don't need the list of target names anymore...
1678 */ 1678 */
1679 Lst_Free(curTargs); 1679 Lst_Free(curTargs);
1680 curTargs = NULL; 1680 curTargs = NULL;
1681 1681
1682 if (!Lst_IsEmpty(targets)) 1682 if (!Lst_IsEmpty(targets))
1683 ParseDoDependencyCheckSpec(specType); 1683 ParseDoDependencyCheckSpec(specType);
1684 1684
1685 /* 1685 /*
1686 * Have now parsed all the target names. Must parse the operator next. 1686 * Have now parsed all the target names. Must parse the operator next.
1687 */ 1687 */
1688 if (!ParseDoDependencyParseOp(&cp, lstart, &op)) 1688 if (!ParseDoDependencyParseOp(&cp, lstart, &op))
1689 goto out; 1689 goto out;
1690 1690
1691 /* 1691 /*
1692 * Apply the operator to the target. This is how we remember which 1692 * Apply the operator to the target. This is how we remember which
1693 * operator a target was defined with. It fails if the operator 1693 * operator a target was defined with. It fails if the operator
1694 * used isn't consistent across all references. 1694 * used isn't consistent across all references.
1695 */ 1695 */
1696 ApplyDependencyOperator(op); 1696 ApplyDependencyOperator(op);
1697 1697
1698 /* 1698 /*
1699 * Onward to the sources. 1699 * Onward to the sources.
1700 * 1700 *
1701 * LINE will now point to the first source word, if any, or the 1701 * LINE will now point to the first source word, if any, or the
1702 * end of the string if not. 1702 * end of the string if not.
1703 */ 1703 */
1704 pp_skip_whitespace(&cp); 1704 pp_skip_whitespace(&cp);
1705 line = cp; 1705 line = cp;
1706 1706
1707 /* 1707 /*
1708 * Several special targets take different actions if present with no 1708 * Several special targets take different actions if present with no
1709 * sources: 1709 * sources:
1710 * a .SUFFIXES line with no sources clears out all old suffixes 1710 * a .SUFFIXES line with no sources clears out all old suffixes
1711 * a .PRECIOUS line makes all targets precious 1711 * a .PRECIOUS line makes all targets precious
1712 * a .IGNORE line ignores errors for all targets 1712 * a .IGNORE line ignores errors for all targets
1713 * a .SILENT line creates silence when making all targets 1713 * a .SILENT line creates silence when making all targets
1714 * a .PATH removes all directories from the search path(s). 1714 * a .PATH removes all directories from the search path(s).
1715 */ 1715 */
1716 if (!*line) { 1716 if (!*line) {
1717 ParseDoDependencySourcesEmpty(specType, paths); 1717 ParseDoDependencySourcesEmpty(specType, paths);
1718 } else if (specType == SP_MFLAGS) { 1718 } else if (specType == SP_MFLAGS) {
1719 /* 1719 /*
1720 * Call on functions in main.c to deal with these arguments and 1720 * Call on functions in main.c to deal with these arguments and
1721 * set the initial character to a null-character so the loop to 1721 * set the initial character to a null-character so the loop to
1722 * get sources won't get anything 1722 * get sources won't get anything
1723 */ 1723 */
1724 Main_ParseArgLine(line); 1724 Main_ParseArgLine(line);
1725 *line = '\0'; 1725 *line = '\0';
1726 } else if (specType == SP_SHELL) { 1726 } else if (specType == SP_SHELL) {
1727 if (!Job_ParseShell(line)) { 1727 if (!Job_ParseShell(line)) {
1728 Parse_Error(PARSE_FATAL, "improper shell specification"); 1728 Parse_Error(PARSE_FATAL, "improper shell specification");
1729 goto out; 1729 goto out;
1730 } 1730 }
1731 *line = '\0'; 1731 *line = '\0';
1732 } else if (specType == SP_NOTPARALLEL || specType == SP_SINGLESHELL || 1732 } else if (specType == SP_NOTPARALLEL || specType == SP_SINGLESHELL ||
1733 specType == SP_DELETE_ON_ERROR) { 1733 specType == SP_DELETE_ON_ERROR) {
1734 *line = '\0'; 1734 *line = '\0';
1735 } 1735 }
1736 1736
1737 /* 1737 /*
1738 * NOW GO FOR THE SOURCES 1738 * NOW GO FOR THE SOURCES
1739 */ 1739 */
1740 if (specType == SP_SUFFIXES || specType == SP_PATH || 1740 if (specType == SP_SUFFIXES || specType == SP_PATH ||
1741 specType == SP_INCLUDES || specType == SP_LIBS || 1741 specType == SP_INCLUDES || specType == SP_LIBS ||
1742 specType == SP_NULL || specType == SP_OBJDIR) 1742 specType == SP_NULL || specType == SP_OBJDIR)
1743 { 1743 {
1744 ParseDoDependencySourcesSpecial(line, cp, specType, paths); 1744 ParseDoDependencySourcesSpecial(line, cp, specType, paths);
1745 if (paths) { 1745 if (paths) {
1746 Lst_Free(paths); 1746 Lst_Free(paths);
1747 paths = NULL; 1747 paths = NULL;
1748 } 1748 }
1749 if (specType == SP_PATH) 1749 if (specType == SP_PATH)
1750 Dir_SetPATH(); 1750 Dir_SetPATH();
1751 } else { 1751 } else {
1752 assert(paths == NULL); 1752 assert(paths == NULL);
1753 if (!ParseDoDependencySourcesMundane(line, cp, specType, tOp)) 1753 if (!ParseDoDependencySourcesMundane(line, cp, specType, tOp))
1754 goto out; 1754 goto out;
1755 } 1755 }
1756 1756
1757 FindMainTarget(); 1757 FindMainTarget();
1758 1758
1759out: 1759out:
1760 if (paths != NULL) 1760 if (paths != NULL)
1761 Lst_Free(paths); 1761 Lst_Free(paths);
1762 if (curTargs != NULL) 1762 if (curTargs != NULL)
1763 Lst_Free(curTargs); 1763 Lst_Free(curTargs);
1764} 1764}
1765 1765
1766typedef struct VarAssignParsed { 1766typedef struct VarAssignParsed {
1767 const char *nameStart; /* unexpanded */ 1767 const char *nameStart; /* unexpanded */
1768 const char *nameEnd; /* before operator adjustment */ 1768 const char *nameEnd; /* before operator adjustment */
1769 const char *eq; /* the '=' of the assignment operator */ 1769 const char *eq; /* the '=' of the assignment operator */
1770} VarAssignParsed; 1770} VarAssignParsed;
1771 1771
1772/* Determine the assignment operator and adjust the end of the variable 1772/* Determine the assignment operator and adjust the end of the variable
1773 * name accordingly. */ 1773 * name accordingly. */
1774static void 1774static void
1775AdjustVarassignOp(const VarAssignParsed *pvar, const char *value, 1775AdjustVarassignOp(const VarAssignParsed *pvar, const char *value,
1776 VarAssign *out_var) 1776 VarAssign *out_var)
1777{ 1777{
1778 const char *op = pvar->eq; 1778 const char *op = pvar->eq;
1779 const char * const name = pvar->nameStart; 1779 const char * const name = pvar->nameStart;
1780 VarAssignOp type; 1780 VarAssignOp type;
1781 1781
1782 if (op > name && op[-1] == '+') { 1782 if (op > name && op[-1] == '+') {
1783 type = VAR_APPEND; 1783 type = VAR_APPEND;
1784 op--; 1784 op--;
1785 1785
1786 } else if (op > name && op[-1] == '?') { 1786 } else if (op > name && op[-1] == '?') {
1787 op--; 1787 op--;
1788 type = VAR_DEFAULT; 1788 type = VAR_DEFAULT;
1789 1789
1790 } else if (op > name && op[-1] == ':') { 1790 } else if (op > name && op[-1] == ':') {
1791 op--; 1791 op--;
1792 type = VAR_SUBST; 1792 type = VAR_SUBST;
1793 1793
1794 } else if (op > name && op[-1] == '!') { 1794 } else if (op > name && op[-1] == '!') {
1795 op--; 1795 op--;
1796 type = VAR_SHELL; 1796 type = VAR_SHELL;
1797 1797
1798 } else { 1798 } else {
1799 type = VAR_NORMAL; 1799 type = VAR_NORMAL;
1800#ifdef SUNSHCMD 1800#ifdef SUNSHCMD
1801 while (op > name && ch_isspace(op[-1])) 1801 while (op > name && ch_isspace(op[-1]))
1802 op--; 1802 op--;
1803 1803
1804 if (op >= name + 3 && op[-3] == ':' && op[-2] == 's' && op[-1] == 'h') { 1804 if (op >= name + 3 && op[-3] == ':' && op[-2] == 's' && op[-1] == 'h') {
1805 type = VAR_SHELL; 1805 type = VAR_SHELL;
1806 op -= 3; 1806 op -= 3;
1807 } 1807 }
1808#endif 1808#endif
1809 } 1809 }
1810 1810
1811 { 1811 {
1812 const char *nameEnd = pvar->nameEnd < op ? pvar->nameEnd : op; 1812 const char *nameEnd = pvar->nameEnd < op ? pvar->nameEnd : op;
1813 out_var->varname = bmake_strsedup(pvar->nameStart, nameEnd); 1813 out_var->varname = bmake_strsedup(pvar->nameStart, nameEnd);
1814 out_var->op = type; 1814 out_var->op = type;
1815 out_var->value = value; 1815 out_var->value = value;
1816 } 1816 }
1817} 1817}
1818 1818
1819/* Parse a variable assignment, consisting of a single-word variable name, 1819/* Parse a variable assignment, consisting of a single-word variable name,
1820 * optional whitespace, an assignment operator, optional whitespace and the 1820 * optional whitespace, an assignment operator, optional whitespace and the
1821 * variable value. 1821 * variable value.
1822 * 1822 *
1823 * Note: There is a lexical ambiguity with assignment modifier characters 1823 * Note: There is a lexical ambiguity with assignment modifier characters
1824 * in variable names. This routine interprets the character before the = 1824 * in variable names. This routine interprets the character before the =
1825 * as a modifier. Therefore, an assignment like 1825 * as a modifier. Therefore, an assignment like
1826 * C++=/usr/bin/CC 1826 * C++=/usr/bin/CC
1827 * is interpreted as "C+ +=" instead of "C++ =". 1827 * is interpreted as "C+ +=" instead of "C++ =".
1828 * 1828 *
1829 * Used for both lines in a file and command line arguments. */ 1829 * Used for both lines in a file and command line arguments. */
1830Boolean 1830Boolean
1831Parse_IsVar(const char *p, VarAssign *out_var) 1831Parse_IsVar(const char *p, VarAssign *out_var)
1832{ 1832{
1833 VarAssignParsed pvar; 1833 VarAssignParsed pvar;
1834 const char *firstSpace = NULL; 1834 const char *firstSpace = NULL;
1835 char ch; 1835 char ch;
1836 int level = 0; 1836 int level = 0;
1837 1837
1838 /* Skip to variable name */ 1838 /* Skip to variable name */
1839 while (*p == ' ' || *p == '\t') 1839 while (*p == ' ' || *p == '\t')
1840 p++; 1840 p++;
1841 1841
1842 /* During parsing, the '+' of the '+=' operator is initially parsed 1842 /* During parsing, the '+' of the '+=' operator is initially parsed
1843 * as part of the variable name. It is later corrected, as is the ':sh' 1843 * as part of the variable name. It is later corrected, as is the ':sh'
1844 * modifier. Of these two (nameEnd and op), the earlier one determines the 1844 * modifier. Of these two (nameEnd and op), the earlier one determines the
1845 * actual end of the variable name. */ 1845 * actual end of the variable name. */
1846 pvar.nameStart = p; 1846 pvar.nameStart = p;
1847#ifdef CLEANUP 1847#ifdef CLEANUP
1848 pvar.nameEnd = NULL; 1848 pvar.nameEnd = NULL;
1849 pvar.eq = NULL; 1849 pvar.eq = NULL;
1850#endif 1850#endif
1851 1851
1852 /* Scan for one of the assignment operators outside a variable expansion */ 1852 /* Scan for one of the assignment operators outside a variable expansion */
1853 while ((ch = *p++) != 0) { 1853 while ((ch = *p++) != 0) {
1854 if (ch == '(' || ch == '{') { 1854 if (ch == '(' || ch == '{') {
1855 level++; 1855 level++;
1856 continue; 1856 continue;
1857 } 1857 }
1858 if (ch == ')' || ch == '}') { 1858 if (ch == ')' || ch == '}') {
1859 level--; 1859 level--;
1860 continue; 1860 continue;
1861 } 1861 }
1862 1862
1863 if (level != 0) 1863 if (level != 0)
1864 continue; 1864 continue;
1865 1865
1866 if (ch == ' ' || ch == '\t') 1866 if (ch == ' ' || ch == '\t')
1867 if (firstSpace == NULL) 1867 if (firstSpace == NULL)
1868 firstSpace = p - 1; 1868 firstSpace = p - 1;
1869 while (ch == ' ' || ch == '\t') 1869 while (ch == ' ' || ch == '\t')
1870 ch = *p++; 1870 ch = *p++;
1871 1871
1872#ifdef SUNSHCMD 1872#ifdef SUNSHCMD
1873 if (ch == ':' && strncmp(p, "sh", 2) == 0) { 1873 if (ch == ':' && strncmp(p, "sh", 2) == 0) {
1874 p += 2; 1874 p += 2;
1875 continue; 1875 continue;
1876 } 1876 }
1877#endif 1877#endif
1878 if (ch == '=') { 1878 if (ch == '=') {
1879 pvar.eq = p - 1; 1879 pvar.eq = p - 1;
1880 pvar.nameEnd = firstSpace != NULL ? firstSpace : p - 1; 1880 pvar.nameEnd = firstSpace != NULL ? firstSpace : p - 1;
1881 cpp_skip_whitespace(&p); 1881 cpp_skip_whitespace(&p);
1882 AdjustVarassignOp(&pvar, p, out_var); 1882 AdjustVarassignOp(&pvar, p, out_var);
1883 return TRUE; 1883 return TRUE;
1884 } 1884 }
1885 if (*p == '=' && (ch == '+' || ch == ':' || ch == '?' || ch == '!')) { 1885 if (*p == '=' && (ch == '+' || ch == ':' || ch == '?' || ch == '!')) {
1886 pvar.eq = p; 1886 pvar.eq = p;
1887 pvar.nameEnd = firstSpace != NULL ? firstSpace : p; 1887 pvar.nameEnd = firstSpace != NULL ? firstSpace : p;
1888 p++; 1888 p++;
1889 cpp_skip_whitespace(&p); 1889 cpp_skip_whitespace(&p);
1890 AdjustVarassignOp(&pvar, p, out_var); 1890 AdjustVarassignOp(&pvar, p, out_var);
1891 return TRUE; 1891 return TRUE;
1892 } 1892 }
1893 if (firstSpace != NULL) 1893 if (firstSpace != NULL)
1894 return FALSE; 1894 return FALSE;
1895 } 1895 }
1896 1896
1897 return FALSE; 1897 return FALSE;
1898} 1898}
1899 1899
1900static void 1900static void
1901VarCheckSyntax(VarAssignOp type, const char *uvalue, GNode *ctxt) 1901VarCheckSyntax(VarAssignOp type, const char *uvalue, GNode *ctxt)
1902{ 1902{
1903 if (DEBUG(LINT)) { 1903 if (DEBUG(LINT)) {
1904 if (type != VAR_SUBST && strchr(uvalue, '$') != NULL) { 1904 if (type != VAR_SUBST && strchr(uvalue, '$') != NULL) {
1905 /* Check for syntax errors such as unclosed expressions or 1905 /* Check for syntax errors such as unclosed expressions or
1906 * unknown modifiers. */ 1906 * unknown modifiers. */
1907 char *expandedValue; 1907 char *expandedValue;
1908 1908
1909 (void)Var_Subst(uvalue, ctxt, VARE_NONE, &expandedValue); 1909 (void)Var_Subst(uvalue, ctxt, VARE_NONE, &expandedValue);
1910 /* TODO: handle errors */ 1910 /* TODO: handle errors */
1911 free(expandedValue); 1911 free(expandedValue);
1912 } 1912 }
1913 } 1913 }
1914} 1914}
1915 1915
1916static void 1916static void
1917VarAssign_EvalSubst(const char *name, const char *uvalue, GNode *ctxt, 1917VarAssign_EvalSubst(const char *name, const char *uvalue, GNode *ctxt,
1918 const char **out_avalue, void **out_avalue_freeIt) 1918 const char **out_avalue, void **out_avalue_freeIt)
1919{ 1919{
1920 const char *avalue = uvalue; 1920 const char *avalue = uvalue;
1921 char *evalue; 1921 char *evalue;
1922 /* 1922 /*
1923 * Allow variables in the old value to be undefined, but leave their 1923 * Allow variables in the old value to be undefined, but leave their
1924 * expressions alone -- this is done by forcing oldVars to be false. 1924 * expressions alone -- this is done by forcing oldVars to be false.
1925 * XXX: This can cause recursive variables, but that's not hard to do, 1925 * XXX: This can cause recursive variables, but that's not hard to do,
1926 * and this allows someone to do something like 1926 * and this allows someone to do something like
1927 * 1927 *
1928 * CFLAGS = $(.INCLUDES) 1928 * CFLAGS = $(.INCLUDES)
1929 * CFLAGS := -I.. $(CFLAGS) 1929 * CFLAGS := -I.. $(CFLAGS)
1930 * 1930 *
1931 * And not get an error. 1931 * And not get an error.
1932 */ 1932 */
1933 Boolean oldOldVars = oldVars; 1933 Boolean oldOldVars = oldVars;
1934 1934
1935 oldVars = FALSE; 1935 oldVars = FALSE;
1936 1936
1937 /* 1937 /*
1938 * make sure that we set the variable the first time to nothing 1938 * make sure that we set the variable the first time to nothing
1939 * so that it gets substituted! 1939 * so that it gets substituted!
1940 */ 1940 */
1941 if (!Var_Exists(name, ctxt)) 1941 if (!Var_Exists(name, ctxt))
1942 Var_Set(name, "", ctxt); 1942 Var_Set(name, "", ctxt);
1943 1943
1944 (void)Var_Subst(uvalue, ctxt, VARE_WANTRES|VARE_ASSIGN, &evalue); 1944 (void)Var_Subst(uvalue, ctxt, VARE_WANTRES|VARE_ASSIGN, &evalue);
1945 /* TODO: handle errors */ 1945 /* TODO: handle errors */
1946 oldVars = oldOldVars; 1946 oldVars = oldOldVars;
1947 avalue = evalue; 1947 avalue = evalue;
1948 Var_Set(name, avalue, ctxt); 1948 Var_Set(name, avalue, ctxt);
1949 1949
1950 *out_avalue = avalue; 1950 *out_avalue = avalue;
1951 *out_avalue_freeIt = evalue; 1951 *out_avalue_freeIt = evalue;
1952} 1952}
1953 1953
1954static void 1954static void
1955VarAssign_EvalShell(const char *name, const char *uvalue, GNode *ctxt, 1955VarAssign_EvalShell(const char *name, const char *uvalue, GNode *ctxt,
1956 const char **out_avalue, void **out_avalue_freeIt) 1956 const char **out_avalue, void **out_avalue_freeIt)
1957{ 1957{
1958 const char *cmd, *errfmt; 1958 const char *cmd, *errfmt;
1959 char *cmdOut; 1959 char *cmdOut;
1960 void *cmd_freeIt = NULL; 1960 void *cmd_freeIt = NULL;
1961 1961
1962 cmd = uvalue; 1962 cmd = uvalue;
1963 if (strchr(cmd, '$') != NULL) { 1963 if (strchr(cmd, '$') != NULL) {
1964 char *ecmd; 1964 char *ecmd;
1965 (void)Var_Subst(cmd, VAR_CMDLINE, VARE_UNDEFERR | VARE_WANTRES, &ecmd); 1965 (void)Var_Subst(cmd, VAR_CMDLINE, VARE_UNDEFERR | VARE_WANTRES, &ecmd);
1966 /* TODO: handle errors */ 1966 /* TODO: handle errors */
1967 cmd = cmd_freeIt = ecmd; 1967 cmd = cmd_freeIt = ecmd;
1968 } 1968 }
1969 1969
1970 cmdOut = Cmd_Exec(cmd, &errfmt); 1970 cmdOut = Cmd_Exec(cmd, &errfmt);
1971 Var_Set(name, cmdOut, ctxt); 1971 Var_Set(name, cmdOut, ctxt);
1972 *out_avalue = *out_avalue_freeIt = cmdOut; 1972 *out_avalue = *out_avalue_freeIt = cmdOut;
1973 1973
1974 if (errfmt) 1974 if (errfmt)
1975 Parse_Error(PARSE_WARNING, errfmt, cmd); 1975 Parse_Error(PARSE_WARNING, errfmt, cmd);
1976 1976
1977 free(cmd_freeIt); 1977 free(cmd_freeIt);
1978} 1978}
1979 1979
1980/* Perform a variable assignment. 1980/* Perform a variable assignment.
1981 * 1981 *
1982 * The actual value of the variable is returned in *out_avalue and 1982 * The actual value of the variable is returned in *out_avalue and
1983 * *out_avalue_freeIt. Especially for VAR_SUBST and VAR_SHELL this can differ 1983 * *out_avalue_freeIt. Especially for VAR_SUBST and VAR_SHELL this can differ
1984 * from the literal value. 1984 * from the literal value.
1985 * 1985 *
1986 * Return whether the assignment was actually done. The assignment is only 1986 * Return whether the assignment was actually done. The assignment is only
1987 * skipped if the operator is '?=' and the variable already exists. */ 1987 * skipped if the operator is '?=' and the variable already exists. */
1988static Boolean 1988static Boolean
1989VarAssign_Eval(const char *name, VarAssignOp op, const char *uvalue, 1989VarAssign_Eval(const char *name, VarAssignOp op, const char *uvalue,
1990 GNode *ctxt, const char **out_avalue, void **out_avalue_freeIt) 1990 GNode *ctxt, const char **out_avalue, void **out_avalue_freeIt)
1991{ 1991{
1992 const char *avalue = uvalue; 1992 const char *avalue = uvalue;
1993 void *avalue_freeIt = NULL; 1993 void *avalue_freeIt = NULL;
1994 1994
1995 if (op == VAR_APPEND) { 1995 if (op == VAR_APPEND) {
1996 Var_Append(name, uvalue, ctxt); 1996 Var_Append(name, uvalue, ctxt);
1997 } else if (op == VAR_SUBST) { 1997 } else if (op == VAR_SUBST) {
1998 VarAssign_EvalSubst(name, uvalue, ctxt, &avalue, &avalue_freeIt); 1998 VarAssign_EvalSubst(name, uvalue, ctxt, &avalue, &avalue_freeIt);
1999 } else if (op == VAR_SHELL) { 1999 } else if (op == VAR_SHELL) {
2000 VarAssign_EvalShell(name, uvalue, ctxt, &avalue, &avalue_freeIt); 2000 VarAssign_EvalShell(name, uvalue, ctxt, &avalue, &avalue_freeIt);
2001 } else { 2001 } else {
2002 if (op == VAR_DEFAULT && Var_Exists(name, ctxt)) { 2002 if (op == VAR_DEFAULT && Var_Exists(name, ctxt)) {
2003 *out_avalue_freeIt = NULL; 2003 *out_avalue_freeIt = NULL;
2004 return FALSE; 2004 return FALSE;
2005 } 2005 }
2006 2006
2007 /* Normal assignment -- just do it. */ 2007 /* Normal assignment -- just do it. */
2008 Var_Set(name, uvalue, ctxt); 2008 Var_Set(name, uvalue, ctxt);
2009 } 2009 }
2010 2010
2011 *out_avalue = avalue; 2011 *out_avalue = avalue;
2012 *out_avalue_freeIt = avalue_freeIt; 2012 *out_avalue_freeIt = avalue_freeIt;
2013 return TRUE; 2013 return TRUE;
2014} 2014}
2015 2015
2016static void 2016static void
2017VarAssignSpecial(const char *name, const char *avalue) 2017VarAssignSpecial(const char *name, const char *avalue)
2018{ 2018{
2019 if (strcmp(name, MAKEOVERRIDES) == 0) 2019 if (strcmp(name, MAKEOVERRIDES) == 0)
2020 Main_ExportMAKEFLAGS(FALSE); /* re-export MAKEFLAGS */ 2020 Main_ExportMAKEFLAGS(FALSE); /* re-export MAKEFLAGS */
2021 else if (strcmp(name, ".CURDIR") == 0) { 2021 else if (strcmp(name, ".CURDIR") == 0) {
2022 /* 2022 /*
2023 * Someone is being (too?) clever... 2023 * Someone is being (too?) clever...
2024 * Let's pretend they know what they are doing and 2024 * Let's pretend they know what they are doing and
2025 * re-initialize the 'cur' CachedDir. 2025 * re-initialize the 'cur' CachedDir.
2026 */ 2026 */
2027 Dir_InitCur(avalue); 2027 Dir_InitCur(avalue);
2028 Dir_SetPATH(); 2028 Dir_SetPATH();
2029 } else if (strcmp(name, MAKE_JOB_PREFIX) == 0) { 2029 } else if (strcmp(name, MAKE_JOB_PREFIX) == 0) {
2030 Job_SetPrefix(); 2030 Job_SetPrefix();
2031 } else if (strcmp(name, MAKE_EXPORTED) == 0) { 2031 } else if (strcmp(name, MAKE_EXPORTED) == 0) {
2032 Var_Export(avalue, FALSE); 2032 Var_Export(avalue, FALSE);
2033 } 2033 }
2034} 2034}
2035 2035
2036/* Perform the variable variable assignment in the given context. */ 2036/* Perform the variable variable assignment in the given context. */
2037void 2037void
2038Parse_DoVar(VarAssign *var, GNode *ctxt) 2038Parse_DoVar(VarAssign *var, GNode *ctxt)
2039{ 2039{
2040 const char *avalue; /* actual value (maybe expanded) */ 2040 const char *avalue; /* actual value (maybe expanded) */
2041 void *avalue_freeIt; 2041 void *avalue_freeIt;
2042 2042
2043 VarCheckSyntax(var->op, var->value, ctxt); 2043 VarCheckSyntax(var->op, var->value, ctxt);
2044 if (VarAssign_Eval(var->varname, var->op, var->value, ctxt, 2044 if (VarAssign_Eval(var->varname, var->op, var->value, ctxt,
2045 &avalue, &avalue_freeIt)) 2045 &avalue, &avalue_freeIt))
2046 VarAssignSpecial(var->varname, avalue); 2046 VarAssignSpecial(var->varname, avalue);
2047 2047
2048 free(avalue_freeIt); 2048 free(avalue_freeIt);
2049 free(var->varname); 2049 free(var->varname);
2050} 2050}
2051 2051
2052 2052
2053/* 2053/*
2054 * ParseMaybeSubMake -- 2054 * ParseMaybeSubMake --
2055 * Scan the command string to see if it a possible submake node 2055 * Scan the command string to see if it a possible submake node
2056 * Input: 2056 * Input:
2057 * cmd the command to scan 2057 * cmd the command to scan
2058 * Results: 2058 * Results:
2059 * TRUE if the command is possibly a submake, FALSE if not. 2059 * TRUE if the command is possibly a submake, FALSE if not.
2060 */ 2060 */
2061static Boolean 2061static Boolean
2062ParseMaybeSubMake(const char *cmd) 2062ParseMaybeSubMake(const char *cmd)
2063{ 2063{
2064 size_t i; 2064 size_t i;
2065 static struct { 2065 static struct {
2066 const char *name; 2066 const char *name;
2067 size_t len; 2067 size_t len;
2068 } vals[] = { 2068 } vals[] = {
2069#define MKV(A) { A, sizeof(A) - 1 } 2069#define MKV(A) { A, sizeof(A) - 1 }
2070 MKV("${MAKE}"), 2070 MKV("${MAKE}"),
2071 MKV("${.MAKE}"), 2071 MKV("${.MAKE}"),
2072 MKV("$(MAKE)"), 2072 MKV("$(MAKE)"),
2073 MKV("$(.MAKE)"), 2073 MKV("$(.MAKE)"),
2074 MKV("make"), 2074 MKV("make"),
2075 }; 2075 };
2076 for (i = 0; i < sizeof vals / sizeof vals[0]; i++) { 2076 for (i = 0; i < sizeof vals / sizeof vals[0]; i++) {
2077 char *ptr; 2077 char *ptr;
2078 if ((ptr = strstr(cmd, vals[i].name)) == NULL) 2078 if ((ptr = strstr(cmd, vals[i].name)) == NULL)
2079 continue; 2079 continue;
2080 if ((ptr == cmd || !ch_isalnum(ptr[-1])) 2080 if ((ptr == cmd || !ch_isalnum(ptr[-1]))
2081 && !ch_isalnum(ptr[vals[i].len])) 2081 && !ch_isalnum(ptr[vals[i].len]))
2082 return TRUE; 2082 return TRUE;
2083 } 2083 }
2084 return FALSE; 2084 return FALSE;
2085} 2085}
2086 2086
2087/* Append the command to the target node. 2087/* Append the command to the target node.
2088 * 2088 *
2089 * The node may be marked as a submake node if the command is determined to 2089 * The node may be marked as a submake node if the command is determined to
2090 * be that. */ 2090 * be that. */
2091static void 2091static void
2092ParseAddCmd(GNode *gn, char *cmd) 2092ParseAddCmd(GNode *gn, char *cmd)
2093{ 2093{
2094 /* Add to last (ie current) cohort for :: targets */ 2094 /* Add to last (ie current) cohort for :: targets */
2095 if ((gn->type & OP_DOUBLEDEP) && gn->cohorts->last != NULL) 2095 if ((gn->type & OP_DOUBLEDEP) && gn->cohorts->last != NULL)
2096 gn = gn->cohorts->last->datum; 2096 gn = gn->cohorts->last->datum;
2097 2097
2098 /* if target already supplied, ignore commands */ 2098 /* if target already supplied, ignore commands */
2099 if (!(gn->type & OP_HAS_COMMANDS)) { 2099 if (!(gn->type & OP_HAS_COMMANDS)) {
2100 Lst_Append(gn->commands, cmd); 2100 Lst_Append(gn->commands, cmd);
2101 if (ParseMaybeSubMake(cmd)) 2101 if (ParseMaybeSubMake(cmd))
2102 gn->type |= OP_SUBMAKE; 2102 gn->type |= OP_SUBMAKE;
2103 ParseMark(gn); 2103 ParseMark(gn);
2104 } else { 2104 } else {
2105#if 0 2105#if 0
2106 /* XXX: We cannot do this until we fix the tree */ 2106 /* XXX: We cannot do this until we fix the tree */
2107 Lst_Append(gn->commands, cmd); 2107 Lst_Append(gn->commands, cmd);
2108 Parse_Error(PARSE_WARNING, 2108 Parse_Error(PARSE_WARNING,
2109 "overriding commands for target \"%s\"; " 2109 "overriding commands for target \"%s\"; "
2110 "previous commands defined at %s: %d ignored", 2110 "previous commands defined at %s: %d ignored",
2111 gn->name, gn->fname, gn->lineno); 2111 gn->name, gn->fname, gn->lineno);
2112#else 2112#else
2113 Parse_Error(PARSE_WARNING, 2113 Parse_Error(PARSE_WARNING,
2114 "duplicate script for target \"%s\" ignored", 2114 "duplicate script for target \"%s\" ignored",
2115 gn->name); 2115 gn->name);
2116 ParseErrorInternal(gn->fname, (size_t)gn->lineno, PARSE_WARNING, 2116 ParseErrorInternal(gn->fname, (size_t)gn->lineno, PARSE_WARNING,
2117 "using previous script for \"%s\" defined here", 2117 "using previous script for \"%s\" defined here",
2118 gn->name); 2118 gn->name);
2119#endif 2119#endif
2120 } 2120 }
2121} 2121}
2122 2122
2123/* Add a directory to the path searched for included makefiles bracketed 2123/* Add a directory to the path searched for included makefiles bracketed
2124 * by double-quotes. */ 2124 * by double-quotes. */
2125void 2125void
2126Parse_AddIncludeDir(const char *dir) 2126Parse_AddIncludeDir(const char *dir)
2127{ 2127{
2128 (void)Dir_AddDir(parseIncPath, dir); 2128 (void)Dir_AddDir(parseIncPath, dir);
2129} 2129}
2130 2130
2131/* Push to another file. 2131/* Push to another file.
2132 * 2132 *
2133 * The input is the line minus the '.'. A file spec is a string enclosed in 2133 * The input is the line minus the '.'. A file spec is a string enclosed in
2134 * <> or "". The <> file is looked for only in sysIncPath. The "" file is 2134 * <> or "". The <> file is looked for only in sysIncPath. The "" file is
2135 * first searched in the parsedir and then in the directories specified by 2135 * first searched in the parsedir and then in the directories specified by
2136 * the -I command line options. 2136 * the -I command line options.
2137 */ 2137 */
2138static void 2138static void
2139Parse_include_file(char *file, Boolean isSystem, Boolean depinc, int silent) 2139Parse_include_file(char *file, Boolean isSystem, Boolean depinc, int silent)
2140{ 2140{
2141 struct loadedfile *lf; 2141 struct loadedfile *lf;
2142 char *fullname; /* full pathname of file */ 2142 char *fullname; /* full pathname of file */
2143 char *newName; 2143 char *newName;
2144 char *prefEnd, *incdir; 2144 char *prefEnd, *incdir;
2145 int fd; 2145 int fd;
2146 int i; 2146 int i;
2147 2147
2148 /* 2148 /*
2149 * Now we know the file's name and its search path, we attempt to 2149 * Now we know the file's name and its search path, we attempt to
2150 * find the durn thing. A return of NULL indicates the file don't 2150 * find the durn thing. A return of NULL indicates the file don't
2151 * exist. 2151 * exist.
2152 */ 2152 */
2153 fullname = file[0] == '/' ? bmake_strdup(file) : NULL; 2153 fullname = file[0] == '/' ? bmake_strdup(file) : NULL;
2154 2154
2155 if (fullname == NULL && !isSystem) { 2155 if (fullname == NULL && !isSystem) {
2156 /* 2156 /*
2157 * Include files contained in double-quotes are first searched for 2157 * Include files contained in double-quotes are first searched for
2158 * relative to the including file's location. We don't want to 2158 * relative to the including file's location. We don't want to
2159 * cd there, of course, so we just tack on the old file's 2159 * cd there, of course, so we just tack on the old file's
2160 * leading path components and call Dir_FindFile to see if 2160 * leading path components and call Dir_FindFile to see if
2161 * we can locate the beast. 2161 * we can locate the beast.
2162 */ 2162 */
2163 2163
2164 incdir = bmake_strdup(CurFile()->fname); 2164 incdir = bmake_strdup(CurFile()->fname);
2165 prefEnd = strrchr(incdir, '/'); 2165 prefEnd = strrchr(incdir, '/');
2166 if (prefEnd != NULL) { 2166 if (prefEnd != NULL) {
2167 *prefEnd = '\0'; 2167 *prefEnd = '\0';
2168 /* Now do lexical processing of leading "../" on the filename */ 2168 /* Now do lexical processing of leading "../" on the filename */
2169 for (i = 0; strncmp(file + i, "../", 3) == 0; i += 3) { 2169 for (i = 0; strncmp(file + i, "../", 3) == 0; i += 3) {
2170 prefEnd = strrchr(incdir + 1, '/'); 2170 prefEnd = strrchr(incdir + 1, '/');
2171 if (prefEnd == NULL || strcmp(prefEnd, "/..") == 0) 2171 if (prefEnd == NULL || strcmp(prefEnd, "/..") == 0)
2172 break; 2172 break;
2173 *prefEnd = '\0'; 2173 *prefEnd = '\0';
2174 } 2174 }
2175 newName = str_concat3(incdir, "/", file + i); 2175 newName = str_concat3(incdir, "/", file + i);
2176 fullname = Dir_FindFile(newName, parseIncPath); 2176 fullname = Dir_FindFile(newName, parseIncPath);
2177 if (fullname == NULL) 2177 if (fullname == NULL)
2178 fullname = Dir_FindFile(newName, dirSearchPath); 2178 fullname = Dir_FindFile(newName, dirSearchPath);
2179 free(newName); 2179 free(newName);
2180 } 2180 }
2181 free(incdir); 2181 free(incdir);
2182 2182
2183 if (fullname == NULL) { 2183 if (fullname == NULL) {
2184 /* 2184 /*
2185 * Makefile wasn't found in same directory as included makefile. 2185 * Makefile wasn't found in same directory as included makefile.
2186 * Search for it first on the -I search path, 2186 * Search for it first on the -I search path,
2187 * then on the .PATH search path, if not found in a -I directory. 2187 * then on the .PATH search path, if not found in a -I directory.
2188 * If we have a suffix specific path we should use that. 2188 * If we have a suffix specific path we should use that.
2189 */ 2189 */
2190 char *suff; 2190 char *suff;
2191 SearchPath *suffPath = NULL; 2191 SearchPath *suffPath = NULL;
2192 2192
2193 if ((suff = strrchr(file, '.'))) { 2193 if ((suff = strrchr(file, '.'))) {
2194 suffPath = Suff_GetPath(suff); 2194 suffPath = Suff_GetPath(suff);
2195 if (suffPath != NULL) { 2195 if (suffPath != NULL) {
2196 fullname = Dir_FindFile(file, suffPath); 2196 fullname = Dir_FindFile(file, suffPath);
2197 } 2197 }
2198 } 2198 }
2199 if (fullname == NULL) { 2199 if (fullname == NULL) {
2200 fullname = Dir_FindFile(file, parseIncPath); 2200 fullname = Dir_FindFile(file, parseIncPath);
2201 if (fullname == NULL) { 2201 if (fullname == NULL) {
2202 fullname = Dir_FindFile(file, dirSearchPath); 2202 fullname = Dir_FindFile(file, dirSearchPath);
2203 } 2203 }
2204 } 2204 }
2205 } 2205 }
2206 } 2206 }
2207 2207
2208 /* Looking for a system file or file still not found */ 2208 /* Looking for a system file or file still not found */
2209 if (fullname == NULL) { 2209 if (fullname == NULL) {
2210 /* 2210 /*
2211 * Look for it on the system path 2211 * Look for it on the system path
2212 */ 2212 */
2213 SearchPath *path = Lst_IsEmpty(sysIncPath) ? defSysIncPath : sysIncPath; 2213 SearchPath *path = Lst_IsEmpty(sysIncPath) ? defSysIncPath : sysIncPath;
2214 fullname = Dir_FindFile(file, path); 2214 fullname = Dir_FindFile(file, path);
2215 } 2215 }
2216 2216
2217 if (fullname == NULL) { 2217 if (fullname == NULL) {
2218 if (!silent) 2218 if (!silent)
2219 Parse_Error(PARSE_FATAL, "Could not find %s", file); 2219 Parse_Error(PARSE_FATAL, "Could not find %s", file);
2220 return; 2220 return;
2221 } 2221 }
2222 2222
2223 /* Actually open the file... */ 2223 /* Actually open the file... */
2224 fd = open(fullname, O_RDONLY); 2224 fd = open(fullname, O_RDONLY);
2225 if (fd == -1) { 2225 if (fd == -1) {
2226 if (!silent) 2226 if (!silent)
2227 Parse_Error(PARSE_FATAL, "Cannot open %s", fullname); 2227 Parse_Error(PARSE_FATAL, "Cannot open %s", fullname);
2228 free(fullname); 2228 free(fullname);
2229 return; 2229 return;
2230 } 2230 }
2231 2231
2232 /* load it */ 2232 /* load it */
2233 lf = loadfile(fullname, fd); 2233 lf = loadfile(fullname, fd);
2234 2234
2235 /* Start reading from this file next */ 2235 /* Start reading from this file next */
2236 Parse_SetInput(fullname, 0, -1, loadedfile_nextbuf, lf); 2236 Parse_SetInput(fullname, 0, -1, loadedfile_nextbuf, lf);
2237 CurFile()->lf = lf; 2237 CurFile()->lf = lf;
2238 if (depinc) 2238 if (depinc)
2239 doing_depend = depinc; /* only turn it on */ 2239 doing_depend = depinc; /* only turn it on */
2240} 2240}
2241 2241
2242static void 2242static void
2243ParseDoInclude(char *line) 2243ParseDoInclude(char *line)
2244{ 2244{
2245 char endc; /* the character which ends the file spec */ 2245 char endc; /* the character which ends the file spec */
2246 char *cp; /* current position in file spec */ 2246 char *cp; /* current position in file spec */
2247 int silent = *line != 'i'; 2247 int silent = *line != 'i';
2248 char *file = line + (silent ? 8 : 7); 2248 char *file = line + (silent ? 8 : 7);
2249 2249
2250 /* Skip to delimiter character so we know where to look */ 2250 /* Skip to delimiter character so we know where to look */
2251 while (*file == ' ' || *file == '\t') 2251 while (*file == ' ' || *file == '\t')
2252 file++; 2252 file++;
2253 2253
2254 if (*file != '"' && *file != '<') { 2254 if (*file != '"' && *file != '<') {
2255 Parse_Error(PARSE_FATAL, 2255 Parse_Error(PARSE_FATAL,
2256 ".include filename must be delimited by '\"' or '<'"); 2256 ".include filename must be delimited by '\"' or '<'");
2257 return; 2257 return;
2258 } 2258 }
2259 2259
2260 /* 2260 /*
2261 * Set the search path on which to find the include file based on the 2261 * Set the search path on which to find the include file based on the
2262 * characters which bracket its name. Angle-brackets imply it's 2262 * characters which bracket its name. Angle-brackets imply it's
2263 * a system Makefile while double-quotes imply it's a user makefile 2263 * a system Makefile while double-quotes imply it's a user makefile
2264 */ 2264 */
2265 if (*file == '<') { 2265 if (*file == '<') {
2266 endc = '>'; 2266 endc = '>';
2267 } else { 2267 } else {
2268 endc = '"'; 2268 endc = '"';
2269 } 2269 }
2270 2270
2271 /* Skip to matching delimiter */ 2271 /* Skip to matching delimiter */
2272 for (cp = ++file; *cp && *cp != endc; cp++) 2272 for (cp = ++file; *cp && *cp != endc; cp++)
2273 continue; 2273 continue;
2274 2274
2275 if (*cp != endc) { 2275 if (*cp != endc) {
2276 Parse_Error(PARSE_FATAL, 2276 Parse_Error(PARSE_FATAL,
2277 "Unclosed %cinclude filename. '%c' expected", 2277 "Unclosed %cinclude filename. '%c' expected",
2278 '.', endc); 2278 '.', endc);
2279 return; 2279 return;
2280 } 2280 }
2281 *cp = '\0'; 2281 *cp = '\0';
2282 2282
2283 /* 2283 /*
2284 * Substitute for any variables in the file name before trying to 2284 * Substitute for any variables in the file name before trying to
2285 * find the thing. 2285 * find the thing.
2286 */ 2286 */
2287 (void)Var_Subst(file, VAR_CMDLINE, VARE_WANTRES, &file); 2287 (void)Var_Subst(file, VAR_CMDLINE, VARE_WANTRES, &file);
2288 /* TODO: handle errors */ 2288 /* TODO: handle errors */
2289 2289
2290 Parse_include_file(file, endc == '>', *line == 'd', silent); 2290 Parse_include_file(file, endc == '>', *line == 'd', silent);
2291 free(file); 2291 free(file);
2292} 2292}
2293 2293
2294/* Split filename into dirname + basename, then assign these to the 2294/* Split filename into dirname + basename, then assign these to the
2295 * given variables. */ 2295 * given variables. */
2296static void 2296static void
2297SetFilenameVars(const char *filename, const char *dirvar, const char *filevar) 2297SetFilenameVars(const char *filename, const char *dirvar, const char *filevar)
2298{ 2298{
2299 const char *slash, *dirname, *basename; 2299 const char *slash, *dirname, *basename;
2300 void *freeIt; 2300 void *freeIt;
2301 2301
2302 slash = strrchr(filename, '/'); 2302 slash = strrchr(filename, '/');
2303 if (slash == NULL) { 2303 if (slash == NULL) {
2304 dirname = curdir; 2304 dirname = curdir;
2305 basename = filename; 2305 basename = filename;
2306 freeIt = NULL; 2306 freeIt = NULL;
2307 } else { 2307 } else {
2308 dirname = freeIt = bmake_strsedup(filename, slash); 2308 dirname = freeIt = bmake_strsedup(filename, slash);
2309 basename = slash + 1; 2309 basename = slash + 1;
2310 } 2310 }
2311 2311
2312 Var_Set(dirvar, dirname, VAR_GLOBAL); 2312 Var_Set(dirvar, dirname, VAR_GLOBAL);
2313 Var_Set(filevar, basename, VAR_GLOBAL); 2313 Var_Set(filevar, basename, VAR_GLOBAL);
2314 2314
2315 DEBUG5(PARSE, "%s: ${%s} = `%s' ${%s} = `%s'\n", 2315 DEBUG5(PARSE, "%s: ${%s} = `%s' ${%s} = `%s'\n",
2316 __func__, dirvar, dirname, filevar, basename); 2316 __func__, dirvar, dirname, filevar, basename);
2317 free(freeIt); 2317 free(freeIt);
2318} 2318}
2319 2319
2320/* Return the immediately including file. 2320/* Return the immediately including file.
2321 * 2321 *
2322 * This is made complicated since the .for loop is implemented as a special 2322 * This is made complicated since the .for loop is implemented as a special
2323 * kind of .include; see For_Run. */ 2323 * kind of .include; see For_Run. */
2324static const char * 2324static const char *
2325GetActuallyIncludingFile(void) 2325GetActuallyIncludingFile(void)
2326{ 2326{
2327 size_t i; 2327 size_t i;
2328 const IFile *incs = GetInclude(0); 2328 const IFile *incs = GetInclude(0);
2329 2329
2330 for (i = includes.len; i >= 2; i--) 2330 for (i = includes.len; i >= 2; i--)
2331 if (!incs[i - 1].fromForLoop) 2331 if (!incs[i - 1].fromForLoop)
2332 return incs[i - 2].fname; 2332 return incs[i - 2].fname;
2333 return NULL; 2333 return NULL;
2334} 2334}
2335 2335
2336/* Set .PARSEDIR, .PARSEFILE, .INCLUDEDFROMDIR and .INCLUDEDFROMFILE. */ 2336/* Set .PARSEDIR, .PARSEFILE, .INCLUDEDFROMDIR and .INCLUDEDFROMFILE. */
2337static void 2337static void
2338ParseSetParseFile(const char *filename) 2338ParseSetParseFile(const char *filename)
2339{ 2339{
2340 const char *including; 2340 const char *including;
2341 2341
2342 SetFilenameVars(filename, ".PARSEDIR", ".PARSEFILE"); 2342 SetFilenameVars(filename, ".PARSEDIR", ".PARSEFILE");
2343 2343
2344 including = GetActuallyIncludingFile(); 2344 including = GetActuallyIncludingFile();
2345 if (including != NULL) { 2345 if (including != NULL) {
2346 SetFilenameVars(including, 2346 SetFilenameVars(including,
2347 ".INCLUDEDFROMDIR", ".INCLUDEDFROMFILE"); 2347 ".INCLUDEDFROMDIR", ".INCLUDEDFROMFILE");
2348 } else { 2348 } else {
2349 Var_Delete(".INCLUDEDFROMDIR", VAR_GLOBAL); 2349 Var_Delete(".INCLUDEDFROMDIR", VAR_GLOBAL);
2350 Var_Delete(".INCLUDEDFROMFILE", VAR_GLOBAL); 2350 Var_Delete(".INCLUDEDFROMFILE", VAR_GLOBAL);
2351 } 2351 }
2352} 2352}
2353 2353
2354static Boolean 2354static Boolean
2355StrContainsWord(const char *str, const char *word) 2355StrContainsWord(const char *str, const char *word)
2356{ 2356{
2357 const char *val = str; 2357 size_t strLen = strlen(str);
2358 size_t valLen = strlen(val); 
2359 size_t wordLen = strlen(word); 2358 size_t wordLen = strlen(word);
2360 const char *end; 2359 const char *p, *end;
2361 2360
2362 if (valLen < wordLen) 2361 if (strLen < wordLen)
2363 return FALSE; /* str is too short to contain word */ 2362 return FALSE; /* str is too short to contain word */
2364 2363
2365 end = val + valLen - wordLen; 2364 end = str + strLen - wordLen;
2366 for (; val != NULL; val = strchr(val, ' ')) { 2365 for (p = str; p != NULL; p = strchr(p, ' ')) {
2367 if (*val == ' ') 2366 if (*p == ' ')
2368 val++; 2367 p++;
2369 if (val > end) 2368 if (p > end)
2370 return FALSE; /* cannot contain word */ 2369 return FALSE; /* cannot contain word */
2371 2370
2372 if (memcmp(val, word, wordLen) == 0 && 2371 if (memcmp(p, word, wordLen) == 0 &&
2373 (val[wordLen] == '\0' || val[wordLen] == ' ')) 2372 (p[wordLen] == '\0' || p[wordLen] == ' '))
2374 return TRUE; 2373 return TRUE;
2375 } 2374 }
2376 return FALSE; 2375 return FALSE;
2377} 2376}
2378 2377
2379/* XXX: Searching through a set of words with this linear search is 2378/* XXX: Searching through a set of words with this linear search is
2380 * inefficient for variables that contain thousands of words. */ 2379 * inefficient for variables that contain thousands of words. */
2381static Boolean 2380static Boolean
2382VarContainsWord(const char *varname, const char *word) 2381VarContainsWord(const char *varname, const char *word)
2383{ 2382{
2384 void *val_freeIt; 2383 void *val_freeIt;
2385 const char *val = Var_Value(varname, VAR_GLOBAL, &val_freeIt); 2384 const char *val = Var_Value(varname, VAR_GLOBAL, &val_freeIt);
2386 Boolean found = val != NULL && StrContainsWord(val, word); 2385 Boolean found = val != NULL && StrContainsWord(val, word);
2387 bmake_free(val_freeIt); 2386 bmake_free(val_freeIt);
2388 return found; 2387 return found;
2389} 2388}
2390 2389
2391/* Track the makefiles we read - so makefiles can set dependencies on them. 2390/* Track the makefiles we read - so makefiles can set dependencies on them.
2392 * Avoid adding anything more than once. */ 2391 * Avoid adding anything more than once. */
2393static void 2392static void
2394ParseTrackInput(const char *name) 2393ParseTrackInput(const char *name)
2395{ 2394{
2396 if (!VarContainsWord(MAKE_MAKEFILES, name)) 2395 if (!VarContainsWord(MAKE_MAKEFILES, name))
2397 Var_Append(MAKE_MAKEFILES, name, VAR_GLOBAL); 2396 Var_Append(MAKE_MAKEFILES, name, VAR_GLOBAL);
2398} 2397}
2399 2398
2400 2399
2401/* Start Parsing from the given source. 2400/* Start Parsing from the given source.
2402 * 2401 *
2403 * The given file is added to the includes stack. */ 2402 * The given file is added to the includes stack. */
2404void 2403void
2405Parse_SetInput(const char *name, int line, int fd, 2404Parse_SetInput(const char *name, int line, int fd,
2406 char *(*nextbuf)(void *, size_t *), void *arg) 2405 char *(*nextbuf)(void *, size_t *), void *arg)
2407{ 2406{
2408 IFile *curFile; 2407 IFile *curFile;
2409 char *buf; 2408 char *buf;
2410 size_t len; 2409 size_t len;
2411 Boolean fromForLoop = name == NULL; 2410 Boolean fromForLoop = name == NULL;
2412 2411
2413 if (fromForLoop) 2412 if (fromForLoop)
2414 name = CurFile()->fname; 2413 name = CurFile()->fname;
2415 else 2414 else
2416 ParseTrackInput(name); 2415 ParseTrackInput(name);
2417 2416
2418 if (DEBUG(PARSE)) 2417 if (DEBUG(PARSE))
2419 debug_printf("%s: file %s, line %d, fd %d, nextbuf %s, arg %p\n", 2418 debug_printf("%s: file %s, line %d, fd %d, nextbuf %s, arg %p\n",
2420 __func__, name, line, fd, 2419 __func__, name, line, fd,
2421 nextbuf == loadedfile_nextbuf ? "loadedfile" : "other", 2420 nextbuf == loadedfile_nextbuf ? "loadedfile" : "other",
2422 arg); 2421 arg);
2423 2422
2424 if (fd == -1 && nextbuf == NULL) 2423 if (fd == -1 && nextbuf == NULL)
2425 /* sanity */ 2424 /* sanity */
2426 return; 2425 return;
2427 2426
2428 curFile = Vector_Push(&includes); 2427 curFile = Vector_Push(&includes);
2429 2428
2430 /* 2429 /*
2431 * Once the previous state has been saved, we can get down to reading 2430 * Once the previous state has been saved, we can get down to reading
2432 * the new file. We set up the name of the file to be the absolute 2431 * the new file. We set up the name of the file to be the absolute
2433 * name of the include file so error messages refer to the right 2432 * name of the include file so error messages refer to the right
2434 * place. 2433 * place.
2435 */ 2434 */
2436 curFile->fname = bmake_strdup(name); 2435 curFile->fname = bmake_strdup(name);
2437 curFile->fromForLoop = fromForLoop; 2436 curFile->fromForLoop = fromForLoop;
2438 curFile->lineno = line; 2437 curFile->lineno = line;
2439 curFile->first_lineno = line; 2438 curFile->first_lineno = line;
2440 curFile->nextbuf = nextbuf; 2439 curFile->nextbuf = nextbuf;
2441 curFile->nextbuf_arg = arg; 2440 curFile->nextbuf_arg = arg;
2442 curFile->lf = NULL; 2441 curFile->lf = NULL;
2443 curFile->depending = doing_depend; /* restore this on EOF */ 2442 curFile->depending = doing_depend; /* restore this on EOF */
2444 2443
2445 assert(nextbuf != NULL); 2444 assert(nextbuf != NULL);
2446 2445
2447 /* Get first block of input data */ 2446 /* Get first block of input data */
2448 buf = curFile->nextbuf(curFile->nextbuf_arg, &len); 2447 buf = curFile->nextbuf(curFile->nextbuf_arg, &len);
2449 if (buf == NULL) { 2448 if (buf == NULL) {
2450 /* Was all a waste of time ... */ 2449 /* Was all a waste of time ... */
2451 if (curFile->fname) 2450 if (curFile->fname)
2452 free(curFile->fname); 2451 free(curFile->fname);
2453 free(curFile); 2452 free(curFile);
2454 return; 2453 return;
2455 } 2454 }
2456 curFile->buf_freeIt = buf; 2455 curFile->buf_freeIt = buf;
2457 curFile->buf_ptr = buf; 2456 curFile->buf_ptr = buf;
2458 curFile->buf_end = buf + len; 2457 curFile->buf_end = buf + len;
2459 2458
2460 curFile->cond_depth = Cond_save_depth(); 2459 curFile->cond_depth = Cond_save_depth();
2461 ParseSetParseFile(name); 2460 ParseSetParseFile(name);
2462} 2461}
2463 2462
2464/* Check if the directive is an include directive. */ 2463/* Check if the directive is an include directive. */
2465static Boolean 2464static Boolean
2466IsInclude(const char *dir, Boolean sysv) 2465IsInclude(const char *dir, Boolean sysv)
2467{ 2466{
2468 if (dir[0] == 's' || dir[0] == '-' || (dir[0] == 'd' && !sysv)) 2467 if (dir[0] == 's' || dir[0] == '-' || (dir[0] == 'd' && !sysv))
2469 dir++; 2468 dir++;
2470 2469
2471 if (strncmp(dir, "include", 7) != 0) 2470 if (strncmp(dir, "include", 7) != 0)
2472 return FALSE; 2471 return FALSE;
2473 2472
2474 /* Space is not mandatory for BSD .include */ 2473 /* Space is not mandatory for BSD .include */
2475 return !sysv || ch_isspace(dir[7]); 2474 return !sysv || ch_isspace(dir[7]);
2476} 2475}
2477 2476
2478 2477
2479#ifdef SYSVINCLUDE 2478#ifdef SYSVINCLUDE
2480/* Check if the line is a SYSV include directive. */ 2479/* Check if the line is a SYSV include directive. */
2481static Boolean 2480static Boolean
2482IsSysVInclude(const char *line) 2481IsSysVInclude(const char *line)
2483{ 2482{
2484 const char *p; 2483 const char *p;
2485 2484
2486 if (!IsInclude(line, TRUE)) 2485 if (!IsInclude(line, TRUE))
2487 return FALSE; 2486 return FALSE;
2488 2487
2489 /* Avoid interpreting a dependency line as an include */ 2488 /* Avoid interpreting a dependency line as an include */
2490 for (p = line; (p = strchr(p, ':')) != NULL;) { 2489 for (p = line; (p = strchr(p, ':')) != NULL;) {
2491 if (*++p == '\0') { 2490 if (*++p == '\0') {
2492 /* end of line -> dependency */ 2491 /* end of line -> dependency */
2493 return FALSE; 2492 return FALSE;
2494 } 2493 }
2495 if (*p == ':' || ch_isspace(*p)) { 2494 if (*p == ':' || ch_isspace(*p)) {
2496 /* :: operator or ': ' -> dependency */ 2495 /* :: operator or ': ' -> dependency */
2497 return FALSE; 2496 return FALSE;
2498 } 2497 }
2499 } 2498 }
2500 return TRUE; 2499 return TRUE;
2501} 2500}
2502 2501
2503/* Push to another file. The line points to the word "include". */ 2502/* Push to another file. The line points to the word "include". */
2504static void 2503static void
2505ParseTraditionalInclude(char *line) 2504ParseTraditionalInclude(char *line)
2506{ 2505{
2507 char *cp; /* current position in file spec */ 2506 char *cp; /* current position in file spec */
2508 int done = 0; 2507 int done = 0;
2509 int silent = line[0] != 'i'; 2508 int silent = line[0] != 'i';
2510 char *file = line + (silent ? 8 : 7); 2509 char *file = line + (silent ? 8 : 7);
2511 char *all_files; 2510 char *all_files;
2512 2511
2513 DEBUG2(PARSE, "%s: %s\n", __func__, file); 2512 DEBUG2(PARSE, "%s: %s\n", __func__, file);
2514 2513
2515 pp_skip_whitespace(&file); 2514 pp_skip_whitespace(&file);
2516 2515
2517 /* 2516 /*
2518 * Substitute for any variables in the file name before trying to 2517 * Substitute for any variables in the file name before trying to
2519 * find the thing. 2518 * find the thing.
2520 */ 2519 */
2521 (void)Var_Subst(file, VAR_CMDLINE, VARE_WANTRES, &all_files); 2520 (void)Var_Subst(file, VAR_CMDLINE, VARE_WANTRES, &all_files);
2522 /* TODO: handle errors */ 2521 /* TODO: handle errors */
2523 2522
2524 if (*file == '\0') { 2523 if (*file == '\0') {
2525 Parse_Error(PARSE_FATAL, "Filename missing from \"include\""); 2524 Parse_Error(PARSE_FATAL, "Filename missing from \"include\"");
2526 goto out; 2525 goto out;
2527 } 2526 }
2528 2527
2529 for (file = all_files; !done; file = cp + 1) { 2528 for (file = all_files; !done; file = cp + 1) {
2530 /* Skip to end of line or next whitespace */ 2529 /* Skip to end of line or next whitespace */
2531 for (cp = file; *cp && !ch_isspace(*cp); cp++) 2530 for (cp = file; *cp && !ch_isspace(*cp); cp++)
2532 continue; 2531 continue;
2533 2532
2534 if (*cp) 2533 if (*cp)
2535 *cp = '\0'; 2534 *cp = '\0';
2536 else 2535 else
2537 done = 1; 2536 done = 1;
2538 2537
2539 Parse_include_file(file, FALSE, FALSE, silent); 2538 Parse_include_file(file, FALSE, FALSE, silent);
2540 } 2539 }
2541out: 2540out:
2542 free(all_files); 2541 free(all_files);
2543} 2542}
2544#endif 2543#endif
2545 2544
2546#ifdef GMAKEEXPORT 2545#ifdef GMAKEEXPORT
2547/* Parse "export <variable>=<value>", and actually export it. */ 2546/* Parse "export <variable>=<value>", and actually export it. */
2548static void 2547static void
2549ParseGmakeExport(char *line) 2548ParseGmakeExport(char *line)
2550{ 2549{
2551 char *variable = line + 6; 2550 char *variable = line + 6;
2552 char *value; 2551 char *value;
2553 2552
2554 DEBUG2(PARSE, "%s: %s\n", __func__, variable); 2553 DEBUG2(PARSE, "%s: %s\n", __func__, variable);
2555 2554
2556 pp_skip_whitespace(&variable); 2555 pp_skip_whitespace(&variable);
2557 2556
2558 for (value = variable; *value && *value != '='; value++) 2557 for (value = variable; *value && *value != '='; value++)
2559 continue; 2558 continue;
2560 2559
2561 if (*value != '=') { 2560 if (*value != '=') {
2562 Parse_Error(PARSE_FATAL, 2561 Parse_Error(PARSE_FATAL,
2563 "Variable/Value missing from \"export\""); 2562 "Variable/Value missing from \"export\"");
2564 return; 2563 return;
2565 } 2564 }
2566 *value++ = '\0'; /* terminate variable */ 2565 *value++ = '\0'; /* terminate variable */
2567 2566
2568 /* 2567 /*
2569 * Expand the value before putting it in the environment. 2568 * Expand the value before putting it in the environment.
2570 */ 2569 */
2571 (void)Var_Subst(value, VAR_CMDLINE, VARE_WANTRES, &value); 2570 (void)Var_Subst(value, VAR_CMDLINE, VARE_WANTRES, &value);
2572 /* TODO: handle errors */ 2571 /* TODO: handle errors */
2573 2572
2574 setenv(variable, value, 1); 2573 setenv(variable, value, 1);
2575 free(value); 2574 free(value);
2576} 2575}
2577#endif 2576#endif
2578 2577
2579/* Called when EOF is reached in the current file. If we were reading an 2578/* Called when EOF is reached in the current file. If we were reading an
2580 * include file, the includes stack is popped and things set up to go back 2579 * include file, the includes stack is popped and things set up to go back
2581 * to reading the previous file at the previous location. 2580 * to reading the previous file at the previous location.
2582 * 2581 *
2583 * Results: 2582 * Results:
2584 * TRUE to continue parsing, i.e. it had only reached the end of an 2583 * TRUE to continue parsing, i.e. it had only reached the end of an
2585 * included file, FALSE if the main file has been parsed completely. 2584 * included file, FALSE if the main file has been parsed completely.
2586 */ 2585 */
2587static Boolean 2586static Boolean
2588ParseEOF(void) 2587ParseEOF(void)
2589{ 2588{
2590 char *ptr; 2589 char *ptr;
2591 size_t len; 2590 size_t len;
2592 IFile *curFile = CurFile(); 2591 IFile *curFile = CurFile();
2593 2592
2594 assert(curFile->nextbuf != NULL); 2593 assert(curFile->nextbuf != NULL);
2595 2594
2596 doing_depend = curFile->depending; /* restore this */ 2595 doing_depend = curFile->depending; /* restore this */
2597 /* get next input buffer, if any */ 2596 /* get next input buffer, if any */
2598 ptr = curFile->nextbuf(curFile->nextbuf_arg, &len); 2597 ptr = curFile->nextbuf(curFile->nextbuf_arg, &len);
2599 curFile->buf_ptr = ptr; 2598 curFile->buf_ptr = ptr;
2600 curFile->buf_freeIt = ptr; 2599 curFile->buf_freeIt = ptr;
2601 curFile->buf_end = ptr + len; 2600 curFile->buf_end = ptr + len;
2602 curFile->lineno = curFile->first_lineno; 2601 curFile->lineno = curFile->first_lineno;
2603 if (ptr != NULL) { 2602 if (ptr != NULL) {
2604 /* Iterate again */ 2603 /* Iterate again */
2605 return TRUE; 2604 return TRUE;
2606 } 2605 }
2607 2606
2608 /* Ensure the makefile (or loop) didn't have mismatched conditionals */ 2607 /* Ensure the makefile (or loop) didn't have mismatched conditionals */
2609 Cond_restore_depth(curFile->cond_depth); 2608 Cond_restore_depth(curFile->cond_depth);
2610 2609
2611 if (curFile->lf != NULL) { 2610 if (curFile->lf != NULL) {
2612 loadedfile_destroy(curFile->lf); 2611 loadedfile_destroy(curFile->lf);
2613 curFile->lf = NULL; 2612 curFile->lf = NULL;
2614 } 2613 }
2615 2614
2616 /* Dispose of curFile info */ 2615 /* Dispose of curFile info */
2617 /* Leak curFile->fname because all the gnodes have pointers to it */ 2616 /* Leak curFile->fname because all the gnodes have pointers to it */
2618 free(curFile->buf_freeIt); 2617 free(curFile->buf_freeIt);
2619 Vector_Pop(&includes); 2618 Vector_Pop(&includes);
2620 2619
2621 if (includes.len == 0) { 2620 if (includes.len == 0) {
2622 /* We've run out of input */ 2621 /* We've run out of input */
2623 Var_Delete(".PARSEDIR", VAR_GLOBAL); 2622 Var_Delete(".PARSEDIR", VAR_GLOBAL);
2624 Var_Delete(".PARSEFILE", VAR_GLOBAL); 2623 Var_Delete(".PARSEFILE", VAR_GLOBAL);
2625 Var_Delete(".INCLUDEDFROMDIR", VAR_GLOBAL); 2624 Var_Delete(".INCLUDEDFROMDIR", VAR_GLOBAL);
2626 Var_Delete(".INCLUDEDFROMFILE", VAR_GLOBAL); 2625 Var_Delete(".INCLUDEDFROMFILE", VAR_GLOBAL);
2627 return FALSE; 2626 return FALSE;
2628 } 2627 }
2629 2628
2630 curFile = CurFile(); 2629 curFile = CurFile();
2631 DEBUG2(PARSE, "ParseEOF: returning to file %s, line %d\n", 2630 DEBUG2(PARSE, "ParseEOF: returning to file %s, line %d\n",
2632 curFile->fname, curFile->lineno); 2631 curFile->fname, curFile->lineno);
2633 2632
2634 ParseSetParseFile(curFile->fname); 2633 ParseSetParseFile(curFile->fname);
2635 return TRUE; 2634 return TRUE;
2636} 2635}
2637 2636
2638#define PARSE_RAW 1 2637#define PARSE_RAW 1
2639#define PARSE_SKIP 2 2638#define PARSE_SKIP 2
2640 2639
2641static char * 2640static char *
2642ParseGetLine(int flags) 2641ParseGetLine(int flags)
2643{ 2642{
2644 IFile *cf = CurFile(); 2643 IFile *cf = CurFile();
2645 char *ptr; 2644 char *ptr;
2646 char ch; 2645 char ch;
2647 char *line; 2646 char *line;
2648 char *line_end; 2647 char *line_end;
2649 char *escaped; 2648 char *escaped;
2650 char *comment; 2649 char *comment;
2651 char *tp; 2650 char *tp;
2652 2651
2653 /* Loop through blank lines and comment lines */ 2652 /* Loop through blank lines and comment lines */
2654 for (;;) { 2653 for (;;) {
2655 cf->lineno++; 2654 cf->lineno++;
2656 line = cf->buf_ptr; 2655 line = cf->buf_ptr;
2657 ptr = line; 2656 ptr = line;
2658 line_end = line; 2657 line_end = line;
2659 escaped = NULL; 2658 escaped = NULL;
2660 comment = NULL; 2659 comment = NULL;
2661 for (;;) { 2660 for (;;) {
2662 /* XXX: can buf_end ever be null? */ 2661 /* XXX: can buf_end ever be null? */
2663 if (cf->buf_end != NULL && ptr == cf->buf_end) { 2662 if (cf->buf_end != NULL && ptr == cf->buf_end) {
2664 /* end of buffer */ 2663 /* end of buffer */
2665 ch = 0; 2664 ch = 0;
2666 break; 2665 break;
2667 } 2666 }
2668 ch = *ptr; 2667 ch = *ptr;
2669 if (ch == 0 || (ch == '\\' && ptr[1] == 0)) { 2668 if (ch == 0 || (ch == '\\' && ptr[1] == 0)) {
2670 /* XXX: can buf_end ever be null? */ 2669 /* XXX: can buf_end ever be null? */
2671 if (cf->buf_end == NULL) 2670 if (cf->buf_end == NULL)
2672 /* End of string (aka for loop) data */ 2671 /* End of string (aka for loop) data */
2673 break; 2672 break;
2674 /* see if there is more we can parse */ 2673 /* see if there is more we can parse */
2675 while (ptr++ < cf->buf_end) { 2674 while (ptr++ < cf->buf_end) {
2676 if ((ch = *ptr) == '\n') { 2675 if ((ch = *ptr) == '\n') {
2677 if (ptr > line && ptr[-1] == '\\') 2676 if (ptr > line && ptr[-1] == '\\')
2678 continue; 2677 continue;
2679 Parse_Error(PARSE_WARNING, 2678 Parse_Error(PARSE_WARNING,
2680 "Zero byte read from file, " 2679 "Zero byte read from file, "
2681 "skipping rest of line."); 2680 "skipping rest of line.");
2682 break; 2681 break;
2683 } 2682 }
2684 } 2683 }
2685 if (cf->nextbuf != NULL) { 2684 if (cf->nextbuf != NULL) {
2686 /* 2685 /*
2687 * End of this buffer; return EOF and outer logic 2686 * End of this buffer; return EOF and outer logic
2688 * will get the next one. (eww) 2687 * will get the next one. (eww)
2689 */ 2688 */
2690 break; 2689 break;
2691 } 2690 }
2692 Parse_Error(PARSE_FATAL, "Zero byte read from file"); 2691 Parse_Error(PARSE_FATAL, "Zero byte read from file");
2693 return NULL; 2692 return NULL;
2694 } 2693 }
2695 2694
2696 if (ch == '\\') { 2695 if (ch == '\\') {
2697 /* Don't treat next character as special, remember first one */ 2696 /* Don't treat next character as special, remember first one */
2698 if (escaped == NULL) 2697 if (escaped == NULL)
2699 escaped = ptr; 2698 escaped = ptr;
2700 if (ptr[1] == '\n') 2699 if (ptr[1] == '\n')
2701 cf->lineno++; 2700 cf->lineno++;
2702 ptr += 2; 2701 ptr += 2;
2703 line_end = ptr; 2702 line_end = ptr;
2704 continue; 2703 continue;
2705 } 2704 }
2706 if (ch == '#' && comment == NULL) { 2705 if (ch == '#' && comment == NULL) {
2707 /* Remember first '#' for comment stripping */ 2706 /* Remember first '#' for comment stripping */
2708 /* Unless previous char was '[', as in modifier :[#] */ 2707 /* Unless previous char was '[', as in modifier :[#] */
2709 if (!(ptr > line && ptr[-1] == '[')) 2708 if (!(ptr > line && ptr[-1] == '['))
2710 comment = line_end; 2709 comment = line_end;
2711 } 2710 }
2712 ptr++; 2711 ptr++;
2713 if (ch == '\n') 2712 if (ch == '\n')
2714 break; 2713 break;
2715 if (!ch_isspace(ch)) 2714 if (!ch_isspace(ch))
2716 /* We are not interested in trailing whitespace */ 2715 /* We are not interested in trailing whitespace */
2717 line_end = ptr; 2716 line_end = ptr;
2718 } 2717 }
2719 2718
2720 /* Save next 'to be processed' location */ 2719 /* Save next 'to be processed' location */
2721 cf->buf_ptr = ptr; 2720 cf->buf_ptr = ptr;
2722 2721
2723 /* Check we have a non-comment, non-blank line */ 2722 /* Check we have a non-comment, non-blank line */
2724 if (line_end == line || comment == line) { 2723 if (line_end == line || comment == line) {
2725 if (ch == 0) 2724 if (ch == 0)
2726 /* At end of file */ 2725 /* At end of file */
2727 return NULL; 2726 return NULL;
2728 /* Parse another line */ 2727 /* Parse another line */
2729 continue; 2728 continue;
2730 } 2729 }
2731 2730
2732 /* We now have a line of data */ 2731 /* We now have a line of data */
2733 *line_end = 0; 2732 *line_end = 0;
2734 2733
2735 if (flags & PARSE_RAW) { 2734 if (flags & PARSE_RAW) {
2736 /* Leave '\' (etc) in line buffer (eg 'for' lines) */ 2735 /* Leave '\' (etc) in line buffer (eg 'for' lines) */
2737 return line; 2736 return line;
2738 } 2737 }
2739 2738
2740 if (flags & PARSE_SKIP) { 2739 if (flags & PARSE_SKIP) {
2741 /* Completely ignore non-directives */ 2740 /* Completely ignore non-directives */
2742 if (line[0] != '.') 2741 if (line[0] != '.')
2743 continue; 2742 continue;
2744 /* We could do more of the .else/.elif/.endif checks here */ 2743 /* We could do more of the .else/.elif/.endif checks here */
2745 } 2744 }
2746 break; 2745 break;
2747 } 2746 }
2748 2747
2749 /* Brutally ignore anything after a non-escaped '#' in non-commands */ 2748 /* Brutally ignore anything after a non-escaped '#' in non-commands */
2750 if (comment != NULL && line[0] != '\t') { 2749 if (comment != NULL && line[0] != '\t') {
2751 line_end = comment; 2750 line_end = comment;
2752 *line_end = 0; 2751 *line_end = 0;
2753 } 2752 }
2754 2753
2755 /* If we didn't see a '\\' then the in-situ data is fine */ 2754 /* If we didn't see a '\\' then the in-situ data is fine */
2756 if (escaped == NULL) 2755 if (escaped == NULL)
2757 return line; 2756 return line;
2758 2757
2759 /* Remove escapes from '\n' and '#' */ 2758 /* Remove escapes from '\n' and '#' */
2760 tp = ptr = escaped; 2759 tp = ptr = escaped;
2761 escaped = line; 2760 escaped = line;
2762 for (; ; *tp++ = ch) { 2761 for (; ; *tp++ = ch) {
2763 ch = *ptr++; 2762 ch = *ptr++;
2764 if (ch != '\\') { 2763 if (ch != '\\') {
2765 if (ch == 0) 2764 if (ch == 0)
2766 break; 2765 break;
2767 continue; 2766 continue;
2768 } 2767 }
2769 2768
2770 ch = *ptr++; 2769 ch = *ptr++;
2771 if (ch == 0) { 2770 if (ch == 0) {
2772 /* Delete '\\' at end of buffer */ 2771 /* Delete '\\' at end of buffer */
2773 tp--; 2772 tp--;
2774 break; 2773 break;
2775 } 2774 }
2776 2775
2777 if (ch == '#' && line[0] != '\t') 2776 if (ch == '#' && line[0] != '\t')
2778 /* Delete '\\' from before '#' on non-command lines */ 2777 /* Delete '\\' from before '#' on non-command lines */
2779 continue; 2778 continue;
2780 2779
2781 if (ch != '\n') { 2780 if (ch != '\n') {
2782 /* Leave '\\' in buffer for later */ 2781 /* Leave '\\' in buffer for later */
2783 *tp++ = '\\'; 2782 *tp++ = '\\';
2784 /* Make sure we don't delete an escaped ' ' from the line end */ 2783 /* Make sure we don't delete an escaped ' ' from the line end */
2785 escaped = tp + 1; 2784 escaped = tp + 1;
2786 continue; 2785 continue;
2787 } 2786 }
2788 2787
2789 /* Escaped '\n' replace following whitespace with a single ' ' */ 2788 /* Escaped '\n' replace following whitespace with a single ' ' */
2790 while (ptr[0] == ' ' || ptr[0] == '\t') 2789 while (ptr[0] == ' ' || ptr[0] == '\t')
2791 ptr++; 2790 ptr++;
2792 ch = ' '; 2791 ch = ' ';
2793 } 2792 }
2794 2793
2795 /* Delete any trailing spaces - eg from empty continuations */ 2794 /* Delete any trailing spaces - eg from empty continuations */
2796 while (tp > escaped && ch_isspace(tp[-1])) 2795 while (tp > escaped && ch_isspace(tp[-1]))
2797 tp--; 2796 tp--;
2798 2797
2799 *tp = 0; 2798 *tp = 0;
2800 return line; 2799 return line;
2801} 2800}
2802 2801
2803/* Read an entire line from the input file. Called only by Parse_File. 2802/* Read an entire line from the input file. Called only by Parse_File.
2804 * 2803 *
2805 * Results: 2804 * Results:
2806 * A line without its newline. 2805 * A line without its newline.
2807 * 2806 *
2808 * Side Effects: 2807 * Side Effects:
2809 * Only those associated with reading a character 2808 * Only those associated with reading a character
2810 */ 2809 */
2811static char * 2810static char *
2812ParseReadLine(void) 2811ParseReadLine(void)
2813{ 2812{
2814 char *line; /* Result */ 2813 char *line; /* Result */
2815 int lineno; /* Saved line # */ 2814 int lineno; /* Saved line # */
2816 int rval; 2815 int rval;
2817 2816
2818 for (;;) { 2817 for (;;) {
2819 line = ParseGetLine(0); 2818 line = ParseGetLine(0);
2820 if (line == NULL) 2819 if (line == NULL)
2821 return NULL; 2820 return NULL;
2822 2821
2823 if (line[0] != '.') 2822 if (line[0] != '.')
2824 return line; 2823 return line;
2825 2824
2826 /* 2825 /*
2827 * The line might be a conditional. Ask the conditional module 2826 * The line might be a conditional. Ask the conditional module
2828 * about it and act accordingly 2827 * about it and act accordingly
2829 */ 2828 */
2830 switch (Cond_EvalLine(line)) { 2829 switch (Cond_EvalLine(line)) {
2831 case COND_SKIP: 2830 case COND_SKIP:
2832 /* Skip to next conditional that evaluates to COND_PARSE. */ 2831 /* Skip to next conditional that evaluates to COND_PARSE. */
2833 do { 2832 do {
2834 line = ParseGetLine(PARSE_SKIP); 2833 line = ParseGetLine(PARSE_SKIP);
2835 } while (line && Cond_EvalLine(line) != COND_PARSE); 2834 } while (line && Cond_EvalLine(line) != COND_PARSE);
2836 if (line == NULL) 2835 if (line == NULL)
2837 break; 2836 break;
2838 continue; 2837 continue;
2839 case COND_PARSE: 2838 case COND_PARSE:
2840 continue; 2839 continue;
2841 case COND_INVALID: /* Not a conditional line */ 2840 case COND_INVALID: /* Not a conditional line */
2842 /* Check for .for loops */ 2841 /* Check for .for loops */
2843 rval = For_Eval(line); 2842 rval = For_Eval(line);
2844 if (rval == 0) 2843 if (rval == 0)
2845 /* Not a .for line */ 2844 /* Not a .for line */
2846 break; 2845 break;
2847 if (rval < 0) 2846 if (rval < 0)
2848 /* Syntax error - error printed, ignore line */ 2847 /* Syntax error - error printed, ignore line */
2849 continue; 2848 continue;
2850 /* Start of a .for loop */ 2849 /* Start of a .for loop */
2851 lineno = CurFile()->lineno; 2850 lineno = CurFile()->lineno;
2852 /* Accumulate loop lines until matching .endfor */ 2851 /* Accumulate loop lines until matching .endfor */
2853 do { 2852 do {
2854 line = ParseGetLine(PARSE_RAW); 2853 line = ParseGetLine(PARSE_RAW);
2855 if (line == NULL) { 2854 if (line == NULL) {
2856 Parse_Error(PARSE_FATAL, 2855 Parse_Error(PARSE_FATAL,
2857 "Unexpected end of file in for loop."); 2856 "Unexpected end of file in for loop.");
2858 break; 2857 break;
2859 } 2858 }
2860 } while (For_Accum(line)); 2859 } while (For_Accum(line));
2861 /* Stash each iteration as a new 'input file' */ 2860 /* Stash each iteration as a new 'input file' */
2862 For_Run(lineno); 2861 For_Run(lineno);
2863 /* Read next line from for-loop buffer */ 2862 /* Read next line from for-loop buffer */
2864 continue; 2863 continue;
2865 } 2864 }
2866 return line; 2865 return line;
2867 } 2866 }
2868} 2867}
2869 2868
2870static void 2869static void
2871FinishDependencyGroup(void) 2870FinishDependencyGroup(void)
2872{ 2871{
2873 if (targets != NULL) { 2872 if (targets != NULL) {
2874 GNodeListNode *ln; 2873 GNodeListNode *ln;
2875 for (ln = targets->first; ln != NULL; ln = ln->next) { 2874 for (ln = targets->first; ln != NULL; ln = ln->next) {
2876 GNode *gn = ln->datum; 2875 GNode *gn = ln->datum;
2877 2876
2878 Suff_EndTransform(gn); 2877 Suff_EndTransform(gn);
2879 2878
2880 /* Mark the target as already having commands if it does, to 2879 /* Mark the target as already having commands if it does, to
2881 * keep from having shell commands on multiple dependency lines. */ 2880 * keep from having shell commands on multiple dependency lines. */
2882 if (!Lst_IsEmpty(gn->commands)) 2881 if (!Lst_IsEmpty(gn->commands))
2883 gn->type |= OP_HAS_COMMANDS; 2882 gn->type |= OP_HAS_COMMANDS;
2884 } 2883 }
2885 2884
2886 Lst_Free(targets); 2885 Lst_Free(targets);
2887 targets = NULL; 2886 targets = NULL;
2888 } 2887 }
2889} 2888}
2890 2889
2891/* Add the command to each target from the current dependency spec. */ 2890/* Add the command to each target from the current dependency spec. */
2892static void 2891static void
2893ParseLine_ShellCommand(const char *p) 2892ParseLine_ShellCommand(const char *p)
2894{ 2893{
2895 cpp_skip_whitespace(&p); 2894 cpp_skip_whitespace(&p);
2896 if (*p == '\0') 2895 if (*p == '\0')
2897 return; /* skip empty commands */ 2896 return; /* skip empty commands */
2898 2897
2899 if (targets == NULL) { 2898 if (targets == NULL) {
2900 Parse_Error(PARSE_FATAL, "Unassociated shell command \"%s\"", p); 2899 Parse_Error(PARSE_FATAL, "Unassociated shell command \"%s\"", p);
2901 return; 2900 return;
2902 } 2901 }
2903 2902
2904 { 2903 {
2905 char *cmd = bmake_strdup(p); 2904 char *cmd = bmake_strdup(p);
2906 GNodeListNode *ln; 2905 GNodeListNode *ln;
2907 2906
2908 for (ln = targets->first; ln != NULL; ln = ln->next) { 2907 for (ln = targets->first; ln != NULL; ln = ln->next) {
2909 GNode *gn = ln->datum; 2908 GNode *gn = ln->datum;
2910 ParseAddCmd(gn, cmd); 2909 ParseAddCmd(gn, cmd);
2911 } 2910 }
2912#ifdef CLEANUP 2911#ifdef CLEANUP
2913 Lst_Append(targCmds, cmd); 2912 Lst_Append(targCmds, cmd);
2914#endif 2913#endif
2915 } 2914 }
2916} 2915}
2917 2916
2918static Boolean 2917static Boolean
2919ParseDirective(char *line) 2918ParseDirective(char *line)
2920{ 2919{
2921 char *cp; 2920 char *cp;
2922 2921
2923 if (*line == '.') { 2922 if (*line == '.') {
2924 /* 2923 /*
2925 * Lines that begin with the special character may be 2924 * Lines that begin with the special character may be
2926 * include or undef directives. 2925 * include or undef directives.
2927 * On the other hand they can be suffix rules (.c.o: ...) 2926 * On the other hand they can be suffix rules (.c.o: ...)
2928 * or just dependencies for filenames that start '.'. 2927 * or just dependencies for filenames that start '.'.
2929 */ 2928 */
2930 cp = line + 1; 2929 cp = line + 1;
2931 pp_skip_whitespace(&cp); 2930 pp_skip_whitespace(&cp);
2932 if (IsInclude(cp, FALSE)) { 2931 if (IsInclude(cp, FALSE)) {
2933 ParseDoInclude(cp); 2932 ParseDoInclude(cp);
2934 return TRUE; 2933 return TRUE;
2935 } 2934 }
2936 if (strncmp(cp, "undef", 5) == 0) { 2935 if (strncmp(cp, "undef", 5) == 0) {
2937 const char *varname; 2936 const char *varname;
2938 cp += 5; 2937 cp += 5;
2939 pp_skip_whitespace(&cp); 2938 pp_skip_whitespace(&cp);
2940 varname = cp; 2939 varname = cp;
2941 for (; !ch_isspace(*cp) && *cp != '\0'; cp++) 2940 for (; !ch_isspace(*cp) && *cp != '\0'; cp++)
2942 continue; 2941 continue;
2943 *cp = '\0'; 2942 *cp = '\0';
2944 Var_Delete(varname, VAR_GLOBAL); 2943 Var_Delete(varname, VAR_GLOBAL);
2945 /* TODO: undefine all variables, not only the first */ 2944 /* TODO: undefine all variables, not only the first */
2946 /* TODO: use Str_Words, like everywhere else */ 2945 /* TODO: use Str_Words, like everywhere else */
2947 return TRUE; 2946 return TRUE;
2948 } else if (strncmp(cp, "export", 6) == 0) { 2947 } else if (strncmp(cp, "export", 6) == 0) {
2949 cp += 6; 2948 cp += 6;
2950 pp_skip_whitespace(&cp); 2949 pp_skip_whitespace(&cp);
2951 Var_Export(cp, TRUE); 2950 Var_Export(cp, TRUE);
2952 return TRUE; 2951 return TRUE;
2953 } else if (strncmp(cp, "unexport", 8) == 0) { 2952 } else if (strncmp(cp, "unexport", 8) == 0) {
2954 Var_UnExport(cp); 2953 Var_UnExport(cp);
2955 return TRUE; 2954 return TRUE;
2956 } else if (strncmp(cp, "info", 4) == 0 || 2955 } else if (strncmp(cp, "info", 4) == 0 ||
2957 strncmp(cp, "error", 5) == 0 || 2956 strncmp(cp, "error", 5) == 0 ||
2958 strncmp(cp, "warning", 7) == 0) { 2957 strncmp(cp, "warning", 7) == 0) {
2959 if (ParseMessage(cp)) 2958 if (ParseMessage(cp))
2960 return TRUE; 2959 return TRUE;
2961 } 2960 }
2962 } 2961 }
2963 return FALSE; 2962 return FALSE;
2964} 2963}
2965 2964
2966static Boolean 2965static Boolean
2967ParseVarassign(const char *line) 2966ParseVarassign(const char *line)
2968{ 2967{
2969 VarAssign var; 2968 VarAssign var;
2970 if (Parse_IsVar(line, &var)) { 2969 if (Parse_IsVar(line, &var)) {
2971 FinishDependencyGroup(); 2970 FinishDependencyGroup();
2972 Parse_DoVar(&var, VAR_GLOBAL); 2971 Parse_DoVar(&var, VAR_GLOBAL);
2973 return TRUE; 2972 return TRUE;
2974 } 2973 }
2975 return FALSE; 2974 return FALSE;
2976} 2975}
2977 2976
2978static char * 2977static char *
2979FindSemicolon(char *p) 2978FindSemicolon(char *p)
2980{ 2979{
2981 int level = 0; 2980 int level = 0;
2982 2981
2983 for (; *p != '\0'; p++) { 2982 for (; *p != '\0'; p++) {
2984 if (*p == '\\' && p[1] != '\0') { 2983 if (*p == '\\' && p[1] != '\0') {
2985 p++; 2984 p++;
2986 continue; 2985 continue;
2987 } 2986 }
2988 2987
2989 if (*p == '$' && (p[1] == '(' || p[1] == '{')) { 2988 if (*p == '$' && (p[1] == '(' || p[1] == '{')) {
2990 level++; 2989 level++;
2991 continue; 2990 continue;
2992 } 2991 }
2993 2992
2994 if (level > 0 && (*p == ')' || *p == '}')) { 2993 if (level > 0 && (*p == ')' || *p == '}')) {
2995 level--; 2994 level--;
2996 continue; 2995 continue;
2997 } 2996 }
2998 2997
2999 if (level == 0 && *p == ';') { 2998 if (level == 0 && *p == ';') {
3000 break; 2999 break;
3001 } 3000 }
3002 } 3001 }
3003 return p; 3002 return p;
3004} 3003}
3005 3004
3006/* dependency -> target... op [source...] 3005/* dependency -> target... op [source...]
3007 * op -> ':' | '::' | '!' */ 3006 * op -> ':' | '::' | '!' */
3008static void 3007static void
3009ParseDependency(char *line) 3008ParseDependency(char *line)
3010{ 3009{
3011 VarEvalFlags eflags; 3010 VarEvalFlags eflags;
3012 char *expanded_line; 3011 char *expanded_line;
3013 const char *shellcmd = NULL; 3012 const char *shellcmd = NULL;
3014 3013
3015 /* 3014 /*
3016 * For some reason - probably to make the parser impossible - 3015 * For some reason - probably to make the parser impossible -
3017 * a ';' can be used to separate commands from dependencies. 3016 * a ';' can be used to separate commands from dependencies.
3018 * Attempt to avoid ';' inside substitution patterns. 3017 * Attempt to avoid ';' inside substitution patterns.
3019 */ 3018 */
3020 { 3019 {
3021 char *semicolon = FindSemicolon(line); 3020 char *semicolon = FindSemicolon(line);
3022 if (*semicolon != '\0') { 3021 if (*semicolon != '\0') {
3023 /* Terminate the dependency list at the ';' */ 3022 /* Terminate the dependency list at the ';' */
3024 *semicolon = '\0'; 3023 *semicolon = '\0';
3025 shellcmd = semicolon + 1; 3024 shellcmd = semicolon + 1;
3026 } 3025 }
3027 } 3026 }
3028 3027
3029 /* 3028 /*
3030 * We now know it's a dependency line so it needs to have all 3029 * We now know it's a dependency line so it needs to have all
3031 * variables expanded before being parsed. 3030 * variables expanded before being parsed.
3032 * 3031 *
3033 * XXX: Ideally the dependency line would first be split into 3032 * XXX: Ideally the dependency line would first be split into
3034 * its left-hand side, dependency operator and right-hand side, 3033 * its left-hand side, dependency operator and right-hand side,
3035 * and then each side would be expanded on its own. This would 3034 * and then each side would be expanded on its own. This would
3036 * allow for the left-hand side to allow only defined variables 3035 * allow for the left-hand side to allow only defined variables
3037 * and to allow variables on the right-hand side to be undefined 3036 * and to allow variables on the right-hand side to be undefined
3038 * as well. 3037 * as well.
3039 * 3038 *
3040 * Parsing the line first would also prevent that targets 3039 * Parsing the line first would also prevent that targets
3041 * generated from variable expressions are interpreted as the 3040 * generated from variable expressions are interpreted as the
3042 * dependency operator, such as in "target${:U:} middle: source", 3041 * dependency operator, such as in "target${:U:} middle: source",
3043 * in which the middle is interpreted as a source, not a target. 3042 * in which the middle is interpreted as a source, not a target.
3044 */ 3043 */
3045 3044
3046 /* In lint mode, allow undefined variables to appear in 3045 /* In lint mode, allow undefined variables to appear in
3047 * dependency lines. 3046 * dependency lines.
3048 * 3047 *
3049 * Ideally, only the right-hand side would allow undefined 3048 * Ideally, only the right-hand side would allow undefined
3050 * variables since it is common to have no dependencies. 3049 * variables since it is common to have no dependencies.
3051 * Having undefined variables on the left-hand side is more 3050 * Having undefined variables on the left-hand side is more
3052 * unusual though. Since both sides are expanded in a single 3051 * unusual though. Since both sides are expanded in a single
3053 * pass, there is not much choice what to do here. 3052 * pass, there is not much choice what to do here.
3054 * 3053 *
3055 * In normal mode, it does not matter whether undefined 3054 * In normal mode, it does not matter whether undefined
3056 * variables are allowed or not since as of 2020-09-14, 3055 * variables are allowed or not since as of 2020-09-14,
3057 * Var_Parse does not print any parse errors in such a case. 3056 * Var_Parse does not print any parse errors in such a case.
3058 * It simply returns the special empty string var_Error, 3057 * It simply returns the special empty string var_Error,
3059 * which cannot be detected in the result of Var_Subst. */ 3058 * which cannot be detected in the result of Var_Subst. */
3060 eflags = DEBUG(LINT) ? VARE_WANTRES : VARE_UNDEFERR | VARE_WANTRES; 3059 eflags = DEBUG(LINT) ? VARE_WANTRES : VARE_UNDEFERR | VARE_WANTRES;
3061 (void)Var_Subst(line, VAR_CMDLINE, eflags, &expanded_line); 3060 (void)Var_Subst(line, VAR_CMDLINE, eflags, &expanded_line);
3062 /* TODO: handle errors */ 3061 /* TODO: handle errors */
3063 3062
3064 /* Need a fresh list for the target nodes */ 3063 /* Need a fresh list for the target nodes */
3065 if (targets != NULL) 3064 if (targets != NULL)
3066 Lst_Free(targets); 3065 Lst_Free(targets);
3067 targets = Lst_New(); 3066 targets = Lst_New();
3068 3067
3069 ParseDoDependency(expanded_line); 3068 ParseDoDependency(expanded_line);
3070 free(expanded_line); 3069 free(expanded_line);
3071 3070
3072 if (shellcmd != NULL) 3071 if (shellcmd != NULL)
3073 ParseLine_ShellCommand(shellcmd); 3072 ParseLine_ShellCommand(shellcmd);
3074} 3073}
3075 3074
3076static void 3075static void
3077ParseLine(char *line) 3076ParseLine(char *line)
3078{ 3077{
3079 if (ParseDirective(line)) 3078 if (ParseDirective(line))
3080 return; 3079 return;
3081 3080
3082 if (*line == '\t') { 3081 if (*line == '\t') {
3083 ParseLine_ShellCommand(line + 1); 3082 ParseLine_ShellCommand(line + 1);
3084 return; 3083 return;
3085 } 3084 }
3086 3085
3087#ifdef SYSVINCLUDE 3086#ifdef SYSVINCLUDE
3088 if (IsSysVInclude(line)) { 3087 if (IsSysVInclude(line)) {
3089 /* 3088 /*
3090 * It's an S3/S5-style "include". 3089 * It's an S3/S5-style "include".
3091 */ 3090 */
3092 ParseTraditionalInclude(line); 3091 ParseTraditionalInclude(line);
3093 return; 3092 return;
3094 } 3093 }
3095#endif 3094#endif
3096 3095
3097#ifdef GMAKEEXPORT 3096#ifdef GMAKEEXPORT
3098 if (strncmp(line, "export", 6) == 0 && ch_isspace(line[6]) && 3097 if (strncmp(line, "export", 6) == 0 && ch_isspace(line[6]) &&
3099 strchr(line, ':') == NULL) { 3098 strchr(line, ':') == NULL) {
3100 /* 3099 /*
3101 * It's a Gmake "export". 3100 * It's a Gmake "export".
3102 */ 3101 */
3103 ParseGmakeExport(line); 3102 ParseGmakeExport(line);
3104 return; 3103 return;
3105 } 3104 }
3106#endif 3105#endif
3107 3106
3108 if (ParseVarassign(line)) 3107 if (ParseVarassign(line))
3109 return; 3108 return;
3110 3109
3111 FinishDependencyGroup(); 3110 FinishDependencyGroup();
3112 3111
3113 ParseDependency(line); 3112 ParseDependency(line);
3114} 3113}
3115 3114
3116/* Parse a top-level makefile into its component parts, incorporating them 3115/* Parse a top-level makefile into its component parts, incorporating them
3117 * into the global dependency graph. 3116 * into the global dependency graph.
3118 * 3117 *
3119 * Input: 3118 * Input:
3120 * name The name of the file being read 3119 * name The name of the file being read
3121 * fd The open file to parse; will be closed at the end 3120 * fd The open file to parse; will be closed at the end
3122 */ 3121 */
3123void 3122void
3124Parse_File(const char *name, int fd) 3123Parse_File(const char *name, int fd)
3125{ 3124{
3126 char *line; /* the line we're working on */ 3125 char *line; /* the line we're working on */
3127 struct loadedfile *lf; 3126 struct loadedfile *lf;
3128 3127
3129 lf = loadfile(name, fd); 3128 lf = loadfile(name, fd);
3130 3129
3131 assert(targets == NULL); 3130 assert(targets == NULL);
3132 fatals = 0; 3131 fatals = 0;
3133 3132
3134 if (name == NULL) 3133 if (name == NULL)
3135 name = "(stdin)"; 3134 name = "(stdin)";
3136 3135
3137 Parse_SetInput(name, 0, -1, loadedfile_nextbuf, lf); 3136 Parse_SetInput(name, 0, -1, loadedfile_nextbuf, lf);
3138 CurFile()->lf = lf; 3137 CurFile()->lf = lf;
3139 3138
3140 do { 3139 do {
3141 while ((line = ParseReadLine()) != NULL) { 3140 while ((line = ParseReadLine()) != NULL) {
3142 DEBUG2(PARSE, "ParseReadLine (%d): '%s'\n", 3141 DEBUG2(PARSE, "ParseReadLine (%d): '%s'\n",
3143 CurFile()->lineno, line); 3142 CurFile()->lineno, line);
3144 ParseLine(line); 3143 ParseLine(line);
3145 } 3144 }
3146 /* 3145 /*
3147 * Reached EOF, but it may be just EOF of an include file... 3146 * Reached EOF, but it may be just EOF of an include file...
3148 */ 3147 */
3149 } while (ParseEOF()); 3148 } while (ParseEOF());
3150 3149
3151 FinishDependencyGroup(); 3150 FinishDependencyGroup();
3152 3151
3153 if (fatals) { 3152 if (fatals) {
3154 (void)fflush(stdout); 3153 (void)fflush(stdout);
3155 (void)fprintf(stderr, 3154 (void)fprintf(stderr,
3156 "%s: Fatal errors encountered -- cannot continue", 3155 "%s: Fatal errors encountered -- cannot continue",
3157 progname); 3156 progname);
3158 PrintOnError(NULL, NULL); 3157 PrintOnError(NULL, NULL);
3159 exit(1); 3158 exit(1);
3160 } 3159 }
3161} 3160}
3162 3161
3163/* Initialize the parsing module. */ 3162/* Initialize the parsing module. */
3164void 3163void
3165Parse_Init(void) 3164Parse_Init(void)
3166{ 3165{
3167 mainNode = NULL; 3166 mainNode = NULL;
3168 parseIncPath = Lst_New(); 3167 parseIncPath = Lst_New();
3169 sysIncPath = Lst_New(); 3168 sysIncPath = Lst_New();
3170 defSysIncPath = Lst_New(); 3169 defSysIncPath = Lst_New();
3171 Vector_Init(&includes, sizeof(IFile)); 3170 Vector_Init(&includes, sizeof(IFile));
3172#ifdef CLEANUP 3171#ifdef CLEANUP
3173 targCmds = Lst_New(); 3172 targCmds = Lst_New();
3174#endif 3173#endif
3175} 3174}
3176 3175
3177/* Clean up the parsing module. */ 3176/* Clean up the parsing module. */
3178void 3177void
3179Parse_End(void) 3178Parse_End(void)
3180{ 3179{
3181#ifdef CLEANUP 3180#ifdef CLEANUP
3182 Lst_Destroy(targCmds, free); 3181 Lst_Destroy(targCmds, free);
3183 assert(targets == NULL); 3182 assert(targets == NULL);
3184 Lst_Destroy(defSysIncPath, Dir_Destroy); 3183 Lst_Destroy(defSysIncPath, Dir_Destroy);
3185 Lst_Destroy(sysIncPath, Dir_Destroy); 3184 Lst_Destroy(sysIncPath, Dir_Destroy);
3186 Lst_Destroy(parseIncPath, Dir_Destroy); 3185 Lst_Destroy(parseIncPath, Dir_Destroy);
3187 assert(includes.len == 0); 3186 assert(includes.len == 0);
3188 Vector_Done(&includes); 3187 Vector_Done(&includes);
3189#endif 3188#endif
3190} 3189}
3191 3190
3192 3191
3193/*- 3192/*-
3194 *----------------------------------------------------------------------- 3193 *-----------------------------------------------------------------------
3195 * Parse_MainName -- 3194 * Parse_MainName --
3196 * Return a Lst of the main target to create for main()'s sake. If 3195 * Return a Lst of the main target to create for main()'s sake. If
3197 * no such target exists, we Punt with an obnoxious error message. 3196 * no such target exists, we Punt with an obnoxious error message.
3198 * 3197 *
3199 * Results: 3198 * Results:
3200 * A Lst of the single node to create. 3199 * A Lst of the single node to create.
3201 * 3200 *
3202 * Side Effects: 3201 * Side Effects:
3203 * None. 3202 * None.
3204 * 3203 *
3205 *----------------------------------------------------------------------- 3204 *-----------------------------------------------------------------------
3206 */ 3205 */
3207GNodeList * 3206GNodeList *
3208Parse_MainName(void) 3207Parse_MainName(void)
3209{ 3208{
3210 GNodeList *mainList; 3209 GNodeList *mainList;
3211 3210
3212 mainList = Lst_New(); 3211 mainList = Lst_New();
3213 3212
3214 if (mainNode == NULL) { 3213 if (mainNode == NULL) {
3215 Punt("no target to make."); 3214 Punt("no target to make.");
3216 /*NOTREACHED*/ 3215 /*NOTREACHED*/
3217 } else if (mainNode->type & OP_DOUBLEDEP) { 3216 } else if (mainNode->type & OP_DOUBLEDEP) {
3218 Lst_Append(mainList, mainNode); 3217 Lst_Append(mainList, mainNode);
3219 Lst_AppendAll(mainList, mainNode->cohorts); 3218 Lst_AppendAll(mainList, mainNode->cohorts);
3220 } else 3219 } else
3221 Lst_Append(mainList, mainNode); 3220 Lst_Append(mainList, mainNode);
3222 Var_Append(".TARGETS", mainNode->name, VAR_GLOBAL); 3221 Var_Append(".TARGETS", mainNode->name, VAR_GLOBAL);
3223 return mainList; 3222 return mainList;
3224} 3223}