version 1.19, 2004/01/06 01:18:52 |
version 1.38, 2008/02/06 18:26:37 |
|
|
* SUCH DAMAGE. |
* SUCH DAMAGE. |
*/ |
*/ |
|
|
#ifdef MAKE_BOOTSTRAP |
#ifndef MAKE_NATIVE |
static char rcsid[] = "$NetBSD$"; |
static char rcsid[] = "$NetBSD$"; |
#else |
#else |
#include <sys/cdefs.h> |
#include <sys/cdefs.h> |
Line 114 __RCSID("$NetBSD$"); |
|
Line 114 __RCSID("$NetBSD$"); |
|
* T -> $(varspec) op value |
* T -> $(varspec) op value |
* T -> $(varspec) == "string" |
* T -> $(varspec) == "string" |
* T -> $(varspec) != "string" |
* T -> $(varspec) != "string" |
|
* T -> "string" |
* T -> ( E ) |
* T -> ( E ) |
* T -> ! T |
* T -> ! T |
* op -> == | != | > | < | >= | <= |
* op -> == | != | > | < | >= | <= |
Line 151 static Token CondT(Boolean); |
|
Line 152 static Token CondT(Boolean); |
|
static Token CondF(Boolean); |
static Token CondF(Boolean); |
static Token CondE(Boolean); |
static Token CondE(Boolean); |
|
|
static struct If { |
static const struct If { |
const char *form; /* Form of if */ |
const char *form; /* Form of if */ |
int formlen; /* Length of form */ |
int formlen; /* Length of form */ |
Boolean doNot; /* TRUE if default function should be negated */ |
Boolean doNot; /* TRUE if default function should be negated */ |
Boolean (*defProc)(int, char *); /* Default function to apply */ |
Boolean (*defProc)(int, char *); /* Default function to apply */ |
} ifs[] = { |
} ifs[] = { |
{ "ifdef", 5, FALSE, CondDoDefined }, |
{ "def", 3, FALSE, CondDoDefined }, |
{ "ifndef", 6, TRUE, CondDoDefined }, |
{ "ndef", 4, TRUE, CondDoDefined }, |
{ "ifmake", 6, FALSE, CondDoMake }, |
{ "make", 4, FALSE, CondDoMake }, |
{ "ifnmake", 7, TRUE, CondDoMake }, |
{ "nmake", 5, TRUE, CondDoMake }, |
{ "if", 2, FALSE, CondDoDefined }, |
{ "", 0, FALSE, CondDoDefined }, |
{ NULL, 0, FALSE, NULL } |
{ NULL, 0, FALSE, NULL } |
}; |
}; |
|
|
Line 171 static char *condExpr; /* The ex |
|
Line 172 static char *condExpr; /* The ex |
|
static Token condPushBack=None; /* Single push-back token used in |
static Token condPushBack=None; /* Single push-back token used in |
* parsing */ |
* parsing */ |
|
|
#define MAXIF 30 /* greatest depth of #if'ing */ |
static unsigned int cond_depth = 0; /* current .if nesting level */ |
|
static unsigned int cond_min_depth = 0; /* depth at makefile open */ |
|
|
static Boolean condStack[MAXIF]; /* Stack of conditionals's values */ |
static int |
static int condTop = MAXIF; /* Top-most conditional */ |
istoken(const char *str, const char *tok, size_t len) |
static int skipIfLevel=0; /* Depth of skipped conditionals */ |
{ |
static Boolean skipLine = FALSE; /* Whether the parse module is skipping |
return strncmp(str, tok, len) == 0 && !isalpha((unsigned char)str[len]); |
* lines */ |
} |
|
|
/*- |
/*- |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
Line 243 CondGetArg(char **linePtr, char **argPtr |
|
Line 245 CondGetArg(char **linePtr, char **argPtr |
|
* than hitting the user with a warning message every time s/he uses |
* than hitting the user with a warning message every time s/he uses |
* the word 'make' or 'defined' at the beginning of a symbol... |
* the word 'make' or 'defined' at the beginning of a symbol... |
*/ |
*/ |
*argPtr = cp; |
*argPtr = NULL; |
return (0); |
return (0); |
} |
} |
|
|
Line 257 CondGetArg(char **linePtr, char **argPtr |
|
Line 259 CondGetArg(char **linePtr, char **argPtr |
|
*/ |
*/ |
buf = Buf_Init(16); |
buf = Buf_Init(16); |
|
|
while ((strchr(" \t)&|", *cp) == (char *)NULL) && (*cp != '\0')) { |
while ((strchr(" \t)&|", *cp) == NULL) && (*cp != '\0')) { |
if (*cp == '$') { |
if (*cp == '$') { |
/* |
/* |
* Parse the variable spec and install it as part of the argument |
* Parse the variable spec and install it as part of the argument |
Line 267 CondGetArg(char **linePtr, char **argPtr |
|
Line 269 CondGetArg(char **linePtr, char **argPtr |
|
*/ |
*/ |
char *cp2; |
char *cp2; |
int len; |
int len; |
Boolean doFree; |
void *freeIt; |
|
|
cp2 = Var_Parse(cp, VAR_CMD, TRUE, &len, &doFree); |
|
|
|
|
cp2 = Var_Parse(cp, VAR_CMD, TRUE, &len, &freeIt); |
Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2); |
Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2); |
if (doFree) { |
if (freeIt) |
free(cp2); |
free(freeIt); |
} |
|
cp += len; |
cp += len; |
} else { |
} else { |
Buf_AddByte(buf, (Byte)*cp); |
Buf_AddByte(buf, (Byte)*cp); |
Line 290 CondGetArg(char **linePtr, char **argPtr |
|
Line 290 CondGetArg(char **linePtr, char **argPtr |
|
cp++; |
cp++; |
} |
} |
if (parens && *cp != ')') { |
if (parens && *cp != ')') { |
Parse_Error (PARSE_WARNING, "Missing closing parenthesis for %s()", |
Parse_Error(PARSE_WARNING, "Missing closing parenthesis for %s()", |
func); |
func); |
return (0); |
return (0); |
} else if (parens) { |
} else if (parens) { |
Line 325 CondDoDefined(int argLen, char *arg) |
|
Line 325 CondDoDefined(int argLen, char *arg) |
|
Boolean result; |
Boolean result; |
|
|
arg[argLen] = '\0'; |
arg[argLen] = '\0'; |
if (Var_Value (arg, VAR_CMD, &p1) != (char *)NULL) { |
if (Var_Value(arg, VAR_CMD, &p1) != NULL) { |
result = TRUE; |
result = TRUE; |
} else { |
} else { |
result = FALSE; |
result = FALSE; |
Line 353 CondDoDefined(int argLen, char *arg) |
|
Line 353 CondDoDefined(int argLen, char *arg) |
|
static int |
static int |
CondStrMatch(ClientData string, ClientData pattern) |
CondStrMatch(ClientData string, ClientData pattern) |
{ |
{ |
return(!Str_Match((char *) string,(char *) pattern)); |
return(!Str_Match((char *)string,(char *)pattern)); |
} |
} |
|
|
/*- |
/*- |
Line 376 CondDoMake(int argLen, char *arg) |
|
Line 376 CondDoMake(int argLen, char *arg) |
|
Boolean result; |
Boolean result; |
|
|
arg[argLen] = '\0'; |
arg[argLen] = '\0'; |
if (Lst_Find (create, (ClientData)arg, CondStrMatch) == NILLNODE) { |
if (Lst_Find(create, arg, CondStrMatch) == NILLNODE) { |
result = FALSE; |
result = FALSE; |
} else { |
} else { |
result = TRUE; |
result = TRUE; |
Line 407 CondDoExists(int argLen, char *arg) |
|
Line 407 CondDoExists(int argLen, char *arg) |
|
|
|
arg[argLen] = '\0'; |
arg[argLen] = '\0'; |
path = Dir_FindFile(arg, dirSearchPath); |
path = Dir_FindFile(arg, dirSearchPath); |
if (path != (char *)NULL) { |
if (path != NULL) { |
result = TRUE; |
result = TRUE; |
free(path); |
free(path); |
} else { |
} else { |
result = FALSE; |
result = FALSE; |
} |
} |
arg[argLen] = savec; |
arg[argLen] = savec; |
|
if (DEBUG(COND)) { |
|
fprintf(debug_file, "exists(%s) result is \"%s\"\n", |
|
arg, path ? path : ""); |
|
} |
return (result); |
return (result); |
} |
} |
|
|
Line 527 CondCvtArg(char *str, double *value) |
|
Line 531 CondCvtArg(char *str, double *value) |
|
|
|
/*- |
/*- |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
|
* CondGetString -- |
|
* Get a string from a variable reference or an optionally quoted |
|
* string. This is called for the lhs and rhs of string compares. |
|
* |
|
* Results: |
|
* Sets freeIt if needed, |
|
* Sets quoted if string was quoted, |
|
* Returns NULL on error, |
|
* else returns string - absent any quotes. |
|
* |
|
* Side Effects: |
|
* Moves condExpr to end of this token. |
|
* |
|
* |
|
*----------------------------------------------------------------------- |
|
*/ |
|
/* coverity:[+alloc : arg-*2] */ |
|
static char * |
|
CondGetString(Boolean doEval, Boolean *quoted, void **freeIt) |
|
{ |
|
Buffer buf; |
|
char *cp; |
|
char *str; |
|
int len; |
|
int qt; |
|
char *start; |
|
|
|
buf = Buf_Init(0); |
|
str = NULL; |
|
*freeIt = NULL; |
|
*quoted = qt = *condExpr == '"' ? 1 : 0; |
|
if (qt) |
|
condExpr++; |
|
for (start = condExpr; *condExpr && str == NULL; condExpr++) { |
|
switch (*condExpr) { |
|
case '\\': |
|
if (condExpr[1] != '\0') { |
|
condExpr++; |
|
Buf_AddByte(buf, (Byte)*condExpr); |
|
} |
|
break; |
|
case '"': |
|
if (qt) { |
|
condExpr++; /* we don't want the quotes */ |
|
goto got_str; |
|
} else |
|
Buf_AddByte(buf, (Byte)*condExpr); /* likely? */ |
|
break; |
|
case ')': |
|
case '!': |
|
case '=': |
|
case '>': |
|
case '<': |
|
case ' ': |
|
case '\t': |
|
if (!qt) |
|
goto got_str; |
|
else |
|
Buf_AddByte(buf, (Byte)*condExpr); |
|
break; |
|
case '$': |
|
/* if we are in quotes, then an undefined variable is ok */ |
|
str = Var_Parse(condExpr, VAR_CMD, (qt ? 0 : doEval), |
|
&len, freeIt); |
|
if (str == var_Error) { |
|
if (*freeIt) { |
|
free(*freeIt); |
|
*freeIt = NULL; |
|
} |
|
/* |
|
* Even if !doEval, we still report syntax errors, which |
|
* is what getting var_Error back with !doEval means. |
|
*/ |
|
str = NULL; |
|
goto cleanup; |
|
} |
|
condExpr += len; |
|
/* |
|
* If the '$' was first char (no quotes), and we are |
|
* followed by space, the operator or end of expression, |
|
* we are done. |
|
*/ |
|
if ((condExpr == start + len) && |
|
(*condExpr == '\0' || |
|
isspace((unsigned char) *condExpr) || |
|
strchr("!=><)", *condExpr))) { |
|
goto cleanup; |
|
} |
|
/* |
|
* Nope, we better copy str to buf |
|
*/ |
|
for (cp = str; *cp; cp++) { |
|
Buf_AddByte(buf, (Byte)*cp); |
|
} |
|
if (*freeIt) { |
|
free(*freeIt); |
|
*freeIt = NULL; |
|
} |
|
str = NULL; /* not finished yet */ |
|
condExpr--; /* don't skip over next char */ |
|
break; |
|
default: |
|
Buf_AddByte(buf, (Byte)*condExpr); |
|
break; |
|
} |
|
} |
|
got_str: |
|
Buf_AddByte(buf, (Byte)'\0'); |
|
str = (char *)Buf_GetAll(buf, NULL); |
|
*freeIt = str; |
|
cleanup: |
|
Buf_Destroy(buf, FALSE); |
|
return str; |
|
} |
|
|
|
/*- |
|
*----------------------------------------------------------------------- |
* CondToken -- |
* CondToken -- |
* Return the next token from the input. |
* Return the next token from the input. |
* |
* |
Line 579 CondToken(Boolean doEval) |
|
Line 700 CondToken(Boolean doEval) |
|
case '\0': |
case '\0': |
t = EndOfFile; |
t = EndOfFile; |
break; |
break; |
|
case '"': |
case '$': { |
case '$': { |
char *lhs; |
char *lhs; |
char *rhs; |
char *rhs; |
char *op; |
char *op; |
int varSpecLen; |
void *lhsFree; |
Boolean doFree; |
void *rhsFree; |
|
Boolean lhsQuoted; |
|
Boolean rhsQuoted; |
|
|
|
rhs = NULL; |
|
lhsFree = rhsFree = FALSE; |
|
lhsQuoted = rhsQuoted = FALSE; |
|
|
/* |
/* |
* Parse the variable spec and skip over it, saving its |
* Parse the variable spec and skip over it, saving its |
* value in lhs. |
* value in lhs. |
*/ |
*/ |
t = Err; |
t = Err; |
lhs = Var_Parse(condExpr, VAR_CMD, doEval,&varSpecLen,&doFree); |
lhs = CondGetString(doEval, &lhsQuoted, &lhsFree); |
if (lhs == var_Error) { |
if (!lhs) { |
/* |
if (lhsFree) |
* Even if !doEval, we still report syntax errors, which |
free(lhsFree); |
* is what getting var_Error back with !doEval means. |
return Err; |
*/ |
|
return(Err); |
|
} |
|
condExpr += varSpecLen; |
|
|
|
if (!isspace((unsigned char) *condExpr) && |
|
strchr("!=><", *condExpr) == NULL) { |
|
Buffer buf; |
|
char *cp; |
|
|
|
buf = Buf_Init(0); |
|
|
|
for (cp = lhs; *cp; cp++) |
|
Buf_AddByte(buf, (Byte)*cp); |
|
|
|
if (doFree) |
|
free(lhs); |
|
|
|
for (;*condExpr && !isspace((unsigned char) *condExpr); |
|
condExpr++) |
|
Buf_AddByte(buf, (Byte)*condExpr); |
|
|
|
Buf_AddByte(buf, (Byte)'\0'); |
|
lhs = (char *)Buf_GetAll(buf, &varSpecLen); |
|
Buf_Destroy(buf, FALSE); |
|
|
|
doFree = TRUE; |
|
} |
} |
|
|
/* |
/* |
* Skip whitespace to get to the operator |
* Skip whitespace to get to the operator |
*/ |
*/ |
Line 650 CondToken(Boolean doEval) |
|
Line 750 CondToken(Boolean doEval) |
|
break; |
break; |
default: |
default: |
op = UNCONST("!="); |
op = UNCONST("!="); |
rhs = UNCONST("0"); |
if (lhsQuoted) |
|
rhs = UNCONST(""); |
|
else |
|
rhs = UNCONST("0"); |
|
|
goto do_compare; |
goto do_compare; |
} |
} |
Line 662 CondToken(Boolean doEval) |
|
Line 765 CondToken(Boolean doEval) |
|
"Missing right-hand-side of operator"); |
"Missing right-hand-side of operator"); |
goto error; |
goto error; |
} |
} |
rhs = condExpr; |
rhs = CondGetString(doEval, &rhsQuoted, &rhsFree); |
|
if (!rhs) { |
|
if (lhsFree) |
|
free(lhsFree); |
|
if (rhsFree) |
|
free(rhsFree); |
|
return Err; |
|
} |
do_compare: |
do_compare: |
if (*rhs == '"') { |
if (rhsQuoted || lhsQuoted) { |
/* |
|
* Doing a string comparison. Only allow == and != for |
|
* operators. |
|
*/ |
|
char *string; |
|
char *cp, *cp2; |
|
int qt; |
|
Buffer buf; |
|
|
|
do_string_compare: |
do_string_compare: |
if (((*op != '!') && (*op != '=')) || (op[1] != '=')) { |
if (((*op != '!') && (*op != '=')) || (op[1] != '=')) { |
Parse_Error(PARSE_WARNING, |
Parse_Error(PARSE_WARNING, |
Line 681 do_string_compare: |
|
Line 782 do_string_compare: |
|
goto error; |
goto error; |
} |
} |
|
|
buf = Buf_Init(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_AddByte(buf, (Byte)*cp); |
|
} else if (*cp == '$') { |
|
int len; |
|
Boolean freeIt; |
|
|
|
cp2 = Var_Parse(cp, VAR_CMD, doEval,&len, &freeIt); |
|
if (cp2 != var_Error) { |
|
Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2); |
|
if (freeIt) { |
|
free(cp2); |
|
} |
|
cp += len - 1; |
|
} else { |
|
Buf_AddByte(buf, (Byte)*cp); |
|
} |
|
} else { |
|
Buf_AddByte(buf, (Byte)*cp); |
|
} |
|
} |
|
|
|
Buf_AddByte(buf, (Byte)0); |
|
|
|
string = (char *)Buf_GetAll(buf, (int *)0); |
|
Buf_Destroy(buf, FALSE); |
|
|
|
if (DEBUG(COND)) { |
if (DEBUG(COND)) { |
printf("lhs = \"%s\", rhs = \"%s\", op = %.2s\n", |
fprintf(debug_file, "lhs = \"%s\", rhs = \"%s\", op = %.2s\n", |
lhs, string, op); |
lhs, rhs, op); |
} |
} |
/* |
/* |
* Null-terminate rhs and perform the comparison. |
* Null-terminate rhs and perform the comparison. |
* t is set to the result. |
* t is set to the result. |
*/ |
*/ |
if (*op == '=') { |
if (*op == '=') { |
t = strcmp(lhs, string) ? False : True; |
t = strcmp(lhs, rhs) ? False : True; |
} else { |
} else { |
t = strcmp(lhs, string) ? True : False; |
t = strcmp(lhs, rhs) ? True : False; |
} |
|
free(string); |
|
if (rhs == condExpr) { |
|
if (!qt && *cp == ')') |
|
condExpr = cp; |
|
else |
|
condExpr = cp + 1; |
|
} |
} |
} else { |
} else { |
/* |
/* |
Line 745 do_string_compare: |
|
Line 801 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 *string; |
char *cp; |
|
|
if (CondCvtArg(lhs, &left)) |
if (CondCvtArg(lhs, &left)) |
goto do_string_compare; |
goto do_string_compare; |
if (*rhs == '$') { |
if ((cp = CondCvtArg(rhs, &right)) && |
int len; |
|
Boolean freeIt; |
|
|
|
string = Var_Parse(rhs, VAR_CMD, 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 { |
|
char *cp; |
|
|
|
if ((cp = CondCvtArg(rhs, &right)) && |
|
cp == rhs) |
cp == rhs) |
goto do_string_compare; |
goto do_string_compare; |
if (rhs == condExpr) { |
|
/* |
|
* Skip over the right-hand side |
|
*/ |
|
if (cp) |
|
condExpr = cp; |
|
else |
|
condExpr = strchr(rhs, '\0'); |
|
} |
|
} |
|
|
|
if (DEBUG(COND)) { |
if (DEBUG(COND)) { |
printf("left = %f, right = %f, op = %.2s\n", left, |
fprintf(debug_file, "left = %f, right = %f, op = %.2s\n", left, |
right, op); |
right, op); |
} |
} |
switch(op[0]) { |
switch(op[0]) { |
Line 822 do_string_compare: |
|
Line 847 do_string_compare: |
|
} |
} |
} |
} |
error: |
error: |
if (doFree) |
if (lhsFree) |
free(lhs); |
free(lhsFree); |
|
if (rhsFree) |
|
free(rhsFree); |
break; |
break; |
} |
} |
default: { |
default: { |
Boolean (*evalProc)(int, char *); |
Boolean (*evalProc)(int, char *); |
Boolean invert = FALSE; |
Boolean invert = FALSE; |
char *arg; |
char *arg = NULL; |
int arglen; |
int arglen = 0; |
|
|
if (strncmp (condExpr, "defined", 7) == 0) { |
if (istoken(condExpr, "defined", 7)) { |
/* |
/* |
* Use CondDoDefined to evaluate the argument and |
* Use CondDoDefined to evaluate the argument and |
* CondGetArg to extract the argument from the 'function |
* CondGetArg to extract the argument from the 'function |
|
|
*/ |
*/ |
evalProc = CondDoDefined; |
evalProc = CondDoDefined; |
condExpr += 7; |
condExpr += 7; |
arglen = CondGetArg (&condExpr, &arg, "defined", TRUE); |
arglen = CondGetArg(&condExpr, &arg, "defined", TRUE); |
if (arglen == 0) { |
if (arglen == 0) { |
condExpr -= 7; |
condExpr -= 7; |
goto use_default; |
goto use_default; |
} |
} |
} else if (strncmp (condExpr, "make", 4) == 0) { |
} else if (istoken(condExpr, "make", 4)) { |
/* |
/* |
* Use CondDoMake to evaluate the argument and |
* Use CondDoMake to evaluate the argument and |
* CondGetArg to extract the argument from the 'function |
* CondGetArg to extract the argument from the 'function |
|
|
*/ |
*/ |
evalProc = CondDoMake; |
evalProc = CondDoMake; |
condExpr += 4; |
condExpr += 4; |
arglen = CondGetArg (&condExpr, &arg, "make", TRUE); |
arglen = CondGetArg(&condExpr, &arg, "make", TRUE); |
if (arglen == 0) { |
if (arglen == 0) { |
condExpr -= 4; |
condExpr -= 4; |
goto use_default; |
goto use_default; |
} |
} |
} else if (strncmp (condExpr, "exists", 6) == 0) { |
} else if (istoken(condExpr, "exists", 6)) { |
/* |
/* |
* Use CondDoExists to evaluate the argument and |
* Use CondDoExists to evaluate the argument and |
* CondGetArg to extract the argument from the |
* CondGetArg to extract the argument from the |
|
|
condExpr -= 6; |
condExpr -= 6; |
goto use_default; |
goto use_default; |
} |
} |
} else if (strncmp(condExpr, "empty", 5) == 0) { |
} else if (istoken(condExpr, "empty", 5)) { |
/* |
/* |
* Use Var_Parse to parse the spec in parens and return |
* Use Var_Parse to parse the spec in parens and return |
* True if the resulting string is empty. |
* True if the resulting string is empty. |
*/ |
*/ |
int length; |
int length; |
Boolean doFree; |
void *freeIt; |
char *val; |
char *val; |
|
|
condExpr += 5; |
condExpr += 5; |
|
|
for (arglen = 0; |
for (arglen = 0; condExpr[arglen] != '\0'; arglen += 1) { |
condExpr[arglen] != '(' && condExpr[arglen] != '\0'; |
if (condExpr[arglen] == '(') |
arglen += 1) |
break; |
continue; |
if (!isspace((unsigned char)condExpr[arglen])) |
|
Parse_Error(PARSE_WARNING, |
|
"Extra characters after \"empty\""); |
|
} |
|
|
if (condExpr[arglen] != '\0') { |
if (condExpr[arglen] != '\0') { |
val = Var_Parse(&condExpr[arglen - 1], VAR_CMD, |
val = Var_Parse(&condExpr[arglen - 1], VAR_CMD, |
FALSE, &length, &doFree); |
FALSE, &length, &freeIt); |
if (val == var_Error) { |
if (val == var_Error) { |
t = Err; |
t = Err; |
} else { |
} else { |
|
|
continue; |
continue; |
t = (*p == '\0') ? True : False; |
t = (*p == '\0') ? True : False; |
} |
} |
if (doFree) { |
if (freeIt) { |
free(val); |
free(freeIt); |
} |
} |
/* |
/* |
* Advance condExpr to beyond the closing ). Note that |
* Advance condExpr to beyond the closing ). Note that |
|
|
goto use_default; |
goto use_default; |
} |
} |
break; |
break; |
} else if (strncmp (condExpr, "target", 6) == 0) { |
} else if (istoken(condExpr, "target", 6)) { |
/* |
/* |
* Use CondDoTarget to evaluate the argument and |
* Use CondDoTarget to evaluate the argument and |
* CondGetArg to extract the argument from the |
* CondGetArg to extract the argument from the |
|
|
condExpr -= 6; |
condExpr -= 6; |
goto use_default; |
goto use_default; |
} |
} |
} else if (strncmp (condExpr, "commands", 8) == 0) { |
} else if (istoken(condExpr, "commands", 8)) { |
/* |
/* |
* Use CondDoCommands to evaluate the argument and |
* Use CondDoCommands to evaluate the argument and |
* CondGetArg to extract the argument from the |
* CondGetArg to extract the argument from the |
|
|
t = (!doEval || (* evalProc) (arglen, arg) ? |
t = (!doEval || (* evalProc) (arglen, arg) ? |
(invert ? False : True) : |
(invert ? False : True) : |
(invert ? True : False)); |
(invert ? True : False)); |
free(arg); |
if (arg) |
|
free(arg); |
break; |
break; |
} |
} |
} |
} |
Line 1059 CondF(Boolean doEval) |
|
Line 1090 CondF(Boolean doEval) |
|
if (l == True) { |
if (l == True) { |
l = CondF(doEval); |
l = CondF(doEval); |
} else { |
} else { |
(void) CondF(FALSE); |
(void)CondF(FALSE); |
} |
} |
} else { |
} else { |
/* |
/* |
* F -> T |
* F -> T |
*/ |
*/ |
CondPushBack (o); |
CondPushBack(o); |
} |
} |
} |
} |
return (l); |
return (l); |
Line 1106 CondE(Boolean doEval) |
|
Line 1137 CondE(Boolean doEval) |
|
if (l == False) { |
if (l == False) { |
l = CondE(doEval); |
l = CondE(doEval); |
} else { |
} else { |
(void) CondE(FALSE); |
(void)CondE(FALSE); |
} |
} |
} else { |
} else { |
/* |
/* |
* E -> F |
* E -> F |
*/ |
*/ |
CondPushBack (o); |
CondPushBack(o); |
} |
} |
} |
} |
return (l); |
return (l); |
Line 1167 Cond_EvalExpression(int dosetup, char *l |
|
Line 1198 Cond_EvalExpression(int dosetup, char *l |
|
case Err: |
case Err: |
err: |
err: |
if (eprint) |
if (eprint) |
Parse_Error (PARSE_FATAL, "Malformed conditional (%s)", |
Parse_Error(PARSE_FATAL, "Malformed conditional (%s)", |
line); |
line); |
return (COND_INVALID); |
return (COND_INVALID); |
default: |
default: |
|
|
* Cond_Eval -- |
* Cond_Eval -- |
* Evaluate the conditional in the passed line. The line |
* Evaluate the conditional in the passed line. The line |
* looks like this: |
* looks like this: |
* #<cond-type> <expr> |
* .<cond-type> <expr> |
* where <cond-type> is any of if, ifmake, ifnmake, ifdef, |
* where <cond-type> is any of if, ifmake, ifnmake, ifdef, |
* ifndef, elif, elifmake, elifnmake, elifdef, elifndef |
* ifndef, elif, elifmake, elifnmake, elifdef, elifndef |
* and <expr> consists of &&, ||, !, make(target), defined(variable) |
* and <expr> consists of &&, ||, !, make(target), defined(variable) |
|
|
* Side Effects: |
* Side Effects: |
* None. |
* None. |
* |
* |
|
* Note that the states IF_ACTIVE and ELSE_ACTIVE are only different in order |
|
* to detect splurious .else lines (as are SKIP_TO_ELSE and SKIP_TO_ENDIF) |
|
* otherwise .else could be treated as '.elif 1'. |
|
* |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
int |
int |
Cond_Eval(char *line) |
Cond_Eval(char *line) |
{ |
{ |
struct If *ifp; |
#define MAXIF 64 /* maximum depth of .if'ing */ |
Boolean isElse; |
enum if_states { |
Boolean value = FALSE; |
IF_ACTIVE, /* .if or .elif part active */ |
|
ELSE_ACTIVE, /* .else part active */ |
|
SEARCH_FOR_ELIF, /* searching for .elif/else to execute */ |
|
SKIP_TO_ELSE, /* has been true, but not seen '.else' */ |
|
SKIP_TO_ENDIF /* nothing else to execute */ |
|
}; |
|
static enum if_states cond_state[MAXIF + 1] = { IF_ACTIVE }; |
|
|
|
const struct If *ifp; |
|
Boolean isElif; |
|
Boolean value; |
int level; /* Level at which to report errors. */ |
int level; /* Level at which to report errors. */ |
|
enum if_states state; |
|
|
level = PARSE_FATAL; |
level = PARSE_FATAL; |
|
|
for (line++; *line == ' ' || *line == '\t'; line++) { |
/* skip leading character (the '.') and any whitespace */ |
|
for (line++; *line == ' ' || *line == '\t'; line++) |
continue; |
continue; |
} |
|
|
|
/* |
/* Find what type of if we're dealing with. */ |
* Find what type of if we're dealing with. The result is left |
if (line[0] == 'e') { |
* in ifp and isElse is set TRUE if it's an elif line. |
if (line[1] != 'l') { |
*/ |
if (!istoken(line + 1, "ndif", 4)) |
if (line[0] == 'e' && line[1] == 'l') { |
return COND_INVALID; |
|
/* End of conditional section */ |
|
if (cond_depth == cond_min_depth) { |
|
Parse_Error(level, "if-less endif"); |
|
return COND_PARSE; |
|
} |
|
/* Return state for previous conditional */ |
|
cond_depth--; |
|
return cond_state[cond_depth] <= ELSE_ACTIVE ? COND_PARSE : COND_SKIP; |
|
} |
|
|
|
/* Quite likely this is 'else' or 'elif' */ |
line += 2; |
line += 2; |
isElse = TRUE; |
if (istoken(line, "se", 2)) { |
} else if (strncmp (line, "endif", 5) == 0) { |
/* It is else... */ |
/* |
if (cond_depth == cond_min_depth) { |
* End of a conditional section. If skipIfLevel is non-zero, that |
Parse_Error(level, "if-less else"); |
* conditional was skipped, so lines following it should also be |
return COND_INVALID; |
* 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 |
state = cond_state[cond_depth]; |
* a decent if. |
switch (state) { |
*/ |
case SEARCH_FOR_ELIF: |
if (skipIfLevel != 0) { |
state = ELSE_ACTIVE; |
skipIfLevel -= 1; |
break; |
return (COND_SKIP); |
case ELSE_ACTIVE: |
} else { |
case SKIP_TO_ENDIF: |
if (condTop == MAXIF) { |
Parse_Error(PARSE_WARNING, "extra else"); |
Parse_Error (level, "if-less endif"); |
/* FALLTHROUGH */ |
return (COND_INVALID); |
default: |
} else { |
case IF_ACTIVE: |
skipLine = FALSE; |
case SKIP_TO_ELSE: |
condTop += 1; |
state = SKIP_TO_ENDIF; |
return (COND_PARSE); |
break; |
} |
} |
|
cond_state[cond_depth] = state; |
|
return state <= ELSE_ACTIVE ? COND_PARSE : COND_SKIP; |
} |
} |
} else { |
/* Assume for now it is an elif */ |
isElse = FALSE; |
isElif = TRUE; |
} |
} else |
|
isElif = FALSE; |
|
|
|
if (line[0] != 'i' || line[1] != 'f') |
|
/* Not an ifxxx or elifxxx line */ |
|
return COND_INVALID; |
|
|
/* |
/* |
* Figure out what sort of conditional it is -- what its default |
* Figure out what sort of conditional it is -- what its default |
* function is, etc. -- by looking in the table of valid "ifs" |
* function is, etc. -- by looking in the table of valid "ifs" |
*/ |
*/ |
for (ifp = ifs; ifp->form != (char *)0; ifp++) { |
line += 2; |
if (strncmp (ifp->form, line, ifp->formlen) == 0) { |
for (ifp = ifs; ; ifp++) { |
|
if (ifp->form == NULL) |
|
return COND_INVALID; |
|
if (istoken(ifp->form, line, ifp->formlen)) { |
|
line += ifp->formlen; |
break; |
break; |
} |
} |
} |
} |
|
|
if (ifp->form == (char *) 0) { |
/* Now we know what sort of 'if' it is... */ |
/* |
state = cond_state[cond_depth]; |
* Nothing fit. If the first word on the line is actually |
|
* "else", it's a valid conditional whose value is the inverse |
if (isElif) { |
* of the previous if we parsed. |
if (cond_depth == cond_min_depth) { |
*/ |
Parse_Error(level, "if-less elif"); |
if (isElse && (line[0] == 's') && (line[1] == 'e')) { |
return COND_INVALID; |
if (condTop == MAXIF) { |
} |
Parse_Error (level, "if-less else"); |
if (state == SKIP_TO_ENDIF || state == ELSE_ACTIVE) |
return (COND_INVALID); |
Parse_Error(PARSE_WARNING, "extra elif"); |
} else if (skipIfLevel == 0) { |
if (state != SEARCH_FOR_ELIF) { |
value = !condStack[condTop]; |
/* Either just finished the 'true' block, or already SKIP_TO_ELSE */ |
} else { |
cond_state[cond_depth] = SKIP_TO_ELSE; |
return (COND_SKIP); |
return COND_SKIP; |
} |
|
} else { |
|
/* |
|
* Not a valid conditional type. No error... |
|
*/ |
|
return (COND_INVALID); |
|
} |
} |
} else { |
} else { |
if (isElse) { |
if (cond_depth >= MAXIF) { |
if (condTop == MAXIF) { |
Parse_Error(PARSE_FATAL, "Too many nested if's. %d max.", MAXIF); |
Parse_Error (level, "if-less elif"); |
return COND_INVALID; |
return (COND_INVALID); |
} |
} else if (skipIfLevel != 0) { |
cond_depth++; |
/* |
if (state > ELSE_ACTIVE) { |
* If skipping this conditional, just ignore the whole thing. |
/* If we aren't parsing the data, treat as always false */ |
* If we don't, the user might be employing a variable that's |
cond_state[cond_depth] = SKIP_TO_ELSE; |
* undefined, for which there's an enclosing ifdef that |
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... |
|
*/ |
|
skipIfLevel += 1; |
|
return(COND_SKIP); |
|
} |
} |
|
|
/* |
|
* Initialize file-global variables for parsing |
|
*/ |
|
condDefProc = ifp->defProc; |
|
condInvert = ifp->doNot; |
|
|
|
line += ifp->formlen; |
|
if (Cond_EvalExpression(0, line, &value, 1) == COND_INVALID) |
|
return COND_INVALID; |
|
} |
|
if (!isElse) { |
|
condTop -= 1; |
|
} else if ((skipIfLevel != 0) || condStack[condTop]) { |
|
/* |
|
* 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... |
|
*/ |
|
skipLine = TRUE; |
|
return (COND_SKIP); |
|
} |
} |
|
|
if (condTop < 0) { |
/* Initialize file-global variables for parsing the expression */ |
/* |
condDefProc = ifp->defProc; |
* This is the one case where we can definitely proclaim a fatal |
condInvert = ifp->doNot; |
* error. If we don't, we're hosed. |
|
*/ |
/* And evaluate the conditional expresssion */ |
Parse_Error (PARSE_FATAL, "Too many nested if's. %d max.", MAXIF); |
if (Cond_EvalExpression(0, line, &value, 1) == COND_INVALID) { |
return (COND_INVALID); |
/* Although we get make to reprocess the line, set a state */ |
} else { |
cond_state[cond_depth] = SEARCH_FOR_ELIF; |
condStack[condTop] = value; |
return COND_INVALID; |
skipLine = !value; |
} |
return (value ? COND_PARSE : COND_SKIP); |
|
|
if (!value) { |
|
cond_state[cond_depth] = SEARCH_FOR_ELIF; |
|
return COND_SKIP; |
} |
} |
|
cond_state[cond_depth] = IF_ACTIVE; |
|
return COND_PARSE; |
} |
} |
|
|
|
|
Line 1357 Cond_Eval(char *line) |
|
Line 1390 Cond_Eval(char *line) |
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
void |
void |
Cond_End(void) |
Cond_restore_depth(unsigned int saved_depth) |
{ |
{ |
if (condTop != MAXIF) { |
int open_conds = cond_depth - cond_min_depth; |
Parse_Error(PARSE_FATAL, "%d open conditional%s", MAXIF-condTop, |
|
MAXIF-condTop == 1 ? "" : "s"); |
if (open_conds != 0 || saved_depth > cond_depth) { |
|
Parse_Error(PARSE_FATAL, "%d open conditional%s", open_conds, |
|
open_conds == 1 ? "" : "s"); |
|
cond_depth = cond_min_depth; |
} |
} |
condTop = MAXIF; |
|
|
cond_min_depth = saved_depth; |
|
} |
|
|
|
unsigned int |
|
Cond_save_depth(void) |
|
{ |
|
int depth = cond_min_depth; |
|
|
|
cond_min_depth = cond_depth; |
|
return depth; |
} |
} |