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