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