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