Home | History | Annotate | Line # | Download | only in make
cond.c revision 1.46
      1 /*	$NetBSD: cond.c,v 1.46 2008/11/23 10:52:58 dsl Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
      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. Neither the name of the University nor the names of its contributors
     19  *    may be used to endorse or promote products derived from this software
     20  *    without specific prior written permission.
     21  *
     22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     32  * SUCH DAMAGE.
     33  */
     34 
     35 /*
     36  * Copyright (c) 1988, 1989 by Adam de Boor
     37  * Copyright (c) 1989 by Berkeley Softworks
     38  * All rights reserved.
     39  *
     40  * This code is derived from software contributed to Berkeley by
     41  * Adam de Boor.
     42  *
     43  * Redistribution and use in source and binary forms, with or without
     44  * modification, are permitted provided that the following conditions
     45  * are met:
     46  * 1. Redistributions of source code must retain the above copyright
     47  *    notice, this list of conditions and the following disclaimer.
     48  * 2. Redistributions in binary form must reproduce the above copyright
     49  *    notice, this list of conditions and the following disclaimer in the
     50  *    documentation and/or other materials provided with the distribution.
     51  * 3. All advertising materials mentioning features or use of this software
     52  *    must display the following acknowledgement:
     53  *	This product includes software developed by the University of
     54  *	California, Berkeley and its contributors.
     55  * 4. Neither the name of the University nor the names of its contributors
     56  *    may be used to endorse or promote products derived from this software
     57  *    without specific prior written permission.
     58  *
     59  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     60  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     61  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     62  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     63  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     64  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     65  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     66  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     67  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     68  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     69  * SUCH DAMAGE.
     70  */
     71 
     72 #ifndef MAKE_NATIVE
     73 static char rcsid[] = "$NetBSD: cond.c,v 1.46 2008/11/23 10:52:58 dsl Exp $";
     74 #else
     75 #include <sys/cdefs.h>
     76 #ifndef lint
     77 #if 0
     78 static char sccsid[] = "@(#)cond.c	8.2 (Berkeley) 1/2/94";
     79 #else
     80 __RCSID("$NetBSD: cond.c,v 1.46 2008/11/23 10:52:58 dsl Exp $");
     81 #endif
     82 #endif /* not lint */
     83 #endif
     84 
     85 /*-
     86  * cond.c --
     87  *	Functions to handle conditionals in a makefile.
     88  *
     89  * Interface:
     90  *	Cond_Eval 	Evaluate the conditional in the passed line.
     91  *
     92  */
     93 
     94 #include    <ctype.h>
     95 #include    <errno.h>    /* For strtoul() error checking */
     96 
     97 #include    "make.h"
     98 #include    "hash.h"
     99 #include    "dir.h"
    100 #include    "buf.h"
    101 
    102 /*
    103  * The parsing of conditional expressions is based on this grammar:
    104  *	E -> F || E
    105  *	E -> F
    106  *	F -> T && F
    107  *	F -> T
    108  *	T -> defined(variable)
    109  *	T -> make(target)
    110  *	T -> exists(file)
    111  *	T -> empty(varspec)
    112  *	T -> target(name)
    113  *	T -> commands(name)
    114  *	T -> symbol
    115  *	T -> $(varspec) op value
    116  *	T -> $(varspec) == "string"
    117  *	T -> $(varspec) != "string"
    118  *	T -> "string"
    119  *	T -> ( E )
    120  *	T -> ! T
    121  *	op -> == | != | > | < | >= | <=
    122  *
    123  * 'symbol' is some other symbol to which the default function (condDefProc)
    124  * is applied.
    125  *
    126  * Tokens are scanned from the 'condExpr' string. The scanner (CondToken)
    127  * will return And for '&' and '&&', Or for '|' and '||', Not for '!',
    128  * LParen for '(', RParen for ')' and will evaluate the other terminal
    129  * symbols, using either the default function or the function given in the
    130  * terminal, and return the result as either True or False.
    131  *
    132  * All Non-Terminal functions (CondE, CondF and CondT) return Err on error.
    133  */
    134 typedef enum {
    135     And, Or, Not, True, False, LParen, RParen, EndOfFile, None, Err
    136 } Token;
    137 
    138 /*-
    139  * Structures to handle elegantly the different forms of #if's. The
    140  * last two fields are stored in condInvert and condDefProc, respectively.
    141  */
    142 static void CondPushBack(Token);
    143 static int CondGetArg(char **, char **, const char *, Boolean);
    144 static Boolean CondDoDefined(int, char *);
    145 static int CondStrMatch(ClientData, ClientData);
    146 static Boolean CondDoMake(int, char *);
    147 static Boolean CondDoExists(int, char *);
    148 static Boolean CondDoTarget(int, char *);
    149 static Boolean CondDoCommands(int, char *);
    150 static Boolean CondCvtArg(char *, double *);
    151 static Token CondToken(Boolean);
    152 static Token CondT(Boolean);
    153 static Token CondF(Boolean);
    154 static Token CondE(Boolean);
    155 
    156 static const struct If {
    157     const char	*form;	      /* Form of if */
    158     int		formlen;      /* Length of form */
    159     Boolean	doNot;	      /* TRUE if default function should be negated */
    160     Boolean	(*defProc)(int, char *); /* Default function to apply */
    161 } ifs[] = {
    162     { "def",	  3,	  FALSE,  CondDoDefined },
    163     { "ndef",	  4,	  TRUE,	  CondDoDefined },
    164     { "make",	  4,	  FALSE,  CondDoMake },
    165     { "nmake",	  5,	  TRUE,	  CondDoMake },
    166     { "",	  0,	  FALSE,  CondDoDefined },
    167     { NULL,	  0,	  FALSE,  NULL }
    168 };
    169 
    170 static Boolean	  condInvert;	    	/* Invert the default function */
    171 static Boolean	  (*condDefProc)(int, char *);	/* Default function to apply */
    172 static char 	  *condExpr;	    	/* The expression to parse */
    173 static Token	  condPushBack=None;	/* Single push-back token used in
    174 					 * parsing */
    175 
    176 static unsigned int	cond_depth = 0;  	/* current .if nesting level */
    177 static unsigned int	cond_min_depth = 0;  	/* depth at makefile open */
    178 
    179 static int
    180 istoken(const char *str, const char *tok, size_t len)
    181 {
    182 	return strncmp(str, tok, len) == 0 && !isalpha((unsigned char)str[len]);
    183 }
    184 
    185 /*-
    186  *-----------------------------------------------------------------------
    187  * CondPushBack --
    188  *	Push back the most recent token read. We only need one level of
    189  *	this, so the thing is just stored in 'condPushback'.
    190  *
    191  * Input:
    192  *	t		Token to push back into the "stream"
    193  *
    194  * Results:
    195  *	None.
    196  *
    197  * Side Effects:
    198  *	condPushback is overwritten.
    199  *
    200  *-----------------------------------------------------------------------
    201  */
    202 static void
    203 CondPushBack(Token t)
    204 {
    205     condPushBack = t;
    206 }
    207 
    208 /*-
    210  *-----------------------------------------------------------------------
    211  * CondGetArg --
    212  *	Find the argument of a built-in function.
    213  *
    214  * Input:
    215  *	parens		TRUE if arg should be bounded by parens
    216  *
    217  * Results:
    218  *	The length of the argument and the address of the argument.
    219  *
    220  * Side Effects:
    221  *	The pointer is set to point to the closing parenthesis of the
    222  *	function call.
    223  *
    224  *-----------------------------------------------------------------------
    225  */
    226 static int
    227 CondGetArg(char **linePtr, char **argPtr, const char *func, Boolean parens)
    228 {
    229     char	  *cp;
    230     int	    	  argLen;
    231     Buffer	  buf;
    232 
    233     cp = *linePtr;
    234     if (parens) {
    235 	while (*cp != '(' && *cp != '\0') {
    236 	    cp++;
    237 	}
    238 	if (*cp == '(') {
    239 	    cp++;
    240 	}
    241     }
    242 
    243     if (*cp == '\0') {
    244 	/*
    245 	 * No arguments whatsoever. Because 'make' and 'defined' aren't really
    246 	 * "reserved words", we don't print a message. I think this is better
    247 	 * than hitting the user with a warning message every time s/he uses
    248 	 * the word 'make' or 'defined' at the beginning of a symbol...
    249 	 */
    250 	*argPtr = NULL;
    251 	return (0);
    252     }
    253 
    254     while (*cp == ' ' || *cp == '\t') {
    255 	cp++;
    256     }
    257 
    258     /*
    259      * Create a buffer for the argument and start it out at 16 characters
    260      * long. Why 16? Why not?
    261      */
    262     buf = Buf_Init(16);
    263 
    264     while ((strchr(" \t)&|", *cp) == NULL) && (*cp != '\0')) {
    265 	if (*cp == '$') {
    266 	    /*
    267 	     * Parse the variable spec and install it as part of the argument
    268 	     * if it's valid. We tell Var_Parse to complain on an undefined
    269 	     * variable, so we don't do it too. Nor do we return an error,
    270 	     * though perhaps we should...
    271 	     */
    272 	    char  	*cp2;
    273 	    int		len;
    274 	    void	*freeIt;
    275 
    276 	    cp2 = Var_Parse(cp, VAR_CMD, TRUE, &len, &freeIt);
    277 	    Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2);
    278 	    if (freeIt)
    279 		free(freeIt);
    280 	    cp += len;
    281 	} else {
    282 	    Buf_AddByte(buf, (Byte)*cp);
    283 	    cp++;
    284 	}
    285     }
    286 
    287     Buf_AddByte(buf, (Byte)'\0');
    288     *argPtr = (char *)Buf_GetAll(buf, &argLen);
    289     Buf_Destroy(buf, FALSE);
    290 
    291     while (*cp == ' ' || *cp == '\t') {
    292 	cp++;
    293     }
    294     if (parens && *cp != ')') {
    295 	Parse_Error(PARSE_WARNING, "Missing closing parenthesis for %s()",
    296 		     func);
    297 	return (0);
    298     } else if (parens) {
    299 	/*
    300 	 * Advance pointer past close parenthesis.
    301 	 */
    302 	cp++;
    303     }
    304 
    305     *linePtr = cp;
    306     return (argLen);
    307 }
    308 
    309 /*-
    311  *-----------------------------------------------------------------------
    312  * CondDoDefined --
    313  *	Handle the 'defined' function for conditionals.
    314  *
    315  * Results:
    316  *	TRUE if the given variable is defined.
    317  *
    318  * Side Effects:
    319  *	None.
    320  *
    321  *-----------------------------------------------------------------------
    322  */
    323 static Boolean
    324 CondDoDefined(int argLen, char *arg)
    325 {
    326     char    savec = arg[argLen];
    327     char    *p1;
    328     Boolean result;
    329 
    330     arg[argLen] = '\0';
    331     if (Var_Value(arg, VAR_CMD, &p1) != NULL) {
    332 	result = TRUE;
    333     } else {
    334 	result = FALSE;
    335     }
    336     if (p1)
    337 	free(p1);
    338     arg[argLen] = savec;
    339     return (result);
    340 }
    341 
    342 /*-
    344  *-----------------------------------------------------------------------
    345  * CondStrMatch --
    346  *	Front-end for Str_Match so it returns 0 on match and non-zero
    347  *	on mismatch. Callback function for CondDoMake via Lst_Find
    348  *
    349  * Results:
    350  *	0 if string matches pattern
    351  *
    352  * Side Effects:
    353  *	None
    354  *
    355  *-----------------------------------------------------------------------
    356  */
    357 static int
    358 CondStrMatch(ClientData string, ClientData pattern)
    359 {
    360     return(!Str_Match((char *)string,(char *)pattern));
    361 }
    362 
    363 /*-
    365  *-----------------------------------------------------------------------
    366  * CondDoMake --
    367  *	Handle the 'make' function for conditionals.
    368  *
    369  * Results:
    370  *	TRUE if the given target is being made.
    371  *
    372  * Side Effects:
    373  *	None.
    374  *
    375  *-----------------------------------------------------------------------
    376  */
    377 static Boolean
    378 CondDoMake(int argLen, char *arg)
    379 {
    380     char    savec = arg[argLen];
    381     Boolean result;
    382 
    383     arg[argLen] = '\0';
    384     if (Lst_Find(create, arg, CondStrMatch) == NILLNODE) {
    385 	result = FALSE;
    386     } else {
    387 	result = TRUE;
    388     }
    389     arg[argLen] = savec;
    390     return (result);
    391 }
    392 
    393 /*-
    395  *-----------------------------------------------------------------------
    396  * CondDoExists --
    397  *	See if the given file exists.
    398  *
    399  * Results:
    400  *	TRUE if the file exists and FALSE if it does not.
    401  *
    402  * Side Effects:
    403  *	None.
    404  *
    405  *-----------------------------------------------------------------------
    406  */
    407 static Boolean
    408 CondDoExists(int argLen, char *arg)
    409 {
    410     char    savec = arg[argLen];
    411     Boolean result;
    412     char    *path;
    413 
    414     arg[argLen] = '\0';
    415     path = Dir_FindFile(arg, dirSearchPath);
    416     if (path != NULL) {
    417 	result = TRUE;
    418 	free(path);
    419     } else {
    420 	result = FALSE;
    421     }
    422     arg[argLen] = savec;
    423     if (DEBUG(COND)) {
    424 	fprintf(debug_file, "exists(%s) result is \"%s\"\n",
    425 	       arg, path ? path : "");
    426     }
    427     return (result);
    428 }
    429 
    430 /*-
    432  *-----------------------------------------------------------------------
    433  * CondDoTarget --
    434  *	See if the given node exists and is an actual target.
    435  *
    436  * Results:
    437  *	TRUE if the node exists as a target and FALSE if it does not.
    438  *
    439  * Side Effects:
    440  *	None.
    441  *
    442  *-----------------------------------------------------------------------
    443  */
    444 static Boolean
    445 CondDoTarget(int argLen, char *arg)
    446 {
    447     char    savec = arg[argLen];
    448     Boolean result;
    449     GNode   *gn;
    450 
    451     arg[argLen] = '\0';
    452     gn = Targ_FindNode(arg, TARG_NOCREATE);
    453     if ((gn != NILGNODE) && !OP_NOP(gn->type)) {
    454 	result = TRUE;
    455     } else {
    456 	result = FALSE;
    457     }
    458     arg[argLen] = savec;
    459     return (result);
    460 }
    461 
    462 /*-
    463  *-----------------------------------------------------------------------
    464  * CondDoCommands --
    465  *	See if the given node exists and is an actual target with commands
    466  *	associated with it.
    467  *
    468  * Results:
    469  *	TRUE if the node exists as a target and has commands associated with
    470  *	it and FALSE if it does not.
    471  *
    472  * Side Effects:
    473  *	None.
    474  *
    475  *-----------------------------------------------------------------------
    476  */
    477 static Boolean
    478 CondDoCommands(int argLen, char *arg)
    479 {
    480     char    savec = arg[argLen];
    481     Boolean result;
    482     GNode   *gn;
    483 
    484     arg[argLen] = '\0';
    485     gn = Targ_FindNode(arg, TARG_NOCREATE);
    486     if ((gn != NILGNODE) && !OP_NOP(gn->type) && !Lst_IsEmpty(gn->commands)) {
    487 	result = TRUE;
    488     } else {
    489 	result = FALSE;
    490     }
    491     arg[argLen] = savec;
    492     return (result);
    493 }
    494 
    495 /*-
    497  *-----------------------------------------------------------------------
    498  * CondCvtArg --
    499  *	Convert the given number into a double.
    500  *	We try a base 10 or 16 integer conversion first, if that fails
    501  *	then we try a floating point conversion instead.
    502  *
    503  * Results:
    504  *	Sets 'value' to double value of string.
    505  *	Returns 'true' if the convertion suceeded
    506  *
    507  *-----------------------------------------------------------------------
    508  */
    509 static Boolean
    510 CondCvtArg(char *str, double *value)
    511 {
    512     char *eptr, ech;
    513     unsigned long l_val;
    514     double d_val;
    515 
    516     errno = 0;
    517     l_val = strtoul(str, &eptr, str[1] == 'x' ? 16 : 10);
    518     ech = *eptr;
    519     if (ech == 0 && errno != ERANGE) {
    520 	d_val = str[0] == '-' ? -(double)-l_val : (double)l_val;
    521     } else {
    522 	if (ech != 0 && ech != '.' && ech != 'e' && ech != 'E')
    523 	    return FALSE;
    524 	d_val = strtod(str, &eptr);
    525 	if (*eptr)
    526 	    return FALSE;
    527     }
    528 
    529     *value = d_val;
    530     return TRUE;
    531 }
    532 
    533 /*-
    534  *-----------------------------------------------------------------------
    535  * CondGetString --
    536  *	Get a string from a variable reference or an optionally quoted
    537  *	string.  This is called for the lhs and rhs of string compares.
    538  *
    539  * Results:
    540  *	Sets freeIt if needed,
    541  *	Sets quoted if string was quoted,
    542  *	Returns NULL on error,
    543  *	else returns string - absent any quotes.
    544  *
    545  * Side Effects:
    546  *	Moves condExpr to end of this token.
    547  *
    548  *
    549  *-----------------------------------------------------------------------
    550  */
    551 /* coverity:[+alloc : arg-*2] */
    552 static char *
    553 CondGetString(Boolean doEval, Boolean *quoted, void **freeIt)
    554 {
    555     Buffer buf;
    556     char *cp;
    557     char *str;
    558     int	len;
    559     int qt;
    560     char *start;
    561 
    562     buf = Buf_Init(0);
    563     str = NULL;
    564     *freeIt = NULL;
    565     *quoted = qt = *condExpr == '"' ? 1 : 0;
    566     if (qt)
    567 	condExpr++;
    568     for (start = condExpr; *condExpr && str == NULL; condExpr++) {
    569 	switch (*condExpr) {
    570 	case '\\':
    571 	    if (condExpr[1] != '\0') {
    572 		condExpr++;
    573 		Buf_AddByte(buf, (Byte)*condExpr);
    574 	    }
    575 	    break;
    576 	case '"':
    577 	    if (qt) {
    578 		condExpr++;		/* we don't want the quotes */
    579 		goto got_str;
    580 	    } else
    581 		Buf_AddByte(buf, (Byte)*condExpr); /* likely? */
    582 	    break;
    583 	case ')':
    584 	case '!':
    585 	case '=':
    586 	case '>':
    587 	case '<':
    588 	case ' ':
    589 	case '\t':
    590 	    if (!qt)
    591 		goto got_str;
    592 	    else
    593 		Buf_AddByte(buf, (Byte)*condExpr);
    594 	    break;
    595 	case '$':
    596 	    /* if we are in quotes, then an undefined variable is ok */
    597 	    str = Var_Parse(condExpr, VAR_CMD, (qt ? 0 : doEval),
    598 			    &len, freeIt);
    599 	    if (str == var_Error) {
    600 		if (*freeIt) {
    601 		    free(*freeIt);
    602 		    *freeIt = NULL;
    603 		}
    604 		/*
    605 		 * Even if !doEval, we still report syntax errors, which
    606 		 * is what getting var_Error back with !doEval means.
    607 		 */
    608 		str = NULL;
    609 		goto cleanup;
    610 	    }
    611 	    condExpr += len;
    612 	    /*
    613 	     * If the '$' was first char (no quotes), and we are
    614 	     * followed by space, the operator or end of expression,
    615 	     * we are done.
    616 	     */
    617 	    if ((condExpr == start + len) &&
    618 		(*condExpr == '\0' ||
    619 		 isspace((unsigned char) *condExpr) ||
    620 		 strchr("!=><)", *condExpr))) {
    621 		goto cleanup;
    622 	    }
    623 	    /*
    624 	     * Nope, we better copy str to buf
    625 	     */
    626 	    for (cp = str; *cp; cp++) {
    627 		Buf_AddByte(buf, (Byte)*cp);
    628 	    }
    629 	    if (*freeIt) {
    630 		free(*freeIt);
    631 		*freeIt = NULL;
    632 	    }
    633 	    str = NULL;			/* not finished yet */
    634 	    condExpr--;			/* don't skip over next char */
    635 	    break;
    636 	default:
    637 	    Buf_AddByte(buf, (Byte)*condExpr);
    638 	    break;
    639 	}
    640     }
    641  got_str:
    642     Buf_AddByte(buf, (Byte)'\0');
    643     str = (char *)Buf_GetAll(buf, NULL);
    644     *freeIt = str;
    645  cleanup:
    646     Buf_Destroy(buf, FALSE);
    647     return str;
    648 }
    649 
    650 /*-
    652  *-----------------------------------------------------------------------
    653  * CondToken --
    654  *	Return the next token from the input.
    655  *
    656  * Results:
    657  *	A Token for the next lexical token in the stream.
    658  *
    659  * Side Effects:
    660  *	condPushback will be set back to None if it is used.
    661  *
    662  *-----------------------------------------------------------------------
    663  */
    664 static Token
    665 compare_expression(Boolean doEval)
    666 {
    667     Token	t;
    668     char	*lhs;
    669     char	*rhs;
    670     char	*op;
    671     void	*lhsFree;
    672     void	*rhsFree;
    673     Boolean lhsQuoted;
    674     Boolean rhsQuoted;
    675 
    676     rhs = NULL;
    677     lhsFree = rhsFree = FALSE;
    678     lhsQuoted = rhsQuoted = FALSE;
    679 
    680     /*
    681      * Parse the variable spec and skip over it, saving its
    682      * value in lhs.
    683      */
    684     t = Err;
    685     lhs = CondGetString(doEval, &lhsQuoted, &lhsFree);
    686     if (!lhs) {
    687 	if (lhsFree)
    688 	    free(lhsFree);
    689 	return Err;
    690     }
    691     /*
    692      * Skip whitespace to get to the operator
    693      */
    694     while (isspace((unsigned char) *condExpr))
    695 	condExpr++;
    696 
    697     /*
    698      * Make sure the operator is a valid one. If it isn't a
    699      * known relational operator, pretend we got a
    700      * != 0 comparison.
    701      */
    702     op = condExpr;
    703     switch (*condExpr) {
    704 	case '!':
    705 	case '=':
    706 	case '<':
    707 	case '>':
    708 	    if (condExpr[1] == '=') {
    709 		condExpr += 2;
    710 	    } else {
    711 		condExpr += 1;
    712 	    }
    713 	    break;
    714 	default:
    715 	    op = UNCONST("!=");
    716 	    if (lhsQuoted)
    717 		rhs = UNCONST("");
    718 	    else
    719 		rhs = UNCONST("0");
    720 
    721 	    goto do_compare;
    722     }
    723     while (isspace((unsigned char) *condExpr)) {
    724 	condExpr++;
    725     }
    726     if (*condExpr == '\0') {
    727 	Parse_Error(PARSE_WARNING,
    728 		    "Missing right-hand-side of operator");
    729 	goto error;
    730     }
    731     rhs = CondGetString(doEval, &rhsQuoted, &rhsFree);
    732     if (!rhs) {
    733 	if (lhsFree)
    734 	    free(lhsFree);
    735 	if (rhsFree)
    736 	    free(rhsFree);
    737 	return Err;
    738     }
    739 do_compare:
    740     if (rhsQuoted || lhsQuoted) {
    741 do_string_compare:
    742 	if (((*op != '!') && (*op != '=')) || (op[1] != '=')) {
    743 	    Parse_Error(PARSE_WARNING,
    744     "String comparison operator should be either == or !=");
    745 	    goto error;
    746 	}
    747 
    748 	if (DEBUG(COND)) {
    749 	    fprintf(debug_file, "lhs = \"%s\", rhs = \"%s\", op = %.2s\n",
    750 		   lhs, rhs, op);
    751 	}
    752 	/*
    753 	 * Null-terminate rhs and perform the comparison.
    754 	 * t is set to the result.
    755 	 */
    756 	if (*op == '=') {
    757 	    t = strcmp(lhs, rhs) ? False : True;
    758 	} else {
    759 	    t = strcmp(lhs, rhs) ? True : False;
    760 	}
    761     } else {
    762 	/*
    763 	 * rhs is either a float or an integer. Convert both the
    764 	 * lhs and the rhs to a double and compare the two.
    765 	 */
    766 	double  	left, right;
    767 
    768 	if (!CondCvtArg(lhs, &left) || !CondCvtArg(rhs, &right))
    769 	    goto do_string_compare;
    770 
    771 	if (DEBUG(COND)) {
    772 	    fprintf(debug_file, "left = %f, right = %f, op = %.2s\n", left,
    773 		   right, op);
    774 	}
    775 	switch(op[0]) {
    776 	case '!':
    777 	    if (op[1] != '=') {
    778 		Parse_Error(PARSE_WARNING,
    779 			    "Unknown operator");
    780 		goto error;
    781 	    }
    782 	    t = (left != right ? True : False);
    783 	    break;
    784 	case '=':
    785 	    if (op[1] != '=') {
    786 		Parse_Error(PARSE_WARNING,
    787 			    "Unknown operator");
    788 		goto error;
    789 	    }
    790 	    t = (left == right ? True : False);
    791 	    break;
    792 	case '<':
    793 	    if (op[1] == '=') {
    794 		t = (left <= right ? True : False);
    795 	    } else {
    796 		t = (left < right ? True : False);
    797 	    }
    798 	    break;
    799 	case '>':
    800 	    if (op[1] == '=') {
    801 		t = (left >= right ? True : False);
    802 	    } else {
    803 		t = (left > right ? True : False);
    804 	    }
    805 	    break;
    806 	}
    807     }
    808 error:
    809     if (lhsFree)
    810 	free(lhsFree);
    811     if (rhsFree)
    812 	free(rhsFree);
    813     return t;
    814 }
    815 
    816 static Token
    817 compare_function(Boolean doEval)
    818 {
    819     Token	t;
    820     Boolean (*evalProc)(int, char *);
    821     Boolean invert = FALSE;
    822     char	*arg = NULL;
    823     int	arglen = 0;
    824 
    825     if (istoken(condExpr, "defined", 7)) {
    826 	/*
    827 	 * Use CondDoDefined to evaluate the argument and
    828 	 * CondGetArg to extract the argument from the 'function
    829 	 * call'.
    830 	 */
    831 	evalProc = CondDoDefined;
    832 	condExpr += 7;
    833 	arglen = CondGetArg(&condExpr, &arg, "defined", TRUE);
    834 	if (arglen == 0) {
    835 	    condExpr -= 7;
    836 	    goto use_default;
    837 	}
    838     } else if (istoken(condExpr, "make", 4)) {
    839 	/*
    840 	 * Use CondDoMake to evaluate the argument and
    841 	 * CondGetArg to extract the argument from the 'function
    842 	 * call'.
    843 	 */
    844 	evalProc = CondDoMake;
    845 	condExpr += 4;
    846 	arglen = CondGetArg(&condExpr, &arg, "make", TRUE);
    847 	if (arglen == 0) {
    848 	    condExpr -= 4;
    849 	    goto use_default;
    850 	}
    851     } else if (istoken(condExpr, "exists", 6)) {
    852 	/*
    853 	 * Use CondDoExists to evaluate the argument and
    854 	 * CondGetArg to extract the argument from the
    855 	 * 'function call'.
    856 	 */
    857 	evalProc = CondDoExists;
    858 	condExpr += 6;
    859 	arglen = CondGetArg(&condExpr, &arg, "exists", TRUE);
    860 	if (arglen == 0) {
    861 	    condExpr -= 6;
    862 	    goto use_default;
    863 	}
    864     } else if (istoken(condExpr, "empty", 5)) {
    865 	/*
    866 	 * Use Var_Parse to parse the spec in parens and return
    867 	 * True if the resulting string is empty.
    868 	 */
    869 	int	    did_warn, length;
    870 	void    *freeIt;
    871 	char    *val;
    872 
    873 	condExpr += 5;
    874 
    875 	did_warn = 0;
    876 	for (arglen = 0; condExpr[arglen] != '\0'; arglen += 1) {
    877 	    if (condExpr[arglen] == '(')
    878 		break;
    879 	    if (!isspace((unsigned char)condExpr[arglen]) &&
    880 		!did_warn) {
    881 
    882 		Parse_Error(PARSE_WARNING,
    883 		    "Extra characters after \"empty\"");
    884 		did_warn = 1;
    885 	    }
    886 	}
    887 
    888 	if (condExpr[arglen] != '\0') {
    889 	    val = Var_Parse(&condExpr[arglen - 1], VAR_CMD,
    890 			    FALSE, &length, &freeIt);
    891 	    if (val == var_Error) {
    892 		t = Err;
    893 	    } else {
    894 		/*
    895 		 * A variable is empty when it just contains
    896 		 * spaces... 4/15/92, christos
    897 		 */
    898 		char *p;
    899 		for (p = val; *p && isspace((unsigned char)*p); p++)
    900 		    continue;
    901 		t = (*p == '\0') ? True : False;
    902 	    }
    903 	    if (freeIt) {
    904 		free(freeIt);
    905 	    }
    906 	    /*
    907 	     * Advance condExpr to beyond the closing ). Note that
    908 	     * we subtract one from arglen + length b/c length
    909 	     * is calculated from condExpr[arglen - 1].
    910 	     */
    911 	    condExpr += arglen + length - 1;
    912 	} else {
    913 	    condExpr -= 5;
    914 	    goto use_default;
    915 	}
    916 	return t;
    917     } else if (istoken(condExpr, "target", 6)) {
    918 	/*
    919 	 * Use CondDoTarget to evaluate the argument and
    920 	 * CondGetArg to extract the argument from the
    921 	 * 'function call'.
    922 	 */
    923 	evalProc = CondDoTarget;
    924 	condExpr += 6;
    925 	arglen = CondGetArg(&condExpr, &arg, "target", TRUE);
    926 	if (arglen == 0) {
    927 	    condExpr -= 6;
    928 	    goto use_default;
    929 	}
    930     } else if (istoken(condExpr, "commands", 8)) {
    931 	/*
    932 	 * Use CondDoCommands to evaluate the argument and
    933 	 * CondGetArg to extract the argument from the
    934 	 * 'function call'.
    935 	 */
    936 	evalProc = CondDoCommands;
    937 	condExpr += 8;
    938 	arglen = CondGetArg(&condExpr, &arg, "commands", TRUE);
    939 	if (arglen == 0) {
    940 	    condExpr -= 8;
    941 	    goto use_default;
    942 	}
    943     } else {
    944 	/*
    945 	 * The symbol is itself the argument to the default
    946 	 * function. We advance condExpr to the end of the symbol
    947 	 * by hand (the next whitespace, closing paren or
    948 	 * binary operator) and set to invert the evaluation
    949 	 * function if condInvert is TRUE.
    950 	 */
    951 	if (isdigit((unsigned char)condExpr[0]) || strchr("+-", condExpr[0])) {
    952 	    /*
    953 	     * Variables may already be substituted
    954 	     * by the time we get here.
    955 	     */
    956 	    return compare_expression(doEval);
    957 	}
    958     use_default:
    959 	invert = condInvert;
    960 	evalProc = condDefProc;
    961 	arglen = CondGetArg(&condExpr, &arg, "", FALSE);
    962     }
    963 
    964     /*
    965      * Evaluate the argument using the set function. If invert
    966      * is TRUE, we invert the sense of the function.
    967      */
    968     t = (!doEval || (* evalProc) (arglen, arg) ?
    969 	 (invert ? False : True) :
    970 	 (invert ? True : False));
    971     if (arg)
    972 	free(arg);
    973     return t;
    974 }
    975 
    976 static Token
    977 CondToken(Boolean doEval)
    978 {
    979     Token	  t;
    980 
    981     if (condPushBack == None) {
    982 	while (*condExpr == ' ' || *condExpr == '\t') {
    983 	    condExpr++;
    984 	}
    985 	switch (*condExpr) {
    986 	    case '(':
    987 		t = LParen;
    988 		condExpr++;
    989 		break;
    990 	    case ')':
    991 		t = RParen;
    992 		condExpr++;
    993 		break;
    994 	    case '|':
    995 		if (condExpr[1] == '|') {
    996 		    condExpr++;
    997 		}
    998 		condExpr++;
    999 		t = Or;
   1000 		break;
   1001 	    case '&':
   1002 		if (condExpr[1] == '&') {
   1003 		    condExpr++;
   1004 		}
   1005 		condExpr++;
   1006 		t = And;
   1007 		break;
   1008 	    case '!':
   1009 		t = Not;
   1010 		condExpr++;
   1011 		break;
   1012 	    case '#':
   1013 	    case '\n':
   1014 	    case '\0':
   1015 		t = EndOfFile;
   1016 		break;
   1017 	    case '"':
   1018 	    case '$':
   1019 		return compare_expression(doEval);
   1020 
   1021 	    default:
   1022 		return compare_function(doEval);
   1023 
   1024 	}
   1025     } else {
   1026 	t = condPushBack;
   1027 	condPushBack = None;
   1028     }
   1029     return (t);
   1030 }
   1031 
   1032 /*-
   1034  *-----------------------------------------------------------------------
   1035  * CondT --
   1036  *	Parse a single term in the expression. This consists of a terminal
   1037  *	symbol or Not and a terminal symbol (not including the binary
   1038  *	operators):
   1039  *	    T -> defined(variable) | make(target) | exists(file) | symbol
   1040  *	    T -> ! T | ( E )
   1041  *
   1042  * Results:
   1043  *	True, False or Err.
   1044  *
   1045  * Side Effects:
   1046  *	Tokens are consumed.
   1047  *
   1048  *-----------------------------------------------------------------------
   1049  */
   1050 static Token
   1051 CondT(Boolean doEval)
   1052 {
   1053     Token   t;
   1054 
   1055     t = CondToken(doEval);
   1056 
   1057     if (t == EndOfFile) {
   1058 	/*
   1059 	 * If we reached the end of the expression, the expression
   1060 	 * is malformed...
   1061 	 */
   1062 	t = Err;
   1063     } else if (t == LParen) {
   1064 	/*
   1065 	 * T -> ( E )
   1066 	 */
   1067 	t = CondE(doEval);
   1068 	if (t != Err) {
   1069 	    if (CondToken(doEval) != RParen) {
   1070 		t = Err;
   1071 	    }
   1072 	}
   1073     } else if (t == Not) {
   1074 	t = CondT(doEval);
   1075 	if (t == True) {
   1076 	    t = False;
   1077 	} else if (t == False) {
   1078 	    t = True;
   1079 	}
   1080     }
   1081     return (t);
   1082 }
   1083 
   1084 /*-
   1086  *-----------------------------------------------------------------------
   1087  * CondF --
   1088  *	Parse a conjunctive factor (nice name, wot?)
   1089  *	    F -> T && F | T
   1090  *
   1091  * Results:
   1092  *	True, False or Err
   1093  *
   1094  * Side Effects:
   1095  *	Tokens are consumed.
   1096  *
   1097  *-----------------------------------------------------------------------
   1098  */
   1099 static Token
   1100 CondF(Boolean doEval)
   1101 {
   1102     Token   l, o;
   1103 
   1104     l = CondT(doEval);
   1105     if (l != Err) {
   1106 	o = CondToken(doEval);
   1107 
   1108 	if (o == And) {
   1109 	    /*
   1110 	     * F -> T && F
   1111 	     *
   1112 	     * If T is False, the whole thing will be False, but we have to
   1113 	     * parse the r.h.s. anyway (to throw it away).
   1114 	     * If T is True, the result is the r.h.s., be it an Err or no.
   1115 	     */
   1116 	    if (l == True) {
   1117 		l = CondF(doEval);
   1118 	    } else {
   1119 		(void)CondF(FALSE);
   1120 	    }
   1121 	} else {
   1122 	    /*
   1123 	     * F -> T
   1124 	     */
   1125 	    CondPushBack(o);
   1126 	}
   1127     }
   1128     return (l);
   1129 }
   1130 
   1131 /*-
   1133  *-----------------------------------------------------------------------
   1134  * CondE --
   1135  *	Main expression production.
   1136  *	    E -> F || E | F
   1137  *
   1138  * Results:
   1139  *	True, False or Err.
   1140  *
   1141  * Side Effects:
   1142  *	Tokens are, of course, consumed.
   1143  *
   1144  *-----------------------------------------------------------------------
   1145  */
   1146 static Token
   1147 CondE(Boolean doEval)
   1148 {
   1149     Token   l, o;
   1150 
   1151     l = CondF(doEval);
   1152     if (l != Err) {
   1153 	o = CondToken(doEval);
   1154 
   1155 	if (o == Or) {
   1156 	    /*
   1157 	     * E -> F || E
   1158 	     *
   1159 	     * A similar thing occurs for ||, except that here we make sure
   1160 	     * the l.h.s. is False before we bother to evaluate the r.h.s.
   1161 	     * Once again, if l is False, the result is the r.h.s. and once
   1162 	     * again if l is True, we parse the r.h.s. to throw it away.
   1163 	     */
   1164 	    if (l == False) {
   1165 		l = CondE(doEval);
   1166 	    } else {
   1167 		(void)CondE(FALSE);
   1168 	    }
   1169 	} else {
   1170 	    /*
   1171 	     * E -> F
   1172 	     */
   1173 	    CondPushBack(o);
   1174 	}
   1175     }
   1176     return (l);
   1177 }
   1178 
   1179 /*-
   1180  *-----------------------------------------------------------------------
   1181  * Cond_EvalExpression --
   1182  *	Evaluate an expression in the passed line. The expression
   1183  *	consists of &&, ||, !, make(target), defined(variable)
   1184  *	and parenthetical groupings thereof.
   1185  *
   1186  * Results:
   1187  *	COND_PARSE	if the condition was valid grammatically
   1188  *	COND_INVALID  	if not a valid conditional.
   1189  *
   1190  *	(*value) is set to the boolean value of the condition
   1191  *
   1192  * Side Effects:
   1193  *	None.
   1194  *
   1195  *-----------------------------------------------------------------------
   1196  */
   1197 int
   1198 Cond_EvalExpression(int dosetup, char *line, Boolean *value, int eprint)
   1199 {
   1200     if (dosetup) {
   1201 	condDefProc = CondDoDefined;
   1202 	condInvert = 0;
   1203     }
   1204 
   1205     while (*line == ' ' || *line == '\t')
   1206 	line++;
   1207 
   1208     condExpr = line;
   1209     condPushBack = None;
   1210 
   1211     switch (CondE(TRUE)) {
   1212     case True:
   1213 	if (CondToken(TRUE) == EndOfFile) {
   1214 	    *value = TRUE;
   1215 	    break;
   1216 	}
   1217 	goto err;
   1218 	/*FALLTHRU*/
   1219     case False:
   1220 	if (CondToken(TRUE) == EndOfFile) {
   1221 	    *value = FALSE;
   1222 	    break;
   1223 	}
   1224 	/*FALLTHRU*/
   1225     case Err:
   1226 err:
   1227 	if (eprint)
   1228 	    Parse_Error(PARSE_FATAL, "Malformed conditional (%s)",
   1229 			 line);
   1230 	return (COND_INVALID);
   1231     default:
   1232 	break;
   1233     }
   1234 
   1235     return COND_PARSE;
   1236 }
   1237 
   1238 
   1239 /*-
   1241  *-----------------------------------------------------------------------
   1242  * Cond_Eval --
   1243  *	Evaluate the conditional in the passed line. The line
   1244  *	looks like this:
   1245  *	    .<cond-type> <expr>
   1246  *	where <cond-type> is any of if, ifmake, ifnmake, ifdef,
   1247  *	ifndef, elif, elifmake, elifnmake, elifdef, elifndef
   1248  *	and <expr> consists of &&, ||, !, make(target), defined(variable)
   1249  *	and parenthetical groupings thereof.
   1250  *
   1251  * Input:
   1252  *	line		Line to parse
   1253  *
   1254  * Results:
   1255  *	COND_PARSE	if should parse lines after the conditional
   1256  *	COND_SKIP	if should skip lines after the conditional
   1257  *	COND_INVALID  	if not a valid conditional.
   1258  *
   1259  * Side Effects:
   1260  *	None.
   1261  *
   1262  * Note that the states IF_ACTIVE and ELSE_ACTIVE are only different in order
   1263  * to detect splurious .else lines (as are SKIP_TO_ELSE and SKIP_TO_ENDIF)
   1264  * otherwise .else could be treated as '.elif 1'.
   1265  *
   1266  *-----------------------------------------------------------------------
   1267  */
   1268 int
   1269 Cond_Eval(char *line)
   1270 {
   1271     #define	    MAXIF	64	/* maximum depth of .if'ing */
   1272     enum if_states {
   1273 	IF_ACTIVE,		/* .if or .elif part active */
   1274 	ELSE_ACTIVE,		/* .else part active */
   1275 	SEARCH_FOR_ELIF,	/* searching for .elif/else to execute */
   1276 	SKIP_TO_ELSE,           /* has been true, but not seen '.else' */
   1277 	SKIP_TO_ENDIF		/* nothing else to execute */
   1278     };
   1279     static enum if_states cond_state[MAXIF + 1] = { IF_ACTIVE };
   1280 
   1281     const struct If *ifp;
   1282     Boolean 	    isElif;
   1283     Boolean 	    value;
   1284     int	    	    level;  	/* Level at which to report errors. */
   1285     enum if_states  state;
   1286 
   1287     level = PARSE_FATAL;
   1288 
   1289     /* skip leading character (the '.') and any whitespace */
   1290     for (line++; *line == ' ' || *line == '\t'; line++)
   1291 	continue;
   1292 
   1293     /* Find what type of if we're dealing with.  */
   1294     if (line[0] == 'e') {
   1295 	if (line[1] != 'l') {
   1296 	    if (!istoken(line + 1, "ndif", 4))
   1297 		return COND_INVALID;
   1298 	    /* End of conditional section */
   1299 	    if (cond_depth == cond_min_depth) {
   1300 		Parse_Error(level, "if-less endif");
   1301 		return COND_PARSE;
   1302 	    }
   1303 	    /* Return state for previous conditional */
   1304 	    cond_depth--;
   1305 	    if (cond_depth > MAXIF)
   1306 		return COND_SKIP;
   1307 	    return cond_state[cond_depth] <= ELSE_ACTIVE ? COND_PARSE : COND_SKIP;
   1308 	}
   1309 
   1310 	/* Quite likely this is 'else' or 'elif' */
   1311 	line += 2;
   1312 	if (istoken(line, "se", 2)) {
   1313 	    /* It is else... */
   1314 	    if (cond_depth == cond_min_depth) {
   1315 		Parse_Error(level, "if-less else");
   1316 		return COND_PARSE;
   1317 	    }
   1318 
   1319 	    if (cond_depth > MAXIF)
   1320 		return COND_SKIP;
   1321 	    state = cond_state[cond_depth];
   1322 	    switch (state) {
   1323 	    case SEARCH_FOR_ELIF:
   1324 		state = ELSE_ACTIVE;
   1325 		break;
   1326 	    case ELSE_ACTIVE:
   1327 	    case SKIP_TO_ENDIF:
   1328 		Parse_Error(PARSE_WARNING, "extra else");
   1329 		/* FALLTHROUGH */
   1330 	    default:
   1331 	    case IF_ACTIVE:
   1332 	    case SKIP_TO_ELSE:
   1333 		state = SKIP_TO_ENDIF;
   1334 		break;
   1335 	    }
   1336 	    cond_state[cond_depth] = state;
   1337 	    return state <= ELSE_ACTIVE ? COND_PARSE : COND_SKIP;
   1338 	}
   1339 	/* Assume for now it is an elif */
   1340 	isElif = TRUE;
   1341     } else
   1342 	isElif = FALSE;
   1343 
   1344     if (line[0] != 'i' || line[1] != 'f')
   1345 	/* Not an ifxxx or elifxxx line */
   1346 	return COND_INVALID;
   1347 
   1348     /*
   1349      * Figure out what sort of conditional it is -- what its default
   1350      * function is, etc. -- by looking in the table of valid "ifs"
   1351      */
   1352     line += 2;
   1353     for (ifp = ifs; ; ifp++) {
   1354 	if (ifp->form == NULL)
   1355 	    return COND_INVALID;
   1356 	if (istoken(ifp->form, line, ifp->formlen)) {
   1357 	    line += ifp->formlen;
   1358 	    break;
   1359 	}
   1360     }
   1361 
   1362     /* Now we know what sort of 'if' it is... */
   1363 
   1364     if (isElif) {
   1365 	if (cond_depth == cond_min_depth) {
   1366 	    Parse_Error(level, "if-less elif");
   1367 	    return COND_PARSE;
   1368 	}
   1369 	if (cond_depth > MAXIF)
   1370 	    /* Error reported when we saw the .if ... */
   1371 	    return COND_SKIP;
   1372 	state = cond_state[cond_depth];
   1373 	if (state == SKIP_TO_ENDIF || state == ELSE_ACTIVE) {
   1374 	    Parse_Error(PARSE_WARNING, "extra elif");
   1375 	    cond_state[cond_depth] = SKIP_TO_ENDIF;
   1376 	    return COND_SKIP;
   1377 	}
   1378 	if (state != SEARCH_FOR_ELIF) {
   1379 	    /* Either just finished the 'true' block, or already SKIP_TO_ELSE */
   1380 	    cond_state[cond_depth] = SKIP_TO_ELSE;
   1381 	    return COND_SKIP;
   1382 	}
   1383     } else {
   1384 	/* Normal .if */
   1385 	if (cond_depth >= MAXIF) {
   1386 	    cond_depth++;
   1387 	    Parse_Error(PARSE_FATAL, "Too many nested if's. %d max.", MAXIF);
   1388 	    return COND_SKIP;
   1389 	}
   1390 	state = cond_state[cond_depth];
   1391 	cond_depth++;
   1392 	if (state > ELSE_ACTIVE) {
   1393 	    /* If we aren't parsing the data, treat as always false */
   1394 	    cond_state[cond_depth] = SKIP_TO_ELSE;
   1395 	    return COND_SKIP;
   1396 	}
   1397     }
   1398 
   1399     /* Initialize file-global variables for parsing the expression */
   1400     condDefProc = ifp->defProc;
   1401     condInvert = ifp->doNot;
   1402 
   1403     /* And evaluate the conditional expresssion */
   1404     if (Cond_EvalExpression(0, line, &value, 1) == COND_INVALID) {
   1405 	/* Syntax error in conditional, error message already output. */
   1406 	/* Skip everything to matching .endif */
   1407 	cond_state[cond_depth] = SKIP_TO_ELSE;
   1408 	return COND_SKIP;
   1409     }
   1410 
   1411     if (!value) {
   1412 	cond_state[cond_depth] = SEARCH_FOR_ELIF;
   1413 	return COND_SKIP;
   1414     }
   1415     cond_state[cond_depth] = IF_ACTIVE;
   1416     return COND_PARSE;
   1417 }
   1418 
   1419 
   1420 
   1421 /*-
   1423  *-----------------------------------------------------------------------
   1424  * Cond_End --
   1425  *	Make sure everything's clean at the end of a makefile.
   1426  *
   1427  * Results:
   1428  *	None.
   1429  *
   1430  * Side Effects:
   1431  *	Parse_Error will be called if open conditionals are around.
   1432  *
   1433  *-----------------------------------------------------------------------
   1434  */
   1435 void
   1436 Cond_restore_depth(unsigned int saved_depth)
   1437 {
   1438     int open_conds = cond_depth - cond_min_depth;
   1439 
   1440     if (open_conds != 0 || saved_depth > cond_depth) {
   1441 	Parse_Error(PARSE_FATAL, "%d open conditional%s", open_conds,
   1442 		    open_conds == 1 ? "" : "s");
   1443 	cond_depth = cond_min_depth;
   1444     }
   1445 
   1446     cond_min_depth = saved_depth;
   1447 }
   1448 
   1449 unsigned int
   1450 Cond_save_depth(void)
   1451 {
   1452     int depth = cond_min_depth;
   1453 
   1454     cond_min_depth = cond_depth;
   1455     return depth;
   1456 }
   1457