cond.c revision 47494
1184299Snwhitehorn/*
2184299Snwhitehorn * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
3184299Snwhitehorn * Copyright (c) 1988, 1989 by Adam de Boor
4184299Snwhitehorn * Copyright (c) 1989 by Berkeley Softworks
5184299Snwhitehorn * All rights reserved.
6184299Snwhitehorn *
7184299Snwhitehorn * This code is derived from software contributed to Berkeley by
8184299Snwhitehorn * Adam de Boor.
9184299Snwhitehorn *
10184299Snwhitehorn * Redistribution and use in source and binary forms, with or without
11184299Snwhitehorn * modification, are permitted provided that the following conditions
12184299Snwhitehorn * are met:
13184299Snwhitehorn * 1. Redistributions of source code must retain the above copyright
14184299Snwhitehorn *    notice, this list of conditions and the following disclaimer.
15184299Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright
16184299Snwhitehorn *    notice, this list of conditions and the following disclaimer in the
17184299Snwhitehorn *    documentation and/or other materials provided with the distribution.
18184299Snwhitehorn * 3. All advertising materials mentioning features or use of this software
19184299Snwhitehorn *    must display the following acknowledgement:
20184299Snwhitehorn *	This product includes software developed by the University of
21184299Snwhitehorn *	California, Berkeley and its contributors.
22184299Snwhitehorn * 4. Neither the name of the University nor the names of its contributors
23184299Snwhitehorn *    may be used to endorse or promote products derived from this software
24184299Snwhitehorn *    without specific prior written permission.
25184299Snwhitehorn *
26184299Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27184299Snwhitehorn * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28184299Snwhitehorn * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29184299Snwhitehorn * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30184299Snwhitehorn * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31184299Snwhitehorn * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32184299Snwhitehorn * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33184299Snwhitehorn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34184299Snwhitehorn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35184299Snwhitehorn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36184299Snwhitehorn * SUCH DAMAGE.
37184299Snwhitehorn *
38199888Snwhitehorn *	$Id: cond.c,v 1.7 1997/02/22 19:27:07 peter Exp $
39184299Snwhitehorn */
40184299Snwhitehorn
41184299Snwhitehorn#ifndef lint
42184299Snwhitehornstatic char sccsid[] = "@(#)cond.c	8.2 (Berkeley) 1/2/94";
43184299Snwhitehorn#endif /* not lint */
44184299Snwhitehorn
45184299Snwhitehorn/*-
46184299Snwhitehorn * cond.c --
47184299Snwhitehorn *	Functions to handle conditionals in a makefile.
48184299Snwhitehorn *
49184299Snwhitehorn * Interface:
50187893Sjhb *	Cond_Eval 	Evaluate the conditional in the passed line.
51184299Snwhitehorn *
52184299Snwhitehorn */
53184299Snwhitehorn
54184299Snwhitehorn#include    <ctype.h>
55199888Snwhitehorn#include    <math.h>
56199888Snwhitehorn#include    "make.h"
57184299Snwhitehorn#include    "hash.h"
58184299Snwhitehorn#include    "dir.h"
59184299Snwhitehorn#include    "buf.h"
60184299Snwhitehorn
61184299Snwhitehorn/*
62184299Snwhitehorn * The parsing of conditional expressions is based on this grammar:
63184299Snwhitehorn *	E -> F || E
64184299Snwhitehorn *	E -> F
65184299Snwhitehorn *	F -> T && F
66184299Snwhitehorn *	F -> T
67184299Snwhitehorn *	T -> defined(variable)
68184299Snwhitehorn *	T -> make(target)
69184299Snwhitehorn *	T -> exists(file)
70184299Snwhitehorn *	T -> empty(varspec)
71184299Snwhitehorn *	T -> target(name)
72184299Snwhitehorn *	T -> symbol
73184565Sed *	T -> $(varspec) op value
74184565Sed *	T -> $(varspec) == "string"
75184565Sed *	T -> $(varspec) != "string"
76184299Snwhitehorn *	T -> ( E )
77184299Snwhitehorn *	T -> ! T
78184299Snwhitehorn *	op -> == | != | > | < | >= | <=
79184299Snwhitehorn *
80184299Snwhitehorn * 'symbol' is some other symbol to which the default function (condDefProc)
81184299Snwhitehorn * is applied.
82184299Snwhitehorn *
83199888Snwhitehorn * Tokens are scanned from the 'condExpr' string. The scanner (CondToken)
84199888Snwhitehorn * will return And for '&' and '&&', Or for '|' and '||', Not for '!',
85184299Snwhitehorn * LParen for '(', RParen for ')' and will evaluate the other terminal
86184299Snwhitehorn * symbols, using either the default function or the function given in the
87184299Snwhitehorn * terminal, and return the result as either True or False.
88184299Snwhitehorn *
89184299Snwhitehorn * All Non-Terminal functions (CondE, CondF and CondT) return Err on error.
90184299Snwhitehorn */
91184299Snwhitehorntypedef enum {
92184299Snwhitehorn    And, Or, Not, True, False, LParen, RParen, EndOfFile, None, Err
93184299Snwhitehorn} Token;
94184299Snwhitehorn
95184299Snwhitehorn/*-
96184299Snwhitehorn * Structures to handle elegantly the different forms of #if's. The
97184299Snwhitehorn * last two fields are stored in condInvert and condDefProc, respectively.
98184299Snwhitehorn */
99184299Snwhitehornstatic void CondPushBack __P((Token));
100184299Snwhitehornstatic int CondGetArg __P((char **, char **, char *, Boolean));
101184299Snwhitehornstatic Boolean CondDoDefined __P((int, char *));
102184299Snwhitehornstatic int CondStrMatch __P((ClientData, ClientData));
103184299Snwhitehornstatic Boolean CondDoMake __P((int, char *));
104184299Snwhitehornstatic Boolean CondDoExists __P((int, char *));
105184299Snwhitehornstatic Boolean CondDoTarget __P((int, char *));
106184299Snwhitehornstatic char * CondCvtArg __P((char *, double *));
107184299Snwhitehornstatic Token CondToken __P((Boolean));
108184299Snwhitehornstatic Token CondT __P((Boolean));
109184299Snwhitehornstatic Token CondF __P((Boolean));
110184299Snwhitehornstatic Token CondE __P((Boolean));
111184299Snwhitehorn
112184299Snwhitehornstatic struct If {
113184299Snwhitehorn    char	*form;	      /* Form of if */
114184299Snwhitehorn    int		formlen;      /* Length of form */
115184299Snwhitehorn    Boolean	doNot;	      /* TRUE if default function should be negated */
116184299Snwhitehorn    Boolean	(*defProc) __P((int, char *)); /* Default function to apply */
117184299Snwhitehorn} ifs[] = {
118184299Snwhitehorn    { "ifdef",	  5,	  FALSE,  CondDoDefined },
119184299Snwhitehorn    { "ifndef",	  6,	  TRUE,	  CondDoDefined },
120184299Snwhitehorn    { "ifmake",	  6,	  FALSE,  CondDoMake },
121184299Snwhitehorn    { "ifnmake",  7,	  TRUE,	  CondDoMake },
122184299Snwhitehorn    { "if",	  2,	  FALSE,  CondDoDefined },
123184299Snwhitehorn    { NULL,	  0,	  FALSE,  NULL }
124184299Snwhitehorn};
125184299Snwhitehorn
126184299Snwhitehornstatic Boolean	  condInvert;	    	/* Invert the default function */
127184299Snwhitehornstatic Boolean	  (*condDefProc)	/* Default function to apply */
128184299Snwhitehorn		    __P((int, char *));
129184299Snwhitehornstatic char 	  *condExpr;	    	/* The expression to parse */
130184299Snwhitehornstatic Token	  condPushBack=None;	/* Single push-back token used in
131184299Snwhitehorn					 * parsing */
132184299Snwhitehorn
133184299Snwhitehorn#define	MAXIF		30	  /* greatest depth of #if'ing */
134184299Snwhitehorn
135184299Snwhitehornstatic Boolean	  condStack[MAXIF]; 	/* Stack of conditionals's values */
136184299Snwhitehornstatic int  	  condTop = MAXIF;  	/* Top-most conditional */
137184299Snwhitehornstatic int  	  skipIfLevel=0;    	/* Depth of skipped conditionals */
138184299Snwhitehornstatic Boolean	  skipLine = FALSE; 	/* Whether the parse module is skipping
139184299Snwhitehorn					 * lines */
140184299Snwhitehorn
141184299Snwhitehorn/*-
142184299Snwhitehorn *-----------------------------------------------------------------------
143184299Snwhitehorn * CondPushBack --
144184299Snwhitehorn *	Push back the most recent token read. We only need one level of
145184299Snwhitehorn *	this, so the thing is just stored in 'condPushback'.
146184299Snwhitehorn *
147184299Snwhitehorn * Results:
148184299Snwhitehorn *	None.
149184299Snwhitehorn *
150184299Snwhitehorn * Side Effects:
151184299Snwhitehorn *	condPushback is overwritten.
152184299Snwhitehorn *
153184299Snwhitehorn *-----------------------------------------------------------------------
154184299Snwhitehorn */
155184299Snwhitehornstatic void
156184299SnwhitehornCondPushBack (t)
157262668Sjhibbits    Token   	  t;	/* Token to push back into the "stream" */
158184299Snwhitehorn{
159184299Snwhitehorn    condPushBack = t;
160184565Sed}
161184299Snwhitehorn
162184299Snwhitehorn/*-
163184299Snwhitehorn *-----------------------------------------------------------------------
164184299Snwhitehorn * CondGetArg --
165184299Snwhitehorn *	Find the argument of a built-in function.
166184299Snwhitehorn *
167184299Snwhitehorn * Results:
168184299Snwhitehorn *	The length of the argument and the address of the argument.
169184299Snwhitehorn *
170184299Snwhitehorn * Side Effects:
171184299Snwhitehorn *	The pointer is set to point to the closing parenthesis of the
172184299Snwhitehorn *	function call.
173184299Snwhitehorn *
174184299Snwhitehorn *-----------------------------------------------------------------------
175199888Snwhitehorn */
176199888Snwhitehornstatic int
177184299SnwhitehornCondGetArg (linePtr, argPtr, func, parens)
178184299Snwhitehorn    char    	  **linePtr;
179184299Snwhitehorn    char    	  **argPtr;
180184299Snwhitehorn    char    	  *func;
181184299Snwhitehorn    Boolean 	  parens;   	/* TRUE if arg should be bounded by parens */
182184299Snwhitehorn{
183184299Snwhitehorn    register char *cp;
184184299Snwhitehorn    int	    	  argLen;
185184299Snwhitehorn    register Buffer buf;
186184299Snwhitehorn
187184299Snwhitehorn    cp = *linePtr;
188184299Snwhitehorn    if (parens) {
189184299Snwhitehorn	while (*cp != '(' && *cp != '\0') {
190184299Snwhitehorn	    cp++;
191185724Snwhitehorn	}
192184299Snwhitehorn	if (*cp == '(') {
193184299Snwhitehorn	    cp++;
194184299Snwhitehorn	}
195184565Sed    }
196184299Snwhitehorn
197184299Snwhitehorn    if (*cp == '\0') {
198184299Snwhitehorn	/*
199184299Snwhitehorn	 * No arguments whatsoever. Because 'make' and 'defined' aren't really
200184299Snwhitehorn	 * "reserved words", we don't print a message. I think this is better
201184299Snwhitehorn	 * than hitting the user with a warning message every time s/he uses
202184299Snwhitehorn	 * the word 'make' or 'defined' at the beginning of a symbol...
203184299Snwhitehorn	 */
204184299Snwhitehorn	*argPtr = cp;
205184299Snwhitehorn	return (0);
206184299Snwhitehorn    }
207184299Snwhitehorn
208184299Snwhitehorn    while (*cp == ' ' || *cp == '\t') {
209184299Snwhitehorn	cp++;
210184299Snwhitehorn    }
211184299Snwhitehorn
212184565Sed    /*
213184565Sed     * Create a buffer for the argument and start it out at 16 characters
214184565Sed     * long. Why 16? Why not?
215199888Snwhitehorn     */
216184565Sed    buf = Buf_Init(16);
217184565Sed
218184299Snwhitehorn    while ((strchr(" \t)&|", *cp) == (char *)NULL) && (*cp != '\0')) {
219184299Snwhitehorn	if (*cp == '$') {
220184299Snwhitehorn	    /*
221184299Snwhitehorn	     * Parse the variable spec and install it as part of the argument
222184299Snwhitehorn	     * if it's valid. We tell Var_Parse to complain on an undefined
223184299Snwhitehorn	     * variable, so we don't do it too. Nor do we return an error,
224184299Snwhitehorn	     * though perhaps we should...
225184299Snwhitehorn	     */
226184299Snwhitehorn	    char  	*cp2;
227184299Snwhitehorn	    int		len;
228184299Snwhitehorn	    Boolean	doFree;
229184299Snwhitehorn
230184299Snwhitehorn	    cp2 = Var_Parse(cp, VAR_CMD, TRUE, &len, &doFree);
231184299Snwhitehorn
232184299Snwhitehorn	    Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2);
233184299Snwhitehorn	    if (doFree) {
234184299Snwhitehorn		free(cp2);
235184299Snwhitehorn	    }
236184299Snwhitehorn	    cp += len;
237184565Sed	} else {
238184299Snwhitehorn	    Buf_AddByte(buf, (Byte)*cp);
239184299Snwhitehorn	    cp++;
240184299Snwhitehorn	}
241184299Snwhitehorn    }
242184299Snwhitehorn
243184299Snwhitehorn    Buf_AddByte(buf, (Byte)'\0');
244184299Snwhitehorn    *argPtr = (char *)Buf_GetAll(buf, &argLen);
245184299Snwhitehorn    Buf_Destroy(buf, FALSE);
246184299Snwhitehorn
247187893Sjhb    while (*cp == ' ' || *cp == '\t') {
248184299Snwhitehorn	cp++;
249184299Snwhitehorn    }
250184299Snwhitehorn    if (parens && *cp != ')') {
251184299Snwhitehorn	Parse_Error (PARSE_WARNING, "Missing closing parenthesis for %s()",
252184299Snwhitehorn		     func);
253184299Snwhitehorn	return (0);
254184299Snwhitehorn    } else if (parens) {
255184299Snwhitehorn	/*
256184299Snwhitehorn	 * Advance pointer past close parenthesis.
257184299Snwhitehorn	 */
258184299Snwhitehorn	cp++;
259184299Snwhitehorn    }
260184299Snwhitehorn
261184299Snwhitehorn    *linePtr = cp;
262184299Snwhitehorn    return (argLen);
263184299Snwhitehorn}
264184299Snwhitehorn
265184299Snwhitehorn/*-
266184299Snwhitehorn *-----------------------------------------------------------------------
267184299Snwhitehorn * CondDoDefined --
268184299Snwhitehorn *	Handle the 'defined' function for conditionals.
269184299Snwhitehorn *
270199888Snwhitehorn * Results:
271199888Snwhitehorn *	TRUE if the given variable is defined.
272199888Snwhitehorn *
273199888Snwhitehorn * Side Effects:
274199888Snwhitehorn *	None.
275199888Snwhitehorn *
276199888Snwhitehorn *-----------------------------------------------------------------------
277199888Snwhitehorn */
278199888Snwhitehornstatic Boolean
279199888SnwhitehornCondDoDefined (argLen, arg)
280199888Snwhitehorn    int	    argLen;
281199888Snwhitehorn    char    *arg;
282199888Snwhitehorn{
283199888Snwhitehorn    char    savec = arg[argLen];
284199888Snwhitehorn    char    *p1;
285199888Snwhitehorn    Boolean result;
286199888Snwhitehorn
287199888Snwhitehorn    arg[argLen] = '\0';
288199888Snwhitehorn    if (Var_Value (arg, VAR_CMD, &p1) != (char *)NULL) {
289199888Snwhitehorn	result = TRUE;
290199888Snwhitehorn    } else {
291199888Snwhitehorn	result = FALSE;
292199888Snwhitehorn    }
293199888Snwhitehorn    if (p1)
294199888Snwhitehorn	free(p1);
295199888Snwhitehorn    arg[argLen] = savec;
296199888Snwhitehorn    return (result);
297199888Snwhitehorn}
298199888Snwhitehorn
299199888Snwhitehorn/*-
300199888Snwhitehorn *-----------------------------------------------------------------------
301199888Snwhitehorn * CondStrMatch --
302199888Snwhitehorn *	Front-end for Str_Match so it returns 0 on match and non-zero
303199888Snwhitehorn *	on mismatch. Callback function for CondDoMake via Lst_Find
304199888Snwhitehorn *
305199888Snwhitehorn * Results:
306199888Snwhitehorn *	0 if string matches pattern
307199888Snwhitehorn *
308199888Snwhitehorn * Side Effects:
309199888Snwhitehorn *	None
310199888Snwhitehorn *
311199888Snwhitehorn *-----------------------------------------------------------------------
312199888Snwhitehorn */
313199888Snwhitehornstatic int
314199888SnwhitehornCondStrMatch(string, pattern)
315199888Snwhitehorn    ClientData    string;
316199888Snwhitehorn    ClientData    pattern;
317199888Snwhitehorn{
318199888Snwhitehorn    return(!Str_Match((char *) string,(char *) pattern));
319199888Snwhitehorn}
320199888Snwhitehorn
321199888Snwhitehorn/*-
322199888Snwhitehorn *-----------------------------------------------------------------------
323199888Snwhitehorn * CondDoMake --
324199888Snwhitehorn *	Handle the 'make' function for conditionals.
325199888Snwhitehorn *
326199888Snwhitehorn * Results:
327199888Snwhitehorn *	TRUE if the given target is being made.
328199888Snwhitehorn *
329199888Snwhitehorn * Side Effects:
330199888Snwhitehorn *	None.
331199888Snwhitehorn *
332199888Snwhitehorn *-----------------------------------------------------------------------
333199888Snwhitehorn */
334184299Snwhitehornstatic Boolean
335184299SnwhitehornCondDoMake (argLen, arg)
336184299Snwhitehorn    int	    argLen;
337184299Snwhitehorn    char    *arg;
338184299Snwhitehorn{
339184299Snwhitehorn    char    savec = arg[argLen];
340184299Snwhitehorn    Boolean result;
341199888Snwhitehorn
342184299Snwhitehorn    arg[argLen] = '\0';
343184299Snwhitehorn    if (Lst_Find (create, (ClientData)arg, CondStrMatch) == NILLNODE) {
344184299Snwhitehorn	result = FALSE;
345184299Snwhitehorn    } else {
346184299Snwhitehorn	result = TRUE;
347184299Snwhitehorn    }
348184299Snwhitehorn    arg[argLen] = savec;
349184299Snwhitehorn    return (result);
350184299Snwhitehorn}
351184299Snwhitehorn
352184299Snwhitehorn/*-
353184299Snwhitehorn *-----------------------------------------------------------------------
354184299Snwhitehorn * CondDoExists --
355184565Sed *	See if the given file exists.
356184299Snwhitehorn *
357184299Snwhitehorn * Results:
358184299Snwhitehorn *	TRUE if the file exists and FALSE if it does not.
359184299Snwhitehorn *
360184299Snwhitehorn * Side Effects:
361184299Snwhitehorn *	None.
362184299Snwhitehorn *
363184299Snwhitehorn *-----------------------------------------------------------------------
364184299Snwhitehorn */
365184299Snwhitehornstatic Boolean
366184299SnwhitehornCondDoExists (argLen, arg)
367184299Snwhitehorn    int	    argLen;
368184299Snwhitehorn    char    *arg;
369184299Snwhitehorn{
370184299Snwhitehorn    char    savec = arg[argLen];
371184299Snwhitehorn    Boolean result;
372184299Snwhitehorn    char    *path;
373199888Snwhitehorn
374199888Snwhitehorn    arg[argLen] = '\0';
375199888Snwhitehorn    path = Dir_FindFile(arg, dirSearchPath);
376199888Snwhitehorn    if (path != (char *)NULL) {
377199888Snwhitehorn	result = TRUE;
378199888Snwhitehorn	free(path);
379199888Snwhitehorn    } else {
380199888Snwhitehorn	result = FALSE;
381199888Snwhitehorn    }
382199888Snwhitehorn    arg[argLen] = savec;
383199888Snwhitehorn    return (result);
384199888Snwhitehorn}
385199888Snwhitehorn
386199888Snwhitehorn/*-
387199888Snwhitehorn *-----------------------------------------------------------------------
388199888Snwhitehorn * CondDoTarget --
389199888Snwhitehorn *	See if the given node exists and is an actual target.
390199888Snwhitehorn *
391199888Snwhitehorn * Results:
392199888Snwhitehorn *	TRUE if the node exists as a target and FALSE if it does not.
393199888Snwhitehorn *
394199888Snwhitehorn * Side Effects:
395199888Snwhitehorn *	None.
396199888Snwhitehorn *
397184299Snwhitehorn *-----------------------------------------------------------------------
398184299Snwhitehorn */
399184299Snwhitehornstatic Boolean
400184299SnwhitehornCondDoTarget (argLen, arg)
401184565Sed    int	    argLen;
402184565Sed    char    *arg;
403184565Sed{
404184299Snwhitehorn    char    savec = arg[argLen];
405184299Snwhitehorn    Boolean result;
406184565Sed    GNode   *gn;
407184565Sed
408184299Snwhitehorn    arg[argLen] = '\0';
409184299Snwhitehorn    gn = Targ_FindNode(arg, TARG_NOCREATE);
410184565Sed    if ((gn != NILGNODE) && !OP_NOP(gn->type)) {
411184299Snwhitehorn	result = TRUE;
412184299Snwhitehorn    } else {
413184299Snwhitehorn	result = FALSE;
414184299Snwhitehorn    }
415184299Snwhitehorn    arg[argLen] = savec;
416184299Snwhitehorn    return (result);
417184299Snwhitehorn}
418184299Snwhitehorn
419184299Snwhitehorn
420184299Snwhitehorn/*-
421184299Snwhitehorn *-----------------------------------------------------------------------
422184299Snwhitehorn * CondCvtArg --
423184299Snwhitehorn *	Convert the given number into a double. If the number begins
424184299Snwhitehorn *	with 0x, it is interpreted as a hexadecimal integer
425184299Snwhitehorn *	and converted to a double from there. All other strings just have
426184299Snwhitehorn *	strtod called on them.
427184299Snwhitehorn *
428184299Snwhitehorn * Results:
429184299Snwhitehorn *	Sets 'value' to double value of string.
430184299Snwhitehorn *	Returns address of the first character after the last valid
431184299Snwhitehorn *	character of the converted number.
432184299Snwhitehorn *
433184299Snwhitehorn * Side Effects:
434184299Snwhitehorn *	Can change 'value' even if string is not a valid number.
435184299Snwhitehorn *
436184299Snwhitehorn *
437184299Snwhitehorn *-----------------------------------------------------------------------
438184299Snwhitehorn */
439184299Snwhitehornstatic char *
440184299SnwhitehornCondCvtArg(str, value)
441184299Snwhitehorn    register char    	*str;
442184299Snwhitehorn    double		*value;
443184299Snwhitehorn{
444184299Snwhitehorn    if ((*str == '0') && (str[1] == 'x')) {
445184299Snwhitehorn	register long i;
446184299Snwhitehorn
447184299Snwhitehorn	for (str += 2, i = 0; ; str++) {
448184299Snwhitehorn	    int x;
449184299Snwhitehorn	    if (isdigit((unsigned char) *str))
450184299Snwhitehorn		x  = *str - '0';
451184299Snwhitehorn	    else if (isxdigit((unsigned char) *str))
452184299Snwhitehorn		x = 10 + *str - isupper((unsigned char) *str) ? 'A' : 'a';
453184299Snwhitehorn	    else {
454184299Snwhitehorn		*value = (double) i;
455184299Snwhitehorn		return str;
456184299Snwhitehorn	    }
457184299Snwhitehorn	    i = (i << 4) + x;
458184299Snwhitehorn	}
459184299Snwhitehorn    }
460184299Snwhitehorn    else {
461184299Snwhitehorn	char *eptr;
462184299Snwhitehorn	*value = strtod(str, &eptr);
463184299Snwhitehorn	return eptr;
464184299Snwhitehorn    }
465184299Snwhitehorn}
466184299Snwhitehorn
467184299Snwhitehorn/*-
468184299Snwhitehorn *-----------------------------------------------------------------------
469184299Snwhitehorn * CondToken --
470184299Snwhitehorn *	Return the next token from the input.
471184299Snwhitehorn *
472184299Snwhitehorn * Results:
473184299Snwhitehorn *	A Token for the next lexical token in the stream.
474255921Sjhibbits *
475255921Sjhibbits * Side Effects:
476184299Snwhitehorn *	condPushback will be set back to None if it is used.
477184299Snwhitehorn *
478184299Snwhitehorn *-----------------------------------------------------------------------
479184299Snwhitehorn */
480184299Snwhitehornstatic Token
481184299SnwhitehornCondToken(doEval)
482184299Snwhitehorn    Boolean doEval;
483184299Snwhitehorn{
484184299Snwhitehorn    Token	  t;
485184299Snwhitehorn
486184299Snwhitehorn    if (condPushBack == None) {
487184299Snwhitehorn	while (*condExpr == ' ' || *condExpr == '\t') {
488184299Snwhitehorn	    condExpr++;
489184299Snwhitehorn	}
490184299Snwhitehorn	switch (*condExpr) {
491184299Snwhitehorn	    case '(':
492184299Snwhitehorn		t = LParen;
493184299Snwhitehorn		condExpr++;
494184520Sed		break;
495184299Snwhitehorn	    case ')':
496184299Snwhitehorn		t = RParen;
497184299Snwhitehorn		condExpr++;
498184299Snwhitehorn		break;
499184299Snwhitehorn	    case '|':
500184299Snwhitehorn		if (condExpr[1] == '|') {
501184299Snwhitehorn		    condExpr++;
502184299Snwhitehorn		}
503184299Snwhitehorn		condExpr++;
504184299Snwhitehorn		t = Or;
505184299Snwhitehorn		break;
506184299Snwhitehorn	    case '&':
507184299Snwhitehorn		if (condExpr[1] == '&') {
508184299Snwhitehorn		    condExpr++;
509184299Snwhitehorn		}
510184299Snwhitehorn		condExpr++;
511184299Snwhitehorn		t = And;
512184299Snwhitehorn		break;
513184299Snwhitehorn	    case '!':
514184299Snwhitehorn		t = Not;
515184299Snwhitehorn		condExpr++;
516184520Sed		break;
517184520Sed	    case '\n':
518184520Sed	    case '\0':
519184520Sed		t = EndOfFile;
520184520Sed		break;
521184299Snwhitehorn	    case '$': {
522184299Snwhitehorn		char	*lhs;
523184299Snwhitehorn		char	*rhs;
524184299Snwhitehorn		char	*op;
525184299Snwhitehorn		int	varSpecLen;
526184299Snwhitehorn		Boolean	doFree;
527184299Snwhitehorn
528184299Snwhitehorn		/*
529184299Snwhitehorn		 * Parse the variable spec and skip over it, saving its
530184299Snwhitehorn		 * value in lhs.
531184299Snwhitehorn		 */
532184299Snwhitehorn		t = Err;
533184299Snwhitehorn		lhs = Var_Parse(condExpr, VAR_CMD, doEval,&varSpecLen,&doFree);
534184299Snwhitehorn		if (lhs == var_Error) {
535184299Snwhitehorn		    /*
536184299Snwhitehorn		     * Even if !doEval, we still report syntax errors, which
537184299Snwhitehorn		     * is what getting var_Error back with !doEval means.
538184299Snwhitehorn		     */
539184299Snwhitehorn		    return(Err);
540184299Snwhitehorn		}
541184299Snwhitehorn		condExpr += varSpecLen;
542184299Snwhitehorn
543184299Snwhitehorn		if (!isspace((unsigned char) *condExpr) &&
544184299Snwhitehorn		    strchr("!=><", *condExpr) == NULL) {
545184299Snwhitehorn		    Buffer buf;
546184299Snwhitehorn		    char *cp;
547184299Snwhitehorn
548184299Snwhitehorn		    buf = Buf_Init(0);
549184299Snwhitehorn
550184299Snwhitehorn		    for (cp = lhs; *cp; cp++)
551184299Snwhitehorn			Buf_AddByte(buf, (Byte)*cp);
552184299Snwhitehorn
553184299Snwhitehorn		    if (doFree)
554184299Snwhitehorn			free(lhs);
555184299Snwhitehorn
556184299Snwhitehorn		    for (;*condExpr && !isspace((unsigned char) *condExpr);
557184299Snwhitehorn			 condExpr++)
558184299Snwhitehorn			Buf_AddByte(buf, (Byte)*condExpr);
559184299Snwhitehorn
560184299Snwhitehorn		    Buf_AddByte(buf, (Byte)'\0');
561184299Snwhitehorn		    lhs = (char *)Buf_GetAll(buf, &varSpecLen);
562184299Snwhitehorn		    Buf_Destroy(buf, FALSE);
563184299Snwhitehorn
564184299Snwhitehorn		    doFree = TRUE;
565184299Snwhitehorn		}
566184299Snwhitehorn
567184299Snwhitehorn		/*
568184299Snwhitehorn		 * Skip whitespace to get to the operator
569184299Snwhitehorn		 */
570184299Snwhitehorn		while (isspace((unsigned char) *condExpr))
571184299Snwhitehorn		    condExpr++;
572184299Snwhitehorn
573242948Skevlo		/*
574184299Snwhitehorn		 * Make sure the operator is a valid one. If it isn't a
575242948Skevlo		 * known relational operator, pretend we got a
576184299Snwhitehorn		 * != 0 comparison.
577184299Snwhitehorn		 */
578184299Snwhitehorn		op = condExpr;
579184299Snwhitehorn		switch (*condExpr) {
580184299Snwhitehorn		    case '!':
581184299Snwhitehorn		    case '=':
582184299Snwhitehorn		    case '<':
583184299Snwhitehorn		    case '>':
584184299Snwhitehorn			if (condExpr[1] == '=') {
585184299Snwhitehorn			    condExpr += 2;
586184299Snwhitehorn			} else {
587184299Snwhitehorn			    condExpr += 1;
588184299Snwhitehorn			}
589184299Snwhitehorn			break;
590184299Snwhitehorn		    default:
591184299Snwhitehorn			op = "!=";
592184299Snwhitehorn			rhs = "0";
593184299Snwhitehorn
594184299Snwhitehorn			goto do_compare;
595184299Snwhitehorn		}
596184299Snwhitehorn		while (isspace((unsigned char) *condExpr)) {
597184299Snwhitehorn		    condExpr++;
598184299Snwhitehorn		}
599184299Snwhitehorn		if (*condExpr == '\0') {
600184299Snwhitehorn		    Parse_Error(PARSE_WARNING,
601184299Snwhitehorn				"Missing right-hand-side of operator");
602184299Snwhitehorn		    goto error;
603184299Snwhitehorn		}
604184299Snwhitehorn		rhs = condExpr;
605184299Snwhitehorndo_compare:
606184299Snwhitehorn		if (*rhs == '"') {
607184299Snwhitehorn		    /*
608184299Snwhitehorn		     * Doing a string comparison. Only allow == and != for
609184299Snwhitehorn		     * operators.
610184299Snwhitehorn		     */
611184299Snwhitehorn		    char    *string;
612184299Snwhitehorn		    char    *cp, *cp2;
613184299Snwhitehorn		    int	    qt;
614184299Snwhitehorn		    Buffer  buf;
615184299Snwhitehorn
616184299Snwhitehorndo_string_compare:
617184299Snwhitehorn		    if (((*op != '!') && (*op != '=')) || (op[1] != '=')) {
618184299Snwhitehorn			Parse_Error(PARSE_WARNING,
619184299Snwhitehorn		"String comparison operator should be either == or !=");
620184299Snwhitehorn			goto error;
621184299Snwhitehorn		    }
622184299Snwhitehorn
623184299Snwhitehorn		    buf = Buf_Init(0);
624184299Snwhitehorn		    qt = *rhs == '"' ? 1 : 0;
625184299Snwhitehorn
626184299Snwhitehorn		    for (cp = &rhs[qt];
627184299Snwhitehorn			 ((qt && (*cp != '"')) ||
628184299Snwhitehorn			  (!qt && strchr(" \t)", *cp) == NULL)) &&
629184299Snwhitehorn			 (*cp != '\0'); cp++) {
630184299Snwhitehorn			if ((*cp == '\\') && (cp[1] != '\0')) {
631184299Snwhitehorn			    /*
632184299Snwhitehorn			     * Backslash escapes things -- skip over next
633184299Snwhitehorn			     * character, if it exists.
634184299Snwhitehorn			     */
635184299Snwhitehorn			    cp++;
636184299Snwhitehorn			    Buf_AddByte(buf, (Byte)*cp);
637184299Snwhitehorn			} else if (*cp == '$') {
638184299Snwhitehorn			    int	len;
639184299Snwhitehorn			    Boolean freeIt;
640184299Snwhitehorn
641184299Snwhitehorn			    cp2 = Var_Parse(cp, VAR_CMD, doEval,&len, &freeIt);
642184299Snwhitehorn			    if (cp2 != var_Error) {
643184299Snwhitehorn				Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2);
644184299Snwhitehorn				if (freeIt) {
645184299Snwhitehorn				    free(cp2);
646184299Snwhitehorn				}
647184299Snwhitehorn				cp += len - 1;
648184299Snwhitehorn			    } else {
649184299Snwhitehorn				Buf_AddByte(buf, (Byte)*cp);
650184299Snwhitehorn			    }
651184299Snwhitehorn			} else {
652184299Snwhitehorn			    Buf_AddByte(buf, (Byte)*cp);
653184299Snwhitehorn			}
654199888Snwhitehorn		    }
655199888Snwhitehorn
656199888Snwhitehorn		    Buf_AddByte(buf, (Byte)0);
657199888Snwhitehorn
658199888Snwhitehorn		    string = (char *)Buf_GetAll(buf, (int *)0);
659199888Snwhitehorn		    Buf_Destroy(buf, FALSE);
660199888Snwhitehorn
661199888Snwhitehorn		    if (DEBUG(COND)) {
662199888Snwhitehorn			printf("lhs = \"%s\", rhs = \"%s\", op = %.2s\n",
663199888Snwhitehorn			       lhs, string, op);
664199888Snwhitehorn		    }
665199888Snwhitehorn		    /*
666199888Snwhitehorn		     * Null-terminate rhs and perform the comparison.
667199888Snwhitehorn		     * t is set to the result.
668199888Snwhitehorn		     */
669199888Snwhitehorn		    if (*op == '=') {
670199888Snwhitehorn			t = strcmp(lhs, string) ? False : True;
671199888Snwhitehorn		    } else {
672199888Snwhitehorn			t = strcmp(lhs, string) ? True : False;
673199888Snwhitehorn		    }
674199888Snwhitehorn		    free(string);
675199888Snwhitehorn		    if (rhs == condExpr) {
676199888Snwhitehorn		    	if (!qt && *cp == ')')
677199888Snwhitehorn			    condExpr = cp;
678199888Snwhitehorn			else
679199888Snwhitehorn			    condExpr = cp + 1;
680199888Snwhitehorn		    }
681199888Snwhitehorn		} else {
682199888Snwhitehorn		    /*
683199888Snwhitehorn		     * rhs is either a float or an integer. Convert both the
684199888Snwhitehorn		     * lhs and the rhs to a double and compare the two.
685199888Snwhitehorn		     */
686199888Snwhitehorn		    double  	left, right;
687		    char    	*string;
688
689		    if (*CondCvtArg(lhs, &left) != '\0')
690			goto do_string_compare;
691		    if (*rhs == '$') {
692			int 	len;
693			Boolean	freeIt;
694
695			string = Var_Parse(rhs, VAR_CMD, doEval,&len,&freeIt);
696			if (string == var_Error) {
697			    right = 0.0;
698			} else {
699			    if (*CondCvtArg(string, &right) != '\0') {
700				if (freeIt)
701				    free(string);
702				goto do_string_compare;
703			    }
704			    if (freeIt)
705				free(string);
706			    if (rhs == condExpr)
707				condExpr += len;
708			}
709		    } else {
710			if (CondCvtArg(rhs, &right) == rhs)
711			    goto do_string_compare;
712			if (rhs == condExpr) {
713			    /*
714			     * Skip over the right-hand side
715			     */
716			    while(!isspace((unsigned char) *condExpr) &&
717				  (*condExpr != '\0')) {
718				condExpr++;
719			    }
720			}
721		    }
722
723		    if (DEBUG(COND)) {
724			printf("left = %f, right = %f, op = %.2s\n", left,
725			       right, op);
726		    }
727		    switch(op[0]) {
728		    case '!':
729			if (op[1] != '=') {
730			    Parse_Error(PARSE_WARNING,
731					"Unknown operator");
732			    goto error;
733			}
734			t = (left != right ? True : False);
735			break;
736		    case '=':
737			if (op[1] != '=') {
738			    Parse_Error(PARSE_WARNING,
739					"Unknown operator");
740			    goto error;
741			}
742			t = (left == right ? True : False);
743			break;
744		    case '<':
745			if (op[1] == '=') {
746			    t = (left <= right ? True : False);
747			} else {
748			    t = (left < right ? True : False);
749			}
750			break;
751		    case '>':
752			if (op[1] == '=') {
753			    t = (left >= right ? True : False);
754			} else {
755			    t = (left > right ? True : False);
756			}
757			break;
758		    }
759		}
760error:
761		if (doFree)
762		    free(lhs);
763		break;
764	    }
765	    default: {
766		Boolean (*evalProc) __P((int, char *));
767		Boolean invert = FALSE;
768		char	*arg;
769		int	arglen;
770
771		if (strncmp (condExpr, "defined", 7) == 0) {
772		    /*
773		     * Use CondDoDefined to evaluate the argument and
774		     * CondGetArg to extract the argument from the 'function
775		     * call'.
776		     */
777		    evalProc = CondDoDefined;
778		    condExpr += 7;
779		    arglen = CondGetArg (&condExpr, &arg, "defined", TRUE);
780		    if (arglen == 0) {
781			condExpr -= 7;
782			goto use_default;
783		    }
784		} else if (strncmp (condExpr, "make", 4) == 0) {
785		    /*
786		     * Use CondDoMake to evaluate the argument and
787		     * CondGetArg to extract the argument from the 'function
788		     * call'.
789		     */
790		    evalProc = CondDoMake;
791		    condExpr += 4;
792		    arglen = CondGetArg (&condExpr, &arg, "make", TRUE);
793		    if (arglen == 0) {
794			condExpr -= 4;
795			goto use_default;
796		    }
797		} else if (strncmp (condExpr, "exists", 6) == 0) {
798		    /*
799		     * Use CondDoExists to evaluate the argument and
800		     * CondGetArg to extract the argument from the
801		     * 'function call'.
802		     */
803		    evalProc = CondDoExists;
804		    condExpr += 6;
805		    arglen = CondGetArg(&condExpr, &arg, "exists", TRUE);
806		    if (arglen == 0) {
807			condExpr -= 6;
808			goto use_default;
809		    }
810		} else if (strncmp(condExpr, "empty", 5) == 0) {
811		    /*
812		     * Use Var_Parse to parse the spec in parens and return
813		     * True if the resulting string is empty.
814		     */
815		    int	    length;
816		    Boolean doFree;
817		    char    *val;
818
819		    condExpr += 5;
820
821		    for (arglen = 0;
822			 condExpr[arglen] != '(' && condExpr[arglen] != '\0';
823			 arglen += 1)
824			continue;
825
826		    if (condExpr[arglen] != '\0') {
827			val = Var_Parse(&condExpr[arglen - 1], VAR_CMD,
828					doEval, &length, &doFree);
829			if (val == var_Error) {
830			    t = Err;
831			} else {
832			    /*
833			     * A variable is empty when it just contains
834			     * spaces... 4/15/92, christos
835			     */
836			    char *p;
837			    for (p = val; *p && isspace((unsigned char)*p); p++)
838				continue;
839			    t = (*p == '\0') ? True : False;
840			}
841			if (doFree) {
842			    free(val);
843			}
844			/*
845			 * Advance condExpr to beyond the closing ). Note that
846			 * we subtract one from arglen + length b/c length
847			 * is calculated from condExpr[arglen - 1].
848			 */
849			condExpr += arglen + length - 1;
850		    } else {
851			condExpr -= 5;
852			goto use_default;
853		    }
854		    break;
855		} else if (strncmp (condExpr, "target", 6) == 0) {
856		    /*
857		     * Use CondDoTarget to evaluate the argument and
858		     * CondGetArg to extract the argument from the
859		     * 'function call'.
860		     */
861		    evalProc = CondDoTarget;
862		    condExpr += 6;
863		    arglen = CondGetArg(&condExpr, &arg, "target", TRUE);
864		    if (arglen == 0) {
865			condExpr -= 6;
866			goto use_default;
867		    }
868		} else {
869		    /*
870		     * The symbol is itself the argument to the default
871		     * function. We advance condExpr to the end of the symbol
872		     * by hand (the next whitespace, closing paren or
873		     * binary operator) and set to invert the evaluation
874		     * function if condInvert is TRUE.
875		     */
876		use_default:
877		    invert = condInvert;
878		    evalProc = condDefProc;
879		    arglen = CondGetArg(&condExpr, &arg, "", FALSE);
880		}
881
882		/*
883		 * Evaluate the argument using the set function. If invert
884		 * is TRUE, we invert the sense of the function.
885		 */
886		t = (!doEval || (* evalProc) (arglen, arg) ?
887		     (invert ? False : True) :
888		     (invert ? True : False));
889		free(arg);
890		break;
891	    }
892	}
893    } else {
894	t = condPushBack;
895	condPushBack = None;
896    }
897    return (t);
898}
899
900/*-
901 *-----------------------------------------------------------------------
902 * CondT --
903 *	Parse a single term in the expression. This consists of a terminal
904 *	symbol or Not and a terminal symbol (not including the binary
905 *	operators):
906 *	    T -> defined(variable) | make(target) | exists(file) | symbol
907 *	    T -> ! T | ( E )
908 *
909 * Results:
910 *	True, False or Err.
911 *
912 * Side Effects:
913 *	Tokens are consumed.
914 *
915 *-----------------------------------------------------------------------
916 */
917static Token
918CondT(doEval)
919    Boolean doEval;
920{
921    Token   t;
922
923    t = CondToken(doEval);
924
925    if (t == EndOfFile) {
926	/*
927	 * If we reached the end of the expression, the expression
928	 * is malformed...
929	 */
930	t = Err;
931    } else if (t == LParen) {
932	/*
933	 * T -> ( E )
934	 */
935	t = CondE(doEval);
936	if (t != Err) {
937	    if (CondToken(doEval) != RParen) {
938		t = Err;
939	    }
940	}
941    } else if (t == Not) {
942	t = CondT(doEval);
943	if (t == True) {
944	    t = False;
945	} else if (t == False) {
946	    t = True;
947	}
948    }
949    return (t);
950}
951
952/*-
953 *-----------------------------------------------------------------------
954 * CondF --
955 *	Parse a conjunctive factor (nice name, wot?)
956 *	    F -> T && F | T
957 *
958 * Results:
959 *	True, False or Err
960 *
961 * Side Effects:
962 *	Tokens are consumed.
963 *
964 *-----------------------------------------------------------------------
965 */
966static Token
967CondF(doEval)
968    Boolean doEval;
969{
970    Token   l, o;
971
972    l = CondT(doEval);
973    if (l != Err) {
974	o = CondToken(doEval);
975
976	if (o == And) {
977	    /*
978	     * F -> T && F
979	     *
980	     * If T is False, the whole thing will be False, but we have to
981	     * parse the r.h.s. anyway (to throw it away).
982	     * If T is True, the result is the r.h.s., be it an Err or no.
983	     */
984	    if (l == True) {
985		l = CondF(doEval);
986	    } else {
987		(void) CondF(FALSE);
988	    }
989	} else {
990	    /*
991	     * F -> T
992	     */
993	    CondPushBack (o);
994	}
995    }
996    return (l);
997}
998
999/*-
1000 *-----------------------------------------------------------------------
1001 * CondE --
1002 *	Main expression production.
1003 *	    E -> F || E | F
1004 *
1005 * Results:
1006 *	True, False or Err.
1007 *
1008 * Side Effects:
1009 *	Tokens are, of course, consumed.
1010 *
1011 *-----------------------------------------------------------------------
1012 */
1013static Token
1014CondE(doEval)
1015    Boolean doEval;
1016{
1017    Token   l, o;
1018
1019    l = CondF(doEval);
1020    if (l != Err) {
1021	o = CondToken(doEval);
1022
1023	if (o == Or) {
1024	    /*
1025	     * E -> F || E
1026	     *
1027	     * A similar thing occurs for ||, except that here we make sure
1028	     * the l.h.s. is False before we bother to evaluate the r.h.s.
1029	     * Once again, if l is False, the result is the r.h.s. and once
1030	     * again if l is True, we parse the r.h.s. to throw it away.
1031	     */
1032	    if (l == False) {
1033		l = CondE(doEval);
1034	    } else {
1035		(void) CondE(FALSE);
1036	    }
1037	} else {
1038	    /*
1039	     * E -> F
1040	     */
1041	    CondPushBack (o);
1042	}
1043    }
1044    return (l);
1045}
1046
1047/*-
1048 *-----------------------------------------------------------------------
1049 * Cond_Eval --
1050 *	Evaluate the conditional in the passed line. The line
1051 *	looks like this:
1052 *	    #<cond-type> <expr>
1053 *	where <cond-type> is any of if, ifmake, ifnmake, ifdef,
1054 *	ifndef, elif, elifmake, elifnmake, elifdef, elifndef
1055 *	and <expr> consists of &&, ||, !, make(target), defined(variable)
1056 *	and parenthetical groupings thereof.
1057 *
1058 * Results:
1059 *	COND_PARSE	if should parse lines after the conditional
1060 *	COND_SKIP	if should skip lines after the conditional
1061 *	COND_INVALID  	if not a valid conditional.
1062 *
1063 * Side Effects:
1064 *	None.
1065 *
1066 *-----------------------------------------------------------------------
1067 */
1068int
1069Cond_Eval (line)
1070    char    	    *line;    /* Line to parse */
1071{
1072    struct If	    *ifp;
1073    Boolean 	    isElse;
1074    Boolean 	    value = FALSE;
1075    int	    	    level;  	/* Level at which to report errors. */
1076
1077    level = PARSE_FATAL;
1078
1079    for (line++; *line == ' ' || *line == '\t'; line++) {
1080	continue;
1081    }
1082
1083    /*
1084     * Find what type of if we're dealing with. The result is left
1085     * in ifp and isElse is set TRUE if it's an elif line.
1086     */
1087    if (line[0] == 'e' && line[1] == 'l') {
1088	line += 2;
1089	isElse = TRUE;
1090    } else if (strncmp (line, "endif", 5) == 0) {
1091	/*
1092	 * End of a conditional section. If skipIfLevel is non-zero, that
1093	 * conditional was skipped, so lines following it should also be
1094	 * skipped. Hence, we return COND_SKIP. Otherwise, the conditional
1095	 * was read so succeeding lines should be parsed (think about it...)
1096	 * so we return COND_PARSE, unless this endif isn't paired with
1097	 * a decent if.
1098	 */
1099	if (skipIfLevel != 0) {
1100	    skipIfLevel -= 1;
1101	    return (COND_SKIP);
1102	} else {
1103	    if (condTop == MAXIF) {
1104		Parse_Error (level, "if-less endif");
1105		return (COND_INVALID);
1106	    } else {
1107		skipLine = FALSE;
1108		condTop += 1;
1109		return (COND_PARSE);
1110	    }
1111	}
1112    } else {
1113	isElse = FALSE;
1114    }
1115
1116    /*
1117     * Figure out what sort of conditional it is -- what its default
1118     * function is, etc. -- by looking in the table of valid "ifs"
1119     */
1120    for (ifp = ifs; ifp->form != (char *)0; ifp++) {
1121	if (strncmp (ifp->form, line, ifp->formlen) == 0) {
1122	    break;
1123	}
1124    }
1125
1126    if (ifp->form == (char *) 0) {
1127	/*
1128	 * Nothing fit. If the first word on the line is actually
1129	 * "else", it's a valid conditional whose value is the inverse
1130	 * of the previous if we parsed.
1131	 */
1132	if (isElse && (line[0] == 's') && (line[1] == 'e')) {
1133	    if (condTop == MAXIF) {
1134		Parse_Error (level, "if-less else");
1135		return (COND_INVALID);
1136	    } else if (skipIfLevel == 0) {
1137		value = !condStack[condTop];
1138	    } else {
1139		return (COND_SKIP);
1140	    }
1141	} else {
1142	    /*
1143	     * Not a valid conditional type. No error...
1144	     */
1145	    return (COND_INVALID);
1146	}
1147    } else {
1148	if (isElse) {
1149	    if (condTop == MAXIF) {
1150		Parse_Error (level, "if-less elif");
1151		return (COND_INVALID);
1152	    } else if (skipIfLevel != 0) {
1153		/*
1154		 * If skipping this conditional, just ignore the whole thing.
1155		 * If we don't, the user might be employing a variable that's
1156		 * undefined, for which there's an enclosing ifdef that
1157		 * we're skipping...
1158		 */
1159		return(COND_SKIP);
1160	    }
1161	} else if (skipLine) {
1162	    /*
1163	     * Don't even try to evaluate a conditional that's not an else if
1164	     * we're skipping things...
1165	     */
1166	    skipIfLevel += 1;
1167	    return(COND_SKIP);
1168	}
1169
1170	/*
1171	 * Initialize file-global variables for parsing
1172	 */
1173	condDefProc = ifp->defProc;
1174	condInvert = ifp->doNot;
1175
1176	line += ifp->formlen;
1177
1178	while (*line == ' ' || *line == '\t') {
1179	    line++;
1180	}
1181
1182	condExpr = line;
1183	condPushBack = None;
1184
1185	switch (CondE(TRUE)) {
1186	    case True:
1187		if (CondToken(TRUE) == EndOfFile) {
1188		    value = TRUE;
1189		    break;
1190		}
1191		goto err;
1192		/*FALLTHRU*/
1193	    case False:
1194		if (CondToken(TRUE) == EndOfFile) {
1195		    value = FALSE;
1196		    break;
1197		}
1198		/*FALLTHRU*/
1199	    case Err:
1200	    err:
1201		Parse_Error (level, "Malformed conditional (%s)",
1202			     line);
1203		return (COND_INVALID);
1204	    default:
1205		break;
1206	}
1207    }
1208    if (!isElse) {
1209	condTop -= 1;
1210    } else if ((skipIfLevel != 0) || condStack[condTop]) {
1211	/*
1212	 * If this is an else-type conditional, it should only take effect
1213	 * if its corresponding if was evaluated and FALSE. If its if was
1214	 * TRUE or skipped, we return COND_SKIP (and start skipping in case
1215	 * we weren't already), leaving the stack unmolested so later elif's
1216	 * don't screw up...
1217	 */
1218	skipLine = TRUE;
1219	return (COND_SKIP);
1220    }
1221
1222    if (condTop < 0) {
1223	/*
1224	 * This is the one case where we can definitely proclaim a fatal
1225	 * error. If we don't, we're hosed.
1226	 */
1227	Parse_Error (PARSE_FATAL, "Too many nested if's. %d max.", MAXIF);
1228	return (COND_INVALID);
1229    } else {
1230	condStack[condTop] = value;
1231	skipLine = !value;
1232	return (value ? COND_PARSE : COND_SKIP);
1233    }
1234}
1235
1236/*-
1237 *-----------------------------------------------------------------------
1238 * Cond_End --
1239 *	Make sure everything's clean at the end of a makefile.
1240 *
1241 * Results:
1242 *	None.
1243 *
1244 * Side Effects:
1245 *	Parse_Error will be called if open conditionals are around.
1246 *
1247 *-----------------------------------------------------------------------
1248 */
1249void
1250Cond_End()
1251{
1252    if (condTop != MAXIF) {
1253	Parse_Error(PARSE_FATAL, "%d open conditional%s", MAXIF-condTop,
1254		    MAXIF-condTop == 1 ? "" : "s");
1255    }
1256    condTop = MAXIF;
1257}
1258