version 1.27, 2002/04/17 16:45:02 |
version 1.28, 2002/06/11 21:12:11 |
|
|
#include "dir.h" |
#include "dir.h" |
#include "buf.h" |
#include "buf.h" |
#include "cond.h" |
#include "cond.h" |
|
#include "cond_int.h" |
|
#include "condhashconsts.h" |
#include "error.h" |
#include "error.h" |
#include "var.h" |
#include "var.h" |
#include "varname.h" |
#include "varname.h" |
|
|
#include "main.h" |
#include "main.h" |
#include "gnode.h" |
#include "gnode.h" |
#include "lst.h" |
#include "lst.h" |
|
#include "ohash.h" |
|
|
|
|
/* The parsing of conditional expressions is based on this grammar: |
/* The parsing of conditional expressions is based on this grammar: |
|
|
static const char *find_cond(const char *); |
static const char *find_cond(const char *); |
|
|
|
|
static struct If { |
struct If { |
char *form; /* Form of if */ |
bool isElse; /* true for else forms */ |
int formlen; /* Length of form */ |
bool doNot; /* true for embedded negation */ |
bool doNot; /* true if default function should be negated */ |
|
bool (*defProc)(struct Name *); |
bool (*defProc)(struct Name *); |
/* Default function to apply */ |
/* function to apply */ |
} ifs[] = { |
|
{ "ifdef", 5, false, CondDoDefined }, |
|
{ "ifndef", 6, true, CondDoDefined }, |
|
{ "ifmake", 6, false, CondDoMake }, |
|
{ "ifnmake", 7, true, CondDoMake }, |
|
{ "if", 2, false, CondDoDefined }, |
|
{ NULL, 0, false, NULL } |
|
}; |
}; |
|
|
|
static struct If ifs[] = { |
|
{ false, false, CondDoDefined }, /* if, ifdef */ |
|
{ false, true, CondDoDefined }, /* ifndef */ |
|
{ false, false, CondDoMake }, /* ifmake */ |
|
{ false, true, CondDoMake }, /* ifnmake */ |
|
{ true, false, CondDoDefined }, /* elif, elifdef */ |
|
{ true, true, CondDoDefined }, /* elifndef */ |
|
{ true, false, CondDoMake }, /* elifmake */ |
|
{ true, true, CondDoMake }, /* elifnmake */ |
|
{ true, false, NULL } |
|
}; |
|
|
|
#define COND_IF_INDEX 0 |
|
#define COND_IFDEF_INDEX 0 |
|
#define COND_IFNDEF_INDEX 1 |
|
#define COND_IFMAKE_INDEX 2 |
|
#define COND_IFNMAKE_INDEX 3 |
|
#define COND_ELIF_INDEX 4 |
|
#define COND_ELIFDEF_INDEX 4 |
|
#define COND_ELIFNDEF_INDEX 5 |
|
#define COND_ELIFMAKE_INDEX 6 |
|
#define COND_ELIFNMAKE_INDEX 7 |
|
#define COND_ELSE_INDEX 8 |
|
|
static bool condInvert; /* Invert the default function */ |
static bool condInvert; /* Invert the default function */ |
static bool (*condDefProc) /* Default function to apply */ |
static bool (*condDefProc) /* Default function to apply */ |
(struct Name *); |
(struct Name *); |
|
|
return l; |
return l; |
} |
} |
|
|
/* A conditional line looks like this: |
/* Evaluate conditional in line. |
* <cond-type> <expr> |
* returns COND_SKIP, COND_PARSE, COND_INVALID, COND_ISFOR, COND_ISINCLUDE, |
|
* COND_ISUNDEF. |
|
* A conditional line looks like this: |
|
* <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) |
* and parenthetical groupings thereof. |
* and parenthetical groupings thereof. |
*/ |
*/ |
int |
int |
Cond_Eval(line) |
Cond_Eval(const char *line) |
const char *line; /* Line to parse */ |
|
{ |
{ |
struct If *ifp; |
/* find end of keyword */ |
bool isElse; |
const char *end; |
bool value = false; |
u_int32_t k; |
int level; /* Level at which to report errors. */ |
size_t len; |
|
struct If *ifp; |
|
bool value = false; |
|
int level; /* Level at which to report errors. */ |
|
|
level = PARSE_FATAL; |
level = PARSE_FATAL; |
|
|
/* Stuff we are looking for can be if*, elif*, else, or endif. |
for (end = line; islower(*end); end++) |
* otherwise, this is not our turf. */ |
; |
|
/* quick path: recognize special targets early on */ |
/* Find what type of if we're dealing with. The result is left |
if (*end == '.' || *end == ':') |
* in ifp and isElse is set true if it's an elif line. */ |
return COND_INVALID; |
if (line[0] == 'e' && line[1] == 'l') { |
len = end - line; |
line += 2; |
k = ohash_interval(line, &end); |
isElse = true; |
switch(k % MAGICSLOTS2) { |
} else if (strncmp(line, "endif", 5) == 0) { |
case K_COND_IF % MAGICSLOTS2: |
|
if (k == K_COND_IF && len == strlen(COND_IF) && |
|
strncmp(line, COND_IF, len) == 0) { |
|
ifp = ifs + COND_IF_INDEX; |
|
} else |
|
return COND_INVALID; |
|
break; |
|
case K_COND_IFDEF % MAGICSLOTS2: |
|
if (k == K_COND_IFDEF && len == strlen(COND_IFDEF) && |
|
strncmp(line, COND_IFDEF, len) == 0) { |
|
ifp = ifs + COND_IFDEF_INDEX; |
|
} else |
|
return COND_INVALID; |
|
break; |
|
case K_COND_IFNDEF % MAGICSLOTS2: |
|
if (k == K_COND_IFNDEF && len == strlen(COND_IFNDEF) && |
|
strncmp(line, COND_IFNDEF, len) == 0) { |
|
ifp = ifs + COND_IFNDEF_INDEX; |
|
} else |
|
return COND_INVALID; |
|
break; |
|
case K_COND_IFMAKE % MAGICSLOTS2: |
|
if (k == K_COND_IFMAKE && len == strlen(COND_IFMAKE) && |
|
strncmp(line, COND_IFMAKE, len) == 0) { |
|
ifp = ifs + COND_IFMAKE_INDEX; |
|
} else |
|
return COND_INVALID; |
|
break; |
|
case K_COND_IFNMAKE % MAGICSLOTS2: |
|
if (k == K_COND_IFNMAKE && len == strlen(COND_IFNMAKE) && |
|
strncmp(line, COND_IFNMAKE, len) == 0) { |
|
ifp = ifs + COND_IFNMAKE_INDEX; |
|
} else |
|
return COND_INVALID; |
|
break; |
|
case K_COND_ELIF % MAGICSLOTS2: |
|
if (k == K_COND_ELIF && len == strlen(COND_ELIF) && |
|
strncmp(line, COND_ELIF, len) == 0) { |
|
ifp = ifs + COND_ELIF_INDEX; |
|
} else |
|
return COND_INVALID; |
|
break; |
|
case K_COND_ELIFDEF % MAGICSLOTS2: |
|
if (k == K_COND_ELIFDEF && len == strlen(COND_ELIFDEF) && |
|
strncmp(line, COND_ELIFDEF, len) == 0) { |
|
ifp = ifs + COND_ELIFDEF_INDEX; |
|
} else |
|
return COND_INVALID; |
|
break; |
|
case K_COND_ELIFNDEF % MAGICSLOTS2: |
|
if (k == K_COND_ELIFNDEF && len == strlen(COND_ELIFNDEF) && |
|
strncmp(line, COND_ELIFNDEF, len) == 0) { |
|
ifp = ifs + COND_ELIFNDEF_INDEX; |
|
} else |
|
return COND_INVALID; |
|
break; |
|
case K_COND_ELIFMAKE % MAGICSLOTS2: |
|
if (k == K_COND_ELIFMAKE && len == strlen(COND_ELIFMAKE) && |
|
strncmp(line, COND_ELIFMAKE, len) == 0) { |
|
ifp = ifs + COND_ELIFMAKE_INDEX; |
|
} else |
|
return COND_INVALID; |
|
break; |
|
case K_COND_ELIFNMAKE % MAGICSLOTS2: |
|
if (k == K_COND_ELIFNMAKE && len == strlen(COND_ELIFNMAKE) && |
|
strncmp(line, COND_ELIFNMAKE, len) == 0) { |
|
ifp = ifs + COND_ELIFNMAKE_INDEX; |
|
} else |
|
return COND_INVALID; |
|
break; |
|
case K_COND_ELSE % MAGICSLOTS2: |
|
/* valid conditional whose value is the inverse |
|
* of the previous if we parsed. */ |
|
if (k == K_COND_ELSE && len == strlen(COND_ELSE) && |
|
strncmp(line, COND_ELSE, len) == 0) { |
|
if (condTop == MAXIF) { |
|
Parse_Error(level, "if-less else"); |
|
return COND_INVALID; |
|
} else if (skipIfLevel == 0) { |
|
value = !condStack[condTop].value; |
|
ifp = ifs + COND_ELSE_INDEX; |
|
} else |
|
return COND_SKIP; |
|
} else |
|
return COND_INVALID; |
|
break; |
|
case K_COND_ENDIF % MAGICSLOTS2: |
|
if (k == K_COND_ENDIF && len == strlen(COND_ENDIF) && |
|
strncmp(line, COND_ENDIF, len) == 0) { |
/* End of a conditional section. If skipIfLevel is non-zero, that |
/* End of a conditional section. If skipIfLevel is non-zero, that |
* conditional was skipped, so lines following it should also be |
* conditional was skipped, so lines following it should also be |
* skipped. Hence, we return COND_SKIP. Otherwise, the conditional |
* skipped. Hence, we return COND_SKIP. Otherwise, the conditional |
* was read so succeeding lines should be parsed (think about it...) |
* was read so succeeding lines should be parsed (think about it...) |
* 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. */ |
if (skipIfLevel != 0) { |
if (skipIfLevel != 0) { |
skipIfLevel -= 1; |
skipIfLevel -= 1; |
return COND_SKIP; |
return COND_SKIP; |
} else { |
|
if (condTop == MAXIF) { |
|
Parse_Error(level, "if-less endif"); |
|
return COND_INVALID; |
|
} else { |
} else { |
skipLine = false; |
if (condTop == MAXIF) { |
condTop += 1; |
Parse_Error(level, "if-less endif"); |
return COND_PARSE; |
return COND_INVALID; |
|
} else { |
|
skipLine = false; |
|
condTop += 1; |
|
return COND_PARSE; |
|
} |
} |
} |
} |
} else |
} else |
return COND_INVALID; |
isElse = false; |
break; |
|
/* Recognize other keywords there, to simplify parser's task */ |
/* Figure out what sort of conditional it is -- what its default |
case K_COND_FOR % MAGICSLOTS2: |
* function is, etc. -- by looking in the table of valid "ifs" */ |
if (k == K_COND_FOR && len == strlen(COND_FOR) && |
for (ifp = ifs; ifp->form != NULL; ifp++) { |
strncmp(line, COND_FOR, len) == 0) |
if (strncmp(ifp->form, line, ifp->formlen) == 0) |
return COND_ISFOR; |
break; |
else |
|
return COND_INVALID; |
|
case K_COND_UNDEF % MAGICSLOTS2: |
|
if (k == K_COND_UNDEF && len == strlen(COND_UNDEF) && |
|
strncmp(line, COND_UNDEF, len) == 0) |
|
return COND_ISUNDEF; |
|
else |
|
return COND_INVALID; |
|
case K_COND_INCLUDE % MAGICSLOTS2: |
|
if (k == K_COND_INCLUDE && len == strlen(COND_INCLUDE) && |
|
strncmp(line, COND_INCLUDE, len) == 0) |
|
return COND_ISINCLUDE; |
|
else |
|
return COND_INVALID; |
|
default: |
|
/* Not a valid conditional type. No error... */ |
|
return COND_INVALID; |
} |
} |
|
|
if (ifp->form == NULL) { |
if (ifp->isElse) { |
/* Nothing fits. If the first word on the line is actually |
if (condTop == MAXIF) { |
* "else", it's a valid conditional whose value is the inverse |
Parse_Error(level, "if-less elif"); |
* 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) |
|
value = !condStack[condTop].value; |
|
else |
|
return COND_SKIP; |
|
} else |
|
/* Not a valid conditional type. No error... */ |
|
return COND_INVALID; |
return COND_INVALID; |
} else { |
} else if (skipIfLevel != 0) { |
if (isElse) { |
/* If skipping this conditional, just ignore the whole thing. |
if (condTop == MAXIF) { |
* If we don't, the user might be employing a variable that's |
Parse_Error(level, "if-less elif"); |
* undefined, for which there's an enclosing ifdef that |
return COND_INVALID; |
* we're skipping... */ |
} else if (skipIfLevel != 0) { |
|
/* 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; |
|
} |
|
} 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; |
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; |
|
} |
|
|
|
if (ifp->defProc) { |
/* Initialize file-global variables for parsing. */ |
/* Initialize file-global variables for parsing. */ |
condDefProc = ifp->defProc; |
condDefProc = ifp->defProc; |
condInvert = ifp->doNot; |
condInvert = ifp->doNot; |
|
|
line += ifp->formlen; |
line += len; |
|
|
while (*line == ' ' || *line == '\t') |
while (*line == ' ' || *line == '\t') |
line++; |
line++; |
|
|
break; |
break; |
} |
} |
} |
} |
if (!isElse) |
|
|
if (!ifp->isElse) |
condTop -= 1; |
condTop -= 1; |
else if (skipIfLevel != 0 || condStack[condTop].value) { |
else if (skipIfLevel != 0 || condStack[condTop].value) { |
/* If this is an else-type conditional, it should only take effect |
/* If this is an else-type conditional, it should only take effect |