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