xref: /freebsd/contrib/bmake/cond.c (revision 3841c287170be8b1cba4d9adf8e727ecaeb64518)
1*3841c287SSimon J. Gerraty /*	$NetBSD: cond.c,v 1.79 2020/07/09 22:34:08 sjg Exp $	*/
23955d011SMarcel Moolenaar 
33955d011SMarcel Moolenaar /*
43955d011SMarcel Moolenaar  * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
53955d011SMarcel Moolenaar  * All rights reserved.
63955d011SMarcel Moolenaar  *
73955d011SMarcel Moolenaar  * This code is derived from software contributed to Berkeley by
83955d011SMarcel Moolenaar  * Adam de Boor.
93955d011SMarcel Moolenaar  *
103955d011SMarcel Moolenaar  * Redistribution and use in source and binary forms, with or without
113955d011SMarcel Moolenaar  * modification, are permitted provided that the following conditions
123955d011SMarcel Moolenaar  * are met:
133955d011SMarcel Moolenaar  * 1. Redistributions of source code must retain the above copyright
143955d011SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer.
153955d011SMarcel Moolenaar  * 2. Redistributions in binary form must reproduce the above copyright
163955d011SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer in the
173955d011SMarcel Moolenaar  *    documentation and/or other materials provided with the distribution.
183955d011SMarcel Moolenaar  * 3. Neither the name of the University nor the names of its contributors
193955d011SMarcel Moolenaar  *    may be used to endorse or promote products derived from this software
203955d011SMarcel Moolenaar  *    without specific prior written permission.
213955d011SMarcel Moolenaar  *
223955d011SMarcel Moolenaar  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
233955d011SMarcel Moolenaar  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
243955d011SMarcel Moolenaar  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
253955d011SMarcel Moolenaar  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
263955d011SMarcel Moolenaar  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
273955d011SMarcel Moolenaar  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
283955d011SMarcel Moolenaar  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
293955d011SMarcel Moolenaar  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
303955d011SMarcel Moolenaar  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
313955d011SMarcel Moolenaar  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
323955d011SMarcel Moolenaar  * SUCH DAMAGE.
333955d011SMarcel Moolenaar  */
343955d011SMarcel Moolenaar 
353955d011SMarcel Moolenaar /*
363955d011SMarcel Moolenaar  * Copyright (c) 1988, 1989 by Adam de Boor
373955d011SMarcel Moolenaar  * Copyright (c) 1989 by Berkeley Softworks
383955d011SMarcel Moolenaar  * All rights reserved.
393955d011SMarcel Moolenaar  *
403955d011SMarcel Moolenaar  * This code is derived from software contributed to Berkeley by
413955d011SMarcel Moolenaar  * Adam de Boor.
423955d011SMarcel Moolenaar  *
433955d011SMarcel Moolenaar  * Redistribution and use in source and binary forms, with or without
443955d011SMarcel Moolenaar  * modification, are permitted provided that the following conditions
453955d011SMarcel Moolenaar  * are met:
463955d011SMarcel Moolenaar  * 1. Redistributions of source code must retain the above copyright
473955d011SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer.
483955d011SMarcel Moolenaar  * 2. Redistributions in binary form must reproduce the above copyright
493955d011SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer in the
503955d011SMarcel Moolenaar  *    documentation and/or other materials provided with the distribution.
513955d011SMarcel Moolenaar  * 3. All advertising materials mentioning features or use of this software
523955d011SMarcel Moolenaar  *    must display the following acknowledgement:
533955d011SMarcel Moolenaar  *	This product includes software developed by the University of
543955d011SMarcel Moolenaar  *	California, Berkeley and its contributors.
553955d011SMarcel Moolenaar  * 4. Neither the name of the University nor the names of its contributors
563955d011SMarcel Moolenaar  *    may be used to endorse or promote products derived from this software
573955d011SMarcel Moolenaar  *    without specific prior written permission.
583955d011SMarcel Moolenaar  *
593955d011SMarcel Moolenaar  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
603955d011SMarcel Moolenaar  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
613955d011SMarcel Moolenaar  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
623955d011SMarcel Moolenaar  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
633955d011SMarcel Moolenaar  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
643955d011SMarcel Moolenaar  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
653955d011SMarcel Moolenaar  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
663955d011SMarcel Moolenaar  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
673955d011SMarcel Moolenaar  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
683955d011SMarcel Moolenaar  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
693955d011SMarcel Moolenaar  * SUCH DAMAGE.
703955d011SMarcel Moolenaar  */
713955d011SMarcel Moolenaar 
723955d011SMarcel Moolenaar #ifndef MAKE_NATIVE
73*3841c287SSimon J. Gerraty static char rcsid[] = "$NetBSD: cond.c,v 1.79 2020/07/09 22:34:08 sjg Exp $";
743955d011SMarcel Moolenaar #else
753955d011SMarcel Moolenaar #include <sys/cdefs.h>
763955d011SMarcel Moolenaar #ifndef lint
773955d011SMarcel Moolenaar #if 0
783955d011SMarcel Moolenaar static char sccsid[] = "@(#)cond.c	8.2 (Berkeley) 1/2/94";
793955d011SMarcel Moolenaar #else
80*3841c287SSimon J. Gerraty __RCSID("$NetBSD: cond.c,v 1.79 2020/07/09 22:34:08 sjg Exp $");
813955d011SMarcel Moolenaar #endif
823955d011SMarcel Moolenaar #endif /* not lint */
833955d011SMarcel Moolenaar #endif
843955d011SMarcel Moolenaar 
853955d011SMarcel Moolenaar /*-
863955d011SMarcel Moolenaar  * cond.c --
873955d011SMarcel Moolenaar  *	Functions to handle conditionals in a makefile.
883955d011SMarcel Moolenaar  *
893955d011SMarcel Moolenaar  * Interface:
903955d011SMarcel Moolenaar  *	Cond_Eval 	Evaluate the conditional in the passed line.
913955d011SMarcel Moolenaar  *
923955d011SMarcel Moolenaar  */
933955d011SMarcel Moolenaar 
94e1cee40dSSimon J. Gerraty #include    <assert.h>
953955d011SMarcel Moolenaar #include    <ctype.h>
963955d011SMarcel Moolenaar #include    <errno.h>    /* For strtoul() error checking */
973955d011SMarcel Moolenaar 
983955d011SMarcel Moolenaar #include    "make.h"
993955d011SMarcel Moolenaar #include    "hash.h"
1003955d011SMarcel Moolenaar #include    "dir.h"
1013955d011SMarcel Moolenaar #include    "buf.h"
1023955d011SMarcel Moolenaar 
1033955d011SMarcel Moolenaar /*
1043955d011SMarcel Moolenaar  * The parsing of conditional expressions is based on this grammar:
1053955d011SMarcel Moolenaar  *	E -> F || E
1063955d011SMarcel Moolenaar  *	E -> F
1073955d011SMarcel Moolenaar  *	F -> T && F
1083955d011SMarcel Moolenaar  *	F -> T
1093955d011SMarcel Moolenaar  *	T -> defined(variable)
1103955d011SMarcel Moolenaar  *	T -> make(target)
1113955d011SMarcel Moolenaar  *	T -> exists(file)
1123955d011SMarcel Moolenaar  *	T -> empty(varspec)
1133955d011SMarcel Moolenaar  *	T -> target(name)
1143955d011SMarcel Moolenaar  *	T -> commands(name)
1153955d011SMarcel Moolenaar  *	T -> symbol
1163955d011SMarcel Moolenaar  *	T -> $(varspec) op value
1173955d011SMarcel Moolenaar  *	T -> $(varspec) == "string"
1183955d011SMarcel Moolenaar  *	T -> $(varspec) != "string"
1193955d011SMarcel Moolenaar  *	T -> "string"
1203955d011SMarcel Moolenaar  *	T -> ( E )
1213955d011SMarcel Moolenaar  *	T -> ! T
1223955d011SMarcel Moolenaar  *	op -> == | != | > | < | >= | <=
1233955d011SMarcel Moolenaar  *
1243955d011SMarcel Moolenaar  * 'symbol' is some other symbol to which the default function (condDefProc)
1253955d011SMarcel Moolenaar  * is applied.
1263955d011SMarcel Moolenaar  *
1273955d011SMarcel Moolenaar  * Tokens are scanned from the 'condExpr' string. The scanner (CondToken)
1283955d011SMarcel Moolenaar  * will return TOK_AND for '&' and '&&', TOK_OR for '|' and '||',
1293955d011SMarcel Moolenaar  * TOK_NOT for '!', TOK_LPAREN for '(', TOK_RPAREN for ')' and will evaluate
1303955d011SMarcel Moolenaar  * the other terminal symbols, using either the default function or the
1313955d011SMarcel Moolenaar  * function given in the terminal, and return the result as either TOK_TRUE
1323955d011SMarcel Moolenaar  * or TOK_FALSE.
1333955d011SMarcel Moolenaar  *
1343955d011SMarcel Moolenaar  * TOK_FALSE is 0 and TOK_TRUE 1 so we can directly assign C comparisons.
1353955d011SMarcel Moolenaar  *
1363955d011SMarcel Moolenaar  * All Non-Terminal functions (CondE, CondF and CondT) return TOK_ERROR on
1373955d011SMarcel Moolenaar  * error.
1383955d011SMarcel Moolenaar  */
1393955d011SMarcel Moolenaar typedef enum {
1403955d011SMarcel Moolenaar     TOK_FALSE = 0, TOK_TRUE = 1, TOK_AND, TOK_OR, TOK_NOT,
1413955d011SMarcel Moolenaar     TOK_LPAREN, TOK_RPAREN, TOK_EOF, TOK_NONE, TOK_ERROR
1423955d011SMarcel Moolenaar } Token;
1433955d011SMarcel Moolenaar 
1443955d011SMarcel Moolenaar /*-
1453955d011SMarcel Moolenaar  * Structures to handle elegantly the different forms of #if's. The
1463955d011SMarcel Moolenaar  * last two fields are stored in condInvert and condDefProc, respectively.
1473955d011SMarcel Moolenaar  */
1483955d011SMarcel Moolenaar static void CondPushBack(Token);
149*3841c287SSimon J. Gerraty static int CondGetArg(Boolean, char **, char **, const char *);
1503955d011SMarcel Moolenaar static Boolean CondDoDefined(int, const char *);
1513955d011SMarcel Moolenaar static int CondStrMatch(const void *, const void *);
1523955d011SMarcel Moolenaar static Boolean CondDoMake(int, const char *);
1533955d011SMarcel Moolenaar static Boolean CondDoExists(int, const char *);
1543955d011SMarcel Moolenaar static Boolean CondDoTarget(int, const char *);
1553955d011SMarcel Moolenaar static Boolean CondDoCommands(int, const char *);
1563955d011SMarcel Moolenaar static Boolean CondCvtArg(char *, double *);
1573955d011SMarcel Moolenaar static Token CondToken(Boolean);
1583955d011SMarcel Moolenaar static Token CondT(Boolean);
1593955d011SMarcel Moolenaar static Token CondF(Boolean);
1603955d011SMarcel Moolenaar static Token CondE(Boolean);
1613955d011SMarcel Moolenaar static int do_Cond_EvalExpression(Boolean *);
1623955d011SMarcel Moolenaar 
1633955d011SMarcel Moolenaar static const struct If {
1643955d011SMarcel Moolenaar     const char	*form;	      /* Form of if */
1653955d011SMarcel Moolenaar     int		formlen;      /* Length of form */
1663955d011SMarcel Moolenaar     Boolean	doNot;	      /* TRUE if default function should be negated */
1673955d011SMarcel Moolenaar     Boolean	(*defProc)(int, const char *); /* Default function to apply */
1683955d011SMarcel Moolenaar } ifs[] = {
1693955d011SMarcel Moolenaar     { "def",	  3,	  FALSE,  CondDoDefined },
1703955d011SMarcel Moolenaar     { "ndef",	  4,	  TRUE,	  CondDoDefined },
1713955d011SMarcel Moolenaar     { "make",	  4,	  FALSE,  CondDoMake },
1723955d011SMarcel Moolenaar     { "nmake",	  5,	  TRUE,	  CondDoMake },
1733955d011SMarcel Moolenaar     { "",	  0,	  FALSE,  CondDoDefined },
1743955d011SMarcel Moolenaar     { NULL,	  0,	  FALSE,  NULL }
1753955d011SMarcel Moolenaar };
1763955d011SMarcel Moolenaar 
1773955d011SMarcel Moolenaar static const struct If *if_info;        /* Info for current statement */
1783955d011SMarcel Moolenaar static char 	  *condExpr;	    	/* The expression to parse */
1793955d011SMarcel Moolenaar static Token	  condPushBack=TOK_NONE;	/* Single push-back token used in
1803955d011SMarcel Moolenaar 					 * parsing */
1813955d011SMarcel Moolenaar 
1823955d011SMarcel Moolenaar static unsigned int	cond_depth = 0;  	/* current .if nesting level */
1833955d011SMarcel Moolenaar static unsigned int	cond_min_depth = 0;  	/* depth at makefile open */
1843955d011SMarcel Moolenaar 
18528a6bc81SSimon J. Gerraty /*
18628a6bc81SSimon J. Gerraty  * Indicate when we should be strict about lhs of comparisons.
18728a6bc81SSimon J. Gerraty  * TRUE when Cond_EvalExpression is called from Cond_Eval (.if etc)
18828a6bc81SSimon J. Gerraty  * FALSE when Cond_EvalExpression is called from var.c:ApplyModifiers
18928a6bc81SSimon J. Gerraty  * since lhs is already expanded and we cannot tell if
19028a6bc81SSimon J. Gerraty  * it was a variable reference or not.
19128a6bc81SSimon J. Gerraty  */
19228a6bc81SSimon J. Gerraty static Boolean lhsStrict;
19328a6bc81SSimon J. Gerraty 
1943955d011SMarcel Moolenaar static int
1953955d011SMarcel Moolenaar istoken(const char *str, const char *tok, size_t len)
1963955d011SMarcel Moolenaar {
1973955d011SMarcel Moolenaar 	return strncmp(str, tok, len) == 0 && !isalpha((unsigned char)str[len]);
1983955d011SMarcel Moolenaar }
1993955d011SMarcel Moolenaar 
2003955d011SMarcel Moolenaar /*-
2013955d011SMarcel Moolenaar  *-----------------------------------------------------------------------
2023955d011SMarcel Moolenaar  * CondPushBack --
2033955d011SMarcel Moolenaar  *	Push back the most recent token read. We only need one level of
2043955d011SMarcel Moolenaar  *	this, so the thing is just stored in 'condPushback'.
2053955d011SMarcel Moolenaar  *
2063955d011SMarcel Moolenaar  * Input:
2073955d011SMarcel Moolenaar  *	t		Token to push back into the "stream"
2083955d011SMarcel Moolenaar  *
2093955d011SMarcel Moolenaar  * Results:
2103955d011SMarcel Moolenaar  *	None.
2113955d011SMarcel Moolenaar  *
2123955d011SMarcel Moolenaar  * Side Effects:
2133955d011SMarcel Moolenaar  *	condPushback is overwritten.
2143955d011SMarcel Moolenaar  *
2153955d011SMarcel Moolenaar  *-----------------------------------------------------------------------
2163955d011SMarcel Moolenaar  */
2173955d011SMarcel Moolenaar static void
2183955d011SMarcel Moolenaar CondPushBack(Token t)
2193955d011SMarcel Moolenaar {
2203955d011SMarcel Moolenaar     condPushBack = t;
2213955d011SMarcel Moolenaar }
2223955d011SMarcel Moolenaar 
2233955d011SMarcel Moolenaar /*-
2243955d011SMarcel Moolenaar  *-----------------------------------------------------------------------
2253955d011SMarcel Moolenaar  * CondGetArg --
2263955d011SMarcel Moolenaar  *	Find the argument of a built-in function.
2273955d011SMarcel Moolenaar  *
2283955d011SMarcel Moolenaar  * Results:
2293955d011SMarcel Moolenaar  *	The length of the argument and the address of the argument.
2303955d011SMarcel Moolenaar  *
2313955d011SMarcel Moolenaar  * Side Effects:
2323955d011SMarcel Moolenaar  *	The pointer is set to point to the closing parenthesis of the
2333955d011SMarcel Moolenaar  *	function call.
2343955d011SMarcel Moolenaar  *
2353955d011SMarcel Moolenaar  *-----------------------------------------------------------------------
2363955d011SMarcel Moolenaar  */
2373955d011SMarcel Moolenaar static int
238*3841c287SSimon J. Gerraty CondGetArg(Boolean doEval, char **linePtr, char **argPtr, const char *func)
2393955d011SMarcel Moolenaar {
2403955d011SMarcel Moolenaar     char	  *cp;
2413955d011SMarcel Moolenaar     int	    	  argLen;
2423955d011SMarcel Moolenaar     Buffer	  buf;
2433955d011SMarcel Moolenaar     int           paren_depth;
2443955d011SMarcel Moolenaar     char          ch;
2453955d011SMarcel Moolenaar 
2463955d011SMarcel Moolenaar     cp = *linePtr;
2473955d011SMarcel Moolenaar     if (func != NULL)
2483955d011SMarcel Moolenaar 	/* Skip opening '(' - verfied by caller */
2493955d011SMarcel Moolenaar 	cp++;
2503955d011SMarcel Moolenaar 
2513955d011SMarcel Moolenaar     if (*cp == '\0') {
2523955d011SMarcel Moolenaar 	/*
2533955d011SMarcel Moolenaar 	 * No arguments whatsoever. Because 'make' and 'defined' aren't really
2543955d011SMarcel Moolenaar 	 * "reserved words", we don't print a message. I think this is better
2553955d011SMarcel Moolenaar 	 * than hitting the user with a warning message every time s/he uses
2563955d011SMarcel Moolenaar 	 * the word 'make' or 'defined' at the beginning of a symbol...
2573955d011SMarcel Moolenaar 	 */
2583955d011SMarcel Moolenaar 	*argPtr = NULL;
259*3841c287SSimon J. Gerraty 	return 0;
2603955d011SMarcel Moolenaar     }
2613955d011SMarcel Moolenaar 
2623955d011SMarcel Moolenaar     while (*cp == ' ' || *cp == '\t') {
2633955d011SMarcel Moolenaar 	cp++;
2643955d011SMarcel Moolenaar     }
2653955d011SMarcel Moolenaar 
2663955d011SMarcel Moolenaar     /*
2673955d011SMarcel Moolenaar      * Create a buffer for the argument and start it out at 16 characters
2683955d011SMarcel Moolenaar      * long. Why 16? Why not?
2693955d011SMarcel Moolenaar      */
2703955d011SMarcel Moolenaar     Buf_Init(&buf, 16);
2713955d011SMarcel Moolenaar 
2723955d011SMarcel Moolenaar     paren_depth = 0;
2733955d011SMarcel Moolenaar     for (;;) {
2743955d011SMarcel Moolenaar 	ch = *cp;
2753955d011SMarcel Moolenaar 	if (ch == 0 || ch == ' ' || ch == '\t')
2763955d011SMarcel Moolenaar 	    break;
2773955d011SMarcel Moolenaar 	if ((ch == '&' || ch == '|') && paren_depth == 0)
2783955d011SMarcel Moolenaar 	    break;
2793955d011SMarcel Moolenaar 	if (*cp == '$') {
2803955d011SMarcel Moolenaar 	    /*
2813955d011SMarcel Moolenaar 	     * Parse the variable spec and install it as part of the argument
2823955d011SMarcel Moolenaar 	     * if it's valid. We tell Var_Parse to complain on an undefined
2833955d011SMarcel Moolenaar 	     * variable, so we don't do it too. Nor do we return an error,
2843955d011SMarcel Moolenaar 	     * though perhaps we should...
2853955d011SMarcel Moolenaar 	     */
2863955d011SMarcel Moolenaar 	    char  	*cp2;
2873955d011SMarcel Moolenaar 	    int		len;
2883955d011SMarcel Moolenaar 	    void	*freeIt;
2893955d011SMarcel Moolenaar 
290*3841c287SSimon J. Gerraty 	    cp2 = Var_Parse(cp, VAR_CMD, VARF_UNDEFERR|
291*3841c287SSimon J. Gerraty 			    (doEval ? VARF_WANTRES : 0),
292be19d90bSSimon J. Gerraty 			    &len, &freeIt);
2933955d011SMarcel Moolenaar 	    Buf_AddBytes(&buf, strlen(cp2), cp2);
2943955d011SMarcel Moolenaar 	    free(freeIt);
2953955d011SMarcel Moolenaar 	    cp += len;
2963955d011SMarcel Moolenaar 	    continue;
2973955d011SMarcel Moolenaar 	}
2983955d011SMarcel Moolenaar 	if (ch == '(')
2993955d011SMarcel Moolenaar 	    paren_depth++;
3003955d011SMarcel Moolenaar 	else
3013955d011SMarcel Moolenaar 	    if (ch == ')' && --paren_depth < 0)
3023955d011SMarcel Moolenaar 		break;
3033955d011SMarcel Moolenaar 	Buf_AddByte(&buf, *cp);
3043955d011SMarcel Moolenaar 	cp++;
3053955d011SMarcel Moolenaar     }
3063955d011SMarcel Moolenaar 
3073955d011SMarcel Moolenaar     *argPtr = Buf_GetAll(&buf, &argLen);
3083955d011SMarcel Moolenaar     Buf_Destroy(&buf, FALSE);
3093955d011SMarcel Moolenaar 
3103955d011SMarcel Moolenaar     while (*cp == ' ' || *cp == '\t') {
3113955d011SMarcel Moolenaar 	cp++;
3123955d011SMarcel Moolenaar     }
3133955d011SMarcel Moolenaar 
3143955d011SMarcel Moolenaar     if (func != NULL && *cp++ != ')') {
3153955d011SMarcel Moolenaar 	Parse_Error(PARSE_WARNING, "Missing closing parenthesis for %s()",
3163955d011SMarcel Moolenaar 		     func);
317*3841c287SSimon J. Gerraty 	return 0;
3183955d011SMarcel Moolenaar     }
3193955d011SMarcel Moolenaar 
3203955d011SMarcel Moolenaar     *linePtr = cp;
321*3841c287SSimon J. Gerraty     return argLen;
3223955d011SMarcel Moolenaar }
3233955d011SMarcel Moolenaar 
3243955d011SMarcel Moolenaar /*-
3253955d011SMarcel Moolenaar  *-----------------------------------------------------------------------
3263955d011SMarcel Moolenaar  * CondDoDefined --
3273955d011SMarcel Moolenaar  *	Handle the 'defined' function for conditionals.
3283955d011SMarcel Moolenaar  *
3293955d011SMarcel Moolenaar  * Results:
3303955d011SMarcel Moolenaar  *	TRUE if the given variable is defined.
3313955d011SMarcel Moolenaar  *
3323955d011SMarcel Moolenaar  * Side Effects:
3333955d011SMarcel Moolenaar  *	None.
3343955d011SMarcel Moolenaar  *
3353955d011SMarcel Moolenaar  *-----------------------------------------------------------------------
3363955d011SMarcel Moolenaar  */
3373955d011SMarcel Moolenaar static Boolean
3383955d011SMarcel Moolenaar CondDoDefined(int argLen MAKE_ATTR_UNUSED, const char *arg)
3393955d011SMarcel Moolenaar {
3403955d011SMarcel Moolenaar     char    *p1;
3413955d011SMarcel Moolenaar     Boolean result;
3423955d011SMarcel Moolenaar 
3433955d011SMarcel Moolenaar     if (Var_Value(arg, VAR_CMD, &p1) != NULL) {
3443955d011SMarcel Moolenaar 	result = TRUE;
3453955d011SMarcel Moolenaar     } else {
3463955d011SMarcel Moolenaar 	result = FALSE;
3473955d011SMarcel Moolenaar     }
348be19d90bSSimon J. Gerraty 
3493955d011SMarcel Moolenaar     free(p1);
350*3841c287SSimon J. Gerraty     return result;
3513955d011SMarcel Moolenaar }
3523955d011SMarcel Moolenaar 
3533955d011SMarcel Moolenaar /*-
3543955d011SMarcel Moolenaar  *-----------------------------------------------------------------------
3553955d011SMarcel Moolenaar  * CondStrMatch --
3563955d011SMarcel Moolenaar  *	Front-end for Str_Match so it returns 0 on match and non-zero
3573955d011SMarcel Moolenaar  *	on mismatch. Callback function for CondDoMake via Lst_Find
3583955d011SMarcel Moolenaar  *
3593955d011SMarcel Moolenaar  * Results:
3603955d011SMarcel Moolenaar  *	0 if string matches pattern
3613955d011SMarcel Moolenaar  *
3623955d011SMarcel Moolenaar  * Side Effects:
3633955d011SMarcel Moolenaar  *	None
3643955d011SMarcel Moolenaar  *
3653955d011SMarcel Moolenaar  *-----------------------------------------------------------------------
3663955d011SMarcel Moolenaar  */
3673955d011SMarcel Moolenaar static int
3683955d011SMarcel Moolenaar CondStrMatch(const void *string, const void *pattern)
3693955d011SMarcel Moolenaar {
370*3841c287SSimon J. Gerraty     return !Str_Match(string, pattern);
3713955d011SMarcel Moolenaar }
3723955d011SMarcel Moolenaar 
3733955d011SMarcel Moolenaar /*-
3743955d011SMarcel Moolenaar  *-----------------------------------------------------------------------
3753955d011SMarcel Moolenaar  * CondDoMake --
3763955d011SMarcel Moolenaar  *	Handle the 'make' function for conditionals.
3773955d011SMarcel Moolenaar  *
3783955d011SMarcel Moolenaar  * Results:
3793955d011SMarcel Moolenaar  *	TRUE if the given target is being made.
3803955d011SMarcel Moolenaar  *
3813955d011SMarcel Moolenaar  * Side Effects:
3823955d011SMarcel Moolenaar  *	None.
3833955d011SMarcel Moolenaar  *
3843955d011SMarcel Moolenaar  *-----------------------------------------------------------------------
3853955d011SMarcel Moolenaar  */
3863955d011SMarcel Moolenaar static Boolean
3873955d011SMarcel Moolenaar CondDoMake(int argLen MAKE_ATTR_UNUSED, const char *arg)
3883955d011SMarcel Moolenaar {
3893955d011SMarcel Moolenaar     return Lst_Find(create, arg, CondStrMatch) != NULL;
3903955d011SMarcel Moolenaar }
3913955d011SMarcel Moolenaar 
3923955d011SMarcel Moolenaar /*-
3933955d011SMarcel Moolenaar  *-----------------------------------------------------------------------
3943955d011SMarcel Moolenaar  * CondDoExists --
3953955d011SMarcel Moolenaar  *	See if the given file exists.
3963955d011SMarcel Moolenaar  *
3973955d011SMarcel Moolenaar  * Results:
3983955d011SMarcel Moolenaar  *	TRUE if the file exists and FALSE if it does not.
3993955d011SMarcel Moolenaar  *
4003955d011SMarcel Moolenaar  * Side Effects:
4013955d011SMarcel Moolenaar  *	None.
4023955d011SMarcel Moolenaar  *
4033955d011SMarcel Moolenaar  *-----------------------------------------------------------------------
4043955d011SMarcel Moolenaar  */
4053955d011SMarcel Moolenaar static Boolean
4063955d011SMarcel Moolenaar CondDoExists(int argLen MAKE_ATTR_UNUSED, const char *arg)
4073955d011SMarcel Moolenaar {
4083955d011SMarcel Moolenaar     Boolean result;
4093955d011SMarcel Moolenaar     char    *path;
4103955d011SMarcel Moolenaar 
4113955d011SMarcel Moolenaar     path = Dir_FindFile(arg, dirSearchPath);
4123955d011SMarcel Moolenaar     if (DEBUG(COND)) {
4133955d011SMarcel Moolenaar 	fprintf(debug_file, "exists(%s) result is \"%s\"\n",
4143955d011SMarcel Moolenaar 	       arg, path ? path : "");
4153955d011SMarcel Moolenaar     }
4163955d011SMarcel Moolenaar     if (path != NULL) {
4173955d011SMarcel Moolenaar 	result = TRUE;
4183955d011SMarcel Moolenaar 	free(path);
4193955d011SMarcel Moolenaar     } else {
4203955d011SMarcel Moolenaar 	result = FALSE;
4213955d011SMarcel Moolenaar     }
422*3841c287SSimon J. Gerraty     return result;
4233955d011SMarcel Moolenaar }
4243955d011SMarcel Moolenaar 
4253955d011SMarcel Moolenaar /*-
4263955d011SMarcel Moolenaar  *-----------------------------------------------------------------------
4273955d011SMarcel Moolenaar  * CondDoTarget --
4283955d011SMarcel Moolenaar  *	See if the given node exists and is an actual target.
4293955d011SMarcel Moolenaar  *
4303955d011SMarcel Moolenaar  * Results:
4313955d011SMarcel Moolenaar  *	TRUE if the node exists as a target and FALSE if it does not.
4323955d011SMarcel Moolenaar  *
4333955d011SMarcel Moolenaar  * Side Effects:
4343955d011SMarcel Moolenaar  *	None.
4353955d011SMarcel Moolenaar  *
4363955d011SMarcel Moolenaar  *-----------------------------------------------------------------------
4373955d011SMarcel Moolenaar  */
4383955d011SMarcel Moolenaar static Boolean
4393955d011SMarcel Moolenaar CondDoTarget(int argLen MAKE_ATTR_UNUSED, const char *arg)
4403955d011SMarcel Moolenaar {
4413955d011SMarcel Moolenaar     GNode   *gn;
4423955d011SMarcel Moolenaar 
4433955d011SMarcel Moolenaar     gn = Targ_FindNode(arg, TARG_NOCREATE);
444*3841c287SSimon J. Gerraty     return gn != NULL && !OP_NOP(gn->type);
4453955d011SMarcel Moolenaar }
4463955d011SMarcel Moolenaar 
4473955d011SMarcel Moolenaar /*-
4483955d011SMarcel Moolenaar  *-----------------------------------------------------------------------
4493955d011SMarcel Moolenaar  * CondDoCommands --
4503955d011SMarcel Moolenaar  *	See if the given node exists and is an actual target with commands
4513955d011SMarcel Moolenaar  *	associated with it.
4523955d011SMarcel Moolenaar  *
4533955d011SMarcel Moolenaar  * Results:
4543955d011SMarcel Moolenaar  *	TRUE if the node exists as a target and has commands associated with
4553955d011SMarcel Moolenaar  *	it and FALSE if it does not.
4563955d011SMarcel Moolenaar  *
4573955d011SMarcel Moolenaar  * Side Effects:
4583955d011SMarcel Moolenaar  *	None.
4593955d011SMarcel Moolenaar  *
4603955d011SMarcel Moolenaar  *-----------------------------------------------------------------------
4613955d011SMarcel Moolenaar  */
4623955d011SMarcel Moolenaar static Boolean
4633955d011SMarcel Moolenaar CondDoCommands(int argLen MAKE_ATTR_UNUSED, const char *arg)
4643955d011SMarcel Moolenaar {
4653955d011SMarcel Moolenaar     GNode   *gn;
4663955d011SMarcel Moolenaar 
4673955d011SMarcel Moolenaar     gn = Targ_FindNode(arg, TARG_NOCREATE);
468*3841c287SSimon J. Gerraty     return gn != NULL && !OP_NOP(gn->type) && !Lst_IsEmpty(gn->commands);
4693955d011SMarcel Moolenaar }
4703955d011SMarcel Moolenaar 
4713955d011SMarcel Moolenaar /*-
4723955d011SMarcel Moolenaar  *-----------------------------------------------------------------------
4733955d011SMarcel Moolenaar  * CondCvtArg --
4743955d011SMarcel Moolenaar  *	Convert the given number into a double.
4753955d011SMarcel Moolenaar  *	We try a base 10 or 16 integer conversion first, if that fails
4763955d011SMarcel Moolenaar  *	then we try a floating point conversion instead.
4773955d011SMarcel Moolenaar  *
4783955d011SMarcel Moolenaar  * Results:
4793955d011SMarcel Moolenaar  *	Sets 'value' to double value of string.
4803955d011SMarcel Moolenaar  *	Returns 'true' if the convertion suceeded
4813955d011SMarcel Moolenaar  *
4823955d011SMarcel Moolenaar  *-----------------------------------------------------------------------
4833955d011SMarcel Moolenaar  */
4843955d011SMarcel Moolenaar static Boolean
4853955d011SMarcel Moolenaar CondCvtArg(char *str, double *value)
4863955d011SMarcel Moolenaar {
4873955d011SMarcel Moolenaar     char *eptr, ech;
4883955d011SMarcel Moolenaar     unsigned long l_val;
4893955d011SMarcel Moolenaar     double d_val;
4903955d011SMarcel Moolenaar 
4913955d011SMarcel Moolenaar     errno = 0;
492ac3446e9SSimon J. Gerraty     if (!*str) {
493ac3446e9SSimon J. Gerraty 	*value = (double)0;
494ac3446e9SSimon J. Gerraty 	return TRUE;
495ac3446e9SSimon J. Gerraty     }
4963955d011SMarcel Moolenaar     l_val = strtoul(str, &eptr, str[1] == 'x' ? 16 : 10);
4973955d011SMarcel Moolenaar     ech = *eptr;
4983955d011SMarcel Moolenaar     if (ech == 0 && errno != ERANGE) {
4993955d011SMarcel Moolenaar 	d_val = str[0] == '-' ? -(double)-l_val : (double)l_val;
5003955d011SMarcel Moolenaar     } else {
5013955d011SMarcel Moolenaar 	if (ech != 0 && ech != '.' && ech != 'e' && ech != 'E')
5023955d011SMarcel Moolenaar 	    return FALSE;
5033955d011SMarcel Moolenaar 	d_val = strtod(str, &eptr);
5043955d011SMarcel Moolenaar 	if (*eptr)
5053955d011SMarcel Moolenaar 	    return FALSE;
5063955d011SMarcel Moolenaar     }
5073955d011SMarcel Moolenaar 
5083955d011SMarcel Moolenaar     *value = d_val;
5093955d011SMarcel Moolenaar     return TRUE;
5103955d011SMarcel Moolenaar }
5113955d011SMarcel Moolenaar 
5123955d011SMarcel Moolenaar /*-
5133955d011SMarcel Moolenaar  *-----------------------------------------------------------------------
5143955d011SMarcel Moolenaar  * CondGetString --
5153955d011SMarcel Moolenaar  *	Get a string from a variable reference or an optionally quoted
5163955d011SMarcel Moolenaar  *	string.  This is called for the lhs and rhs of string compares.
5173955d011SMarcel Moolenaar  *
5183955d011SMarcel Moolenaar  * Results:
5193955d011SMarcel Moolenaar  *	Sets freeIt if needed,
5203955d011SMarcel Moolenaar  *	Sets quoted if string was quoted,
5213955d011SMarcel Moolenaar  *	Returns NULL on error,
5223955d011SMarcel Moolenaar  *	else returns string - absent any quotes.
5233955d011SMarcel Moolenaar  *
5243955d011SMarcel Moolenaar  * Side Effects:
5253955d011SMarcel Moolenaar  *	Moves condExpr to end of this token.
5263955d011SMarcel Moolenaar  *
5273955d011SMarcel Moolenaar  *
5283955d011SMarcel Moolenaar  *-----------------------------------------------------------------------
5293955d011SMarcel Moolenaar  */
5303955d011SMarcel Moolenaar /* coverity:[+alloc : arg-*2] */
5313955d011SMarcel Moolenaar static char *
53228a6bc81SSimon J. Gerraty CondGetString(Boolean doEval, Boolean *quoted, void **freeIt, Boolean strictLHS)
5333955d011SMarcel Moolenaar {
5343955d011SMarcel Moolenaar     Buffer buf;
5353955d011SMarcel Moolenaar     char *cp;
5363955d011SMarcel Moolenaar     char *str;
5373955d011SMarcel Moolenaar     int	len;
5383955d011SMarcel Moolenaar     int qt;
5393955d011SMarcel Moolenaar     char *start;
5403955d011SMarcel Moolenaar 
5413955d011SMarcel Moolenaar     Buf_Init(&buf, 0);
5423955d011SMarcel Moolenaar     str = NULL;
5433955d011SMarcel Moolenaar     *freeIt = NULL;
5443955d011SMarcel Moolenaar     *quoted = qt = *condExpr == '"' ? 1 : 0;
5453955d011SMarcel Moolenaar     if (qt)
5463955d011SMarcel Moolenaar 	condExpr++;
5473955d011SMarcel Moolenaar     for (start = condExpr; *condExpr && str == NULL; condExpr++) {
5483955d011SMarcel Moolenaar 	switch (*condExpr) {
5493955d011SMarcel Moolenaar 	case '\\':
5503955d011SMarcel Moolenaar 	    if (condExpr[1] != '\0') {
5513955d011SMarcel Moolenaar 		condExpr++;
5523955d011SMarcel Moolenaar 		Buf_AddByte(&buf, *condExpr);
5533955d011SMarcel Moolenaar 	    }
5543955d011SMarcel Moolenaar 	    break;
5553955d011SMarcel Moolenaar 	case '"':
5563955d011SMarcel Moolenaar 	    if (qt) {
5573955d011SMarcel Moolenaar 		condExpr++;		/* we don't want the quotes */
5583955d011SMarcel Moolenaar 		goto got_str;
5593955d011SMarcel Moolenaar 	    } else
5603955d011SMarcel Moolenaar 		Buf_AddByte(&buf, *condExpr); /* likely? */
5613955d011SMarcel Moolenaar 	    break;
5623955d011SMarcel Moolenaar 	case ')':
5633955d011SMarcel Moolenaar 	case '!':
5643955d011SMarcel Moolenaar 	case '=':
5653955d011SMarcel Moolenaar 	case '>':
5663955d011SMarcel Moolenaar 	case '<':
5673955d011SMarcel Moolenaar 	case ' ':
5683955d011SMarcel Moolenaar 	case '\t':
5693955d011SMarcel Moolenaar 	    if (!qt)
5703955d011SMarcel Moolenaar 		goto got_str;
5713955d011SMarcel Moolenaar 	    else
5723955d011SMarcel Moolenaar 		Buf_AddByte(&buf, *condExpr);
5733955d011SMarcel Moolenaar 	    break;
5743955d011SMarcel Moolenaar 	case '$':
5753955d011SMarcel Moolenaar 	    /* if we are in quotes, then an undefined variable is ok */
576be19d90bSSimon J. Gerraty 	    str = Var_Parse(condExpr, VAR_CMD,
577be19d90bSSimon J. Gerraty 			    ((!qt && doEval) ? VARF_UNDEFERR : 0) |
578*3841c287SSimon J. Gerraty 			    (doEval ? VARF_WANTRES : 0), &len, freeIt);
5793955d011SMarcel Moolenaar 	    if (str == var_Error) {
5803955d011SMarcel Moolenaar 		if (*freeIt) {
5813955d011SMarcel Moolenaar 		    free(*freeIt);
5823955d011SMarcel Moolenaar 		    *freeIt = NULL;
5833955d011SMarcel Moolenaar 		}
5843955d011SMarcel Moolenaar 		/*
5853955d011SMarcel Moolenaar 		 * Even if !doEval, we still report syntax errors, which
5863955d011SMarcel Moolenaar 		 * is what getting var_Error back with !doEval means.
5873955d011SMarcel Moolenaar 		 */
5883955d011SMarcel Moolenaar 		str = NULL;
5893955d011SMarcel Moolenaar 		goto cleanup;
5903955d011SMarcel Moolenaar 	    }
5913955d011SMarcel Moolenaar 	    condExpr += len;
5923955d011SMarcel Moolenaar 	    /*
5933955d011SMarcel Moolenaar 	     * If the '$' was first char (no quotes), and we are
5943955d011SMarcel Moolenaar 	     * followed by space, the operator or end of expression,
5953955d011SMarcel Moolenaar 	     * we are done.
5963955d011SMarcel Moolenaar 	     */
5973955d011SMarcel Moolenaar 	    if ((condExpr == start + len) &&
5983955d011SMarcel Moolenaar 		(*condExpr == '\0' ||
5993955d011SMarcel Moolenaar 		 isspace((unsigned char) *condExpr) ||
6003955d011SMarcel Moolenaar 		 strchr("!=><)", *condExpr))) {
6013955d011SMarcel Moolenaar 		goto cleanup;
6023955d011SMarcel Moolenaar 	    }
6033955d011SMarcel Moolenaar 	    /*
6043955d011SMarcel Moolenaar 	     * Nope, we better copy str to buf
6053955d011SMarcel Moolenaar 	     */
6063955d011SMarcel Moolenaar 	    for (cp = str; *cp; cp++) {
6073955d011SMarcel Moolenaar 		Buf_AddByte(&buf, *cp);
6083955d011SMarcel Moolenaar 	    }
6093955d011SMarcel Moolenaar 	    if (*freeIt) {
6103955d011SMarcel Moolenaar 		free(*freeIt);
6113955d011SMarcel Moolenaar 		*freeIt = NULL;
6123955d011SMarcel Moolenaar 	    }
6133955d011SMarcel Moolenaar 	    str = NULL;			/* not finished yet */
6143955d011SMarcel Moolenaar 	    condExpr--;			/* don't skip over next char */
6153955d011SMarcel Moolenaar 	    break;
6163955d011SMarcel Moolenaar 	default:
61728a6bc81SSimon J. Gerraty 	    if (strictLHS && !qt && *start != '$' &&
61828a6bc81SSimon J. Gerraty 		!isdigit((unsigned char) *start)) {
61928a6bc81SSimon J. Gerraty 		/* lhs must be quoted, a variable reference or number */
62028a6bc81SSimon J. Gerraty 		if (*freeIt) {
62128a6bc81SSimon J. Gerraty 		    free(*freeIt);
62228a6bc81SSimon J. Gerraty 		    *freeIt = NULL;
62328a6bc81SSimon J. Gerraty 		}
62428a6bc81SSimon J. Gerraty 		str = NULL;
62528a6bc81SSimon J. Gerraty 		goto cleanup;
62628a6bc81SSimon J. Gerraty 	    }
6273955d011SMarcel Moolenaar 	    Buf_AddByte(&buf, *condExpr);
6283955d011SMarcel Moolenaar 	    break;
6293955d011SMarcel Moolenaar 	}
6303955d011SMarcel Moolenaar     }
6313955d011SMarcel Moolenaar  got_str:
6323955d011SMarcel Moolenaar     str = Buf_GetAll(&buf, NULL);
6333955d011SMarcel Moolenaar     *freeIt = str;
6343955d011SMarcel Moolenaar  cleanup:
6353955d011SMarcel Moolenaar     Buf_Destroy(&buf, FALSE);
6363955d011SMarcel Moolenaar     return str;
6373955d011SMarcel Moolenaar }
6383955d011SMarcel Moolenaar 
6393955d011SMarcel Moolenaar /*-
6403955d011SMarcel Moolenaar  *-----------------------------------------------------------------------
6413955d011SMarcel Moolenaar  * CondToken --
6423955d011SMarcel Moolenaar  *	Return the next token from the input.
6433955d011SMarcel Moolenaar  *
6443955d011SMarcel Moolenaar  * Results:
6453955d011SMarcel Moolenaar  *	A Token for the next lexical token in the stream.
6463955d011SMarcel Moolenaar  *
6473955d011SMarcel Moolenaar  * Side Effects:
6483955d011SMarcel Moolenaar  *	condPushback will be set back to TOK_NONE if it is used.
6493955d011SMarcel Moolenaar  *
6503955d011SMarcel Moolenaar  *-----------------------------------------------------------------------
6513955d011SMarcel Moolenaar  */
6523955d011SMarcel Moolenaar static Token
6533955d011SMarcel Moolenaar compare_expression(Boolean doEval)
6543955d011SMarcel Moolenaar {
6553955d011SMarcel Moolenaar     Token	t;
6563955d011SMarcel Moolenaar     char	*lhs;
6573955d011SMarcel Moolenaar     char	*rhs;
6583955d011SMarcel Moolenaar     char	*op;
6593955d011SMarcel Moolenaar     void	*lhsFree;
6603955d011SMarcel Moolenaar     void	*rhsFree;
6613955d011SMarcel Moolenaar     Boolean lhsQuoted;
6623955d011SMarcel Moolenaar     Boolean rhsQuoted;
6633955d011SMarcel Moolenaar     double  	left, right;
6643955d011SMarcel Moolenaar 
6653955d011SMarcel Moolenaar     t = TOK_ERROR;
6663955d011SMarcel Moolenaar     rhs = NULL;
6673955d011SMarcel Moolenaar     lhsFree = rhsFree = FALSE;
6683955d011SMarcel Moolenaar     lhsQuoted = rhsQuoted = FALSE;
6693955d011SMarcel Moolenaar 
6703955d011SMarcel Moolenaar     /*
6713955d011SMarcel Moolenaar      * Parse the variable spec and skip over it, saving its
6723955d011SMarcel Moolenaar      * value in lhs.
6733955d011SMarcel Moolenaar      */
67428a6bc81SSimon J. Gerraty     lhs = CondGetString(doEval, &lhsQuoted, &lhsFree, lhsStrict);
6753955d011SMarcel Moolenaar     if (!lhs)
6763955d011SMarcel Moolenaar 	goto done;
6773955d011SMarcel Moolenaar 
6783955d011SMarcel Moolenaar     /*
6793955d011SMarcel Moolenaar      * Skip whitespace to get to the operator
6803955d011SMarcel Moolenaar      */
6813955d011SMarcel Moolenaar     while (isspace((unsigned char) *condExpr))
6823955d011SMarcel Moolenaar 	condExpr++;
6833955d011SMarcel Moolenaar 
6843955d011SMarcel Moolenaar     /*
6853955d011SMarcel Moolenaar      * Make sure the operator is a valid one. If it isn't a
6863955d011SMarcel Moolenaar      * known relational operator, pretend we got a
6873955d011SMarcel Moolenaar      * != 0 comparison.
6883955d011SMarcel Moolenaar      */
6893955d011SMarcel Moolenaar     op = condExpr;
6903955d011SMarcel Moolenaar     switch (*condExpr) {
6913955d011SMarcel Moolenaar 	case '!':
6923955d011SMarcel Moolenaar 	case '=':
6933955d011SMarcel Moolenaar 	case '<':
6943955d011SMarcel Moolenaar 	case '>':
6953955d011SMarcel Moolenaar 	    if (condExpr[1] == '=') {
6963955d011SMarcel Moolenaar 		condExpr += 2;
6973955d011SMarcel Moolenaar 	    } else {
6983955d011SMarcel Moolenaar 		condExpr += 1;
6993955d011SMarcel Moolenaar 	    }
7003955d011SMarcel Moolenaar 	    break;
7013955d011SMarcel Moolenaar 	default:
7023955d011SMarcel Moolenaar 	    if (!doEval) {
7033955d011SMarcel Moolenaar 		t = TOK_FALSE;
7043955d011SMarcel Moolenaar 		goto done;
7053955d011SMarcel Moolenaar 	    }
7063955d011SMarcel Moolenaar 	    /* For .ifxxx "..." check for non-empty string. */
7073955d011SMarcel Moolenaar 	    if (lhsQuoted) {
7083955d011SMarcel Moolenaar 		t = lhs[0] != 0;
7093955d011SMarcel Moolenaar 		goto done;
7103955d011SMarcel Moolenaar 	    }
7113955d011SMarcel Moolenaar 	    /* For .ifxxx <number> compare against zero */
7123955d011SMarcel Moolenaar 	    if (CondCvtArg(lhs, &left)) {
7133955d011SMarcel Moolenaar 		t = left != 0.0;
7143955d011SMarcel Moolenaar 		goto done;
7153955d011SMarcel Moolenaar 	    }
7163955d011SMarcel Moolenaar 	    /* For .if ${...} check for non-empty string (defProc is ifdef). */
7173955d011SMarcel Moolenaar 	    if (if_info->form[0] == 0) {
7183955d011SMarcel Moolenaar 		t = lhs[0] != 0;
7193955d011SMarcel Moolenaar 		goto done;
7203955d011SMarcel Moolenaar 	    }
7213955d011SMarcel Moolenaar 	    /* Otherwise action default test ... */
7223955d011SMarcel Moolenaar 	    t = if_info->defProc(strlen(lhs), lhs) != if_info->doNot;
7233955d011SMarcel Moolenaar 	    goto done;
7243955d011SMarcel Moolenaar     }
7253955d011SMarcel Moolenaar 
7263955d011SMarcel Moolenaar     while (isspace((unsigned char)*condExpr))
7273955d011SMarcel Moolenaar 	condExpr++;
7283955d011SMarcel Moolenaar 
7293955d011SMarcel Moolenaar     if (*condExpr == '\0') {
7303955d011SMarcel Moolenaar 	Parse_Error(PARSE_WARNING,
7313955d011SMarcel Moolenaar 		    "Missing right-hand-side of operator");
7323955d011SMarcel Moolenaar 	goto done;
7333955d011SMarcel Moolenaar     }
7343955d011SMarcel Moolenaar 
73528a6bc81SSimon J. Gerraty     rhs = CondGetString(doEval, &rhsQuoted, &rhsFree, FALSE);
7363955d011SMarcel Moolenaar     if (!rhs)
7373955d011SMarcel Moolenaar 	goto done;
7383955d011SMarcel Moolenaar 
739*3841c287SSimon J. Gerraty     if (!doEval) {
740*3841c287SSimon J. Gerraty 	t = TOK_FALSE;
741*3841c287SSimon J. Gerraty 	goto done;
742*3841c287SSimon J. Gerraty     }
743*3841c287SSimon J. Gerraty 
7443955d011SMarcel Moolenaar     if (rhsQuoted || lhsQuoted) {
7453955d011SMarcel Moolenaar do_string_compare:
7463955d011SMarcel Moolenaar 	if (((*op != '!') && (*op != '=')) || (op[1] != '=')) {
7473955d011SMarcel Moolenaar 	    Parse_Error(PARSE_WARNING,
7483955d011SMarcel Moolenaar     "String comparison operator should be either == or !=");
7493955d011SMarcel Moolenaar 	    goto done;
7503955d011SMarcel Moolenaar 	}
7513955d011SMarcel Moolenaar 
7523955d011SMarcel Moolenaar 	if (DEBUG(COND)) {
7533955d011SMarcel Moolenaar 	    fprintf(debug_file, "lhs = \"%s\", rhs = \"%s\", op = %.2s\n",
7543955d011SMarcel Moolenaar 		   lhs, rhs, op);
7553955d011SMarcel Moolenaar 	}
7563955d011SMarcel Moolenaar 	/*
7573955d011SMarcel Moolenaar 	 * Null-terminate rhs and perform the comparison.
7583955d011SMarcel Moolenaar 	 * t is set to the result.
7593955d011SMarcel Moolenaar 	 */
7603955d011SMarcel Moolenaar 	if (*op == '=') {
7613955d011SMarcel Moolenaar 	    t = strcmp(lhs, rhs) == 0;
7623955d011SMarcel Moolenaar 	} else {
7633955d011SMarcel Moolenaar 	    t = strcmp(lhs, rhs) != 0;
7643955d011SMarcel Moolenaar 	}
7653955d011SMarcel Moolenaar     } else {
7663955d011SMarcel Moolenaar 	/*
7673955d011SMarcel Moolenaar 	 * rhs is either a float or an integer. Convert both the
7683955d011SMarcel Moolenaar 	 * lhs and the rhs to a double and compare the two.
7693955d011SMarcel Moolenaar 	 */
7703955d011SMarcel Moolenaar 
7713955d011SMarcel Moolenaar 	if (!CondCvtArg(lhs, &left) || !CondCvtArg(rhs, &right))
7723955d011SMarcel Moolenaar 	    goto do_string_compare;
7733955d011SMarcel Moolenaar 
7743955d011SMarcel Moolenaar 	if (DEBUG(COND)) {
7753955d011SMarcel Moolenaar 	    fprintf(debug_file, "left = %f, right = %f, op = %.2s\n", left,
7763955d011SMarcel Moolenaar 		   right, op);
7773955d011SMarcel Moolenaar 	}
7783955d011SMarcel Moolenaar 	switch(op[0]) {
7793955d011SMarcel Moolenaar 	case '!':
7803955d011SMarcel Moolenaar 	    if (op[1] != '=') {
7813955d011SMarcel Moolenaar 		Parse_Error(PARSE_WARNING,
7823955d011SMarcel Moolenaar 			    "Unknown operator");
7833955d011SMarcel Moolenaar 		goto done;
7843955d011SMarcel Moolenaar 	    }
7853955d011SMarcel Moolenaar 	    t = (left != right);
7863955d011SMarcel Moolenaar 	    break;
7873955d011SMarcel Moolenaar 	case '=':
7883955d011SMarcel Moolenaar 	    if (op[1] != '=') {
7893955d011SMarcel Moolenaar 		Parse_Error(PARSE_WARNING,
7903955d011SMarcel Moolenaar 			    "Unknown operator");
7913955d011SMarcel Moolenaar 		goto done;
7923955d011SMarcel Moolenaar 	    }
7933955d011SMarcel Moolenaar 	    t = (left == right);
7943955d011SMarcel Moolenaar 	    break;
7953955d011SMarcel Moolenaar 	case '<':
7963955d011SMarcel Moolenaar 	    if (op[1] == '=') {
7973955d011SMarcel Moolenaar 		t = (left <= right);
7983955d011SMarcel Moolenaar 	    } else {
7993955d011SMarcel Moolenaar 		t = (left < right);
8003955d011SMarcel Moolenaar 	    }
8013955d011SMarcel Moolenaar 	    break;
8023955d011SMarcel Moolenaar 	case '>':
8033955d011SMarcel Moolenaar 	    if (op[1] == '=') {
8043955d011SMarcel Moolenaar 		t = (left >= right);
8053955d011SMarcel Moolenaar 	    } else {
8063955d011SMarcel Moolenaar 		t = (left > right);
8073955d011SMarcel Moolenaar 	    }
8083955d011SMarcel Moolenaar 	    break;
8093955d011SMarcel Moolenaar 	}
8103955d011SMarcel Moolenaar     }
8113955d011SMarcel Moolenaar 
8123955d011SMarcel Moolenaar done:
8133955d011SMarcel Moolenaar     free(lhsFree);
8143955d011SMarcel Moolenaar     free(rhsFree);
8153955d011SMarcel Moolenaar     return t;
8163955d011SMarcel Moolenaar }
8173955d011SMarcel Moolenaar 
8183955d011SMarcel Moolenaar static int
819*3841c287SSimon J. Gerraty get_mpt_arg(Boolean doEval, char **linePtr, char **argPtr, const char *func MAKE_ATTR_UNUSED)
8203955d011SMarcel Moolenaar {
8213955d011SMarcel Moolenaar     /*
8223955d011SMarcel Moolenaar      * Use Var_Parse to parse the spec in parens and return
8233955d011SMarcel Moolenaar      * TOK_TRUE if the resulting string is empty.
8243955d011SMarcel Moolenaar      */
8253955d011SMarcel Moolenaar     int	    length;
8263955d011SMarcel Moolenaar     void    *freeIt;
8273955d011SMarcel Moolenaar     char    *val;
8283955d011SMarcel Moolenaar     char    *cp = *linePtr;
8293955d011SMarcel Moolenaar 
8303955d011SMarcel Moolenaar     /* We do all the work here and return the result as the length */
8313955d011SMarcel Moolenaar     *argPtr = NULL;
8323955d011SMarcel Moolenaar 
833*3841c287SSimon J. Gerraty     val = Var_Parse(cp - 1, VAR_CMD, doEval ? VARF_WANTRES : 0, &length, &freeIt);
8343955d011SMarcel Moolenaar     /*
8353955d011SMarcel Moolenaar      * Advance *linePtr to beyond the closing ). Note that
8363955d011SMarcel Moolenaar      * we subtract one because 'length' is calculated from 'cp - 1'.
8373955d011SMarcel Moolenaar      */
8383955d011SMarcel Moolenaar     *linePtr = cp - 1 + length;
8393955d011SMarcel Moolenaar 
8403955d011SMarcel Moolenaar     if (val == var_Error) {
8413955d011SMarcel Moolenaar 	free(freeIt);
8423955d011SMarcel Moolenaar 	return -1;
8433955d011SMarcel Moolenaar     }
8443955d011SMarcel Moolenaar 
8453955d011SMarcel Moolenaar     /* A variable is empty when it just contains spaces... 4/15/92, christos */
8463955d011SMarcel Moolenaar     while (isspace(*(unsigned char *)val))
8473955d011SMarcel Moolenaar 	val++;
8483955d011SMarcel Moolenaar 
8493955d011SMarcel Moolenaar     /*
8503955d011SMarcel Moolenaar      * For consistency with the other functions we can't generate the
8513955d011SMarcel Moolenaar      * true/false here.
8523955d011SMarcel Moolenaar      */
8533955d011SMarcel Moolenaar     length = *val ? 2 : 1;
8543955d011SMarcel Moolenaar     free(freeIt);
8553955d011SMarcel Moolenaar     return length;
8563955d011SMarcel Moolenaar }
8573955d011SMarcel Moolenaar 
8583955d011SMarcel Moolenaar static Boolean
8593955d011SMarcel Moolenaar CondDoEmpty(int arglen, const char *arg MAKE_ATTR_UNUSED)
8603955d011SMarcel Moolenaar {
8613955d011SMarcel Moolenaar     return arglen == 1;
8623955d011SMarcel Moolenaar }
8633955d011SMarcel Moolenaar 
8643955d011SMarcel Moolenaar static Token
8653955d011SMarcel Moolenaar compare_function(Boolean doEval)
8663955d011SMarcel Moolenaar {
8673955d011SMarcel Moolenaar     static const struct fn_def {
8683955d011SMarcel Moolenaar 	const char  *fn_name;
8693955d011SMarcel Moolenaar 	int         fn_name_len;
870*3841c287SSimon J. Gerraty         int         (*fn_getarg)(Boolean, char **, char **, const char *);
8713955d011SMarcel Moolenaar 	Boolean     (*fn_proc)(int, const char *);
8723955d011SMarcel Moolenaar     } fn_defs[] = {
8733955d011SMarcel Moolenaar 	{ "defined",   7, CondGetArg, CondDoDefined },
8743955d011SMarcel Moolenaar 	{ "make",      4, CondGetArg, CondDoMake },
8753955d011SMarcel Moolenaar 	{ "exists",    6, CondGetArg, CondDoExists },
8763955d011SMarcel Moolenaar 	{ "empty",     5, get_mpt_arg, CondDoEmpty },
8773955d011SMarcel Moolenaar 	{ "target",    6, CondGetArg, CondDoTarget },
8783955d011SMarcel Moolenaar 	{ "commands",  8, CondGetArg, CondDoCommands },
8793955d011SMarcel Moolenaar 	{ NULL,        0, NULL, NULL },
8803955d011SMarcel Moolenaar     };
8813955d011SMarcel Moolenaar     const struct fn_def *fn_def;
8823955d011SMarcel Moolenaar     Token	t;
8833955d011SMarcel Moolenaar     char	*arg = NULL;
8843955d011SMarcel Moolenaar     int	arglen;
8853955d011SMarcel Moolenaar     char *cp = condExpr;
8863955d011SMarcel Moolenaar     char *cp1;
8873955d011SMarcel Moolenaar 
8883955d011SMarcel Moolenaar     for (fn_def = fn_defs; fn_def->fn_name != NULL; fn_def++) {
8893955d011SMarcel Moolenaar 	if (!istoken(cp, fn_def->fn_name, fn_def->fn_name_len))
8903955d011SMarcel Moolenaar 	    continue;
8913955d011SMarcel Moolenaar 	cp += fn_def->fn_name_len;
8923955d011SMarcel Moolenaar 	/* There can only be whitespace before the '(' */
8933955d011SMarcel Moolenaar 	while (isspace(*(unsigned char *)cp))
8943955d011SMarcel Moolenaar 	    cp++;
8953955d011SMarcel Moolenaar 	if (*cp != '(')
8963955d011SMarcel Moolenaar 	    break;
8973955d011SMarcel Moolenaar 
898*3841c287SSimon J. Gerraty 	arglen = fn_def->fn_getarg(doEval, &cp, &arg, fn_def->fn_name);
8993955d011SMarcel Moolenaar 	if (arglen <= 0) {
9003955d011SMarcel Moolenaar 	    condExpr = cp;
9013955d011SMarcel Moolenaar 	    return arglen < 0 ? TOK_ERROR : TOK_FALSE;
9023955d011SMarcel Moolenaar 	}
9033955d011SMarcel Moolenaar 	/* Evaluate the argument using the required function. */
9043955d011SMarcel Moolenaar 	t = !doEval || fn_def->fn_proc(arglen, arg);
9053955d011SMarcel Moolenaar 	free(arg);
9063955d011SMarcel Moolenaar 	condExpr = cp;
9073955d011SMarcel Moolenaar 	return t;
9083955d011SMarcel Moolenaar     }
9093955d011SMarcel Moolenaar 
9103955d011SMarcel Moolenaar     /* Push anything numeric through the compare expression */
9113955d011SMarcel Moolenaar     cp = condExpr;
9123955d011SMarcel Moolenaar     if (isdigit((unsigned char)cp[0]) || strchr("+-", cp[0]))
9133955d011SMarcel Moolenaar 	return compare_expression(doEval);
9143955d011SMarcel Moolenaar 
9153955d011SMarcel Moolenaar     /*
9163955d011SMarcel Moolenaar      * Most likely we have a naked token to apply the default function to.
9173955d011SMarcel Moolenaar      * However ".if a == b" gets here when the "a" is unquoted and doesn't
9183955d011SMarcel Moolenaar      * start with a '$'. This surprises people.
9193955d011SMarcel Moolenaar      * If what follows the function argument is a '=' or '!' then the syntax
9203955d011SMarcel Moolenaar      * would be invalid if we did "defined(a)" - so instead treat as an
9213955d011SMarcel Moolenaar      * expression.
9223955d011SMarcel Moolenaar      */
923*3841c287SSimon J. Gerraty     arglen = CondGetArg(doEval, &cp, &arg, NULL);
9243955d011SMarcel Moolenaar     for (cp1 = cp; isspace(*(unsigned char *)cp1); cp1++)
9253955d011SMarcel Moolenaar 	continue;
9263955d011SMarcel Moolenaar     if (*cp1 == '=' || *cp1 == '!')
9273955d011SMarcel Moolenaar 	return compare_expression(doEval);
9283955d011SMarcel Moolenaar     condExpr = cp;
9293955d011SMarcel Moolenaar 
9303955d011SMarcel Moolenaar     /*
9313955d011SMarcel Moolenaar      * Evaluate the argument using the default function.
9323955d011SMarcel Moolenaar      * This path always treats .if as .ifdef. To get here the character
9333955d011SMarcel Moolenaar      * after .if must have been taken literally, so the argument cannot
9343955d011SMarcel Moolenaar      * be empty - even if it contained a variable expansion.
9353955d011SMarcel Moolenaar      */
9363955d011SMarcel Moolenaar     t = !doEval || if_info->defProc(arglen, arg) != if_info->doNot;
9373955d011SMarcel Moolenaar     free(arg);
9383955d011SMarcel Moolenaar     return t;
9393955d011SMarcel Moolenaar }
9403955d011SMarcel Moolenaar 
9413955d011SMarcel Moolenaar static Token
9423955d011SMarcel Moolenaar CondToken(Boolean doEval)
9433955d011SMarcel Moolenaar {
9443955d011SMarcel Moolenaar     Token t;
9453955d011SMarcel Moolenaar 
9463955d011SMarcel Moolenaar     t = condPushBack;
9473955d011SMarcel Moolenaar     if (t != TOK_NONE) {
9483955d011SMarcel Moolenaar 	condPushBack = TOK_NONE;
9493955d011SMarcel Moolenaar 	return t;
9503955d011SMarcel Moolenaar     }
9513955d011SMarcel Moolenaar 
9523955d011SMarcel Moolenaar     while (*condExpr == ' ' || *condExpr == '\t') {
9533955d011SMarcel Moolenaar 	condExpr++;
9543955d011SMarcel Moolenaar     }
9553955d011SMarcel Moolenaar 
9563955d011SMarcel Moolenaar     switch (*condExpr) {
9573955d011SMarcel Moolenaar 
9583955d011SMarcel Moolenaar     case '(':
9593955d011SMarcel Moolenaar 	condExpr++;
9603955d011SMarcel Moolenaar 	return TOK_LPAREN;
9613955d011SMarcel Moolenaar 
9623955d011SMarcel Moolenaar     case ')':
9633955d011SMarcel Moolenaar 	condExpr++;
9643955d011SMarcel Moolenaar 	return TOK_RPAREN;
9653955d011SMarcel Moolenaar 
9663955d011SMarcel Moolenaar     case '|':
9673955d011SMarcel Moolenaar 	if (condExpr[1] == '|') {
9683955d011SMarcel Moolenaar 	    condExpr++;
9693955d011SMarcel Moolenaar 	}
9703955d011SMarcel Moolenaar 	condExpr++;
9713955d011SMarcel Moolenaar 	return TOK_OR;
9723955d011SMarcel Moolenaar 
9733955d011SMarcel Moolenaar     case '&':
9743955d011SMarcel Moolenaar 	if (condExpr[1] == '&') {
9753955d011SMarcel Moolenaar 	    condExpr++;
9763955d011SMarcel Moolenaar 	}
9773955d011SMarcel Moolenaar 	condExpr++;
9783955d011SMarcel Moolenaar 	return TOK_AND;
9793955d011SMarcel Moolenaar 
9803955d011SMarcel Moolenaar     case '!':
9813955d011SMarcel Moolenaar 	condExpr++;
9823955d011SMarcel Moolenaar 	return TOK_NOT;
9833955d011SMarcel Moolenaar 
9843955d011SMarcel Moolenaar     case '#':
9853955d011SMarcel Moolenaar     case '\n':
9863955d011SMarcel Moolenaar     case '\0':
9873955d011SMarcel Moolenaar 	return TOK_EOF;
9883955d011SMarcel Moolenaar 
9893955d011SMarcel Moolenaar     case '"':
9903955d011SMarcel Moolenaar     case '$':
9913955d011SMarcel Moolenaar 	return compare_expression(doEval);
9923955d011SMarcel Moolenaar 
9933955d011SMarcel Moolenaar     default:
9943955d011SMarcel Moolenaar 	return compare_function(doEval);
9953955d011SMarcel Moolenaar     }
9963955d011SMarcel Moolenaar }
9973955d011SMarcel Moolenaar 
9983955d011SMarcel Moolenaar /*-
9993955d011SMarcel Moolenaar  *-----------------------------------------------------------------------
10003955d011SMarcel Moolenaar  * CondT --
10013955d011SMarcel Moolenaar  *	Parse a single term in the expression. This consists of a terminal
10023955d011SMarcel Moolenaar  *	symbol or TOK_NOT and a terminal symbol (not including the binary
10033955d011SMarcel Moolenaar  *	operators):
10043955d011SMarcel Moolenaar  *	    T -> defined(variable) | make(target) | exists(file) | symbol
10053955d011SMarcel Moolenaar  *	    T -> ! T | ( E )
10063955d011SMarcel Moolenaar  *
10073955d011SMarcel Moolenaar  * Results:
10083955d011SMarcel Moolenaar  *	TOK_TRUE, TOK_FALSE or TOK_ERROR.
10093955d011SMarcel Moolenaar  *
10103955d011SMarcel Moolenaar  * Side Effects:
10113955d011SMarcel Moolenaar  *	Tokens are consumed.
10123955d011SMarcel Moolenaar  *
10133955d011SMarcel Moolenaar  *-----------------------------------------------------------------------
10143955d011SMarcel Moolenaar  */
10153955d011SMarcel Moolenaar static Token
10163955d011SMarcel Moolenaar CondT(Boolean doEval)
10173955d011SMarcel Moolenaar {
10183955d011SMarcel Moolenaar     Token   t;
10193955d011SMarcel Moolenaar 
10203955d011SMarcel Moolenaar     t = CondToken(doEval);
10213955d011SMarcel Moolenaar 
10223955d011SMarcel Moolenaar     if (t == TOK_EOF) {
10233955d011SMarcel Moolenaar 	/*
10243955d011SMarcel Moolenaar 	 * If we reached the end of the expression, the expression
10253955d011SMarcel Moolenaar 	 * is malformed...
10263955d011SMarcel Moolenaar 	 */
10273955d011SMarcel Moolenaar 	t = TOK_ERROR;
10283955d011SMarcel Moolenaar     } else if (t == TOK_LPAREN) {
10293955d011SMarcel Moolenaar 	/*
10303955d011SMarcel Moolenaar 	 * T -> ( E )
10313955d011SMarcel Moolenaar 	 */
10323955d011SMarcel Moolenaar 	t = CondE(doEval);
10333955d011SMarcel Moolenaar 	if (t != TOK_ERROR) {
10343955d011SMarcel Moolenaar 	    if (CondToken(doEval) != TOK_RPAREN) {
10353955d011SMarcel Moolenaar 		t = TOK_ERROR;
10363955d011SMarcel Moolenaar 	    }
10373955d011SMarcel Moolenaar 	}
10383955d011SMarcel Moolenaar     } else if (t == TOK_NOT) {
10393955d011SMarcel Moolenaar 	t = CondT(doEval);
10403955d011SMarcel Moolenaar 	if (t == TOK_TRUE) {
10413955d011SMarcel Moolenaar 	    t = TOK_FALSE;
10423955d011SMarcel Moolenaar 	} else if (t == TOK_FALSE) {
10433955d011SMarcel Moolenaar 	    t = TOK_TRUE;
10443955d011SMarcel Moolenaar 	}
10453955d011SMarcel Moolenaar     }
1046*3841c287SSimon J. Gerraty     return t;
10473955d011SMarcel Moolenaar }
10483955d011SMarcel Moolenaar 
10493955d011SMarcel Moolenaar /*-
10503955d011SMarcel Moolenaar  *-----------------------------------------------------------------------
10513955d011SMarcel Moolenaar  * CondF --
10523955d011SMarcel Moolenaar  *	Parse a conjunctive factor (nice name, wot?)
10533955d011SMarcel Moolenaar  *	    F -> T && F | T
10543955d011SMarcel Moolenaar  *
10553955d011SMarcel Moolenaar  * Results:
10563955d011SMarcel Moolenaar  *	TOK_TRUE, TOK_FALSE or TOK_ERROR
10573955d011SMarcel Moolenaar  *
10583955d011SMarcel Moolenaar  * Side Effects:
10593955d011SMarcel Moolenaar  *	Tokens are consumed.
10603955d011SMarcel Moolenaar  *
10613955d011SMarcel Moolenaar  *-----------------------------------------------------------------------
10623955d011SMarcel Moolenaar  */
10633955d011SMarcel Moolenaar static Token
10643955d011SMarcel Moolenaar CondF(Boolean doEval)
10653955d011SMarcel Moolenaar {
10663955d011SMarcel Moolenaar     Token   l, o;
10673955d011SMarcel Moolenaar 
10683955d011SMarcel Moolenaar     l = CondT(doEval);
10693955d011SMarcel Moolenaar     if (l != TOK_ERROR) {
10703955d011SMarcel Moolenaar 	o = CondToken(doEval);
10713955d011SMarcel Moolenaar 
10723955d011SMarcel Moolenaar 	if (o == TOK_AND) {
10733955d011SMarcel Moolenaar 	    /*
10743955d011SMarcel Moolenaar 	     * F -> T && F
10753955d011SMarcel Moolenaar 	     *
10763955d011SMarcel Moolenaar 	     * If T is TOK_FALSE, the whole thing will be TOK_FALSE, but we have to
10773955d011SMarcel Moolenaar 	     * parse the r.h.s. anyway (to throw it away).
10783955d011SMarcel Moolenaar 	     * If T is TOK_TRUE, the result is the r.h.s., be it an TOK_ERROR or no.
10793955d011SMarcel Moolenaar 	     */
10803955d011SMarcel Moolenaar 	    if (l == TOK_TRUE) {
10813955d011SMarcel Moolenaar 		l = CondF(doEval);
10823955d011SMarcel Moolenaar 	    } else {
10833955d011SMarcel Moolenaar 		(void)CondF(FALSE);
10843955d011SMarcel Moolenaar 	    }
10853955d011SMarcel Moolenaar 	} else {
10863955d011SMarcel Moolenaar 	    /*
10873955d011SMarcel Moolenaar 	     * F -> T
10883955d011SMarcel Moolenaar 	     */
10893955d011SMarcel Moolenaar 	    CondPushBack(o);
10903955d011SMarcel Moolenaar 	}
10913955d011SMarcel Moolenaar     }
1092*3841c287SSimon J. Gerraty     return l;
10933955d011SMarcel Moolenaar }
10943955d011SMarcel Moolenaar 
10953955d011SMarcel Moolenaar /*-
10963955d011SMarcel Moolenaar  *-----------------------------------------------------------------------
10973955d011SMarcel Moolenaar  * CondE --
10983955d011SMarcel Moolenaar  *	Main expression production.
10993955d011SMarcel Moolenaar  *	    E -> F || E | F
11003955d011SMarcel Moolenaar  *
11013955d011SMarcel Moolenaar  * Results:
11023955d011SMarcel Moolenaar  *	TOK_TRUE, TOK_FALSE or TOK_ERROR.
11033955d011SMarcel Moolenaar  *
11043955d011SMarcel Moolenaar  * Side Effects:
11053955d011SMarcel Moolenaar  *	Tokens are, of course, consumed.
11063955d011SMarcel Moolenaar  *
11073955d011SMarcel Moolenaar  *-----------------------------------------------------------------------
11083955d011SMarcel Moolenaar  */
11093955d011SMarcel Moolenaar static Token
11103955d011SMarcel Moolenaar CondE(Boolean doEval)
11113955d011SMarcel Moolenaar {
11123955d011SMarcel Moolenaar     Token   l, o;
11133955d011SMarcel Moolenaar 
11143955d011SMarcel Moolenaar     l = CondF(doEval);
11153955d011SMarcel Moolenaar     if (l != TOK_ERROR) {
11163955d011SMarcel Moolenaar 	o = CondToken(doEval);
11173955d011SMarcel Moolenaar 
11183955d011SMarcel Moolenaar 	if (o == TOK_OR) {
11193955d011SMarcel Moolenaar 	    /*
11203955d011SMarcel Moolenaar 	     * E -> F || E
11213955d011SMarcel Moolenaar 	     *
11223955d011SMarcel Moolenaar 	     * A similar thing occurs for ||, except that here we make sure
11233955d011SMarcel Moolenaar 	     * the l.h.s. is TOK_FALSE before we bother to evaluate the r.h.s.
11243955d011SMarcel Moolenaar 	     * Once again, if l is TOK_FALSE, the result is the r.h.s. and once
11253955d011SMarcel Moolenaar 	     * again if l is TOK_TRUE, we parse the r.h.s. to throw it away.
11263955d011SMarcel Moolenaar 	     */
11273955d011SMarcel Moolenaar 	    if (l == TOK_FALSE) {
11283955d011SMarcel Moolenaar 		l = CondE(doEval);
11293955d011SMarcel Moolenaar 	    } else {
11303955d011SMarcel Moolenaar 		(void)CondE(FALSE);
11313955d011SMarcel Moolenaar 	    }
11323955d011SMarcel Moolenaar 	} else {
11333955d011SMarcel Moolenaar 	    /*
11343955d011SMarcel Moolenaar 	     * E -> F
11353955d011SMarcel Moolenaar 	     */
11363955d011SMarcel Moolenaar 	    CondPushBack(o);
11373955d011SMarcel Moolenaar 	}
11383955d011SMarcel Moolenaar     }
1139*3841c287SSimon J. Gerraty     return l;
11403955d011SMarcel Moolenaar }
11413955d011SMarcel Moolenaar 
11423955d011SMarcel Moolenaar /*-
11433955d011SMarcel Moolenaar  *-----------------------------------------------------------------------
11443955d011SMarcel Moolenaar  * Cond_EvalExpression --
11453955d011SMarcel Moolenaar  *	Evaluate an expression in the passed line. The expression
11463955d011SMarcel Moolenaar  *	consists of &&, ||, !, make(target), defined(variable)
11473955d011SMarcel Moolenaar  *	and parenthetical groupings thereof.
11483955d011SMarcel Moolenaar  *
11493955d011SMarcel Moolenaar  * Results:
11503955d011SMarcel Moolenaar  *	COND_PARSE	if the condition was valid grammatically
11513955d011SMarcel Moolenaar  *	COND_INVALID  	if not a valid conditional.
11523955d011SMarcel Moolenaar  *
11533955d011SMarcel Moolenaar  *	(*value) is set to the boolean value of the condition
11543955d011SMarcel Moolenaar  *
11553955d011SMarcel Moolenaar  * Side Effects:
11563955d011SMarcel Moolenaar  *	None.
11573955d011SMarcel Moolenaar  *
11583955d011SMarcel Moolenaar  *-----------------------------------------------------------------------
11593955d011SMarcel Moolenaar  */
11603955d011SMarcel Moolenaar int
116128a6bc81SSimon J. Gerraty Cond_EvalExpression(const struct If *info, char *line, Boolean *value, int eprint, Boolean strictLHS)
11623955d011SMarcel Moolenaar {
11633955d011SMarcel Moolenaar     static const struct If *dflt_info;
11643955d011SMarcel Moolenaar     const struct If *sv_if_info = if_info;
11653955d011SMarcel Moolenaar     char *sv_condExpr = condExpr;
11663955d011SMarcel Moolenaar     Token sv_condPushBack = condPushBack;
11673955d011SMarcel Moolenaar     int rval;
11683955d011SMarcel Moolenaar 
116928a6bc81SSimon J. Gerraty     lhsStrict = strictLHS;
117028a6bc81SSimon J. Gerraty 
11713955d011SMarcel Moolenaar     while (*line == ' ' || *line == '\t')
11723955d011SMarcel Moolenaar 	line++;
11733955d011SMarcel Moolenaar 
11743955d011SMarcel Moolenaar     if (info == NULL && (info = dflt_info) == NULL) {
11753955d011SMarcel Moolenaar 	/* Scan for the entry for .if - it can't be first */
11763955d011SMarcel Moolenaar 	for (info = ifs; ; info++)
11773955d011SMarcel Moolenaar 	    if (info->form[0] == 0)
11783955d011SMarcel Moolenaar 		break;
11793955d011SMarcel Moolenaar 	dflt_info = info;
11803955d011SMarcel Moolenaar     }
1181e1cee40dSSimon J. Gerraty     assert(info != NULL);
11823955d011SMarcel Moolenaar 
1183e1cee40dSSimon J. Gerraty     if_info = info;
11843955d011SMarcel Moolenaar     condExpr = line;
11853955d011SMarcel Moolenaar     condPushBack = TOK_NONE;
11863955d011SMarcel Moolenaar 
11873955d011SMarcel Moolenaar     rval = do_Cond_EvalExpression(value);
11883955d011SMarcel Moolenaar 
11893955d011SMarcel Moolenaar     if (rval == COND_INVALID && eprint)
11903955d011SMarcel Moolenaar 	Parse_Error(PARSE_FATAL, "Malformed conditional (%s)", line);
11913955d011SMarcel Moolenaar 
11923955d011SMarcel Moolenaar     if_info = sv_if_info;
11933955d011SMarcel Moolenaar     condExpr = sv_condExpr;
11943955d011SMarcel Moolenaar     condPushBack = sv_condPushBack;
11953955d011SMarcel Moolenaar 
11963955d011SMarcel Moolenaar     return rval;
11973955d011SMarcel Moolenaar }
11983955d011SMarcel Moolenaar 
11993955d011SMarcel Moolenaar static int
12003955d011SMarcel Moolenaar do_Cond_EvalExpression(Boolean *value)
12013955d011SMarcel Moolenaar {
12023955d011SMarcel Moolenaar 
12033955d011SMarcel Moolenaar     switch (CondE(TRUE)) {
12043955d011SMarcel Moolenaar     case TOK_TRUE:
12053955d011SMarcel Moolenaar 	if (CondToken(TRUE) == TOK_EOF) {
12063955d011SMarcel Moolenaar 	    *value = TRUE;
12073955d011SMarcel Moolenaar 	    return COND_PARSE;
12083955d011SMarcel Moolenaar 	}
12093955d011SMarcel Moolenaar 	break;
12103955d011SMarcel Moolenaar     case TOK_FALSE:
12113955d011SMarcel Moolenaar 	if (CondToken(TRUE) == TOK_EOF) {
12123955d011SMarcel Moolenaar 	    *value = FALSE;
12133955d011SMarcel Moolenaar 	    return COND_PARSE;
12143955d011SMarcel Moolenaar 	}
12153955d011SMarcel Moolenaar 	break;
12163955d011SMarcel Moolenaar     default:
12173955d011SMarcel Moolenaar     case TOK_ERROR:
12183955d011SMarcel Moolenaar 	break;
12193955d011SMarcel Moolenaar     }
12203955d011SMarcel Moolenaar 
12213955d011SMarcel Moolenaar     return COND_INVALID;
12223955d011SMarcel Moolenaar }
12233955d011SMarcel Moolenaar 
12243955d011SMarcel Moolenaar 
12253955d011SMarcel Moolenaar /*-
12263955d011SMarcel Moolenaar  *-----------------------------------------------------------------------
12273955d011SMarcel Moolenaar  * Cond_Eval --
12283955d011SMarcel Moolenaar  *	Evaluate the conditional in the passed line. The line
12293955d011SMarcel Moolenaar  *	looks like this:
12303955d011SMarcel Moolenaar  *	    .<cond-type> <expr>
12313955d011SMarcel Moolenaar  *	where <cond-type> is any of if, ifmake, ifnmake, ifdef,
12323955d011SMarcel Moolenaar  *	ifndef, elif, elifmake, elifnmake, elifdef, elifndef
12333955d011SMarcel Moolenaar  *	and <expr> consists of &&, ||, !, make(target), defined(variable)
12343955d011SMarcel Moolenaar  *	and parenthetical groupings thereof.
12353955d011SMarcel Moolenaar  *
12363955d011SMarcel Moolenaar  * Input:
12373955d011SMarcel Moolenaar  *	line		Line to parse
12383955d011SMarcel Moolenaar  *
12393955d011SMarcel Moolenaar  * Results:
12403955d011SMarcel Moolenaar  *	COND_PARSE	if should parse lines after the conditional
12413955d011SMarcel Moolenaar  *	COND_SKIP	if should skip lines after the conditional
12423955d011SMarcel Moolenaar  *	COND_INVALID  	if not a valid conditional.
12433955d011SMarcel Moolenaar  *
12443955d011SMarcel Moolenaar  * Side Effects:
12453955d011SMarcel Moolenaar  *	None.
12463955d011SMarcel Moolenaar  *
12473955d011SMarcel Moolenaar  * Note that the states IF_ACTIVE and ELSE_ACTIVE are only different in order
12483955d011SMarcel Moolenaar  * to detect splurious .else lines (as are SKIP_TO_ELSE and SKIP_TO_ENDIF)
12493955d011SMarcel Moolenaar  * otherwise .else could be treated as '.elif 1'.
12503955d011SMarcel Moolenaar  *
12513955d011SMarcel Moolenaar  *-----------------------------------------------------------------------
12523955d011SMarcel Moolenaar  */
12533955d011SMarcel Moolenaar int
12543955d011SMarcel Moolenaar Cond_Eval(char *line)
12553955d011SMarcel Moolenaar {
12563955d011SMarcel Moolenaar #define	    MAXIF      128	/* maximum depth of .if'ing */
125759a02420SSimon J. Gerraty #define	    MAXIF_BUMP  32	/* how much to grow by */
12583955d011SMarcel Moolenaar     enum if_states {
12593955d011SMarcel Moolenaar 	IF_ACTIVE,		/* .if or .elif part active */
12603955d011SMarcel Moolenaar 	ELSE_ACTIVE,		/* .else part active */
12613955d011SMarcel Moolenaar 	SEARCH_FOR_ELIF,	/* searching for .elif/else to execute */
12623955d011SMarcel Moolenaar 	SKIP_TO_ELSE,           /* has been true, but not seen '.else' */
12633955d011SMarcel Moolenaar 	SKIP_TO_ENDIF		/* nothing else to execute */
12643955d011SMarcel Moolenaar     };
126559a02420SSimon J. Gerraty     static enum if_states *cond_state = NULL;
126659a02420SSimon J. Gerraty     static unsigned int max_if_depth = MAXIF;
12673955d011SMarcel Moolenaar 
12683955d011SMarcel Moolenaar     const struct If *ifp;
12693955d011SMarcel Moolenaar     Boolean 	    isElif;
12703955d011SMarcel Moolenaar     Boolean 	    value;
12713955d011SMarcel Moolenaar     int	    	    level;  	/* Level at which to report errors. */
12723955d011SMarcel Moolenaar     enum if_states  state;
12733955d011SMarcel Moolenaar 
12743955d011SMarcel Moolenaar     level = PARSE_FATAL;
127559a02420SSimon J. Gerraty     if (!cond_state) {
127659a02420SSimon J. Gerraty 	cond_state = bmake_malloc(max_if_depth * sizeof(*cond_state));
127759a02420SSimon J. Gerraty 	cond_state[0] = IF_ACTIVE;
127859a02420SSimon J. Gerraty     }
12793955d011SMarcel Moolenaar     /* skip leading character (the '.') and any whitespace */
12803955d011SMarcel Moolenaar     for (line++; *line == ' ' || *line == '\t'; line++)
12813955d011SMarcel Moolenaar 	continue;
12823955d011SMarcel Moolenaar 
12833955d011SMarcel Moolenaar     /* Find what type of if we're dealing with.  */
12843955d011SMarcel Moolenaar     if (line[0] == 'e') {
12853955d011SMarcel Moolenaar 	if (line[1] != 'l') {
12863955d011SMarcel Moolenaar 	    if (!istoken(line + 1, "ndif", 4))
12873955d011SMarcel Moolenaar 		return COND_INVALID;
12883955d011SMarcel Moolenaar 	    /* End of conditional section */
12893955d011SMarcel Moolenaar 	    if (cond_depth == cond_min_depth) {
12903955d011SMarcel Moolenaar 		Parse_Error(level, "if-less endif");
12913955d011SMarcel Moolenaar 		return COND_PARSE;
12923955d011SMarcel Moolenaar 	    }
12933955d011SMarcel Moolenaar 	    /* Return state for previous conditional */
12943955d011SMarcel Moolenaar 	    cond_depth--;
12953955d011SMarcel Moolenaar 	    return cond_state[cond_depth] <= ELSE_ACTIVE ? COND_PARSE : COND_SKIP;
12963955d011SMarcel Moolenaar 	}
12973955d011SMarcel Moolenaar 
12983955d011SMarcel Moolenaar 	/* Quite likely this is 'else' or 'elif' */
12993955d011SMarcel Moolenaar 	line += 2;
13003955d011SMarcel Moolenaar 	if (istoken(line, "se", 2)) {
13013955d011SMarcel Moolenaar 	    /* It is else... */
13023955d011SMarcel Moolenaar 	    if (cond_depth == cond_min_depth) {
13033955d011SMarcel Moolenaar 		Parse_Error(level, "if-less else");
13043955d011SMarcel Moolenaar 		return COND_PARSE;
13053955d011SMarcel Moolenaar 	    }
13063955d011SMarcel Moolenaar 
13073955d011SMarcel Moolenaar 	    state = cond_state[cond_depth];
13083955d011SMarcel Moolenaar 	    switch (state) {
13093955d011SMarcel Moolenaar 	    case SEARCH_FOR_ELIF:
13103955d011SMarcel Moolenaar 		state = ELSE_ACTIVE;
13113955d011SMarcel Moolenaar 		break;
13123955d011SMarcel Moolenaar 	    case ELSE_ACTIVE:
13133955d011SMarcel Moolenaar 	    case SKIP_TO_ENDIF:
13143955d011SMarcel Moolenaar 		Parse_Error(PARSE_WARNING, "extra else");
13153955d011SMarcel Moolenaar 		/* FALLTHROUGH */
13163955d011SMarcel Moolenaar 	    default:
13173955d011SMarcel Moolenaar 	    case IF_ACTIVE:
13183955d011SMarcel Moolenaar 	    case SKIP_TO_ELSE:
13193955d011SMarcel Moolenaar 		state = SKIP_TO_ENDIF;
13203955d011SMarcel Moolenaar 		break;
13213955d011SMarcel Moolenaar 	    }
13223955d011SMarcel Moolenaar 	    cond_state[cond_depth] = state;
13233955d011SMarcel Moolenaar 	    return state <= ELSE_ACTIVE ? COND_PARSE : COND_SKIP;
13243955d011SMarcel Moolenaar 	}
13253955d011SMarcel Moolenaar 	/* Assume for now it is an elif */
13263955d011SMarcel Moolenaar 	isElif = TRUE;
13273955d011SMarcel Moolenaar     } else
13283955d011SMarcel Moolenaar 	isElif = FALSE;
13293955d011SMarcel Moolenaar 
13303955d011SMarcel Moolenaar     if (line[0] != 'i' || line[1] != 'f')
13313955d011SMarcel Moolenaar 	/* Not an ifxxx or elifxxx line */
13323955d011SMarcel Moolenaar 	return COND_INVALID;
13333955d011SMarcel Moolenaar 
13343955d011SMarcel Moolenaar     /*
13353955d011SMarcel Moolenaar      * Figure out what sort of conditional it is -- what its default
13363955d011SMarcel Moolenaar      * function is, etc. -- by looking in the table of valid "ifs"
13373955d011SMarcel Moolenaar      */
13383955d011SMarcel Moolenaar     line += 2;
13393955d011SMarcel Moolenaar     for (ifp = ifs; ; ifp++) {
13403955d011SMarcel Moolenaar 	if (ifp->form == NULL)
13413955d011SMarcel Moolenaar 	    return COND_INVALID;
13423955d011SMarcel Moolenaar 	if (istoken(ifp->form, line, ifp->formlen)) {
13433955d011SMarcel Moolenaar 	    line += ifp->formlen;
13443955d011SMarcel Moolenaar 	    break;
13453955d011SMarcel Moolenaar 	}
13463955d011SMarcel Moolenaar     }
13473955d011SMarcel Moolenaar 
13483955d011SMarcel Moolenaar     /* Now we know what sort of 'if' it is... */
13493955d011SMarcel Moolenaar 
13503955d011SMarcel Moolenaar     if (isElif) {
13513955d011SMarcel Moolenaar 	if (cond_depth == cond_min_depth) {
13523955d011SMarcel Moolenaar 	    Parse_Error(level, "if-less elif");
13533955d011SMarcel Moolenaar 	    return COND_PARSE;
13543955d011SMarcel Moolenaar 	}
13553955d011SMarcel Moolenaar 	state = cond_state[cond_depth];
13563955d011SMarcel Moolenaar 	if (state == SKIP_TO_ENDIF || state == ELSE_ACTIVE) {
13573955d011SMarcel Moolenaar 	    Parse_Error(PARSE_WARNING, "extra elif");
13583955d011SMarcel Moolenaar 	    cond_state[cond_depth] = SKIP_TO_ENDIF;
13593955d011SMarcel Moolenaar 	    return COND_SKIP;
13603955d011SMarcel Moolenaar 	}
13613955d011SMarcel Moolenaar 	if (state != SEARCH_FOR_ELIF) {
13623955d011SMarcel Moolenaar 	    /* Either just finished the 'true' block, or already SKIP_TO_ELSE */
13633955d011SMarcel Moolenaar 	    cond_state[cond_depth] = SKIP_TO_ELSE;
13643955d011SMarcel Moolenaar 	    return COND_SKIP;
13653955d011SMarcel Moolenaar 	}
13663955d011SMarcel Moolenaar     } else {
13673955d011SMarcel Moolenaar 	/* Normal .if */
136859a02420SSimon J. Gerraty 	if (cond_depth + 1 >= max_if_depth) {
136959a02420SSimon J. Gerraty 	    /*
137059a02420SSimon J. Gerraty 	     * This is rare, but not impossible.
137159a02420SSimon J. Gerraty 	     * In meta mode, dirdeps.mk (only runs at level 0)
137259a02420SSimon J. Gerraty 	     * can need more than the default.
137359a02420SSimon J. Gerraty 	     */
137459a02420SSimon J. Gerraty 	    max_if_depth += MAXIF_BUMP;
137559a02420SSimon J. Gerraty 	    cond_state = bmake_realloc(cond_state, max_if_depth *
137659a02420SSimon J. Gerraty 		sizeof(*cond_state));
13773955d011SMarcel Moolenaar 	}
13783955d011SMarcel Moolenaar 	state = cond_state[cond_depth];
13793955d011SMarcel Moolenaar 	cond_depth++;
13803955d011SMarcel Moolenaar 	if (state > ELSE_ACTIVE) {
13813955d011SMarcel Moolenaar 	    /* If we aren't parsing the data, treat as always false */
13823955d011SMarcel Moolenaar 	    cond_state[cond_depth] = SKIP_TO_ELSE;
13833955d011SMarcel Moolenaar 	    return COND_SKIP;
13843955d011SMarcel Moolenaar 	}
13853955d011SMarcel Moolenaar     }
13863955d011SMarcel Moolenaar 
13873955d011SMarcel Moolenaar     /* And evaluate the conditional expresssion */
138828a6bc81SSimon J. Gerraty     if (Cond_EvalExpression(ifp, line, &value, 1, TRUE) == COND_INVALID) {
13893955d011SMarcel Moolenaar 	/* Syntax error in conditional, error message already output. */
13903955d011SMarcel Moolenaar 	/* Skip everything to matching .endif */
13913955d011SMarcel Moolenaar 	cond_state[cond_depth] = SKIP_TO_ELSE;
13923955d011SMarcel Moolenaar 	return COND_SKIP;
13933955d011SMarcel Moolenaar     }
13943955d011SMarcel Moolenaar 
13953955d011SMarcel Moolenaar     if (!value) {
13963955d011SMarcel Moolenaar 	cond_state[cond_depth] = SEARCH_FOR_ELIF;
13973955d011SMarcel Moolenaar 	return COND_SKIP;
13983955d011SMarcel Moolenaar     }
13993955d011SMarcel Moolenaar     cond_state[cond_depth] = IF_ACTIVE;
14003955d011SMarcel Moolenaar     return COND_PARSE;
14013955d011SMarcel Moolenaar }
14023955d011SMarcel Moolenaar 
14033955d011SMarcel Moolenaar 
14043955d011SMarcel Moolenaar 
14053955d011SMarcel Moolenaar /*-
14063955d011SMarcel Moolenaar  *-----------------------------------------------------------------------
14073955d011SMarcel Moolenaar  * Cond_End --
14083955d011SMarcel Moolenaar  *	Make sure everything's clean at the end of a makefile.
14093955d011SMarcel Moolenaar  *
14103955d011SMarcel Moolenaar  * Results:
14113955d011SMarcel Moolenaar  *	None.
14123955d011SMarcel Moolenaar  *
14133955d011SMarcel Moolenaar  * Side Effects:
14143955d011SMarcel Moolenaar  *	Parse_Error will be called if open conditionals are around.
14153955d011SMarcel Moolenaar  *
14163955d011SMarcel Moolenaar  *-----------------------------------------------------------------------
14173955d011SMarcel Moolenaar  */
14183955d011SMarcel Moolenaar void
14193955d011SMarcel Moolenaar Cond_restore_depth(unsigned int saved_depth)
14203955d011SMarcel Moolenaar {
14213955d011SMarcel Moolenaar     int open_conds = cond_depth - cond_min_depth;
14223955d011SMarcel Moolenaar 
14233955d011SMarcel Moolenaar     if (open_conds != 0 || saved_depth > cond_depth) {
14243955d011SMarcel Moolenaar 	Parse_Error(PARSE_FATAL, "%d open conditional%s", open_conds,
14253955d011SMarcel Moolenaar 		    open_conds == 1 ? "" : "s");
14263955d011SMarcel Moolenaar 	cond_depth = cond_min_depth;
14273955d011SMarcel Moolenaar     }
14283955d011SMarcel Moolenaar 
14293955d011SMarcel Moolenaar     cond_min_depth = saved_depth;
14303955d011SMarcel Moolenaar }
14313955d011SMarcel Moolenaar 
14323955d011SMarcel Moolenaar unsigned int
14333955d011SMarcel Moolenaar Cond_save_depth(void)
14343955d011SMarcel Moolenaar {
14353955d011SMarcel Moolenaar     int depth = cond_min_depth;
14363955d011SMarcel Moolenaar 
14373955d011SMarcel Moolenaar     cond_min_depth = cond_depth;
14383955d011SMarcel Moolenaar     return depth;
14393955d011SMarcel Moolenaar }
1440