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