xref: /openbsd/usr.bin/make/cond.c (revision 09467b48)
1 /*	$OpenBSD: cond.c,v 1.54 2019/12/21 15:29:25 espie Exp $	*/
2 /*	$NetBSD: cond.c,v 1.7 1996/11/06 17:59:02 christos Exp $	*/
3 
4 /*
5  * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
6  * Copyright (c) 1988, 1989 by Adam de Boor
7  * Copyright (c) 1989 by Berkeley Softworks
8  * All rights reserved.
9  *
10  * This code is derived from software contributed to Berkeley by
11  * Adam de Boor.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  * 3. Neither the name of the University nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  */
37 
38 #include <ctype.h>
39 #include <stddef.h>
40 #include <stdint.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <ohash.h>
45 #include "config.h"
46 #include "defines.h"
47 #include "dir.h"
48 #include "buf.h"
49 #include "cond.h"
50 #include "cond_int.h"
51 #include "condhashconsts.h"
52 #include "error.h"
53 #include "var.h"
54 #include "varname.h"
55 #include "targ.h"
56 #include "lowparse.h"
57 #include "str.h"
58 #include "main.h"
59 #include "gnode.h"
60 #include "lst.h"
61 
62 
63 /* The parsing of conditional expressions is based on this grammar:
64  *	E -> F || E
65  *	E -> F
66  *	F -> T && F
67  *	F -> T
68  *	T -> defined(variable)
69  *	T -> make(target)
70  *	T -> exists(file)
71  *	T -> empty(varspec)
72  *	T -> target(name)
73  *	T -> commands(name)
74  *	T -> symbol
75  *	T -> $(varspec) op value
76  *	T -> $(varspec) == "string"
77  *	T -> $(varspec) != "string"
78  *	T -> "string" == "string"
79  *	T -> "string" != "string"
80  *	T -> number op number
81  *	T -> ( E )
82  *	T -> ! T
83  *	op -> == | != | > | < | >= | <=
84  *
85  * 'symbol' is some other symbol to which the default function (condDefProc)
86  * is applied.
87  *
88  * Tokens are scanned from the 'condExpr' string. The scanner (CondToken)
89  * will return And for '&' and '&&', Or for '|' and '||', Not for '!',
90  * LParen for '(', RParen for ')' and will evaluate the other terminal
91  * symbols, using either the default function or the function given in the
92  * terminal, and return the result as either true or False.
93  *
94  * All Non-Terminal functions (CondE, CondF and CondT) return Err on error.  */
95 typedef enum {
96 	False = 0, True = 1, And, Or, Not, LParen, RParen, EndOfFile, None, Err
97 } Token;
98 
99 /*-
100  * Structures to handle elegantly the different forms of #if's. The
101  * last two fields are stored in condInvert and condDefProc, respectively.
102  */
103 static bool CondGetArg(const char **, struct Name *,
104     const char *, bool);
105 static bool CondDoDefined(struct Name *);
106 static bool CondDoMake(struct Name *);
107 static bool CondDoExists(struct Name *);
108 static bool CondDoTarget(struct Name *);
109 static bool CondDoTargetWithCommands(struct Name *);
110 static bool CondCvtArg(const char *, double *);
111 static Token CondToken(bool);
112 static Token CondT(bool);
113 static Token CondF(bool);
114 static Token CondE(bool);
115 static Token CondHandleVarSpec(bool);
116 static Token CondHandleDefault(bool);
117 static Token CondHandleComparison(char *, bool, bool);
118 static Token CondHandleString(bool);
119 static Token CondHandleNumber(bool);
120 static const char *find_cond(const char *);
121 
122 
123 struct If {
124 	bool isElse;			/* true for else forms */
125 	bool doNot;			/* true for embedded negation */
126 	bool (*defProc)(struct Name *); /* function to apply */
127 };
128 
129 static struct If ifs[] = {
130 	{ false,false,	CondDoDefined },	/* if, ifdef */
131 	{ false,true,	CondDoDefined },	/* ifndef */
132 	{ false,false,	CondDoMake },		/* ifmake */
133 	{ false,true,	CondDoMake },		/* ifnmake */
134 	{ true,	false,	CondDoDefined },	/* elif, elifdef */
135 	{ true,	true,	CondDoDefined },	/* elifndef */
136 	{ true,	false,	CondDoMake },		/* elifmake */
137 	{ true,	true,	CondDoMake },		/* elifnmake */
138 	{ true,	false,	NULL }
139 };
140 
141 #define COND_IF_INDEX		0
142 #define COND_IFDEF_INDEX	0
143 #define COND_IFNDEF_INDEX	1
144 #define COND_IFMAKE_INDEX	2
145 #define COND_IFNMAKE_INDEX	3
146 #define COND_ELIF_INDEX		4
147 #define COND_ELIFDEF_INDEX	4
148 #define COND_ELIFNDEF_INDEX	5
149 #define COND_ELIFMAKE_INDEX	6
150 #define COND_ELIFNMAKE_INDEX	7
151 #define COND_ELSE_INDEX		8
152 
153 static bool condInvert;		/* Invert the default function */
154 static bool (*condDefProc)(struct Name *);
155 				/* Default function to apply */
156 static const char *condExpr;	/* The expression to parse */
157 static Token condPushBack=None;	/* Single push-back token used in parsing */
158 
159 #define MAXIF 30		/* greatest depth of #if'ing */
160 
161 static struct {
162 	bool 	value;
163 	Location origin;
164 } condStack[MAXIF];		/* Stack of conditionals */
165 
166 static int condTop = MAXIF;	/* Top-most conditional */
167 static int skipIfLevel=0;	/* Depth of skipped conditionals */
168 static bool skipLine = false;	/* Whether the parse module is skipping lines */
169 
170 static const char *
171 find_cond(const char *p)
172 {
173 	for (;;p++) {
174 		/* XXX: when *p == '\0', strchr() returns !NULL */
175 		if (strchr(" \t)&|$", *p) != NULL)
176 			return p;
177 	}
178 }
179 
180 
181 /*-
182  *-----------------------------------------------------------------------
183  * CondGetArg --
184  *	Find the argument of a built-in function.
185  *
186  * Results:
187  *	true if evaluation went okay
188  *
189  * Side Effects:
190  *	The line pointer is set to point to the closing parenthesis of the
191  *	function call. The argument is filled.
192  *-----------------------------------------------------------------------
193  */
194 static bool
195 CondGetArg(const char **linePtr, struct Name *arg, const char *func,
196     bool parens) /* true if arg should be bounded by parens */
197 {
198 	const char *cp;
199 
200 	cp = *linePtr;
201 	/* Set things up to return faster in case of problem */
202 	arg->s = cp;
203 	arg->e = cp;
204 	arg->tofree = false;
205 
206 	/* make and defined are not really keywords, so if CondGetArg doesn't
207 	 * work...
208 	 */
209 	if (parens) {
210 		while (ISSPACE(*cp))
211 			cp++;
212 		if (*cp == '(')
213 			cp++;
214 		else
215 			return false;
216 	}
217 
218 	if (*cp == '\0')
219 		return false;
220 
221 	while (ISSPACE(*cp))
222 		cp++;
223 
224 	cp = VarName_Get(cp, arg, NULL, true, find_cond);
225 
226 	while (ISSPACE(*cp))
227 		cp++;
228 	if (parens) {
229 		if (*cp == ')')
230 			cp++;
231 		else {
232 			Parse_Error(PARSE_WARNING,
233 			    "Missing closing parenthesis for %s()", func);
234 			return false;
235 	    	}
236 	}
237 
238 	*linePtr = cp;
239 	return true;
240 }
241 
242 /*-
243  *-----------------------------------------------------------------------
244  * CondDoDefined --
245  *	Handle the 'defined' function for conditionals.
246  *
247  * Results:
248  *	true if the given variable is defined.
249  *-----------------------------------------------------------------------
250  */
251 static bool
252 CondDoDefined(struct Name *arg)
253 {
254 	return Var_Definedi(arg->s, arg->e);
255 }
256 
257 /*-
258  *-----------------------------------------------------------------------
259  * CondDoMake --
260  *	Handle the 'make' function for conditionals.
261  *
262  * Results:
263  *	true if the given target is currently being built,
264  *	either explicitly on the command line, or implicitly as the
265  *	default target.
266  *-----------------------------------------------------------------------
267  */
268 static bool
269 CondDoMake(struct Name *arg)
270 {
271 	LstNode ln;
272 
273 	for (ln = Lst_First(create); ln != NULL; ln = Lst_Adv(ln)) {
274 		char *s = Lst_Datum(ln);
275 		if (Str_Matchi(s, strchr(s, '\0'), arg->s, arg->e))
276 			return true;
277 	}
278 
279 	return false;
280 }
281 
282 /*-
283  *-----------------------------------------------------------------------
284  * CondDoExists --
285  *	See if the given file exists.
286  *
287  * Results:
288  *	true if the file exists and false if it does not.
289  *-----------------------------------------------------------------------
290  */
291 static bool
292 CondDoExists(struct Name *arg)
293 {
294 	bool result;
295 	char *path;
296 
297 	if (arg->s == arg->e)
298 		Parse_Error(PARSE_FATAL, "Empty file name in .if exists()");
299 
300 	path = Dir_FindFilei(arg->s, arg->e, defaultPath);
301 	if (path != NULL) {
302 		result = true;
303 		free(path);
304 	} else {
305 		result = false;
306 	}
307 	return result;
308 }
309 
310 /*-
311  *-----------------------------------------------------------------------
312  * CondDoTarget --
313  *	See if the given node exists and is an actual target.
314  *
315  * Results:
316  *	true if the node exists as a target and false if it does not.
317  *-----------------------------------------------------------------------
318  */
319 static bool
320 CondDoTarget(struct Name *arg)
321 {
322 	GNode *gn;
323 
324 	gn = Targ_FindNodei(arg->s, arg->e, TARG_NOCREATE);
325 	if (gn != NULL && !OP_NOP(gn->type))
326 		return true;
327 	else
328 		return false;
329 }
330 
331 /*-
332  *-----------------------------------------------------------------------
333  * CondDoTargetWithCommands --
334  *	See if the given node exists and has commands.
335  *
336  * Results:
337  *	true if the node is complete and false if it does not.
338  *-----------------------------------------------------------------------
339  */
340 static bool
341 CondDoTargetWithCommands(struct Name *arg)
342 {
343 	GNode *gn;
344 
345 	gn = Targ_FindNodei(arg->s, arg->e, TARG_NOCREATE);
346 	if (gn != NULL && !OP_NOP(gn->type) && (gn->type & OP_HAS_COMMANDS))
347 		return true;
348 	else
349 		return false;
350 }
351 
352 
353 /*-
354  *-----------------------------------------------------------------------
355  * CondCvtArg --
356  *	Convert the given number into a double. If the number begins
357  *	with 0x, it is interpreted as a hexadecimal integer
358  *	and converted to a double from there. All other strings just have
359  *	strtod called on them.
360  *
361  * Results:
362  *	Sets 'value' to double value of string.
363  *	Returns true if the string was a valid number, false o.w.
364  *
365  * Side Effects:
366  *	Can change 'value' even if string is not a valid number.
367  *-----------------------------------------------------------------------
368  */
369 static bool
370 CondCvtArg(const char *str, double *value)
371 {
372 	if (*str == '0' && str[1] == 'x') {
373 		long i;
374 
375 		for (str += 2, i = 0; *str; str++) {
376 			int x;
377 			if (ISDIGIT(*str))
378 				x  = *str - '0';
379 			else if (ISXDIGIT(*str))
380 				x = 10 + *str - (ISUPPER(*str) ? 'A' : 'a');
381 			else
382 				return false;
383 			i = (i << 4) + x;
384 		}
385 		*value = (double) i;
386 		return true;
387 	}
388 	else {
389 		char *eptr;
390 		*value = strtod(str, &eptr);
391 		return *eptr == '\0';
392 	}
393 }
394 
395 
396 static Token
397 CondHandleNumber(bool doEval)
398 {
399 	const char *end;
400 	char *lhs;
401 
402 	end = condExpr;
403 	while (*end != '\0' && !ISSPACE(*end) && strchr("!=><", *end) == NULL)
404 		end++;
405 	lhs = Str_dupi(condExpr, end);
406 	condExpr = end;
407 	return CondHandleComparison(lhs, true, doEval);
408 }
409 
410 static Token
411 CondHandleVarSpec(bool doEval)
412 {
413 	char *lhs;
414 	size_t varSpecLen;
415 	bool doFree;
416 
417 	/* Parse the variable spec and skip over it, saving its
418 	 * value in lhs.  */
419 	lhs = Var_Parse(condExpr, NULL, doEval,&varSpecLen,&doFree);
420 	if (lhs == var_Error)
421 		/* Even if !doEval, we still report syntax errors, which
422 		 * is what getting var_Error back with !doEval means.  */
423 		return Err;
424 	condExpr += varSpecLen;
425 
426 	if (*condExpr && !ISSPACE(*condExpr) &&
427 		strchr("!=><", *condExpr) == NULL) {
428 		BUFFER buf;
429 
430 		Buf_Init(&buf, 0);
431 
432 		Buf_AddString(&buf, lhs);
433 
434 		if (doFree)
435 			free(lhs);
436 
437 		for (;*condExpr && !ISSPACE(*condExpr); condExpr++)
438 			Buf_AddChar(&buf, *condExpr);
439 
440 		lhs = Var_Subst(Buf_Retrieve(&buf), NULL, doEval);
441 		Buf_Destroy(&buf);
442 		doFree = true;
443 	}
444 
445 	return CondHandleComparison(lhs, doFree, doEval);
446 }
447 
448 static Token
449 CondHandleString(bool doEval)
450 {
451 	char *lhs;
452 	const char *begin;
453 	BUFFER buf;
454 
455 	/* find the extent of the string */
456 	begin = ++condExpr;
457 	while (*condExpr && *condExpr != '"') {
458 		condExpr++;
459 	}
460 
461 	Buf_Init(&buf, 0);
462 	Buf_Addi(&buf, begin, condExpr);
463 	if (*condExpr == '"')
464 		condExpr++;
465 	lhs = Var_Subst(Buf_Retrieve(&buf), NULL, doEval);
466 	Buf_Destroy(&buf);
467 	return CondHandleComparison(lhs, true, doEval);
468 }
469 
470 static Token
471 CondHandleComparison(char *lhs, bool doFree, bool doEval)
472 {
473 	Token t;
474 	const char *rhs;
475 	const char *op;
476 
477 	t = Err;
478 	/* Skip whitespace to get to the operator.	*/
479 	while (ISSPACE(*condExpr))
480 		condExpr++;
481 
482 	/* Make sure the operator is a valid one. If it isn't a
483 	 * known relational operator, pretend we got a
484 	 * != 0 comparison.  */
485 	op = condExpr;
486 	switch (*condExpr) {
487 	case '!':
488 	case '=':
489 	case '<':
490 	case '>':
491 		if (condExpr[1] == '=')
492 			condExpr += 2;
493 		else
494 			condExpr += 1;
495 		break;
496 	default:
497 		op = "!=";
498 		rhs = "0";
499 
500 		goto do_compare;
501 	}
502 	while (ISSPACE(*condExpr))
503 		condExpr++;
504 	if (*condExpr == '\0') {
505 		Parse_Error(PARSE_WARNING,
506 		    "Missing right-hand-side of operator");
507 		goto error;
508 	}
509 	rhs = condExpr;
510 do_compare:
511 	if (*rhs == '"') {
512 		/* Doing a string comparison. Only allow == and != for
513 		 * operators.  */
514 		char *string;
515 		const char *cp;
516 		int qt;
517 		BUFFER buf;
518 
519 do_string_compare:
520 		if ((*op != '!' && *op != '=') || op[1] != '=') {
521 			Parse_Error(PARSE_WARNING,
522 			    "String comparison operator should be either == or !=");
523 			goto error;
524 		}
525 
526 		Buf_Init(&buf, 0);
527 		qt = *rhs == '"' ? 1 : 0;
528 
529 		for (cp = &rhs[qt]; ((qt && *cp != '"') ||
530 		    (!qt && strchr(" \t)", *cp) == NULL)) && *cp != '\0';) {
531 			if (*cp == '$') {
532 				size_t len;
533 
534 				if (Var_ParseBuffer(&buf, cp, NULL, doEval,
535 				    &len)) {
536 					cp += len;
537 					continue;
538 				}
539 			} else if (*cp == '\\' && cp[1] != '\0')
540 				/* Backslash escapes things -- skip over next
541 				 * character, if it exists.  */
542 				cp++;
543 			Buf_AddChar(&buf, *cp++);
544 		}
545 
546 		string = Buf_Retrieve(&buf);
547 
548 		if (DEBUG(COND))
549 			printf("lhs = \"%s\", rhs = \"%s\", op = %.2s\n",
550 			    lhs, string, op);
551 		/* Null-terminate rhs and perform the comparison.
552 		 * t is set to the result.  */
553 		if (*op == '=')
554 			t = strcmp(lhs, string) ? False : True;
555 		else
556 			t = strcmp(lhs, string) ? True : False;
557 		free(string);
558 		if (rhs == condExpr) {
559 			if (!qt && *cp == ')')
560 				condExpr = cp;
561 			else if (*cp == '\0')
562 				condExpr = cp;
563 			else
564 				condExpr = cp + 1;
565 		}
566 	} else {
567 		/* rhs is either a float or an integer. Convert both the
568 		 * lhs and the rhs to a double and compare the two.  */
569 		double left, right;
570 		char *string;
571 
572 		if (!CondCvtArg(lhs, &left))
573 			goto do_string_compare;
574 		if (*rhs == '$') {
575 			size_t len;
576 			bool freeIt;
577 
578 			string = Var_Parse(rhs, NULL, doEval,&len,&freeIt);
579 			if (string == var_Error)
580 				right = 0.0;
581 			else {
582 				if (!CondCvtArg(string, &right)) {
583 					if (freeIt)
584 						free(string);
585 					goto do_string_compare;
586 				}
587 				if (freeIt)
588 					free(string);
589 				if (rhs == condExpr)
590 					condExpr += len;
591 			}
592 		} else {
593 			if (!CondCvtArg(rhs, &right))
594 				goto do_string_compare;
595 			if (rhs == condExpr) {
596 				/* Skip over the right-hand side.  */
597 				while (!ISSPACE(*condExpr) && *condExpr != '\0')
598 					condExpr++;
599 			}
600 		}
601 
602 		if (DEBUG(COND))
603 			printf("left = %f, right = %f, op = %.2s\n", left,
604 			    right, op);
605 		switch (op[0]) {
606 		case '!':
607 			if (op[1] != '=') {
608 				Parse_Error(PARSE_WARNING, "Unknown operator");
609 				goto error;
610 			}
611 			t = left != right ? True : False;
612 			break;
613 		case '=':
614 			if (op[1] != '=') {
615 				Parse_Error(PARSE_WARNING, "Unknown operator");
616 				goto error;
617 			}
618 			t = left == right ? True : False;
619 			break;
620 		case '<':
621 			if (op[1] == '=')
622 				t = left <= right ? True : False;
623 			else
624 				t = left < right ? True : False;
625 			break;
626 		case '>':
627 			if (op[1] == '=')
628 				t = left >= right ? True : False;
629 			else
630 				t = left > right ? True : False;
631 			break;
632 		}
633 	}
634 error:
635 	if (doFree)
636 		free(lhs);
637 	return t;
638 }
639 
640 #define S(s)	s, sizeof(s)-1
641 static struct operator {
642 	const char *s;
643 	size_t len;
644 	bool (*proc)(struct Name *);
645 } ops[] = {
646 	{S("defined"), CondDoDefined},
647 	{S("make"), CondDoMake},
648 	{S("exists"), CondDoExists},
649 	{S("target"), CondDoTarget},
650 	{S("commands"), CondDoTargetWithCommands},
651 	{NULL, 0, NULL}
652 };
653 
654 static Token
655 CondHandleDefault(bool doEval)
656 {
657 	bool t;
658 	bool (*evalProc)(struct Name *);
659 	bool invert = false;
660 	struct Name arg;
661 	size_t arglen;
662 
663 	evalProc = NULL;
664 	if (strncmp(condExpr, "empty", 5) == 0) {
665 		/* Use Var_Parse to parse the spec in parens and return
666 		 * True if the resulting string is empty.  */
667 		size_t length;
668 		bool doFree;
669 		char *val;
670 
671 		condExpr += 5;
672 
673 		for (arglen = 0; condExpr[arglen] != '(' &&
674 		    condExpr[arglen] != '\0';)
675 			arglen++;
676 
677 		if (condExpr[arglen] != '\0') {
678 			val = Var_Parse(&condExpr[arglen - 1], NULL,
679 			    doEval, &length, &doFree);
680 			if (val == var_Error)
681 				t = Err;
682 			else {
683 				/* A variable is empty when it just contains
684 				 * spaces... 4/15/92, christos */
685 				char *p;
686 				for (p = val; ISSPACE(*p); p++)
687 					continue;
688 				t = *p == '\0' ? True : False;
689 			}
690 			if (doFree)
691 				free(val);
692 			/* Advance condExpr to beyond the closing ). Note that
693 			 * we subtract one from arglen + length b/c length
694 			 * is calculated from condExpr[arglen - 1].  */
695 			condExpr += arglen + length - 1;
696 			return t;
697 		} else
698 			condExpr -= 5;
699 	} else {
700 		struct operator *op;
701 
702 		for (op = ops; op != NULL; op++)
703 			if (strncmp(condExpr, op->s, op->len) == 0) {
704 				condExpr += op->len;
705 				if (CondGetArg(&condExpr, &arg, op->s, true))
706 					evalProc = op->proc;
707 				else
708 					condExpr -= op->len;
709 				break;
710 			}
711 	}
712 	if (evalProc == NULL) {
713 		/* The symbol is itself the argument to the default
714 		 * function. We advance condExpr to the end of the symbol
715 		 * by hand (the next whitespace, closing paren or
716 		 * binary operator) and set to invert the evaluation
717 		 * function if condInvert is true.  */
718 		invert = condInvert;
719 		evalProc = condDefProc;
720 		/* XXX should we ignore problems now ? */
721 		CondGetArg(&condExpr, &arg, "", false);
722 	}
723 
724 	/* Evaluate the argument using the set function. If invert
725 	 * is true, we invert the sense of the function.  */
726 	t = (!doEval || (*evalProc)(&arg) ?
727 	     (invert ? False : True) :
728 	     (invert ? True : False));
729 	VarName_Free(&arg);
730 	return t;
731 }
732 
733 /*-
734  *-----------------------------------------------------------------------
735  * CondToken --
736  *	Return the next token from the input.
737  *
738  * Results:
739  *	A Token for the next lexical token in the stream.
740  *
741  * Side Effects:
742  *	condPushback will be set back to None if it is used.
743  *-----------------------------------------------------------------------
744  */
745 static Token
746 CondToken(bool doEval)
747 {
748 
749 	if (condPushBack != None) {
750 		Token t;
751 
752 		t = condPushBack;
753 		condPushBack = None;
754 		return t;
755 	}
756 
757 	while (ISSPACE(*condExpr))
758 		condExpr++;
759 	switch (*condExpr) {
760 	case '(':
761 		condExpr++;
762 		return LParen;
763 	case ')':
764 		condExpr++;
765 		return RParen;
766 	case '|':
767 		if (condExpr[1] == '|')
768 			condExpr++;
769 		condExpr++;
770 		return Or;
771 	case '&':
772 		if (condExpr[1] == '&')
773 			condExpr++;
774 		condExpr++;
775 		return And;
776 	case '!':
777 		condExpr++;
778 		return Not;
779 	case '\n':
780 	case '\0':
781 		return EndOfFile;
782 	case '"':
783 		return CondHandleString(doEval);
784 	case '$':
785 		return CondHandleVarSpec(doEval);
786 	case '0': case '1': case '2': case '3': case '4':
787 	case '5': case '6': case '7': case '8': case '9':
788 		return CondHandleNumber(doEval);
789 	default:
790 		return CondHandleDefault(doEval);
791 	}
792 }
793 
794 /*-
795  *-----------------------------------------------------------------------
796  * CondT --
797  *	Parse a single term in the expression. This consists of a terminal
798  *	symbol or Not and a terminal symbol (not including the binary
799  *	operators):
800  *	    T -> defined(variable) | make(target) | exists(file) | symbol
801  *	    T -> ! T | ( E )
802  *
803  * Results:
804  *	True, False or Err.
805  *
806  * Side Effects:
807  *	Tokens are consumed.
808  *-----------------------------------------------------------------------
809  */
810 static Token
811 CondT(bool doEval)
812 {
813 	Token t;
814 
815 	t = CondToken(doEval);
816 
817 	if (t == EndOfFile)
818 		/* If we reached the end of the expression, the expression
819 		 * is malformed...  */
820 		t = Err;
821 	else if (t == LParen) {
822 		/* T -> ( E ).	*/
823 		t = CondE(doEval);
824 		if (t != Err)
825 			if (CondToken(doEval) != RParen)
826 				t = Err;
827 	} else if (t == Not) {
828 		t = CondT(doEval);
829 		if (t == True)
830 			t = False;
831 		else if (t == False)
832 			t = True;
833 	}
834 	return t;
835 }
836 
837 /*-
838  *-----------------------------------------------------------------------
839  * CondF --
840  *	Parse a conjunctive factor (nice name, wot?)
841  *	    F -> T && F | T
842  *
843  * Results:
844  *	True, False or Err
845  *
846  * Side Effects:
847  *	Tokens are consumed.
848  *-----------------------------------------------------------------------
849  */
850 static Token
851 CondF(bool doEval)
852 {
853 	Token l, o;
854 
855 	l = CondT(doEval);
856 	if (l != Err) {
857 		o = CondToken(doEval);
858 
859 		if (o == And) {
860 		    /* F -> T && F
861 		     *
862 		     * If T is False, the whole thing will be False, but we
863 		     * have to parse the r.h.s. anyway (to throw it away).  If
864 		     * T is True, the result is the r.h.s., be it an Err or no.
865 		     * */
866 		    if (l == True)
867 			    l = CondF(doEval);
868 		    else
869 			    (void)CondF(false);
870 		} else
871 			/* F -> T.	*/
872 			condPushBack = o;
873 	}
874 	return l;
875 }
876 
877 /*-
878  *-----------------------------------------------------------------------
879  * CondE --
880  *	Main expression production.
881  *	    E -> F || E | F
882  *
883  * Results:
884  *	True, False or Err.
885  *
886  * Side Effects:
887  *	Tokens are, of course, consumed.
888  *-----------------------------------------------------------------------
889  */
890 static Token
891 CondE(bool doEval)
892 {
893 	Token l, o;
894 
895 	l = CondF(doEval);
896 	if (l != Err) {
897 		o = CondToken(doEval);
898 
899 		if (o == Or) {
900 			/* E -> F || E
901 			 *
902 			 * A similar thing occurs for ||, except that here we
903 			 * make sure the l.h.s. is False before we bother to
904 			 * evaluate the r.h.s.  Once again, if l is False, the
905 			 * result is the r.h.s. and once again if l is True, we
906 			 * parse the r.h.s. to throw it away.  */
907 			if (l == False)
908 				l = CondE(doEval);
909 			else
910 				(void)CondE(false);
911 		} else
912 			/* E -> F.	*/
913 			condPushBack = o;
914 	}
915 	return l;
916 }
917 
918 /* Evaluate conditional in line.
919  * returns COND_SKIP, COND_PARSE, COND_INVALID, COND_ISFOR, COND_ISINCLUDE,
920  * COND_ISUNDEF.
921  * A conditional line looks like this:
922  *	<cond-type> <expr>
923  *	where <cond-type> is any of if, ifmake, ifnmake, ifdef,
924  *	ifndef, elif, elifmake, elifnmake, elifdef, elifndef
925  *	and <expr> consists of &&, ||, !, make(target), defined(variable)
926  *	and parenthetical groupings thereof.
927  */
928 int
929 Cond_Eval(const char *line)
930 {
931 	/* find end of keyword */
932 	const char *end;
933 	uint32_t k;
934 	size_t len;
935 	struct If *ifp;
936 	bool value = false;
937 	int level;	/* Level at which to report errors. */
938 
939 	level = PARSE_FATAL;
940 
941 	for (end = line; ISLOWER(*end); end++)
942 		;
943 	/* quick path: recognize special targets early on */
944 	if (*end == '.' || *end == ':')
945 		return COND_INVALID;
946 	len = end - line;
947 	k = ohash_interval(line, &end);
948 	switch(k % MAGICSLOTS2) {
949 	case K_COND_IF % MAGICSLOTS2:
950 		if (k == K_COND_IF && len == strlen(COND_IF) &&
951 		    strncmp(line, COND_IF, len) == 0) {
952 			ifp = ifs + COND_IF_INDEX;
953 		} else
954 			return COND_INVALID;
955 		break;
956 	case K_COND_IFDEF % MAGICSLOTS2:
957 		if (k == K_COND_IFDEF && len == strlen(COND_IFDEF) &&
958 		    strncmp(line, COND_IFDEF, len) == 0) {
959 			ifp = ifs + COND_IFDEF_INDEX;
960 		} else
961 			return COND_INVALID;
962 		break;
963 	case K_COND_IFNDEF % MAGICSLOTS2:
964 		if (k == K_COND_IFNDEF && len == strlen(COND_IFNDEF) &&
965 		    strncmp(line, COND_IFNDEF, len) == 0) {
966 			ifp = ifs + COND_IFNDEF_INDEX;
967 		} else
968 			return COND_INVALID;
969 		break;
970 	case K_COND_IFMAKE % MAGICSLOTS2:
971 		if (k == K_COND_IFMAKE && len == strlen(COND_IFMAKE) &&
972 		    strncmp(line, COND_IFMAKE, len) == 0) {
973 			ifp = ifs + COND_IFMAKE_INDEX;
974 		} else
975 			return COND_INVALID;
976 		break;
977 	case K_COND_IFNMAKE % MAGICSLOTS2:
978 		if (k == K_COND_IFNMAKE && len == strlen(COND_IFNMAKE) &&
979 		    strncmp(line, COND_IFNMAKE, len) == 0) {
980 			ifp = ifs + COND_IFNMAKE_INDEX;
981 		} else
982 			return COND_INVALID;
983 		break;
984 	case K_COND_ELIF % MAGICSLOTS2:
985 		if (k == K_COND_ELIF && len == strlen(COND_ELIF) &&
986 		    strncmp(line, COND_ELIF, len) == 0) {
987 			ifp = ifs + COND_ELIF_INDEX;
988 		} else
989 			return COND_INVALID;
990 		break;
991 	case K_COND_ELIFDEF % MAGICSLOTS2:
992 		if (k == K_COND_ELIFDEF && len == strlen(COND_ELIFDEF) &&
993 		    strncmp(line, COND_ELIFDEF, len) == 0) {
994 			ifp = ifs + COND_ELIFDEF_INDEX;
995 		} else
996 			return COND_INVALID;
997 		break;
998 	case K_COND_ELIFNDEF % MAGICSLOTS2:
999 		if (k == K_COND_ELIFNDEF && len == strlen(COND_ELIFNDEF) &&
1000 		    strncmp(line, COND_ELIFNDEF, len) == 0) {
1001 			ifp = ifs + COND_ELIFNDEF_INDEX;
1002 		} else
1003 			return COND_INVALID;
1004 		break;
1005 	case K_COND_ELIFMAKE % MAGICSLOTS2:
1006 		if (k == K_COND_ELIFMAKE && len == strlen(COND_ELIFMAKE) &&
1007 		    strncmp(line, COND_ELIFMAKE, len) == 0) {
1008 			ifp = ifs + COND_ELIFMAKE_INDEX;
1009 		} else
1010 			return COND_INVALID;
1011 		break;
1012 	case K_COND_ELIFNMAKE % MAGICSLOTS2:
1013 		if (k == K_COND_ELIFNMAKE && len == strlen(COND_ELIFNMAKE) &&
1014 		    strncmp(line, COND_ELIFNMAKE, len) == 0) {
1015 			ifp = ifs + COND_ELIFNMAKE_INDEX;
1016 		} else
1017 			return COND_INVALID;
1018 		break;
1019 	case K_COND_ELSE % MAGICSLOTS2:
1020 		/* valid conditional whose value is the inverse
1021 		 * of the previous if we parsed.  */
1022 		if (k == K_COND_ELSE && len == strlen(COND_ELSE) &&
1023 		    strncmp(line, COND_ELSE, len) == 0) {
1024 			if (condTop == MAXIF) {
1025 				Parse_Error(level, "if-less else");
1026 				return COND_INVALID;
1027 			} else if (skipIfLevel == 0) {
1028 				value = !condStack[condTop].value;
1029 				ifp = ifs + COND_ELSE_INDEX;
1030 			} else
1031 				return COND_SKIP;
1032 		} else
1033 			return COND_INVALID;
1034 		break;
1035 	case K_COND_ENDIF % MAGICSLOTS2:
1036 		if (k == K_COND_ENDIF && len == strlen(COND_ENDIF) &&
1037 		    strncmp(line, COND_ENDIF, len) == 0) {
1038 			/* End of a conditional section. If skipIfLevel is
1039 			 * non-zero, that conditional was skipped, so lines
1040 			 * following it should also be skipped. Hence, we
1041 			 * return COND_SKIP. Otherwise, the conditional was
1042 			 * read so succeeding lines should be parsed (think
1043 			 * about it...) so we return COND_PARSE, unless this
1044 			 * endif isn't paired with a decent if.  */
1045 			if (skipIfLevel != 0) {
1046 				skipIfLevel--;
1047 				return COND_SKIP;
1048 			} else {
1049 				if (condTop == MAXIF) {
1050 					Parse_Error(level, "if-less endif");
1051 					return COND_INVALID;
1052 				} else {
1053 					skipLine = false;
1054 					condTop++;
1055 					return COND_PARSE;
1056 				}
1057 			}
1058 		} else
1059 			return COND_INVALID;
1060 		break;
1061 
1062 	/* Recognize other keywords there, to simplify parser's task */
1063 	case K_COND_FOR % MAGICSLOTS2:
1064 		if (k == K_COND_FOR && len == strlen(COND_FOR) &&
1065 		    strncmp(line, COND_FOR, len) == 0)
1066 			return COND_ISFOR;
1067 		else
1068 			return COND_INVALID;
1069 	case K_COND_UNDEF % MAGICSLOTS2:
1070 		if (k == K_COND_UNDEF && len == strlen(COND_UNDEF) &&
1071 		    strncmp(line, COND_UNDEF, len) == 0)
1072 			return COND_ISUNDEF;
1073 		else
1074 			return COND_INVALID;
1075 	case K_COND_POISON % MAGICSLOTS2:
1076 		if (k == K_COND_POISON && len == strlen(COND_POISON) &&
1077 		    strncmp(line, COND_POISON, len) == 0)
1078 			return COND_ISPOISON;
1079 		else
1080 			return COND_INVALID;
1081 	case K_COND_INCLUDE % MAGICSLOTS2:
1082 		if (k == K_COND_INCLUDE && len == strlen(COND_INCLUDE) &&
1083 		    strncmp(line, COND_INCLUDE, len) == 0)
1084 			return COND_ISINCLUDE;
1085 		else
1086 			return COND_INVALID;
1087 	default:
1088 		/* Not a valid conditional type. No error...  */
1089 		return COND_INVALID;
1090 	}
1091 
1092 	if (ifp->isElse) {
1093 		if (condTop == MAXIF) {
1094 			Parse_Error(level, "if-less elif");
1095 			return COND_INVALID;
1096 		} else if (skipIfLevel != 0 || condStack[condTop].value) {
1097 			/*
1098 			 * Skip if we're meant to or is an else-type
1099 			 * conditional and previous corresponding one was
1100 			 * evaluated to true.
1101 			 */
1102 			skipLine = true;
1103 			return COND_SKIP;
1104 		}
1105 	} else if (skipLine) {
1106 		/* Don't even try to evaluate a conditional that's not an else
1107 		 * if we're skipping things...  */
1108 		skipIfLevel++;
1109 		return COND_SKIP;
1110 	} else
1111 		condTop--;
1112 
1113 	if (condTop < 0) {
1114 		/* This is the one case where we can definitely proclaim a fatal
1115 		 * error. If we don't, we're hosed.  */
1116 		Parse_Error(PARSE_FATAL, "Too many nested if's. %d max.",
1117 		    MAXIF);
1118 		condTop = 0;
1119 		return COND_INVALID;
1120 	}
1121 
1122 	if (ifp->defProc) {
1123 		/* Initialize file-global variables for parsing.  */
1124 		condDefProc = ifp->defProc;
1125 		condInvert = ifp->doNot;
1126 
1127 		line += len;
1128 
1129 		while (*line == ' ' || *line == '\t')
1130 			line++;
1131 
1132 		condExpr = line;
1133 		condPushBack = None;
1134 
1135 		switch (CondE(true)) {
1136 		case True:
1137 			if (CondToken(true) == EndOfFile) {
1138 				value = true;
1139 				break;
1140 			}
1141 			goto err;
1142 			/* FALLTHROUGH */
1143 		case False:
1144 			if (CondToken(true) == EndOfFile) {
1145 				value = false;
1146 				break;
1147 			}
1148 			/* FALLTHROUGH */
1149 		case Err:
1150 err:
1151 			Parse_Error(level, "Malformed conditional (%s)", line);
1152 			return COND_INVALID;
1153 		default:
1154 			break;
1155 		}
1156 	}
1157 
1158 	condStack[condTop].value = value;
1159 	Parse_FillLocation(&condStack[condTop].origin);
1160 	skipLine = !value;
1161 	return value ? COND_PARSE : COND_SKIP;
1162 }
1163 
1164 void
1165 Cond_End(void)
1166 {
1167 	int i;
1168 
1169 	if (condTop != MAXIF) {
1170 		Parse_Error(PARSE_FATAL, "%s%d open conditional%s",
1171 		    condTop == 0 ? "at least ": "", MAXIF-condTop,
1172 		    MAXIF-condTop == 1 ? "" : "s");
1173 		for (i = MAXIF-1; i >= condTop; i--) {
1174 			fprintf(stderr, "\t(%s:%lu)\n",
1175 			    condStack[i].origin.fname,
1176 			    condStack[i].origin.lineno);
1177 		}
1178 	}
1179 	condTop = MAXIF;
1180 }
1181