xref: /openbsd/usr.bin/make/cond.c (revision a6445c1d)
1 /*	$OpenBSD: cond.c,v 1.50 2013/11/22 15:47:35 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 being made.
264  *-----------------------------------------------------------------------
265  */
266 static bool
267 CondDoMake(struct Name *arg)
268 {
269 	LstNode ln;
270 
271 	for (ln = Lst_First(create); ln != NULL; ln = Lst_Adv(ln)) {
272 		char *s = (char *)Lst_Datum(ln);
273 		if (Str_Matchi(s, strchr(s, '\0'), arg->s, arg->e))
274 			return true;
275 	}
276 
277 	return false;
278 }
279 
280 /*-
281  *-----------------------------------------------------------------------
282  * CondDoExists --
283  *	See if the given file exists.
284  *
285  * Results:
286  *	true if the file exists and false if it does not.
287  *-----------------------------------------------------------------------
288  */
289 static bool
290 CondDoExists(struct Name *arg)
291 {
292 	bool result;
293 	char *path;
294 
295 	path = Dir_FindFilei(arg->s, arg->e, defaultPath);
296 	if (path != NULL) {
297 		result = true;
298 		free(path);
299 	} else {
300 		result = false;
301 	}
302 	return result;
303 }
304 
305 /*-
306  *-----------------------------------------------------------------------
307  * CondDoTarget --
308  *	See if the given node exists and is an actual target.
309  *
310  * Results:
311  *	true if the node exists as a target and false if it does not.
312  *-----------------------------------------------------------------------
313  */
314 static bool
315 CondDoTarget(struct Name *arg)
316 {
317 	GNode *gn;
318 
319 	gn = Targ_FindNodei(arg->s, arg->e, TARG_NOCREATE);
320 	if (gn != NULL && !OP_NOP(gn->type))
321 		return true;
322 	else
323 		return false;
324 }
325 
326 /*-
327  *-----------------------------------------------------------------------
328  * CondDoTargetWithCommands --
329  *	See if the given node exists and has commands.
330  *
331  * Results:
332  *	true if the node is complete and false if it does not.
333  *-----------------------------------------------------------------------
334  */
335 static bool
336 CondDoTargetWithCommands(struct Name *arg)
337 {
338 	GNode *gn;
339 
340 	gn = Targ_FindNodei(arg->s, arg->e, TARG_NOCREATE);
341 	if (gn != NULL && !OP_NOP(gn->type) && (gn->type & OP_HAS_COMMANDS))
342 		return true;
343 	else
344 		return false;
345 }
346 
347 
348 /*-
349  *-----------------------------------------------------------------------
350  * CondCvtArg --
351  *	Convert the given number into a double. If the number begins
352  *	with 0x, it is interpreted as a hexadecimal integer
353  *	and converted to a double from there. All other strings just have
354  *	strtod called on them.
355  *
356  * Results:
357  *	Sets 'value' to double value of string.
358  *	Returns true if the string was a valid number, false o.w.
359  *
360  * Side Effects:
361  *	Can change 'value' even if string is not a valid number.
362  *-----------------------------------------------------------------------
363  */
364 static bool
365 CondCvtArg(const char *str, double *value)
366 {
367 	if (*str == '0' && str[1] == 'x') {
368 		long i;
369 
370 		for (str += 2, i = 0; *str; str++) {
371 			int x;
372 			if (ISDIGIT(*str))
373 				x  = *str - '0';
374 			else if (ISXDIGIT(*str))
375 				x = 10 + *str - (ISUPPER(*str) ? 'A' : 'a');
376 			else
377 				return false;
378 			i = (i << 4) + x;
379 		}
380 		*value = (double) i;
381 		return true;
382 	}
383 	else {
384 		char *eptr;
385 		*value = strtod(str, &eptr);
386 		return *eptr == '\0';
387 	}
388 }
389 
390 
391 static Token
392 CondHandleNumber(bool doEval)
393 {
394 	const char *end;
395 	char *lhs;
396 
397 	end = condExpr;
398 	while (!ISSPACE(*end) && strchr("!=><", *end) == NULL)
399 		end++;
400 	lhs = Str_dupi(condExpr, end);
401 	condExpr = end;
402 	return CondHandleComparison(lhs, true, doEval);
403 }
404 
405 static Token
406 CondHandleVarSpec(bool doEval)
407 {
408 	char *lhs;
409 	size_t varSpecLen;
410 	bool doFree;
411 
412 	/* Parse the variable spec and skip over it, saving its
413 	 * value in lhs.  */
414 	lhs = Var_Parse(condExpr, NULL, doEval,&varSpecLen,&doFree);
415 	if (lhs == var_Error)
416 		/* Even if !doEval, we still report syntax errors, which
417 		 * is what getting var_Error back with !doEval means.  */
418 		return Err;
419 	condExpr += varSpecLen;
420 
421 	if (!ISSPACE(*condExpr) &&
422 		strchr("!=><", *condExpr) == NULL) {
423 		BUFFER buf;
424 
425 		Buf_Init(&buf, 0);
426 
427 		Buf_AddString(&buf, lhs);
428 
429 		if (doFree)
430 			free(lhs);
431 
432 		for (;*condExpr && !ISSPACE(*condExpr); condExpr++)
433 			Buf_AddChar(&buf, *condExpr);
434 
435 		lhs = Var_Subst(Buf_Retrieve(&buf), NULL, doEval);
436 		Buf_Destroy(&buf);
437 		doFree = true;
438 	}
439 
440 	return CondHandleComparison(lhs, doFree, doEval);
441 }
442 
443 static Token
444 CondHandleString(bool doEval)
445 {
446 	char *lhs;
447 	const char *begin;
448 	BUFFER buf;
449 
450 	/* find the extent of the string */
451 	begin = ++condExpr;
452 	while (*condExpr && *condExpr != '"') {
453 		condExpr++;
454 	}
455 
456 	Buf_Init(&buf, 0);
457 	Buf_Addi(&buf, begin, condExpr);
458 	if (*condExpr == '"')
459 		condExpr++;
460 	lhs = Var_Subst(Buf_Retrieve(&buf), NULL, doEval);
461 	Buf_Destroy(&buf);
462 	return CondHandleComparison(lhs, true, doEval);
463 }
464 
465 static Token
466 CondHandleComparison(char *lhs, bool doFree, bool doEval)
467 {
468 	Token t;
469 	const char *rhs;
470 	const char *op;
471 
472 	t = Err;
473 	/* Skip whitespace to get to the operator.	*/
474 	while (ISSPACE(*condExpr))
475 		condExpr++;
476 
477 	/* Make sure the operator is a valid one. If it isn't a
478 	 * known relational operator, pretend we got a
479 	 * != 0 comparison.  */
480 	op = condExpr;
481 	switch (*condExpr) {
482 	case '!':
483 	case '=':
484 	case '<':
485 	case '>':
486 		if (condExpr[1] == '=')
487 			condExpr += 2;
488 		else
489 			condExpr += 1;
490 		break;
491 	default:
492 		op = "!=";
493 		rhs = "0";
494 
495 		goto do_compare;
496 	}
497 	while (ISSPACE(*condExpr))
498 		condExpr++;
499 	if (*condExpr == '\0') {
500 		Parse_Error(PARSE_WARNING,
501 		    "Missing right-hand-side of operator");
502 		goto error;
503 	}
504 	rhs = condExpr;
505 do_compare:
506 	if (*rhs == '"') {
507 		/* Doing a string comparison. Only allow == and != for
508 		 * operators.  */
509 		char *string;
510 		const char *cp;
511 		int qt;
512 		BUFFER buf;
513 
514 do_string_compare:
515 		if ((*op != '!' && *op != '=') || op[1] != '=') {
516 			Parse_Error(PARSE_WARNING,
517 			    "String comparison operator should be either == or !=");
518 			goto error;
519 		}
520 
521 		Buf_Init(&buf, 0);
522 		qt = *rhs == '"' ? 1 : 0;
523 
524 		for (cp = &rhs[qt]; ((qt && *cp != '"') ||
525 		    (!qt && strchr(" \t)", *cp) == NULL)) && *cp != '\0';) {
526 			if (*cp == '$') {
527 				size_t len;
528 
529 				if (Var_ParseBuffer(&buf, cp, NULL, doEval,
530 				    &len)) {
531 					cp += len;
532 					continue;
533 				}
534 			} else if (*cp == '\\' && cp[1] != '\0')
535 				/* Backslash escapes things -- skip over next
536 				 * character, if it exists.  */
537 				cp++;
538 			Buf_AddChar(&buf, *cp++);
539 		}
540 
541 		string = Buf_Retrieve(&buf);
542 
543 		if (DEBUG(COND))
544 			printf("lhs = \"%s\", rhs = \"%s\", op = %.2s\n",
545 			    lhs, string, op);
546 		/* Null-terminate rhs and perform the comparison.
547 		 * t is set to the result.  */
548 		if (*op == '=')
549 			t = strcmp(lhs, string) ? False : True;
550 		else
551 			t = strcmp(lhs, string) ? True : False;
552 		free(string);
553 		if (rhs == condExpr) {
554 			if (!qt && *cp == ')')
555 				condExpr = cp;
556 			else if (*cp == '\0')
557 				condExpr = cp;
558 			else
559 				condExpr = cp + 1;
560 		}
561 	} else {
562 		/* rhs is either a float or an integer. Convert both the
563 		 * lhs and the rhs to a double and compare the two.  */
564 		double left, right;
565 		char *string;
566 
567 		if (!CondCvtArg(lhs, &left))
568 			goto do_string_compare;
569 		if (*rhs == '$') {
570 			size_t len;
571 			bool freeIt;
572 
573 			string = Var_Parse(rhs, NULL, doEval,&len,&freeIt);
574 			if (string == var_Error)
575 				right = 0.0;
576 			else {
577 				if (!CondCvtArg(string, &right)) {
578 					if (freeIt)
579 						free(string);
580 					goto do_string_compare;
581 				}
582 				if (freeIt)
583 					free(string);
584 				if (rhs == condExpr)
585 					condExpr += len;
586 			}
587 		} else {
588 			if (!CondCvtArg(rhs, &right))
589 				goto do_string_compare;
590 			if (rhs == condExpr) {
591 				/* Skip over the right-hand side.  */
592 				while (!ISSPACE(*condExpr) && *condExpr != '\0')
593 					condExpr++;
594 			}
595 		}
596 
597 		if (DEBUG(COND))
598 			printf("left = %f, right = %f, op = %.2s\n", left,
599 			    right, op);
600 		switch (op[0]) {
601 		case '!':
602 			if (op[1] != '=') {
603 				Parse_Error(PARSE_WARNING, "Unknown operator");
604 				goto error;
605 			}
606 			t = left != right ? True : False;
607 			break;
608 		case '=':
609 			if (op[1] != '=') {
610 				Parse_Error(PARSE_WARNING, "Unknown operator");
611 				goto error;
612 			}
613 			t = left == right ? True : False;
614 			break;
615 		case '<':
616 			if (op[1] == '=')
617 				t = left <= right ? True : False;
618 			else
619 				t = left < right ? True : False;
620 			break;
621 		case '>':
622 			if (op[1] == '=')
623 				t = left >= right ? True : False;
624 			else
625 				t = left > right ? True : False;
626 			break;
627 		}
628 	}
629 error:
630 	if (doFree)
631 		free(lhs);
632 	return t;
633 }
634 
635 #define S(s)	s, sizeof(s)-1
636 static struct operator {
637 	const char *s;
638 	size_t len;
639 	bool (*proc)(struct Name *);
640 } ops[] = {
641 	{S("defined"), CondDoDefined},
642 	{S("make"), CondDoMake},
643 	{S("exists"), CondDoExists},
644 	{S("target"), CondDoTarget},
645 	{S("commands"), CondDoTargetWithCommands},
646 	{NULL, 0, NULL}
647 };
648 
649 static Token
650 CondHandleDefault(bool doEval)
651 {
652 	bool t;
653 	bool (*evalProc)(struct Name *);
654 	bool invert = false;
655 	struct Name arg;
656 	size_t arglen;
657 
658 	evalProc = NULL;
659 	if (strncmp(condExpr, "empty", 5) == 0) {
660 		/* Use Var_Parse to parse the spec in parens and return
661 		 * True if the resulting string is empty.  */
662 		size_t length;
663 		bool doFree;
664 		char *val;
665 
666 		condExpr += 5;
667 
668 		for (arglen = 0; condExpr[arglen] != '(' &&
669 		    condExpr[arglen] != '\0';)
670 			arglen++;
671 
672 		if (condExpr[arglen] != '\0') {
673 			val = Var_Parse(&condExpr[arglen - 1], NULL,
674 			    doEval, &length, &doFree);
675 			if (val == var_Error)
676 				t = Err;
677 			else {
678 				/* A variable is empty when it just contains
679 				 * spaces... 4/15/92, christos */
680 				char *p;
681 				for (p = val; ISSPACE(*p); p++)
682 					continue;
683 				t = *p == '\0' ? True : False;
684 			}
685 			if (doFree)
686 				free(val);
687 			/* Advance condExpr to beyond the closing ). Note that
688 			 * we subtract one from arglen + length b/c length
689 			 * is calculated from condExpr[arglen - 1].  */
690 			condExpr += arglen + length - 1;
691 			return t;
692 		} else
693 			condExpr -= 5;
694 	} else {
695 		struct operator *op;
696 
697 		for (op = ops; op != NULL; op++)
698 			if (strncmp(condExpr, op->s, op->len) == 0) {
699 				condExpr += op->len;
700 				if (CondGetArg(&condExpr, &arg, op->s, true))
701 					evalProc = op->proc;
702 				else
703 					condExpr -= op->len;
704 				break;
705 			}
706 	}
707 	if (evalProc == NULL) {
708 		/* The symbol is itself the argument to the default
709 		 * function. We advance condExpr to the end of the symbol
710 		 * by hand (the next whitespace, closing paren or
711 		 * binary operator) and set to invert the evaluation
712 		 * function if condInvert is true.  */
713 		invert = condInvert;
714 		evalProc = condDefProc;
715 		/* XXX should we ignore problems now ? */
716 		CondGetArg(&condExpr, &arg, "", false);
717 	}
718 
719 	/* Evaluate the argument using the set function. If invert
720 	 * is true, we invert the sense of the function.  */
721 	t = (!doEval || (*evalProc)(&arg) ?
722 	     (invert ? False : True) :
723 	     (invert ? True : False));
724 	VarName_Free(&arg);
725 	return t;
726 }
727 
728 /*-
729  *-----------------------------------------------------------------------
730  * CondToken --
731  *	Return the next token from the input.
732  *
733  * Results:
734  *	A Token for the next lexical token in the stream.
735  *
736  * Side Effects:
737  *	condPushback will be set back to None if it is used.
738  *-----------------------------------------------------------------------
739  */
740 static Token
741 CondToken(bool doEval)
742 {
743 
744 	if (condPushBack != None) {
745 		Token t;
746 
747 		t = condPushBack;
748 		condPushBack = None;
749 		return t;
750 	}
751 
752 	while (ISSPACE(*condExpr))
753 		condExpr++;
754 	switch (*condExpr) {
755 	case '(':
756 		condExpr++;
757 		return LParen;
758 	case ')':
759 		condExpr++;
760 		return RParen;
761 	case '|':
762 		if (condExpr[1] == '|')
763 			condExpr++;
764 		condExpr++;
765 		return Or;
766 	case '&':
767 		if (condExpr[1] == '&')
768 			condExpr++;
769 		condExpr++;
770 		return And;
771 	case '!':
772 		condExpr++;
773 		return Not;
774 	case '\n':
775 	case '\0':
776 		return EndOfFile;
777 	case '"':
778 		return CondHandleString(doEval);
779 	case '$':
780 		return CondHandleVarSpec(doEval);
781 	case '0': case '1': case '2': case '3': case '4':
782 	case '5': case '6': case '7': case '8': case '9':
783 		return CondHandleNumber(doEval);
784 	default:
785 		return CondHandleDefault(doEval);
786 	}
787 }
788 
789 /*-
790  *-----------------------------------------------------------------------
791  * CondT --
792  *	Parse a single term in the expression. This consists of a terminal
793  *	symbol or Not and a terminal symbol (not including the binary
794  *	operators):
795  *	    T -> defined(variable) | make(target) | exists(file) | symbol
796  *	    T -> ! T | ( E )
797  *
798  * Results:
799  *	True, False or Err.
800  *
801  * Side Effects:
802  *	Tokens are consumed.
803  *-----------------------------------------------------------------------
804  */
805 static Token
806 CondT(bool doEval)
807 {
808 	Token t;
809 
810 	t = CondToken(doEval);
811 
812 	if (t == EndOfFile)
813 		/* If we reached the end of the expression, the expression
814 		 * is malformed...  */
815 		t = Err;
816 	else if (t == LParen) {
817 		/* T -> ( E ).	*/
818 		t = CondE(doEval);
819 		if (t != Err)
820 			if (CondToken(doEval) != RParen)
821 				t = Err;
822 	} else if (t == Not) {
823 		t = CondT(doEval);
824 		if (t == True)
825 			t = False;
826 		else if (t == False)
827 			t = True;
828 	}
829 	return t;
830 }
831 
832 /*-
833  *-----------------------------------------------------------------------
834  * CondF --
835  *	Parse a conjunctive factor (nice name, wot?)
836  *	    F -> T && F | T
837  *
838  * Results:
839  *	True, False or Err
840  *
841  * Side Effects:
842  *	Tokens are consumed.
843  *-----------------------------------------------------------------------
844  */
845 static Token
846 CondF(bool doEval)
847 {
848 	Token l, o;
849 
850 	l = CondT(doEval);
851 	if (l != Err) {
852 		o = CondToken(doEval);
853 
854 		if (o == And) {
855 		    /* F -> T && F
856 		     *
857 		     * If T is False, the whole thing will be False, but we
858 		     * have to parse the r.h.s. anyway (to throw it away).  If
859 		     * T is True, the result is the r.h.s., be it an Err or no.
860 		     * */
861 		    if (l == True)
862 			    l = CondF(doEval);
863 		    else
864 			    (void)CondF(false);
865 		} else
866 			/* F -> T.	*/
867 			condPushBack = o;
868 	}
869 	return l;
870 }
871 
872 /*-
873  *-----------------------------------------------------------------------
874  * CondE --
875  *	Main expression production.
876  *	    E -> F || E | F
877  *
878  * Results:
879  *	True, False or Err.
880  *
881  * Side Effects:
882  *	Tokens are, of course, consumed.
883  *-----------------------------------------------------------------------
884  */
885 static Token
886 CondE(bool doEval)
887 {
888 	Token l, o;
889 
890 	l = CondF(doEval);
891 	if (l != Err) {
892 		o = CondToken(doEval);
893 
894 		if (o == Or) {
895 			/* E -> F || E
896 			 *
897 			 * A similar thing occurs for ||, except that here we
898 			 * make sure the l.h.s. is False before we bother to
899 			 * evaluate the r.h.s.  Once again, if l is False, the
900 			 * result is the r.h.s. and once again if l is True, we
901 			 * parse the r.h.s. to throw it away.  */
902 			if (l == False)
903 				l = CondE(doEval);
904 			else
905 				(void)CondE(false);
906 		} else
907 			/* E -> F.	*/
908 			condPushBack = o;
909 	}
910 	return l;
911 }
912 
913 /* Evaluate conditional in line.
914  * returns COND_SKIP, COND_PARSE, COND_INVALID, COND_ISFOR, COND_ISINCLUDE,
915  * COND_ISUNDEF.
916  * A conditional line looks like this:
917  *	<cond-type> <expr>
918  *	where <cond-type> is any of if, ifmake, ifnmake, ifdef,
919  *	ifndef, elif, elifmake, elifnmake, elifdef, elifndef
920  *	and <expr> consists of &&, ||, !, make(target), defined(variable)
921  *	and parenthetical groupings thereof.
922  */
923 int
924 Cond_Eval(const char *line)
925 {
926 	/* find end of keyword */
927 	const char *end;
928 	uint32_t k;
929 	size_t len;
930 	struct If *ifp;
931 	bool value = false;
932 	int level;	/* Level at which to report errors. */
933 
934 	level = PARSE_FATAL;
935 
936 	for (end = line; ISLOWER(*end); end++)
937 		;
938 	/* quick path: recognize special targets early on */
939 	if (*end == '.' || *end == ':')
940 		return COND_INVALID;
941 	len = end - line;
942 	k = ohash_interval(line, &end);
943 	switch(k % MAGICSLOTS2) {
944 	case K_COND_IF % MAGICSLOTS2:
945 		if (k == K_COND_IF && len == strlen(COND_IF) &&
946 		    strncmp(line, COND_IF, len) == 0) {
947 			ifp = ifs + COND_IF_INDEX;
948 		} else
949 			return COND_INVALID;
950 		break;
951 	case K_COND_IFDEF % MAGICSLOTS2:
952 		if (k == K_COND_IFDEF && len == strlen(COND_IFDEF) &&
953 		    strncmp(line, COND_IFDEF, len) == 0) {
954 			ifp = ifs + COND_IFDEF_INDEX;
955 		} else
956 			return COND_INVALID;
957 		break;
958 	case K_COND_IFNDEF % MAGICSLOTS2:
959 		if (k == K_COND_IFNDEF && len == strlen(COND_IFNDEF) &&
960 		    strncmp(line, COND_IFNDEF, len) == 0) {
961 			ifp = ifs + COND_IFNDEF_INDEX;
962 		} else
963 			return COND_INVALID;
964 		break;
965 	case K_COND_IFMAKE % MAGICSLOTS2:
966 		if (k == K_COND_IFMAKE && len == strlen(COND_IFMAKE) &&
967 		    strncmp(line, COND_IFMAKE, len) == 0) {
968 			ifp = ifs + COND_IFMAKE_INDEX;
969 		} else
970 			return COND_INVALID;
971 		break;
972 	case K_COND_IFNMAKE % MAGICSLOTS2:
973 		if (k == K_COND_IFNMAKE && len == strlen(COND_IFNMAKE) &&
974 		    strncmp(line, COND_IFNMAKE, len) == 0) {
975 			ifp = ifs + COND_IFNMAKE_INDEX;
976 		} else
977 			return COND_INVALID;
978 		break;
979 	case K_COND_ELIF % MAGICSLOTS2:
980 		if (k == K_COND_ELIF && len == strlen(COND_ELIF) &&
981 		    strncmp(line, COND_ELIF, len) == 0) {
982 			ifp = ifs + COND_ELIF_INDEX;
983 		} else
984 			return COND_INVALID;
985 		break;
986 	case K_COND_ELIFDEF % MAGICSLOTS2:
987 		if (k == K_COND_ELIFDEF && len == strlen(COND_ELIFDEF) &&
988 		    strncmp(line, COND_ELIFDEF, len) == 0) {
989 			ifp = ifs + COND_ELIFDEF_INDEX;
990 		} else
991 			return COND_INVALID;
992 		break;
993 	case K_COND_ELIFNDEF % MAGICSLOTS2:
994 		if (k == K_COND_ELIFNDEF && len == strlen(COND_ELIFNDEF) &&
995 		    strncmp(line, COND_ELIFNDEF, len) == 0) {
996 			ifp = ifs + COND_ELIFNDEF_INDEX;
997 		} else
998 			return COND_INVALID;
999 		break;
1000 	case K_COND_ELIFMAKE % MAGICSLOTS2:
1001 		if (k == K_COND_ELIFMAKE && len == strlen(COND_ELIFMAKE) &&
1002 		    strncmp(line, COND_ELIFMAKE, len) == 0) {
1003 			ifp = ifs + COND_ELIFMAKE_INDEX;
1004 		} else
1005 			return COND_INVALID;
1006 		break;
1007 	case K_COND_ELIFNMAKE % MAGICSLOTS2:
1008 		if (k == K_COND_ELIFNMAKE && len == strlen(COND_ELIFNMAKE) &&
1009 		    strncmp(line, COND_ELIFNMAKE, len) == 0) {
1010 			ifp = ifs + COND_ELIFNMAKE_INDEX;
1011 		} else
1012 			return COND_INVALID;
1013 		break;
1014 	case K_COND_ELSE % MAGICSLOTS2:
1015 		/* valid conditional whose value is the inverse
1016 		 * of the previous if we parsed.  */
1017 		if (k == K_COND_ELSE && len == strlen(COND_ELSE) &&
1018 		    strncmp(line, COND_ELSE, len) == 0) {
1019 			if (condTop == MAXIF) {
1020 				Parse_Error(level, "if-less else");
1021 				return COND_INVALID;
1022 			} else if (skipIfLevel == 0) {
1023 				value = !condStack[condTop].value;
1024 				ifp = ifs + COND_ELSE_INDEX;
1025 			} else
1026 				return COND_SKIP;
1027 		} else
1028 			return COND_INVALID;
1029 		break;
1030 	case K_COND_ENDIF % MAGICSLOTS2:
1031 		if (k == K_COND_ENDIF && len == strlen(COND_ENDIF) &&
1032 		    strncmp(line, COND_ENDIF, len) == 0) {
1033 			/* End of a conditional section. If skipIfLevel is
1034 			 * non-zero, that conditional was skipped, so lines
1035 			 * following it should also be skipped. Hence, we
1036 			 * return COND_SKIP. Otherwise, the conditional was
1037 			 * read so succeeding lines should be parsed (think
1038 			 * about it...) so we return COND_PARSE, unless this
1039 			 * endif isn't paired with a decent if.  */
1040 			if (skipIfLevel != 0) {
1041 				skipIfLevel--;
1042 				return COND_SKIP;
1043 			} else {
1044 				if (condTop == MAXIF) {
1045 					Parse_Error(level, "if-less endif");
1046 					return COND_INVALID;
1047 				} else {
1048 					skipLine = false;
1049 					condTop++;
1050 					return COND_PARSE;
1051 				}
1052 			}
1053 		} else
1054 			return COND_INVALID;
1055 		break;
1056 
1057 	/* Recognize other keywords there, to simplify parser's task */
1058 	case K_COND_FOR % MAGICSLOTS2:
1059 		if (k == K_COND_FOR && len == strlen(COND_FOR) &&
1060 		    strncmp(line, COND_FOR, len) == 0)
1061 			return COND_ISFOR;
1062 		else
1063 			return COND_INVALID;
1064 	case K_COND_UNDEF % MAGICSLOTS2:
1065 		if (k == K_COND_UNDEF && len == strlen(COND_UNDEF) &&
1066 		    strncmp(line, COND_UNDEF, len) == 0)
1067 			return COND_ISUNDEF;
1068 		else
1069 			return COND_INVALID;
1070 	case K_COND_POISON % MAGICSLOTS2:
1071 		if (k == K_COND_POISON && len == strlen(COND_POISON) &&
1072 		    strncmp(line, COND_POISON, len) == 0)
1073 			return COND_ISPOISON;
1074 		else
1075 			return COND_INVALID;
1076 	case K_COND_INCLUDE % MAGICSLOTS2:
1077 		if (k == K_COND_INCLUDE && len == strlen(COND_INCLUDE) &&
1078 		    strncmp(line, COND_INCLUDE, len) == 0)
1079 			return COND_ISINCLUDE;
1080 		else
1081 			return COND_INVALID;
1082 	default:
1083 		/* Not a valid conditional type. No error...  */
1084 		return COND_INVALID;
1085 	}
1086 
1087 	if (ifp->isElse) {
1088 		if (condTop == MAXIF) {
1089 			Parse_Error(level, "if-less elif");
1090 			return COND_INVALID;
1091 		} else if (skipIfLevel != 0 || condStack[condTop].value) {
1092 			/*
1093 			 * Skip if we're meant to or is an else-type
1094 			 * conditional and previous corresponding one was
1095 			 * evaluated to true.
1096 			 */
1097 			skipLine = true;
1098 			return COND_SKIP;
1099 		}
1100 	} else if (skipLine) {
1101 		/* Don't even try to evaluate a conditional that's not an else
1102 		 * if we're skipping things...  */
1103 		skipIfLevel++;
1104 		return COND_SKIP;
1105 	} else
1106 		condTop--;
1107 
1108 	if (condTop < 0) {
1109 		/* This is the one case where we can definitely proclaim a fatal
1110 		 * error. If we don't, we're hosed.  */
1111 		Parse_Error(PARSE_FATAL, "Too many nested if's. %d max.",
1112 		    MAXIF);
1113 		condTop = 0;
1114 		return COND_INVALID;
1115 	}
1116 
1117 	if (ifp->defProc) {
1118 		/* Initialize file-global variables for parsing.  */
1119 		condDefProc = ifp->defProc;
1120 		condInvert = ifp->doNot;
1121 
1122 		line += len;
1123 
1124 		while (*line == ' ' || *line == '\t')
1125 			line++;
1126 
1127 		condExpr = line;
1128 		condPushBack = None;
1129 
1130 		switch (CondE(true)) {
1131 		case True:
1132 			if (CondToken(true) == EndOfFile) {
1133 				value = true;
1134 				break;
1135 			}
1136 			goto err;
1137 			/* FALLTHROUGH */
1138 		case False:
1139 			if (CondToken(true) == EndOfFile) {
1140 				value = false;
1141 				break;
1142 			}
1143 			/* FALLTHROUGH */
1144 		case Err:
1145 err:
1146 			Parse_Error(level, "Malformed conditional (%s)", line);
1147 			return COND_INVALID;
1148 		default:
1149 			break;
1150 		}
1151 	}
1152 
1153 	condStack[condTop].value = value;
1154 	Parse_FillLocation(&condStack[condTop].origin);
1155 	skipLine = !value;
1156 	return value ? COND_PARSE : COND_SKIP;
1157 }
1158 
1159 void
1160 Cond_End(void)
1161 {
1162 	int i;
1163 
1164 	if (condTop != MAXIF) {
1165 		Parse_Error(PARSE_FATAL, "%s%d open conditional%s",
1166 		    condTop == 0 ? "at least ": "", MAXIF-condTop,
1167 		    MAXIF-condTop == 1 ? "" : "s");
1168 		for (i = MAXIF-1; i >= condTop; i--) {
1169 			fprintf(stderr, "\t(%s:%lu)\n",
1170 			    condStack[i].origin.fname,
1171 			    condStack[i].origin.lineno);
1172 		}
1173 	}
1174 	condTop = MAXIF;
1175 }
1176