diff options
Diffstat (limited to 'usr.bin/make/cond.c')
-rw-r--r-- | usr.bin/make/cond.c | 1294 |
1 files changed, 529 insertions, 765 deletions
diff --git a/usr.bin/make/cond.c b/usr.bin/make/cond.c index 45ae0af6c3c..93ad02834d5 100644 --- a/usr.bin/make/cond.c +++ b/usr.bin/make/cond.c @@ -1,4 +1,5 @@ -/* $OpenBSD: cond.c,v 1.23 2001/02/17 14:39:07 espie Exp $ */ +/* $OpenPackages$ */ +/* $OpenBSD: cond.c,v 1.24 2001/05/03 13:41:02 espie Exp $ */ /* $NetBSD: cond.c,v 1.7 1996/11/06 17:59:02 christos Exp $ */ /* @@ -44,13 +45,13 @@ * Functions to handle conditionals in a makefile. * * Interface: - * Cond_Eval Evaluate the conditional in the passed line. + * Cond_Eval Evaluate the conditional in the passed line. * */ -#include <stddef.h> #include <ctype.h> #include <math.h> +#include <stddef.h> #include "make.h" #include "ohash.h" #include "dir.h" @@ -61,12 +62,12 @@ static char sccsid[] = "@(#)cond.c 8.2 (Berkeley) 1/2/94"; #else UNUSED -static char rcsid[] = "$OpenBSD: cond.c,v 1.23 2001/02/17 14:39:07 espie Exp $"; +static char rcsid[] = "$OpenBSD: cond.c,v 1.24 2001/05/03 13:41:02 espie Exp $"; #endif #endif /* not lint */ -/* - * The parsing of conditional expressions is based on this grammar: + +/* The parsing of conditional expressions is based on this grammar: * E -> F || E * E -> F * F -> T && F @@ -93,83 +94,76 @@ static char rcsid[] = "$OpenBSD: cond.c,v 1.23 2001/02/17 14:39:07 espie Exp $"; * symbols, using either the default function or the function given in the * terminal, and return the result as either True or False. * - * All Non-Terminal functions (CondE, CondF and CondT) return Err on error. - */ + * All Non-Terminal functions (CondE, CondF and CondT) return Err on error. */ typedef enum { - And, Or, Not, True, False, LParen, RParen, EndOfFile, None, Err + False = 0, True = 1, And, Or, Not, LParen, RParen, EndOfFile, None, Err } Token; /*- * Structures to handle elegantly the different forms of #if's. The * last two fields are stored in condInvert and condDefProc, respectively. */ -static void CondPushBack __P((Token)); -static Boolean CondGetArg __P((char **, char **, size_t *, char *, Boolean)); -static Boolean CondDoDefined __P((size_t, char *)); -static int CondStrMatch __P((void *, void *)); -static Boolean CondDoMake __P((size_t, char *)); -static Boolean CondDoExists __P((size_t, char *)); -static Boolean CondDoTarget __P((size_t, char *)); -static Boolean CondCvtArg __P((char *, double *)); -static Token CondToken __P((Boolean)); -static Token CondT __P((Boolean)); -static Token CondF __P((Boolean)); -static Token CondE __P((Boolean)); +static Boolean CondGetArg(const char **, struct Name *, + const char *, Boolean); +static Boolean CondDoDefined(struct Name *); +static Boolean CondDoMake(struct Name *); +static Boolean CondDoExists(struct Name *); +static Boolean CondDoTarget(struct Name *); +static Boolean CondCvtArg(const char *, double *); +static Token CondToken(Boolean); +static Token CondT(Boolean); +static Token CondF(Boolean); +static Token CondE(Boolean); +static Token CondHandleVarSpec(Boolean); +static Token CondHandleDefault(Boolean); +static const char *find_cond(const char *); + static struct If { - char *form; /* Form of if */ - int formlen; /* Length of form */ - Boolean doNot; /* TRUE if default function should be negated */ - Boolean (*defProc) __P((size_t, char *)); /* Default function to apply */ + char *form; /* Form of if */ + int formlen; /* Length of form */ + Boolean doNot; /* TRUE if default function should be negated */ + Boolean (*defProc)(struct Name *); + /* Default function to apply */ } ifs[] = { { "ifdef", 5, FALSE, CondDoDefined }, - { "ifndef", 6, TRUE, CondDoDefined }, - { "ifmake", 6, FALSE, CondDoMake }, - { "ifnmake", 7, TRUE, CondDoMake }, + { "ifndef", 6, TRUE, CondDoDefined }, + { "ifmake", 6, FALSE, CondDoMake }, + { "ifnmake", 7, TRUE, CondDoMake }, { "if", 2, FALSE, CondDoDefined }, { NULL, 0, FALSE, NULL } }; -static Boolean condInvert; /* Invert the default function */ +static Boolean condInvert; /* Invert the default function */ static Boolean (*condDefProc) /* Default function to apply */ - __P((size_t, char *)); -static char *condExpr; /* The expression to parse */ + (struct Name *); +static const char *condExpr; /* The expression to parse */ static Token condPushBack=None; /* Single push-back token used in * parsing */ -#define MAXIF 30 /* greatest depth of #if'ing */ +#define MAXIF 30 /* greatest depth of #if'ing */ static struct { Boolean value; - unsigned long lineno; - const char *filename; -} condStack[MAXIF]; /* Stack of conditionals */ -static int condTop = MAXIF; /* Top-most conditional */ -static int skipIfLevel=0; /* Depth of skipped conditionals */ -static Boolean skipLine = FALSE; /* Whether the parse module is skipping + unsigned long lineno; + const char *filename; +} condStack[MAXIF]; /* Stack of conditionals */ +static int condTop = MAXIF; /* Top-most conditional */ +static int skipIfLevel=0; /* Depth of skipped conditionals */ +static Boolean skipLine = FALSE; /* Whether the parse module is skipping * lines */ -/*- - *----------------------------------------------------------------------- - * CondPushBack -- - * Push back the most recent token read. We only need one level of - * this, so the thing is just stored in 'condPushback'. - * - * Results: - * None. - * - * Side Effects: - * condPushback is overwritten. - * - *----------------------------------------------------------------------- - */ -static void -CondPushBack (t) - Token t; /* Token to push back into the "stream" */ +static const char * +find_cond(p) + const char *p; { - condPushBack = t; + for (;;p++) { + if (strchr(" \t)&|$", *p) != NULL) + return p; + } } - + + /*- *----------------------------------------------------------------------- * CondGetArg -- @@ -180,97 +174,57 @@ CondPushBack (t) * * Side Effects: * The line pointer is set to point to the closing parenthesis of the - * function call. The argument and argument length are filled. + * function call. The argument is filled. *----------------------------------------------------------------------- */ static Boolean -CondGetArg(linePtr, argPtr, argLen, func, parens) - char **linePtr; - char **argPtr; - size_t *argLen; - char *func; - Boolean parens; /* TRUE if arg should be bounded by parens */ +CondGetArg(linePtr, arg, func, parens) + const char **linePtr; + struct Name *arg; + const char *func; + Boolean parens; /* TRUE if arg should be bounded by parens */ { - register char *cp; - BUFFER buf; + const char *cp; cp = *linePtr; if (parens) { - while (*cp != '(' && *cp != '\0') { + while (*cp != '(' && *cp != '\0') cp++; - } - if (*cp == '(') { + if (*cp == '(') cp++; - } } if (*cp == '\0') { - /* - * No arguments whatsoever. Because 'make' and 'defined' aren't really + /* No arguments whatsoever. Because 'make' and 'defined' aren't really * "reserved words", we don't print a message. I think this is better * than hitting the user with a warning message every time s/he uses - * the word 'make' or 'defined' at the beginning of a symbol... - */ - *argPtr = cp; + * the word 'make' or 'defined' at the beginning of a symbol... */ + arg->s = cp; + arg->e = cp; + arg->tofree = FALSE; return FALSE; } - while (*cp == ' ' || *cp == '\t') { + while (*cp == ' ' || *cp == '\t') cp++; - } - /* - * Create a buffer for the argument and start it out at 16 characters - * long. Why 16? Why not? - */ - Buf_Init(&buf, 16); - - while ((strchr(" \t)&|", *cp) == (char *)NULL) && (*cp != '\0')) { - if (*cp == '$') { - /* - * Parse the variable spec and install it as part of the argument - * if it's valid. We tell Var_Parse to complain on an undefined - * variable, so we don't do it too. Nor do we return an error, - * though perhaps we should... - */ - char *cp2; - size_t len; - Boolean doFree; - cp2 = Var_Parse(cp, NULL, TRUE, &len, &doFree); + cp = Var_Name_Get(cp, arg, NULL, TRUE, find_cond); - Buf_AddString(&buf, cp2); - if (doFree) { - free(cp2); - } - cp += len; - } else { - Buf_AddChar(&buf, *cp); - cp++; - } - } - - *argPtr = Buf_Retrieve(&buf); - *argLen = Buf_Size(&buf); - - while (*cp == ' ' || *cp == '\t') { + while (*cp == ' ' || *cp == '\t') cp++; - } if (parens && *cp != ')') { - Parse_Error (PARSE_WARNING, "Missing closing parenthesis for %s()", + Parse_Error(PARSE_WARNING, "Missing closing parenthesis for %s()", func); return FALSE; - } else if (parens) { - /* - * Advance pointer past close parenthesis. - */ + } else if (parens) + /* Advance pointer past close parenthesis. */ cp++; - } *linePtr = cp; return TRUE; } - + /*- *----------------------------------------------------------------------- * CondDoDefined -- @@ -278,50 +232,18 @@ CondGetArg(linePtr, argPtr, argLen, func, parens) * * Results: * TRUE if the given variable is defined. - * - * Side Effects: - * None. - * *----------------------------------------------------------------------- */ static Boolean -CondDoDefined(argLen, arg) - size_t argLen; - char *arg; +CondDoDefined(arg) + struct Name *arg; { - char savec = arg[argLen]; - Boolean result; - - if (argLen == 0) - return FALSE; - - arg[argLen] = '\0'; - if (Var_Value(arg, NULL) != NULL) - result = TRUE; + if (Var_Value_interval(arg->s, arg->e) != NULL) + return TRUE; else - result = FALSE; - arg[argLen] = savec; - return (result); -} - -/*- - *----------------------------------------------------------------------- - * CondStrMatch -- - * Front-end for Str_Match so it returns 0 on match and non-zero - * on mismatch. Callback function for CondDoMake via Lst_Find - * - * Results: - * 0 if string matches pattern - *----------------------------------------------------------------------- - */ -static int -CondStrMatch(string, pattern) - void *string; - void *pattern; -{ - return !Str_Match((char *)string,(char *)pattern); + return FALSE; } - + /*- *----------------------------------------------------------------------- * CondDoMake -- @@ -329,30 +251,22 @@ CondStrMatch(string, pattern) * * Results: * TRUE if the given target is being made. - * - * Side Effects: - * None. - * *----------------------------------------------------------------------- */ static Boolean -CondDoMake (argLen, arg) - size_t argLen; - char *arg; +CondDoMake(arg) + struct Name *arg; { - char savec = arg[argLen]; - Boolean result; + LstNode ln; - arg[argLen] = '\0'; - if (Lst_Find(&create, CondStrMatch, arg) == NULL) { - result = FALSE; - } else { - result = TRUE; + for (ln = Lst_First(&create); ln != NULL; ln = Lst_Adv(ln)) { + if (Str_Matchi((char *)Lst_Datum(ln), arg->s, arg->e)) + return TRUE; } - arg[argLen] = savec; - return (result); + + return FALSE; } - + /*- *----------------------------------------------------------------------- * CondDoExists -- @@ -360,33 +274,25 @@ CondDoMake (argLen, arg) * * Results: * TRUE if the file exists and FALSE if it does not. - * - * Side Effects: - * None. - * *----------------------------------------------------------------------- */ static Boolean -CondDoExists (argLen, arg) - size_t argLen; - char *arg; +CondDoExists(arg) + struct Name *arg; { - char savec = arg[argLen]; Boolean result; char *path; - arg[argLen] = '\0'; - path = Dir_FindFile(arg, &dirSearchPath); - if (path != (char *)NULL) { + path = Dir_FindFilei(arg->s, arg->e, &dirSearchPath); + if (path != NULL) { result = TRUE; free(path); } else { result = FALSE; } - arg[argLen] = savec; - return (result); + return result; } - + /*- *----------------------------------------------------------------------- * CondDoTarget -- @@ -394,33 +300,22 @@ CondDoExists (argLen, arg) * * Results: * TRUE if the node exists as a target and FALSE if it does not. - * - * Side Effects: - * None. - * *----------------------------------------------------------------------- */ static Boolean -CondDoTarget(argLen, arg) - size_t argLen; - char *arg; +CondDoTarget(arg) + struct Name *arg; { - char savec = arg[argLen]; - Boolean result; GNode *gn; - arg[argLen] = '\0'; - gn = Targ_FindNode(arg, TARG_NOCREATE); - if ((gn != NULL) && !OP_NOP(gn->type)) { - result = TRUE; - } else { - result = FALSE; - } - arg[argLen] = savec; - return (result); + gn = Targ_FindNode(arg->s, arg->e, TARG_NOCREATE); + if (gn != NULL && !OP_NOP(gn->type)) + return TRUE; + else + return FALSE; } - + /*- *----------------------------------------------------------------------- * CondCvtArg -- @@ -435,24 +330,22 @@ CondDoTarget(argLen, arg) * * Side Effects: * Can change 'value' even if string is not a valid number. - * - * *----------------------------------------------------------------------- */ static Boolean CondCvtArg(str, value) - register char *str; + const char *str; double *value; { - if ((*str == '0') && (str[1] == 'x')) { - register long i; + if (*str == '0' && str[1] == 'x') { + long i; for (str += 2, i = 0; *str; str++) { int x; - if (isdigit((unsigned char) *str)) + if (isdigit(*str)) x = *str - '0'; - else if (isxdigit((unsigned char) *str)) - x = 10 + *str - isupper((unsigned char) *str) ? 'A' : 'a'; + else if (isxdigit(*str)) + x = 10 + *str - isupper(*str) ? 'A' : 'a'; else return FALSE; i = (i << 4) + x; @@ -466,436 +359,364 @@ CondCvtArg(str, value) return *eptr == '\0'; } } - -/*- - *----------------------------------------------------------------------- - * CondToken -- - * Return the next token from the input. - * - * Results: - * A Token for the next lexical token in the stream. - * - * Side Effects: - * condPushback will be set back to None if it is used. - * - *----------------------------------------------------------------------- - */ + + static Token -CondToken(doEval) +CondHandleVarSpec(doEval) Boolean doEval; { - Token t; + Token t; + char *lhs; + const char *rhs; + const char *op; + size_t varSpecLen; + Boolean doFree; - if (condPushBack == None) { - while (*condExpr == ' ' || *condExpr == '\t') { - condExpr++; - } - switch (*condExpr) { - case '(': - t = LParen; - condExpr++; - break; - case ')': - t = RParen; - condExpr++; - break; - case '|': - if (condExpr[1] == '|') { - condExpr++; - } - condExpr++; - t = Or; - break; - case '&': - if (condExpr[1] == '&') { - condExpr++; - } - condExpr++; - t = And; - break; - case '!': - t = Not; - condExpr++; - break; - case '\n': - case '\0': - t = EndOfFile; - break; - case '$': { - char *lhs; - char *rhs; - char *op; - size_t varSpecLen; - Boolean doFree; - - /* - * Parse the variable spec and skip over it, saving its - * value in lhs. - */ - t = Err; - lhs = Var_Parse(condExpr, NULL, doEval,&varSpecLen,&doFree); - if (lhs == var_Error) { - /* - * Even if !doEval, we still report syntax errors, which - * is what getting var_Error back with !doEval means. - */ - return(Err); - } - condExpr += varSpecLen; + /* Parse the variable spec and skip over it, saving its + * value in lhs. */ + t = Err; + lhs = Var_Parse(condExpr, NULL, doEval,&varSpecLen,&doFree); + if (lhs == var_Error) + /* Even if !doEval, we still report syntax errors, which + * is what getting var_Error back with !doEval means. */ + return Err; + condExpr += varSpecLen; - if (!isspace((unsigned char) *condExpr) && - strchr("!=><", *condExpr) == NULL) { - BUFFER buf; + if (!isspace(*condExpr) && + strchr("!=><", *condExpr) == NULL) { + BUFFER buf; - Buf_Init(&buf, 0); + Buf_Init(&buf, 0); - Buf_AddString(&buf, lhs); + Buf_AddString(&buf, lhs); - if (doFree) - free(lhs); + if (doFree) + free(lhs); - for (;*condExpr && !isspace((unsigned char) *condExpr); - condExpr++) - Buf_AddChar(&buf, *condExpr); + for (;*condExpr && !isspace(*condExpr); condExpr++) + Buf_AddChar(&buf, *condExpr); - lhs = Buf_Retrieve(&buf); + lhs = Buf_Retrieve(&buf); - doFree = TRUE; - } + doFree = TRUE; + } - /* - * Skip whitespace to get to the operator - */ - while (isspace((unsigned char) *condExpr)) - condExpr++; + /* Skip whitespace to get to the operator. */ + while (isspace(*condExpr)) + condExpr++; + + /* Make sure the operator is a valid one. If it isn't a + * known relational operator, pretend we got a + * != 0 comparison. */ + op = condExpr; + switch (*condExpr) { + case '!': + case '=': + case '<': + case '>': + if (condExpr[1] == '=') + condExpr += 2; + else + condExpr += 1; + break; + default: + op = "!="; + rhs = "0"; - /* - * Make sure the operator is a valid one. If it isn't a - * known relational operator, pretend we got a - * != 0 comparison. - */ - op = condExpr; - switch (*condExpr) { - case '!': - case '=': - case '<': - case '>': - if (condExpr[1] == '=') { - condExpr += 2; - } else { - condExpr += 1; - } - break; - default: - op = "!="; - rhs = "0"; - - goto do_compare; - } - while (isspace((unsigned char) *condExpr)) { - condExpr++; - } - if (*condExpr == '\0') { - Parse_Error(PARSE_WARNING, - "Missing right-hand-side of operator"); - goto error; - } - rhs = condExpr; + goto do_compare; + } + while (isspace(*condExpr)) + condExpr++; + if (*condExpr == '\0') { + Parse_Error(PARSE_WARNING, + "Missing right-hand-side of operator"); + goto error; + } + rhs = condExpr; do_compare: - if (*rhs == '"') { - /* - * Doing a string comparison. Only allow == and != for - * operators. - */ - char *string; - char *cp, *cp2; - int qt; - BUFFER buf; + if (*rhs == '"') { + /* Doing a string comparison. Only allow == and != for + * operators. */ + char *string; + const char *cp; + int qt; + BUFFER buf; do_string_compare: - if (((*op != '!') && (*op != '=')) || (op[1] != '=')) { - Parse_Error(PARSE_WARNING, - "String comparison operator should be either == or !="); - goto error; - } - - Buf_Init(&buf, 0); - qt = *rhs == '"' ? 1 : 0; - - for (cp = &rhs[qt]; - ((qt && (*cp != '"')) || - (!qt && strchr(" \t)", *cp) == NULL)) && - (*cp != '\0'); cp++) { - if ((*cp == '\\') && (cp[1] != '\0')) { - /* - * Backslash escapes things -- skip over next - * character, if it exists. - */ - cp++; - Buf_AddChar(&buf, *cp); - } else if (*cp == '$') { - size_t len; - Boolean freeIt; - - cp2 = Var_Parse(cp, NULL, doEval,&len, &freeIt); - if (cp2 != var_Error) { - Buf_AddString(&buf, cp2); - if (freeIt) { - free(cp2); - } - cp += len - 1; - } else { - Buf_AddChar(&buf, *cp); - } - } else { - Buf_AddChar(&buf, *cp); - } - } - - string = Buf_Retrieve(&buf); - - if (DEBUG(COND)) { - printf("lhs = \"%s\", rhs = \"%s\", op = %.2s\n", - lhs, string, op); - } - /* - * Null-terminate rhs and perform the comparison. - * t is set to the result. - */ - if (*op == '=') { - t = strcmp(lhs, string) ? False : True; - } else { - t = strcmp(lhs, string) ? True : False; - } - free(string); - if (rhs == condExpr) { - if (!qt && *cp == ')') - condExpr = cp; - else if (*cp == '\0') - condExpr = cp; - else - condExpr = cp + 1; - } - } else { - /* - * rhs is either a float or an integer. Convert both the - * lhs and the rhs to a double and compare the two. - */ - double left, right; - char *string; - - if (!CondCvtArg(lhs, &left)) - goto do_string_compare; - if (*rhs == '$') { - size_t len; - Boolean freeIt; - - string = Var_Parse(rhs, NULL, doEval,&len,&freeIt); - if (string == var_Error) { - right = 0.0; - } else { - if (!CondCvtArg(string, &right)) { - if (freeIt) - free(string); - goto do_string_compare; - } - if (freeIt) - free(string); - if (rhs == condExpr) - condExpr += len; - } - } else { - if (!CondCvtArg(rhs, &right)) - goto do_string_compare; - if (rhs == condExpr) { - /* - * Skip over the right-hand side - */ - while(!isspace((unsigned char) *condExpr) && - (*condExpr != '\0')) { - condExpr++; - } - } - } - - if (DEBUG(COND)) { - printf("left = %f, right = %f, op = %.2s\n", left, - right, op); - } - switch(op[0]) { - case '!': - if (op[1] != '=') { - Parse_Error(PARSE_WARNING, - "Unknown operator"); - goto error; - } - t = (left != right ? True : False); - break; - case '=': - if (op[1] != '=') { - Parse_Error(PARSE_WARNING, - "Unknown operator"); - goto error; - } - t = (left == right ? True : False); - break; - case '<': - if (op[1] == '=') { - t = (left <= right ? True : False); - } else { - t = (left < right ? True : False); - } - break; - case '>': - if (op[1] == '=') { - t = (left >= right ? True : False); - } else { - t = (left > right ? True : False); - } - break; - } + if ((*op != '!' && *op != '=') || op[1] != '=') { + Parse_Error(PARSE_WARNING, + "String comparison operator should be either == or !="); + goto error; + } + + Buf_Init(&buf, 0); + qt = *rhs == '"' ? 1 : 0; + + for (cp = &rhs[qt]; + ((qt && *cp != '"') || + (!qt && strchr(" \t)", *cp) == NULL)) && + *cp != '\0';) { + if (*cp == '$') { + size_t len; + + if (Var_ParseBuffer(&buf, cp, NULL, doEval, &len) + == SUCCESS) { + cp += len; + continue; } -error: - if (doFree) - free(lhs); - break; - } - default: { - Boolean (*evalProc) __P((size_t, char *)); - Boolean invert = FALSE; - char *arg; - size_t arglen; - - if (strncmp (condExpr, "defined", 7) == 0) { - /* - * Use CondDoDefined to evaluate the argument and - * CondGetArg to extract the argument from the 'function - * call'. - */ - evalProc = CondDoDefined; - condExpr += 7; - if (!CondGetArg(&condExpr, &arg, &arglen, - "defined", TRUE)) { - condExpr -= 7; - goto use_default; - } - } else if (strncmp (condExpr, "make", 4) == 0) { - /* - * Use CondDoMake to evaluate the argument and - * CondGetArg to extract the argument from the 'function - * call'. - */ - evalProc = CondDoMake; - condExpr += 4; - if (!CondGetArg(&condExpr, &arg, &arglen, - "make", TRUE)) { - condExpr -= 4; - goto use_default; - } - } else if (strncmp (condExpr, "exists", 6) == 0) { - /* - * Use CondDoExists to evaluate the argument and - * CondGetArg to extract the argument from the - * 'function call'. - */ - evalProc = CondDoExists; - condExpr += 6; - if (!CondGetArg(&condExpr, &arg, &arglen, - "exists", TRUE)) { - condExpr -= 6; - goto use_default; - } - } else if (strncmp(condExpr, "empty", 5) == 0) { - /* - * Use Var_Parse to parse the spec in parens and return - * True if the resulting string is empty. - */ - size_t length; - Boolean doFree; - char *val; - - condExpr += 5; - - for (arglen = 0; - condExpr[arglen] != '(' && condExpr[arglen] != '\0'; - arglen += 1) - continue; - - if (condExpr[arglen] != '\0') { - val = Var_Parse(&condExpr[arglen - 1], NULL, - doEval, &length, &doFree); - if (val == var_Error) { - t = Err; - } else { - /* - * A variable is empty when it just contains - * spaces... 4/15/92, christos - */ - char *p; - for (p = val; *p && isspace((unsigned char)*p); p++) - continue; - t = (*p == '\0') ? True : False; - } - if (doFree) { - free(val); - } - /* - * Advance condExpr to beyond the closing ). Note that - * we subtract one from arglen + length b/c length - * is calculated from condExpr[arglen - 1]. - */ - condExpr += arglen + length - 1; - } else { - condExpr -= 5; - goto use_default; - } - break; - } else if (strncmp (condExpr, "target", 6) == 0) { - /* - * Use CondDoTarget to evaluate the argument and - * CondGetArg to extract the argument from the - * 'function call'. - */ - evalProc = CondDoTarget; - condExpr += 6; - if (!CondGetArg(&condExpr, &arg, &arglen, - "target", TRUE)) { - condExpr -= 6; - goto use_default; - } - } else { - /* - * The symbol is itself the argument to the default - * function. We advance condExpr to the end of the symbol - * by hand (the next whitespace, closing paren or - * binary operator) and set to invert the evaluation - * function if condInvert is TRUE. - */ - use_default: - invert = condInvert; - evalProc = condDefProc; - /* XXX should we ignore problems now ? */ - CondGetArg(&condExpr, &arg, &arglen, "", FALSE); + } else if (*cp == '\\' && cp[1] != '\0') + /* Backslash escapes things -- skip over next + * character, if it exists. */ + cp++; + Buf_AddChar(&buf, *cp++); + } + + string = Buf_Retrieve(&buf); + + if (DEBUG(COND)) + printf("lhs = \"%s\", rhs = \"%s\", op = %.2s\n", + lhs, string, op); + /* Null-terminate rhs and perform the comparison. + * t is set to the result. */ + if (*op == '=') + t = strcmp(lhs, string) ? False : True; + else + t = strcmp(lhs, string) ? True : False; + free(string); + if (rhs == condExpr) { + if (!qt && *cp == ')') + condExpr = cp; + else if (*cp == '\0') + condExpr = cp; + else + condExpr = cp + 1; + } + } else { + /* rhs is either a float or an integer. Convert both the + * lhs and the rhs to a double and compare the two. */ + double left, right; + char *string; + + if (!CondCvtArg(lhs, &left)) + goto do_string_compare; + if (*rhs == '$') { + size_t len; + Boolean freeIt; + + string = Var_Parse(rhs, NULL, doEval,&len,&freeIt); + if (string == var_Error) + right = 0.0; + else { + if (!CondCvtArg(string, &right)) { + if (freeIt) + free(string); + goto do_string_compare; } + if (freeIt) + free(string); + if (rhs == condExpr) + condExpr += len; + } + } else { + if (!CondCvtArg(rhs, &right)) + goto do_string_compare; + if (rhs == condExpr) { + /* Skip over the right-hand side. */ + while (!isspace(*condExpr) && + *condExpr != '\0') + condExpr++; - /* - * Evaluate the argument using the set function. If invert - * is TRUE, we invert the sense of the function. - */ - t = (!doEval || (* evalProc) (arglen, arg) ? - (invert ? False : True) : - (invert ? True : False)); - free(arg); - break; } } + + if (DEBUG(COND)) + printf("left = %f, right = %f, op = %.2s\n", left, + right, op); + switch (op[0]) { + case '!': + if (op[1] != '=') { + Parse_Error(PARSE_WARNING, + "Unknown operator"); + goto error; + } + t = left != right ? True : False; + break; + case '=': + if (op[1] != '=') { + Parse_Error(PARSE_WARNING, + "Unknown operator"); + goto error; + } + t = left == right ? True : False; + break; + case '<': + if (op[1] == '=') + t = left <= right ? True : False; + else + t = left < right ? True : False; + break; + case '>': + if (op[1] == '=') + t = left >= right ? True : False; + else + t = left > right ? True : False; + break; + } + } +error: + if (doFree) + free(lhs); + return t; +} + +#define S(s) s, sizeof(s)-1 +static struct operator { + const char *s; + size_t len; + Boolean (*proc)(struct Name *); +} ops[] = { + {S("defined"), CondDoDefined}, + {S("make"), CondDoMake}, + {S("exists"), CondDoExists}, + {S("target"), CondDoTarget}, + {NULL, 0, NULL} +}; +static Token +CondHandleDefault(doEval) + Boolean doEval; +{ + Boolean t; + Boolean (*evalProc)(struct Name *); + Boolean invert = FALSE; + struct Name arg; + size_t arglen; + + evalProc = NULL; + if (strncmp(condExpr, "empty", 5) == 0) { + /* Use Var_Parse to parse the spec in parens and return + * True if the resulting string is empty. */ + size_t length; + Boolean doFree; + char *val; + + condExpr += 5; + + for (arglen = 0; condExpr[arglen] != '(' && condExpr[arglen] != '\0';) + arglen++; + + if (condExpr[arglen] != '\0') { + val = Var_Parse(&condExpr[arglen - 1], NULL, + doEval, &length, &doFree); + if (val == var_Error) + t = Err; + else { + /* A variable is empty when it just contains + * spaces... 4/15/92, christos */ + char *p; + for (p = val; *p && isspace(*p); p++) + continue; + t = *p == '\0' ? True : False; + } + if (doFree) + free(val); + /* Advance condExpr to beyond the closing ). Note that + * we subtract one from arglen + length b/c length + * is calculated from condExpr[arglen - 1]. */ + condExpr += arglen + length - 1; + return t; + } else + condExpr -= 5; } else { + struct operator *op; + + for (op = ops; op != NULL; op++) + if (strncmp(condExpr, op->s, op->len) == 0) { + condExpr += op->len; + if (CondGetArg(&condExpr, &arg, op->s, TRUE)) + evalProc = op->proc; + else + condExpr -= op->len; + break; + } + } + if (evalProc == NULL) { + /* The symbol is itself the argument to the default + * function. We advance condExpr to the end of the symbol + * by hand (the next whitespace, closing paren or + * binary operator) and set to invert the evaluation + * function if condInvert is TRUE. */ + invert = condInvert; + evalProc = condDefProc; + /* XXX should we ignore problems now ? */ + CondGetArg(&condExpr, &arg, "", FALSE); + } + + /* Evaluate the argument using the set function. If invert + * is TRUE, we invert the sense of the function. */ + t = (!doEval || (*evalProc)(&arg) ? + (invert ? False : True) : + (invert ? True : False)); + Var_Name_Free(&arg); + return t; +} + +/*- + *----------------------------------------------------------------------- + * CondToken -- + * Return the next token from the input. + * + * Results: + * A Token for the next lexical token in the stream. + * + * Side Effects: + * condPushback will be set back to None if it is used. + *----------------------------------------------------------------------- + */ +static Token +CondToken(doEval) + Boolean doEval; +{ + + if (condPushBack != None) { + Token t; + t = condPushBack; condPushBack = None; + return t; + } + + while (*condExpr == ' ' || *condExpr == '\t') + condExpr++; + switch (*condExpr) { + case '(': + condExpr++; + return LParen; + case ')': + condExpr++; + return RParen; + case '|': + if (condExpr[1] == '|') + condExpr++; + condExpr++; + return Or; + case '&': + if (condExpr[1] == '&') + condExpr++; + condExpr++; + return And; + case '!': + condExpr++; + return Not; + case '\n': + case '\0': + return EndOfFile; + case '$': + return CondHandleVarSpec(doEval); + default: + return CondHandleDefault(doEval); } - return (t); } - + /*- *----------------------------------------------------------------------- * CondT -- @@ -910,7 +731,6 @@ error: * * Side Effects: * Tokens are consumed. - * *----------------------------------------------------------------------- */ static Token @@ -921,33 +741,26 @@ CondT(doEval) t = CondToken(doEval); - if (t == EndOfFile) { - /* - * If we reached the end of the expression, the expression - * is malformed... - */ + if (t == EndOfFile) + /* If we reached the end of the expression, the expression + * is malformed... */ t = Err; - } else if (t == LParen) { - /* - * T -> ( E ) - */ + else if (t == LParen) { + /* T -> ( E ). */ t = CondE(doEval); - if (t != Err) { - if (CondToken(doEval) != RParen) { + if (t != Err) + if (CondToken(doEval) != RParen) t = Err; - } - } } else if (t == Not) { t = CondT(doEval); - if (t == True) { + if (t == True) t = False; - } else if (t == False) { + else if (t == False) t = True; - } } - return (t); + return t; } - + /*- *----------------------------------------------------------------------- * CondF -- @@ -959,7 +772,6 @@ CondT(doEval) * * Side Effects: * Tokens are consumed. - * *----------------------------------------------------------------------- */ static Token @@ -973,28 +785,22 @@ CondF(doEval) o = CondToken(doEval); if (o == And) { - /* - * F -> T && F + /* F -> T && F * * If T is False, the whole thing will be False, but we have to * parse the r.h.s. anyway (to throw it away). - * If T is True, the result is the r.h.s., be it an Err or no. - */ - if (l == True) { + * If T is True, the result is the r.h.s., be it an Err or no. */ + if (l == True) l = CondF(doEval); - } else { - (void) CondF(FALSE); - } - } else { - /* - * F -> T - */ - CondPushBack (o); - } + else + (void)CondF(FALSE); + } else + /* F -> T. */ + condPushBack = o; } - return (l); + return l; } - + /*- *----------------------------------------------------------------------- * CondE -- @@ -1006,7 +812,6 @@ CondF(doEval) * * Side Effects: * Tokens are, of course, consumed. - * *----------------------------------------------------------------------- */ static Token @@ -1020,35 +825,29 @@ CondE(doEval) o = CondToken(doEval); if (o == Or) { - /* - * E -> F || E + /* E -> F || E * * A similar thing occurs for ||, except that here we make sure * the l.h.s. is False before we bother to evaluate the r.h.s. * Once again, if l is False, the result is the r.h.s. and once - * again if l is True, we parse the r.h.s. to throw it away. - */ - if (l == False) { + * again if l is True, we parse the r.h.s. to throw it away. */ + if (l == False) l = CondE(doEval); - } else { - (void) CondE(FALSE); - } - } else { - /* - * E -> F - */ - CondPushBack (o); - } + else + (void)CondE(FALSE); + } else + /* E -> F. */ + condPushBack = o; } - return (l); + return l; } - + /*- *----------------------------------------------------------------------- * Cond_Eval -- - * Evaluate the conditional in the passed line. The line + * Evaluate the conditional in the passed fragment. The fragment * looks like this: - * #<cond-type> <expr> + * <cond-type> <expr> * where <cond-type> is any of if, ifmake, ifnmake, ifdef, * ifndef, elif, elifmake, elifnmake, elifdef, elifndef * and <expr> consists of &&, ||, !, make(target), defined(variable) @@ -1057,126 +856,100 @@ CondE(doEval) * Results: * COND_PARSE if should parse lines after the conditional * COND_SKIP if should skip lines after the conditional - * COND_INVALID if not a valid conditional. - * - * Side Effects: - * None. - * + * COND_INVALID if not a valid conditional. *----------------------------------------------------------------------- */ int -Cond_Eval (line) - char *line; /* Line to parse */ +Cond_Eval(line) + char *line; /* Line to parse */ { struct If *ifp; - Boolean isElse; - Boolean value = FALSE; - int level; /* Level at which to report errors. */ + Boolean isElse; + Boolean value = FALSE; + int level; /* Level at which to report errors. */ level = PARSE_FATAL; - for (line++; *line == ' ' || *line == '\t'; line++) { - continue; - } + /* Stuff we are looking for can be if*, elif*, else, or endif. + * otherwise, this is not our turf. */ - /* - * Find what type of if we're dealing with. The result is left - * in ifp and isElse is set TRUE if it's an elif line. - */ + /* Find what type of if we're dealing with. The result is left + * in ifp and isElse is set TRUE if it's an elif line. */ if (line[0] == 'e' && line[1] == 'l') { line += 2; isElse = TRUE; - } else if (strncmp (line, "endif", 5) == 0) { - /* - * End of a conditional section. If skipIfLevel is non-zero, that + } else if (strncmp(line, "endif", 5) == 0) { + /* End of a conditional section. If skipIfLevel is non-zero, that * conditional was skipped, so lines following it should also be * skipped. Hence, we return COND_SKIP. Otherwise, the conditional * was read so succeeding lines should be parsed (think about it...) * so we return COND_PARSE, unless this endif isn't paired with - * a decent if. - */ + * a decent if. */ if (skipIfLevel != 0) { skipIfLevel -= 1; - return (COND_SKIP); + return COND_SKIP; } else { if (condTop == MAXIF) { - Parse_Error (level, "if-less endif"); - return (COND_INVALID); + Parse_Error(level, "if-less endif"); + return COND_INVALID; } else { skipLine = FALSE; condTop += 1; - return (COND_PARSE); + return COND_PARSE; } } - } else { + } else isElse = FALSE; - } - /* - * Figure out what sort of conditional it is -- what its default - * function is, etc. -- by looking in the table of valid "ifs" - */ - for (ifp = ifs; ifp->form != (char *)0; ifp++) { - if (strncmp (ifp->form, line, ifp->formlen) == 0) { + /* Figure out what sort of conditional it is -- what its default + * function is, etc. -- by looking in the table of valid "ifs" */ + for (ifp = ifs; ifp->form != NULL; ifp++) { + if (strncmp(ifp->form, line, ifp->formlen) == 0) break; - } } - if (ifp->form == (char *) 0) { - /* - * Nothing fit. If the first word on the line is actually + if (ifp->form == NULL) { + /* Nothing fits. If the first word on the line is actually * "else", it's a valid conditional whose value is the inverse - * of the previous if we parsed. - */ - if (isElse && (line[0] == 's') && (line[1] == 'e')) { + * of the previous if we parsed. */ + if (isElse && line[0] == 's' && line[1] == 'e') { if (condTop == MAXIF) { - Parse_Error (level, "if-less else"); - return (COND_INVALID); - } else if (skipIfLevel == 0) { + Parse_Error(level, "if-less else"); + return COND_INVALID; + } else if (skipIfLevel == 0) value = !condStack[condTop].value; - } else { - return (COND_SKIP); - } - } else { - /* - * Not a valid conditional type. No error... - */ - return (COND_INVALID); - } + else + return COND_SKIP; + } else + /* Not a valid conditional type. No error... */ + return COND_INVALID; } else { if (isElse) { if (condTop == MAXIF) { - Parse_Error (level, "if-less elif"); - return (COND_INVALID); + Parse_Error(level, "if-less elif"); + return COND_INVALID; } else if (skipIfLevel != 0) { - /* - * If skipping this conditional, just ignore the whole thing. + /* If skipping this conditional, just ignore the whole thing. * If we don't, the user might be employing a variable that's * undefined, for which there's an enclosing ifdef that - * we're skipping... - */ - return(COND_SKIP); + * we're skipping... */ + return COND_SKIP; } } else if (skipLine) { - /* - * Don't even try to evaluate a conditional that's not an else if - * we're skipping things... - */ + /* Don't even try to evaluate a conditional that's not an else if + * we're skipping things... */ skipIfLevel += 1; - return(COND_SKIP); + return COND_SKIP; } - /* - * Initialize file-global variables for parsing - */ + /* Initialize file-global variables for parsing. */ condDefProc = ifp->defProc; condInvert = ifp->doNot; line += ifp->formlen; - while (*line == ' ' || *line == '\t') { + while (*line == ' ' || *line == '\t') line++; - } condExpr = line; condPushBack = None; @@ -1197,54 +970,45 @@ Cond_Eval (line) /* FALLTHROUGH */ case Err: err: - Parse_Error (level, "Malformed conditional (%s)", - line); - return (COND_INVALID); + Parse_Error(level, "Malformed conditional (%s)", line); + return COND_INVALID; default: break; } } - if (!isElse) { + if (!isElse) condTop -= 1; - } else if ((skipIfLevel != 0) || condStack[condTop].value) { - /* - * If this is an else-type conditional, it should only take effect + else if (skipIfLevel != 0 || condStack[condTop].value) { + /* If this is an else-type conditional, it should only take effect * if its corresponding if was evaluated and FALSE. If its if was * TRUE or skipped, we return COND_SKIP (and start skipping in case * we weren't already), leaving the stack unmolested so later elif's - * don't screw up... - */ + * don't screw up... */ skipLine = TRUE; - return (COND_SKIP); + return COND_SKIP; } if (condTop < 0) { - /* - * This is the one case where we can definitely proclaim a fatal - * error. If we don't, we're hosed. - */ - Parse_Error (PARSE_FATAL, "Too many nested if's. %d max.", MAXIF); - return (COND_INVALID); + /* This is the one case where we can definitely proclaim a fatal + * error. If we don't, we're hosed. */ + Parse_Error(PARSE_FATAL, "Too many nested if's. %d max.", MAXIF); + return COND_INVALID; } else { condStack[condTop].value = value; condStack[condTop].lineno = Parse_Getlineno(); condStack[condTop].filename = Parse_Getfilename(); skipLine = !value; - return (value ? COND_PARSE : COND_SKIP); + return value ? COND_PARSE : COND_SKIP; } } - + /*- *----------------------------------------------------------------------- * Cond_End -- * Make sure everything's clean at the end of a makefile. * - * Results: - * None. - * * Side Effects: * Parse_Error will be called if open conditionals are around. - * *----------------------------------------------------------------------- */ void |