xref: /netbsd-src/usr.bin/make/cond.c (revision 181254a7b1bdde6873432bffef2d2decc4b5c22f)
1 /*	$NetBSD: cond.c,v 1.112 2020/09/04 21:08:44 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.112 2020/09/04 21:08:44 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.112 2020/09/04 21:08:44 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 static Token CondE(Boolean);
140 static CondEvalResult do_Cond_EvalExpression(Boolean *);
141 
142 static const struct If *if_info;	/* Info for current statement */
143 static const char *condExpr;		/* The expression to parse */
144 static Token condPushBack = TOK_NONE;	/* Single push-back token used in
145 					 * parsing */
146 
147 static unsigned int cond_depth = 0;	/* current .if nesting level */
148 static unsigned int cond_min_depth = 0;	/* depth at makefile open */
149 
150 /*
151  * Indicate when we should be strict about lhs of comparisons.
152  * TRUE when Cond_EvalExpression is called from Cond_Eval (.if etc)
153  * FALSE when Cond_EvalExpression is called from var.c:ApplyModifiers
154  * since lhs is already expanded and we cannot tell if
155  * it was a variable reference or not.
156  */
157 static Boolean lhsStrict;
158 
159 static int
160 istoken(const char *str, const char *tok, size_t len)
161 {
162     return strncmp(str, tok, len) == 0 && !isalpha((unsigned char)str[len]);
163 }
164 
165 /* Push back the most recent token read. We only need one level of
166  * this, so the thing is just stored in 'condPushback'. */
167 static void
168 CondPushBack(Token t)
169 {
170     condPushBack = t;
171 }
172 
173 /* Parse the argument of a built-in function.
174  *
175  * Arguments:
176  *	*linePtr initially points to the '(', upon successful return points
177  *	beyond the ')'.
178  *
179  *	*out_arg receives the argument as string.
180  *
181  *	func says whether the argument belongs to an actual function, or
182  *	whether the parsed argument is passed to the default function.
183  *
184  *	XXX: This is ambiguous for the empty() function since its argument is
185  *	parsed differently.
186  *
187  * Return the length of the argument. */
188 static int
189 ParseFuncArg(Boolean doEval, const char **linePtr, char **out_arg,
190 	     const char *func) {
191     const char *cp;
192     Buffer buf;
193     int paren_depth;
194     char ch;
195     size_t argLen;
196 
197     cp = *linePtr;
198     if (func != NULL)
199 	/* Skip opening '(' - verified by caller */
200 	cp++;
201 
202     if (*cp == '\0') {
203 	/*
204 	 * No arguments whatsoever. Because 'make' and 'defined' aren't really
205 	 * "reserved words", we don't print a message. I think this is better
206 	 * than hitting the user with a warning message every time s/he uses
207 	 * the word 'make' or 'defined' at the beginning of a symbol...
208 	 */
209 	*out_arg = NULL;
210 	return 0;
211     }
212 
213     while (*cp == ' ' || *cp == '\t') {
214 	cp++;
215     }
216 
217     /*
218      * Create a buffer for the argument and start it out at 16 characters
219      * long. Why 16? Why not?
220      */
221     Buf_Init(&buf, 16);
222 
223     paren_depth = 0;
224     for (;;) {
225 	ch = *cp;
226 	if (ch == 0 || ch == ' ' || ch == '\t')
227 	    break;
228 	if ((ch == '&' || ch == '|') && paren_depth == 0)
229 	    break;
230 	if (*cp == '$') {
231 	    /*
232 	     * Parse the variable spec and install it as part of the argument
233 	     * if it's valid. We tell Var_Parse to complain on an undefined
234 	     * variable, so we don't do it too. Nor do we return an error,
235 	     * though perhaps we should...
236 	     */
237 	    void *freeIt;
238 	    VarEvalFlags eflags = VARE_UNDEFERR | (doEval ? VARE_WANTRES : 0);
239 	    const char *cp2 = Var_ParsePP(&cp, VAR_CMD, eflags, &freeIt);
240 	    Buf_AddStr(&buf, cp2);
241 	    free(freeIt);
242 	    continue;
243 	}
244 	if (ch == '(')
245 	    paren_depth++;
246 	else if (ch == ')' && --paren_depth < 0)
247 	    break;
248 	Buf_AddByte(&buf, *cp);
249 	cp++;
250     }
251 
252     *out_arg = Buf_GetAll(&buf, &argLen);
253     Buf_Destroy(&buf, FALSE);
254 
255     while (*cp == ' ' || *cp == '\t') {
256 	cp++;
257     }
258 
259     if (func != NULL && *cp++ != ')') {
260 	Parse_Error(PARSE_WARNING, "Missing closing parenthesis for %s()",
261 		    func);
262 	return 0;
263     }
264 
265     *linePtr = cp;
266     return argLen;
267 }
268 
269 /* Test whether the given variable is defined. */
270 static Boolean
271 CondDoDefined(int argLen MAKE_ATTR_UNUSED, const char *arg)
272 {
273     char *freeIt;
274     Boolean result = Var_Value(arg, VAR_CMD, &freeIt) != NULL;
275     bmake_free(freeIt);
276     return result;
277 }
278 
279 /* Wrapper around Str_Match, to be used by Lst_Find. */
280 static Boolean
281 CondFindStrMatch(const void *string, const void *pattern)
282 {
283     return Str_Match(string, pattern);
284 }
285 
286 /* See if the given target is being made. */
287 static Boolean
288 CondDoMake(int argLen MAKE_ATTR_UNUSED, const char *arg)
289 {
290     return Lst_Find(create, CondFindStrMatch, arg) != NULL;
291 }
292 
293 /* See if the given file exists. */
294 static Boolean
295 CondDoExists(int argLen MAKE_ATTR_UNUSED, const char *arg)
296 {
297     Boolean result;
298     char *path;
299 
300     path = Dir_FindFile(arg, dirSearchPath);
301     if (DEBUG(COND)) {
302 	fprintf(debug_file, "exists(%s) result is \"%s\"\n",
303 		arg, path ? path : "");
304     }
305     if (path != NULL) {
306 	result = TRUE;
307 	free(path);
308     } else {
309 	result = FALSE;
310     }
311     return result;
312 }
313 
314 /* See if the given node exists and is an actual target. */
315 static Boolean
316 CondDoTarget(int argLen MAKE_ATTR_UNUSED, const char *arg)
317 {
318     GNode *gn;
319 
320     gn = Targ_FindNode(arg, TARG_NOCREATE);
321     return gn != NULL && !OP_NOP(gn->type);
322 }
323 
324 /* See if the given node exists and is an actual target with commands
325  * associated with it. */
326 static Boolean
327 CondDoCommands(int argLen MAKE_ATTR_UNUSED, const char *arg)
328 {
329     GNode *gn;
330 
331     gn = Targ_FindNode(arg, TARG_NOCREATE);
332     return gn != NULL && !OP_NOP(gn->type) && !Lst_IsEmpty(gn->commands);
333 }
334 
335 /*-
336  * Convert the given number into a double.
337  * We try a base 10 or 16 integer conversion first, if that fails
338  * then we try a floating point conversion instead.
339  *
340  * Results:
341  *	Sets 'value' to double value of string.
342  *	Returns TRUE if the conversion succeeded.
343  */
344 static Boolean
345 CondCvtArg(const char *str, double *value)
346 {
347     char *eptr, ech;
348     unsigned long l_val;
349     double d_val;
350 
351     errno = 0;
352     if (!*str) {
353 	*value = (double)0;
354 	return TRUE;
355     }
356     l_val = strtoul(str, &eptr, str[1] == 'x' ? 16 : 10);
357     ech = *eptr;
358     if (ech == 0 && errno != ERANGE) {
359 	d_val = str[0] == '-' ? -(double)-l_val : (double)l_val;
360     } else {
361 	if (ech != 0 && ech != '.' && ech != 'e' && ech != 'E')
362 	    return FALSE;
363 	d_val = strtod(str, &eptr);
364 	if (*eptr)
365 	    return FALSE;
366     }
367 
368     *value = d_val;
369     return TRUE;
370 }
371 
372 /*-
373  * Get a string from a variable reference or an optionally quoted
374  * string.  This is called for the lhs and rhs of string compares.
375  *
376  * Results:
377  *	Returns the string, absent any quotes, or NULL on error.
378  *	Sets quoted if the string was quoted.
379  *	Sets freeIt if needed.
380  *
381  * Side Effects:
382  *	Moves condExpr past the end of this token.
383  */
384 /* coverity:[+alloc : arg-*2] */
385 static const char *
386 CondGetString(Boolean doEval, Boolean *quoted, void **freeIt, Boolean strictLHS)
387 {
388     Buffer buf;
389     const char *cp;
390     const char *str;
391     int len;
392     Boolean qt;
393     const char *start;
394     VarEvalFlags eflags;
395 
396     Buf_Init(&buf, 0);
397     str = NULL;
398     *freeIt = NULL;
399     *quoted = qt = *condExpr == '"' ? 1 : 0;
400     if (qt)
401 	condExpr++;
402     for (start = condExpr; *condExpr && str == NULL; condExpr++) {
403 	switch (*condExpr) {
404 	case '\\':
405 	    if (condExpr[1] != '\0') {
406 		condExpr++;
407 		Buf_AddByte(&buf, *condExpr);
408 	    }
409 	    break;
410 	case '"':
411 	    if (qt) {
412 		condExpr++;		/* we don't want the quotes */
413 		goto got_str;
414 	    } else
415 		Buf_AddByte(&buf, *condExpr); /* likely? */
416 	    break;
417 	case ')':
418 	case '!':
419 	case '=':
420 	case '>':
421 	case '<':
422 	case ' ':
423 	case '\t':
424 	    if (!qt)
425 		goto got_str;
426 	    else
427 		Buf_AddByte(&buf, *condExpr);
428 	    break;
429 	case '$':
430 	    /* if we are in quotes, then an undefined variable is ok */
431 	    eflags = ((!qt && doEval) ? VARE_UNDEFERR : 0) |
432 		     (doEval ? VARE_WANTRES : 0);
433 	    str = Var_Parse(condExpr, VAR_CMD, eflags, &len, freeIt);
434 	    if (str == var_Error) {
435 		if (*freeIt) {
436 		    free(*freeIt);
437 		    *freeIt = NULL;
438 		}
439 		/*
440 		 * Even if !doEval, we still report syntax errors, which
441 		 * is what getting var_Error back with !doEval means.
442 		 */
443 		str = NULL;
444 		goto cleanup;
445 	    }
446 	    condExpr += len;
447 	    /*
448 	     * If the '$' was first char (no quotes), and we are
449 	     * followed by space, the operator or end of expression,
450 	     * we are done.
451 	     */
452 	    if ((condExpr == start + len) &&
453 		(*condExpr == '\0' ||
454 		 isspace((unsigned char)*condExpr) ||
455 		 strchr("!=><)", *condExpr))) {
456 		goto cleanup;
457 	    }
458 	    /*
459 	     * Nope, we better copy str to buf
460 	     */
461 	    for (cp = str; *cp; cp++) {
462 		Buf_AddByte(&buf, *cp);
463 	    }
464 	    if (*freeIt) {
465 		free(*freeIt);
466 		*freeIt = NULL;
467 	    }
468 	    str = NULL;		/* not finished yet */
469 	    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, *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(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(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)*condExpr))
545 	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 = condExpr;
553     switch (*condExpr) {
554     case '!':
555     case '=':
556     case '<':
557     case '>':
558 	if (condExpr[1] == '=') {
559 	    condExpr += 2;
560 	} else {
561 	    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 (if_info->form[0] == 0) {
581 	    t = lhs[0] != 0;
582 	    goto done;
583 	}
584 	/* Otherwise action default test ... */
585 	t = if_info->defProc(strlen(lhs), lhs) != if_info->doNot;
586 	goto done;
587     }
588 
589     while (isspace((unsigned char)*condExpr))
590 	condExpr++;
591 
592     if (*condExpr == '\0') {
593 	Parse_Error(PARSE_WARNING,
594 		    "Missing right-hand-side of operator");
595 	goto done;
596     }
597 
598     rhs = CondGetString(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(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 = 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 	    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 	condExpr = cp;
764 	return t;
765     }
766 
767     /* Push anything numeric through the compare expression */
768     cp = condExpr;
769     if (isdigit((unsigned char)cp[0]) || strchr("+-", cp[0]))
770 	return compare_expression(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(doEval);
785     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 || if_info->defProc(arglen, arg) != if_info->doNot;
794     free(arg);
795     return t;
796 }
797 
798 static Token
799 CondToken(Boolean doEval)
800 {
801     Token t;
802 
803     t = condPushBack;
804     if (t != TOK_NONE) {
805 	condPushBack = TOK_NONE;
806 	return t;
807     }
808 
809     while (*condExpr == ' ' || *condExpr == '\t') {
810 	condExpr++;
811     }
812 
813     switch (*condExpr) {
814 
815     case '(':
816 	condExpr++;
817 	return TOK_LPAREN;
818 
819     case ')':
820 	condExpr++;
821 	return TOK_RPAREN;
822 
823     case '|':
824 	if (condExpr[1] == '|') {
825 	    condExpr++;
826 	}
827 	condExpr++;
828 	return TOK_OR;
829 
830     case '&':
831 	if (condExpr[1] == '&') {
832 	    condExpr++;
833 	}
834 	condExpr++;
835 	return TOK_AND;
836 
837     case '!':
838 	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(doEval);
849 
850     default:
851 	return compare_function(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(Boolean doEval)
874 {
875     Token t;
876 
877     t = CondToken(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(doEval);
890 	if (t != TOK_ERROR) {
891 	    if (CondToken(doEval) != TOK_RPAREN) {
892 		t = TOK_ERROR;
893 	    }
894 	}
895     } else if (t == TOK_NOT) {
896 	t = CondT(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(Boolean doEval)
922 {
923     Token l, o;
924 
925     l = CondT(doEval);
926     if (l != TOK_ERROR) {
927 	o = CondToken(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(doEval);
939 	    } else {
940 		(void)CondF(FALSE);
941 	    }
942 	} else {
943 	    /*
944 	     * F -> T
945 	     */
946 	    CondPushBack(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(Boolean doEval)
968 {
969     Token l, o;
970 
971     l = CondF(doEval);
972     if (l != TOK_ERROR) {
973 	o = CondToken(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(doEval);
986 	    } else {
987 		(void)CondE(FALSE);
988 	    }
989 	} else {
990 	    /*
991 	     * E -> F
992 	     */
993 	    CondPushBack(o);
994 	}
995     }
996     return l;
997 }
998 
999 static CondEvalResult
1000 do_Cond_EvalExpression(Boolean *value)
1001 {
1002 
1003     switch (CondE(TRUE)) {
1004     case TOK_TRUE:
1005 	if (CondToken(TRUE) == TOK_EOF) {
1006 	    *value = TRUE;
1007 	    return COND_PARSE;
1008 	}
1009 	break;
1010     case TOK_FALSE:
1011 	if (CondToken(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     const struct If *sv_if_info = if_info;
1040     const char *sv_condExpr = condExpr;
1041     Token sv_condPushBack = condPushBack;
1042     int rval;
1043 
1044     lhsStrict = strictLHS;
1045 
1046     while (*line == ' ' || *line == '\t')
1047 	line++;
1048 
1049     if (info == NULL && (info = dflt_info) == NULL) {
1050 	/* Scan for the entry for .if - it can't be first */
1051 	for (info = ifs;; info++)
1052 	    if (info->form[0] == 0)
1053 		break;
1054 	dflt_info = info;
1055     }
1056     assert(info != NULL);
1057 
1058     if_info = info;
1059     condExpr = line;
1060     condPushBack = TOK_NONE;
1061 
1062     rval = do_Cond_EvalExpression(value);
1063 
1064     if (rval == COND_INVALID && eprint)
1065 	Parse_Error(PARSE_FATAL, "Malformed conditional (%s)", line);
1066 
1067     if_info = sv_if_info;
1068     condExpr = sv_condExpr;
1069     condPushBack = sv_condPushBack;
1070 
1071     return rval;
1072 }
1073 
1074 
1075 /* Evaluate the conditional in the passed line. The line looks like this:
1076  *	.<cond-type> <expr>
1077  * In this line, <cond-type> is any of if, ifmake, ifnmake, ifdef, ifndef,
1078  * elif, elifmake, elifnmake, elifdef, elifndef.
1079  * In this line, <expr> consists of &&, ||, !, function(arg), comparisons
1080  * and parenthetical groupings thereof.
1081  *
1082  * Note that the states IF_ACTIVE and ELSE_ACTIVE are only different in order
1083  * to detect spurious .else lines (as are SKIP_TO_ELSE and SKIP_TO_ENDIF),
1084  * otherwise .else could be treated as '.elif 1'.
1085  *
1086  * Results:
1087  *	COND_PARSE	to continue parsing the lines after the conditional
1088  *			(when .if or .else returns TRUE)
1089  *	COND_SKIP	to skip the lines after the conditional
1090  *			(when .if or .elif returns FALSE, or when a previous
1091  *			branch has already been taken)
1092  *	COND_INVALID  	if the conditional was not valid, either because of
1093  *			a syntax error or because some variable was undefined
1094  *			or because the condition could not be evaluated
1095  */
1096 CondEvalResult
1097 Cond_Eval(const char *line)
1098 {
1099     enum { MAXIF = 128 };	/* maximum depth of .if'ing */
1100     enum { MAXIF_BUMP = 32 };	/* how much to grow by */
1101     enum if_states {
1102 	IF_ACTIVE,		/* .if or .elif part active */
1103 	ELSE_ACTIVE,		/* .else part active */
1104 	SEARCH_FOR_ELIF,	/* searching for .elif/else to execute */
1105 	SKIP_TO_ELSE,		/* has been true, but not seen '.else' */
1106 	SKIP_TO_ENDIF		/* nothing else to execute */
1107     };
1108     static enum if_states *cond_state = NULL;
1109     static unsigned int max_if_depth = MAXIF;
1110 
1111     const struct If *ifp;
1112     Boolean isElif;
1113     Boolean value;
1114     int level;			/* Level at which to report errors. */
1115     enum if_states state;
1116 
1117     level = PARSE_FATAL;
1118     if (!cond_state) {
1119 	cond_state = bmake_malloc(max_if_depth * sizeof(*cond_state));
1120 	cond_state[0] = IF_ACTIVE;
1121     }
1122     /* skip leading character (the '.') and any whitespace */
1123     for (line++; *line == ' ' || *line == '\t'; line++)
1124 	continue;
1125 
1126     /* Find what type of if we're dealing with.  */
1127     if (line[0] == 'e') {
1128 	if (line[1] != 'l') {
1129 	    if (!istoken(line + 1, "ndif", 4))
1130 		return COND_INVALID;
1131 	    /* End of conditional section */
1132 	    if (cond_depth == cond_min_depth) {
1133 		Parse_Error(level, "if-less endif");
1134 		return COND_PARSE;
1135 	    }
1136 	    /* Return state for previous conditional */
1137 	    cond_depth--;
1138 	    return cond_state[cond_depth] <= ELSE_ACTIVE
1139 		   ? COND_PARSE : COND_SKIP;
1140 	}
1141 
1142 	/* Quite likely this is 'else' or 'elif' */
1143 	line += 2;
1144 	if (istoken(line, "se", 2)) {
1145 	    /* It is else... */
1146 	    if (cond_depth == cond_min_depth) {
1147 		Parse_Error(level, "if-less else");
1148 		return COND_PARSE;
1149 	    }
1150 
1151 	    state = cond_state[cond_depth];
1152 	    switch (state) {
1153 	    case SEARCH_FOR_ELIF:
1154 		state = ELSE_ACTIVE;
1155 		break;
1156 	    case ELSE_ACTIVE:
1157 	    case SKIP_TO_ENDIF:
1158 		Parse_Error(PARSE_WARNING, "extra else");
1159 		/* FALLTHROUGH */
1160 	    default:
1161 	    case IF_ACTIVE:
1162 	    case SKIP_TO_ELSE:
1163 		state = SKIP_TO_ENDIF;
1164 		break;
1165 	    }
1166 	    cond_state[cond_depth] = state;
1167 	    return state <= ELSE_ACTIVE ? COND_PARSE : COND_SKIP;
1168 	}
1169 	/* Assume for now it is an elif */
1170 	isElif = TRUE;
1171     } else
1172 	isElif = FALSE;
1173 
1174     if (line[0] != 'i' || line[1] != 'f')
1175 	/* Not an ifxxx or elifxxx line */
1176 	return COND_INVALID;
1177 
1178     /*
1179      * Figure out what sort of conditional it is -- what its default
1180      * function is, etc. -- by looking in the table of valid "ifs"
1181      */
1182     line += 2;
1183     for (ifp = ifs;; ifp++) {
1184 	if (ifp->form == NULL)
1185 	    return COND_INVALID;
1186 	if (istoken(ifp->form, line, ifp->formlen)) {
1187 	    line += ifp->formlen;
1188 	    break;
1189 	}
1190     }
1191 
1192     /* Now we know what sort of 'if' it is... */
1193 
1194     if (isElif) {
1195 	if (cond_depth == cond_min_depth) {
1196 	    Parse_Error(level, "if-less elif");
1197 	    return COND_PARSE;
1198 	}
1199 	state = cond_state[cond_depth];
1200 	if (state == SKIP_TO_ENDIF || state == ELSE_ACTIVE) {
1201 	    Parse_Error(PARSE_WARNING, "extra elif");
1202 	    cond_state[cond_depth] = SKIP_TO_ENDIF;
1203 	    return COND_SKIP;
1204 	}
1205 	if (state != SEARCH_FOR_ELIF) {
1206 	    /* Either just finished the 'true' block, or already SKIP_TO_ELSE */
1207 	    cond_state[cond_depth] = SKIP_TO_ELSE;
1208 	    return COND_SKIP;
1209 	}
1210     } else {
1211 	/* Normal .if */
1212 	if (cond_depth + 1 >= max_if_depth) {
1213 	    /*
1214 	     * This is rare, but not impossible.
1215 	     * In meta mode, dirdeps.mk (only runs at level 0)
1216 	     * can need more than the default.
1217 	     */
1218 	    max_if_depth += MAXIF_BUMP;
1219 	    cond_state = bmake_realloc(cond_state,
1220 				       max_if_depth * sizeof(*cond_state));
1221 	}
1222 	state = cond_state[cond_depth];
1223 	cond_depth++;
1224 	if (state > ELSE_ACTIVE) {
1225 	    /* If we aren't parsing the data, treat as always false */
1226 	    cond_state[cond_depth] = SKIP_TO_ELSE;
1227 	    return COND_SKIP;
1228 	}
1229     }
1230 
1231     /* And evaluate the conditional expression */
1232     if (Cond_EvalExpression(ifp, line, &value, 1, TRUE) == COND_INVALID) {
1233 	/* Syntax error in conditional, error message already output. */
1234 	/* Skip everything to matching .endif */
1235 	cond_state[cond_depth] = SKIP_TO_ELSE;
1236 	return COND_SKIP;
1237     }
1238 
1239     if (!value) {
1240 	cond_state[cond_depth] = SEARCH_FOR_ELIF;
1241 	return COND_SKIP;
1242     }
1243     cond_state[cond_depth] = IF_ACTIVE;
1244     return COND_PARSE;
1245 }
1246 
1247 void
1248 Cond_restore_depth(unsigned int saved_depth)
1249 {
1250     int open_conds = cond_depth - cond_min_depth;
1251 
1252     if (open_conds != 0 || saved_depth > cond_depth) {
1253 	Parse_Error(PARSE_FATAL, "%d open conditional%s", open_conds,
1254 		    open_conds == 1 ? "" : "s");
1255 	cond_depth = cond_min_depth;
1256     }
1257 
1258     cond_min_depth = saved_depth;
1259 }
1260 
1261 unsigned int
1262 Cond_save_depth(void)
1263 {
1264     int depth = cond_min_depth;
1265 
1266     cond_min_depth = cond_depth;
1267     return depth;
1268 }
1269