cond.c revision 1.118 1 /* $NetBSD: cond.c,v 1.118 2020/09/10 22:47:22 rillig Exp $ */
2
3 /*
4 * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Adam de Boor.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 /*
36 * Copyright (c) 1988, 1989 by Adam de Boor
37 * Copyright (c) 1989 by Berkeley Softworks
38 * All rights reserved.
39 *
40 * This code is derived from software contributed to Berkeley by
41 * Adam de Boor.
42 *
43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions
45 * are met:
46 * 1. Redistributions of source code must retain the above copyright
47 * notice, this list of conditions and the following disclaimer.
48 * 2. Redistributions in binary form must reproduce the above copyright
49 * notice, this list of conditions and the following disclaimer in the
50 * documentation and/or other materials provided with the distribution.
51 * 3. All advertising materials mentioning features or use of this software
52 * must display the following acknowledgement:
53 * This product includes software developed by the University of
54 * California, Berkeley and 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
57 * without specific prior written permission.
58 *
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
61 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
62 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
63 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
64 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
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
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
69 * SUCH DAMAGE.
70 */
71
72 #ifndef MAKE_NATIVE
73 static char rcsid[] = "$NetBSD: cond.c,v 1.118 2020/09/10 22:47:22 rillig Exp $";
74 #else
75 #include <sys/cdefs.h>
76 #ifndef lint
77 #if 0
78 static char sccsid[] = "@(#)cond.c 8.2 (Berkeley) 1/2/94";
79 #else
80 __RCSID("$NetBSD: cond.c,v 1.118 2020/09/10 22:47:22 rillig Exp $");
81 #endif
82 #endif /* not lint */
83 #endif
84
85 /* Handling of conditionals in a makefile.
86 *
87 * Interface:
88 * Cond_Eval Evaluate the conditional in the passed line.
89 *
90 * Cond_EvalExpression
91 * Evaluate the conditional in the passed line, which
92 * is either the argument of one of the .if directives
93 * or the condition in a :?true:false variable modifier.
94 *
95 * Cond_save_depth
96 * Cond_restore_depth
97 * Save and restore the nesting of the conditions, at
98 * the start and end of including another makefile, to
99 * ensure that in each makefile the conditional
100 * directives are well-balanced.
101 */
102
103 #include <errno.h>
104
105 #include "make.h"
106 #include "dir.h"
107
108 /*
109 * The parsing of conditional expressions is based on this grammar:
110 * E -> F || E
111 * E -> F
112 * F -> T && F
113 * F -> T
114 * T -> defined(variable)
115 * T -> make(target)
116 * T -> exists(file)
117 * T -> empty(varspec)
118 * T -> target(name)
119 * T -> commands(name)
120 * T -> symbol
121 * T -> $(varspec) op value
122 * T -> $(varspec) == "string"
123 * T -> $(varspec) != "string"
124 * T -> "string"
125 * T -> ( E )
126 * T -> ! T
127 * op -> == | != | > | < | >= | <=
128 *
129 * 'symbol' is some other symbol to which the default function is applied.
130 *
131 * Tokens are scanned from the lexer. The scanner (CondToken)
132 * will return TOK_AND for '&' and '&&', TOK_OR for '|' and '||',
133 * TOK_NOT for '!', TOK_LPAREN for '(', TOK_RPAREN for ')' and will evaluate
134 * the other terminal symbols, using either the default function or the
135 * function given in the terminal, and return the result as either TOK_TRUE
136 * or TOK_FALSE.
137 *
138 * TOK_FALSE is 0 and TOK_TRUE 1 so we can directly assign C comparisons.
139 *
140 * All Non-Terminal functions (CondE, CondF and CondT) return TOK_ERROR on
141 * error.
142 */
143 typedef enum {
144 TOK_FALSE = 0, TOK_TRUE = 1, TOK_AND, TOK_OR, TOK_NOT,
145 TOK_LPAREN, TOK_RPAREN, TOK_EOF, TOK_NONE, TOK_ERROR
146 } Token;
147
148 typedef struct {
149 const struct If *if_info; /* Info for current statement */
150 const char *condExpr; /* The expression to parse */
151 Token curr; /* Single push-back token used in parsing */
152 } CondLexer;
153
154 static Token CondE(CondLexer *lex, Boolean);
155 static CondEvalResult do_Cond_EvalExpression(CondLexer *lex, Boolean *);
156
157 static unsigned int cond_depth = 0; /* current .if nesting level */
158 static unsigned int cond_min_depth = 0; /* depth at makefile open */
159
160 /*
161 * Indicate when we should be strict about lhs of comparisons.
162 * In strict mode, the lhs must be a variable expression or a string literal
163 * in quotes. In non-strict mode it may also be an unquoted string literal.
164 *
165 * TRUE when Cond_EvalExpression is called from Cond_Eval (.if etc)
166 * FALSE when Cond_EvalExpression is called from var.c:ApplyModifiers
167 * since lhs is already expanded and we cannot tell if
168 * it was a variable reference or not.
169 */
170 static Boolean lhsStrict;
171
172 static int
173 istoken(const char *str, const char *tok, size_t len)
174 {
175 return strncmp(str, tok, len) == 0 && !isalpha((unsigned char)str[len]);
176 }
177
178 /* Push back the most recent token read. We only need one level of this. */
179 static void
180 CondLexer_PushBack(CondLexer *lex, Token t)
181 {
182 assert(lex->curr == TOK_NONE);
183 assert(t != TOK_NONE);
184
185 lex->curr = t;
186 }
187
188 static void
189 CondLexer_SkipWhitespace(CondLexer *lex)
190 {
191 while (isspace((unsigned char)lex->condExpr[0]))
192 lex->condExpr++;
193 }
194
195 /* Parse the argument of a built-in function.
196 *
197 * Arguments:
198 * *linePtr initially points to the '(', upon successful return points
199 * beyond the ')'.
200 *
201 * *out_arg receives the argument as string.
202 *
203 * func says whether the argument belongs to an actual function, or
204 * whether the parsed argument is passed to the default function.
205 *
206 * Return the length of the argument. */
207 static int
208 ParseFuncArg(Boolean doEval, const char **linePtr, char **out_arg,
209 const char *func) {
210 const char *cp;
211 Buffer buf;
212 int paren_depth;
213 char ch;
214 size_t argLen;
215
216 cp = *linePtr;
217 if (func != NULL)
218 /* Skip opening '(' - verified by caller */
219 cp++;
220
221 if (*cp == '\0') {
222 /*
223 * No arguments whatsoever. Because 'make' and 'defined' aren't really
224 * "reserved words", we don't print a message. I think this is better
225 * than hitting the user with a warning message every time s/he uses
226 * the word 'make' or 'defined' at the beginning of a symbol...
227 */
228 *out_arg = NULL;
229 return 0;
230 }
231
232 while (*cp == ' ' || *cp == '\t') {
233 cp++;
234 }
235
236 /*
237 * Create a buffer for the argument and start it out at 16 characters
238 * long. Why 16? Why not?
239 */
240 Buf_Init(&buf, 16);
241
242 paren_depth = 0;
243 for (;;) {
244 ch = *cp;
245 if (ch == 0 || ch == ' ' || ch == '\t')
246 break;
247 if ((ch == '&' || ch == '|') && paren_depth == 0)
248 break;
249 if (*cp == '$') {
250 /*
251 * Parse the variable spec and install it as part of the argument
252 * if it's valid. We tell Var_Parse to complain on an undefined
253 * variable, so we don't need to do it. Nor do we return an error,
254 * though perhaps we should...
255 */
256 void *freeIt;
257 VarEvalFlags eflags = VARE_UNDEFERR | (doEval ? VARE_WANTRES : 0);
258 const char *cp2 = Var_ParsePP(&cp, VAR_CMD, eflags, &freeIt);
259 Buf_AddStr(&buf, cp2);
260 free(freeIt);
261 continue;
262 }
263 if (ch == '(')
264 paren_depth++;
265 else if (ch == ')' && --paren_depth < 0)
266 break;
267 Buf_AddByte(&buf, *cp);
268 cp++;
269 }
270
271 *out_arg = Buf_GetAll(&buf, &argLen);
272 Buf_Destroy(&buf, FALSE);
273
274 while (*cp == ' ' || *cp == '\t') {
275 cp++;
276 }
277
278 if (func != NULL && *cp++ != ')') {
279 Parse_Error(PARSE_WARNING, "Missing closing parenthesis for %s()",
280 func);
281 return 0;
282 }
283
284 *linePtr = cp;
285 return argLen;
286 }
287
288 /* Test whether the given variable is defined. */
289 static Boolean
290 CondDoDefined(int argLen MAKE_ATTR_UNUSED, const char *arg)
291 {
292 char *freeIt;
293 Boolean result = Var_Value(arg, VAR_CMD, &freeIt) != NULL;
294 bmake_free(freeIt);
295 return result;
296 }
297
298 /* Wrapper around Str_Match, to be used by Lst_Find. */
299 static Boolean
300 CondFindStrMatch(const void *string, const void *pattern)
301 {
302 return Str_Match(string, pattern);
303 }
304
305 /* See if the given target is being made. */
306 static Boolean
307 CondDoMake(int argLen MAKE_ATTR_UNUSED, const char *arg)
308 {
309 return Lst_Find(create, CondFindStrMatch, arg) != NULL;
310 }
311
312 /* See if the given file exists. */
313 static Boolean
314 CondDoExists(int argLen MAKE_ATTR_UNUSED, const char *arg)
315 {
316 Boolean result;
317 char *path;
318
319 path = Dir_FindFile(arg, dirSearchPath);
320 if (DEBUG(COND)) {
321 fprintf(debug_file, "exists(%s) result is \"%s\"\n",
322 arg, path ? path : "");
323 }
324 if (path != NULL) {
325 result = TRUE;
326 free(path);
327 } else {
328 result = FALSE;
329 }
330 return result;
331 }
332
333 /* See if the given node exists and is an actual target. */
334 static Boolean
335 CondDoTarget(int argLen MAKE_ATTR_UNUSED, const char *arg)
336 {
337 GNode *gn;
338
339 gn = Targ_FindNode(arg, TARG_NOCREATE);
340 return gn != NULL && !OP_NOP(gn->type);
341 }
342
343 /* See if the given node exists and is an actual target with commands
344 * associated with it. */
345 static Boolean
346 CondDoCommands(int argLen MAKE_ATTR_UNUSED, const char *arg)
347 {
348 GNode *gn;
349
350 gn = Targ_FindNode(arg, TARG_NOCREATE);
351 return gn != NULL && !OP_NOP(gn->type) && !Lst_IsEmpty(gn->commands);
352 }
353
354 /*-
355 * Convert the given number into a double.
356 * We try a base 10 or 16 integer conversion first, if that fails
357 * then we try a floating point conversion instead.
358 *
359 * Results:
360 * Sets 'value' to double value of string.
361 * Returns TRUE if the conversion succeeded.
362 */
363 static Boolean
364 CondCvtArg(const char *str, double *value)
365 {
366 char *eptr, ech;
367 unsigned long l_val;
368 double d_val;
369
370 errno = 0;
371 if (!*str) {
372 *value = (double)0;
373 return TRUE;
374 }
375 l_val = strtoul(str, &eptr, str[1] == 'x' ? 16 : 10);
376 ech = *eptr;
377 if (ech == 0 && errno != ERANGE) {
378 d_val = str[0] == '-' ? -(double)-l_val : (double)l_val;
379 } else {
380 if (ech != 0 && ech != '.' && ech != 'e' && ech != 'E')
381 return FALSE;
382 d_val = strtod(str, &eptr);
383 if (*eptr)
384 return FALSE;
385 }
386
387 *value = d_val;
388 return TRUE;
389 }
390
391 /*-
392 * Parse a string from a variable reference or an optionally quoted
393 * string. This is called for the lhs and rhs of string compares.
394 *
395 * Results:
396 * Returns the string, absent any quotes, or NULL on error.
397 * Sets quoted if the string was quoted.
398 * Sets freeIt if needed.
399 */
400 /* coverity:[+alloc : arg-*3] */
401 static const char *
402 CondGetString(CondLexer *lex, Boolean doEval, Boolean *quoted, void **freeIt,
403 Boolean strictLHS)
404 {
405 Buffer buf;
406 const char *str;
407 int len;
408 Boolean qt;
409 const char *start;
410 VarEvalFlags eflags;
411
412 Buf_Init(&buf, 0);
413 str = NULL;
414 *freeIt = NULL;
415 *quoted = qt = *lex->condExpr == '"' ? 1 : 0;
416 if (qt)
417 lex->condExpr++;
418 for (start = lex->condExpr;
419 *lex->condExpr && str == NULL; lex->condExpr++) {
420 switch (*lex->condExpr) {
421 case '\\':
422 if (lex->condExpr[1] != '\0') {
423 lex->condExpr++;
424 Buf_AddByte(&buf, *lex->condExpr);
425 }
426 break;
427 case '"':
428 if (qt) {
429 lex->condExpr++; /* we don't want the quotes */
430 goto got_str;
431 } else
432 Buf_AddByte(&buf, *lex->condExpr); /* likely? */
433 break;
434 case ')':
435 case '!':
436 case '=':
437 case '>':
438 case '<':
439 case ' ':
440 case '\t':
441 if (!qt)
442 goto got_str;
443 else
444 Buf_AddByte(&buf, *lex->condExpr);
445 break;
446 case '$':
447 /* if we are in quotes, then an undefined variable is ok */
448 eflags = ((!qt && doEval) ? VARE_UNDEFERR : 0) |
449 (doEval ? VARE_WANTRES : 0);
450 str = Var_Parse(lex->condExpr, VAR_CMD, eflags, &len, freeIt);
451 if (str == var_Error) {
452 if (*freeIt) {
453 free(*freeIt);
454 *freeIt = NULL;
455 }
456 /*
457 * Even if !doEval, we still report syntax errors, which
458 * is what getting var_Error back with !doEval means.
459 */
460 str = NULL;
461 goto cleanup;
462 }
463 lex->condExpr += len;
464 /*
465 * If the '$' was first char (no quotes), and we are
466 * followed by space, the operator or end of expression,
467 * we are done.
468 */
469 if ((lex->condExpr == start + len) &&
470 (*lex->condExpr == '\0' ||
471 isspace((unsigned char)*lex->condExpr) ||
472 strchr("!=><)", *lex->condExpr))) {
473 goto cleanup;
474 }
475
476 Buf_AddStr(&buf, str);
477 if (*freeIt) {
478 free(*freeIt);
479 *freeIt = NULL;
480 }
481 str = NULL; /* not finished yet */
482 lex->condExpr--; /* don't skip over next char */
483 break;
484 default:
485 if (strictLHS && !qt && *start != '$' &&
486 !isdigit((unsigned char)*start)) {
487 /* lhs must be quoted, a variable reference or number */
488 if (*freeIt) {
489 free(*freeIt);
490 *freeIt = NULL;
491 }
492 str = NULL;
493 goto cleanup;
494 }
495 Buf_AddByte(&buf, *lex->condExpr);
496 break;
497 }
498 }
499 got_str:
500 *freeIt = Buf_GetAll(&buf, NULL);
501 str = *freeIt;
502 cleanup:
503 Buf_Destroy(&buf, FALSE);
504 return str;
505 }
506
507 /* The different forms of .if directives. */
508 static const struct If {
509 const char *form; /* Form of if */
510 size_t formlen; /* Length of form */
511 Boolean doNot; /* TRUE if default function should be negated */
512 Boolean (*defProc)(int, const char *); /* Default function to apply */
513 } ifs[] = {
514 { "def", 3, FALSE, CondDoDefined },
515 { "ndef", 4, TRUE, CondDoDefined },
516 { "make", 4, FALSE, CondDoMake },
517 { "nmake", 5, TRUE, CondDoMake },
518 { "", 0, FALSE, CondDoDefined },
519 { NULL, 0, FALSE, NULL }
520 };
521
522 static Token
523 compare_expression(CondLexer *lex, Boolean doEval)
524 {
525 Token t;
526 const char *lhs;
527 const char *rhs;
528 const char *op;
529 void *lhsFree;
530 void *rhsFree;
531 Boolean lhsQuoted;
532 Boolean rhsQuoted;
533 double left, right;
534
535 t = TOK_ERROR;
536 rhs = NULL;
537 lhsFree = rhsFree = NULL;
538 lhsQuoted = rhsQuoted = FALSE;
539
540 /*
541 * Parse the variable spec and skip over it, saving its
542 * value in lhs.
543 */
544 lhs = CondGetString(lex, doEval, &lhsQuoted, &lhsFree, lhsStrict);
545 if (!lhs)
546 goto done;
547
548 CondLexer_SkipWhitespace(lex);
549
550 /*
551 * Make sure the operator is a valid one. If it isn't a
552 * known relational operator, pretend we got a
553 * != 0 comparison.
554 */
555 op = lex->condExpr;
556 switch (*lex->condExpr) {
557 case '!':
558 case '=':
559 case '<':
560 case '>':
561 if (lex->condExpr[1] == '=') {
562 lex->condExpr += 2;
563 } else {
564 lex->condExpr += 1;
565 }
566 break;
567 default:
568 if (!doEval) {
569 t = TOK_FALSE;
570 goto done;
571 }
572 /* For .ifxxx "..." check for non-empty string. */
573 if (lhsQuoted) {
574 t = lhs[0] != 0;
575 goto done;
576 }
577 /* For .ifxxx <number> compare against zero */
578 if (CondCvtArg(lhs, &left)) {
579 t = left != 0.0;
580 goto done;
581 }
582 /* For .if ${...} check for non-empty string (defProc is ifdef). */
583 if (lex->if_info->form[0] == 0) {
584 t = lhs[0] != 0;
585 goto done;
586 }
587 /* Otherwise action default test ... */
588 t = lex->if_info->defProc(strlen(lhs), lhs) != lex->if_info->doNot;
589 goto done;
590 }
591
592 CondLexer_SkipWhitespace(lex);
593
594 if (*lex->condExpr == '\0') {
595 Parse_Error(PARSE_WARNING,
596 "Missing right-hand-side of operator");
597 goto done;
598 }
599
600 rhs = CondGetString(lex, doEval, &rhsQuoted, &rhsFree, FALSE);
601 if (!rhs)
602 goto done;
603
604 if (!doEval) {
605 t = TOK_FALSE;
606 goto done;
607 }
608
609 if (rhsQuoted || lhsQuoted) {
610 do_string_compare:
611 if (((*op != '!') && (*op != '=')) || (op[1] != '=')) {
612 Parse_Error(PARSE_WARNING,
613 "String comparison operator should be either == or !=");
614 goto done;
615 }
616
617 if (DEBUG(COND)) {
618 fprintf(debug_file, "lhs = \"%s\", rhs = \"%s\", op = %.2s\n",
619 lhs, rhs, op);
620 }
621 /*
622 * Null-terminate rhs and perform the comparison.
623 * t is set to the result.
624 */
625 if (*op == '=') {
626 t = strcmp(lhs, rhs) == 0;
627 } else {
628 t = strcmp(lhs, rhs) != 0;
629 }
630 } else {
631 /*
632 * rhs is either a float or an integer. Convert both the
633 * lhs and the rhs to a double and compare the two.
634 */
635
636 if (!CondCvtArg(lhs, &left) || !CondCvtArg(rhs, &right))
637 goto do_string_compare;
638
639 if (DEBUG(COND)) {
640 fprintf(debug_file, "left = %f, right = %f, op = %.2s\n", left,
641 right, op);
642 }
643 switch (op[0]) {
644 case '!':
645 if (op[1] != '=') {
646 Parse_Error(PARSE_WARNING,
647 "Unknown operator");
648 goto done;
649 }
650 t = (left != right);
651 break;
652 case '=':
653 if (op[1] != '=') {
654 Parse_Error(PARSE_WARNING,
655 "Unknown operator");
656 goto done;
657 }
658 t = (left == right);
659 break;
660 case '<':
661 if (op[1] == '=') {
662 t = (left <= right);
663 } else {
664 t = (left < right);
665 }
666 break;
667 case '>':
668 if (op[1] == '=') {
669 t = (left >= right);
670 } else {
671 t = (left > right);
672 }
673 break;
674 }
675 }
676
677 done:
678 free(lhsFree);
679 free(rhsFree);
680 return t;
681 }
682
683 static int
684 ParseEmptyArg(Boolean doEval, const char **linePtr, char **argPtr,
685 const char *func MAKE_ATTR_UNUSED)
686 {
687 void *val_freeIt;
688 const char *val;
689 int magic_res;
690
691 /* We do all the work here and return the result as the length */
692 *argPtr = NULL;
693
694 (*linePtr)--; /* Make (*linePtr)[1] point to the '('. */
695 val = Var_ParsePP(linePtr, VAR_CMD, doEval ? VARE_WANTRES : 0, &val_freeIt);
696 /* If successful, *linePtr points beyond the closing ')' now. */
697
698 if (val == var_Error) {
699 free(val_freeIt);
700 return -1;
701 }
702
703 /* A variable is empty when it just contains spaces... 4/15/92, christos */
704 while (isspace((unsigned char)val[0]))
705 val++;
706
707 /*
708 * For consistency with the other functions we can't generate the
709 * true/false here.
710 */
711 magic_res = *val != '\0' ? 2 : 1;
712 free(val_freeIt);
713 return magic_res;
714 }
715
716 static Boolean
717 CondDoEmpty(int arglen, const char *arg MAKE_ATTR_UNUSED)
718 {
719 /* Magic values ahead, see ParseEmptyArg. */
720 return arglen == 1;
721 }
722
723 static Token
724 compare_function(CondLexer *lex, Boolean doEval)
725 {
726 static const struct fn_def {
727 const char *fn_name;
728 size_t fn_name_len;
729 int (*fn_getarg)(Boolean, const char **, char **, const char *);
730 Boolean (*fn_proc)(int, const char *);
731 } fn_defs[] = {
732 { "defined", 7, ParseFuncArg, CondDoDefined },
733 { "make", 4, ParseFuncArg, CondDoMake },
734 { "exists", 6, ParseFuncArg, CondDoExists },
735 { "empty", 5, ParseEmptyArg, CondDoEmpty },
736 { "target", 6, ParseFuncArg, CondDoTarget },
737 { "commands", 8, ParseFuncArg, CondDoCommands },
738 { NULL, 0, NULL, NULL },
739 };
740 const struct fn_def *fn_def;
741 Token t;
742 char *arg = NULL;
743 int arglen;
744 const char *cp = lex->condExpr;
745 const char *cp1;
746
747 for (fn_def = fn_defs; fn_def->fn_name != NULL; fn_def++) {
748 if (!istoken(cp, fn_def->fn_name, fn_def->fn_name_len))
749 continue;
750 cp += fn_def->fn_name_len;
751 /* There can only be whitespace before the '(' */
752 while (isspace((unsigned char)*cp))
753 cp++;
754 if (*cp != '(')
755 break;
756
757 arglen = fn_def->fn_getarg(doEval, &cp, &arg, fn_def->fn_name);
758 if (arglen <= 0) {
759 lex->condExpr = cp;
760 return arglen < 0 ? TOK_ERROR : TOK_FALSE;
761 }
762 /* Evaluate the argument using the required function. */
763 t = !doEval || fn_def->fn_proc(arglen, arg);
764 free(arg);
765 lex->condExpr = cp;
766 return t;
767 }
768
769 /* Push anything numeric through the compare expression */
770 cp = lex->condExpr;
771 if (isdigit((unsigned char)cp[0]) || strchr("+-", cp[0]))
772 return compare_expression(lex, doEval);
773
774 /*
775 * Most likely we have a naked token to apply the default function to.
776 * However ".if a == b" gets here when the "a" is unquoted and doesn't
777 * start with a '$'. This surprises people.
778 * If what follows the function argument is a '=' or '!' then the syntax
779 * would be invalid if we did "defined(a)" - so instead treat as an
780 * expression.
781 */
782 arglen = ParseFuncArg(doEval, &cp, &arg, NULL);
783 for (cp1 = cp; isspace((unsigned char)*cp1); cp1++)
784 continue;
785 if (*cp1 == '=' || *cp1 == '!')
786 return compare_expression(lex, doEval);
787 lex->condExpr = cp;
788
789 /*
790 * Evaluate the argument using the default function.
791 * This path always treats .if as .ifdef. To get here, the character
792 * after .if must have been taken literally, so the argument cannot
793 * be empty - even if it contained a variable expansion.
794 */
795 t = !doEval || lex->if_info->defProc(arglen, arg) != lex->if_info->doNot;
796 free(arg);
797 return t;
798 }
799
800 /* Return the next token or comparison result from the lexer. */
801 static Token
802 CondToken(CondLexer *lex, Boolean doEval)
803 {
804 Token t;
805
806 t = lex->curr;
807 if (t != TOK_NONE) {
808 lex->curr = TOK_NONE;
809 return t;
810 }
811
812 while (lex->condExpr[0] == ' ' || lex->condExpr[0] == '\t') {
813 lex->condExpr++;
814 }
815
816 switch (lex->condExpr[0]) {
817
818 case '(':
819 lex->condExpr++;
820 return TOK_LPAREN;
821
822 case ')':
823 lex->condExpr++;
824 return TOK_RPAREN;
825
826 case '|':
827 lex->condExpr++;
828 if (lex->condExpr[0] == '|') {
829 lex->condExpr++;
830 }
831 return TOK_OR;
832
833 case '&':
834 lex->condExpr++;
835 if (lex->condExpr[0] == '&') {
836 lex->condExpr++;
837 }
838 return TOK_AND;
839
840 case '!':
841 lex->condExpr++;
842 return TOK_NOT;
843
844 case '#':
845 case '\n':
846 case '\0':
847 return TOK_EOF;
848
849 case '"':
850 case '$':
851 return compare_expression(lex, doEval);
852
853 default:
854 return compare_function(lex, doEval);
855 }
856 }
857
858 /* Parse a single term in the expression. This consists of a terminal symbol
859 * or TOK_NOT and a term (not including the binary operators):
860 *
861 * T -> defined(variable) | make(target) | exists(file) | symbol
862 * T -> ! T | ( E )
863 *
864 * Results:
865 * TOK_TRUE, TOK_FALSE or TOK_ERROR.
866 */
867 static Token
868 CondT(CondLexer *lex, Boolean doEval)
869 {
870 Token t;
871
872 t = CondToken(lex, doEval);
873
874 if (t == TOK_EOF) {
875 /*
876 * If we reached the end of the expression, the expression
877 * is malformed...
878 */
879 t = TOK_ERROR;
880 } else if (t == TOK_LPAREN) {
881 /*
882 * T -> ( E )
883 */
884 t = CondE(lex, doEval);
885 if (t != TOK_ERROR) {
886 if (CondToken(lex, doEval) != TOK_RPAREN) {
887 t = TOK_ERROR;
888 }
889 }
890 } else if (t == TOK_NOT) {
891 t = CondT(lex, doEval);
892 if (t == TOK_TRUE) {
893 t = TOK_FALSE;
894 } else if (t == TOK_FALSE) {
895 t = TOK_TRUE;
896 }
897 }
898 return t;
899 }
900
901 /* Parse a conjunctive factor (nice name, wot?)
902 *
903 * F -> T && F | T
904 *
905 * Results:
906 * TOK_TRUE, TOK_FALSE or TOK_ERROR
907 */
908 static Token
909 CondF(CondLexer *lex, Boolean doEval)
910 {
911 Token l, o;
912
913 l = CondT(lex, doEval);
914 if (l != TOK_ERROR) {
915 o = CondToken(lex, doEval);
916
917 if (o == TOK_AND) {
918 /*
919 * F -> T && F
920 *
921 * If T is TOK_FALSE, the whole thing will be TOK_FALSE, but we
922 * have to parse the r.h.s. anyway (to throw it away).
923 * If T is TOK_TRUE, the result is the r.h.s., be it a TOK_ERROR
924 * or not.
925 */
926 if (l == TOK_TRUE) {
927 l = CondF(lex, doEval);
928 } else {
929 (void)CondF(lex, FALSE);
930 }
931 } else {
932 /*
933 * F -> T
934 */
935 CondLexer_PushBack(lex, o);
936 }
937 }
938 return l;
939 }
940
941 /* Main expression production.
942 *
943 * E -> F || E | F
944 *
945 * Results:
946 * TOK_TRUE, TOK_FALSE or TOK_ERROR.
947 */
948 static Token
949 CondE(CondLexer *lex, Boolean doEval)
950 {
951 Token l, o;
952
953 l = CondF(lex, doEval);
954 if (l != TOK_ERROR) {
955 o = CondToken(lex, doEval);
956
957 if (o == TOK_OR) {
958 /*
959 * E -> F || E
960 *
961 * A similar thing occurs for ||, except that here we make sure
962 * the l.h.s. is TOK_FALSE before we bother to evaluate the r.h.s.
963 * Once again, if l is TOK_FALSE, the result is the r.h.s. and once
964 * again if l is TOK_TRUE, we parse the r.h.s. to throw it away.
965 */
966 if (l == TOK_FALSE) {
967 l = CondE(lex, doEval);
968 } else {
969 (void)CondE(lex, FALSE);
970 }
971 } else {
972 /*
973 * E -> F
974 */
975 CondLexer_PushBack(lex, o);
976 }
977 }
978 return l;
979 }
980
981 static CondEvalResult
982 do_Cond_EvalExpression(CondLexer *lex, Boolean *value)
983 {
984
985 switch (CondE(lex, TRUE)) {
986 case TOK_TRUE:
987 if (CondToken(lex, TRUE) == TOK_EOF) {
988 *value = TRUE;
989 return COND_PARSE;
990 }
991 break;
992 case TOK_FALSE:
993 if (CondToken(lex, TRUE) == TOK_EOF) {
994 *value = FALSE;
995 return COND_PARSE;
996 }
997 break;
998 default:
999 case TOK_ERROR:
1000 break;
1001 }
1002
1003 return COND_INVALID;
1004 }
1005
1006 /* Evaluate the condition in the passed line, including any side effects from
1007 * the variable expressions in the condition. The condition consists of &&,
1008 * ||, !, function(arg), comparisons and parenthetical groupings thereof.
1009 *
1010 * Results:
1011 * COND_PARSE if the condition was valid grammatically
1012 * COND_INVALID if not a valid conditional.
1013 *
1014 * (*value) is set to the boolean value of the condition
1015 */
1016 CondEvalResult
1017 Cond_EvalExpression(const struct If *info, const char *line, Boolean *value,
1018 int eprint, Boolean strictLHS)
1019 {
1020 static const struct If *dflt_info;
1021 CondLexer lex;
1022 int rval;
1023
1024 lhsStrict = strictLHS;
1025
1026 while (*line == ' ' || *line == '\t')
1027 line++;
1028
1029 if (info == NULL && (info = dflt_info) == NULL) {
1030 /* Scan for the entry for .if - it can't be first */
1031 for (info = ifs;; info++)
1032 if (info->form[0] == 0)
1033 break;
1034 dflt_info = info;
1035 }
1036 assert(info != NULL);
1037
1038 lex.if_info = info;
1039 lex.condExpr = line;
1040 lex.curr = TOK_NONE;
1041
1042 rval = do_Cond_EvalExpression(&lex, value);
1043
1044 if (rval == COND_INVALID && eprint)
1045 Parse_Error(PARSE_FATAL, "Malformed conditional (%s)", line);
1046
1047 return rval;
1048 }
1049
1050
1051 /* Evaluate the conditional in the passed line. The line looks like this:
1052 * .<cond-type> <expr>
1053 * In this line, <cond-type> is any of if, ifmake, ifnmake, ifdef, ifndef,
1054 * elif, elifmake, elifnmake, elifdef, elifndef.
1055 * In this line, <expr> consists of &&, ||, !, function(arg), comparisons
1056 * and parenthetical groupings thereof.
1057 *
1058 * Note that the states IF_ACTIVE and ELSE_ACTIVE are only different in order
1059 * to detect spurious .else lines (as are SKIP_TO_ELSE and SKIP_TO_ENDIF),
1060 * otherwise .else could be treated as '.elif 1'.
1061 *
1062 * Results:
1063 * COND_PARSE to continue parsing the lines after the conditional
1064 * (when .if or .else returns TRUE)
1065 * COND_SKIP to skip the lines after the conditional
1066 * (when .if or .elif returns FALSE, or when a previous
1067 * branch has already been taken)
1068 * COND_INVALID if the conditional was not valid, either because of
1069 * a syntax error or because some variable was undefined
1070 * or because the condition could not be evaluated
1071 */
1072 CondEvalResult
1073 Cond_Eval(const char *line)
1074 {
1075 enum { MAXIF = 128 }; /* maximum depth of .if'ing */
1076 enum { MAXIF_BUMP = 32 }; /* how much to grow by */
1077 enum if_states {
1078 IF_ACTIVE, /* .if or .elif part active */
1079 ELSE_ACTIVE, /* .else part active */
1080 SEARCH_FOR_ELIF, /* searching for .elif/else to execute */
1081 SKIP_TO_ELSE, /* has been true, but not seen '.else' */
1082 SKIP_TO_ENDIF /* nothing else to execute */
1083 };
1084 static enum if_states *cond_state = NULL;
1085 static unsigned int max_if_depth = MAXIF;
1086
1087 const struct If *ifp;
1088 Boolean isElif;
1089 Boolean value;
1090 int level; /* Level at which to report errors. */
1091 enum if_states state;
1092
1093 level = PARSE_FATAL;
1094 if (!cond_state) {
1095 cond_state = bmake_malloc(max_if_depth * sizeof(*cond_state));
1096 cond_state[0] = IF_ACTIVE;
1097 }
1098 /* skip leading character (the '.') and any whitespace */
1099 for (line++; *line == ' ' || *line == '\t'; line++)
1100 continue;
1101
1102 /* Find what type of if we're dealing with. */
1103 if (line[0] == 'e') {
1104 if (line[1] != 'l') {
1105 if (!istoken(line + 1, "ndif", 4))
1106 return COND_INVALID;
1107 /* End of conditional section */
1108 if (cond_depth == cond_min_depth) {
1109 Parse_Error(level, "if-less endif");
1110 return COND_PARSE;
1111 }
1112 /* Return state for previous conditional */
1113 cond_depth--;
1114 return cond_state[cond_depth] <= ELSE_ACTIVE
1115 ? COND_PARSE : COND_SKIP;
1116 }
1117
1118 /* Quite likely this is 'else' or 'elif' */
1119 line += 2;
1120 if (istoken(line, "se", 2)) {
1121 /* It is else... */
1122 if (cond_depth == cond_min_depth) {
1123 Parse_Error(level, "if-less else");
1124 return COND_PARSE;
1125 }
1126
1127 state = cond_state[cond_depth];
1128 switch (state) {
1129 case SEARCH_FOR_ELIF:
1130 state = ELSE_ACTIVE;
1131 break;
1132 case ELSE_ACTIVE:
1133 case SKIP_TO_ENDIF:
1134 Parse_Error(PARSE_WARNING, "extra else");
1135 /* FALLTHROUGH */
1136 default:
1137 case IF_ACTIVE:
1138 case SKIP_TO_ELSE:
1139 state = SKIP_TO_ENDIF;
1140 break;
1141 }
1142 cond_state[cond_depth] = state;
1143 return state <= ELSE_ACTIVE ? COND_PARSE : COND_SKIP;
1144 }
1145 /* Assume for now it is an elif */
1146 isElif = TRUE;
1147 } else
1148 isElif = FALSE;
1149
1150 if (line[0] != 'i' || line[1] != 'f')
1151 /* Not an ifxxx or elifxxx line */
1152 return COND_INVALID;
1153
1154 /*
1155 * Figure out what sort of conditional it is -- what its default
1156 * function is, etc. -- by looking in the table of valid "ifs"
1157 */
1158 line += 2;
1159 for (ifp = ifs;; ifp++) {
1160 if (ifp->form == NULL)
1161 return COND_INVALID;
1162 if (istoken(ifp->form, line, ifp->formlen)) {
1163 line += ifp->formlen;
1164 break;
1165 }
1166 }
1167
1168 /* Now we know what sort of 'if' it is... */
1169
1170 if (isElif) {
1171 if (cond_depth == cond_min_depth) {
1172 Parse_Error(level, "if-less elif");
1173 return COND_PARSE;
1174 }
1175 state = cond_state[cond_depth];
1176 if (state == SKIP_TO_ENDIF || state == ELSE_ACTIVE) {
1177 Parse_Error(PARSE_WARNING, "extra elif");
1178 cond_state[cond_depth] = SKIP_TO_ENDIF;
1179 return COND_SKIP;
1180 }
1181 if (state != SEARCH_FOR_ELIF) {
1182 /* Either just finished the 'true' block, or already SKIP_TO_ELSE */
1183 cond_state[cond_depth] = SKIP_TO_ELSE;
1184 return COND_SKIP;
1185 }
1186 } else {
1187 /* Normal .if */
1188 if (cond_depth + 1 >= max_if_depth) {
1189 /*
1190 * This is rare, but not impossible.
1191 * In meta mode, dirdeps.mk (only runs at level 0)
1192 * can need more than the default.
1193 */
1194 max_if_depth += MAXIF_BUMP;
1195 cond_state = bmake_realloc(cond_state,
1196 max_if_depth * sizeof(*cond_state));
1197 }
1198 state = cond_state[cond_depth];
1199 cond_depth++;
1200 if (state > ELSE_ACTIVE) {
1201 /* If we aren't parsing the data, treat as always false */
1202 cond_state[cond_depth] = SKIP_TO_ELSE;
1203 return COND_SKIP;
1204 }
1205 }
1206
1207 /* And evaluate the conditional expression */
1208 if (Cond_EvalExpression(ifp, line, &value, 1, TRUE) == COND_INVALID) {
1209 /* Syntax error in conditional, error message already output. */
1210 /* Skip everything to matching .endif */
1211 cond_state[cond_depth] = SKIP_TO_ELSE;
1212 return COND_SKIP;
1213 }
1214
1215 if (!value) {
1216 cond_state[cond_depth] = SEARCH_FOR_ELIF;
1217 return COND_SKIP;
1218 }
1219 cond_state[cond_depth] = IF_ACTIVE;
1220 return COND_PARSE;
1221 }
1222
1223 void
1224 Cond_restore_depth(unsigned int saved_depth)
1225 {
1226 int open_conds = cond_depth - cond_min_depth;
1227
1228 if (open_conds != 0 || saved_depth > cond_depth) {
1229 Parse_Error(PARSE_FATAL, "%d open conditional%s", open_conds,
1230 open_conds == 1 ? "" : "s");
1231 cond_depth = cond_min_depth;
1232 }
1233
1234 cond_min_depth = saved_depth;
1235 }
1236
1237 unsigned int
1238 Cond_save_depth(void)
1239 {
1240 int depth = cond_min_depth;
1241
1242 cond_min_depth = cond_depth;
1243 return depth;
1244 }
1245