Rework the directive parsing code. Instead of using a lot of strcmp()s
on every line that starts with a dot use a minimal perfect hash function and a single strcmp() on the first word after the dot to find out whether it is really a directive call and, if yes, which one. Then directly dispatch to a handler function for that directive (or fall through to the dependency handling code). This makes the directive parse a little bit more strict about the syntax: the directive word must be followed by a character that is not alphanumerical and not an underline (making .undefFOO illegal); .endif and .else can only be followed by comments.
This commit is contained in:
parent
f2968c80c9
commit
e0e1cda47d
@ -127,18 +127,21 @@ static Token CondT(Boolean);
|
||||
static Token CondF(Boolean);
|
||||
static Token CondE(Boolean);
|
||||
|
||||
static struct If {
|
||||
char *form; /* Form of if */
|
||||
int formlen; /* Length of form */
|
||||
static const struct If {
|
||||
Boolean doNot; /* TRUE if default function should be negated */
|
||||
CondProc *defProc; /* Default function to apply */
|
||||
Boolean isElse; /* actually el<XXX> */
|
||||
} 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 }
|
||||
[COND_IF] = { FALSE, CondDoDefined, FALSE },
|
||||
[COND_IFDEF] = { FALSE, CondDoDefined, FALSE },
|
||||
[COND_IFNDEF] = { TRUE, CondDoDefined, FALSE },
|
||||
[COND_IFMAKE] = { FALSE, CondDoMake, FALSE },
|
||||
[COND_IFNMAKE] = { TRUE, CondDoMake, FALSE },
|
||||
[COND_ELIF] = { FALSE, CondDoDefined, TRUE },
|
||||
[COND_ELIFDEF] = { FALSE, CondDoDefined, TRUE },
|
||||
[COND_ELIFNDEF] = { TRUE, CondDoDefined, TRUE },
|
||||
[COND_ELIFMAKE] = { FALSE, CondDoMake, TRUE },
|
||||
[COND_ELIFNMAKE] = { TRUE, CondDoMake, TRUE },
|
||||
};
|
||||
|
||||
static Boolean condInvert; /* Invert the default function */
|
||||
@ -153,7 +156,7 @@ static int condLineno[MAXIF]; /* Line numbers of the opening .if */
|
||||
static int condTop = MAXIF; /* Top-most conditional */
|
||||
static int skipIfLevel = 0; /* Depth of skipped conditionals */
|
||||
static int skipIfLineno[MAXIF]; /* Line numbers of skipped .ifs */
|
||||
static Boolean skipLine = FALSE; /* Whether the parse module is skipping
|
||||
Boolean skipLine = FALSE; /* Whether the parse module is skipping
|
||||
* lines */
|
||||
|
||||
/**
|
||||
@ -1005,171 +1008,84 @@ CondE(Boolean doEval)
|
||||
}
|
||||
|
||||
/**
|
||||
* Cond_Eval --
|
||||
* Evaluate the conditional in the passed line. The line
|
||||
* looks like this:
|
||||
* .<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)
|
||||
* and parenthetical groupings thereof.
|
||||
*
|
||||
* 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.
|
||||
* Cond_If
|
||||
* Handle .if<X> and .elif<X> directives.
|
||||
* This function is called even when we're skipping.
|
||||
*/
|
||||
int
|
||||
Cond_Eval(char *line, int lineno)
|
||||
void
|
||||
Cond_If(char *line, int code, int lineno)
|
||||
{
|
||||
struct If *ifp;
|
||||
Boolean isElse;
|
||||
Boolean value = FALSE;
|
||||
int level; /* Level at which to report errors. */
|
||||
const struct If *ifp;
|
||||
Boolean value;
|
||||
|
||||
level = PARSE_FATAL;
|
||||
ifp = &ifs[code];
|
||||
|
||||
for (line++; *line == ' ' || *line == '\t'; line++) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 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.
|
||||
*/
|
||||
if (ifp->isElse) {
|
||||
if (condTop == MAXIF) {
|
||||
Parse_Error(PARSE_FATAL, "if-less elif");
|
||||
return;
|
||||
}
|
||||
if (skipIfLevel != 0) {
|
||||
skipIfLevel -= 1;
|
||||
return (COND_SKIP);
|
||||
} else {
|
||||
if (condTop == MAXIF) {
|
||||
Parse_Error(level, "if-less endif");
|
||||
return (COND_INVALID);
|
||||
} else {
|
||||
skipLine = FALSE;
|
||||
condTop += 1;
|
||||
return (COND_PARSE);
|
||||
}
|
||||
/*
|
||||
* 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...
|
||||
*/
|
||||
skipIfLineno[skipIfLevel - 1] = lineno;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
isElse = FALSE;
|
||||
|
||||
} else if (skipLine) {
|
||||
/*
|
||||
* Don't even try to evaluate a conditional that's
|
||||
* not an else if we're skipping things...
|
||||
*/
|
||||
skipIfLineno[skipIfLevel] = lineno;
|
||||
skipIfLevel += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Figure out what sort of conditional it is -- what its default
|
||||
* function is, etc. -- by looking in the table of valid "ifs"
|
||||
* Initialize file-global variables for parsing
|
||||
*/
|
||||
for (ifp = ifs; ifp->form != NULL; ifp++) {
|
||||
if (strncmp(ifp->form, line, ifp->formlen) == 0) {
|
||||
break;
|
||||
}
|
||||
condDefProc = ifp->defProc;
|
||||
condInvert = ifp->doNot;
|
||||
|
||||
while (*line == ' ' || *line == '\t') {
|
||||
line++;
|
||||
}
|
||||
|
||||
if (ifp->form == NULL) {
|
||||
/*
|
||||
* Nothing fit. 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')) {
|
||||
if (condTop == MAXIF) {
|
||||
Parse_Error(level, "if-less else");
|
||||
return (COND_INVALID);
|
||||
} else if (skipIfLevel == 0) {
|
||||
value = !condStack[condTop];
|
||||
lineno = condLineno[condTop];
|
||||
} else {
|
||||
return (COND_SKIP);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Not a valid conditional type. No error...
|
||||
*/
|
||||
return (COND_INVALID);
|
||||
}
|
||||
condExpr = line;
|
||||
condPushBack = None;
|
||||
|
||||
} else {
|
||||
if (isElse) {
|
||||
if (condTop == MAXIF) {
|
||||
Parse_Error(level, "if-less elif");
|
||||
return (COND_INVALID);
|
||||
|
||||
} 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...
|
||||
*/
|
||||
skipIfLineno[skipIfLevel - 1] = lineno;
|
||||
return (COND_SKIP);
|
||||
}
|
||||
} else if (skipLine) {
|
||||
/*
|
||||
* Don't even try to evaluate a conditional that's
|
||||
* not an else if we're skipping things...
|
||||
*/
|
||||
skipIfLineno[skipIfLevel] = lineno;
|
||||
skipIfLevel += 1;
|
||||
return (COND_SKIP);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize file-global variables for parsing
|
||||
*/
|
||||
condDefProc = ifp->defProc;
|
||||
condInvert = ifp->doNot;
|
||||
|
||||
line += ifp->formlen;
|
||||
|
||||
while (*line == ' ' || *line == '\t') {
|
||||
line++;
|
||||
}
|
||||
|
||||
condExpr = line;
|
||||
condPushBack = None;
|
||||
|
||||
switch (CondE(TRUE)) {
|
||||
case True:
|
||||
if (CondToken(TRUE) == EndOfFile) {
|
||||
value = TRUE;
|
||||
break;
|
||||
}
|
||||
switch (CondE(TRUE)) {
|
||||
case True:
|
||||
if (CondToken(TRUE) != EndOfFile)
|
||||
goto err;
|
||||
/*FALLTHRU*/
|
||||
value = TRUE;
|
||||
break;
|
||||
|
||||
case False:
|
||||
if (CondToken(TRUE) == EndOfFile) {
|
||||
value = FALSE;
|
||||
break;
|
||||
}
|
||||
/*FALLTHRU*/
|
||||
case False:
|
||||
if (CondToken(TRUE) != EndOfFile)
|
||||
goto err;
|
||||
value = FALSE;
|
||||
break;
|
||||
|
||||
case Err:
|
||||
err:
|
||||
Parse_Error(level, "Malformed conditional (%s)", line);
|
||||
return (COND_INVALID);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
case Err:
|
||||
err: Parse_Error(PARSE_FATAL, "Malformed conditional (%s)", line);
|
||||
return;
|
||||
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
if (!isElse) {
|
||||
|
||||
if (!ifp->isElse) {
|
||||
/* push this value */
|
||||
condTop -= 1;
|
||||
|
||||
} 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 its corresponding if was evaluated and FALSE.
|
||||
@ -1178,7 +1094,7 @@ Cond_Eval(char *line, int lineno)
|
||||
* stack unmolested so later elif's don't screw up...
|
||||
*/
|
||||
skipLine = TRUE;
|
||||
return (COND_SKIP);
|
||||
return;
|
||||
}
|
||||
|
||||
if (condTop < 0) {
|
||||
@ -1186,15 +1102,91 @@ Cond_Eval(char *line, int lineno)
|
||||
* 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;
|
||||
condLineno[condTop] = lineno;
|
||||
skipLine = !value;
|
||||
return (value ? COND_PARSE : COND_SKIP);
|
||||
Parse_Error(PARSE_FATAL, "Too many nested if's. %d max.",MAXIF);
|
||||
return;
|
||||
}
|
||||
|
||||
/* push */
|
||||
condStack[condTop] = value;
|
||||
condLineno[condTop] = lineno;
|
||||
skipLine = !value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cond_Else
|
||||
* Handle .else statement.
|
||||
*/
|
||||
void
|
||||
Cond_Else(char *line __unused, int code __unused, int lineno __unused)
|
||||
{
|
||||
|
||||
while (isspace((u_char)*line))
|
||||
line++;
|
||||
|
||||
if (*line != '\0') {
|
||||
Parse_Error(PARSE_WARNING, "junk after .else ignored '%s'", line);
|
||||
}
|
||||
|
||||
if (condTop == MAXIF) {
|
||||
Parse_Error(PARSE_FATAL, "if-less else");
|
||||
return;
|
||||
}
|
||||
if (skipIfLevel != 0)
|
||||
return;
|
||||
|
||||
if (skipIfLevel != 0 || condStack[condTop]) {
|
||||
/*
|
||||
* An else 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...
|
||||
* XXX How does this work with two .else's?
|
||||
*/
|
||||
skipLine = TRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
/* inverse value */
|
||||
condStack[condTop] = !condStack[condTop];
|
||||
skipLine = !condStack[condTop];
|
||||
}
|
||||
|
||||
/**
|
||||
* Cond_Endif
|
||||
* Handle .endif statement.
|
||||
*/
|
||||
void
|
||||
Cond_Endif(char *line __unused, int code __unused, int lineno __unused)
|
||||
{
|
||||
|
||||
while (isspace((u_char)*line))
|
||||
line++;
|
||||
|
||||
if (*line != '\0') {
|
||||
Parse_Error(PARSE_WARNING, "junk after .endif ignored '%s'", line);
|
||||
}
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
if (skipIfLevel != 0) {
|
||||
skipIfLevel -= 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (condTop == MAXIF) {
|
||||
Parse_Error(PARSE_FATAL, "if-less endif");
|
||||
return;
|
||||
}
|
||||
|
||||
/* pop */
|
||||
skipLine = FALSE;
|
||||
condTop += 1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -48,7 +48,26 @@
|
||||
#define COND_SKIP 1 /* Skip the next lines */
|
||||
#define COND_INVALID 2 /* Not a conditional statement */
|
||||
|
||||
int Cond_Eval(char *, int);
|
||||
enum {
|
||||
COND_IF,
|
||||
COND_IFDEF,
|
||||
COND_IFNDEF,
|
||||
COND_IFMAKE,
|
||||
COND_IFNMAKE,
|
||||
COND_ELSE,
|
||||
COND_ELIF,
|
||||
COND_ELIFDEF,
|
||||
COND_ELIFNDEF,
|
||||
COND_ELIFMAKE,
|
||||
COND_ELIFNMAKE,
|
||||
COND_ENDIF,
|
||||
};
|
||||
|
||||
void Cond_If(char *, int, int);
|
||||
void Cond_Else(char *, int, int);
|
||||
void Cond_Endif(char *, int, int);
|
||||
void Cond_End(void);
|
||||
|
||||
extern Boolean skipLine;
|
||||
|
||||
#endif /* cond_h_6e96ad7c */
|
||||
|
@ -78,144 +78,142 @@ static char *forVar; /* Iteration variable */
|
||||
static Buffer *forBuf; /* Commands in loop */
|
||||
static Lst forLst; /* List of items */
|
||||
|
||||
/*-
|
||||
*-----------------------------------------------------------------------
|
||||
* For_Eval --
|
||||
/**
|
||||
* For_For
|
||||
* Evaluate the for loop in the passed line. The line
|
||||
* looks like this:
|
||||
* .for <variable> in <varlist>
|
||||
* The line pointer points just behind the for.
|
||||
*
|
||||
* Results:
|
||||
* TRUE: We found a for loop, or we are inside a for loop
|
||||
* FALSE: We did not find a for loop, or we found the end of the for
|
||||
* for loop.
|
||||
*
|
||||
* Side Effects:
|
||||
* None.
|
||||
*
|
||||
*-----------------------------------------------------------------------
|
||||
* TRUE: Syntax ok.
|
||||
* FALSE: Syntax error.
|
||||
*/
|
||||
int
|
||||
For_Eval(char *line)
|
||||
Boolean
|
||||
For_For(char *line)
|
||||
{
|
||||
char *ptr;
|
||||
char *sub;
|
||||
char *wrd;
|
||||
int level; /* Level at which to report errors. */
|
||||
char *sub;
|
||||
Buffer *buf;
|
||||
size_t varlen;
|
||||
|
||||
ptr = line;
|
||||
level = PARSE_FATAL;
|
||||
|
||||
if (forLevel == 0) {
|
||||
/*
|
||||
* maybe start of a for loop
|
||||
*/
|
||||
Buffer *buf;
|
||||
size_t varlen;
|
||||
/*
|
||||
* Skip space between for and the variable.
|
||||
*/
|
||||
for (ptr++; *ptr && isspace((u_char)*ptr); ptr++)
|
||||
;
|
||||
|
||||
for (ptr++; *ptr && isspace((unsigned char)*ptr); ptr++)
|
||||
;
|
||||
/*
|
||||
* If we are not in a for loop quickly determine if
|
||||
* the statement is a for.
|
||||
*/
|
||||
if (ptr[0] != 'f' || ptr[1] != 'o' || ptr[2] != 'r' ||
|
||||
!isspace((unsigned char)ptr[3]))
|
||||
return (FALSE);
|
||||
ptr += 3;
|
||||
/*
|
||||
* Grab the variable
|
||||
*/
|
||||
for (wrd = ptr; *ptr && !isspace((u_char)*ptr); ptr++)
|
||||
;
|
||||
|
||||
/*
|
||||
* we found a for loop, and now we are going to parse it.
|
||||
*/
|
||||
while (*ptr && isspace((unsigned char)*ptr))
|
||||
ptr++;
|
||||
buf = Buf_Init(0);
|
||||
Buf_AppendRange(buf, wrd, ptr);
|
||||
forVar = Buf_GetAll(buf, &varlen);
|
||||
|
||||
/*
|
||||
* Grab the variable
|
||||
*/
|
||||
buf = Buf_Init(0);
|
||||
for (wrd = ptr; *ptr && !isspace((unsigned char)*ptr); ptr++)
|
||||
;
|
||||
Buf_AppendRange(buf, wrd, ptr);
|
||||
if (varlen == 0) {
|
||||
Buf_Destroy(buf, TRUE);
|
||||
Parse_Error(PARSE_FATAL, "missing variable in for");
|
||||
return (FALSE);
|
||||
}
|
||||
Buf_Destroy(buf, FALSE);
|
||||
|
||||
forVar = (char *)Buf_GetAll(buf, &varlen);
|
||||
if (varlen == 0) {
|
||||
/* XXXHB Buf_Destroy(buf, TRUE) */
|
||||
Parse_Error(level, "missing variable in for");
|
||||
return (0);
|
||||
}
|
||||
Buf_Destroy(buf, FALSE);
|
||||
/*
|
||||
* Skip to 'in'.
|
||||
*/
|
||||
while (*ptr && isspace((u_char)*ptr))
|
||||
ptr++;
|
||||
|
||||
while (*ptr && isspace((unsigned char)*ptr))
|
||||
ptr++;
|
||||
/*
|
||||
* Grab the `in'
|
||||
*/
|
||||
if (ptr[0] != 'i' || ptr[1] != 'n' || !isspace((u_char)ptr[2])) {
|
||||
free(forVar);
|
||||
Parse_Error(PARSE_FATAL, "missing `in' in for");
|
||||
fprintf(stderr, "%s\n", ptr);
|
||||
return (FALSE);
|
||||
}
|
||||
ptr += 3;
|
||||
|
||||
/*
|
||||
* Grab the `in'
|
||||
*/
|
||||
if (ptr[0] != 'i' || ptr[1] != 'n' ||
|
||||
!isspace((unsigned char)ptr[2])) {
|
||||
/* XXXHB free(forVar) */
|
||||
Parse_Error(level, "missing `in' in for");
|
||||
printf("%s\n", ptr);
|
||||
return (0);
|
||||
}
|
||||
ptr += 3;
|
||||
/*
|
||||
* Skip to values
|
||||
*/
|
||||
while (*ptr && isspace((u_char)*ptr))
|
||||
ptr++;
|
||||
|
||||
while (*ptr && isspace((unsigned char)*ptr))
|
||||
ptr++;
|
||||
/*
|
||||
* Make a list with the remaining words
|
||||
* XXX should use brk_string here.
|
||||
*/
|
||||
sub = Buf_Peel(Var_Subst(NULL, ptr, VAR_CMD, FALSE));
|
||||
for (ptr = sub; *ptr != '\0' && isspace((u_char)*ptr); ptr++)
|
||||
;
|
||||
|
||||
/*
|
||||
* Make a list with the remaining words
|
||||
*/
|
||||
sub = Buf_Peel(Var_Subst(NULL, ptr, VAR_CMD, FALSE));
|
||||
for (ptr = sub; *ptr && isspace((unsigned char)*ptr); ptr++)
|
||||
;
|
||||
|
||||
Lst_Init(&forLst);
|
||||
buf = Buf_Init(0);
|
||||
for (wrd = ptr; *ptr != '\0'; ptr++) {
|
||||
if (isspace((unsigned char)*ptr)) {
|
||||
Buf_AppendRange(buf, wrd, ptr);
|
||||
Lst_AtFront(&forLst, Buf_Peel(buf));
|
||||
|
||||
buf = Buf_Init(0);
|
||||
while (*ptr && isspace((unsigned char)*ptr))
|
||||
ptr++;
|
||||
wrd = ptr--;
|
||||
}
|
||||
}
|
||||
DEBUGF(FOR, ("For: Iterator %s List %s\n", forVar, sub));
|
||||
if (ptr - wrd > 0) {
|
||||
Lst_Init(&forLst);
|
||||
buf = Buf_Init(0);
|
||||
for (wrd = ptr; *ptr != '\0'; ptr++) {
|
||||
if (isspace((u_char)*ptr)) {
|
||||
Buf_AppendRange(buf, wrd, ptr);
|
||||
Lst_AtFront(&forLst, Buf_Peel(buf));
|
||||
} else {
|
||||
Buf_Destroy(buf, TRUE);
|
||||
}
|
||||
free(sub);
|
||||
|
||||
forBuf = Buf_Init(0);
|
||||
forLevel++;
|
||||
return (1);
|
||||
buf = Buf_Init(0);
|
||||
while (*ptr != '\0' && isspace((u_char)*ptr))
|
||||
ptr++;
|
||||
wrd = ptr--;
|
||||
}
|
||||
}
|
||||
DEBUGF(FOR, ("For: Iterator %s List %s\n", forVar, sub));
|
||||
|
||||
if (ptr - wrd > 0) {
|
||||
Buf_AppendRange(buf, wrd, ptr);
|
||||
Lst_AtFront(&forLst, Buf_Peel(buf));
|
||||
} else {
|
||||
Buf_Destroy(buf, TRUE);
|
||||
}
|
||||
free(sub);
|
||||
|
||||
forBuf = Buf_Init(0);
|
||||
forLevel++;
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* For_Eval
|
||||
* Eat a line of the .for body looking for embedded .for loops
|
||||
* and the .endfor
|
||||
*/
|
||||
Boolean
|
||||
For_Eval(char *line)
|
||||
{
|
||||
char *ptr;
|
||||
|
||||
ptr = line;
|
||||
|
||||
if (*ptr == '.') {
|
||||
/*
|
||||
* Need to check for 'endfor' and 'for' to find the end
|
||||
* of our loop or to find embedded for loops.
|
||||
*/
|
||||
for (ptr++; *ptr && isspace((unsigned char)*ptr); ptr++)
|
||||
for (ptr++; *ptr != '\0' && isspace((u_char)*ptr); ptr++)
|
||||
;
|
||||
|
||||
/* XXX the isspace is wrong */
|
||||
if (strncmp(ptr, "endfor", 6) == 0 &&
|
||||
(isspace((unsigned char)ptr[6]) || !ptr[6])) {
|
||||
(isspace((u_char)ptr[6]) || ptr[6] == '\0')) {
|
||||
DEBUGF(FOR, ("For: end for %d\n", forLevel));
|
||||
if (--forLevel < 0) {
|
||||
Parse_Error(level, "for-less endfor");
|
||||
return (0);
|
||||
if (forLevel == 0) {
|
||||
/* should not be here */
|
||||
abort();
|
||||
}
|
||||
forLevel--;
|
||||
|
||||
} else if (strncmp(ptr, "for", 3) == 0 &&
|
||||
isspace((unsigned char)ptr[3])) {
|
||||
isspace((u_char)ptr[3])) {
|
||||
forLevel++;
|
||||
DEBUGF(FOR, ("For: new loop %d\n", forLevel));
|
||||
}
|
||||
@ -227,10 +225,10 @@ For_Eval(char *line)
|
||||
*/
|
||||
Buf_Append(forBuf, line);
|
||||
Buf_AddByte(forBuf, (Byte)'\n');
|
||||
return (1);
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
return (0);
|
||||
return (FALSE);
|
||||
}
|
||||
|
||||
/*-
|
||||
|
@ -41,7 +41,10 @@
|
||||
#ifndef for_h_9d770f33
|
||||
#define for_h_9d770f33
|
||||
|
||||
int For_Eval(char *);
|
||||
#include "sprite.h"
|
||||
|
||||
Boolean For_For(char *);
|
||||
Boolean For_Eval(char *);
|
||||
void For_Run(int);
|
||||
|
||||
#endif /* for_h_9d770f33 */
|
||||
|
@ -242,6 +242,79 @@ static struct {
|
||||
{ ".WAIT", Wait, 0 },
|
||||
};
|
||||
|
||||
/*
|
||||
* Directive table. We use a hash table. This hash table has been generated
|
||||
* with mph which can be found on the usual GNU mirrors. If you change the
|
||||
* directives (adding, deleting, reordering) you need to create a new table
|
||||
* and hash function (directive_hash). The command line to generate the
|
||||
* table is:
|
||||
*
|
||||
* mph -d2 -m1 <tab | emitc -l -s
|
||||
*
|
||||
* Where tab is a file containing just the directive strings, one per line.
|
||||
*
|
||||
* While inporting the result of this the following changes have been made
|
||||
* to the generated code:
|
||||
*
|
||||
* prefix the names of the g, T0 and T1 arrays with 'directive_'.
|
||||
*
|
||||
* make the type of the tables 'const [un]signed char'.
|
||||
*
|
||||
* make the hash function use the length for termination,
|
||||
* not the trailing '\0'.
|
||||
*/
|
||||
static void parse_include(char *, int, int);
|
||||
static void parse_message(char *, int, int);
|
||||
static void parse_undef(char *, int, int);
|
||||
static void parse_for(char *, int, int);
|
||||
static void parse_endfor(char *, int, int);
|
||||
|
||||
static const signed char directive_g[] = {
|
||||
16, 0, -1, 14, 5, 2, 2, -1, 0, 0,
|
||||
-1, -1, 16, 11, -1, 15, -1, 14, 7, -1,
|
||||
8, 6, 1, -1, -1, 0, 4, 6, -1, 0,
|
||||
0, 2, 0, 13, -1, 14, -1, 0,
|
||||
};
|
||||
|
||||
static const unsigned char directive_T0[] = {
|
||||
11, 25, 14, 30, 14, 26, 23, 15, 9, 37,
|
||||
27, 32, 27, 1, 17, 27, 35, 13, 8, 22,
|
||||
8, 28, 7,
|
||||
};
|
||||
|
||||
static const unsigned char directive_T1[] = {
|
||||
19, 20, 31, 17, 29, 2, 7, 12, 1, 31,
|
||||
11, 18, 11, 20, 10, 2, 15, 19, 4, 10,
|
||||
13, 36, 3,
|
||||
};
|
||||
|
||||
static const struct directive {
|
||||
const char *name;
|
||||
int code;
|
||||
Boolean skip_flag; /* execute even when skipped */
|
||||
void (*func)(char *, int, int);
|
||||
} directives[] = {
|
||||
{ "elif", COND_ELIF, TRUE, Cond_If },
|
||||
{ "elifdef", COND_ELIFDEF, TRUE, Cond_If },
|
||||
{ "elifmake", COND_ELIFMAKE, TRUE, Cond_If },
|
||||
{ "elifndef", COND_ELIFNDEF, TRUE, Cond_If },
|
||||
{ "elifnmake", COND_ELIFNMAKE, TRUE, Cond_If },
|
||||
{ "else", COND_ELSE, TRUE, Cond_Else },
|
||||
{ "endfor", 0, FALSE, parse_endfor },
|
||||
{ "endif", COND_ENDIF, TRUE, Cond_Endif },
|
||||
{ "error", 1, FALSE, parse_message },
|
||||
{ "for", 0, FALSE, parse_for },
|
||||
{ "if", COND_IF, TRUE, Cond_If },
|
||||
{ "ifdef", COND_IFDEF, TRUE, Cond_If },
|
||||
{ "ifmake", COND_IFMAKE, TRUE, Cond_If },
|
||||
{ "ifndef", COND_IFNDEF, TRUE, Cond_If },
|
||||
{ "ifnmake", COND_IFNMAKE, TRUE, Cond_If },
|
||||
{ "include", 0, FALSE, parse_include },
|
||||
{ "undef", 0, FALSE, parse_undef },
|
||||
{ "warning", 0, FALSE, parse_message },
|
||||
};
|
||||
#define NDIRECTS (sizeof(directives) / sizeof(directives[0]))
|
||||
|
||||
/*-
|
||||
*----------------------------------------------------------------------
|
||||
* ParseFindKeyword --
|
||||
@ -1551,220 +1624,6 @@ Parse_AddIncludeDir(char *dir)
|
||||
Path_AddDir(&parseIncPath, dir);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
* ParseDoError --
|
||||
* Handle error directive
|
||||
*
|
||||
* The input is the line minus the ".error". We substitute variables,
|
||||
* print the message and exit(1) or just print a warning if the ".error"
|
||||
* directive is malformed.
|
||||
*
|
||||
*---------------------------------------------------------------------
|
||||
*/
|
||||
static void
|
||||
ParseDoError(char *errmsg)
|
||||
{
|
||||
Buffer *buf;
|
||||
|
||||
if (!isspace((unsigned char)*errmsg)) {
|
||||
Parse_Error(PARSE_WARNING, "invalid syntax: .error%s", errmsg);
|
||||
return;
|
||||
}
|
||||
|
||||
while (isspace((unsigned char)*errmsg))
|
||||
errmsg++;
|
||||
|
||||
buf = Var_Subst(NULL, errmsg, VAR_GLOBAL, FALSE);
|
||||
Parse_Error(PARSE_FATAL, "%s", Buf_Data(buf));
|
||||
Buf_Destroy(buf, TRUE);
|
||||
|
||||
/* Terminate immediately. */
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
* ParseDoWarning --
|
||||
* Handle warning directive
|
||||
*
|
||||
* The input is the line minus the ".warning". We substitute variables
|
||||
* and print the message or just print a warning if the ".warning"
|
||||
* directive is malformed.
|
||||
*
|
||||
*---------------------------------------------------------------------
|
||||
*/
|
||||
static void
|
||||
ParseDoWarning(char *warnmsg)
|
||||
{
|
||||
Buffer *buf;
|
||||
|
||||
if (!isspace((unsigned char)*warnmsg)) {
|
||||
Parse_Error(PARSE_WARNING, "invalid syntax: .warning%s",
|
||||
warnmsg);
|
||||
return;
|
||||
}
|
||||
|
||||
while (isspace((unsigned char)*warnmsg))
|
||||
warnmsg++;
|
||||
|
||||
buf = Var_Subst(NULL, warnmsg, VAR_GLOBAL, FALSE);
|
||||
Parse_Error(PARSE_WARNING, "%s", Buf_Data(buf));
|
||||
Buf_Destroy(buf, TRUE);
|
||||
}
|
||||
|
||||
/*-
|
||||
*---------------------------------------------------------------------
|
||||
* ParseDoInclude --
|
||||
* Push to another file.
|
||||
*
|
||||
* The input is the line minus the #include. A file spec is a string
|
||||
* enclosed in <> or "". The former is looked for only in sysIncPath.
|
||||
* The latter in . and the directories specified by -I command line
|
||||
* options
|
||||
*
|
||||
* Results:
|
||||
* None
|
||||
*
|
||||
* Side Effects:
|
||||
* A structure is added to the includes Lst and readProc.
|
||||
*---------------------------------------------------------------------
|
||||
*/
|
||||
static void
|
||||
ParseDoInclude(char *file)
|
||||
{
|
||||
char *fullname; /* full pathname of file */
|
||||
char endc; /* the character which ends the file spec */
|
||||
char *cp; /* current position in file spec */
|
||||
Boolean isSystem; /* TRUE if makefile is a system makefile */
|
||||
Buffer *buf;
|
||||
|
||||
/*
|
||||
* Skip to delimiter character so we know where to look
|
||||
*/
|
||||
while (*file == ' ' || *file == '\t') {
|
||||
file++;
|
||||
}
|
||||
|
||||
if (*file != '"' && *file != '<') {
|
||||
Parse_Error(PARSE_FATAL,
|
||||
".include filename must be delimited by '\"' or '<'");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the search path on which to find the include file based on the
|
||||
* characters which bracket its name. Angle-brackets imply it's
|
||||
* a system Makefile while double-quotes imply it's a user makefile
|
||||
*/
|
||||
if (*file == '<') {
|
||||
isSystem = TRUE;
|
||||
endc = '>';
|
||||
} else {
|
||||
isSystem = FALSE;
|
||||
endc = '"';
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip to matching delimiter
|
||||
*/
|
||||
for (cp = ++file; *cp && *cp != endc; cp++) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*cp != endc) {
|
||||
Parse_Error(PARSE_FATAL,
|
||||
"Unclosed %cinclude filename. '%c' expected", '.', endc);
|
||||
return;
|
||||
}
|
||||
*cp = '\0';
|
||||
|
||||
/*
|
||||
* Substitute for any variables in the file name before trying to
|
||||
* find the thing.
|
||||
*/
|
||||
buf = Var_Subst(NULL, file, VAR_CMD, FALSE);
|
||||
file = Buf_Peel(buf);
|
||||
|
||||
/*
|
||||
* Now we know the file's name and its search path, we attempt to
|
||||
* find the durn thing. A return of NULL indicates the file don't
|
||||
* exist.
|
||||
*/
|
||||
if (!isSystem) {
|
||||
/*
|
||||
* Include files contained in double-quotes are first searched
|
||||
* for relative to the including file's location. We don't want
|
||||
* to cd there, of course, so we just tack on the old file's
|
||||
* leading path components and call Dir_FindFile to see if
|
||||
* we can locate the beast.
|
||||
*/
|
||||
char *prefEnd, *Fname;
|
||||
|
||||
/* Make a temporary copy of this, to be safe. */
|
||||
Fname = estrdup(CURFILE->fname);
|
||||
|
||||
prefEnd = strrchr(Fname, '/');
|
||||
if (prefEnd != (char *)NULL) {
|
||||
char *newName;
|
||||
|
||||
*prefEnd = '\0';
|
||||
if (file[0] == '/')
|
||||
newName = estrdup(file);
|
||||
else
|
||||
newName = str_concat(Fname, file, STR_ADDSLASH);
|
||||
fullname = Path_FindFile(newName, &parseIncPath);
|
||||
if (fullname == NULL) {
|
||||
fullname = Path_FindFile(newName,
|
||||
&dirSearchPath);
|
||||
}
|
||||
free(newName);
|
||||
*prefEnd = '/';
|
||||
} else {
|
||||
fullname = NULL;
|
||||
}
|
||||
free(Fname);
|
||||
} else {
|
||||
fullname = NULL;
|
||||
}
|
||||
|
||||
if (fullname == NULL) {
|
||||
/*
|
||||
* System makefile or makefile wasn't found in same directory as
|
||||
* included makefile. Search for it first on the -I search path,
|
||||
* then on the .PATH search path, if not found in a -I
|
||||
* directory.
|
||||
* XXX: Suffix specific?
|
||||
*/
|
||||
fullname = Path_FindFile(file, &parseIncPath);
|
||||
if (fullname == NULL) {
|
||||
fullname = Path_FindFile(file, &dirSearchPath);
|
||||
}
|
||||
}
|
||||
|
||||
if (fullname == NULL) {
|
||||
/*
|
||||
* Still haven't found the makefile. Look for it on the system
|
||||
* path as a last resort.
|
||||
*/
|
||||
fullname = Path_FindFile(file, &sysIncPath);
|
||||
}
|
||||
|
||||
if (fullname == NULL) {
|
||||
*cp = endc;
|
||||
Parse_Error(PARSE_FATAL, "Could not find %s", file);
|
||||
/* XXXHB free(file) */
|
||||
return;
|
||||
}
|
||||
|
||||
free(file);
|
||||
|
||||
/*
|
||||
* We set up the name of the file to be the absolute
|
||||
* name of the include file so error messages refer to the right
|
||||
* place.
|
||||
*/
|
||||
ParsePushInput(fullname, NULL, NULL, 0);
|
||||
}
|
||||
|
||||
/*-
|
||||
*---------------------------------------------------------------------
|
||||
* Parse_FromString --
|
||||
@ -1809,7 +1668,6 @@ ParseTraditionalInclude(char *file)
|
||||
{
|
||||
char *fullname; /* full pathname of file */
|
||||
char *cp; /* current position in file spec */
|
||||
Buffer *buf;
|
||||
|
||||
/*
|
||||
* Skip over whitespace
|
||||
@ -1836,8 +1694,7 @@ ParseTraditionalInclude(char *file)
|
||||
* Substitute for any variables in the file name before trying to
|
||||
* find the thing.
|
||||
*/
|
||||
buf = Var_Subst(NULL, file, VAR_CMD, FALSE);
|
||||
file = Buf_Peel(buf);
|
||||
file = Buf_Peel(Var_Subst(NULL, file, VAR_CMD, FALSE));
|
||||
|
||||
/*
|
||||
* Now we know the file's name, we attempt to find the durn thing.
|
||||
@ -2249,6 +2106,312 @@ ParseFinishLine(void)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* parse_include
|
||||
* Parse an .include directive and push the file onto the input stack.
|
||||
* The input is the line minus the .include. A file spec is a string
|
||||
* enclosed in <> or "". The former is looked for only in sysIncPath.
|
||||
* The latter in . and the directories specified by -I command line
|
||||
* options
|
||||
*/
|
||||
static void
|
||||
parse_include(char *file, int code __unused, int lineno __unused)
|
||||
{
|
||||
char *fullname; /* full pathname of file */
|
||||
char endc; /* the character which ends the file spec */
|
||||
char *cp; /* current position in file spec */
|
||||
Boolean isSystem; /* TRUE if makefile is a system makefile */
|
||||
char *prefEnd, *Fname;
|
||||
char *newName;
|
||||
|
||||
/*
|
||||
* Skip to delimiter character so we know where to look
|
||||
*/
|
||||
while (*file == ' ' || *file == '\t') {
|
||||
file++;
|
||||
}
|
||||
|
||||
if (*file != '"' && *file != '<') {
|
||||
Parse_Error(PARSE_FATAL,
|
||||
".include filename must be delimited by '\"' or '<'");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the search path on which to find the include file based on the
|
||||
* characters which bracket its name. Angle-brackets imply it's
|
||||
* a system Makefile while double-quotes imply it's a user makefile
|
||||
*/
|
||||
if (*file == '<') {
|
||||
isSystem = TRUE;
|
||||
endc = '>';
|
||||
} else {
|
||||
isSystem = FALSE;
|
||||
endc = '"';
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip to matching delimiter
|
||||
*/
|
||||
for (cp = ++file; *cp != endc; cp++) {
|
||||
if (*cp == '\0') {
|
||||
Parse_Error(PARSE_FATAL,
|
||||
"Unclosed .include filename. '%c' expected", endc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
*cp = '\0';
|
||||
|
||||
/*
|
||||
* Substitute for any variables in the file name before trying to
|
||||
* find the thing.
|
||||
*/
|
||||
file = Buf_Peel(Var_Subst(NULL, file, VAR_CMD, FALSE));
|
||||
|
||||
/*
|
||||
* Now we know the file's name and its search path, we attempt to
|
||||
* find the durn thing. A return of NULL indicates the file don't
|
||||
* exist.
|
||||
*/
|
||||
if (!isSystem) {
|
||||
/*
|
||||
* Include files contained in double-quotes are first searched
|
||||
* for relative to the including file's location. We don't want
|
||||
* to cd there, of course, so we just tack on the old file's
|
||||
* leading path components and call Dir_FindFile to see if
|
||||
* we can locate the beast.
|
||||
*/
|
||||
|
||||
/* Make a temporary copy of this, to be safe. */
|
||||
Fname = estrdup(CURFILE->fname);
|
||||
|
||||
prefEnd = strrchr(Fname, '/');
|
||||
if (prefEnd != NULL) {
|
||||
*prefEnd = '\0';
|
||||
if (file[0] == '/')
|
||||
newName = estrdup(file);
|
||||
else
|
||||
newName = str_concat(Fname, file, STR_ADDSLASH);
|
||||
fullname = Path_FindFile(newName, &parseIncPath);
|
||||
if (fullname == NULL) {
|
||||
fullname = Path_FindFile(newName,
|
||||
&dirSearchPath);
|
||||
}
|
||||
free(newName);
|
||||
*prefEnd = '/';
|
||||
} else {
|
||||
fullname = NULL;
|
||||
}
|
||||
free(Fname);
|
||||
} else {
|
||||
fullname = NULL;
|
||||
}
|
||||
|
||||
if (fullname == NULL) {
|
||||
/*
|
||||
* System makefile or makefile wasn't found in same directory as
|
||||
* included makefile. Search for it first on the -I search path,
|
||||
* then on the .PATH search path, if not found in a -I
|
||||
* directory.
|
||||
* XXX: Suffix specific?
|
||||
*/
|
||||
fullname = Path_FindFile(file, &parseIncPath);
|
||||
if (fullname == NULL) {
|
||||
fullname = Path_FindFile(file, &dirSearchPath);
|
||||
}
|
||||
}
|
||||
|
||||
if (fullname == NULL) {
|
||||
/*
|
||||
* Still haven't found the makefile. Look for it on the system
|
||||
* path as a last resort.
|
||||
*/
|
||||
fullname = Path_FindFile(file, &sysIncPath);
|
||||
}
|
||||
|
||||
if (fullname == NULL) {
|
||||
*cp = endc;
|
||||
Parse_Error(PARSE_FATAL, "Could not find %s", file);
|
||||
free(file);
|
||||
return;
|
||||
}
|
||||
free(file);
|
||||
|
||||
/*
|
||||
* We set up the name of the file to be the absolute
|
||||
* name of the include file so error messages refer to the right
|
||||
* place.
|
||||
*/
|
||||
ParsePushInput(fullname, NULL, NULL, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* parse_message
|
||||
* Parse a .warning or .error directive
|
||||
*
|
||||
* The input is the line minus the ".error"/".warning". We substitute
|
||||
* variables, print the message and exit(1) (for .error) or just print
|
||||
* a warning if the directive is malformed.
|
||||
*/
|
||||
static void
|
||||
parse_message(char *line, int iserror, int lineno __unused)
|
||||
{
|
||||
|
||||
if (!isspace((u_char)*line)) {
|
||||
Parse_Error(PARSE_WARNING, "invalid syntax: .%s%s",
|
||||
iserror ? "error" : "warning", line);
|
||||
return;
|
||||
}
|
||||
|
||||
while (isspace((u_char)*line))
|
||||
line++;
|
||||
|
||||
line = Buf_Peel(Var_Subst(NULL, line, VAR_GLOBAL, FALSE));
|
||||
Parse_Error(iserror ? PARSE_FATAL : PARSE_WARNING, "%s", line);
|
||||
free(line);
|
||||
|
||||
if (iserror) {
|
||||
/* Terminate immediately. */
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* parse_undef
|
||||
* Parse an .undef directive.
|
||||
*/
|
||||
static void
|
||||
parse_undef(char *line, int code __unused, int lineno __unused)
|
||||
{
|
||||
char *cp;
|
||||
|
||||
while (isspace((u_char)*line))
|
||||
line++;
|
||||
|
||||
for (cp = line; !isspace((u_char)*cp) && *cp != '\0'; cp++) {
|
||||
;
|
||||
}
|
||||
*cp = '\0';
|
||||
|
||||
cp = Buf_Peel(Var_Subst(NULL, line, VAR_CMD, FALSE));
|
||||
Var_Delete(cp, VAR_GLOBAL);
|
||||
free(cp);
|
||||
}
|
||||
|
||||
/**
|
||||
* parse_for
|
||||
* Parse a .for directive.
|
||||
*/
|
||||
static void
|
||||
parse_for(char *line, int code __unused, int lineno)
|
||||
{
|
||||
|
||||
if (!For_For(line)) {
|
||||
/* syntax error */
|
||||
return;
|
||||
}
|
||||
line = NULL;
|
||||
|
||||
/*
|
||||
* Skip after the matching endfor.
|
||||
*/
|
||||
do {
|
||||
free(line);
|
||||
line = ParseSkipLine(0, 1);
|
||||
if (line == NULL) {
|
||||
Parse_Error(PARSE_FATAL,
|
||||
"Unexpected end of file in for loop.\n");
|
||||
return;
|
||||
}
|
||||
} while (For_Eval(line));
|
||||
free(line);
|
||||
|
||||
/* execute */
|
||||
For_Run(lineno);
|
||||
}
|
||||
|
||||
/**
|
||||
* parse_endfor
|
||||
* Parse endfor. This may only happen if there was no matching .for.
|
||||
*/
|
||||
static void
|
||||
parse_endfor(char *line __unused, int code __unused, int lineno __unused)
|
||||
{
|
||||
|
||||
Parse_Error(PARSE_FATAL, "for-less endfor");
|
||||
}
|
||||
|
||||
/**
|
||||
* directive_hash
|
||||
*/
|
||||
static int
|
||||
directive_hash(const u_char *key, size_t len)
|
||||
{
|
||||
unsigned f0, f1;
|
||||
const u_char *kp = key;
|
||||
|
||||
if (len < 2 || len > 9)
|
||||
return (-1);
|
||||
|
||||
for (f0 = f1 = 0; kp < key + len; ++kp) {
|
||||
if (*kp < 97 || *kp > 119)
|
||||
return (-1);
|
||||
f0 += directive_T0[-97 + *kp];
|
||||
f1 += directive_T1[-97 + *kp];
|
||||
}
|
||||
|
||||
f0 %= 38;
|
||||
f1 %= 38;
|
||||
|
||||
return (directive_g[f0] + directive_g[f1]) % 18;
|
||||
}
|
||||
|
||||
/**
|
||||
* parse_directive
|
||||
* Got a line starting with a '.'. Check if this is a directive
|
||||
* and parse it.
|
||||
*
|
||||
* return:
|
||||
* TRUE if line was a directive, FALSE otherwise.
|
||||
*/
|
||||
static Boolean
|
||||
parse_directive(char *line)
|
||||
{
|
||||
char *start;
|
||||
char *cp;
|
||||
int dir;
|
||||
|
||||
/*
|
||||
* Get the keyword:
|
||||
* .[[:space:]]*\([[:alpha:]][[:alnum:]_]*\).*
|
||||
* \1 is the keyword.
|
||||
*/
|
||||
for (start = line; isspace((u_char)*start); start++) {
|
||||
;
|
||||
}
|
||||
|
||||
if (!isalpha((u_char)*start)) {
|
||||
return (FALSE);
|
||||
}
|
||||
|
||||
cp = start + 1;
|
||||
while (isalnum((u_char)*cp) || *cp == '_') {
|
||||
cp++;
|
||||
}
|
||||
|
||||
dir = directive_hash(start, cp - start);
|
||||
if (dir < 0 || dir >= (int)NDIRECTS ||
|
||||
(size_t)(cp - start) != strlen(directives[dir].name) ||
|
||||
strncmp(start, directives[dir].name, cp - start) != 0) {
|
||||
/* not actually matched */
|
||||
return (FALSE);
|
||||
}
|
||||
|
||||
if (!skipLine || directives[dir].skip_flag)
|
||||
(*directives[dir].func)(cp, directives[dir].code,
|
||||
CURFILE->lineno);
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*-
|
||||
*---------------------------------------------------------------------
|
||||
@ -2270,8 +2433,6 @@ Parse_File(const char *name, FILE *stream)
|
||||
{
|
||||
char *cp; /* pointer into the line */
|
||||
char *line; /* the line we're working on */
|
||||
Buffer *buf;
|
||||
int lineno;
|
||||
|
||||
inLine = FALSE;
|
||||
fatals = 0;
|
||||
@ -2279,90 +2440,12 @@ Parse_File(const char *name, FILE *stream)
|
||||
ParsePushInput(estrdup(name), stream, NULL, 0);
|
||||
|
||||
while ((line = ParseReadLine()) != NULL) {
|
||||
if (*line == '.') {
|
||||
/*
|
||||
* Lines that begin with the special character
|
||||
* are either include or undef directives.
|
||||
*/
|
||||
for (cp = line + 1; isspace((unsigned char)*cp); cp++) {
|
||||
continue;
|
||||
}
|
||||
if (strncmp(cp, "include", 7) == 0) {
|
||||
ParseDoInclude(cp + 7);
|
||||
goto nextLine;
|
||||
} else if (strncmp(cp, "error", 5) == 0) {
|
||||
ParseDoError(cp + 5);
|
||||
goto nextLine;
|
||||
} else if (strncmp(cp, "warning", 7) == 0) {
|
||||
ParseDoWarning(cp + 7);
|
||||
goto nextLine;
|
||||
} else if (strncmp(cp, "undef", 5) == 0) {
|
||||
char *cp2;
|
||||
for (cp += 5; isspace((unsigned char)*cp);
|
||||
cp++) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (cp2 = cp; !isspace((unsigned char)*cp2) &&
|
||||
*cp2 != '\0'; cp2++) {
|
||||
continue;
|
||||
}
|
||||
|
||||
*cp2 = '\0';
|
||||
|
||||
buf = Var_Subst(NULL, cp, VAR_CMD, FALSE);
|
||||
cp = Buf_Peel(buf);
|
||||
|
||||
Var_Delete(cp, VAR_GLOBAL);
|
||||
goto nextLine;
|
||||
|
||||
} else if (For_Eval(line)) {
|
||||
lineno = CURFILE->lineno;
|
||||
do {
|
||||
/*
|
||||
* Skip after the matching end.
|
||||
*/
|
||||
free(line);
|
||||
line = ParseSkipLine(0, 1);
|
||||
if (line == NULL) {
|
||||
Parse_Error(PARSE_FATAL,
|
||||
"Unexpected end of"
|
||||
" file in for loop.\n");
|
||||
goto nextLine;
|
||||
}
|
||||
} while (For_Eval(line));
|
||||
For_Run(lineno);
|
||||
goto nextLine;
|
||||
|
||||
} else {
|
||||
/*
|
||||
* The line might be a conditional. Ask the
|
||||
* conditional module about it and act
|
||||
* accordingly
|
||||
*/
|
||||
int cond = Cond_Eval(line, CURFILE->lineno);
|
||||
|
||||
if (cond == COND_SKIP) {
|
||||
/*
|
||||
* Skip to next conditional that
|
||||
* evaluates to COND_PARSE.
|
||||
*/
|
||||
do {
|
||||
free(line);
|
||||
line = ParseSkipLine(1, 0);
|
||||
} while (line && Cond_Eval(line,
|
||||
CURFILE->lineno) != COND_PARSE);
|
||||
goto nextLine;
|
||||
}
|
||||
if (cond == COND_PARSE)
|
||||
goto nextLine;
|
||||
}
|
||||
if (*line == '.' && parse_directive(line + 1)) {
|
||||
/* directive consumed */
|
||||
goto nextLine;
|
||||
}
|
||||
if (*line == '#') {
|
||||
/*
|
||||
* If we're this far, the line must be
|
||||
* a comment.
|
||||
*/
|
||||
if (skipLine || *line == '#') {
|
||||
/* Skipping .if block or comment. */
|
||||
goto nextLine;
|
||||
}
|
||||
|
||||
@ -2434,7 +2517,7 @@ Parse_File(const char *name, FILE *stream)
|
||||
* have an operator and we're in a dependency
|
||||
* line's script, we assume it's actually a
|
||||
* shell command and add it to the current
|
||||
* list of targets.
|
||||
* list of targets. XXX this comment seems wrong.
|
||||
*/
|
||||
cp = line;
|
||||
if (isspace((unsigned char)line[0])) {
|
||||
@ -2449,8 +2532,7 @@ Parse_File(const char *name, FILE *stream)
|
||||
|
||||
ParseFinishLine();
|
||||
|
||||
buf = Var_Subst(NULL, line, VAR_CMD, TRUE);
|
||||
cp = Buf_Peel(buf);
|
||||
cp = Buf_Peel(Var_Subst(NULL, line, VAR_CMD, TRUE));
|
||||
|
||||
free(line);
|
||||
line = cp;
|
||||
@ -2479,25 +2561,6 @@ Parse_File(const char *name, FILE *stream)
|
||||
errx(1, "fatal errors encountered -- cannot continue");
|
||||
}
|
||||
|
||||
/*-
|
||||
*---------------------------------------------------------------------
|
||||
* Parse_Init --
|
||||
* initialize the parsing module
|
||||
*
|
||||
* Results:
|
||||
* none
|
||||
*
|
||||
* Side Effects:
|
||||
* the parseIncPath list is initialized...
|
||||
*---------------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
Parse_Init(void)
|
||||
{
|
||||
|
||||
mainNode = NULL;
|
||||
}
|
||||
|
||||
/*-
|
||||
*-----------------------------------------------------------------------
|
||||
* Parse_MainName --
|
||||
|
@ -54,7 +54,6 @@ Boolean Parse_IsVar(char *);
|
||||
void Parse_DoVar(char *, struct GNode *);
|
||||
void Parse_AddIncludeDir(char *);
|
||||
void Parse_File(const char *, FILE *);
|
||||
void Parse_Init(void);
|
||||
void Parse_FromString(char *, int);
|
||||
void Parse_MainName(struct Lst *);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user