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