version 1.44, 2008/11/22 18:47:47 |
version 1.48, 2008/11/29 14:42:21 |
Line 92 __RCSID("$NetBSD$"); |
|
Line 92 __RCSID("$NetBSD$"); |
|
*/ |
*/ |
|
|
#include <ctype.h> |
#include <ctype.h> |
|
#include <errno.h> /* For strtoul() error checking */ |
|
|
#include "make.h" |
#include "make.h" |
#include "hash.h" |
#include "hash.h" |
Line 146 static Boolean CondDoMake(int, char *); |
|
Line 147 static Boolean CondDoMake(int, char *); |
|
static Boolean CondDoExists(int, char *); |
static Boolean CondDoExists(int, char *); |
static Boolean CondDoTarget(int, char *); |
static Boolean CondDoTarget(int, char *); |
static Boolean CondDoCommands(int, char *); |
static Boolean CondDoCommands(int, char *); |
static char * CondCvtArg(char *, double *); |
static Boolean CondCvtArg(char *, double *); |
static Token CondToken(Boolean); |
static Token CondToken(Boolean); |
static Token CondT(Boolean); |
static Token CondT(Boolean); |
static Token CondF(Boolean); |
static Token CondF(Boolean); |
Line 488 CondDoCommands(int argLen, char *arg) |
|
Line 489 CondDoCommands(int argLen, char *arg) |
|
/*- |
/*- |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
* CondCvtArg -- |
* CondCvtArg -- |
* Convert the given number into a double. If the number begins |
* Convert the given number into a double. |
* with 0x, it is interpreted as a hexadecimal integer |
* We try a base 10 or 16 integer conversion first, if that fails |
* and converted to a double from there. All other strings just have |
* then we try a floating point conversion instead. |
* strtod called on them. |
|
* |
* |
* Results: |
* Results: |
* Sets 'value' to double value of string. |
* Sets 'value' to double value of string. |
* Returns NULL if string was fully consumed, |
* Returns 'true' if the convertion suceeded |
* else returns remaining input. |
|
* |
|
* Side Effects: |
|
* Can change 'value' even if string is not a valid number. |
|
* |
|
* |
* |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
static char * |
static Boolean |
CondCvtArg(char *str, double *value) |
CondCvtArg(char *str, double *value) |
{ |
{ |
if ((*str == '0') && (str[1] == 'x')) { |
char *eptr, ech; |
long i; |
unsigned long l_val; |
|
double d_val; |
for (str += 2, i = 0; *str; str++) { |
|
int x; |
errno = 0; |
if (isdigit((unsigned char) *str)) |
l_val = strtoul(str, &eptr, str[1] == 'x' ? 16 : 10); |
x = *str - '0'; |
ech = *eptr; |
else if (isxdigit((unsigned char) *str)) |
if (ech == 0 && errno != ERANGE) { |
x = 10 + *str - isupper((unsigned char) *str) ? 'A' : 'a'; |
d_val = str[0] == '-' ? -(double)-l_val : (double)l_val; |
else |
|
break; |
|
i = (i << 4) + x; |
|
} |
|
*value = (double) i; |
|
return *str ? str : NULL; |
|
} else { |
} else { |
char *eptr; |
if (ech != 0 && ech != '.' && ech != 'e' && ech != 'E') |
*value = strtod(str, &eptr); |
return FALSE; |
return *eptr ? eptr : NULL; |
d_val = strtod(str, &eptr); |
|
if (*eptr) |
|
return FALSE; |
} |
} |
|
|
|
*value = d_val; |
|
return TRUE; |
} |
} |
|
|
/*- |
/*- |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
* CondGetString -- |
* CondGetString -- |
Line 762 do_string_compare: |
|
Line 756 do_string_compare: |
|
* lhs and the rhs to a double and compare the two. |
* lhs and the rhs to a double and compare the two. |
*/ |
*/ |
double left, right; |
double left, right; |
char *cp; |
|
|
|
if (CondCvtArg(lhs, &left)) |
if (!CondCvtArg(lhs, &left) || !CondCvtArg(rhs, &right)) |
goto do_string_compare; |
|
if ((cp = CondCvtArg(rhs, &right)) && |
|
cp == rhs) |
|
goto do_string_compare; |
goto do_string_compare; |
|
|
if (DEBUG(COND)) { |
if (DEBUG(COND)) { |
|
|
return t; |
return t; |
} |
} |
|
|
|
static int |
|
get_mpt_arg(char **linePtr, char **argPtr, const char *func, Boolean parens) |
|
{ |
|
/* |
|
* Use Var_Parse to parse the spec in parens and return |
|
* True if the resulting string is empty. |
|
*/ |
|
int length; |
|
void *freeIt; |
|
char *val; |
|
char *cp = *linePtr; |
|
|
|
/* We do all the work here and return the result as the length */ |
|
*argPtr = NULL; |
|
|
|
val = Var_Parse(cp - 1, VAR_CMD, FALSE, &length, &freeIt); |
|
/* |
|
* Advance *linePtr to beyond the closing ). Note that |
|
* we subtract one because 'length' is calculated from 'cp - 1'. |
|
*/ |
|
*linePtr = cp - 1 + length; |
|
|
|
if (val == var_Error) { |
|
free(freeIt); |
|
return -1; |
|
} |
|
|
|
/* A variable is empty when it just contains spaces... 4/15/92, christos */ |
|
while (isspace(*(unsigned char *)val)) |
|
val++; |
|
|
|
/* |
|
* For consistency with the other functions we can't generate the |
|
* true/false here. |
|
*/ |
|
length = *val ? 2 : 1; |
|
if (freeIt) |
|
free(freeIt); |
|
return length; |
|
} |
|
|
|
static Boolean |
|
CondDoEmpty(int arglen, char *arg) |
|
{ |
|
return arglen == 1; |
|
} |
|
|
static Token |
static Token |
compare_function(Boolean doEval) |
compare_function(Boolean doEval) |
{ |
{ |
|
static const struct fn_def { |
|
const char *fn_name; |
|
int fn_name_len; |
|
int (*fn_getarg)(char **, char **, const char *, Boolean); |
|
Boolean (*fn_proc)(int, char *); |
|
} fn_defs[] = { |
|
{ "defined", 7, CondGetArg, CondDoDefined }, |
|
{ "make", 4, CondGetArg, CondDoMake }, |
|
{ "exists", 6, CondGetArg, CondDoExists }, |
|
{ "empty", 5, get_mpt_arg, CondDoEmpty }, |
|
{ "target", 6, CondGetArg, CondDoTarget }, |
|
{ "commands", 8, CondGetArg, CondDoCommands }, |
|
{ NULL, 0, NULL, NULL }, |
|
}; |
|
const struct fn_def *fn_def; |
Token t; |
Token t; |
Boolean (*evalProc)(int, char *); |
|
Boolean invert = FALSE; |
|
char *arg = NULL; |
char *arg = NULL; |
int arglen = 0; |
int arglen; |
|
char *cp = condExpr; |
if (istoken(condExpr, "defined", 7)) { |
char *cp1; |
/* |
|
* Use CondDoDefined to evaluate the argument and |
for (fn_def = fn_defs; fn_def->fn_name != NULL; fn_def++) { |
* CondGetArg to extract the argument from the 'function |
if (!istoken(cp, fn_def->fn_name, fn_def->fn_name_len)) |
* call'. |
continue; |
*/ |
cp += fn_def->fn_name_len; |
evalProc = CondDoDefined; |
/* There can only be whitespace before the '(' */ |
condExpr += 7; |
while (isspace(*(unsigned char *)cp)) |
arglen = CondGetArg(&condExpr, &arg, "defined", TRUE); |
cp++; |
if (arglen == 0) { |
if (*cp != '(') |
condExpr -= 7; |
break; |
goto use_default; |
|
} |
|
} else if (istoken(condExpr, "make", 4)) { |
|
/* |
|
* Use CondDoMake to evaluate the argument and |
|
* CondGetArg to extract the argument from the 'function |
|
* call'. |
|
*/ |
|
evalProc = CondDoMake; |
|
condExpr += 4; |
|
arglen = CondGetArg(&condExpr, &arg, "make", TRUE); |
|
if (arglen == 0) { |
|
condExpr -= 4; |
|
goto use_default; |
|
} |
|
} else if (istoken(condExpr, "exists", 6)) { |
|
/* |
|
* Use CondDoExists to evaluate the argument and |
|
* CondGetArg to extract the argument from the |
|
* 'function call'. |
|
*/ |
|
evalProc = CondDoExists; |
|
condExpr += 6; |
|
arglen = CondGetArg(&condExpr, &arg, "exists", TRUE); |
|
if (arglen == 0) { |
|
condExpr -= 6; |
|
goto use_default; |
|
} |
|
} else if (istoken(condExpr, "empty", 5)) { |
|
/* |
|
* Use Var_Parse to parse the spec in parens and return |
|
* True if the resulting string is empty. |
|
*/ |
|
int did_warn, length; |
|
void *freeIt; |
|
char *val; |
|
|
|
condExpr += 5; |
|
|
|
did_warn = 0; |
|
for (arglen = 0; condExpr[arglen] != '\0'; arglen += 1) { |
|
if (condExpr[arglen] == '(') |
|
break; |
|
if (!isspace((unsigned char)condExpr[arglen]) && |
|
!did_warn) { |
|
|
|
Parse_Error(PARSE_WARNING, |
arglen = fn_def->fn_getarg(&cp, &arg, fn_def->fn_name, TRUE); |
"Extra characters after \"empty\""); |
if (arglen <= 0) { |
did_warn = 1; |
if (arglen < 0) { |
|
condExpr = cp; |
|
return Err; |
} |
} |
|
break; |
} |
} |
|
/* Evaluate the argument using the required function. */ |
if (condExpr[arglen] != '\0') { |
t = !doEval || fn_def->fn_proc(arglen, arg) ? True : False; |
val = Var_Parse(&condExpr[arglen - 1], VAR_CMD, |
if (arg) |
FALSE, &length, &freeIt); |
free(arg); |
if (val == var_Error) { |
condExpr = cp; |
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 (freeIt) { |
|
free(freeIt); |
|
} |
|
/* |
|
* 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; |
|
} |
|
return t; |
return t; |
} else if (istoken(condExpr, "target", 6)) { |
|
/* |
|
* Use CondDoTarget to evaluate the argument and |
|
* CondGetArg to extract the argument from the |
|
* 'function call'. |
|
*/ |
|
evalProc = CondDoTarget; |
|
condExpr += 6; |
|
arglen = CondGetArg(&condExpr, &arg, "target", TRUE); |
|
if (arglen == 0) { |
|
condExpr -= 6; |
|
goto use_default; |
|
} |
|
} else if (istoken(condExpr, "commands", 8)) { |
|
/* |
|
* Use CondDoCommands to evaluate the argument and |
|
* CondGetArg to extract the argument from the |
|
* 'function call'. |
|
*/ |
|
evalProc = CondDoCommands; |
|
condExpr += 8; |
|
arglen = CondGetArg(&condExpr, &arg, "commands", TRUE); |
|
if (arglen == 0) { |
|
condExpr -= 8; |
|
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. |
|
*/ |
|
if (isdigit((unsigned char)condExpr[0])) { |
|
/* |
|
* Variables may already be substituted |
|
* by the time we get here. |
|
*/ |
|
return compare_expression(doEval); |
|
} |
|
use_default: |
|
invert = condInvert; |
|
evalProc = condDefProc; |
|
arglen = CondGetArg(&condExpr, &arg, "", FALSE); |
|
} |
} |
|
|
|
/* Push anything numeric through the compare expression */ |
|
cp = condExpr; |
|
if (isdigit((unsigned char)cp[0]) || strchr("+-", cp[0])) |
|
return compare_expression(doEval); |
|
|
/* |
/* |
* Evaluate the argument using the set function. If invert |
* Most likely we have a naked token to apply the default function to. |
* is TRUE, we invert the sense of the function. |
* However ".if a == b" gets here when the "a" is unquoted and doesn't |
|
* start with a '$'. This surprises people - especially given the way |
|
* that for loops get expanded. |
|
* If what follows the function argument is a '=' or '!' then the syntax |
|
* would be invalid if we did "defined(a)" - so instead treat as an |
|
* expression. |
*/ |
*/ |
t = (!doEval || (* evalProc) (arglen, arg) ? |
arglen = CondGetArg(&cp, &arg, "", FALSE); |
(invert ? False : True) : |
for (cp1 = cp; isspace(*(unsigned char *)cp1); cp1++) |
(invert ? True : False)); |
continue; |
|
if (*cp1 == '=' || *cp1 == '!') |
|
return compare_expression(doEval); |
|
condExpr = cp; |
|
|
|
/* |
|
* Evaluate the argument using the default function. If invert |
|
* is TRUE, we invert the sense of the result. |
|
*/ |
|
t = !doEval || (* condDefProc)(arglen, arg) != condInvert ? True : False; |
if (arg) |
if (arg) |
free(arg); |
free(arg); |
return t; |
return t; |
Line 978 compare_function(Boolean doEval) |
|
Line 936 compare_function(Boolean doEval) |
|
static Token |
static Token |
CondToken(Boolean doEval) |
CondToken(Boolean doEval) |
{ |
{ |
Token t; |
Token t; |
|
|
|
t = condPushBack; |
|
if (t != None) { |
|
condPushBack = None; |
|
return t; |
|
} |
|
|
if (condPushBack == None) { |
while (*condExpr == ' ' || *condExpr == '\t') { |
while (*condExpr == ' ' || *condExpr == '\t') { |
condExpr++; |
|
} |
|
|
|
switch (*condExpr) { |
|
|
|
case '(': |
|
condExpr++; |
|
return LParen; |
|
|
|
case ')': |
|
condExpr++; |
|
return RParen; |
|
|
|
case '|': |
|
if (condExpr[1] == '|') { |
condExpr++; |
condExpr++; |
} |
} |
switch (*condExpr) { |
condExpr++; |
case '(': |
return Or; |
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 '#': |
|
case '\n': |
|
case '\0': |
|
t = EndOfFile; |
|
break; |
|
case '"': |
|
case '$': |
|
return compare_expression(doEval); |
|
|
|
default: |
|
return compare_function(doEval); |
|
|
|
|
case '&': |
|
if (condExpr[1] == '&') { |
|
condExpr++; |
} |
} |
} else { |
condExpr++; |
t = condPushBack; |
return And; |
condPushBack = None; |
|
|
case '!': |
|
condExpr++; |
|
return Not; |
|
|
|
case '#': |
|
case '\n': |
|
case '\0': |
|
return EndOfFile; |
|
|
|
case '"': |
|
case '$': |
|
return compare_expression(doEval); |
|
|
|
default: |
|
return compare_function(doEval); |
} |
} |
return (t); |
|
} |
} |
|
|
/*- |
/*- |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
* CondT -- |
* CondT -- |