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