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