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