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