Fri Jun 16 07:12:46 2023 UTC ()
make: remove parameter names from function declarations

No binary change.


(rillig)
diff -r1.345 -r1.346 src/usr.bin/make/cond.c
diff -r1.320 -r1.321 src/usr.bin/make/make.h

cvs diff -r1.345 -r1.346 src/usr.bin/make/cond.c (switch to unified diff)

--- src/usr.bin/make/cond.c 2023/06/01 07:44:10 1.345
+++ src/usr.bin/make/cond.c 2023/06/16 07:12:46 1.346
@@ -1,1175 +1,1175 @@ @@ -1,1175 +1,1175 @@
1/* $NetBSD: cond.c,v 1.345 2023/06/01 07:44:10 rillig Exp $ */ 1/* $NetBSD: cond.c,v 1.346 2023/06/16 07:12:46 rillig Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. 4 * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
5 * All rights reserved. 5 * 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) 1988, 1989 by Adam de Boor 36 * Copyright (c) 1988, 1989 by Adam de Boor
37 * Copyright (c) 1989 by Berkeley Softworks 37 * Copyright (c) 1989 by Berkeley Softworks
38 * All rights reserved. 38 * All rights reserved.
39 * 39 *
40 * This code is derived from software contributed to Berkeley by 40 * This code is derived from software contributed to Berkeley by
41 * Adam de Boor. 41 * Adam de Boor.
42 * 42 *
43 * Redistribution and use in source and binary forms, with or without 43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions 44 * modification, are permitted provided that the following conditions
45 * are met: 45 * are met:
46 * 1. Redistributions of source code must retain the above copyright 46 * 1. Redistributions of source code must retain the above copyright
47 * notice, this list of conditions and the following disclaimer. 47 * notice, this list of conditions and the following disclaimer.
48 * 2. Redistributions in binary form must reproduce the above copyright 48 * 2. Redistributions in binary form must reproduce the above copyright
49 * notice, this list of conditions and the following disclaimer in the 49 * notice, this list of conditions and the following disclaimer in the
50 * documentation and/or other materials provided with the distribution. 50 * documentation and/or other materials provided with the distribution.
51 * 3. All advertising materials mentioning features or use of this software 51 * 3. All advertising materials mentioning features or use of this software
52 * must display the following acknowledgement: 52 * must display the following acknowledgement:
53 * This product includes software developed by the University of 53 * This product includes software developed by the University of
54 * California, Berkeley and its contributors. 54 * California, Berkeley and its contributors.
55 * 4. Neither the name of the University nor the names of its contributors 55 * 4. Neither the name of the University nor the names of its contributors
56 * may be used to endorse or promote products derived from this software 56 * may be used to endorse or promote products derived from this software
57 * without specific prior written permission. 57 * without specific prior written permission.
58 * 58 *
59 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 59 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
60 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 60 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
61 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 61 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
62 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 62 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
63 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 63 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
64 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 64 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
65 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 65 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
66 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 66 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
67 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 67 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
68 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 68 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
69 * SUCH DAMAGE. 69 * SUCH DAMAGE.
70 */ 70 */
71 71
72/* 72/*
73 * Handling of conditionals in a makefile. 73 * Handling of conditionals in a makefile.
74 * 74 *
75 * Interface: 75 * Interface:
76 * Cond_EvalLine Evaluate the conditional directive, such as 76 * Cond_EvalLine Evaluate the conditional directive, such as
77 * '.if <cond>', '.elifnmake <cond>', '.else', '.endif'. 77 * '.if <cond>', '.elifnmake <cond>', '.else', '.endif'.
78 * 78 *
79 * Cond_EvalCondition 79 * Cond_EvalCondition
80 * Evaluate the conditional, which is either the argument 80 * Evaluate the conditional, which is either the argument
81 * of one of the .if directives or the condition in a 81 * of one of the .if directives or the condition in a
82 * ':?then:else' variable modifier. 82 * ':?then:else' variable modifier.
83 * 83 *
84 * Cond_EndFile 84 * Cond_EndFile
85 * At the end of reading a makefile, ensure that the 85 * At the end of reading a makefile, ensure that the
86 * conditional directives are well-balanced. 86 * conditional directives are well-balanced.
87 */ 87 */
88 88
89#include <errno.h> 89#include <errno.h>
90 90
91#include "make.h" 91#include "make.h"
92#include "dir.h" 92#include "dir.h"
93 93
94/* "@(#)cond.c 8.2 (Berkeley) 1/2/94" */ 94/* "@(#)cond.c 8.2 (Berkeley) 1/2/94" */
95MAKE_RCSID("$NetBSD: cond.c,v 1.345 2023/06/01 07:44:10 rillig Exp $"); 95MAKE_RCSID("$NetBSD: cond.c,v 1.346 2023/06/16 07:12:46 rillig Exp $");
96 96
97/* 97/*
98 * Conditional expressions conform to this grammar: 98 * Conditional expressions conform to this grammar:
99 * Or -> And ('||' And)* 99 * Or -> And ('||' And)*
100 * And -> Term ('&&' Term)* 100 * And -> Term ('&&' Term)*
101 * Term -> Function '(' Argument ')' 101 * Term -> Function '(' Argument ')'
102 * Term -> Leaf Operator Leaf 102 * Term -> Leaf Operator Leaf
103 * Term -> Leaf 103 * Term -> Leaf
104 * Term -> '(' Or ')' 104 * Term -> '(' Or ')'
105 * Term -> '!' Term 105 * Term -> '!' Term
106 * Leaf -> "string" 106 * Leaf -> "string"
107 * Leaf -> Number 107 * Leaf -> Number
108 * Leaf -> VariableExpression 108 * Leaf -> VariableExpression
109 * Leaf -> BareWord 109 * Leaf -> BareWord
110 * Operator -> '==' | '!=' | '>' | '<' | '>=' | '<=' 110 * Operator -> '==' | '!=' | '>' | '<' | '>=' | '<='
111 * 111 *
112 * BareWord is an unquoted string literal, its evaluation depends on the kind 112 * BareWord is an unquoted string literal, its evaluation depends on the kind
113 * of '.if' directive. 113 * of '.if' directive.
114 * 114 *
115 * The tokens are scanned by CondParser_Token, which returns: 115 * The tokens are scanned by CondParser_Token, which returns:
116 * TOK_AND for '&&' 116 * TOK_AND for '&&'
117 * TOK_OR for '||' 117 * TOK_OR for '||'
118 * TOK_NOT for '!' 118 * TOK_NOT for '!'
119 * TOK_LPAREN for '(' 119 * TOK_LPAREN for '('
120 * TOK_RPAREN for ')' 120 * TOK_RPAREN for ')'
121 * 121 *
122 * Other terminal symbols are evaluated using either the default function or 122 * Other terminal symbols are evaluated using either the default function or
123 * the function given in the terminal, they return either TOK_TRUE, TOK_FALSE 123 * the function given in the terminal, they return either TOK_TRUE, TOK_FALSE
124 * or TOK_ERROR. 124 * or TOK_ERROR.
125 */ 125 */
126typedef enum Token { 126typedef enum Token {
127 TOK_FALSE, TOK_TRUE, TOK_AND, TOK_OR, TOK_NOT, 127 TOK_FALSE, TOK_TRUE, TOK_AND, TOK_OR, TOK_NOT,
128 TOK_LPAREN, TOK_RPAREN, TOK_EOF, TOK_NONE, TOK_ERROR 128 TOK_LPAREN, TOK_RPAREN, TOK_EOF, TOK_NONE, TOK_ERROR
129} Token; 129} Token;
130 130
131typedef enum ComparisonOp { 131typedef enum ComparisonOp {
132 LT, LE, GT, GE, EQ, NE 132 LT, LE, GT, GE, EQ, NE
133} ComparisonOp; 133} ComparisonOp;
134 134
135typedef struct CondParser { 135typedef struct CondParser {
136 136
137 /* 137 /*
138 * The plain '.if ${VAR}' evaluates to true if the value of the 138 * The plain '.if ${VAR}' evaluates to true if the value of the
139 * expression has length > 0 and is not numerically zero. The other 139 * expression has length > 0 and is not numerically zero. The other
140 * '.if' variants delegate to evalBare instead, for example '.ifdef 140 * '.if' variants delegate to evalBare instead, for example '.ifdef
141 * ${VAR}' is equivalent to '.if defined(${VAR})', checking whether 141 * ${VAR}' is equivalent to '.if defined(${VAR})', checking whether
142 * the variable named by the expression '${VAR}' is defined. 142 * the variable named by the expression '${VAR}' is defined.
143 */ 143 */
144 bool plain; 144 bool plain;
145 145
146 /* The function to apply on unquoted bare words. */ 146 /* The function to apply on unquoted bare words. */
147 bool (*evalBare)(const char *); 147 bool (*evalBare)(const char *);
148 bool negateEvalBare; 148 bool negateEvalBare;
149 149
150 /* 150 /*
151 * Whether the left-hand side of a comparison may be an unquoted 151 * Whether the left-hand side of a comparison may be an unquoted
152 * string. This is allowed for expressions of the form 152 * string. This is allowed for expressions of the form
153 * ${condition:?:}, see ApplyModifier_IfElse. Such a condition is 153 * ${condition:?:}, see ApplyModifier_IfElse. Such a condition is
154 * expanded before it is evaluated, due to ease of implementation. 154 * expanded before it is evaluated, due to ease of implementation.
155 * This means that at the point where the condition is evaluated, 155 * This means that at the point where the condition is evaluated,
156 * make cannot know anymore whether the left-hand side had originally 156 * make cannot know anymore whether the left-hand side had originally
157 * been a variable expression or a plain word. 157 * been a variable expression or a plain word.
158 * 158 *
159 * In conditional directives like '.if', the left-hand side must 159 * In conditional directives like '.if', the left-hand side must
160 * either be a variable expression, a quoted string or a number. 160 * either be a variable expression, a quoted string or a number.
161 */ 161 */
162 bool leftUnquotedOK; 162 bool leftUnquotedOK;
163 163
164 const char *p; /* The remaining condition to parse */ 164 const char *p; /* The remaining condition to parse */
165 Token curr; /* Single push-back token used in parsing */ 165 Token curr; /* Single push-back token used in parsing */
166 166
167 /* 167 /*
168 * Whether an error message has already been printed for this 168 * Whether an error message has already been printed for this
169 * condition. The first available error message is usually the most 169 * condition. The first available error message is usually the most
170 * specific one, therefore it makes sense to suppress the standard 170 * specific one, therefore it makes sense to suppress the standard
171 * "Malformed conditional" message. 171 * "Malformed conditional" message.
172 */ 172 */
173 bool printedError; 173 bool printedError;
174} CondParser; 174} CondParser;
175 175
176static CondResult CondParser_Or(CondParser *par, bool); 176static CondResult CondParser_Or(CondParser *, bool);
177 177
178unsigned int cond_depth = 0; /* current .if nesting level */ 178unsigned int cond_depth = 0; /* current .if nesting level */
179 179
180/* Names for ComparisonOp. */ 180/* Names for ComparisonOp. */
181static const char opname[][3] = { "<", "<=", ">", ">=", "==", "!=" }; 181static const char opname[][3] = { "<", "<=", ">", ">=", "==", "!=" };
182 182
183MAKE_INLINE bool 183MAKE_INLINE bool
184skip_string(const char **pp, const char *str) 184skip_string(const char **pp, const char *str)
185{ 185{
186 size_t len = strlen(str); 186 size_t len = strlen(str);
187 bool ok = strncmp(*pp, str, len) == 0; 187 bool ok = strncmp(*pp, str, len) == 0;
188 if (ok) 188 if (ok)
189 *pp += len; 189 *pp += len;
190 return ok; 190 return ok;
191} 191}
192 192
193static Token 193static Token
194ToToken(bool cond) 194ToToken(bool cond)
195{ 195{
196 return cond ? TOK_TRUE : TOK_FALSE; 196 return cond ? TOK_TRUE : TOK_FALSE;
197} 197}
198 198
199static void 199static void
200CondParser_SkipWhitespace(CondParser *par) 200CondParser_SkipWhitespace(CondParser *par)
201{ 201{
202 cpp_skip_whitespace(&par->p); 202 cpp_skip_whitespace(&par->p);
203} 203}
204 204
205/* 205/*
206 * Parse a single word, taking into account balanced parentheses as well as 206 * Parse a single word, taking into account balanced parentheses as well as
207 * embedded expressions. Used for the argument of a built-in function as 207 * embedded expressions. Used for the argument of a built-in function as
208 * well as for bare words, which are then passed to the default function. 208 * well as for bare words, which are then passed to the default function.
209 */ 209 */
210static char * 210static char *
211ParseWord(const char **pp, bool doEval) 211ParseWord(const char **pp, bool doEval)
212{ 212{
213 const char *p = *pp; 213 const char *p = *pp;
214 Buffer word; 214 Buffer word;
215 int paren_depth; 215 int paren_depth;
216 216
217 Buf_InitSize(&word, 16); 217 Buf_InitSize(&word, 16);
218 218
219 paren_depth = 0; 219 paren_depth = 0;
220 for (;;) { 220 for (;;) {
221 char ch = *p; 221 char ch = *p;
222 if (ch == '\0' || ch == ' ' || ch == '\t') 222 if (ch == '\0' || ch == ' ' || ch == '\t')
223 break; 223 break;
224 if ((ch == '&' || ch == '|') && paren_depth == 0) 224 if ((ch == '&' || ch == '|') && paren_depth == 0)
225 break; 225 break;
226 if (ch == '$') { 226 if (ch == '$') {
227 /* 227 /*
228 * Parse the variable expression and install it as 228 * Parse the variable expression and install it as
229 * part of the argument if it's valid. We tell 229 * part of the argument if it's valid. We tell
230 * Var_Parse to complain on an undefined variable, 230 * Var_Parse to complain on an undefined variable,
231 * (XXX: but Var_Parse ignores that request) 231 * (XXX: but Var_Parse ignores that request)
232 * so we don't need to do it. Nor do we return an 232 * so we don't need to do it. Nor do we return an
233 * error, though perhaps we should. 233 * error, though perhaps we should.
234 */ 234 */
235 VarEvalMode emode = doEval 235 VarEvalMode emode = doEval
236 ? VARE_UNDEFERR 236 ? VARE_UNDEFERR
237 : VARE_PARSE_ONLY; 237 : VARE_PARSE_ONLY;
238 FStr nestedVal = Var_Parse(&p, SCOPE_CMDLINE, emode); 238 FStr nestedVal = Var_Parse(&p, SCOPE_CMDLINE, emode);
239 /* TODO: handle errors */ 239 /* TODO: handle errors */
240 Buf_AddStr(&word, nestedVal.str); 240 Buf_AddStr(&word, nestedVal.str);
241 FStr_Done(&nestedVal); 241 FStr_Done(&nestedVal);
242 continue; 242 continue;
243 } 243 }
244 if (ch == '(') 244 if (ch == '(')
245 paren_depth++; 245 paren_depth++;
246 else if (ch == ')' && --paren_depth < 0) 246 else if (ch == ')' && --paren_depth < 0)
247 break; 247 break;
248 Buf_AddByte(&word, ch); 248 Buf_AddByte(&word, ch);
249 p++; 249 p++;
250 } 250 }
251 251
252 cpp_skip_hspace(&p); 252 cpp_skip_hspace(&p);
253 *pp = p; 253 *pp = p;
254 254
255 return Buf_DoneData(&word); 255 return Buf_DoneData(&word);
256} 256}
257 257
258/* Parse the function argument, including the surrounding parentheses. */ 258/* Parse the function argument, including the surrounding parentheses. */
259static char * 259static char *
260ParseFuncArg(CondParser *par, const char **pp, bool doEval, const char *func) 260ParseFuncArg(CondParser *par, const char **pp, bool doEval, const char *func)
261{ 261{
262 const char *p = *pp; 262 const char *p = *pp;
263 char *res; 263 char *res;
264 264
265 p++; /* Skip opening '(' - verified by caller */ 265 p++; /* Skip opening '(' - verified by caller */
266 cpp_skip_hspace(&p); 266 cpp_skip_hspace(&p);
267 res = ParseWord(&p, doEval); 267 res = ParseWord(&p, doEval);
268 cpp_skip_hspace(&p); 268 cpp_skip_hspace(&p);
269 269
270 if (*p++ != ')') { 270 if (*p++ != ')') {
271 int len = 0; 271 int len = 0;
272 while (ch_isalpha(func[len])) 272 while (ch_isalpha(func[len]))
273 len++; 273 len++;
274 274
275 Parse_Error(PARSE_FATAL, 275 Parse_Error(PARSE_FATAL,
276 "Missing closing parenthesis for %.*s()", len, func); 276 "Missing closing parenthesis for %.*s()", len, func);
277 par->printedError = true; 277 par->printedError = true;
278 free(res); 278 free(res);
279 return NULL; 279 return NULL;
280 } 280 }
281 281
282 *pp = p; 282 *pp = p;
283 return res; 283 return res;
284} 284}
285 285
286/* See if the given variable is defined. */ 286/* See if the given variable is defined. */
287static bool 287static bool
288FuncDefined(const char *var) 288FuncDefined(const char *var)
289{ 289{
290 return Var_Exists(SCOPE_CMDLINE, var); 290 return Var_Exists(SCOPE_CMDLINE, var);
291} 291}
292 292
293/* See if a target matching targetPattern is requested to be made. */ 293/* See if a target matching targetPattern is requested to be made. */
294static bool 294static bool
295FuncMake(const char *targetPattern) 295FuncMake(const char *targetPattern)
296{ 296{
297 StringListNode *ln; 297 StringListNode *ln;
298 298
299 for (ln = opts.create.first; ln != NULL; ln = ln->next) 299 for (ln = opts.create.first; ln != NULL; ln = ln->next)
300 if (Str_Match(ln->datum, targetPattern)) 300 if (Str_Match(ln->datum, targetPattern))
301 return true; 301 return true;
302 return false; 302 return false;
303} 303}
304 304
305/* See if the given file exists. */ 305/* See if the given file exists. */
306static bool 306static bool
307FuncExists(const char *file) 307FuncExists(const char *file)
308{ 308{
309 bool result; 309 bool result;
310 char *path; 310 char *path;
311 311
312 path = Dir_FindFile(file, &dirSearchPath); 312 path = Dir_FindFile(file, &dirSearchPath);
313 DEBUG2(COND, "exists(%s) result is \"%s\"\n", 313 DEBUG2(COND, "exists(%s) result is \"%s\"\n",
314 file, path != NULL ? path : ""); 314 file, path != NULL ? path : "");
315 result = path != NULL; 315 result = path != NULL;
316 free(path); 316 free(path);
317 return result; 317 return result;
318} 318}
319 319
320/* See if the given node exists and is an actual target. */ 320/* See if the given node exists and is an actual target. */
321static bool 321static bool
322FuncTarget(const char *node) 322FuncTarget(const char *node)
323{ 323{
324 GNode *gn = Targ_FindNode(node); 324 GNode *gn = Targ_FindNode(node);
325 return gn != NULL && GNode_IsTarget(gn); 325 return gn != NULL && GNode_IsTarget(gn);
326} 326}
327 327
328/* 328/*
329 * See if the given node exists and is an actual target with commands 329 * See if the given node exists and is an actual target with commands
330 * associated with it. 330 * associated with it.
331 */ 331 */
332static bool 332static bool
333FuncCommands(const char *node) 333FuncCommands(const char *node)
334{ 334{
335 GNode *gn = Targ_FindNode(node); 335 GNode *gn = Targ_FindNode(node);
336 return gn != NULL && GNode_IsTarget(gn) && 336 return gn != NULL && GNode_IsTarget(gn) &&
337 !Lst_IsEmpty(&gn->commands); 337 !Lst_IsEmpty(&gn->commands);
338} 338}
339 339
340/* 340/*
341 * Convert the string to a floating point number. Accepted formats are 341 * Convert the string to a floating point number. Accepted formats are
342 * base-10 integer, base-16 integer and finite floating point numbers. 342 * base-10 integer, base-16 integer and finite floating point numbers.
343 */ 343 */
344static bool 344static bool
345TryParseNumber(const char *str, double *out_value) 345TryParseNumber(const char *str, double *out_value)
346{ 346{
347 char *end; 347 char *end;
348 unsigned long ul_val; 348 unsigned long ul_val;
349 double dbl_val; 349 double dbl_val;
350 350
351 if (str[0] == '\0') { /* XXX: why is an empty string a number? */ 351 if (str[0] == '\0') { /* XXX: why is an empty string a number? */
352 *out_value = 0.0; 352 *out_value = 0.0;
353 return true; 353 return true;
354 } 354 }
355 355
356 errno = 0; 356 errno = 0;
357 ul_val = strtoul(str, &end, str[1] == 'x' ? 16 : 10); 357 ul_val = strtoul(str, &end, str[1] == 'x' ? 16 : 10);
358 if (*end == '\0' && errno != ERANGE) { 358 if (*end == '\0' && errno != ERANGE) {
359 *out_value = str[0] == '-' ? -(double)-ul_val : (double)ul_val; 359 *out_value = str[0] == '-' ? -(double)-ul_val : (double)ul_val;
360 return true; 360 return true;
361 } 361 }
362 362
363 if (*end != '\0' && *end != '.' && *end != 'e' && *end != 'E') 363 if (*end != '\0' && *end != '.' && *end != 'e' && *end != 'E')
364 return false; /* skip the expensive strtod call */ 364 return false; /* skip the expensive strtod call */
365 dbl_val = strtod(str, &end); 365 dbl_val = strtod(str, &end);
366 if (*end != '\0') 366 if (*end != '\0')
367 return false; 367 return false;
368 368
369 *out_value = dbl_val; 369 *out_value = dbl_val;
370 return true; 370 return true;
371} 371}
372 372
373static bool 373static bool
374is_separator(char ch) 374is_separator(char ch)
375{ 375{
376 return ch == '\0' || ch_isspace(ch) || ch == '!' || ch == '=' || 376 return ch == '\0' || ch_isspace(ch) || ch == '!' || ch == '=' ||
377 ch == '>' || ch == '<' || ch == ')' /* but not '(' */; 377 ch == '>' || ch == '<' || ch == ')' /* but not '(' */;
378} 378}
379 379
380/* 380/*
381 * In a quoted or unquoted string literal or a number, parse a variable 381 * In a quoted or unquoted string literal or a number, parse a variable
382 * expression and add its value to the buffer. 382 * expression and add its value to the buffer.
383 * 383 *
384 * Return whether to continue parsing the leaf. 384 * Return whether to continue parsing the leaf.
385 * 385 *
386 * Example: .if x${CENTER}y == "${PREFIX}${SUFFIX}" || 0x${HEX} 386 * Example: .if x${CENTER}y == "${PREFIX}${SUFFIX}" || 0x${HEX}
387 */ 387 */
388static bool 388static bool
389CondParser_StringExpr(CondParser *par, const char *start, 389CondParser_StringExpr(CondParser *par, const char *start,
390 bool doEval, bool quoted, 390 bool doEval, bool quoted,
391 Buffer *buf, FStr *inout_str) 391 Buffer *buf, FStr *inout_str)
392{ 392{
393 VarEvalMode emode; 393 VarEvalMode emode;
394 const char *p; 394 const char *p;
395 bool atStart; 395 bool atStart;
396 396
397 emode = doEval && quoted ? VARE_WANTRES 397 emode = doEval && quoted ? VARE_WANTRES
398 : doEval ? VARE_UNDEFERR 398 : doEval ? VARE_UNDEFERR
399 : VARE_PARSE_ONLY; 399 : VARE_PARSE_ONLY;
400 400
401 p = par->p; 401 p = par->p;
402 atStart = p == start; 402 atStart = p == start;
403 *inout_str = Var_Parse(&p, SCOPE_CMDLINE, emode); 403 *inout_str = Var_Parse(&p, SCOPE_CMDLINE, emode);
404 /* TODO: handle errors */ 404 /* TODO: handle errors */
405 if (inout_str->str == var_Error) { 405 if (inout_str->str == var_Error) {
406 FStr_Done(inout_str); 406 FStr_Done(inout_str);
407 *inout_str = FStr_InitRefer(NULL); 407 *inout_str = FStr_InitRefer(NULL);
408 return false; 408 return false;
409 } 409 }
410 par->p = p; 410 par->p = p;
411 411
412 /* 412 /*
413 * If the '$' started the string literal (which means no quotes), and 413 * If the '$' started the string literal (which means no quotes), and
414 * the expression is followed by a space, a comparison operator or 414 * the expression is followed by a space, a comparison operator or
415 * the end of the expression, we are done. 415 * the end of the expression, we are done.
416 */ 416 */
417 if (atStart && is_separator(par->p[0])) 417 if (atStart && is_separator(par->p[0]))
418 return false; 418 return false;
419 419
420 Buf_AddStr(buf, inout_str->str); 420 Buf_AddStr(buf, inout_str->str);
421 FStr_Done(inout_str); 421 FStr_Done(inout_str);
422 *inout_str = FStr_InitRefer(NULL); /* not finished yet */ 422 *inout_str = FStr_InitRefer(NULL); /* not finished yet */
423 return true; 423 return true;
424} 424}
425 425
426/* 426/*
427 * Parse a string from a variable expression or an optionally quoted string, 427 * Parse a string from a variable expression or an optionally quoted string,
428 * on the left-hand and right-hand sides of comparisons. 428 * on the left-hand and right-hand sides of comparisons.
429 * 429 *
430 * Results: 430 * Results:
431 * Returns the string without any enclosing quotes, or NULL on error. 431 * Returns the string without any enclosing quotes, or NULL on error.
432 * Sets out_quoted if the leaf was a quoted string literal. 432 * Sets out_quoted if the leaf was a quoted string literal.
433 */ 433 */
434static void 434static void
435CondParser_Leaf(CondParser *par, bool doEval, bool unquotedOK, 435CondParser_Leaf(CondParser *par, bool doEval, bool unquotedOK,
436 FStr *out_str, bool *out_quoted) 436 FStr *out_str, bool *out_quoted)
437{ 437{
438 Buffer buf; 438 Buffer buf;
439 FStr str; 439 FStr str;
440 bool quoted; 440 bool quoted;
441 const char *start; 441 const char *start;
442 442
443 Buf_Init(&buf); 443 Buf_Init(&buf);
444 str = FStr_InitRefer(NULL); 444 str = FStr_InitRefer(NULL);
445 *out_quoted = quoted = par->p[0] == '"'; 445 *out_quoted = quoted = par->p[0] == '"';
446 start = par->p; 446 start = par->p;
447 if (quoted) 447 if (quoted)
448 par->p++; 448 par->p++;
449 449
450 while (par->p[0] != '\0' && str.str == NULL) { 450 while (par->p[0] != '\0' && str.str == NULL) {
451 switch (par->p[0]) { 451 switch (par->p[0]) {
452 case '\\': 452 case '\\':
453 par->p++; 453 par->p++;
454 if (par->p[0] != '\0') { 454 if (par->p[0] != '\0') {
455 Buf_AddByte(&buf, par->p[0]); 455 Buf_AddByte(&buf, par->p[0]);
456 par->p++; 456 par->p++;
457 } 457 }
458 continue; 458 continue;
459 case '"': 459 case '"':
460 par->p++; 460 par->p++;
461 if (quoted) 461 if (quoted)
462 goto return_buf; /* skip the closing quote */ 462 goto return_buf; /* skip the closing quote */
463 Buf_AddByte(&buf, '"'); 463 Buf_AddByte(&buf, '"');
464 continue; 464 continue;
465 case ')': /* see is_separator */ 465 case ')': /* see is_separator */
466 case '!': 466 case '!':
467 case '=': 467 case '=':
468 case '>': 468 case '>':
469 case '<': 469 case '<':
470 case ' ': 470 case ' ':
471 case '\t': 471 case '\t':
472 if (!quoted) 472 if (!quoted)
473 goto return_buf; 473 goto return_buf;
474 Buf_AddByte(&buf, par->p[0]); 474 Buf_AddByte(&buf, par->p[0]);
475 par->p++; 475 par->p++;
476 continue; 476 continue;
477 case '$': 477 case '$':
478 if (!CondParser_StringExpr(par, 478 if (!CondParser_StringExpr(par,
479 start, doEval, quoted, &buf, &str)) 479 start, doEval, quoted, &buf, &str))
480 goto return_str; 480 goto return_str;
481 continue; 481 continue;
482 default: 482 default:
483 if (!unquotedOK && !quoted && *start != '$' && 483 if (!unquotedOK && !quoted && *start != '$' &&
484 !ch_isdigit(*start)) { 484 !ch_isdigit(*start)) {
485 /* 485 /*
486 * The left-hand side must be quoted, 486 * The left-hand side must be quoted,
487 * a variable expression or a number. 487 * a variable expression or a number.
488 */ 488 */
489 str = FStr_InitRefer(NULL); 489 str = FStr_InitRefer(NULL);
490 goto return_str; 490 goto return_str;
491 } 491 }
492 Buf_AddByte(&buf, par->p[0]); 492 Buf_AddByte(&buf, par->p[0]);
493 par->p++; 493 par->p++;
494 continue; 494 continue;
495 } 495 }
496 } 496 }
497return_buf: 497return_buf:
498 str = FStr_InitOwn(buf.data); 498 str = FStr_InitOwn(buf.data);
499 buf.data = NULL; 499 buf.data = NULL;
500return_str: 500return_str:
501 Buf_Done(&buf); 501 Buf_Done(&buf);
502 *out_str = str; 502 *out_str = str;
503} 503}
504 504
505/* 505/*
506 * Evaluate a "comparison without operator", such as in ".if ${VAR}" or 506 * Evaluate a "comparison without operator", such as in ".if ${VAR}" or
507 * ".if 0". 507 * ".if 0".
508 */ 508 */
509static bool 509static bool
510EvalTruthy(CondParser *par, const char *value, bool quoted) 510EvalTruthy(CondParser *par, const char *value, bool quoted)
511{ 511{
512 double num; 512 double num;
513 513
514 /* For .ifxxx "...", check for non-empty string. */ 514 /* For .ifxxx "...", check for non-empty string. */
515 if (quoted) 515 if (quoted)
516 return value[0] != '\0'; 516 return value[0] != '\0';
517 517
518 /* For .ifxxx <number>, compare against zero */ 518 /* For .ifxxx <number>, compare against zero */
519 if (TryParseNumber(value, &num)) 519 if (TryParseNumber(value, &num))
520 return num != 0.0; 520 return num != 0.0;
521 521
522 /* 522 /*
523 * For .if ${...}, check for non-empty string. This is different 523 * For .if ${...}, check for non-empty string. This is different
524 * from the evaluation function from that .if variant, which would 524 * from the evaluation function from that .if variant, which would
525 * test whether a variable of the given name were defined. 525 * test whether a variable of the given name were defined.
526 */ 526 */
527 /* 527 /*
528 * XXX: Whitespace should count as empty, just as in 528 * XXX: Whitespace should count as empty, just as in
529 * CondParser_FuncCallEmpty. 529 * CondParser_FuncCallEmpty.
530 */ 530 */
531 if (par->plain) 531 if (par->plain)
532 return value[0] != '\0'; 532 return value[0] != '\0';
533 533
534 return par->evalBare(value) != par->negateEvalBare; 534 return par->evalBare(value) != par->negateEvalBare;
535} 535}
536 536
537/* Evaluate a numerical comparison, such as in ".if ${VAR} >= 9". */ 537/* Evaluate a numerical comparison, such as in ".if ${VAR} >= 9". */
538static bool 538static bool
539EvalCompareNum(double lhs, ComparisonOp op, double rhs) 539EvalCompareNum(double lhs, ComparisonOp op, double rhs)
540{ 540{
541 DEBUG3(COND, "Comparing %f %s %f\n", lhs, opname[op], rhs); 541 DEBUG3(COND, "Comparing %f %s %f\n", lhs, opname[op], rhs);
542 542
543 switch (op) { 543 switch (op) {
544 case LT: 544 case LT:
545 return lhs < rhs; 545 return lhs < rhs;
546 case LE: 546 case LE:
547 return lhs <= rhs; 547 return lhs <= rhs;
548 case GT: 548 case GT:
549 return lhs > rhs; 549 return lhs > rhs;
550 case GE: 550 case GE:
551 return lhs >= rhs; 551 return lhs >= rhs;
552 case EQ: 552 case EQ:
553 return lhs == rhs; 553 return lhs == rhs;
554 default: 554 default:
555 return lhs != rhs; 555 return lhs != rhs;
556 } 556 }
557} 557}
558 558
559static Token 559static Token
560EvalCompareStr(CondParser *par, const char *lhs, 560EvalCompareStr(CondParser *par, const char *lhs,
561 ComparisonOp op, const char *rhs) 561 ComparisonOp op, const char *rhs)
562{ 562{
563 if (op != EQ && op != NE) { 563 if (op != EQ && op != NE) {
564 Parse_Error(PARSE_FATAL, 564 Parse_Error(PARSE_FATAL,
565 "Comparison with '%s' requires both operands " 565 "Comparison with '%s' requires both operands "
566 "'%s' and '%s' to be numeric", 566 "'%s' and '%s' to be numeric",
567 opname[op], lhs, rhs); 567 opname[op], lhs, rhs);
568 par->printedError = true; 568 par->printedError = true;
569 return TOK_ERROR; 569 return TOK_ERROR;
570 } 570 }
571 571
572 DEBUG3(COND, "Comparing \"%s\" %s \"%s\"\n", lhs, opname[op], rhs); 572 DEBUG3(COND, "Comparing \"%s\" %s \"%s\"\n", lhs, opname[op], rhs);
573 return ToToken((op == EQ) == (strcmp(lhs, rhs) == 0)); 573 return ToToken((op == EQ) == (strcmp(lhs, rhs) == 0));
574} 574}
575 575
576/* Evaluate a comparison, such as "${VAR} == 12345". */ 576/* Evaluate a comparison, such as "${VAR} == 12345". */
577static Token 577static Token
578EvalCompare(CondParser *par, const char *lhs, bool lhsQuoted, 578EvalCompare(CondParser *par, const char *lhs, bool lhsQuoted,
579 ComparisonOp op, const char *rhs, bool rhsQuoted) 579 ComparisonOp op, const char *rhs, bool rhsQuoted)
580{ 580{
581 double left, right; 581 double left, right;
582 582
583 if (!rhsQuoted && !lhsQuoted) 583 if (!rhsQuoted && !lhsQuoted)
584 if (TryParseNumber(lhs, &left) && TryParseNumber(rhs, &right)) 584 if (TryParseNumber(lhs, &left) && TryParseNumber(rhs, &right))
585 return ToToken(EvalCompareNum(left, op, right)); 585 return ToToken(EvalCompareNum(left, op, right));
586 586
587 return EvalCompareStr(par, lhs, op, rhs); 587 return EvalCompareStr(par, lhs, op, rhs);
588} 588}
589 589
590static bool 590static bool
591CondParser_ComparisonOp(CondParser *par, ComparisonOp *out_op) 591CondParser_ComparisonOp(CondParser *par, ComparisonOp *out_op)
592{ 592{
593 const char *p = par->p; 593 const char *p = par->p;
594 594
595 if (p[0] == '<' && p[1] == '=') 595 if (p[0] == '<' && p[1] == '=')
596 return par->p += 2, *out_op = LE, true; 596 return par->p += 2, *out_op = LE, true;
597 if (p[0] == '<') 597 if (p[0] == '<')
598 return par->p += 1, *out_op = LT, true; 598 return par->p += 1, *out_op = LT, true;
599 if (p[0] == '>' && p[1] == '=') 599 if (p[0] == '>' && p[1] == '=')
600 return par->p += 2, *out_op = GE, true; 600 return par->p += 2, *out_op = GE, true;
601 if (p[0] == '>') 601 if (p[0] == '>')
602 return par->p += 1, *out_op = GT, true; 602 return par->p += 1, *out_op = GT, true;
603 if (p[0] == '=' && p[1] == '=') 603 if (p[0] == '=' && p[1] == '=')
604 return par->p += 2, *out_op = EQ, true; 604 return par->p += 2, *out_op = EQ, true;
605 if (p[0] == '!' && p[1] == '=') 605 if (p[0] == '!' && p[1] == '=')
606 return par->p += 2, *out_op = NE, true; 606 return par->p += 2, *out_op = NE, true;
607 return false; 607 return false;
608} 608}
609 609
610/* 610/*
611 * Parse a comparison condition such as: 611 * Parse a comparison condition such as:
612 * 612 *
613 * 0 613 * 0
614 * ${VAR:Mpattern} 614 * ${VAR:Mpattern}
615 * ${VAR} == value 615 * ${VAR} == value
616 * ${VAR:U0} < 12345 616 * ${VAR:U0} < 12345
617 */ 617 */
618static Token 618static Token
619CondParser_Comparison(CondParser *par, bool doEval) 619CondParser_Comparison(CondParser *par, bool doEval)
620{ 620{
621 Token t = TOK_ERROR; 621 Token t = TOK_ERROR;
622 FStr lhs, rhs; 622 FStr lhs, rhs;
623 ComparisonOp op; 623 ComparisonOp op;
624 bool lhsQuoted, rhsQuoted; 624 bool lhsQuoted, rhsQuoted;
625 625
626 CondParser_Leaf(par, doEval, par->leftUnquotedOK, &lhs, &lhsQuoted); 626 CondParser_Leaf(par, doEval, par->leftUnquotedOK, &lhs, &lhsQuoted);
627 if (lhs.str == NULL) 627 if (lhs.str == NULL)
628 goto done_lhs; 628 goto done_lhs;
629 629
630 CondParser_SkipWhitespace(par); 630 CondParser_SkipWhitespace(par);
631 631
632 if (!CondParser_ComparisonOp(par, &op)) { 632 if (!CondParser_ComparisonOp(par, &op)) {
633 /* Unknown operator, compare against an empty string or 0. */ 633 /* Unknown operator, compare against an empty string or 0. */
634 t = ToToken(doEval && EvalTruthy(par, lhs.str, lhsQuoted)); 634 t = ToToken(doEval && EvalTruthy(par, lhs.str, lhsQuoted));
635 goto done_lhs; 635 goto done_lhs;
636 } 636 }
637 637
638 CondParser_SkipWhitespace(par); 638 CondParser_SkipWhitespace(par);
639 639
640 if (par->p[0] == '\0') { 640 if (par->p[0] == '\0') {
641 Parse_Error(PARSE_FATAL, 641 Parse_Error(PARSE_FATAL,
642 "Missing right-hand side of operator '%s'", opname[op]); 642 "Missing right-hand side of operator '%s'", opname[op]);
643 par->printedError = true; 643 par->printedError = true;
644 goto done_lhs; 644 goto done_lhs;
645 } 645 }
646 646
647 CondParser_Leaf(par, doEval, true, &rhs, &rhsQuoted); 647 CondParser_Leaf(par, doEval, true, &rhs, &rhsQuoted);
648 t = rhs.str == NULL ? TOK_ERROR 648 t = rhs.str == NULL ? TOK_ERROR
649 : !doEval ? TOK_FALSE 649 : !doEval ? TOK_FALSE
650 : EvalCompare(par, lhs.str, lhsQuoted, op, rhs.str, rhsQuoted); 650 : EvalCompare(par, lhs.str, lhsQuoted, op, rhs.str, rhsQuoted);
651 FStr_Done(&rhs); 651 FStr_Done(&rhs);
652 652
653done_lhs: 653done_lhs:
654 FStr_Done(&lhs); 654 FStr_Done(&lhs);
655 return t; 655 return t;
656} 656}
657 657
658/* 658/*
659 * The argument to empty() is a variable name, optionally followed by 659 * The argument to empty() is a variable name, optionally followed by
660 * variable modifiers. 660 * variable modifiers.
661 */ 661 */
662static bool 662static bool
663CondParser_FuncCallEmpty(CondParser *par, bool doEval, Token *out_token) 663CondParser_FuncCallEmpty(CondParser *par, bool doEval, Token *out_token)
664{ 664{
665 const char *cp = par->p; 665 const char *cp = par->p;
666 Token tok; 666 Token tok;
667 FStr val; 667 FStr val;
668 668
669 if (!skip_string(&cp, "empty")) 669 if (!skip_string(&cp, "empty"))
670 return false; 670 return false;
671 671
672 cpp_skip_whitespace(&cp); 672 cpp_skip_whitespace(&cp);
673 if (*cp != '(') 673 if (*cp != '(')
674 return false; 674 return false;
675 675
676 cp--; /* Make cp[1] point to the '('. */ 676 cp--; /* Make cp[1] point to the '('. */
677 val = Var_Parse(&cp, SCOPE_CMDLINE, 677 val = Var_Parse(&cp, SCOPE_CMDLINE,
678 doEval ? VARE_WANTRES : VARE_PARSE_ONLY); 678 doEval ? VARE_WANTRES : VARE_PARSE_ONLY);
679 /* TODO: handle errors */ 679 /* TODO: handle errors */
680 680
681 if (val.str == var_Error) 681 if (val.str == var_Error)
682 tok = TOK_ERROR; 682 tok = TOK_ERROR;
683 else { 683 else {
684 cpp_skip_whitespace(&val.str); 684 cpp_skip_whitespace(&val.str);
685 tok = ToToken(doEval && val.str[0] == '\0'); 685 tok = ToToken(doEval && val.str[0] == '\0');
686 } 686 }
687 687
688 FStr_Done(&val); 688 FStr_Done(&val);
689 *out_token = tok; 689 *out_token = tok;
690 par->p = cp; 690 par->p = cp;
691 return true; 691 return true;
692} 692}
693 693
694/* Parse a function call expression, such as 'exists(${file})'. */ 694/* Parse a function call expression, such as 'exists(${file})'. */
695static bool 695static bool
696CondParser_FuncCall(CondParser *par, bool doEval, Token *out_token) 696CondParser_FuncCall(CondParser *par, bool doEval, Token *out_token)
697{ 697{
698 char *arg; 698 char *arg;
699 const char *p = par->p; 699 const char *p = par->p;
700 bool (*fn)(const char *); 700 bool (*fn)(const char *);
701 const char *fn_name = p; 701 const char *fn_name = p;
702 702
703 if (skip_string(&p, "defined")) 703 if (skip_string(&p, "defined"))
704 fn = FuncDefined; 704 fn = FuncDefined;
705 else if (skip_string(&p, "make")) 705 else if (skip_string(&p, "make"))
706 fn = FuncMake; 706 fn = FuncMake;
707 else if (skip_string(&p, "exists")) 707 else if (skip_string(&p, "exists"))
708 fn = FuncExists; 708 fn = FuncExists;
709 else if (skip_string(&p, "target")) 709 else if (skip_string(&p, "target"))
710 fn = FuncTarget; 710 fn = FuncTarget;
711 else if (skip_string(&p, "commands")) 711 else if (skip_string(&p, "commands"))
712 fn = FuncCommands; 712 fn = FuncCommands;
713 else 713 else
714 return false; 714 return false;
715 715
716 cpp_skip_whitespace(&p); 716 cpp_skip_whitespace(&p);
717 if (*p != '(') 717 if (*p != '(')
718 return false; 718 return false;
719 719
720 arg = ParseFuncArg(par, &p, doEval, fn_name); 720 arg = ParseFuncArg(par, &p, doEval, fn_name);
721 *out_token = ToToken(doEval && 721 *out_token = ToToken(doEval &&
722 arg != NULL && arg[0] != '\0' && fn(arg)); 722 arg != NULL && arg[0] != '\0' && fn(arg));
723 free(arg); 723 free(arg);
724 724
725 par->p = p; 725 par->p = p;
726 return true; 726 return true;
727} 727}
728 728
729/* 729/*
730 * Parse a comparison that neither starts with '"' nor '$', such as the 730 * Parse a comparison that neither starts with '"' nor '$', such as the
731 * unusual 'bare == right' or '3 == ${VAR}', or a simple leaf without 731 * unusual 'bare == right' or '3 == ${VAR}', or a simple leaf without
732 * operator, which is a number, a variable expression or a string literal. 732 * operator, which is a number, a variable expression or a string literal.
733 * 733 *
734 * TODO: Can this be merged into CondParser_Comparison? 734 * TODO: Can this be merged into CondParser_Comparison?
735 */ 735 */
736static Token 736static Token
737CondParser_ComparisonOrLeaf(CondParser *par, bool doEval) 737CondParser_ComparisonOrLeaf(CondParser *par, bool doEval)
738{ 738{
739 Token t; 739 Token t;
740 char *arg; 740 char *arg;
741 const char *cp; 741 const char *cp;
742 742
743 /* Push anything numeric through the compare expression */ 743 /* Push anything numeric through the compare expression */
744 cp = par->p; 744 cp = par->p;
745 if (ch_isdigit(cp[0]) || cp[0] == '-' || cp[0] == '+') 745 if (ch_isdigit(cp[0]) || cp[0] == '-' || cp[0] == '+')
746 return CondParser_Comparison(par, doEval); 746 return CondParser_Comparison(par, doEval);
747 747
748 /* 748 /*
749 * Most likely we have a naked token to apply the default function to. 749 * Most likely we have a naked token to apply the default function to.
750 * However ".if a == b" gets here when the "a" is unquoted and doesn't 750 * However ".if a == b" gets here when the "a" is unquoted and doesn't
751 * start with a '$'. This surprises people. 751 * start with a '$'. This surprises people.
752 * If what follows the function argument is a '=' or '!' then the 752 * If what follows the function argument is a '=' or '!' then the
753 * syntax would be invalid if we did "defined(a)" - so instead treat 753 * syntax would be invalid if we did "defined(a)" - so instead treat
754 * as an expression. 754 * as an expression.
755 */ 755 */
756 /* 756 /*
757 * XXX: In edge cases, a variable expression may be evaluated twice, 757 * XXX: In edge cases, a variable expression may be evaluated twice,
758 * see cond-token-plain.mk, keyword 'twice'. 758 * see cond-token-plain.mk, keyword 'twice'.
759 */ 759 */
760 arg = ParseWord(&cp, doEval); 760 arg = ParseWord(&cp, doEval);
761 assert(arg[0] != '\0'); 761 assert(arg[0] != '\0');
762 762
763 if (*cp == '=' || *cp == '!' || *cp == '<' || *cp == '>') 763 if (*cp == '=' || *cp == '!' || *cp == '<' || *cp == '>')
764 return CondParser_Comparison(par, doEval); 764 return CondParser_Comparison(par, doEval);
765 par->p = cp; 765 par->p = cp;
766 766
767 /* 767 /*
768 * Evaluate the argument using the default function. 768 * Evaluate the argument using the default function.
769 * This path always treats .if as .ifdef. To get here, the character 769 * This path always treats .if as .ifdef. To get here, the character
770 * after .if must have been taken literally, so the argument cannot 770 * after .if must have been taken literally, so the argument cannot
771 * be empty - even if it contained a variable expansion. 771 * be empty - even if it contained a variable expansion.
772 */ 772 */
773 t = ToToken(doEval && par->evalBare(arg) != par->negateEvalBare); 773 t = ToToken(doEval && par->evalBare(arg) != par->negateEvalBare);
774 free(arg); 774 free(arg);
775 return t; 775 return t;
776} 776}
777 777
778/* Return the next token or comparison result from the parser. */ 778/* Return the next token or comparison result from the parser. */
779static Token 779static Token
780CondParser_Token(CondParser *par, bool doEval) 780CondParser_Token(CondParser *par, bool doEval)
781{ 781{
782 Token t; 782 Token t;
783 783
784 t = par->curr; 784 t = par->curr;
785 if (t != TOK_NONE) { 785 if (t != TOK_NONE) {
786 par->curr = TOK_NONE; 786 par->curr = TOK_NONE;
787 return t; 787 return t;
788 } 788 }
789 789
790 cpp_skip_hspace(&par->p); 790 cpp_skip_hspace(&par->p);
791 791
792 switch (par->p[0]) { 792 switch (par->p[0]) {
793 793
794 case '(': 794 case '(':
795 par->p++; 795 par->p++;
796 return TOK_LPAREN; 796 return TOK_LPAREN;
797 797
798 case ')': 798 case ')':
799 par->p++; 799 par->p++;
800 return TOK_RPAREN; 800 return TOK_RPAREN;
801 801
802 case '|': 802 case '|':
803 par->p++; 803 par->p++;
804 if (par->p[0] == '|') 804 if (par->p[0] == '|')
805 par->p++; 805 par->p++;
806 else if (opts.strict) { 806 else if (opts.strict) {
807 Parse_Error(PARSE_FATAL, "Unknown operator '|'"); 807 Parse_Error(PARSE_FATAL, "Unknown operator '|'");
808 par->printedError = true; 808 par->printedError = true;
809 return TOK_ERROR; 809 return TOK_ERROR;
810 } 810 }
811 return TOK_OR; 811 return TOK_OR;
812 812
813 case '&': 813 case '&':
814 par->p++; 814 par->p++;
815 if (par->p[0] == '&') 815 if (par->p[0] == '&')
816 par->p++; 816 par->p++;
817 else if (opts.strict) { 817 else if (opts.strict) {
818 Parse_Error(PARSE_FATAL, "Unknown operator '&'"); 818 Parse_Error(PARSE_FATAL, "Unknown operator '&'");
819 par->printedError = true; 819 par->printedError = true;
820 return TOK_ERROR; 820 return TOK_ERROR;
821 } 821 }
822 return TOK_AND; 822 return TOK_AND;
823 823
824 case '!': 824 case '!':
825 par->p++; 825 par->p++;
826 return TOK_NOT; 826 return TOK_NOT;
827 827
828 case '#': /* XXX: see unit-tests/cond-token-plain.mk */ 828 case '#': /* XXX: see unit-tests/cond-token-plain.mk */
829 case '\n': /* XXX: why should this end the condition? */ 829 case '\n': /* XXX: why should this end the condition? */
830 /* Probably obsolete now, from 1993-03-21. */ 830 /* Probably obsolete now, from 1993-03-21. */
831 case '\0': 831 case '\0':
832 return TOK_EOF; 832 return TOK_EOF;
833 833
834 case '"': 834 case '"':
835 case '$': 835 case '$':
836 return CondParser_Comparison(par, doEval); 836 return CondParser_Comparison(par, doEval);
837 837
838 default: 838 default:
839 if (CondParser_FuncCallEmpty(par, doEval, &t)) 839 if (CondParser_FuncCallEmpty(par, doEval, &t))
840 return t; 840 return t;
841 if (CondParser_FuncCall(par, doEval, &t)) 841 if (CondParser_FuncCall(par, doEval, &t))
842 return t; 842 return t;
843 return CondParser_ComparisonOrLeaf(par, doEval); 843 return CondParser_ComparisonOrLeaf(par, doEval);
844 } 844 }
845} 845}
846 846
847/* Skip the next token if it equals t. */ 847/* Skip the next token if it equals t. */
848static bool 848static bool
849CondParser_Skip(CondParser *par, Token t) 849CondParser_Skip(CondParser *par, Token t)
850{ 850{
851 Token actual; 851 Token actual;
852 852
853 actual = CondParser_Token(par, false); 853 actual = CondParser_Token(par, false);
854 if (actual == t) 854 if (actual == t)
855 return true; 855 return true;
856 856
857 assert(par->curr == TOK_NONE); 857 assert(par->curr == TOK_NONE);
858 assert(actual != TOK_NONE); 858 assert(actual != TOK_NONE);
859 par->curr = actual; 859 par->curr = actual;
860 return false; 860 return false;
861} 861}
862 862
863/* 863/*
864 * Term -> '(' Or ')' 864 * Term -> '(' Or ')'
865 * Term -> '!' Term 865 * Term -> '!' Term
866 * Term -> Leaf Operator Leaf 866 * Term -> Leaf Operator Leaf
867 * Term -> Leaf 867 * Term -> Leaf
868 */ 868 */
869static CondResult 869static CondResult
870CondParser_Term(CondParser *par, bool doEval) 870CondParser_Term(CondParser *par, bool doEval)
871{ 871{
872 CondResult res; 872 CondResult res;
873 Token t; 873 Token t;
874 874
875 t = CondParser_Token(par, doEval); 875 t = CondParser_Token(par, doEval);
876 if (t == TOK_TRUE) 876 if (t == TOK_TRUE)
877 return CR_TRUE; 877 return CR_TRUE;
878 if (t == TOK_FALSE) 878 if (t == TOK_FALSE)
879 return CR_FALSE; 879 return CR_FALSE;
880 880
881 if (t == TOK_LPAREN) { 881 if (t == TOK_LPAREN) {
882 res = CondParser_Or(par, doEval); 882 res = CondParser_Or(par, doEval);
883 if (res == CR_ERROR) 883 if (res == CR_ERROR)
884 return CR_ERROR; 884 return CR_ERROR;
885 if (CondParser_Token(par, doEval) != TOK_RPAREN) 885 if (CondParser_Token(par, doEval) != TOK_RPAREN)
886 return CR_ERROR; 886 return CR_ERROR;
887 return res; 887 return res;
888 } 888 }
889 889
890 if (t == TOK_NOT) { 890 if (t == TOK_NOT) {
891 res = CondParser_Term(par, doEval); 891 res = CondParser_Term(par, doEval);
892 if (res == CR_TRUE) 892 if (res == CR_TRUE)
893 res = CR_FALSE; 893 res = CR_FALSE;
894 else if (res == CR_FALSE) 894 else if (res == CR_FALSE)
895 res = CR_TRUE; 895 res = CR_TRUE;
896 return res; 896 return res;
897 } 897 }
898 898
899 return CR_ERROR; 899 return CR_ERROR;
900} 900}
901 901
902/* 902/*
903 * And -> Term ('&&' Term)* 903 * And -> Term ('&&' Term)*
904 */ 904 */
905static CondResult 905static CondResult
906CondParser_And(CondParser *par, bool doEval) 906CondParser_And(CondParser *par, bool doEval)
907{ 907{
908 CondResult res, rhs; 908 CondResult res, rhs;
909 909
910 res = CR_TRUE; 910 res = CR_TRUE;
911 do { 911 do {
912 if ((rhs = CondParser_Term(par, doEval)) == CR_ERROR) 912 if ((rhs = CondParser_Term(par, doEval)) == CR_ERROR)
913 return CR_ERROR; 913 return CR_ERROR;
914 if (rhs == CR_FALSE) { 914 if (rhs == CR_FALSE) {
915 res = CR_FALSE; 915 res = CR_FALSE;
916 doEval = false; 916 doEval = false;
917 } 917 }
918 } while (CondParser_Skip(par, TOK_AND)); 918 } while (CondParser_Skip(par, TOK_AND));
919 919
920 return res; 920 return res;
921} 921}
922 922
923/* 923/*
924 * Or -> And ('||' And)* 924 * Or -> And ('||' And)*
925 */ 925 */
926static CondResult 926static CondResult
927CondParser_Or(CondParser *par, bool doEval) 927CondParser_Or(CondParser *par, bool doEval)
928{ 928{
929 CondResult res, rhs; 929 CondResult res, rhs;
930 930
931 res = CR_FALSE; 931 res = CR_FALSE;
932 do { 932 do {
933 if ((rhs = CondParser_And(par, doEval)) == CR_ERROR) 933 if ((rhs = CondParser_And(par, doEval)) == CR_ERROR)
934 return CR_ERROR; 934 return CR_ERROR;
935 if (rhs == CR_TRUE) { 935 if (rhs == CR_TRUE) {
936 res = CR_TRUE; 936 res = CR_TRUE;
937 doEval = false; 937 doEval = false;
938 } 938 }
939 } while (CondParser_Skip(par, TOK_OR)); 939 } while (CondParser_Skip(par, TOK_OR));
940 940
941 return res; 941 return res;
942} 942}
943 943
944static CondResult 944static CondResult
945CondParser_Eval(CondParser *par) 945CondParser_Eval(CondParser *par)
946{ 946{
947 CondResult res; 947 CondResult res;
948 948
949 DEBUG1(COND, "CondParser_Eval: %s\n", par->p); 949 DEBUG1(COND, "CondParser_Eval: %s\n", par->p);
950 950
951 res = CondParser_Or(par, true); 951 res = CondParser_Or(par, true);
952 if (res != CR_ERROR && CondParser_Token(par, false) != TOK_EOF) 952 if (res != CR_ERROR && CondParser_Token(par, false) != TOK_EOF)
953 return CR_ERROR; 953 return CR_ERROR;
954 954
955 return res; 955 return res;
956} 956}
957 957
958/* 958/*
959 * Evaluate the condition, including any side effects from the variable 959 * Evaluate the condition, including any side effects from the variable
960 * expressions in the condition. The condition consists of &&, ||, !, 960 * expressions in the condition. The condition consists of &&, ||, !,
961 * function(arg), comparisons and parenthetical groupings thereof. 961 * function(arg), comparisons and parenthetical groupings thereof.
962 */ 962 */
963static CondResult 963static CondResult
964CondEvalExpression(const char *cond, bool plain, 964CondEvalExpression(const char *cond, bool plain,
965 bool (*evalBare)(const char *), bool negate, 965 bool (*evalBare)(const char *), bool negate,
966 bool eprint, bool leftUnquotedOK) 966 bool eprint, bool leftUnquotedOK)
967{ 967{
968 CondParser par; 968 CondParser par;
969 CondResult rval; 969 CondResult rval;
970 970
971 cpp_skip_hspace(&cond); 971 cpp_skip_hspace(&cond);
972 972
973 par.plain = plain; 973 par.plain = plain;
974 par.evalBare = evalBare; 974 par.evalBare = evalBare;
975 par.negateEvalBare = negate; 975 par.negateEvalBare = negate;
976 par.leftUnquotedOK = leftUnquotedOK; 976 par.leftUnquotedOK = leftUnquotedOK;
977 par.p = cond; 977 par.p = cond;
978 par.curr = TOK_NONE; 978 par.curr = TOK_NONE;
979 par.printedError = false; 979 par.printedError = false;
980 980
981 rval = CondParser_Eval(&par); 981 rval = CondParser_Eval(&par);
982 982
983 if (rval == CR_ERROR && eprint && !par.printedError) 983 if (rval == CR_ERROR && eprint && !par.printedError)
984 Parse_Error(PARSE_FATAL, "Malformed conditional (%s)", cond); 984 Parse_Error(PARSE_FATAL, "Malformed conditional (%s)", cond);
985 985
986 return rval; 986 return rval;
987} 987}
988 988
989/* 989/*
990 * Evaluate a condition in a :? modifier, such as 990 * Evaluate a condition in a :? modifier, such as
991 * ${"${VAR}" == value:?yes:no}. 991 * ${"${VAR}" == value:?yes:no}.
992 */ 992 */
993CondResult 993CondResult
994Cond_EvalCondition(const char *cond) 994Cond_EvalCondition(const char *cond)
995{ 995{
996 return CondEvalExpression(cond, true, 996 return CondEvalExpression(cond, true,
997 FuncDefined, false, false, true); 997 FuncDefined, false, false, true);
998} 998}
999 999
1000static bool 1000static bool
1001IsEndif(const char *p) 1001IsEndif(const char *p)
1002{ 1002{
1003 return p[0] == 'e' && p[1] == 'n' && p[2] == 'd' && 1003 return p[0] == 'e' && p[1] == 'n' && p[2] == 'd' &&
1004 p[3] == 'i' && p[4] == 'f' && !ch_isalpha(p[5]); 1004 p[3] == 'i' && p[4] == 'f' && !ch_isalpha(p[5]);
1005} 1005}
1006 1006
1007static bool 1007static bool
1008DetermineKindOfConditional(const char **pp, bool *out_plain, 1008DetermineKindOfConditional(const char **pp, bool *out_plain,
1009 bool (**out_evalBare)(const char *), 1009 bool (**out_evalBare)(const char *),
1010 bool *out_negate) 1010 bool *out_negate)
1011{ 1011{
1012 const char *p = *pp + 2; 1012 const char *p = *pp + 2;
1013 1013
1014 *out_plain = false; 1014 *out_plain = false;
1015 *out_evalBare = FuncDefined; 1015 *out_evalBare = FuncDefined;
1016 *out_negate = skip_string(&p, "n"); 1016 *out_negate = skip_string(&p, "n");
1017 1017
1018 if (skip_string(&p, "def")) { /* .ifdef and .ifndef */ 1018 if (skip_string(&p, "def")) { /* .ifdef and .ifndef */
1019 } else if (skip_string(&p, "make")) /* .ifmake and .ifnmake */ 1019 } else if (skip_string(&p, "make")) /* .ifmake and .ifnmake */
1020 *out_evalBare = FuncMake; 1020 *out_evalBare = FuncMake;
1021 else if (!*out_negate) /* plain .if */ 1021 else if (!*out_negate) /* plain .if */
1022 *out_plain = true; 1022 *out_plain = true;
1023 else 1023 else
1024 goto unknown_directive; 1024 goto unknown_directive;
1025 if (ch_isalpha(*p)) 1025 if (ch_isalpha(*p))
1026 goto unknown_directive; 1026 goto unknown_directive;
1027 1027
1028 *pp = p; 1028 *pp = p;
1029 return true; 1029 return true;
1030 1030
1031unknown_directive: 1031unknown_directive:
1032 /* 1032 /*
1033 * TODO: Add error message about unknown directive, since there is no 1033 * TODO: Add error message about unknown directive, since there is no
1034 * other known directive that starts with 'el' or 'if'. 1034 * other known directive that starts with 'el' or 'if'.
1035 * 1035 *
1036 * Example: .elifx 123 1036 * Example: .elifx 123
1037 */ 1037 */
1038 return false; 1038 return false;
1039} 1039}
1040 1040
1041/* 1041/*
1042 * Evaluate the conditional directive in the line, which is one of: 1042 * Evaluate the conditional directive in the line, which is one of:
1043 * 1043 *
1044 * .if <cond> 1044 * .if <cond>
1045 * .ifmake <cond> 1045 * .ifmake <cond>
1046 * .ifnmake <cond> 1046 * .ifnmake <cond>
1047 * .ifdef <cond> 1047 * .ifdef <cond>
1048 * .ifndef <cond> 1048 * .ifndef <cond>
1049 * .elif <cond> 1049 * .elif <cond>
1050 * .elifmake <cond> 1050 * .elifmake <cond>
1051 * .elifnmake <cond> 1051 * .elifnmake <cond>
1052 * .elifdef <cond> 1052 * .elifdef <cond>
1053 * .elifndef <cond> 1053 * .elifndef <cond>
1054 * .else 1054 * .else
1055 * .endif 1055 * .endif
1056 * 1056 *
1057 * In these directives, <cond> consists of &&, ||, !, function(arg), 1057 * In these directives, <cond> consists of &&, ||, !, function(arg),
1058 * comparisons, expressions, bare words, numbers and strings, and 1058 * comparisons, expressions, bare words, numbers and strings, and
1059 * parenthetical groupings thereof. 1059 * parenthetical groupings thereof.
1060 * 1060 *
1061 * Results: 1061 * Results:
1062 * CR_TRUE to continue parsing the lines that follow the 1062 * CR_TRUE to continue parsing the lines that follow the
1063 * conditional (when <cond> evaluates to true) 1063 * conditional (when <cond> evaluates to true)
1064 * CR_FALSE to skip the lines after the conditional 1064 * CR_FALSE to skip the lines after the conditional
1065 * (when <cond> evaluates to false, or when a previous 1065 * (when <cond> evaluates to false, or when a previous
1066 * branch has already been taken) 1066 * branch has already been taken)
1067 * CR_ERROR if the conditional was not valid, either because of 1067 * CR_ERROR if the conditional was not valid, either because of
1068 * a syntax error or because some variable was undefined 1068 * a syntax error or because some variable was undefined
1069 * or because the condition could not be evaluated 1069 * or because the condition could not be evaluated
1070 */ 1070 */
1071CondResult 1071CondResult
1072Cond_EvalLine(const char *line) 1072Cond_EvalLine(const char *line)
1073{ 1073{
1074 typedef enum IfState { 1074 typedef enum IfState {
1075 1075
1076 /* None of the previous <cond> evaluated to true. */ 1076 /* None of the previous <cond> evaluated to true. */
1077 IFS_INITIAL = 0, 1077 IFS_INITIAL = 0,
1078 1078
1079 /* 1079 /*
1080 * The previous <cond> evaluated to true. The lines following 1080 * The previous <cond> evaluated to true. The lines following
1081 * this condition are interpreted. 1081 * this condition are interpreted.
1082 */ 1082 */
1083 IFS_ACTIVE = 1 << 0, 1083 IFS_ACTIVE = 1 << 0,
1084 1084
1085 /* The previous directive was an '.else'. */ 1085 /* The previous directive was an '.else'. */
1086 IFS_SEEN_ELSE = 1 << 1, 1086 IFS_SEEN_ELSE = 1 << 1,
1087 1087
1088 /* One of the previous <cond> evaluated to true. */ 1088 /* One of the previous <cond> evaluated to true. */
1089 IFS_WAS_ACTIVE = 1 << 2 1089 IFS_WAS_ACTIVE = 1 << 2
1090 1090
1091 } IfState; 1091 } IfState;
1092 1092
1093 static enum IfState *cond_states = NULL; 1093 static enum IfState *cond_states = NULL;
1094 static unsigned int cond_states_cap = 128; 1094 static unsigned int cond_states_cap = 128;
1095 1095
1096 bool plain; 1096 bool plain;
1097 bool (*evalBare)(const char *); 1097 bool (*evalBare)(const char *);
1098 bool negate; 1098 bool negate;
1099 bool isElif; 1099 bool isElif;
1100 CondResult res; 1100 CondResult res;
1101 IfState state; 1101 IfState state;
1102 const char *p = line; 1102 const char *p = line;
1103 1103
1104 if (cond_states == NULL) { 1104 if (cond_states == NULL) {
1105 cond_states = bmake_malloc( 1105 cond_states = bmake_malloc(
1106 cond_states_cap * sizeof *cond_states); 1106 cond_states_cap * sizeof *cond_states);
1107 cond_states[0] = IFS_ACTIVE; 1107 cond_states[0] = IFS_ACTIVE;
1108 } 1108 }
1109 1109
1110 p++; /* skip the leading '.' */ 1110 p++; /* skip the leading '.' */
1111 cpp_skip_hspace(&p); 1111 cpp_skip_hspace(&p);
1112 1112
1113 if (IsEndif(p)) { /* It is an '.endif'. */ 1113 if (IsEndif(p)) { /* It is an '.endif'. */
1114 if (p[5] != '\0') { 1114 if (p[5] != '\0') {
1115 Parse_Error(PARSE_FATAL, 1115 Parse_Error(PARSE_FATAL,
1116 "The .endif directive does not take arguments"); 1116 "The .endif directive does not take arguments");
1117 } 1117 }
1118 1118
1119 if (cond_depth == CurFile_CondMinDepth()) { 1119 if (cond_depth == CurFile_CondMinDepth()) {
1120 Parse_Error(PARSE_FATAL, "if-less endif"); 1120 Parse_Error(PARSE_FATAL, "if-less endif");
1121 return CR_TRUE; 1121 return CR_TRUE;
1122 } 1122 }
1123 1123
1124 /* Return state for previous conditional */ 1124 /* Return state for previous conditional */
1125 cond_depth--; 1125 cond_depth--;
1126 return cond_states[cond_depth] & IFS_ACTIVE 1126 return cond_states[cond_depth] & IFS_ACTIVE
1127 ? CR_TRUE : CR_FALSE; 1127 ? CR_TRUE : CR_FALSE;
1128 } 1128 }
1129 1129
1130 /* Parse the name of the directive, such as 'if', 'elif', 'endif'. */ 1130 /* Parse the name of the directive, such as 'if', 'elif', 'endif'. */
1131 if (p[0] == 'e') { 1131 if (p[0] == 'e') {
1132 if (p[1] != 'l') { 1132 if (p[1] != 'l') {
1133 /* 1133 /*
1134 * Unknown directive. It might still be a 1134 * Unknown directive. It might still be a
1135 * transformation rule like '.err.txt', 1135 * transformation rule like '.err.txt',
1136 * therefore no error message here. 1136 * therefore no error message here.
1137 */ 1137 */
1138 return CR_ERROR; 1138 return CR_ERROR;
1139 } 1139 }
1140 1140
1141 /* Quite likely this is 'else' or 'elif' */ 1141 /* Quite likely this is 'else' or 'elif' */
1142 p += 2; 1142 p += 2;
1143 if (strncmp(p, "se", 2) == 0 && !ch_isalpha(p[2])) { 1143 if (strncmp(p, "se", 2) == 0 && !ch_isalpha(p[2])) {
1144 if (p[2] != '\0') 1144 if (p[2] != '\0')
1145 Parse_Error(PARSE_FATAL, 1145 Parse_Error(PARSE_FATAL,
1146 "The .else directive " 1146 "The .else directive "
1147 "does not take arguments"); 1147 "does not take arguments");
1148 1148
1149 if (cond_depth == CurFile_CondMinDepth()) { 1149 if (cond_depth == CurFile_CondMinDepth()) {
1150 Parse_Error(PARSE_FATAL, "if-less else"); 1150 Parse_Error(PARSE_FATAL, "if-less else");
1151 return CR_TRUE; 1151 return CR_TRUE;
1152 } 1152 }
1153 1153
1154 state = cond_states[cond_depth]; 1154 state = cond_states[cond_depth];
1155 if (state == IFS_INITIAL) { 1155 if (state == IFS_INITIAL) {
1156 state = IFS_ACTIVE | IFS_SEEN_ELSE; 1156 state = IFS_ACTIVE | IFS_SEEN_ELSE;
1157 } else { 1157 } else {
1158 if (state & IFS_SEEN_ELSE) 1158 if (state & IFS_SEEN_ELSE)
1159 Parse_Error(PARSE_WARNING, 1159 Parse_Error(PARSE_WARNING,
1160 "extra else"); 1160 "extra else");
1161 state = IFS_WAS_ACTIVE | IFS_SEEN_ELSE; 1161 state = IFS_WAS_ACTIVE | IFS_SEEN_ELSE;
1162 } 1162 }
1163 cond_states[cond_depth] = state; 1163 cond_states[cond_depth] = state;
1164 1164
1165 return state & IFS_ACTIVE ? CR_TRUE : CR_FALSE; 1165 return state & IFS_ACTIVE ? CR_TRUE : CR_FALSE;
1166 } 1166 }
1167 /* Assume for now it is an elif */ 1167 /* Assume for now it is an elif */
1168 isElif = true; 1168 isElif = true;
1169 } else 1169 } else
1170 isElif = false; 1170 isElif = false;
1171 1171
1172 if (p[0] != 'i' || p[1] != 'f') { 1172 if (p[0] != 'i' || p[1] != 'f') {
1173 /* 1173 /*
1174 * Unknown directive. It might still be a transformation rule 1174 * Unknown directive. It might still be a transformation rule
1175 * like '.elisp.scm', therefore no error message here. 1175 * like '.elisp.scm', therefore no error message here.

cvs diff -r1.320 -r1.321 src/usr.bin/make/make.h (switch to unified diff)

--- src/usr.bin/make/make.h 2023/06/01 07:44:10 1.320
+++ src/usr.bin/make/make.h 2023/06/16 07:12:46 1.321
@@ -1,1199 +1,1199 @@ @@ -1,1199 +1,1199 @@
1/* $NetBSD: make.h,v 1.320 2023/06/01 07:44:10 rillig Exp $ */ 1/* $NetBSD: make.h,v 1.321 2023/06/16 07:12:46 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 * from: @(#)make.h 8.3 (Berkeley) 6/13/95 34 * from: @(#)make.h 8.3 (Berkeley) 6/13/95
35 */ 35 */
36 36
37/* 37/*
38 * Copyright (c) 1989 by Berkeley Softworks 38 * Copyright (c) 1989 by Berkeley Softworks
39 * All rights reserved. 39 * All rights reserved.
40 * 40 *
41 * This code is derived from software contributed to Berkeley by 41 * This code is derived from software contributed to Berkeley by
42 * Adam de Boor. 42 * Adam de Boor.
43 * 43 *
44 * Redistribution and use in source and binary forms, with or without 44 * Redistribution and use in source and binary forms, with or without
45 * modification, are permitted provided that the following conditions 45 * modification, are permitted provided that the following conditions
46 * are met: 46 * are met:
47 * 1. Redistributions of source code must retain the above copyright 47 * 1. Redistributions of source code must retain the above copyright
48 * notice, this list of conditions and the following disclaimer. 48 * notice, this list of conditions and the following disclaimer.
49 * 2. Redistributions in binary form must reproduce the above copyright 49 * 2. Redistributions in binary form must reproduce the above copyright
50 * notice, this list of conditions and the following disclaimer in the 50 * notice, this list of conditions and the following disclaimer in the
51 * documentation and/or other materials provided with the distribution. 51 * documentation and/or other materials provided with the distribution.
52 * 3. All advertising materials mentioning features or use of this software 52 * 3. All advertising materials mentioning features or use of this software
53 * must display the following acknowledgement: 53 * must display the following acknowledgement:
54 * This product includes software developed by the University of 54 * This product includes software developed by the University of
55 * California, Berkeley and its contributors. 55 * California, Berkeley and its contributors.
56 * 4. Neither the name of the University nor the names of its contributors 56 * 4. Neither the name of the University nor the names of its contributors
57 * may be used to endorse or promote products derived from this software 57 * may be used to endorse or promote products derived from this software
58 * without specific prior written permission. 58 * without specific prior written permission.
59 * 59 *
60 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 60 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
61 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 61 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
62 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 62 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
63 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 63 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
64 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 64 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
65 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 65 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
66 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 66 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
67 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 67 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
68 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 68 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
69 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 69 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
70 * SUCH DAMAGE. 70 * SUCH DAMAGE.
71 * 71 *
72 * from: @(#)make.h 8.3 (Berkeley) 6/13/95 72 * from: @(#)make.h 8.3 (Berkeley) 6/13/95
73 */ 73 */
74 74
75/* 75/*
76 * make.h -- 76 * make.h --
77 * The global definitions for make 77 * The global definitions for make
78 */ 78 */
79 79
80#ifndef MAKE_MAKE_H 80#ifndef MAKE_MAKE_H
81#define MAKE_MAKE_H 81#define MAKE_MAKE_H
82 82
83#include <sys/types.h> 83#include <sys/types.h>
84#include <sys/param.h> 84#include <sys/param.h>
85#include <sys/stat.h> 85#include <sys/stat.h>
86 86
87#include <assert.h> 87#include <assert.h>
88#include <ctype.h> 88#include <ctype.h>
89#include <fcntl.h> 89#include <fcntl.h>
90#include <stdarg.h> 90#include <stdarg.h>
91#include <stdio.h> 91#include <stdio.h>
92#include <stdlib.h> 92#include <stdlib.h>
93#include <string.h> 93#include <string.h>
94#include <unistd.h> 94#include <unistd.h>
95 95
96#ifdef BSD4_4 96#ifdef BSD4_4
97# include <sys/cdefs.h> 97# include <sys/cdefs.h>
98#endif 98#endif
99 99
100#ifndef FD_CLOEXEC 100#ifndef FD_CLOEXEC
101#define FD_CLOEXEC 1 101#define FD_CLOEXEC 1
102#endif 102#endif
103 103
104#if defined(__GNUC__) 104#if defined(__GNUC__)
105#define MAKE_GNUC_PREREQ(x, y) \ 105#define MAKE_GNUC_PREREQ(x, y) \
106 ((__GNUC__ == (x) && __GNUC_MINOR__ >= (y)) || \ 106 ((__GNUC__ == (x) && __GNUC_MINOR__ >= (y)) || \
107 (__GNUC__ > (x))) 107 (__GNUC__ > (x)))
108#else 108#else
109#define MAKE_GNUC_PREREQ(x, y) 0 109#define MAKE_GNUC_PREREQ(x, y) 0
110#endif 110#endif
111 111
112#if MAKE_GNUC_PREREQ(2, 7) 112#if MAKE_GNUC_PREREQ(2, 7)
113#define MAKE_ATTR_UNUSED __attribute__((__unused__)) 113#define MAKE_ATTR_UNUSED __attribute__((__unused__))
114#else 114#else
115#define MAKE_ATTR_UNUSED /* delete */ 115#define MAKE_ATTR_UNUSED /* delete */
116#endif 116#endif
117 117
118#if MAKE_GNUC_PREREQ(2, 5) 118#if MAKE_GNUC_PREREQ(2, 5)
119#define MAKE_ATTR_DEAD __attribute__((__noreturn__)) 119#define MAKE_ATTR_DEAD __attribute__((__noreturn__))
120#elif defined(__GNUC__) 120#elif defined(__GNUC__)
121#define MAKE_ATTR_DEAD __volatile 121#define MAKE_ATTR_DEAD __volatile
122#else 122#else
123#define MAKE_ATTR_DEAD /* delete */ 123#define MAKE_ATTR_DEAD /* delete */
124#endif 124#endif
125 125
126#if MAKE_GNUC_PREREQ(2, 7) 126#if MAKE_GNUC_PREREQ(2, 7)
127#define MAKE_ATTR_PRINTFLIKE(fmtarg, firstvararg) \ 127#define MAKE_ATTR_PRINTFLIKE(fmtarg, firstvararg) \
128 __attribute__((__format__ (__printf__, fmtarg, firstvararg))) 128 __attribute__((__format__ (__printf__, fmtarg, firstvararg)))
129#else 129#else
130#define MAKE_ATTR_PRINTFLIKE(fmtarg, firstvararg) /* delete */ 130#define MAKE_ATTR_PRINTFLIKE(fmtarg, firstvararg) /* delete */
131#endif 131#endif
132 132
133#if MAKE_GNUC_PREREQ(4, 0) 133#if MAKE_GNUC_PREREQ(4, 0)
134#define MAKE_ATTR_USE __attribute__((__warn_unused_result__)) 134#define MAKE_ATTR_USE __attribute__((__warn_unused_result__))
135#else 135#else
136#define MAKE_ATTR_USE /* delete */ 136#define MAKE_ATTR_USE /* delete */
137#endif 137#endif
138 138
139#if __STDC_VERSION__ >= 199901L || defined(lint) 139#if __STDC_VERSION__ >= 199901L || defined(lint)
140#define MAKE_INLINE static inline MAKE_ATTR_UNUSED 140#define MAKE_INLINE static inline MAKE_ATTR_UNUSED
141#else 141#else
142#define MAKE_INLINE static MAKE_ATTR_UNUSED 142#define MAKE_INLINE static MAKE_ATTR_UNUSED
143#endif 143#endif
144 144
145/* MAKE_STATIC marks a function that may or may not be inlined. */ 145/* MAKE_STATIC marks a function that may or may not be inlined. */
146#if defined(lint) 146#if defined(lint)
147/* As of 2021-07-31, NetBSD lint ignores __attribute__((unused)). */ 147/* As of 2021-07-31, NetBSD lint ignores __attribute__((unused)). */
148#define MAKE_STATIC MAKE_INLINE 148#define MAKE_STATIC MAKE_INLINE
149#else 149#else
150#define MAKE_STATIC static MAKE_ATTR_UNUSED 150#define MAKE_STATIC static MAKE_ATTR_UNUSED
151#endif 151#endif
152 152
153#if __STDC_VERSION__ >= 199901L || defined(lint) || defined(USE_C99_BOOLEAN) 153#if __STDC_VERSION__ >= 199901L || defined(lint) || defined(USE_C99_BOOLEAN)
154#include <stdbool.h> 154#include <stdbool.h>
155#elif defined(__bool_true_false_are_defined) 155#elif defined(__bool_true_false_are_defined)
156/* 156/*
157 * All files of make must be compiled with the same definition of bool. 157 * All files of make must be compiled with the same definition of bool.
158 * Since one of the files includes <stdbool.h>, that means the header is 158 * Since one of the files includes <stdbool.h>, that means the header is
159 * available on this platform. Recompile everything with -DUSE_C99_BOOLEAN. 159 * available on this platform. Recompile everything with -DUSE_C99_BOOLEAN.
160 */ 160 */
161#error "<stdbool.h> is included in pre-C99 mode" 161#error "<stdbool.h> is included in pre-C99 mode"
162#elif defined(bool) || defined(true) || defined(false) 162#elif defined(bool) || defined(true) || defined(false)
163/* 163/*
164 * In pre-C99 mode, make does not expect that bool is already defined. 164 * In pre-C99 mode, make does not expect that bool is already defined.
165 * You need to ensure that all translation units use the same definition for 165 * You need to ensure that all translation units use the same definition for
166 * bool. 166 * bool.
167 */ 167 */
168#error "bool/true/false is defined in pre-C99 mode" 168#error "bool/true/false is defined in pre-C99 mode"
169#else 169#else
170typedef unsigned char bool; 170typedef unsigned char bool;
171#define true 1 171#define true 1
172#define false 0 172#define false 0
173#endif 173#endif
174 174
175#include "lst.h" 175#include "lst.h"
176#include "make_malloc.h" 176#include "make_malloc.h"
177#include "str.h" 177#include "str.h"
178#include "hash.h" 178#include "hash.h"
179#include "config.h" 179#include "config.h"
180#include "buf.h" 180#include "buf.h"
181 181
182/* 182/*
183 * The typical flow of states is: 183 * The typical flow of states is:
184 * 184 *
185 * The direct successful path: 185 * The direct successful path:
186 * UNMADE -> BEINGMADE -> MADE. 186 * UNMADE -> BEINGMADE -> MADE.
187 * 187 *
188 * The direct error path: 188 * The direct error path:
189 * UNMADE -> BEINGMADE -> ERROR. 189 * UNMADE -> BEINGMADE -> ERROR.
190 * 190 *
191 * The successful path when dependencies need to be made first: 191 * The successful path when dependencies need to be made first:
192 * UNMADE -> DEFERRED -> REQUESTED -> BEINGMADE -> MADE. 192 * UNMADE -> DEFERRED -> REQUESTED -> BEINGMADE -> MADE.
193 * 193 *
194 * A node that has dependencies, and one of the dependencies cannot be made: 194 * A node that has dependencies, and one of the dependencies cannot be made:
195 * UNMADE -> DEFERRED -> ABORTED. 195 * UNMADE -> DEFERRED -> ABORTED.
196 * 196 *
197 * A node that turns out to be up-to-date: 197 * A node that turns out to be up-to-date:
198 * UNMADE -> BEINGMADE -> UPTODATE. 198 * UNMADE -> BEINGMADE -> UPTODATE.
199 */ 199 */
200typedef enum GNodeMade { 200typedef enum GNodeMade {
201 /* Not examined yet. */ 201 /* Not examined yet. */
202 UNMADE, 202 UNMADE,
203 /* 203 /*
204 * The node has been examined but is not yet ready since its 204 * The node has been examined but is not yet ready since its
205 * dependencies have to be made first. 205 * dependencies have to be made first.
206 */ 206 */
207 DEFERRED, 207 DEFERRED,
208 208
209 /* The node is on the toBeMade list. */ 209 /* The node is on the toBeMade list. */
210 REQUESTED, 210 REQUESTED,
211 211
212 /* 212 /*
213 * The node is already being made. Trying to build a node in this 213 * The node is already being made. Trying to build a node in this
214 * state indicates a cycle in the graph. 214 * state indicates a cycle in the graph.
215 */ 215 */
216 BEINGMADE, 216 BEINGMADE,
217 217
218 /* Was out-of-date and has been made. */ 218 /* Was out-of-date and has been made. */
219 MADE, 219 MADE,
220 /* Was already up-to-date, does not need to be made. */ 220 /* Was already up-to-date, does not need to be made. */
221 UPTODATE, 221 UPTODATE,
222 /* 222 /*
223 * An error occurred while it was being made. Used only in compat 223 * An error occurred while it was being made. Used only in compat
224 * mode. 224 * mode.
225 */ 225 */
226 ERROR, 226 ERROR,
227 /* 227 /*
228 * The target was aborted due to an error making a dependency. Used 228 * The target was aborted due to an error making a dependency. Used
229 * only in compat mode. 229 * only in compat mode.
230 */ 230 */
231 ABORTED 231 ABORTED
232} GNodeMade; 232} GNodeMade;
233 233
234/* 234/*
235 * The OP_ constants are used when parsing a dependency line as a way of 235 * The OP_ constants are used when parsing a dependency line as a way of
236 * communicating to other parts of the program the way in which a target 236 * communicating to other parts of the program the way in which a target
237 * should be made. 237 * should be made.
238 * 238 *
239 * Some of the OP_ constants can be combined, others cannot. 239 * Some of the OP_ constants can be combined, others cannot.
240 * 240 *
241 * See the tests depsrc-*.mk and deptgt-*.mk. 241 * See the tests depsrc-*.mk and deptgt-*.mk.
242 */ 242 */
243typedef enum GNodeType { 243typedef enum GNodeType {
244 OP_NONE = 0, 244 OP_NONE = 0,
245 245
246 /* 246 /*
247 * The dependency operator ':' is the most common one. The commands 247 * The dependency operator ':' is the most common one. The commands
248 * of this node are executed if any child is out-of-date. 248 * of this node are executed if any child is out-of-date.
249 */ 249 */
250 OP_DEPENDS = 1 << 0, 250 OP_DEPENDS = 1 << 0,
251 /* 251 /*
252 * The dependency operator '!' always executes its commands, even if 252 * The dependency operator '!' always executes its commands, even if
253 * its children are up-to-date. 253 * its children are up-to-date.
254 */ 254 */
255 OP_FORCE = 1 << 1, 255 OP_FORCE = 1 << 1,
256 /* 256 /*
257 * The dependency operator '::' behaves like ':', except that it 257 * The dependency operator '::' behaves like ':', except that it
258 * allows multiple dependency groups to be defined. Each of these 258 * allows multiple dependency groups to be defined. Each of these
259 * groups is executed on its own, independently from the others. Each 259 * groups is executed on its own, independently from the others. Each
260 * individual dependency group is called a cohort. 260 * individual dependency group is called a cohort.
261 */ 261 */
262 OP_DOUBLEDEP = 1 << 2, 262 OP_DOUBLEDEP = 1 << 2,
263 263
264 /* Matches the dependency operators ':', '!' and '::'. */ 264 /* Matches the dependency operators ':', '!' and '::'. */
265 OP_OPMASK = OP_DEPENDS | OP_FORCE | OP_DOUBLEDEP, 265 OP_OPMASK = OP_DEPENDS | OP_FORCE | OP_DOUBLEDEP,
266 266
267 /* Don't care if the target doesn't exist and can't be created. */ 267 /* Don't care if the target doesn't exist and can't be created. */
268 OP_OPTIONAL = 1 << 3, 268 OP_OPTIONAL = 1 << 3,
269 /* Use associated commands for parents. */ 269 /* Use associated commands for parents. */
270 OP_USE = 1 << 4, 270 OP_USE = 1 << 4,
271 /* 271 /*
272 * Target is never out of date, but always execute commands anyway. 272 * Target is never out of date, but always execute commands anyway.
273 * Its time doesn't matter, so it has none...sort of. 273 * Its time doesn't matter, so it has none...sort of.
274 */ 274 */
275 OP_EXEC = 1 << 5, 275 OP_EXEC = 1 << 5,
276 /* 276 /*
277 * Ignore non-zero exit status from shell commands when creating the 277 * Ignore non-zero exit status from shell commands when creating the
278 * node. 278 * node.
279 */ 279 */
280 OP_IGNORE = 1 << 6, 280 OP_IGNORE = 1 << 6,
281 /* Don't remove the target when interrupted. */ 281 /* Don't remove the target when interrupted. */
282 OP_PRECIOUS = 1 << 7, 282 OP_PRECIOUS = 1 << 7,
283 /* Don't echo commands when executed. */ 283 /* Don't echo commands when executed. */
284 OP_SILENT = 1 << 8, 284 OP_SILENT = 1 << 8,
285 /* 285 /*
286 * Target is a recursive make so its commands should always be 286 * Target is a recursive make so its commands should always be
287 * executed when it is out of date, regardless of the state of the -n 287 * executed when it is out of date, regardless of the state of the -n
288 * or -t flags. 288 * or -t flags.
289 */ 289 */
290 OP_MAKE = 1 << 9, 290 OP_MAKE = 1 << 9,
291 /* 291 /*
292 * Target is out-of-date only if any of its children was out-of-date. 292 * Target is out-of-date only if any of its children was out-of-date.
293 */ 293 */
294 OP_JOIN = 1 << 10, 294 OP_JOIN = 1 << 10,
295 /* Assume the children of the node have been already made. */ 295 /* Assume the children of the node have been already made. */
296 OP_MADE = 1 << 11, 296 OP_MADE = 1 << 11,
297 /* Special .BEGIN, .END or .INTERRUPT. */ 297 /* Special .BEGIN, .END or .INTERRUPT. */
298 OP_SPECIAL = 1 << 12, 298 OP_SPECIAL = 1 << 12,
299 /* Like .USE, only prepend commands. */ 299 /* Like .USE, only prepend commands. */
300 OP_USEBEFORE = 1 << 13, 300 OP_USEBEFORE = 1 << 13,
301 /* 301 /*
302 * The node is invisible to its parents. I.e. it doesn't show up in 302 * The node is invisible to its parents. I.e. it doesn't show up in
303 * the parents' local variables (.IMPSRC, .ALLSRC). 303 * the parents' local variables (.IMPSRC, .ALLSRC).
304 */ 304 */
305 OP_INVISIBLE = 1 << 14, 305 OP_INVISIBLE = 1 << 14,
306 /* 306 /*
307 * The node does not become the main target, even if it is the first 307 * The node does not become the main target, even if it is the first
308 * target in the first makefile. 308 * target in the first makefile.
309 */ 309 */
310 OP_NOTMAIN = 1 << 15, 310 OP_NOTMAIN = 1 << 15,
311 /* Not a file target; run always. */ 311 /* Not a file target; run always. */
312 OP_PHONY = 1 << 16, 312 OP_PHONY = 1 << 16,
313 /* Don't search for the file in the path. */ 313 /* Don't search for the file in the path. */
314 OP_NOPATH = 1 << 17, 314 OP_NOPATH = 1 << 17,
315 /* 315 /*
316 * In a dependency line "target: source1 .WAIT source2", source1 is 316 * In a dependency line "target: source1 .WAIT source2", source1 is
317 * made first, including its children. Once that is finished, 317 * made first, including its children. Once that is finished,
318 * source2 is made, including its children. The .WAIT keyword may 318 * source2 is made, including its children. The .WAIT keyword may
319 * appear more than once in a single dependency declaration. 319 * appear more than once in a single dependency declaration.
320 */ 320 */
321 OP_WAIT = 1 << 18, 321 OP_WAIT = 1 << 18,
322 /* .NOMETA do not create a .meta file */ 322 /* .NOMETA do not create a .meta file */
323 OP_NOMETA = 1 << 19, 323 OP_NOMETA = 1 << 19,
324 /* .META we _do_ want a .meta file */ 324 /* .META we _do_ want a .meta file */
325 OP_META = 1 << 20, 325 OP_META = 1 << 20,
326 /* Do not compare commands in .meta file */ 326 /* Do not compare commands in .meta file */
327 OP_NOMETA_CMP = 1 << 21, 327 OP_NOMETA_CMP = 1 << 21,
328 /* Possibly a submake node */ 328 /* Possibly a submake node */
329 OP_SUBMAKE = 1 << 22, 329 OP_SUBMAKE = 1 << 22,
330 330
331 /* Attributes applied by PMake */ 331 /* Attributes applied by PMake */
332 332
333 /* The node is a transformation rule, such as ".c.o". */ 333 /* The node is a transformation rule, such as ".c.o". */
334 OP_TRANSFORM = 1 << 30, 334 OP_TRANSFORM = 1 << 30,
335 /* Target is a member of an archive */ 335 /* Target is a member of an archive */
336 /* XXX: How does this differ from OP_ARCHV? */ 336 /* XXX: How does this differ from OP_ARCHV? */
337 OP_MEMBER = 1 << 29, 337 OP_MEMBER = 1 << 29,
338 /* 338 /*
339 * The node is a library, its name has the form "-l<libname>". 339 * The node is a library, its name has the form "-l<libname>".
340 */ 340 */
341 OP_LIB = 1 << 28, 341 OP_LIB = 1 << 28,
342 /* 342 /*
343 * The node is an archive member, its name has the form 343 * The node is an archive member, its name has the form
344 * "archive(member)". 344 * "archive(member)".
345 */ 345 */
346 /* XXX: How does this differ from OP_MEMBER? */ 346 /* XXX: How does this differ from OP_MEMBER? */
347 OP_ARCHV = 1 << 27, 347 OP_ARCHV = 1 << 27,
348 /* 348 /*
349 * Target has all the commands it should. Used when parsing to catch 349 * Target has all the commands it should. Used when parsing to catch
350 * multiple command groups for a target. Only applies to the 350 * multiple command groups for a target. Only applies to the
351 * dependency operators ':' and '!', but not to '::'. 351 * dependency operators ':' and '!', but not to '::'.
352 */ 352 */
353 OP_HAS_COMMANDS = 1 << 26, 353 OP_HAS_COMMANDS = 1 << 26,
354 /* 354 /*
355 * The special command "..." has been seen. All further commands from 355 * The special command "..." has been seen. All further commands from
356 * this node will be saved on the .END node instead, to be executed 356 * this node will be saved on the .END node instead, to be executed
357 * at the very end. 357 * at the very end.
358 */ 358 */
359 OP_SAVE_CMDS = 1 << 25, 359 OP_SAVE_CMDS = 1 << 25,
360 /* 360 /*
361 * Already processed by Suff_FindDeps, to find dependencies from 361 * Already processed by Suff_FindDeps, to find dependencies from
362 * suffix transformation rules. 362 * suffix transformation rules.
363 */ 363 */
364 OP_DEPS_FOUND = 1 << 24, 364 OP_DEPS_FOUND = 1 << 24,
365 /* Node found while expanding .ALLSRC */ 365 /* Node found while expanding .ALLSRC */
366 OP_MARK = 1 << 23 366 OP_MARK = 1 << 23
367} GNodeType; 367} GNodeType;
368 368
369typedef struct GNodeFlags { 369typedef struct GNodeFlags {
370 /* this target needs to be (re)made */ 370 /* this target needs to be (re)made */
371 bool remake:1; 371 bool remake:1;
372 /* children of this target were made */ 372 /* children of this target were made */
373 bool childMade:1; 373 bool childMade:1;
374 /* children don't exist, and we pretend made */ 374 /* children don't exist, and we pretend made */
375 bool force:1; 375 bool force:1;
376 /* Set by Make_ProcessWait() */ 376 /* Set by Make_ProcessWait() */
377 bool doneWait:1; 377 bool doneWait:1;
378 /* Build requested by .ORDER processing */ 378 /* Build requested by .ORDER processing */
379 bool doneOrder:1; 379 bool doneOrder:1;
380 /* Node created from .depend */ 380 /* Node created from .depend */
381 bool fromDepend:1; 381 bool fromDepend:1;
382 /* We do it once only */ 382 /* We do it once only */
383 bool doneAllsrc:1; 383 bool doneAllsrc:1;
384 /* Used by MakePrintStatus */ 384 /* Used by MakePrintStatus */
385 bool cycle:1; 385 bool cycle:1;
386 /* Used by MakePrintStatus */ 386 /* Used by MakePrintStatus */
387 bool doneCycle:1; 387 bool doneCycle:1;
388} GNodeFlags; 388} GNodeFlags;
389 389
390typedef struct List StringList; 390typedef struct List StringList;
391typedef struct ListNode StringListNode; 391typedef struct ListNode StringListNode;
392 392
393typedef struct List GNodeList; 393typedef struct List GNodeList;
394typedef struct ListNode GNodeListNode; 394typedef struct ListNode GNodeListNode;
395 395
396typedef struct SearchPath { 396typedef struct SearchPath {
397 List /* of CachedDir */ dirs; 397 List /* of CachedDir */ dirs;
398} SearchPath; 398} SearchPath;
399 399
400/* 400/*
401 * A graph node represents a target that can possibly be made, including its 401 * A graph node represents a target that can possibly be made, including its
402 * relation to other targets and a lot of other details. 402 * relation to other targets and a lot of other details.
403 */ 403 */
404typedef struct GNode { 404typedef struct GNode {
405 /* The target's name, such as "clean" or "make.c" */ 405 /* The target's name, such as "clean" or "make.c" */
406 char *name; 406 char *name;
407 /* The unexpanded name of a .USE node */ 407 /* The unexpanded name of a .USE node */
408 char *uname; 408 char *uname;
409 /* 409 /*
410 * The full pathname of the file belonging to the target. 410 * The full pathname of the file belonging to the target.
411 * 411 *
412 * XXX: What about .PHONY targets? These don't have an associated 412 * XXX: What about .PHONY targets? These don't have an associated
413 * path. 413 * path.
414 */ 414 */
415 char *path; 415 char *path;
416 416
417 /* 417 /*
418 * The type of operator used to define the sources (see the OP flags 418 * The type of operator used to define the sources (see the OP flags
419 * below). 419 * below).
420 * 420 *
421 * XXX: This looks like a wild mixture of type and flags. 421 * XXX: This looks like a wild mixture of type and flags.
422 */ 422 */
423 GNodeType type; 423 GNodeType type;
424 GNodeFlags flags; 424 GNodeFlags flags;
425 425
426 /* The state of processing on this node */ 426 /* The state of processing on this node */
427 GNodeMade made; 427 GNodeMade made;
428 /* The number of unmade children */ 428 /* The number of unmade children */
429 int unmade; 429 int unmade;
430 430
431 /* 431 /*
432 * The modification time; 0 means the node does not have a 432 * The modification time; 0 means the node does not have a
433 * corresponding file; see GNode_IsOODate. 433 * corresponding file; see GNode_IsOODate.
434 */ 434 */
435 time_t mtime; 435 time_t mtime;
436 struct GNode *youngestChild; 436 struct GNode *youngestChild;
437 437
438 /* 438 /*
439 * The GNodes for which this node is an implied source. May be empty. 439 * The GNodes for which this node is an implied source. May be empty.
440 * For example, when there is an inference rule for .c.o, the node 440 * For example, when there is an inference rule for .c.o, the node
441 * for file.c has the node for file.o in this list. 441 * for file.c has the node for file.o in this list.
442 */ 442 */
443 GNodeList implicitParents; 443 GNodeList implicitParents;
444 444
445 /* 445 /*
446 * The nodes that depend on this one, or in other words, the nodes 446 * The nodes that depend on this one, or in other words, the nodes
447 * for which this is a source. 447 * for which this is a source.
448 */ 448 */
449 GNodeList parents; 449 GNodeList parents;
450 /* The nodes on which this one depends. */ 450 /* The nodes on which this one depends. */
451 GNodeList children; 451 GNodeList children;
452 452
453 /* 453 /*
454 * .ORDER nodes we need made. The nodes that must be made (if they're 454 * .ORDER nodes we need made. The nodes that must be made (if they're
455 * made) before this node can be made, but that do not enter into the 455 * made) before this node can be made, but that do not enter into the
456 * datedness of this node. 456 * datedness of this node.
457 */ 457 */
458 GNodeList order_pred; 458 GNodeList order_pred;
459 /* 459 /*
460 * .ORDER nodes who need us. The nodes that must be made (if they're 460 * .ORDER nodes who need us. The nodes that must be made (if they're
461 * made at all) after this node is made, but that do not depend on 461 * made at all) after this node is made, but that do not depend on
462 * this node, in the normal sense. 462 * this node, in the normal sense.
463 */ 463 */
464 GNodeList order_succ; 464 GNodeList order_succ;
465 465
466 /* 466 /*
467 * Other nodes of the same name, for targets that were defined using 467 * Other nodes of the same name, for targets that were defined using
468 * the '::' dependency operator (OP_DOUBLEDEP). 468 * the '::' dependency operator (OP_DOUBLEDEP).
469 */ 469 */
470 GNodeList cohorts; 470 GNodeList cohorts;
471 /* The "#n" suffix for this cohort, or "" for other nodes */ 471 /* The "#n" suffix for this cohort, or "" for other nodes */
472 char cohort_num[8]; 472 char cohort_num[8];
473 /* The number of unmade instances on the cohorts list */ 473 /* The number of unmade instances on the cohorts list */
474 int unmade_cohorts; 474 int unmade_cohorts;
475 /* 475 /*
476 * Pointer to the first instance of a '::' node; only set when on a 476 * Pointer to the first instance of a '::' node; only set when on a
477 * cohorts list 477 * cohorts list
478 */ 478 */
479 struct GNode *centurion; 479 struct GNode *centurion;
480 480
481 /* Last time (sequence number) we tried to make this node */ 481 /* Last time (sequence number) we tried to make this node */
482 unsigned int checked_seqno; 482 unsigned int checked_seqno;
483 483
484 /* 484 /*
485 * The "local" variables that are specific to this target and this 485 * The "local" variables that are specific to this target and this
486 * target only, such as $@, $<, $?. 486 * target only, such as $@, $<, $?.
487 * 487 *
488 * Also used for the global variable scopes SCOPE_GLOBAL, 488 * Also used for the global variable scopes SCOPE_GLOBAL,
489 * SCOPE_CMDLINE, SCOPE_INTERNAL, which contain variables with 489 * SCOPE_CMDLINE, SCOPE_INTERNAL, which contain variables with
490 * arbitrary names. 490 * arbitrary names.
491 */ 491 */
492 HashTable /* of Var pointer */ vars; 492 HashTable /* of Var pointer */ vars;
493 493
494 /* The commands to be given to a shell to create this target. */ 494 /* The commands to be given to a shell to create this target. */
495 StringList commands; 495 StringList commands;
496 496
497 /* 497 /*
498 * Suffix for the node (determined by Suff_FindDeps and opaque to 498 * Suffix for the node (determined by Suff_FindDeps and opaque to
499 * everyone but the Suff module) 499 * everyone but the Suff module)
500 */ 500 */
501 struct Suffix *suffix; 501 struct Suffix *suffix;
502 502
503 /* Filename where the GNode got defined, unlimited lifetime */ 503 /* Filename where the GNode got defined, unlimited lifetime */
504 const char *fname; 504 const char *fname;
505 /* Line number where the GNode got defined, 1-based */ 505 /* Line number where the GNode got defined, 1-based */
506 unsigned lineno; 506 unsigned lineno;
507} GNode; 507} GNode;
508 508
509/* 509/*
510 * Keep track of whether to include <posix.mk> when parsing the line 510 * Keep track of whether to include <posix.mk> when parsing the line
511 * '.POSIX:'. 511 * '.POSIX:'.
512 */ 512 */
513extern enum PosixState { 513extern enum PosixState {
514 PS_NOT_YET, 514 PS_NOT_YET,
515 PS_MAYBE_NEXT_LINE, 515 PS_MAYBE_NEXT_LINE,
516 PS_NOW_OR_NEVER, 516 PS_NOW_OR_NEVER,
517 PS_TOO_LATE 517 PS_TOO_LATE
518} posix_state; 518} posix_state;
519 519
520/* Error levels for diagnostics during parsing. */ 520/* Error levels for diagnostics during parsing. */
521typedef enum ParseErrorLevel { 521typedef enum ParseErrorLevel {
522 /* 522 /*
523 * Exit when the current top-level makefile has been parsed 523 * Exit when the current top-level makefile has been parsed
524 * completely. 524 * completely.
525 */ 525 */
526 PARSE_FATAL = 1, 526 PARSE_FATAL = 1,
527 /* Print "warning"; may be upgraded to fatal by the -w option. */ 527 /* Print "warning"; may be upgraded to fatal by the -w option. */
528 PARSE_WARNING, 528 PARSE_WARNING,
529 /* Informational, mainly used during development of makefiles. */ 529 /* Informational, mainly used during development of makefiles. */
530 PARSE_INFO 530 PARSE_INFO
531} ParseErrorLevel; 531} ParseErrorLevel;
532 532
533/* 533/*
534 * Values returned by Cond_EvalLine and Cond_EvalCondition. 534 * Values returned by Cond_EvalLine and Cond_EvalCondition.
535 */ 535 */
536typedef enum CondResult { 536typedef enum CondResult {
537 CR_TRUE, /* Parse the next lines */ 537 CR_TRUE, /* Parse the next lines */
538 CR_FALSE, /* Skip the next lines */ 538 CR_FALSE, /* Skip the next lines */
539 CR_ERROR /* Unknown directive or parse error */ 539 CR_ERROR /* Unknown directive or parse error */
540} CondResult; 540} CondResult;
541 541
542/* Names of the variables that are "local" to a specific target. */ 542/* Names of the variables that are "local" to a specific target. */
543#define TARGET "@" /* Target of dependency */ 543#define TARGET "@" /* Target of dependency */
544#define OODATE "?" /* All out-of-date sources */ 544#define OODATE "?" /* All out-of-date sources */
545#define ALLSRC ">" /* All sources */ 545#define ALLSRC ">" /* All sources */
546#define IMPSRC "<" /* Source implied by transformation */ 546#define IMPSRC "<" /* Source implied by transformation */
547#define PREFIX "*" /* Common prefix */ 547#define PREFIX "*" /* Common prefix */
548#define ARCHIVE "!" /* Archive in "archive(member)" syntax */ 548#define ARCHIVE "!" /* Archive in "archive(member)" syntax */
549#define MEMBER "%" /* Member in "archive(member)" syntax */ 549#define MEMBER "%" /* Member in "archive(member)" syntax */
550 550
551/* 551/*
552 * Global Variables 552 * Global Variables
553 */ 553 */
554 554
555/* True if every target is precious */ 555/* True if every target is precious */
556extern bool allPrecious; 556extern bool allPrecious;
557/* True if failed targets should be deleted */ 557/* True if failed targets should be deleted */
558extern bool deleteOnError; 558extern bool deleteOnError;
559/* true while processing .depend */ 559/* true while processing .depend */
560extern bool doing_depend; 560extern bool doing_depend;
561/* .DEFAULT rule */ 561/* .DEFAULT rule */
562extern GNode *defaultNode; 562extern GNode *defaultNode;
563 563
564/* 564/*
565 * Variables defined internally by make which should not override those set 565 * Variables defined internally by make which should not override those set
566 * by makefiles. 566 * by makefiles.
567 */ 567 */
568extern GNode *SCOPE_INTERNAL; 568extern GNode *SCOPE_INTERNAL;
569/* Variables defined in a global scope, e.g in the makefile itself. */ 569/* Variables defined in a global scope, e.g in the makefile itself. */
570extern GNode *SCOPE_GLOBAL; 570extern GNode *SCOPE_GLOBAL;
571/* Variables defined on the command line. */ 571/* Variables defined on the command line. */
572extern GNode *SCOPE_CMDLINE; 572extern GNode *SCOPE_CMDLINE;
573 573
574/* 574/*
575 * Value returned by Var_Parse when an error is encountered. It actually 575 * Value returned by Var_Parse when an error is encountered. It actually
576 * points to an empty string, so naive callers needn't worry about it. 576 * points to an empty string, so naive callers needn't worry about it.
577 */ 577 */
578extern char var_Error[]; 578extern char var_Error[];
579 579
580/* The time at the start of this whole process */ 580/* The time at the start of this whole process */
581extern time_t now; 581extern time_t now;
582 582
583/* 583/*
584 * The list of directories to search when looking for targets (set by the 584 * The list of directories to search when looking for targets (set by the
585 * special target .PATH). 585 * special target .PATH).
586 */ 586 */
587extern SearchPath dirSearchPath; 587extern SearchPath dirSearchPath;
588/* Used for .include "...". */ 588/* Used for .include "...". */
589extern SearchPath *parseIncPath; 589extern SearchPath *parseIncPath;
590/* 590/*
591 * Used for .include <...>, for the built-in sys.mk and for makefiles from 591 * Used for .include <...>, for the built-in sys.mk and for makefiles from
592 * the command line arguments. 592 * the command line arguments.
593 */ 593 */
594extern SearchPath *sysIncPath; 594extern SearchPath *sysIncPath;
595/* The default for sysIncPath. */ 595/* The default for sysIncPath. */
596extern SearchPath *defSysIncPath; 596extern SearchPath *defSysIncPath;
597 597
598/* Startup directory */ 598/* Startup directory */
599extern char curdir[]; 599extern char curdir[];
600/* The basename of the program name, suffixed with [n] for sub-makes. */ 600/* The basename of the program name, suffixed with [n] for sub-makes. */
601extern const char *progname; 601extern const char *progname;
602extern int makelevel; 602extern int makelevel;
603/* Name of the .depend makefile */ 603/* Name of the .depend makefile */
604extern char *makeDependfile; 604extern char *makeDependfile;
605/* If we replaced environ, this will be non-NULL. */ 605/* If we replaced environ, this will be non-NULL. */
606extern char **savedEnv; 606extern char **savedEnv;
607extern GNode *mainNode; 607extern GNode *mainNode;
608 608
609extern pid_t myPid; 609extern pid_t myPid;
610 610
611#define MAKEFLAGS ".MAKEFLAGS" 611#define MAKEFLAGS ".MAKEFLAGS"
612#ifndef MAKE_LEVEL_ENV 612#ifndef MAKE_LEVEL_ENV
613# define MAKE_LEVEL_ENV "MAKELEVEL" 613# define MAKE_LEVEL_ENV "MAKELEVEL"
614#endif 614#endif
615 615
616typedef struct DebugFlags { 616typedef struct DebugFlags {
617 bool DEBUG_ARCH:1; 617 bool DEBUG_ARCH:1;
618 bool DEBUG_COND:1; 618 bool DEBUG_COND:1;
619 bool DEBUG_CWD:1; 619 bool DEBUG_CWD:1;
620 bool DEBUG_DIR:1; 620 bool DEBUG_DIR:1;
621 bool DEBUG_ERROR:1; 621 bool DEBUG_ERROR:1;
622 bool DEBUG_FOR:1; 622 bool DEBUG_FOR:1;
623 bool DEBUG_GRAPH1:1; 623 bool DEBUG_GRAPH1:1;
624 bool DEBUG_GRAPH2:1; 624 bool DEBUG_GRAPH2:1;
625 bool DEBUG_GRAPH3:1; 625 bool DEBUG_GRAPH3:1;
626 bool DEBUG_HASH:1; 626 bool DEBUG_HASH:1;
627 bool DEBUG_JOB:1; 627 bool DEBUG_JOB:1;
628 bool DEBUG_LOUD:1; 628 bool DEBUG_LOUD:1;
629 bool DEBUG_MAKE:1; 629 bool DEBUG_MAKE:1;
630 bool DEBUG_META:1; 630 bool DEBUG_META:1;
631 bool DEBUG_PARSE:1; 631 bool DEBUG_PARSE:1;
632 bool DEBUG_SCRIPT:1; 632 bool DEBUG_SCRIPT:1;
633 bool DEBUG_SHELL:1; 633 bool DEBUG_SHELL:1;
634 bool DEBUG_SUFF:1; 634 bool DEBUG_SUFF:1;
635 bool DEBUG_TARG:1; 635 bool DEBUG_TARG:1;
636 bool DEBUG_VAR:1; 636 bool DEBUG_VAR:1;
637} DebugFlags; 637} DebugFlags;
638 638
639#define CONCAT(a, b) a##b 639#define CONCAT(a, b) a##b
640 640
641#define DEBUG(module) (opts.debug.CONCAT(DEBUG_, module)) 641#define DEBUG(module) (opts.debug.CONCAT(DEBUG_, module))
642 642
643void debug_printf(const char *, ...) MAKE_ATTR_PRINTFLIKE(1, 2); 643void debug_printf(const char *, ...) MAKE_ATTR_PRINTFLIKE(1, 2);
644 644
645#define DEBUG_IMPL(module, args) \ 645#define DEBUG_IMPL(module, args) \
646 do { \ 646 do { \
647 if (DEBUG(module)) \ 647 if (DEBUG(module)) \
648 debug_printf args; \ 648 debug_printf args; \
649 } while (false) 649 } while (false)
650 650
651#define DEBUG0(module, fmt) \ 651#define DEBUG0(module, fmt) \
652 DEBUG_IMPL(module, (fmt)) 652 DEBUG_IMPL(module, (fmt))
653#define DEBUG1(module, fmt, arg1) \ 653#define DEBUG1(module, fmt, arg1) \
654 DEBUG_IMPL(module, (fmt, arg1)) 654 DEBUG_IMPL(module, (fmt, arg1))
655#define DEBUG2(module, fmt, arg1, arg2) \ 655#define DEBUG2(module, fmt, arg1, arg2) \
656 DEBUG_IMPL(module, (fmt, arg1, arg2)) 656 DEBUG_IMPL(module, (fmt, arg1, arg2))
657#define DEBUG3(module, fmt, arg1, arg2, arg3) \ 657#define DEBUG3(module, fmt, arg1, arg2, arg3) \
658 DEBUG_IMPL(module, (fmt, arg1, arg2, arg3)) 658 DEBUG_IMPL(module, (fmt, arg1, arg2, arg3))
659#define DEBUG4(module, fmt, arg1, arg2, arg3, arg4) \ 659#define DEBUG4(module, fmt, arg1, arg2, arg3, arg4) \
660 DEBUG_IMPL(module, (fmt, arg1, arg2, arg3, arg4)) 660 DEBUG_IMPL(module, (fmt, arg1, arg2, arg3, arg4))
661#define DEBUG5(module, fmt, arg1, arg2, arg3, arg4, arg5) \ 661#define DEBUG5(module, fmt, arg1, arg2, arg3, arg4, arg5) \
662 DEBUG_IMPL(module, (fmt, arg1, arg2, arg3, arg4, arg5)) 662 DEBUG_IMPL(module, (fmt, arg1, arg2, arg3, arg4, arg5))
663 663
664typedef enum PrintVarsMode { 664typedef enum PrintVarsMode {
665 PVM_NONE, 665 PVM_NONE,
666 PVM_UNEXPANDED, 666 PVM_UNEXPANDED,
667 PVM_EXPANDED 667 PVM_EXPANDED
668} PrintVarsMode; 668} PrintVarsMode;
669 669
670/* Command line options */ 670/* Command line options */
671typedef struct CmdOpts { 671typedef struct CmdOpts {
672 /* -B: whether we are make compatible */ 672 /* -B: whether we are make compatible */
673 bool compatMake; 673 bool compatMake;
674 674
675 /* 675 /*
676 * -d: debug control: There is one bit per module. It is up to the 676 * -d: debug control: There is one bit per module. It is up to the
677 * module what debug information to print. 677 * module what debug information to print.
678 */ 678 */
679 DebugFlags debug; 679 DebugFlags debug;
680 680
681 /* -df: debug output is written here - default stderr */ 681 /* -df: debug output is written here - default stderr */
682 FILE *debug_file; 682 FILE *debug_file;
683 683
684 /* 684 /*
685 * -dL: lint mode 685 * -dL: lint mode
686 * 686 *
687 * Runs make in strict mode, with additional checks and better error 687 * Runs make in strict mode, with additional checks and better error
688 * handling. 688 * handling.
689 */ 689 */
690 bool strict; 690 bool strict;
691 691
692 /* -dV: for the -V option, print unexpanded variable values */ 692 /* -dV: for the -V option, print unexpanded variable values */
693 bool debugVflag; 693 bool debugVflag;
694 694
695 /* -e: check environment variables before global variables */ 695 /* -e: check environment variables before global variables */
696 bool checkEnvFirst; 696 bool checkEnvFirst;
697 697
698 /* -f: the makefiles to read */ 698 /* -f: the makefiles to read */
699 StringList makefiles; 699 StringList makefiles;
700 700
701 /* -i: if true, ignore all errors from shell commands */ 701 /* -i: if true, ignore all errors from shell commands */
702 bool ignoreErrors; 702 bool ignoreErrors;
703 703
704 /* 704 /*
705 * -j: the maximum number of jobs that can run in parallel; this is 705 * -j: the maximum number of jobs that can run in parallel; this is
706 * coordinated with the submakes 706 * coordinated with the submakes
707 */ 707 */
708 int maxJobs; 708 int maxJobs;
709 709
710 /* 710 /*
711 * -k: if true and an error occurs while making a node, continue 711 * -k: if true and an error occurs while making a node, continue
712 * making nodes that do not depend on the erroneous node 712 * making nodes that do not depend on the erroneous node
713 */ 713 */
714 bool keepgoing; 714 bool keepgoing;
715 715
716 /* -N: execute no commands from the targets */ 716 /* -N: execute no commands from the targets */
717 bool noRecursiveExecute; 717 bool noRecursiveExecute;
718 718
719 /* -n: execute almost no commands from the targets */ 719 /* -n: execute almost no commands from the targets */
720 bool noExecute; 720 bool noExecute;
721 721
722 /* 722 /*
723 * -q: if true, do not really make anything, just see if the targets 723 * -q: if true, do not really make anything, just see if the targets
724 * are out-of-date 724 * are out-of-date
725 */ 725 */
726 bool query; 726 bool query;
727 727
728 /* -r: raw mode, do not load the builtin rules. */ 728 /* -r: raw mode, do not load the builtin rules. */
729 bool noBuiltins; 729 bool noBuiltins;
730 730
731 /* -s: don't echo the shell commands before executing them */ 731 /* -s: don't echo the shell commands before executing them */
732 bool silent; 732 bool silent;
733 733
734 /* 734 /*
735 * -t: touch the targets if they are out-of-date, but don't actually 735 * -t: touch the targets if they are out-of-date, but don't actually
736 * make them 736 * make them
737 */ 737 */
738 bool touch; 738 bool touch;
739 739
740 /* -[Vv]: print expanded or unexpanded selected variables */ 740 /* -[Vv]: print expanded or unexpanded selected variables */
741 PrintVarsMode printVars; 741 PrintVarsMode printVars;
742 /* -[Vv]: the variables to print */ 742 /* -[Vv]: the variables to print */
743 StringList variables; 743 StringList variables;
744 744
745 /* -W: if true, makefile parsing warnings are treated as errors */ 745 /* -W: if true, makefile parsing warnings are treated as errors */
746 bool parseWarnFatal; 746 bool parseWarnFatal;
747 747
748 /* -w: print 'Entering' and 'Leaving' for submakes */ 748 /* -w: print 'Entering' and 'Leaving' for submakes */
749 bool enterFlag; 749 bool enterFlag;
750 750
751 /* 751 /*
752 * -X: if true, do not export variables set on the command line to 752 * -X: if true, do not export variables set on the command line to
753 * the environment. 753 * the environment.
754 */ 754 */
755 bool varNoExportEnv; 755 bool varNoExportEnv;
756 756
757 /* 757 /*
758 * The target names specified on the command line. Used to resolve 758 * The target names specified on the command line. Used to resolve
759 * .if make(...) statements. 759 * .if make(...) statements.
760 */ 760 */
761 StringList create; 761 StringList create;
762 762
763 /* 763 /*
764 * Randomize the order in which the targets from toBeMade are made, 764 * Randomize the order in which the targets from toBeMade are made,
765 * to catch undeclared dependencies. 765 * to catch undeclared dependencies.
766 */ 766 */
767 bool randomizeTargets; 767 bool randomizeTargets;
768} CmdOpts; 768} CmdOpts;
769 769
770extern CmdOpts opts; 770extern CmdOpts opts;
771extern bool forceJobs; 771extern bool forceJobs;
772extern char **environ; 772extern char **environ;
773 773
774/* arch.c */ 774/* arch.c */
775void Arch_Init(void); 775void Arch_Init(void);
776void Arch_End(void); 776void Arch_End(void);
777 777
778bool Arch_ParseArchive(char **, GNodeList *, GNode *); 778bool Arch_ParseArchive(char **, GNodeList *, GNode *);
779void Arch_Touch(GNode *); 779void Arch_Touch(GNode *);
780void Arch_TouchLib(GNode *); 780void Arch_TouchLib(GNode *);
781void Arch_UpdateMTime(GNode *gn); 781void Arch_UpdateMTime(GNode *);
782void Arch_UpdateMemberMTime(GNode *gn); 782void Arch_UpdateMemberMTime(GNode *);
783void Arch_FindLib(GNode *, SearchPath *); 783void Arch_FindLib(GNode *, SearchPath *);
784bool Arch_LibOODate(GNode *) MAKE_ATTR_USE; 784bool Arch_LibOODate(GNode *) MAKE_ATTR_USE;
785bool Arch_IsLib(GNode *) MAKE_ATTR_USE; 785bool Arch_IsLib(GNode *) MAKE_ATTR_USE;
786 786
787/* compat.c */ 787/* compat.c */
788bool Compat_RunCommand(const char *, GNode *, StringListNode *); 788bool Compat_RunCommand(const char *, GNode *, StringListNode *);
789void Compat_MakeAll(GNodeList *); 789void Compat_MakeAll(GNodeList *);
790void Compat_Make(GNode *, GNode *); 790void Compat_Make(GNode *, GNode *);
791 791
792/* cond.c */ 792/* cond.c */
793extern unsigned int cond_depth; 793extern unsigned int cond_depth;
794CondResult Cond_EvalCondition(const char *) MAKE_ATTR_USE; 794CondResult Cond_EvalCondition(const char *) MAKE_ATTR_USE;
795CondResult Cond_EvalLine(const char *) MAKE_ATTR_USE; 795CondResult Cond_EvalLine(const char *) MAKE_ATTR_USE;
796void Cond_EndFile(void); 796void Cond_EndFile(void);
797 797
798/* dir.c; see also dir.h */ 798/* dir.c; see also dir.h */
799 799
800MAKE_INLINE const char * MAKE_ATTR_USE 800MAKE_INLINE const char * MAKE_ATTR_USE
801str_basename(const char *pathname) 801str_basename(const char *pathname)
802{ 802{
803 const char *lastSlash = strrchr(pathname, '/'); 803 const char *lastSlash = strrchr(pathname, '/');
804 return lastSlash != NULL ? lastSlash + 1 : pathname; 804 return lastSlash != NULL ? lastSlash + 1 : pathname;
805} 805}
806 806
807MAKE_INLINE SearchPath * MAKE_ATTR_USE 807MAKE_INLINE SearchPath * MAKE_ATTR_USE
808SearchPath_New(void) 808SearchPath_New(void)
809{ 809{
810 SearchPath *path = bmake_malloc(sizeof *path); 810 SearchPath *path = bmake_malloc(sizeof *path);
811 Lst_Init(&path->dirs); 811 Lst_Init(&path->dirs);
812 return path; 812 return path;
813} 813}
814 814
815void SearchPath_Free(SearchPath *); 815void SearchPath_Free(SearchPath *);
816 816
817/* for.c */ 817/* for.c */
818struct ForLoop; 818struct ForLoop;
819int For_Eval(const char *) MAKE_ATTR_USE; 819int For_Eval(const char *) MAKE_ATTR_USE;
820bool For_Accum(const char *, int *) MAKE_ATTR_USE; 820bool For_Accum(const char *, int *) MAKE_ATTR_USE;
821void For_Run(unsigned, unsigned); 821void For_Run(unsigned, unsigned);
822bool For_NextIteration(struct ForLoop *, Buffer *); 822bool For_NextIteration(struct ForLoop *, Buffer *);
823char *ForLoop_Details(const struct ForLoop *); 823char *ForLoop_Details(const struct ForLoop *);
824void ForLoop_Free(struct ForLoop *); 824void ForLoop_Free(struct ForLoop *);
825void For_Break(struct ForLoop *); 825void For_Break(struct ForLoop *);
826 826
827/* job.c */ 827/* job.c */
828void JobReapChild(pid_t, int, bool); 828void JobReapChild(pid_t, int, bool);
829 829
830/* main.c */ 830/* main.c */
831void Main_ParseArgLine(const char *); 831void Main_ParseArgLine(const char *);
832char *Cmd_Exec(const char *, char **) MAKE_ATTR_USE; 832char *Cmd_Exec(const char *, char **) MAKE_ATTR_USE;
833void Error(const char *, ...) MAKE_ATTR_PRINTFLIKE(1, 2); 833void Error(const char *, ...) MAKE_ATTR_PRINTFLIKE(1, 2);
834void Fatal(const char *, ...) MAKE_ATTR_PRINTFLIKE(1, 2) MAKE_ATTR_DEAD; 834void Fatal(const char *, ...) MAKE_ATTR_PRINTFLIKE(1, 2) MAKE_ATTR_DEAD;
835void Punt(const char *, ...) MAKE_ATTR_PRINTFLIKE(1, 2) MAKE_ATTR_DEAD; 835void Punt(const char *, ...) MAKE_ATTR_PRINTFLIKE(1, 2) MAKE_ATTR_DEAD;
836void DieHorribly(void) MAKE_ATTR_DEAD; 836void DieHorribly(void) MAKE_ATTR_DEAD;
837void Finish(int) MAKE_ATTR_DEAD; 837void Finish(int) MAKE_ATTR_DEAD;
838int unlink_file(const char *) MAKE_ATTR_USE; 838int unlink_file(const char *) MAKE_ATTR_USE;
839void execDie(const char *, const char *); 839void execDie(const char *, const char *);
840char *getTmpdir(void) MAKE_ATTR_USE; 840char *getTmpdir(void) MAKE_ATTR_USE;
841bool ParseBoolean(const char *, bool) MAKE_ATTR_USE; 841bool ParseBoolean(const char *, bool) MAKE_ATTR_USE;
842const char *cached_realpath(const char *, char *); 842const char *cached_realpath(const char *, char *);
843bool GetBooleanExpr(const char *, bool); 843bool GetBooleanExpr(const char *, bool);
844 844
845/* parse.c */ 845/* parse.c */
846void Parse_Init(void); 846void Parse_Init(void);
847void Parse_End(void); 847void Parse_End(void);
848 848
849void PrintLocation(FILE *, bool, const GNode *); 849void PrintLocation(FILE *, bool, const GNode *);
850void PrintStackTrace(bool); 850void PrintStackTrace(bool);
851void Parse_Error(ParseErrorLevel, const char *, ...) MAKE_ATTR_PRINTFLIKE(2, 3); 851void Parse_Error(ParseErrorLevel, const char *, ...) MAKE_ATTR_PRINTFLIKE(2, 3);
852bool Parse_VarAssign(const char *, bool, GNode *) MAKE_ATTR_USE; 852bool Parse_VarAssign(const char *, bool, GNode *) MAKE_ATTR_USE;
853void Parse_AddIncludeDir(const char *); 853void Parse_AddIncludeDir(const char *);
854void Parse_File(const char *, int); 854void Parse_File(const char *, int);
855void Parse_PushInput(const char *, unsigned, unsigned, Buffer, 855void Parse_PushInput(const char *, unsigned, unsigned, Buffer,
856 struct ForLoop *); 856 struct ForLoop *);
857void Parse_MainName(GNodeList *); 857void Parse_MainName(GNodeList *);
858int Parse_NumErrors(void) MAKE_ATTR_USE; 858int Parse_NumErrors(void) MAKE_ATTR_USE;
859unsigned int CurFile_CondMinDepth(void) MAKE_ATTR_USE; 859unsigned int CurFile_CondMinDepth(void) MAKE_ATTR_USE;
860 860
861 861
862/* suff.c */ 862/* suff.c */
863void Suff_Init(void); 863void Suff_Init(void);
864void Suff_End(void); 864void Suff_End(void);
865 865
866void Suff_ClearSuffixes(void); 866void Suff_ClearSuffixes(void);
867bool Suff_IsTransform(const char *) MAKE_ATTR_USE; 867bool Suff_IsTransform(const char *) MAKE_ATTR_USE;
868GNode *Suff_AddTransform(const char *); 868GNode *Suff_AddTransform(const char *);
869void Suff_EndTransform(GNode *); 869void Suff_EndTransform(GNode *);
870void Suff_AddSuffix(const char *); 870void Suff_AddSuffix(const char *);
871SearchPath *Suff_GetPath(const char *) MAKE_ATTR_USE; 871SearchPath *Suff_GetPath(const char *) MAKE_ATTR_USE;
872void Suff_ExtendPaths(void); 872void Suff_ExtendPaths(void);
873void Suff_AddInclude(const char *); 873void Suff_AddInclude(const char *);
874void Suff_AddLib(const char *); 874void Suff_AddLib(const char *);
875void Suff_FindDeps(GNode *); 875void Suff_FindDeps(GNode *);
876SearchPath *Suff_FindPath(GNode *) MAKE_ATTR_USE; 876SearchPath *Suff_FindPath(GNode *) MAKE_ATTR_USE;
877void Suff_SetNull(const char *); 877void Suff_SetNull(const char *);
878void Suff_PrintAll(void); 878void Suff_PrintAll(void);
879char *Suff_NamesStr(void) MAKE_ATTR_USE; 879char *Suff_NamesStr(void) MAKE_ATTR_USE;
880 880
881/* targ.c */ 881/* targ.c */
882void Targ_Init(void); 882void Targ_Init(void);
883void Targ_End(void); 883void Targ_End(void);
884 884
885void Targ_Stats(void); 885void Targ_Stats(void);
886GNodeList *Targ_List(void) MAKE_ATTR_USE; 886GNodeList *Targ_List(void) MAKE_ATTR_USE;
887GNode *GNode_New(const char *) MAKE_ATTR_USE; 887GNode *GNode_New(const char *) MAKE_ATTR_USE;
888GNode *Targ_FindNode(const char *) MAKE_ATTR_USE; 888GNode *Targ_FindNode(const char *) MAKE_ATTR_USE;
889GNode *Targ_GetNode(const char *) MAKE_ATTR_USE; 889GNode *Targ_GetNode(const char *) MAKE_ATTR_USE;
890GNode *Targ_NewInternalNode(const char *) MAKE_ATTR_USE; 890GNode *Targ_NewInternalNode(const char *) MAKE_ATTR_USE;
891GNode *Targ_GetEndNode(void); 891GNode *Targ_GetEndNode(void);
892void Targ_FindList(GNodeList *, StringList *); 892void Targ_FindList(GNodeList *, StringList *);
893void Targ_PrintCmds(GNode *); 893void Targ_PrintCmds(GNode *);
894void Targ_PrintNode(GNode *, int); 894void Targ_PrintNode(GNode *, int);
895void Targ_PrintNodes(GNodeList *, int); 895void Targ_PrintNodes(GNodeList *, int);
896const char *Targ_FmtTime(time_t) MAKE_ATTR_USE; 896const char *Targ_FmtTime(time_t) MAKE_ATTR_USE;
897void Targ_PrintType(GNodeType); 897void Targ_PrintType(GNodeType);
898void Targ_PrintGraph(int); 898void Targ_PrintGraph(int);
899void Targ_Propagate(void); 899void Targ_Propagate(void);
900const char *GNodeMade_Name(GNodeMade) MAKE_ATTR_USE; 900const char *GNodeMade_Name(GNodeMade) MAKE_ATTR_USE;
901 901
902/* var.c */ 902/* var.c */
903void Var_Init(void); 903void Var_Init(void);
904void Var_End(void); 904void Var_End(void);
905 905
906typedef enum VarEvalMode { 906typedef enum VarEvalMode {
907 907
908 /* 908 /*
909 * Only parse the expression but don't evaluate any part of it. 909 * Only parse the expression but don't evaluate any part of it.
910 * 910 *
911 * TODO: Document what Var_Parse and Var_Subst return in this mode. 911 * TODO: Document what Var_Parse and Var_Subst return in this mode.
912 * As of 2021-03-15, they return unspecified, inconsistent results. 912 * As of 2021-03-15, they return unspecified, inconsistent results.
913 */ 913 */
914 VARE_PARSE_ONLY, 914 VARE_PARSE_ONLY,
915 915
916 /* 916 /*
917 * Parse text in which '${...}' and '$(...)' are not parsed as 917 * Parse text in which '${...}' and '$(...)' are not parsed as
918 * subexpressions (with all their individual escaping rules) but 918 * subexpressions (with all their individual escaping rules) but
919 * instead simply as text with balanced '${}' or '$()'. Other '$' 919 * instead simply as text with balanced '${}' or '$()'. Other '$'
920 * are copied verbatim. 920 * are copied verbatim.
921 */ 921 */
922 VARE_PARSE_BALANCED, 922 VARE_PARSE_BALANCED,
923 923
924 /* Parse and evaluate the expression. */ 924 /* Parse and evaluate the expression. */
925 VARE_WANTRES, 925 VARE_WANTRES,
926 926
927 /* 927 /*
928 * Parse and evaluate the expression. It is an error if a 928 * Parse and evaluate the expression. It is an error if a
929 * subexpression evaluates to undefined. 929 * subexpression evaluates to undefined.
930 */ 930 */
931 VARE_UNDEFERR, 931 VARE_UNDEFERR,
932 932
933 /* 933 /*
934 * Parse and evaluate the expression. Keep '$$' as '$$' instead of 934 * Parse and evaluate the expression. Keep '$$' as '$$' instead of
935 * reducing it to a single '$'. Subexpressions that evaluate to 935 * reducing it to a single '$'. Subexpressions that evaluate to
936 * undefined expand to an empty string. 936 * undefined expand to an empty string.
937 * 937 *
938 * Used in variable assignments using the ':=' operator. It allows 938 * Used in variable assignments using the ':=' operator. It allows
939 * multiple such assignments to be chained without accidentally 939 * multiple such assignments to be chained without accidentally
940 * expanding '$$file' to '$file' in the first assignment and 940 * expanding '$$file' to '$file' in the first assignment and
941 * interpreting it as '${f}' followed by 'ile' in the next assignment. 941 * interpreting it as '${f}' followed by 'ile' in the next assignment.
942 */ 942 */
943 VARE_EVAL_KEEP_DOLLAR, 943 VARE_EVAL_KEEP_DOLLAR,
944 944
945 /* 945 /*
946 * Parse and evaluate the expression. Keep undefined variables as-is 946 * Parse and evaluate the expression. Keep undefined variables as-is
947 * instead of expanding them to an empty string. 947 * instead of expanding them to an empty string.
948 * 948 *
949 * Example for a ':=' assignment: 949 * Example for a ':=' assignment:
950 * CFLAGS = $(.INCLUDES) 950 * CFLAGS = $(.INCLUDES)
951 * CFLAGS := -I.. $(CFLAGS) 951 * CFLAGS := -I.. $(CFLAGS)
952 * # If .INCLUDES (an undocumented special variable, by the 952 * # If .INCLUDES (an undocumented special variable, by the
953 * # way) is still undefined, the updated CFLAGS becomes 953 * # way) is still undefined, the updated CFLAGS becomes
954 * # "-I.. $(.INCLUDES)". 954 * # "-I.. $(.INCLUDES)".
955 */ 955 */
956 VARE_EVAL_KEEP_UNDEF, 956 VARE_EVAL_KEEP_UNDEF,
957 957
958 /* 958 /*
959 * Parse and evaluate the expression. Keep '$$' as '$$' and preserve 959 * Parse and evaluate the expression. Keep '$$' as '$$' and preserve
960 * undefined subexpressions. 960 * undefined subexpressions.
961 */ 961 */
962 VARE_KEEP_DOLLAR_UNDEF 962 VARE_KEEP_DOLLAR_UNDEF
963} VarEvalMode; 963} VarEvalMode;
964 964
965typedef enum VarSetFlags { 965typedef enum VarSetFlags {
966 VAR_SET_NONE = 0, 966 VAR_SET_NONE = 0,
967 967
968 /* do not export */ 968 /* do not export */
969 VAR_SET_NO_EXPORT = 1 << 0, 969 VAR_SET_NO_EXPORT = 1 << 0,
970 970
971 /* 971 /*
972 * Make the variable read-only. No further modification is possible, 972 * Make the variable read-only. No further modification is possible,
973 * except for another call to Var_Set with the same flag. See the 973 * except for another call to Var_Set with the same flag. See the
974 * special targets '.NOREADONLY' and '.READONLY'. 974 * special targets '.NOREADONLY' and '.READONLY'.
975 */ 975 */
976 VAR_SET_READONLY = 1 << 1 976 VAR_SET_READONLY = 1 << 1
977} VarSetFlags; 977} VarSetFlags;
978 978
979typedef enum VarExportMode { 979typedef enum VarExportMode {
980 /* .export-env */ 980 /* .export-env */
981 VEM_ENV, 981 VEM_ENV,
982 /* .export: Initial export or update an already exported variable. */ 982 /* .export: Initial export or update an already exported variable. */
983 VEM_PLAIN, 983 VEM_PLAIN,
984 /* .export-literal: Do not expand the variable value. */ 984 /* .export-literal: Do not expand the variable value. */
985 VEM_LITERAL 985 VEM_LITERAL
986} VarExportMode; 986} VarExportMode;
987 987
988void Var_Delete(GNode *, const char *); 988void Var_Delete(GNode *, const char *);
989void Var_Undef(const char *); 989void Var_Undef(const char *);
990void Var_Set(GNode *, const char *, const char *); 990void Var_Set(GNode *, const char *, const char *);
991void Var_SetExpand(GNode *, const char *, const char *); 991void Var_SetExpand(GNode *, const char *, const char *);
992void Var_SetWithFlags(GNode *, const char *, const char *, VarSetFlags); 992void Var_SetWithFlags(GNode *, const char *, const char *, VarSetFlags);
993void Var_Append(GNode *, const char *, const char *); 993void Var_Append(GNode *, const char *, const char *);
994void Var_AppendExpand(GNode *, const char *, const char *); 994void Var_AppendExpand(GNode *, const char *, const char *);
995bool Var_Exists(GNode *, const char *) MAKE_ATTR_USE; 995bool Var_Exists(GNode *, const char *) MAKE_ATTR_USE;
996bool Var_ExistsExpand(GNode *, const char *) MAKE_ATTR_USE; 996bool Var_ExistsExpand(GNode *, const char *) MAKE_ATTR_USE;
997FStr Var_Value(GNode *, const char *) MAKE_ATTR_USE; 997FStr Var_Value(GNode *, const char *) MAKE_ATTR_USE;
998const char *GNode_ValueDirect(GNode *, const char *) MAKE_ATTR_USE; 998const char *GNode_ValueDirect(GNode *, const char *) MAKE_ATTR_USE;
999FStr Var_Parse(const char **, GNode *, VarEvalMode); 999FStr Var_Parse(const char **, GNode *, VarEvalMode);
1000char *Var_Subst(const char *, GNode *, VarEvalMode); 1000char *Var_Subst(const char *, GNode *, VarEvalMode);
1001void Var_Expand(FStr *, GNode *, VarEvalMode); 1001void Var_Expand(FStr *, GNode *, VarEvalMode);
1002void Var_Stats(void); 1002void Var_Stats(void);
1003void Var_Dump(GNode *); 1003void Var_Dump(GNode *);
1004void Var_ReexportVars(void); 1004void Var_ReexportVars(void);
1005void Var_Export(VarExportMode, const char *); 1005void Var_Export(VarExportMode, const char *);
1006void Var_ExportVars(const char *); 1006void Var_ExportVars(const char *);
1007void Var_UnExport(bool, const char *); 1007void Var_UnExport(bool, const char *);
1008void Var_ReadOnly(const char *, bool); 1008void Var_ReadOnly(const char *, bool);
1009 1009
1010void Global_Set(const char *, const char *); 1010void Global_Set(const char *, const char *);
1011void Global_Append(const char *, const char *); 1011void Global_Append(const char *, const char *);
1012void Global_Delete(const char *); 1012void Global_Delete(const char *);
1013void Global_Set_ReadOnly(const char *, const char *); 1013void Global_Set_ReadOnly(const char *, const char *);
1014 1014
1015/* util.c */ 1015/* util.c */
1016typedef void (*SignalProc)(int); 1016typedef void (*SignalProc)(int);
1017SignalProc bmake_signal(int, SignalProc); 1017SignalProc bmake_signal(int, SignalProc);
1018 1018
1019/* make.c */ 1019/* make.c */
1020void GNode_UpdateYoungestChild(GNode *, GNode *); 1020void GNode_UpdateYoungestChild(GNode *, GNode *);
1021bool GNode_IsOODate(GNode *) MAKE_ATTR_USE; 1021bool GNode_IsOODate(GNode *) MAKE_ATTR_USE;
1022void Make_ExpandUse(GNodeList *); 1022void Make_ExpandUse(GNodeList *);
1023time_t Make_Recheck(GNode *) MAKE_ATTR_USE; 1023time_t Make_Recheck(GNode *) MAKE_ATTR_USE;
1024void Make_HandleUse(GNode *, GNode *); 1024void Make_HandleUse(GNode *, GNode *);
1025void Make_Update(GNode *); 1025void Make_Update(GNode *);
1026void GNode_SetLocalVars(GNode *); 1026void GNode_SetLocalVars(GNode *);
1027bool Make_Run(GNodeList *); 1027bool Make_Run(GNodeList *);
1028bool shouldDieQuietly(GNode *, int) MAKE_ATTR_USE; 1028bool shouldDieQuietly(GNode *, int) MAKE_ATTR_USE;
1029void PrintOnError(GNode *, const char *); 1029void PrintOnError(GNode *, const char *);
1030void Main_ExportMAKEFLAGS(bool); 1030void Main_ExportMAKEFLAGS(bool);
1031bool Main_SetObjdir(bool, const char *, ...) MAKE_ATTR_PRINTFLIKE(2, 3); 1031bool Main_SetObjdir(bool, const char *, ...) MAKE_ATTR_PRINTFLIKE(2, 3);
1032int mkTempFile(const char *, char *, size_t) MAKE_ATTR_USE; 1032int mkTempFile(const char *, char *, size_t) MAKE_ATTR_USE;
1033int str2Lst_Append(StringList *, char *); 1033int str2Lst_Append(StringList *, char *);
1034void GNode_FprintDetails(FILE *, const char *, const GNode *, const char *); 1034void GNode_FprintDetails(FILE *, const char *, const GNode *, const char *);
1035bool GNode_ShouldExecute(GNode *gn) MAKE_ATTR_USE; 1035bool GNode_ShouldExecute(GNode *gn) MAKE_ATTR_USE;
1036 1036
1037/* See if the node was seen on the left-hand side of a dependency operator. */ 1037/* See if the node was seen on the left-hand side of a dependency operator. */
1038MAKE_INLINE bool MAKE_ATTR_USE 1038MAKE_INLINE bool MAKE_ATTR_USE
1039GNode_IsTarget(const GNode *gn) 1039GNode_IsTarget(const GNode *gn)
1040{ 1040{
1041 return (gn->type & OP_OPMASK) != OP_NONE; 1041 return (gn->type & OP_OPMASK) != OP_NONE;
1042} 1042}
1043 1043
1044MAKE_INLINE const char * MAKE_ATTR_USE 1044MAKE_INLINE const char * MAKE_ATTR_USE
1045GNode_Path(const GNode *gn) 1045GNode_Path(const GNode *gn)
1046{ 1046{
1047 return gn->path != NULL ? gn->path : gn->name; 1047 return gn->path != NULL ? gn->path : gn->name;
1048} 1048}
1049 1049
1050MAKE_INLINE bool MAKE_ATTR_USE 1050MAKE_INLINE bool MAKE_ATTR_USE
1051GNode_IsWaitingFor(const GNode *gn) 1051GNode_IsWaitingFor(const GNode *gn)
1052{ 1052{
1053 return gn->flags.remake && gn->made <= REQUESTED; 1053 return gn->flags.remake && gn->made <= REQUESTED;
1054} 1054}
1055 1055
1056MAKE_INLINE bool MAKE_ATTR_USE 1056MAKE_INLINE bool MAKE_ATTR_USE
1057GNode_IsReady(const GNode *gn) 1057GNode_IsReady(const GNode *gn)
1058{ 1058{
1059 return gn->made > DEFERRED; 1059 return gn->made > DEFERRED;
1060} 1060}
1061 1061
1062MAKE_INLINE bool MAKE_ATTR_USE 1062MAKE_INLINE bool MAKE_ATTR_USE
1063GNode_IsDone(const GNode *gn) 1063GNode_IsDone(const GNode *gn)
1064{ 1064{
1065 return gn->made >= MADE; 1065 return gn->made >= MADE;
1066} 1066}
1067 1067
1068MAKE_INLINE bool MAKE_ATTR_USE 1068MAKE_INLINE bool MAKE_ATTR_USE
1069GNode_IsError(const GNode *gn) 1069GNode_IsError(const GNode *gn)
1070{ 1070{
1071 return gn->made == ERROR || gn->made == ABORTED; 1071 return gn->made == ERROR || gn->made == ABORTED;
1072} 1072}
1073 1073
1074MAKE_INLINE bool MAKE_ATTR_USE 1074MAKE_INLINE bool MAKE_ATTR_USE
1075GNode_IsMainCandidate(const GNode *gn) 1075GNode_IsMainCandidate(const GNode *gn)
1076{ 1076{
1077 return (gn->type & (OP_NOTMAIN | OP_USE | OP_USEBEFORE | 1077 return (gn->type & (OP_NOTMAIN | OP_USE | OP_USEBEFORE |
1078 OP_EXEC | OP_TRANSFORM)) == 0; 1078 OP_EXEC | OP_TRANSFORM)) == 0;
1079} 1079}
1080 1080
1081/* Return whether the target file should be preserved on interrupt. */ 1081/* Return whether the target file should be preserved on interrupt. */
1082MAKE_INLINE bool MAKE_ATTR_USE 1082MAKE_INLINE bool MAKE_ATTR_USE
1083GNode_IsPrecious(const GNode *gn) 1083GNode_IsPrecious(const GNode *gn)
1084{ 1084{
1085 /* XXX: Why are '::' targets precious? */ 1085 /* XXX: Why are '::' targets precious? */
1086 return allPrecious || gn->type & (OP_PRECIOUS | OP_DOUBLEDEP); 1086 return allPrecious || gn->type & (OP_PRECIOUS | OP_DOUBLEDEP);
1087} 1087}
1088 1088
1089MAKE_INLINE const char * MAKE_ATTR_USE 1089MAKE_INLINE const char * MAKE_ATTR_USE
1090GNode_VarTarget(GNode *gn) { return GNode_ValueDirect(gn, TARGET); } 1090GNode_VarTarget(GNode *gn) { return GNode_ValueDirect(gn, TARGET); }
1091MAKE_INLINE const char * MAKE_ATTR_USE 1091MAKE_INLINE const char * MAKE_ATTR_USE
1092GNode_VarOodate(GNode *gn) { return GNode_ValueDirect(gn, OODATE); } 1092GNode_VarOodate(GNode *gn) { return GNode_ValueDirect(gn, OODATE); }
1093MAKE_INLINE const char * MAKE_ATTR_USE 1093MAKE_INLINE const char * MAKE_ATTR_USE
1094GNode_VarAllsrc(GNode *gn) { return GNode_ValueDirect(gn, ALLSRC); } 1094GNode_VarAllsrc(GNode *gn) { return GNode_ValueDirect(gn, ALLSRC); }
1095MAKE_INLINE const char * MAKE_ATTR_USE 1095MAKE_INLINE const char * MAKE_ATTR_USE
1096GNode_VarImpsrc(GNode *gn) { return GNode_ValueDirect(gn, IMPSRC); } 1096GNode_VarImpsrc(GNode *gn) { return GNode_ValueDirect(gn, IMPSRC); }
1097MAKE_INLINE const char * MAKE_ATTR_USE 1097MAKE_INLINE const char * MAKE_ATTR_USE
1098GNode_VarPrefix(GNode *gn) { return GNode_ValueDirect(gn, PREFIX); } 1098GNode_VarPrefix(GNode *gn) { return GNode_ValueDirect(gn, PREFIX); }
1099MAKE_INLINE const char * MAKE_ATTR_USE 1099MAKE_INLINE const char * MAKE_ATTR_USE
1100GNode_VarArchive(GNode *gn) { return GNode_ValueDirect(gn, ARCHIVE); } 1100GNode_VarArchive(GNode *gn) { return GNode_ValueDirect(gn, ARCHIVE); }
1101MAKE_INLINE const char * MAKE_ATTR_USE 1101MAKE_INLINE const char * MAKE_ATTR_USE
1102GNode_VarMember(GNode *gn) { return GNode_ValueDirect(gn, MEMBER); } 1102GNode_VarMember(GNode *gn) { return GNode_ValueDirect(gn, MEMBER); }
1103 1103
1104MAKE_INLINE void * MAKE_ATTR_USE 1104MAKE_INLINE void * MAKE_ATTR_USE
1105UNCONST(const void *ptr) 1105UNCONST(const void *ptr)
1106{ 1106{
1107 void *ret; 1107 void *ret;
1108 memcpy(&ret, &ptr, sizeof(ret)); 1108 memcpy(&ret, &ptr, sizeof(ret));
1109 return ret; 1109 return ret;
1110} 1110}
1111 1111
1112/* At least GNU/Hurd systems lack hardcoded MAXPATHLEN/PATH_MAX */ 1112/* At least GNU/Hurd systems lack hardcoded MAXPATHLEN/PATH_MAX */
1113#include <limits.h> 1113#include <limits.h>
1114#ifndef MAXPATHLEN 1114#ifndef MAXPATHLEN
1115#define MAXPATHLEN 4096 1115#define MAXPATHLEN 4096
1116#endif 1116#endif
1117#ifndef PATH_MAX 1117#ifndef PATH_MAX
1118#define PATH_MAX MAXPATHLEN 1118#define PATH_MAX MAXPATHLEN
1119#endif 1119#endif
1120 1120
1121#if defined(SYSV) 1121#if defined(SYSV)
1122#define KILLPG(pid, sig) kill(-(pid), (sig)) 1122#define KILLPG(pid, sig) kill(-(pid), (sig))
1123#else 1123#else
1124#define KILLPG(pid, sig) killpg((pid), (sig)) 1124#define KILLPG(pid, sig) killpg((pid), (sig))
1125#endif 1125#endif
1126 1126
1127MAKE_INLINE bool MAKE_ATTR_USE 1127MAKE_INLINE bool MAKE_ATTR_USE
1128ch_isalnum(char ch) { return isalnum((unsigned char)ch) != 0; } 1128ch_isalnum(char ch) { return isalnum((unsigned char)ch) != 0; }
1129MAKE_INLINE bool MAKE_ATTR_USE 1129MAKE_INLINE bool MAKE_ATTR_USE
1130ch_isalpha(char ch) { return isalpha((unsigned char)ch) != 0; } 1130ch_isalpha(char ch) { return isalpha((unsigned char)ch) != 0; }
1131MAKE_INLINE bool MAKE_ATTR_USE 1131MAKE_INLINE bool MAKE_ATTR_USE
1132ch_isdigit(char ch) { return isdigit((unsigned char)ch) != 0; } 1132ch_isdigit(char ch) { return isdigit((unsigned char)ch) != 0; }
1133MAKE_INLINE bool MAKE_ATTR_USE 1133MAKE_INLINE bool MAKE_ATTR_USE
1134ch_islower(char ch) { return islower((unsigned char)ch) != 0; } 1134ch_islower(char ch) { return islower((unsigned char)ch) != 0; }
1135MAKE_INLINE bool MAKE_ATTR_USE 1135MAKE_INLINE bool MAKE_ATTR_USE
1136ch_isspace(char ch) { return isspace((unsigned char)ch) != 0; } 1136ch_isspace(char ch) { return isspace((unsigned char)ch) != 0; }
1137MAKE_INLINE bool MAKE_ATTR_USE 1137MAKE_INLINE bool MAKE_ATTR_USE
1138ch_isupper(char ch) { return isupper((unsigned char)ch) != 0; } 1138ch_isupper(char ch) { return isupper((unsigned char)ch) != 0; }
1139MAKE_INLINE char MAKE_ATTR_USE 1139MAKE_INLINE char MAKE_ATTR_USE
1140ch_tolower(char ch) { return (char)tolower((unsigned char)ch); } 1140ch_tolower(char ch) { return (char)tolower((unsigned char)ch); }
1141MAKE_INLINE char MAKE_ATTR_USE 1141MAKE_INLINE char MAKE_ATTR_USE
1142ch_toupper(char ch) { return (char)toupper((unsigned char)ch); } 1142ch_toupper(char ch) { return (char)toupper((unsigned char)ch); }
1143 1143
1144MAKE_INLINE void 1144MAKE_INLINE void
1145cpp_skip_whitespace(const char **pp) 1145cpp_skip_whitespace(const char **pp)
1146{ 1146{
1147 while (ch_isspace(**pp)) 1147 while (ch_isspace(**pp))
1148 (*pp)++; 1148 (*pp)++;
1149} 1149}
1150 1150
1151MAKE_INLINE void 1151MAKE_INLINE void
1152cpp_skip_hspace(const char **pp) 1152cpp_skip_hspace(const char **pp)
1153{ 1153{
1154 while (**pp == ' ' || **pp == '\t') 1154 while (**pp == ' ' || **pp == '\t')
1155 (*pp)++; 1155 (*pp)++;
1156} 1156}
1157 1157
1158MAKE_INLINE bool 1158MAKE_INLINE bool
1159cpp_skip_string(const char **pp, const char *s) 1159cpp_skip_string(const char **pp, const char *s)
1160{ 1160{
1161 const char *p = *pp; 1161 const char *p = *pp;
1162 while (*p == *s && *s != '\0') 1162 while (*p == *s && *s != '\0')
1163 p++, s++; 1163 p++, s++;
1164 if (*s == '\0') 1164 if (*s == '\0')
1165 *pp = p; 1165 *pp = p;
1166 return *s == '\0'; 1166 return *s == '\0';
1167} 1167}
1168 1168
1169MAKE_INLINE void 1169MAKE_INLINE void
1170pp_skip_whitespace(char **pp) 1170pp_skip_whitespace(char **pp)
1171{ 1171{
1172 while (ch_isspace(**pp)) 1172 while (ch_isspace(**pp))
1173 (*pp)++; 1173 (*pp)++;
1174} 1174}
1175 1175
1176MAKE_INLINE void 1176MAKE_INLINE void
1177pp_skip_hspace(char **pp) 1177pp_skip_hspace(char **pp)
1178{ 1178{
1179 while (**pp == ' ' || **pp == '\t') 1179 while (**pp == ' ' || **pp == '\t')
1180 (*pp)++; 1180 (*pp)++;
1181} 1181}
1182 1182
1183#if defined(lint) 1183#if defined(lint)
1184extern void do_not_define_rcsid(void); /* for lint */ 1184extern void do_not_define_rcsid(void); /* for lint */
1185# define MAKE_RCSID(id) extern void do_not_define_rcsid(void) 1185# define MAKE_RCSID(id) extern void do_not_define_rcsid(void)
1186#elif defined(MAKE_NATIVE) 1186#elif defined(MAKE_NATIVE)
1187# include <sys/cdefs.h> 1187# include <sys/cdefs.h>
1188# define MAKE_RCSID(id) __RCSID(id) 1188# define MAKE_RCSID(id) __RCSID(id)
1189#elif defined(MAKE_ALL_IN_ONE) && defined(__COUNTER__) 1189#elif defined(MAKE_ALL_IN_ONE) && defined(__COUNTER__)
1190# define MAKE_RCSID_CONCAT(x, y) CONCAT(x, y) 1190# define MAKE_RCSID_CONCAT(x, y) CONCAT(x, y)
1191# define MAKE_RCSID(id) static volatile char \ 1191# define MAKE_RCSID(id) static volatile char \
1192 MAKE_RCSID_CONCAT(rcsid_, __COUNTER__)[] = id 1192 MAKE_RCSID_CONCAT(rcsid_, __COUNTER__)[] = id
1193#elif defined(MAKE_ALL_IN_ONE) 1193#elif defined(MAKE_ALL_IN_ONE)
1194# define MAKE_RCSID(id) extern void do_not_define_rcsid(void) 1194# define MAKE_RCSID(id) extern void do_not_define_rcsid(void)
1195#else 1195#else
1196# define MAKE_RCSID(id) static volatile char rcsid[] = id 1196# define MAKE_RCSID(id) static volatile char rcsid[] = id
1197#endif 1197#endif
1198 1198
1199#endif 1199#endif