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