version 1.19, 2004/01/06 01:18:52 |
version 1.23, 2004/04/13 16:06:23 |
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 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 */ |
#define MAXIF 64 /* greatest depth of #if'ing */ |
|
|
|
static Boolean finalElse[MAXIF+1][MAXIF+1]; /* Seen final else (stack) */ |
static Boolean condStack[MAXIF]; /* Stack of conditionals's values */ |
static Boolean condStack[MAXIF]; /* Stack of conditionals's values */ |
static int condTop = MAXIF; /* Top-most conditional */ |
static int condTop = MAXIF; /* Top-most conditional */ |
static int skipIfLevel=0; /* Depth of skipped conditionals */ |
static int skipIfLevel=0; /* Depth of skipped conditionals */ |
Line 527 CondCvtArg(char *str, double *value) |
|
Line 529 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 doFree 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. |
|
* |
|
* |
|
*----------------------------------------------------------------------- |
|
*/ |
|
static char * |
|
CondGetString(Boolean doEval, Boolean *quoted, Boolean *doFree) |
|
{ |
|
Buffer buf; |
|
char *cp; |
|
char *str; |
|
int len; |
|
int qt; |
|
char *start; |
|
|
|
buf = Buf_Init(0); |
|
str = 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, doFree); |
|
if (str == var_Error) { |
|
/* |
|
* 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 (*doFree) |
|
free(str); |
|
*doFree = FALSE; |
|
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); |
|
*doFree = TRUE; |
|
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 691 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; |
Boolean lhsFree; |
Boolean doFree; |
Boolean rhsFree; |
|
Boolean lhsQuoted; |
|
Boolean rhsQuoted; |
|
|
|
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) |
/* |
return Err; |
* 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; |
|
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 737 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 752 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) |
|
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 764 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", |
printf("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 783 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, |
printf("left = %f, right = %f, op = %.2s\n", left, |
Line 822 do_string_compare: |
|
Line 829 do_string_compare: |
|
} |
} |
} |
} |
error: |
error: |
if (doFree) |
if (lhsFree) |
free(lhs); |
free(lhs); |
|
if (rhsFree) |
|
free(rhs); |
break; |
break; |
} |
} |
default: { |
default: { |
Line 1232 Cond_Eval(char *line) |
|
Line 1241 Cond_Eval(char *line) |
|
* so we return COND_PARSE, unless this endif isn't paired with |
* so we return COND_PARSE, unless this endif isn't paired with |
* a decent if. |
* a decent if. |
*/ |
*/ |
|
finalElse[condTop][skipIfLevel] = FALSE; |
if (skipIfLevel != 0) { |
if (skipIfLevel != 0) { |
skipIfLevel -= 1; |
skipIfLevel -= 1; |
return (COND_SKIP); |
return (COND_SKIP); |
Line 1266 Cond_Eval(char *line) |
|
Line 1276 Cond_Eval(char *line) |
|
* of the previous if we parsed. |
* of the previous if we parsed. |
*/ |
*/ |
if (isElse && (line[0] == 's') && (line[1] == 'e')) { |
if (isElse && (line[0] == 's') && (line[1] == 'e')) { |
|
if (finalElse[condTop][skipIfLevel]) { |
|
Parse_Error (PARSE_WARNING, "extra else"); |
|
} else { |
|
finalElse[condTop][skipIfLevel] = TRUE; |
|
} |
if (condTop == MAXIF) { |
if (condTop == MAXIF) { |
Parse_Error (level, "if-less else"); |
Parse_Error (level, "if-less else"); |
return (COND_INVALID); |
return (COND_INVALID); |
Line 1300 Cond_Eval(char *line) |
|
Line 1315 Cond_Eval(char *line) |
|
* we're skipping things... |
* we're skipping things... |
*/ |
*/ |
skipIfLevel += 1; |
skipIfLevel += 1; |
|
if (skipIfLevel >= MAXIF) { |
|
Parse_Error (PARSE_FATAL, "Too many nested if's. %d max.", MAXIF); |
|
return (COND_INVALID); |
|
} |
|
finalElse[condTop][skipIfLevel] = FALSE; |
return(COND_SKIP); |
return(COND_SKIP); |
} |
} |
|
|
Line 1315 Cond_Eval(char *line) |
|
Line 1335 Cond_Eval(char *line) |
|
} |
} |
if (!isElse) { |
if (!isElse) { |
condTop -= 1; |
condTop -= 1; |
|
finalElse[condTop][skipIfLevel] = FALSE; |
} else if ((skipIfLevel != 0) || condStack[condTop]) { |
} else if ((skipIfLevel != 0) || condStack[condTop]) { |
/* |
/* |
* If this is an else-type conditional, it should only take effect |
* If this is an else-type conditional, it should only take effect |