Sat Oct 31 23:01:23 2020 UTC ()
make(1): fix off-by-one bug in ParseTrackInput (since 2015-11-26)


(rillig)
diff -r1.415 -r1.416 src/usr.bin/make/parse.c
diff -r1.2 -r1.3 src/usr.bin/make/unit-tests/directive-include.exp
diff -r1.2 -r1.3 src/usr.bin/make/unit-tests/directive-include.mk

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

--- src/usr.bin/make/parse.c 2020/10/31 21:52:56 1.415
+++ src/usr.bin/make/parse.c 2020/10/31 23:01:23 1.416
@@ -1,1119 +1,1119 @@ @@ -1,1119 +1,1119 @@
1/* $NetBSD: parse.c,v 1.415 2020/10/31 21:52:56 rillig Exp $ */ 1/* $NetBSD: parse.c,v 1.416 2020/10/31 23:01:23 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.415 2020/10/31 21:52:56 rillig Exp $"); 120MAKE_RCSID("$NetBSD: parse.c,v 1.416 2020/10/31 23:01:23 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 */
@@ -1370,1836 +1370,1836 @@ ParseDoDependencySourcesEmpty(ParseSpeci @@ -1370,1836 +1370,1836 @@ ParseDoDependencySourcesEmpty(ParseSpeci
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
2354/* Track the makefiles we read - so makefiles can set dependencies on them. 2354/* Track the makefiles we read - so makefiles can set dependencies on them.
2355 * Avoid adding anything more than once. */ 2355 * Avoid adding anything more than once. */
2356static void 2356static void
2357ParseTrackInput(const char *name) 2357ParseTrackInput(const char *name)
2358{ 2358{
2359 void *fp = NULL; 2359 void *fp = NULL;
2360 2360
2361 const char *old = Var_Value(MAKE_MAKEFILES, VAR_GLOBAL, &fp); 2361 const char *old = Var_Value(MAKE_MAKEFILES, VAR_GLOBAL, &fp);
2362 if (old) { 2362 if (old) {
2363 size_t name_len = strlen(name); 2363 size_t name_len = strlen(name);
2364 const char *ep = old + strlen(old) - name_len; 2364 const char *ep = old + strlen(old) - name_len;
2365 /* does it contain name? */ 2365 /* does it contain name? */
2366 for (; old != NULL; old = strchr(old, ' ')) { 2366 for (; old != NULL; old = strchr(old, ' ')) {
2367 if (*old == ' ') 2367 if (*old == ' ')
2368 old++; 2368 old++;
2369 if (old >= ep) 2369 if (old > ep)
2370 break; /* cannot contain name */ 2370 break; /* cannot contain name */
2371 if (memcmp(old, name, name_len) == 0 && 2371 if (memcmp(old, name, name_len) == 0 &&
2372 (old[name_len] == '\0' || old[name_len] == ' ')) 2372 (old[name_len] == '\0' || old[name_len] == ' '))
2373 goto cleanup; 2373 goto cleanup;
2374 } 2374 }
2375 } 2375 }
2376 Var_Append(MAKE_MAKEFILES, name, VAR_GLOBAL); 2376 Var_Append(MAKE_MAKEFILES, name, VAR_GLOBAL);
2377cleanup: 2377cleanup:
2378 bmake_free(fp); 2378 bmake_free(fp);
2379} 2379}
2380 2380
2381 2381
2382/* Start Parsing from the given source. 2382/* Start Parsing from the given source.
2383 * 2383 *
2384 * The given file is added to the includes stack. */ 2384 * The given file is added to the includes stack. */
2385void 2385void
2386Parse_SetInput(const char *name, int line, int fd, 2386Parse_SetInput(const char *name, int line, int fd,
2387 char *(*nextbuf)(void *, size_t *), void *arg) 2387 char *(*nextbuf)(void *, size_t *), void *arg)
2388{ 2388{
2389 IFile *curFile; 2389 IFile *curFile;
2390 char *buf; 2390 char *buf;
2391 size_t len; 2391 size_t len;
2392 Boolean fromForLoop = name == NULL; 2392 Boolean fromForLoop = name == NULL;
2393 2393
2394 if (fromForLoop) 2394 if (fromForLoop)
2395 name = CurFile()->fname; 2395 name = CurFile()->fname;
2396 else 2396 else
2397 ParseTrackInput(name); 2397 ParseTrackInput(name);
2398 2398
2399 if (DEBUG(PARSE)) 2399 if (DEBUG(PARSE))
2400 debug_printf("%s: file %s, line %d, fd %d, nextbuf %s, arg %p\n", 2400 debug_printf("%s: file %s, line %d, fd %d, nextbuf %s, arg %p\n",
2401 __func__, name, line, fd, 2401 __func__, name, line, fd,
2402 nextbuf == loadedfile_nextbuf ? "loadedfile" : "other", 2402 nextbuf == loadedfile_nextbuf ? "loadedfile" : "other",
2403 arg); 2403 arg);
2404 2404
2405 if (fd == -1 && nextbuf == NULL) 2405 if (fd == -1 && nextbuf == NULL)
2406 /* sanity */ 2406 /* sanity */
2407 return; 2407 return;
2408 2408
2409 curFile = Vector_Push(&includes); 2409 curFile = Vector_Push(&includes);
2410 2410
2411 /* 2411 /*
2412 * Once the previous state has been saved, we can get down to reading 2412 * Once the previous state has been saved, we can get down to reading
2413 * the new file. We set up the name of the file to be the absolute 2413 * the new file. We set up the name of the file to be the absolute
2414 * name of the include file so error messages refer to the right 2414 * name of the include file so error messages refer to the right
2415 * place. 2415 * place.
2416 */ 2416 */
2417 curFile->fname = bmake_strdup(name); 2417 curFile->fname = bmake_strdup(name);
2418 curFile->fromForLoop = fromForLoop; 2418 curFile->fromForLoop = fromForLoop;
2419 curFile->lineno = line; 2419 curFile->lineno = line;
2420 curFile->first_lineno = line; 2420 curFile->first_lineno = line;
2421 curFile->nextbuf = nextbuf; 2421 curFile->nextbuf = nextbuf;
2422 curFile->nextbuf_arg = arg; 2422 curFile->nextbuf_arg = arg;
2423 curFile->lf = NULL; 2423 curFile->lf = NULL;
2424 curFile->depending = doing_depend; /* restore this on EOF */ 2424 curFile->depending = doing_depend; /* restore this on EOF */
2425 2425
2426 assert(nextbuf != NULL); 2426 assert(nextbuf != NULL);
2427 2427
2428 /* Get first block of input data */ 2428 /* Get first block of input data */
2429 buf = curFile->nextbuf(curFile->nextbuf_arg, &len); 2429 buf = curFile->nextbuf(curFile->nextbuf_arg, &len);
2430 if (buf == NULL) { 2430 if (buf == NULL) {
2431 /* Was all a waste of time ... */ 2431 /* Was all a waste of time ... */
2432 if (curFile->fname) 2432 if (curFile->fname)
2433 free(curFile->fname); 2433 free(curFile->fname);
2434 free(curFile); 2434 free(curFile);
2435 return; 2435 return;
2436 } 2436 }
2437 curFile->buf_freeIt = buf; 2437 curFile->buf_freeIt = buf;
2438 curFile->buf_ptr = buf; 2438 curFile->buf_ptr = buf;
2439 curFile->buf_end = buf + len; 2439 curFile->buf_end = buf + len;
2440 2440
2441 curFile->cond_depth = Cond_save_depth(); 2441 curFile->cond_depth = Cond_save_depth();
2442 ParseSetParseFile(name); 2442 ParseSetParseFile(name);
2443} 2443}
2444 2444
2445/* Check if the directive is an include directive. */ 2445/* Check if the directive is an include directive. */
2446static Boolean 2446static Boolean
2447IsInclude(const char *dir, Boolean sysv) 2447IsInclude(const char *dir, Boolean sysv)
2448{ 2448{
2449 if (dir[0] == 's' || dir[0] == '-' || (dir[0] == 'd' && !sysv)) 2449 if (dir[0] == 's' || dir[0] == '-' || (dir[0] == 'd' && !sysv))
2450 dir++; 2450 dir++;
2451 2451
2452 if (strncmp(dir, "include", 7) != 0) 2452 if (strncmp(dir, "include", 7) != 0)
2453 return FALSE; 2453 return FALSE;
2454 2454
2455 /* Space is not mandatory for BSD .include */ 2455 /* Space is not mandatory for BSD .include */
2456 return !sysv || ch_isspace(dir[7]); 2456 return !sysv || ch_isspace(dir[7]);
2457} 2457}
2458 2458
2459 2459
2460#ifdef SYSVINCLUDE 2460#ifdef SYSVINCLUDE
2461/* Check if the line is a SYSV include directive. */ 2461/* Check if the line is a SYSV include directive. */
2462static Boolean 2462static Boolean
2463IsSysVInclude(const char *line) 2463IsSysVInclude(const char *line)
2464{ 2464{
2465 const char *p; 2465 const char *p;
2466 2466
2467 if (!IsInclude(line, TRUE)) 2467 if (!IsInclude(line, TRUE))
2468 return FALSE; 2468 return FALSE;
2469 2469
2470 /* Avoid interpreting a dependency line as an include */ 2470 /* Avoid interpreting a dependency line as an include */
2471 for (p = line; (p = strchr(p, ':')) != NULL;) { 2471 for (p = line; (p = strchr(p, ':')) != NULL;) {
2472 if (*++p == '\0') { 2472 if (*++p == '\0') {
2473 /* end of line -> dependency */ 2473 /* end of line -> dependency */
2474 return FALSE; 2474 return FALSE;
2475 } 2475 }
2476 if (*p == ':' || ch_isspace(*p)) { 2476 if (*p == ':' || ch_isspace(*p)) {
2477 /* :: operator or ': ' -> dependency */ 2477 /* :: operator or ': ' -> dependency */
2478 return FALSE; 2478 return FALSE;
2479 } 2479 }
2480 } 2480 }
2481 return TRUE; 2481 return TRUE;
2482} 2482}
2483 2483
2484/* Push to another file. The line points to the word "include". */ 2484/* Push to another file. The line points to the word "include". */
2485static void 2485static void
2486ParseTraditionalInclude(char *line) 2486ParseTraditionalInclude(char *line)
2487{ 2487{
2488 char *cp; /* current position in file spec */ 2488 char *cp; /* current position in file spec */
2489 int done = 0; 2489 int done = 0;
2490 int silent = line[0] != 'i'; 2490 int silent = line[0] != 'i';
2491 char *file = line + (silent ? 8 : 7); 2491 char *file = line + (silent ? 8 : 7);
2492 char *all_files; 2492 char *all_files;
2493 2493
2494 DEBUG2(PARSE, "%s: %s\n", __func__, file); 2494 DEBUG2(PARSE, "%s: %s\n", __func__, file);
2495 2495
2496 pp_skip_whitespace(&file); 2496 pp_skip_whitespace(&file);
2497 2497
2498 /* 2498 /*
2499 * Substitute for any variables in the file name before trying to 2499 * Substitute for any variables in the file name before trying to
2500 * find the thing. 2500 * find the thing.
2501 */ 2501 */
2502 (void)Var_Subst(file, VAR_CMDLINE, VARE_WANTRES, &all_files); 2502 (void)Var_Subst(file, VAR_CMDLINE, VARE_WANTRES, &all_files);
2503 /* TODO: handle errors */ 2503 /* TODO: handle errors */
2504 2504
2505 if (*file == '\0') { 2505 if (*file == '\0') {
2506 Parse_Error(PARSE_FATAL, "Filename missing from \"include\""); 2506 Parse_Error(PARSE_FATAL, "Filename missing from \"include\"");
2507 goto out; 2507 goto out;
2508 } 2508 }
2509 2509
2510 for (file = all_files; !done; file = cp + 1) { 2510 for (file = all_files; !done; file = cp + 1) {
2511 /* Skip to end of line or next whitespace */ 2511 /* Skip to end of line or next whitespace */
2512 for (cp = file; *cp && !ch_isspace(*cp); cp++) 2512 for (cp = file; *cp && !ch_isspace(*cp); cp++)
2513 continue; 2513 continue;
2514 2514
2515 if (*cp) 2515 if (*cp)
2516 *cp = '\0'; 2516 *cp = '\0';
2517 else 2517 else
2518 done = 1; 2518 done = 1;
2519 2519
2520 Parse_include_file(file, FALSE, FALSE, silent); 2520 Parse_include_file(file, FALSE, FALSE, silent);
2521 } 2521 }
2522out: 2522out:
2523 free(all_files); 2523 free(all_files);
2524} 2524}
2525#endif 2525#endif
2526 2526
2527#ifdef GMAKEEXPORT 2527#ifdef GMAKEEXPORT
2528/* Parse "export <variable>=<value>", and actually export it. */ 2528/* Parse "export <variable>=<value>", and actually export it. */
2529static void 2529static void
2530ParseGmakeExport(char *line) 2530ParseGmakeExport(char *line)
2531{ 2531{
2532 char *variable = line + 6; 2532 char *variable = line + 6;
2533 char *value; 2533 char *value;
2534 2534
2535 DEBUG2(PARSE, "%s: %s\n", __func__, variable); 2535 DEBUG2(PARSE, "%s: %s\n", __func__, variable);
2536 2536
2537 pp_skip_whitespace(&variable); 2537 pp_skip_whitespace(&variable);
2538 2538
2539 for (value = variable; *value && *value != '='; value++) 2539 for (value = variable; *value && *value != '='; value++)
2540 continue; 2540 continue;
2541 2541
2542 if (*value != '=') { 2542 if (*value != '=') {
2543 Parse_Error(PARSE_FATAL, 2543 Parse_Error(PARSE_FATAL,
2544 "Variable/Value missing from \"export\""); 2544 "Variable/Value missing from \"export\"");
2545 return; 2545 return;
2546 } 2546 }
2547 *value++ = '\0'; /* terminate variable */ 2547 *value++ = '\0'; /* terminate variable */
2548 2548
2549 /* 2549 /*
2550 * Expand the value before putting it in the environment. 2550 * Expand the value before putting it in the environment.
2551 */ 2551 */
2552 (void)Var_Subst(value, VAR_CMDLINE, VARE_WANTRES, &value); 2552 (void)Var_Subst(value, VAR_CMDLINE, VARE_WANTRES, &value);
2553 /* TODO: handle errors */ 2553 /* TODO: handle errors */
2554 2554
2555 setenv(variable, value, 1); 2555 setenv(variable, value, 1);
2556 free(value); 2556 free(value);
2557} 2557}
2558#endif 2558#endif
2559 2559
2560/* Called when EOF is reached in the current file. If we were reading an 2560/* Called when EOF is reached in the current file. If we were reading an
2561 * include file, the includes stack is popped and things set up to go back 2561 * include file, the includes stack is popped and things set up to go back
2562 * to reading the previous file at the previous location. 2562 * to reading the previous file at the previous location.
2563 * 2563 *
2564 * Results: 2564 * Results:
2565 * TRUE to continue parsing, i.e. it had only reached the end of an 2565 * TRUE to continue parsing, i.e. it had only reached the end of an
2566 * included file, FALSE if the main file has been parsed completely. 2566 * included file, FALSE if the main file has been parsed completely.
2567 */ 2567 */
2568static Boolean 2568static Boolean
2569ParseEOF(void) 2569ParseEOF(void)
2570{ 2570{
2571 char *ptr; 2571 char *ptr;
2572 size_t len; 2572 size_t len;
2573 IFile *curFile = CurFile(); 2573 IFile *curFile = CurFile();
2574 2574
2575 assert(curFile->nextbuf != NULL); 2575 assert(curFile->nextbuf != NULL);
2576 2576
2577 doing_depend = curFile->depending; /* restore this */ 2577 doing_depend = curFile->depending; /* restore this */
2578 /* get next input buffer, if any */ 2578 /* get next input buffer, if any */
2579 ptr = curFile->nextbuf(curFile->nextbuf_arg, &len); 2579 ptr = curFile->nextbuf(curFile->nextbuf_arg, &len);
2580 curFile->buf_ptr = ptr; 2580 curFile->buf_ptr = ptr;
2581 curFile->buf_freeIt = ptr; 2581 curFile->buf_freeIt = ptr;
2582 curFile->buf_end = ptr + len; 2582 curFile->buf_end = ptr + len;
2583 curFile->lineno = curFile->first_lineno; 2583 curFile->lineno = curFile->first_lineno;
2584 if (ptr != NULL) { 2584 if (ptr != NULL) {
2585 /* Iterate again */ 2585 /* Iterate again */
2586 return TRUE; 2586 return TRUE;
2587 } 2587 }
2588 2588
2589 /* Ensure the makefile (or loop) didn't have mismatched conditionals */ 2589 /* Ensure the makefile (or loop) didn't have mismatched conditionals */
2590 Cond_restore_depth(curFile->cond_depth); 2590 Cond_restore_depth(curFile->cond_depth);
2591 2591
2592 if (curFile->lf != NULL) { 2592 if (curFile->lf != NULL) {
2593 loadedfile_destroy(curFile->lf); 2593 loadedfile_destroy(curFile->lf);
2594 curFile->lf = NULL; 2594 curFile->lf = NULL;
2595 } 2595 }
2596 2596
2597 /* Dispose of curFile info */ 2597 /* Dispose of curFile info */
2598 /* Leak curFile->fname because all the gnodes have pointers to it */ 2598 /* Leak curFile->fname because all the gnodes have pointers to it */
2599 free(curFile->buf_freeIt); 2599 free(curFile->buf_freeIt);
2600 Vector_Pop(&includes); 2600 Vector_Pop(&includes);
2601 2601
2602 if (includes.len == 0) { 2602 if (includes.len == 0) {
2603 /* We've run out of input */ 2603 /* We've run out of input */
2604 Var_Delete(".PARSEDIR", VAR_GLOBAL); 2604 Var_Delete(".PARSEDIR", VAR_GLOBAL);
2605 Var_Delete(".PARSEFILE", VAR_GLOBAL); 2605 Var_Delete(".PARSEFILE", VAR_GLOBAL);
2606 Var_Delete(".INCLUDEDFROMDIR", VAR_GLOBAL); 2606 Var_Delete(".INCLUDEDFROMDIR", VAR_GLOBAL);
2607 Var_Delete(".INCLUDEDFROMFILE", VAR_GLOBAL); 2607 Var_Delete(".INCLUDEDFROMFILE", VAR_GLOBAL);
2608 return FALSE; 2608 return FALSE;
2609 } 2609 }
2610 2610
2611 curFile = CurFile(); 2611 curFile = CurFile();
2612 DEBUG2(PARSE, "ParseEOF: returning to file %s, line %d\n", 2612 DEBUG2(PARSE, "ParseEOF: returning to file %s, line %d\n",
2613 curFile->fname, curFile->lineno); 2613 curFile->fname, curFile->lineno);
2614 2614
2615 ParseSetParseFile(curFile->fname); 2615 ParseSetParseFile(curFile->fname);
2616 return TRUE; 2616 return TRUE;
2617} 2617}
2618 2618
2619#define PARSE_RAW 1 2619#define PARSE_RAW 1
2620#define PARSE_SKIP 2 2620#define PARSE_SKIP 2
2621 2621
2622static char * 2622static char *
2623ParseGetLine(int flags) 2623ParseGetLine(int flags)
2624{ 2624{
2625 IFile *cf = CurFile(); 2625 IFile *cf = CurFile();
2626 char *ptr; 2626 char *ptr;
2627 char ch; 2627 char ch;
2628 char *line; 2628 char *line;
2629 char *line_end; 2629 char *line_end;
2630 char *escaped; 2630 char *escaped;
2631 char *comment; 2631 char *comment;
2632 char *tp; 2632 char *tp;
2633 2633
2634 /* Loop through blank lines and comment lines */ 2634 /* Loop through blank lines and comment lines */
2635 for (;;) { 2635 for (;;) {
2636 cf->lineno++; 2636 cf->lineno++;
2637 line = cf->buf_ptr; 2637 line = cf->buf_ptr;
2638 ptr = line; 2638 ptr = line;
2639 line_end = line; 2639 line_end = line;
2640 escaped = NULL; 2640 escaped = NULL;
2641 comment = NULL; 2641 comment = NULL;
2642 for (;;) { 2642 for (;;) {
2643 /* XXX: can buf_end ever be null? */ 2643 /* XXX: can buf_end ever be null? */
2644 if (cf->buf_end != NULL && ptr == cf->buf_end) { 2644 if (cf->buf_end != NULL && ptr == cf->buf_end) {
2645 /* end of buffer */ 2645 /* end of buffer */
2646 ch = 0; 2646 ch = 0;
2647 break; 2647 break;
2648 } 2648 }
2649 ch = *ptr; 2649 ch = *ptr;
2650 if (ch == 0 || (ch == '\\' && ptr[1] == 0)) { 2650 if (ch == 0 || (ch == '\\' && ptr[1] == 0)) {
2651 /* XXX: can buf_end ever be null? */ 2651 /* XXX: can buf_end ever be null? */
2652 if (cf->buf_end == NULL) 2652 if (cf->buf_end == NULL)
2653 /* End of string (aka for loop) data */ 2653 /* End of string (aka for loop) data */
2654 break; 2654 break;
2655 /* see if there is more we can parse */ 2655 /* see if there is more we can parse */
2656 while (ptr++ < cf->buf_end) { 2656 while (ptr++ < cf->buf_end) {
2657 if ((ch = *ptr) == '\n') { 2657 if ((ch = *ptr) == '\n') {
2658 if (ptr > line && ptr[-1] == '\\') 2658 if (ptr > line && ptr[-1] == '\\')
2659 continue; 2659 continue;
2660 Parse_Error(PARSE_WARNING, 2660 Parse_Error(PARSE_WARNING,
2661 "Zero byte read from file, " 2661 "Zero byte read from file, "
2662 "skipping rest of line."); 2662 "skipping rest of line.");
2663 break; 2663 break;
2664 } 2664 }
2665 } 2665 }
2666 if (cf->nextbuf != NULL) { 2666 if (cf->nextbuf != NULL) {
2667 /* 2667 /*
2668 * End of this buffer; return EOF and outer logic 2668 * End of this buffer; return EOF and outer logic
2669 * will get the next one. (eww) 2669 * will get the next one. (eww)
2670 */ 2670 */
2671 break; 2671 break;
2672 } 2672 }
2673 Parse_Error(PARSE_FATAL, "Zero byte read from file"); 2673 Parse_Error(PARSE_FATAL, "Zero byte read from file");
2674 return NULL; 2674 return NULL;
2675 } 2675 }
2676 2676
2677 if (ch == '\\') { 2677 if (ch == '\\') {
2678 /* Don't treat next character as special, remember first one */ 2678 /* Don't treat next character as special, remember first one */
2679 if (escaped == NULL) 2679 if (escaped == NULL)
2680 escaped = ptr; 2680 escaped = ptr;
2681 if (ptr[1] == '\n') 2681 if (ptr[1] == '\n')
2682 cf->lineno++; 2682 cf->lineno++;
2683 ptr += 2; 2683 ptr += 2;
2684 line_end = ptr; 2684 line_end = ptr;
2685 continue; 2685 continue;
2686 } 2686 }
2687 if (ch == '#' && comment == NULL) { 2687 if (ch == '#' && comment == NULL) {
2688 /* Remember first '#' for comment stripping */ 2688 /* Remember first '#' for comment stripping */
2689 /* Unless previous char was '[', as in modifier :[#] */ 2689 /* Unless previous char was '[', as in modifier :[#] */
2690 if (!(ptr > line && ptr[-1] == '[')) 2690 if (!(ptr > line && ptr[-1] == '['))
2691 comment = line_end; 2691 comment = line_end;
2692 } 2692 }
2693 ptr++; 2693 ptr++;
2694 if (ch == '\n') 2694 if (ch == '\n')
2695 break; 2695 break;
2696 if (!ch_isspace(ch)) 2696 if (!ch_isspace(ch))
2697 /* We are not interested in trailing whitespace */ 2697 /* We are not interested in trailing whitespace */
2698 line_end = ptr; 2698 line_end = ptr;
2699 } 2699 }
2700 2700
2701 /* Save next 'to be processed' location */ 2701 /* Save next 'to be processed' location */
2702 cf->buf_ptr = ptr; 2702 cf->buf_ptr = ptr;
2703 2703
2704 /* Check we have a non-comment, non-blank line */ 2704 /* Check we have a non-comment, non-blank line */
2705 if (line_end == line || comment == line) { 2705 if (line_end == line || comment == line) {
2706 if (ch == 0) 2706 if (ch == 0)
2707 /* At end of file */ 2707 /* At end of file */
2708 return NULL; 2708 return NULL;
2709 /* Parse another line */ 2709 /* Parse another line */
2710 continue; 2710 continue;
2711 } 2711 }
2712 2712
2713 /* We now have a line of data */ 2713 /* We now have a line of data */
2714 *line_end = 0; 2714 *line_end = 0;
2715 2715
2716 if (flags & PARSE_RAW) { 2716 if (flags & PARSE_RAW) {
2717 /* Leave '\' (etc) in line buffer (eg 'for' lines) */ 2717 /* Leave '\' (etc) in line buffer (eg 'for' lines) */
2718 return line; 2718 return line;
2719 } 2719 }
2720 2720
2721 if (flags & PARSE_SKIP) { 2721 if (flags & PARSE_SKIP) {
2722 /* Completely ignore non-directives */ 2722 /* Completely ignore non-directives */
2723 if (line[0] != '.') 2723 if (line[0] != '.')
2724 continue; 2724 continue;
2725 /* We could do more of the .else/.elif/.endif checks here */ 2725 /* We could do more of the .else/.elif/.endif checks here */
2726 } 2726 }
2727 break; 2727 break;
2728 } 2728 }
2729 2729
2730 /* Brutally ignore anything after a non-escaped '#' in non-commands */ 2730 /* Brutally ignore anything after a non-escaped '#' in non-commands */
2731 if (comment != NULL && line[0] != '\t') { 2731 if (comment != NULL && line[0] != '\t') {
2732 line_end = comment; 2732 line_end = comment;
2733 *line_end = 0; 2733 *line_end = 0;
2734 } 2734 }
2735 2735
2736 /* If we didn't see a '\\' then the in-situ data is fine */ 2736 /* If we didn't see a '\\' then the in-situ data is fine */
2737 if (escaped == NULL) 2737 if (escaped == NULL)
2738 return line; 2738 return line;
2739 2739
2740 /* Remove escapes from '\n' and '#' */ 2740 /* Remove escapes from '\n' and '#' */
2741 tp = ptr = escaped; 2741 tp = ptr = escaped;
2742 escaped = line; 2742 escaped = line;
2743 for (; ; *tp++ = ch) { 2743 for (; ; *tp++ = ch) {
2744 ch = *ptr++; 2744 ch = *ptr++;
2745 if (ch != '\\') { 2745 if (ch != '\\') {
2746 if (ch == 0) 2746 if (ch == 0)
2747 break; 2747 break;
2748 continue; 2748 continue;
2749 } 2749 }
2750 2750
2751 ch = *ptr++; 2751 ch = *ptr++;
2752 if (ch == 0) { 2752 if (ch == 0) {
2753 /* Delete '\\' at end of buffer */ 2753 /* Delete '\\' at end of buffer */
2754 tp--; 2754 tp--;
2755 break; 2755 break;
2756 } 2756 }
2757 2757
2758 if (ch == '#' && line[0] != '\t') 2758 if (ch == '#' && line[0] != '\t')
2759 /* Delete '\\' from before '#' on non-command lines */ 2759 /* Delete '\\' from before '#' on non-command lines */
2760 continue; 2760 continue;
2761 2761
2762 if (ch != '\n') { 2762 if (ch != '\n') {
2763 /* Leave '\\' in buffer for later */ 2763 /* Leave '\\' in buffer for later */
2764 *tp++ = '\\'; 2764 *tp++ = '\\';
2765 /* Make sure we don't delete an escaped ' ' from the line end */ 2765 /* Make sure we don't delete an escaped ' ' from the line end */
2766 escaped = tp + 1; 2766 escaped = tp + 1;
2767 continue; 2767 continue;
2768 } 2768 }
2769 2769
2770 /* Escaped '\n' replace following whitespace with a single ' ' */ 2770 /* Escaped '\n' replace following whitespace with a single ' ' */
2771 while (ptr[0] == ' ' || ptr[0] == '\t') 2771 while (ptr[0] == ' ' || ptr[0] == '\t')
2772 ptr++; 2772 ptr++;
2773 ch = ' '; 2773 ch = ' ';
2774 } 2774 }
2775 2775
2776 /* Delete any trailing spaces - eg from empty continuations */ 2776 /* Delete any trailing spaces - eg from empty continuations */
2777 while (tp > escaped && ch_isspace(tp[-1])) 2777 while (tp > escaped && ch_isspace(tp[-1]))
2778 tp--; 2778 tp--;
2779 2779
2780 *tp = 0; 2780 *tp = 0;
2781 return line; 2781 return line;
2782} 2782}
2783 2783
2784/* Read an entire line from the input file. Called only by Parse_File. 2784/* Read an entire line from the input file. Called only by Parse_File.
2785 * 2785 *
2786 * Results: 2786 * Results:
2787 * A line without its newline. 2787 * A line without its newline.
2788 * 2788 *
2789 * Side Effects: 2789 * Side Effects:
2790 * Only those associated with reading a character 2790 * Only those associated with reading a character
2791 */ 2791 */
2792static char * 2792static char *
2793ParseReadLine(void) 2793ParseReadLine(void)
2794{ 2794{
2795 char *line; /* Result */ 2795 char *line; /* Result */
2796 int lineno; /* Saved line # */ 2796 int lineno; /* Saved line # */
2797 int rval; 2797 int rval;
2798 2798
2799 for (;;) { 2799 for (;;) {
2800 line = ParseGetLine(0); 2800 line = ParseGetLine(0);
2801 if (line == NULL) 2801 if (line == NULL)
2802 return NULL; 2802 return NULL;
2803 2803
2804 if (line[0] != '.') 2804 if (line[0] != '.')
2805 return line; 2805 return line;
2806 2806
2807 /* 2807 /*
2808 * The line might be a conditional. Ask the conditional module 2808 * The line might be a conditional. Ask the conditional module
2809 * about it and act accordingly 2809 * about it and act accordingly
2810 */ 2810 */
2811 switch (Cond_EvalLine(line)) { 2811 switch (Cond_EvalLine(line)) {
2812 case COND_SKIP: 2812 case COND_SKIP:
2813 /* Skip to next conditional that evaluates to COND_PARSE. */ 2813 /* Skip to next conditional that evaluates to COND_PARSE. */
2814 do { 2814 do {
2815 line = ParseGetLine(PARSE_SKIP); 2815 line = ParseGetLine(PARSE_SKIP);
2816 } while (line && Cond_EvalLine(line) != COND_PARSE); 2816 } while (line && Cond_EvalLine(line) != COND_PARSE);
2817 if (line == NULL) 2817 if (line == NULL)
2818 break; 2818 break;
2819 continue; 2819 continue;
2820 case COND_PARSE: 2820 case COND_PARSE:
2821 continue; 2821 continue;
2822 case COND_INVALID: /* Not a conditional line */ 2822 case COND_INVALID: /* Not a conditional line */
2823 /* Check for .for loops */ 2823 /* Check for .for loops */
2824 rval = For_Eval(line); 2824 rval = For_Eval(line);
2825 if (rval == 0) 2825 if (rval == 0)
2826 /* Not a .for line */ 2826 /* Not a .for line */
2827 break; 2827 break;
2828 if (rval < 0) 2828 if (rval < 0)
2829 /* Syntax error - error printed, ignore line */ 2829 /* Syntax error - error printed, ignore line */
2830 continue; 2830 continue;
2831 /* Start of a .for loop */ 2831 /* Start of a .for loop */
2832 lineno = CurFile()->lineno; 2832 lineno = CurFile()->lineno;
2833 /* Accumulate loop lines until matching .endfor */ 2833 /* Accumulate loop lines until matching .endfor */
2834 do { 2834 do {
2835 line = ParseGetLine(PARSE_RAW); 2835 line = ParseGetLine(PARSE_RAW);
2836 if (line == NULL) { 2836 if (line == NULL) {
2837 Parse_Error(PARSE_FATAL, 2837 Parse_Error(PARSE_FATAL,
2838 "Unexpected end of file in for loop."); 2838 "Unexpected end of file in for loop.");
2839 break; 2839 break;
2840 } 2840 }
2841 } while (For_Accum(line)); 2841 } while (For_Accum(line));
2842 /* Stash each iteration as a new 'input file' */ 2842 /* Stash each iteration as a new 'input file' */
2843 For_Run(lineno); 2843 For_Run(lineno);
2844 /* Read next line from for-loop buffer */ 2844 /* Read next line from for-loop buffer */
2845 continue; 2845 continue;
2846 } 2846 }
2847 return line; 2847 return line;
2848 } 2848 }
2849} 2849}
2850 2850
2851static void 2851static void
2852FinishDependencyGroup(void) 2852FinishDependencyGroup(void)
2853{ 2853{
2854 if (targets != NULL) { 2854 if (targets != NULL) {
2855 GNodeListNode *ln; 2855 GNodeListNode *ln;
2856 for (ln = targets->first; ln != NULL; ln = ln->next) { 2856 for (ln = targets->first; ln != NULL; ln = ln->next) {
2857 GNode *gn = ln->datum; 2857 GNode *gn = ln->datum;
2858 2858
2859 Suff_EndTransform(gn); 2859 Suff_EndTransform(gn);
2860 2860
2861 /* Mark the target as already having commands if it does, to 2861 /* Mark the target as already having commands if it does, to
2862 * keep from having shell commands on multiple dependency lines. */ 2862 * keep from having shell commands on multiple dependency lines. */
2863 if (!Lst_IsEmpty(gn->commands)) 2863 if (!Lst_IsEmpty(gn->commands))
2864 gn->type |= OP_HAS_COMMANDS; 2864 gn->type |= OP_HAS_COMMANDS;
2865 } 2865 }
2866 2866
2867 Lst_Free(targets); 2867 Lst_Free(targets);
2868 targets = NULL; 2868 targets = NULL;
2869 } 2869 }
2870} 2870}
2871 2871
2872/* Add the command to each target from the current dependency spec. */ 2872/* Add the command to each target from the current dependency spec. */
2873static void 2873static void
2874ParseLine_ShellCommand(const char *p) 2874ParseLine_ShellCommand(const char *p)
2875{ 2875{
2876 cpp_skip_whitespace(&p); 2876 cpp_skip_whitespace(&p);
2877 if (*p == '\0') 2877 if (*p == '\0')
2878 return; /* skip empty commands */ 2878 return; /* skip empty commands */
2879 2879
2880 if (targets == NULL) { 2880 if (targets == NULL) {
2881 Parse_Error(PARSE_FATAL, "Unassociated shell command \"%s\"", p); 2881 Parse_Error(PARSE_FATAL, "Unassociated shell command \"%s\"", p);
2882 return; 2882 return;
2883 } 2883 }
2884 2884
2885 { 2885 {
2886 char *cmd = bmake_strdup(p); 2886 char *cmd = bmake_strdup(p);
2887 GNodeListNode *ln; 2887 GNodeListNode *ln;
2888 2888
2889 for (ln = targets->first; ln != NULL; ln = ln->next) { 2889 for (ln = targets->first; ln != NULL; ln = ln->next) {
2890 GNode *gn = ln->datum; 2890 GNode *gn = ln->datum;
2891 ParseAddCmd(gn, cmd); 2891 ParseAddCmd(gn, cmd);
2892 } 2892 }
2893#ifdef CLEANUP 2893#ifdef CLEANUP
2894 Lst_Append(targCmds, cmd); 2894 Lst_Append(targCmds, cmd);
2895#endif 2895#endif
2896 } 2896 }
2897} 2897}
2898 2898
2899static Boolean 2899static Boolean
2900ParseDirective(char *line) 2900ParseDirective(char *line)
2901{ 2901{
2902 char *cp; 2902 char *cp;
2903 2903
2904 if (*line == '.') { 2904 if (*line == '.') {
2905 /* 2905 /*
2906 * Lines that begin with the special character may be 2906 * Lines that begin with the special character may be
2907 * include or undef directives. 2907 * include or undef directives.
2908 * On the other hand they can be suffix rules (.c.o: ...) 2908 * On the other hand they can be suffix rules (.c.o: ...)
2909 * or just dependencies for filenames that start '.'. 2909 * or just dependencies for filenames that start '.'.
2910 */ 2910 */
2911 cp = line + 1; 2911 cp = line + 1;
2912 pp_skip_whitespace(&cp); 2912 pp_skip_whitespace(&cp);
2913 if (IsInclude(cp, FALSE)) { 2913 if (IsInclude(cp, FALSE)) {
2914 ParseDoInclude(cp); 2914 ParseDoInclude(cp);
2915 return TRUE; 2915 return TRUE;
2916 } 2916 }
2917 if (strncmp(cp, "undef", 5) == 0) { 2917 if (strncmp(cp, "undef", 5) == 0) {
2918 const char *varname; 2918 const char *varname;
2919 cp += 5; 2919 cp += 5;
2920 pp_skip_whitespace(&cp); 2920 pp_skip_whitespace(&cp);
2921 varname = cp; 2921 varname = cp;
2922 for (; !ch_isspace(*cp) && *cp != '\0'; cp++) 2922 for (; !ch_isspace(*cp) && *cp != '\0'; cp++)
2923 continue; 2923 continue;
2924 *cp = '\0'; 2924 *cp = '\0';
2925 Var_Delete(varname, VAR_GLOBAL); 2925 Var_Delete(varname, VAR_GLOBAL);
2926 /* TODO: undefine all variables, not only the first */ 2926 /* TODO: undefine all variables, not only the first */
2927 /* TODO: use Str_Words, like everywhere else */ 2927 /* TODO: use Str_Words, like everywhere else */
2928 return TRUE; 2928 return TRUE;
2929 } else if (strncmp(cp, "export", 6) == 0) { 2929 } else if (strncmp(cp, "export", 6) == 0) {
2930 cp += 6; 2930 cp += 6;
2931 pp_skip_whitespace(&cp); 2931 pp_skip_whitespace(&cp);
2932 Var_Export(cp, TRUE); 2932 Var_Export(cp, TRUE);
2933 return TRUE; 2933 return TRUE;
2934 } else if (strncmp(cp, "unexport", 8) == 0) { 2934 } else if (strncmp(cp, "unexport", 8) == 0) {
2935 Var_UnExport(cp); 2935 Var_UnExport(cp);
2936 return TRUE; 2936 return TRUE;
2937 } else if (strncmp(cp, "info", 4) == 0 || 2937 } else if (strncmp(cp, "info", 4) == 0 ||
2938 strncmp(cp, "error", 5) == 0 || 2938 strncmp(cp, "error", 5) == 0 ||
2939 strncmp(cp, "warning", 7) == 0) { 2939 strncmp(cp, "warning", 7) == 0) {
2940 if (ParseMessage(cp)) 2940 if (ParseMessage(cp))
2941 return TRUE; 2941 return TRUE;
2942 } 2942 }
2943 } 2943 }
2944 return FALSE; 2944 return FALSE;
2945} 2945}
2946 2946
2947static Boolean 2947static Boolean
2948ParseVarassign(const char *line) 2948ParseVarassign(const char *line)
2949{ 2949{
2950 VarAssign var; 2950 VarAssign var;
2951 if (Parse_IsVar(line, &var)) { 2951 if (Parse_IsVar(line, &var)) {
2952 FinishDependencyGroup(); 2952 FinishDependencyGroup();
2953 Parse_DoVar(&var, VAR_GLOBAL); 2953 Parse_DoVar(&var, VAR_GLOBAL);
2954 return TRUE; 2954 return TRUE;
2955 } 2955 }
2956 return FALSE; 2956 return FALSE;
2957} 2957}
2958 2958
2959static char * 2959static char *
2960FindSemicolon(char *p) 2960FindSemicolon(char *p)
2961{ 2961{
2962 int level = 0; 2962 int level = 0;
2963 2963
2964 for (; *p != '\0'; p++) { 2964 for (; *p != '\0'; p++) {
2965 if (*p == '\\' && p[1] != '\0') { 2965 if (*p == '\\' && p[1] != '\0') {
2966 p++; 2966 p++;
2967 continue; 2967 continue;
2968 } 2968 }
2969 2969
2970 if (*p == '$' && (p[1] == '(' || p[1] == '{')) { 2970 if (*p == '$' && (p[1] == '(' || p[1] == '{')) {
2971 level++; 2971 level++;
2972 continue; 2972 continue;
2973 } 2973 }
2974 2974
2975 if (level > 0 && (*p == ')' || *p == '}')) { 2975 if (level > 0 && (*p == ')' || *p == '}')) {
2976 level--; 2976 level--;
2977 continue; 2977 continue;
2978 } 2978 }
2979 2979
2980 if (level == 0 && *p == ';') { 2980 if (level == 0 && *p == ';') {
2981 break; 2981 break;
2982 } 2982 }
2983 } 2983 }
2984 return p; 2984 return p;
2985} 2985}
2986 2986
2987/* dependency -> target... op [source...] 2987/* dependency -> target... op [source...]
2988 * op -> ':' | '::' | '!' */ 2988 * op -> ':' | '::' | '!' */
2989static void 2989static void
2990ParseDependency(char *line) 2990ParseDependency(char *line)
2991{ 2991{
2992 VarEvalFlags eflags; 2992 VarEvalFlags eflags;
2993 char *expanded_line; 2993 char *expanded_line;
2994 const char *shellcmd = NULL; 2994 const char *shellcmd = NULL;
2995 2995
2996 /* 2996 /*
2997 * For some reason - probably to make the parser impossible - 2997 * For some reason - probably to make the parser impossible -
2998 * a ';' can be used to separate commands from dependencies. 2998 * a ';' can be used to separate commands from dependencies.
2999 * Attempt to avoid ';' inside substitution patterns. 2999 * Attempt to avoid ';' inside substitution patterns.
3000 */ 3000 */
3001 { 3001 {
3002 char *semicolon = FindSemicolon(line); 3002 char *semicolon = FindSemicolon(line);
3003 if (*semicolon != '\0') { 3003 if (*semicolon != '\0') {
3004 /* Terminate the dependency list at the ';' */ 3004 /* Terminate the dependency list at the ';' */
3005 *semicolon = '\0'; 3005 *semicolon = '\0';
3006 shellcmd = semicolon + 1; 3006 shellcmd = semicolon + 1;
3007 } 3007 }
3008 } 3008 }
3009 3009
3010 /* 3010 /*
3011 * We now know it's a dependency line so it needs to have all 3011 * We now know it's a dependency line so it needs to have all
3012 * variables expanded before being parsed. 3012 * variables expanded before being parsed.
3013 * 3013 *
3014 * XXX: Ideally the dependency line would first be split into 3014 * XXX: Ideally the dependency line would first be split into
3015 * its left-hand side, dependency operator and right-hand side, 3015 * its left-hand side, dependency operator and right-hand side,
3016 * and then each side would be expanded on its own. This would 3016 * and then each side would be expanded on its own. This would
3017 * allow for the left-hand side to allow only defined variables 3017 * allow for the left-hand side to allow only defined variables
3018 * and to allow variables on the right-hand side to be undefined 3018 * and to allow variables on the right-hand side to be undefined
3019 * as well. 3019 * as well.
3020 * 3020 *
3021 * Parsing the line first would also prevent that targets 3021 * Parsing the line first would also prevent that targets
3022 * generated from variable expressions are interpreted as the 3022 * generated from variable expressions are interpreted as the
3023 * dependency operator, such as in "target${:U:} middle: source", 3023 * dependency operator, such as in "target${:U:} middle: source",
3024 * in which the middle is interpreted as a source, not a target. 3024 * in which the middle is interpreted as a source, not a target.
3025 */ 3025 */
3026 3026
3027 /* In lint mode, allow undefined variables to appear in 3027 /* In lint mode, allow undefined variables to appear in
3028 * dependency lines. 3028 * dependency lines.
3029 * 3029 *
3030 * Ideally, only the right-hand side would allow undefined 3030 * Ideally, only the right-hand side would allow undefined
3031 * variables since it is common to have no dependencies. 3031 * variables since it is common to have no dependencies.
3032 * Having undefined variables on the left-hand side is more 3032 * Having undefined variables on the left-hand side is more
3033 * unusual though. Since both sides are expanded in a single 3033 * unusual though. Since both sides are expanded in a single
3034 * pass, there is not much choice what to do here. 3034 * pass, there is not much choice what to do here.
3035 * 3035 *
3036 * In normal mode, it does not matter whether undefined 3036 * In normal mode, it does not matter whether undefined
3037 * variables are allowed or not since as of 2020-09-14, 3037 * variables are allowed or not since as of 2020-09-14,
3038 * Var_Parse does not print any parse errors in such a case. 3038 * Var_Parse does not print any parse errors in such a case.
3039 * It simply returns the special empty string var_Error, 3039 * It simply returns the special empty string var_Error,
3040 * which cannot be detected in the result of Var_Subst. */ 3040 * which cannot be detected in the result of Var_Subst. */
3041 eflags = DEBUG(LINT) ? VARE_WANTRES : VARE_UNDEFERR | VARE_WANTRES; 3041 eflags = DEBUG(LINT) ? VARE_WANTRES : VARE_UNDEFERR | VARE_WANTRES;
3042 (void)Var_Subst(line, VAR_CMDLINE, eflags, &expanded_line); 3042 (void)Var_Subst(line, VAR_CMDLINE, eflags, &expanded_line);
3043 /* TODO: handle errors */ 3043 /* TODO: handle errors */
3044 3044
3045 /* Need a fresh list for the target nodes */ 3045 /* Need a fresh list for the target nodes */
3046 if (targets != NULL) 3046 if (targets != NULL)
3047 Lst_Free(targets); 3047 Lst_Free(targets);
3048 targets = Lst_New(); 3048 targets = Lst_New();
3049 3049
3050 ParseDoDependency(expanded_line); 3050 ParseDoDependency(expanded_line);
3051 free(expanded_line); 3051 free(expanded_line);
3052 3052
3053 if (shellcmd != NULL) 3053 if (shellcmd != NULL)
3054 ParseLine_ShellCommand(shellcmd); 3054 ParseLine_ShellCommand(shellcmd);
3055} 3055}
3056 3056
3057static void 3057static void
3058ParseLine(char *line) 3058ParseLine(char *line)
3059{ 3059{
3060 if (ParseDirective(line)) 3060 if (ParseDirective(line))
3061 return; 3061 return;
3062 3062
3063 if (*line == '\t') { 3063 if (*line == '\t') {
3064 ParseLine_ShellCommand(line + 1); 3064 ParseLine_ShellCommand(line + 1);
3065 return; 3065 return;
3066 } 3066 }
3067 3067
3068#ifdef SYSVINCLUDE 3068#ifdef SYSVINCLUDE
3069 if (IsSysVInclude(line)) { 3069 if (IsSysVInclude(line)) {
3070 /* 3070 /*
3071 * It's an S3/S5-style "include". 3071 * It's an S3/S5-style "include".
3072 */ 3072 */
3073 ParseTraditionalInclude(line); 3073 ParseTraditionalInclude(line);
3074 return; 3074 return;
3075 } 3075 }
3076#endif 3076#endif
3077 3077
3078#ifdef GMAKEEXPORT 3078#ifdef GMAKEEXPORT
3079 if (strncmp(line, "export", 6) == 0 && ch_isspace(line[6]) && 3079 if (strncmp(line, "export", 6) == 0 && ch_isspace(line[6]) &&
3080 strchr(line, ':') == NULL) { 3080 strchr(line, ':') == NULL) {
3081 /* 3081 /*
3082 * It's a Gmake "export". 3082 * It's a Gmake "export".
3083 */ 3083 */
3084 ParseGmakeExport(line); 3084 ParseGmakeExport(line);
3085 return; 3085 return;
3086 } 3086 }
3087#endif 3087#endif
3088 3088
3089 if (ParseVarassign(line)) 3089 if (ParseVarassign(line))
3090 return; 3090 return;
3091 3091
3092 FinishDependencyGroup(); 3092 FinishDependencyGroup();
3093 3093
3094 ParseDependency(line); 3094 ParseDependency(line);
3095} 3095}
3096 3096
3097/* Parse a top-level makefile into its component parts, incorporating them 3097/* Parse a top-level makefile into its component parts, incorporating them
3098 * into the global dependency graph. 3098 * into the global dependency graph.
3099 * 3099 *
3100 * Input: 3100 * Input:
3101 * name The name of the file being read 3101 * name The name of the file being read
3102 * fd The open file to parse; will be closed at the end 3102 * fd The open file to parse; will be closed at the end
3103 */ 3103 */
3104void 3104void
3105Parse_File(const char *name, int fd) 3105Parse_File(const char *name, int fd)
3106{ 3106{
3107 char *line; /* the line we're working on */ 3107 char *line; /* the line we're working on */
3108 struct loadedfile *lf; 3108 struct loadedfile *lf;
3109 3109
3110 lf = loadfile(name, fd); 3110 lf = loadfile(name, fd);
3111 3111
3112 assert(targets == NULL); 3112 assert(targets == NULL);
3113 fatals = 0; 3113 fatals = 0;
3114 3114
3115 if (name == NULL) 3115 if (name == NULL)
3116 name = "(stdin)"; 3116 name = "(stdin)";
3117 3117
3118 Parse_SetInput(name, 0, -1, loadedfile_nextbuf, lf); 3118 Parse_SetInput(name, 0, -1, loadedfile_nextbuf, lf);
3119 CurFile()->lf = lf; 3119 CurFile()->lf = lf;
3120 3120
3121 do { 3121 do {
3122 while ((line = ParseReadLine()) != NULL) { 3122 while ((line = ParseReadLine()) != NULL) {
3123 DEBUG2(PARSE, "ParseReadLine (%d): '%s'\n", 3123 DEBUG2(PARSE, "ParseReadLine (%d): '%s'\n",
3124 CurFile()->lineno, line); 3124 CurFile()->lineno, line);
3125 ParseLine(line); 3125 ParseLine(line);
3126 } 3126 }
3127 /* 3127 /*
3128 * Reached EOF, but it may be just EOF of an include file... 3128 * Reached EOF, but it may be just EOF of an include file...
3129 */ 3129 */
3130 } while (ParseEOF()); 3130 } while (ParseEOF());
3131 3131
3132 FinishDependencyGroup(); 3132 FinishDependencyGroup();
3133 3133
3134 if (fatals) { 3134 if (fatals) {
3135 (void)fflush(stdout); 3135 (void)fflush(stdout);
3136 (void)fprintf(stderr, 3136 (void)fprintf(stderr,
3137 "%s: Fatal errors encountered -- cannot continue", 3137 "%s: Fatal errors encountered -- cannot continue",
3138 progname); 3138 progname);
3139 PrintOnError(NULL, NULL); 3139 PrintOnError(NULL, NULL);
3140 exit(1); 3140 exit(1);
3141 } 3141 }
3142} 3142}
3143 3143
3144/* Initialize the parsing module. */ 3144/* Initialize the parsing module. */
3145void 3145void
3146Parse_Init(void) 3146Parse_Init(void)
3147{ 3147{
3148 mainNode = NULL; 3148 mainNode = NULL;
3149 parseIncPath = Lst_New(); 3149 parseIncPath = Lst_New();
3150 sysIncPath = Lst_New(); 3150 sysIncPath = Lst_New();
3151 defSysIncPath = Lst_New(); 3151 defSysIncPath = Lst_New();
3152 Vector_Init(&includes, sizeof(IFile)); 3152 Vector_Init(&includes, sizeof(IFile));
3153#ifdef CLEANUP 3153#ifdef CLEANUP
3154 targCmds = Lst_New(); 3154 targCmds = Lst_New();
3155#endif 3155#endif
3156} 3156}
3157 3157
3158/* Clean up the parsing module. */ 3158/* Clean up the parsing module. */
3159void 3159void
3160Parse_End(void) 3160Parse_End(void)
3161{ 3161{
3162#ifdef CLEANUP 3162#ifdef CLEANUP
3163 Lst_Destroy(targCmds, free); 3163 Lst_Destroy(targCmds, free);
3164 assert(targets == NULL); 3164 assert(targets == NULL);
3165 Lst_Destroy(defSysIncPath, Dir_Destroy); 3165 Lst_Destroy(defSysIncPath, Dir_Destroy);
3166 Lst_Destroy(sysIncPath, Dir_Destroy); 3166 Lst_Destroy(sysIncPath, Dir_Destroy);
3167 Lst_Destroy(parseIncPath, Dir_Destroy); 3167 Lst_Destroy(parseIncPath, Dir_Destroy);
3168 assert(includes.len == 0); 3168 assert(includes.len == 0);
3169 Vector_Done(&includes); 3169 Vector_Done(&includes);
3170#endif 3170#endif
3171} 3171}
3172 3172
3173 3173
3174/*- 3174/*-
3175 *----------------------------------------------------------------------- 3175 *-----------------------------------------------------------------------
3176 * Parse_MainName -- 3176 * Parse_MainName --
3177 * Return a Lst of the main target to create for main()'s sake. If 3177 * Return a Lst of the main target to create for main()'s sake. If
3178 * no such target exists, we Punt with an obnoxious error message. 3178 * no such target exists, we Punt with an obnoxious error message.
3179 * 3179 *
3180 * Results: 3180 * Results:
3181 * A Lst of the single node to create. 3181 * A Lst of the single node to create.
3182 * 3182 *
3183 * Side Effects: 3183 * Side Effects:
3184 * None. 3184 * None.
3185 * 3185 *
3186 *----------------------------------------------------------------------- 3186 *-----------------------------------------------------------------------
3187 */ 3187 */
3188GNodeList * 3188GNodeList *
3189Parse_MainName(void) 3189Parse_MainName(void)
3190{ 3190{
3191 GNodeList *mainList; 3191 GNodeList *mainList;
3192 3192
3193 mainList = Lst_New(); 3193 mainList = Lst_New();
3194 3194
3195 if (mainNode == NULL) { 3195 if (mainNode == NULL) {
3196 Punt("no target to make."); 3196 Punt("no target to make.");
3197 /*NOTREACHED*/ 3197 /*NOTREACHED*/
3198 } else if (mainNode->type & OP_DOUBLEDEP) { 3198 } else if (mainNode->type & OP_DOUBLEDEP) {
3199 Lst_Append(mainList, mainNode); 3199 Lst_Append(mainList, mainNode);
3200 Lst_AppendAll(mainList, mainNode->cohorts); 3200 Lst_AppendAll(mainList, mainNode->cohorts);
3201 } else 3201 } else
3202 Lst_Append(mainList, mainNode); 3202 Lst_Append(mainList, mainNode);
3203 Var_Append(".TARGETS", mainNode->name, VAR_GLOBAL); 3203 Var_Append(".TARGETS", mainNode->name, VAR_GLOBAL);
3204 return mainList; 3204 return mainList;
3205} 3205}

cvs diff -r1.2 -r1.3 src/usr.bin/make/unit-tests/directive-include.exp (switch to unified diff)

--- src/usr.bin/make/unit-tests/directive-include.exp 2020/10/31 22:55:35 1.2
+++ src/usr.bin/make/unit-tests/directive-include.exp 2020/10/31 23:01:23 1.3
@@ -1,7 +1,5 @@ @@ -1,7 +1,5 @@
1CondParser_Eval: ${.MAKE.MAKEFILES:T} != "${.PARSEFILE} null" 1CondParser_Eval: ${.MAKE.MAKEFILES:T} != "${.PARSEFILE} null"
2lhs = "directive-include.mk null", rhs = "directive-include.mk null", op = != 2lhs = "directive-include.mk null", rhs = "directive-include.mk null", op = !=
3CondParser_Eval: ${.MAKE.MAKEFILES:T} != "${.PARSEFILE} null null" 3CondParser_Eval: ${.MAKE.MAKEFILES:T} != "${.PARSEFILE} null"
4lhs = "directive-include.mk null null", rhs = "directive-include.mk null null", op = != 4lhs = "directive-include.mk null", rhs = "directive-include.mk null", op = !=
5CondParser_Eval: ${.MAKE.MAKEFILES:T} != "${.PARSEFILE} null null" 
6lhs = "directive-include.mk null null", rhs = "directive-include.mk null null", op = != 
7exit status 0 5exit status 0

cvs diff -r1.2 -r1.3 src/usr.bin/make/unit-tests/directive-include.mk (switch to unified diff)

--- src/usr.bin/make/unit-tests/directive-include.mk 2020/10/31 22:55:35 1.2
+++ src/usr.bin/make/unit-tests/directive-include.mk 2020/10/31 23:01:23 1.3
@@ -1,33 +1,26 @@ @@ -1,33 +1,26 @@
1# $NetBSD: directive-include.mk,v 1.2 2020/10/31 22:55:35 rillig Exp $ 1# $NetBSD: directive-include.mk,v 1.3 2020/10/31 23:01:23 rillig Exp $
2# 2#
3# Tests for the .include directive, which includes another file. 3# Tests for the .include directive, which includes another file.
4 4
5# TODO: Implementation 5# TODO: Implementation
6 6
7.MAKEFLAGS: -dc 7.MAKEFLAGS: -dc
8 8
9# All included files are recorded in the variable .MAKE.MAKEFILES. 9# All included files are recorded in the variable .MAKE.MAKEFILES.
10# In this test, only the basenames of the files are compared since 10# In this test, only the basenames of the files are compared since
11# the directories can differ. 11# the directories can differ.
12.include "/dev/null" 12.include "/dev/null"
13.if ${.MAKE.MAKEFILES:T} != "${.PARSEFILE} null" 13.if ${.MAKE.MAKEFILES:T} != "${.PARSEFILE} null"
14. error 14. error
15.endif 15.endif
16 16
17# Each file is recorded only once in the variable .MAKE.MAKEFILES. 17# Each file is recorded only once in the variable .MAKE.MAKEFILES.
18# XXX: As of 2020-10-31, the very last file can be repeated, due to an 18# Between 2015-11-26 and 2020-10-31, the very last file could be repeated,
19# off-by-one bug in ParseTrackInput. 19# due to an off-by-one bug in ParseTrackInput.
20.include "/dev/null" 20.include "/dev/null"
21.if ${.MAKE.MAKEFILES:T} != "${.PARSEFILE} null null" 21.if ${.MAKE.MAKEFILES:T} != "${.PARSEFILE} null"
22. error 
23.endif 
24 
25# Since the file /dev/null is not only recorded at the very end of the 
26# variable .MAKE.MAKEFILES, it is not added a third time. 
27.include "/dev/null" 
28.if ${.MAKE.MAKEFILES:T} != "${.PARSEFILE} null null" 
29. error 22. error
30.endif 23.endif
31 24
32all: 25all:
33 @:; 26 @:;