version 1.5, 1994/06/06 22:45:23 |
version 1.15, 2003/04/17 15:57:52 |
|
|
|
/* $NetBSD$ */ |
|
|
/* |
/* |
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California. |
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California. |
* Copyright (c) 1988, 1989 by Adam de Boor |
* Copyright (c) 1988, 1989 by Adam de Boor |
|
|
* SUCH DAMAGE. |
* SUCH DAMAGE. |
*/ |
*/ |
|
|
|
#ifdef MAKE_BOOTSTRAP |
|
static char rcsid[] = "$NetBSD$"; |
|
#else |
|
#include <sys/cdefs.h> |
#ifndef lint |
#ifndef lint |
/* from: static char sccsid[] = "@(#)cond.c 5.6 (Berkeley) 6/1/90"; */ |
#if 0 |
static char *rcsid = "$Id$"; |
static char sccsid[] = "@(#)cond.c 8.2 (Berkeley) 1/2/94"; |
|
#else |
|
__RCSID("$NetBSD$"); |
|
#endif |
#endif /* not lint */ |
#endif /* not lint */ |
|
#endif |
|
|
/*- |
/*- |
* cond.c -- |
* cond.c -- |
Line 51 static char *rcsid = "$Id$"; |
|
Line 61 static char *rcsid = "$Id$"; |
|
*/ |
*/ |
|
|
#include <ctype.h> |
#include <ctype.h> |
#include <math.h> |
|
#include "make.h" |
#include "make.h" |
#include "hash.h" |
#include "hash.h" |
#include "dir.h" |
#include "dir.h" |
Line 68 static char *rcsid = "$Id$"; |
|
Line 78 static char *rcsid = "$Id$"; |
|
* T -> exists(file) |
* T -> exists(file) |
* T -> empty(varspec) |
* T -> empty(varspec) |
* T -> target(name) |
* T -> target(name) |
|
* T -> commands(name) |
* T -> symbol |
* T -> symbol |
* T -> $(varspec) op value |
* T -> $(varspec) op value |
* T -> $(varspec) == "string" |
* T -> $(varspec) == "string" |
|
|
* Structures to handle elegantly the different forms of #if's. The |
* Structures to handle elegantly the different forms of #if's. The |
* last two fields are stored in condInvert and condDefProc, respectively. |
* last two fields are stored in condInvert and condDefProc, respectively. |
*/ |
*/ |
static int CondGetArg __P((char **, char **, char *, Boolean)); |
static void CondPushBack(Token); |
static Boolean CondDoDefined __P((int, char *)); |
static int CondGetArg(char **, char **, char *, Boolean); |
static int CondStrMatch __P((ClientData, ClientData)); |
static Boolean CondDoDefined(int, char *); |
static Boolean CondDoMake __P((int, char *)); |
static int CondStrMatch(ClientData, ClientData); |
static Boolean CondDoExists __P((int, char *)); |
static Boolean CondDoMake(int, char *); |
static Boolean CondDoTarget __P((int, char *)); |
static Boolean CondDoExists(int, char *); |
static Boolean CondCvtArg __P((char *, double *)); |
static Boolean CondDoTarget(int, char *); |
static Token CondToken __P((Boolean)); |
static Boolean CondDoCommands(int, char *); |
static Token CondT __P((Boolean)); |
static Boolean CondCvtArg(char *, double *); |
static Token CondF __P((Boolean)); |
static Token CondToken(Boolean); |
static Token CondE __P((Boolean)); |
static Token CondT(Boolean); |
|
static Token CondF(Boolean); |
|
static Token CondE(Boolean); |
|
|
static struct If { |
static struct If { |
char *form; /* Form of if */ |
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)(); /* Default function to apply */ |
Boolean (*defProc)(int, char *); /* Default function to apply */ |
} ifs[] = { |
} ifs[] = { |
{ "ifdef", 5, FALSE, CondDoDefined }, |
{ "ifdef", 5, FALSE, CondDoDefined }, |
{ "ifndef", 6, TRUE, CondDoDefined }, |
{ "ifndef", 6, TRUE, CondDoDefined }, |
{ "ifmake", 6, FALSE, CondDoMake }, |
{ "ifmake", 6, FALSE, CondDoMake }, |
{ "ifnmake", 7, TRUE, CondDoMake }, |
{ "ifnmake", 7, TRUE, CondDoMake }, |
{ "if", 2, FALSE, CondDoDefined }, |
{ "if", 2, FALSE, CondDoDefined }, |
{ (char *)0, 0, FALSE, (Boolean (*)())0 } |
{ NULL, 0, FALSE, NULL } |
}; |
}; |
|
|
static Boolean condInvert; /* Invert the default function */ |
static Boolean condInvert; /* Invert the default function */ |
static Boolean (*condDefProc)(); /* Default function to apply */ |
static Boolean (*condDefProc)(int, char *); /* Default function to apply */ |
static char *condExpr; /* The expression to parse */ |
static char *condExpr; /* The expression to parse */ |
static Token condPushBack=None; /* Single push-back token used in |
static Token condPushBack=None; /* Single push-back token used in |
* parsing */ |
* parsing */ |
Line 141 static Boolean skipLine = FALSE; /* W |
|
Line 154 static Boolean skipLine = FALSE; /* W |
|
* Push back the most recent token read. We only need one level of |
* Push back the most recent token read. We only need one level of |
* this, so the thing is just stored in 'condPushback'. |
* this, so the thing is just stored in 'condPushback'. |
* |
* |
|
* Input: |
|
* t Token to push back into the "stream" |
|
* |
* Results: |
* Results: |
* None. |
* None. |
* |
* |
Line 150 static Boolean skipLine = FALSE; /* W |
|
Line 166 static Boolean skipLine = FALSE; /* W |
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
static void |
static void |
CondPushBack (t) |
CondPushBack(Token t) |
Token t; /* Token to push back into the "stream" */ |
|
{ |
{ |
condPushBack = t; |
condPushBack = t; |
} |
} |
Line 161 CondPushBack (t) |
|
Line 176 CondPushBack (t) |
|
* CondGetArg -- |
* CondGetArg -- |
* Find the argument of a built-in function. |
* Find the argument of a built-in function. |
* |
* |
|
* Input: |
|
* parens TRUE if arg should be bounded by parens |
|
* |
* Results: |
* Results: |
* The length of the argument and the address of the argument. |
* The length of the argument and the address of the argument. |
* |
* |
Line 171 CondPushBack (t) |
|
Line 189 CondPushBack (t) |
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
static int |
static int |
CondGetArg (linePtr, argPtr, func, parens) |
CondGetArg(char **linePtr, char **argPtr, char *func, Boolean parens) |
char **linePtr; |
|
char **argPtr; |
|
char *func; |
|
Boolean parens; /* TRUE if arg should be bounded by parens */ |
|
{ |
{ |
register char *cp; |
char *cp; |
int argLen; |
int argLen; |
register Buffer buf; |
Buffer buf; |
|
|
cp = *linePtr; |
cp = *linePtr; |
if (parens) { |
if (parens) { |
Line 211 CondGetArg (linePtr, argPtr, func, paren |
|
Line 225 CondGetArg (linePtr, argPtr, func, paren |
|
* long. Why 16? Why not? |
* long. Why 16? Why not? |
*/ |
*/ |
buf = Buf_Init(16); |
buf = Buf_Init(16); |
|
|
while ((strchr(" \t)&|", *cp) == (char *)NULL) && (*cp != '\0')) { |
while ((strchr(" \t)&|", *cp) == (char *)NULL) && (*cp != '\0')) { |
if (*cp == '$') { |
if (*cp == '$') { |
/* |
/* |
Line 254 CondGetArg (linePtr, argPtr, func, paren |
|
Line 268 CondGetArg (linePtr, argPtr, func, paren |
|
*/ |
*/ |
cp++; |
cp++; |
} |
} |
|
|
*linePtr = cp; |
*linePtr = cp; |
return (argLen); |
return (argLen); |
} |
} |
Line 273 CondGetArg (linePtr, argPtr, func, paren |
|
Line 287 CondGetArg (linePtr, argPtr, func, paren |
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
static Boolean |
static Boolean |
CondDoDefined (argLen, arg) |
CondDoDefined(int argLen, char *arg) |
int argLen; |
|
char *arg; |
|
{ |
{ |
char savec = arg[argLen]; |
char savec = arg[argLen]; |
char *p1; |
char *p1; |
Line 308 CondDoDefined (argLen, arg) |
|
Line 320 CondDoDefined (argLen, arg) |
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
static int |
static int |
CondStrMatch(string, pattern) |
CondStrMatch(ClientData string, ClientData pattern) |
ClientData string; |
|
ClientData pattern; |
|
{ |
{ |
return(!Str_Match((char *) string,(char *) pattern)); |
return(!Str_Match((char *) string,(char *) pattern)); |
} |
} |
Line 329 CondStrMatch(string, pattern) |
|
Line 339 CondStrMatch(string, pattern) |
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
static Boolean |
static Boolean |
CondDoMake (argLen, arg) |
CondDoMake(int argLen, char *arg) |
int argLen; |
|
char *arg; |
|
{ |
{ |
char savec = arg[argLen]; |
char savec = arg[argLen]; |
Boolean result; |
Boolean result; |
Line 360 CondDoMake (argLen, arg) |
|
Line 368 CondDoMake (argLen, arg) |
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
static Boolean |
static Boolean |
CondDoExists (argLen, arg) |
CondDoExists(int argLen, char *arg) |
int argLen; |
|
char *arg; |
|
{ |
{ |
char savec = arg[argLen]; |
char savec = arg[argLen]; |
Boolean result; |
Boolean result; |
Line 394 CondDoExists (argLen, arg) |
|
Line 400 CondDoExists (argLen, arg) |
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
static Boolean |
static Boolean |
CondDoTarget (argLen, arg) |
CondDoTarget(int argLen, char *arg) |
int argLen; |
|
char *arg; |
|
{ |
{ |
char savec = arg[argLen]; |
char savec = arg[argLen]; |
Boolean result; |
Boolean result; |
Line 413 CondDoTarget (argLen, arg) |
|
Line 417 CondDoTarget (argLen, arg) |
|
return (result); |
return (result); |
} |
} |
|
|
|
/*- |
|
*----------------------------------------------------------------------- |
|
* CondDoCommands -- |
|
* See if the given node exists and is an actual target with commands |
|
* associated with it. |
|
* |
|
* Results: |
|
* TRUE if the node exists as a target and has commands associated with |
|
* it and FALSE if it does not. |
|
* |
|
* Side Effects: |
|
* None. |
|
* |
|
*----------------------------------------------------------------------- |
|
*/ |
|
static Boolean |
|
CondDoCommands(int argLen, char *arg) |
|
{ |
|
char savec = arg[argLen]; |
|
Boolean result; |
|
GNode *gn; |
|
|
|
arg[argLen] = '\0'; |
|
gn = Targ_FindNode(arg, TARG_NOCREATE); |
|
if ((gn != NILGNODE) && !OP_NOP(gn->type) && !Lst_IsEmpty(gn->commands)) { |
|
result = TRUE; |
|
} else { |
|
result = FALSE; |
|
} |
|
arg[argLen] = savec; |
|
return (result); |
|
} |
|
|
/*- |
/*- |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
Line 428 CondDoTarget (argLen, arg) |
|
Line 464 CondDoTarget (argLen, arg) |
|
* |
* |
* Side Effects: |
* Side Effects: |
* Can change 'value' even if string is not a valid number. |
* Can change 'value' even if string is not a valid number. |
* |
* |
* |
* |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
static Boolean |
static Boolean |
CondCvtArg(str, value) |
CondCvtArg(char *str, double *value) |
register char *str; |
|
double *value; |
|
{ |
{ |
if ((*str == '0') && (str[1] == 'x')) { |
if ((*str == '0') && (str[1] == 'x')) { |
register long i; |
long i; |
|
|
for (str += 2, i = 0; *str; str++) { |
for (str += 2, i = 0; *str; str++) { |
int x; |
int x; |
Line 474 CondCvtArg(str, value) |
|
Line 508 CondCvtArg(str, value) |
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
static Token |
static Token |
CondToken(doEval) |
CondToken(Boolean doEval) |
Boolean doEval; |
|
{ |
{ |
Token t; |
Token t; |
|
|
Line 510 CondToken(doEval) |
|
Line 543 CondToken(doEval) |
|
t = Not; |
t = Not; |
condExpr++; |
condExpr++; |
break; |
break; |
|
case '#': |
case '\n': |
case '\n': |
case '\0': |
case '\0': |
t = EndOfFile; |
t = EndOfFile; |
Line 618 do_string_compare: |
|
Line 652 do_string_compare: |
|
|
|
buf = Buf_Init(0); |
buf = Buf_Init(0); |
qt = *rhs == '"' ? 1 : 0; |
qt = *rhs == '"' ? 1 : 0; |
|
|
for (cp = &rhs[qt]; |
for (cp = &rhs[qt]; |
((qt && (*cp != '"')) || |
((qt && (*cp != '"')) || |
(!qt && strchr(" \t)", *cp) == NULL)) && |
(!qt && strchr(" \t)", *cp) == NULL)) && |
(*cp != '\0'); cp++) { |
(*cp != '\0'); cp++) { |
if ((*cp == '\\') && (cp[1] != '\0')) { |
if ((*cp == '\\') && (cp[1] != '\0')) { |
/* |
/* |
Line 633 do_string_compare: |
|
Line 667 do_string_compare: |
|
} else if (*cp == '$') { |
} else if (*cp == '$') { |
int len; |
int len; |
Boolean freeIt; |
Boolean freeIt; |
|
|
cp2 = Var_Parse(cp, VAR_CMD, doEval,&len, &freeIt); |
cp2 = Var_Parse(cp, VAR_CMD, doEval,&len, &freeIt); |
if (cp2 != var_Error) { |
if (cp2 != var_Error) { |
Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2); |
Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2); |
Line 687 do_string_compare: |
|
Line 721 do_string_compare: |
|
if (*rhs == '$') { |
if (*rhs == '$') { |
int len; |
int len; |
Boolean freeIt; |
Boolean freeIt; |
|
|
string = Var_Parse(rhs, VAR_CMD, doEval,&len,&freeIt); |
string = Var_Parse(rhs, VAR_CMD, doEval,&len,&freeIt); |
if (string == var_Error) { |
if (string == var_Error) { |
right = 0.0; |
right = 0.0; |
Line 715 do_string_compare: |
|
Line 749 do_string_compare: |
|
} |
} |
} |
} |
} |
} |
|
|
if (DEBUG(COND)) { |
if (DEBUG(COND)) { |
printf("left = %f, right = %f, op = %.2s\n", left, |
printf("left = %f, right = %f, op = %.2s\n", left, |
right, op); |
right, op); |
|
|
break; |
break; |
} |
} |
default: { |
default: { |
Boolean (*evalProc)(); |
Boolean (*evalProc)(int, char *); |
Boolean invert = FALSE; |
Boolean invert = FALSE; |
char *arg; |
char *arg; |
int arglen; |
int arglen; |
|
|
if (strncmp (condExpr, "defined", 7) == 0) { |
if (strncmp (condExpr, "defined", 7) == 0) { |
/* |
/* |
* Use CondDoDefined to evaluate the argument and |
* Use CondDoDefined to evaluate the argument and |
|
|
if (val == var_Error) { |
if (val == var_Error) { |
t = Err; |
t = Err; |
} else { |
} else { |
/* |
/* |
* A variable is empty when it just contains |
* A variable is empty when it just contains |
* spaces... 4/15/92, christos |
* spaces... 4/15/92, christos |
*/ |
*/ |
char *p; |
char *p; |
|
|
condExpr -= 6; |
condExpr -= 6; |
goto use_default; |
goto use_default; |
} |
} |
|
} else if (strncmp (condExpr, "commands", 8) == 0) { |
|
/* |
|
* Use CondDoCommands to evaluate the argument and |
|
* CondGetArg to extract the argument from the |
|
* 'function call'. |
|
*/ |
|
evalProc = CondDoCommands; |
|
condExpr += 8; |
|
arglen = CondGetArg(&condExpr, &arg, "commands", TRUE); |
|
if (arglen == 0) { |
|
condExpr -= 8; |
|
goto use_default; |
|
} |
} else { |
} else { |
/* |
/* |
* The symbol is itself the argument to the default |
* The symbol is itself the argument to the default |
|
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
static Token |
static Token |
CondT(doEval) |
CondT(Boolean doEval) |
Boolean doEval; |
|
{ |
{ |
Token t; |
Token t; |
|
|
|
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
static Token |
static Token |
CondF(doEval) |
CondF(Boolean doEval) |
Boolean doEval; |
|
{ |
{ |
Token l, o; |
Token l, o; |
|
|
|
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
static Token |
static Token |
CondE(doEval) |
CondE(Boolean doEval) |
Boolean doEval; |
|
{ |
{ |
Token l, o; |
Token l, o; |
|
|
|
|
} |
} |
return (l); |
return (l); |
} |
} |
|
|
|
/*- |
|
*----------------------------------------------------------------------- |
|
* Cond_EvalExpression -- |
|
* Evaluate an expression in the passed line. The expression |
|
* consists of &&, ||, !, make(target), defined(variable) |
|
* and parenthetical groupings thereof. |
|
* |
|
* Results: |
|
* COND_PARSE if the condition was valid grammatically |
|
* COND_INVALID if not a valid conditional. |
|
* |
|
* (*value) is set to the boolean value of the condition |
|
* |
|
* Side Effects: |
|
* None. |
|
* |
|
*----------------------------------------------------------------------- |
|
*/ |
|
int |
|
Cond_EvalExpression(int dosetup, char *line, Boolean *value, int eprint) |
|
{ |
|
if (dosetup) { |
|
condDefProc = CondDoDefined; |
|
condInvert = 0; |
|
} |
|
|
|
while (*line == ' ' || *line == '\t') |
|
line++; |
|
|
|
condExpr = line; |
|
condPushBack = None; |
|
|
|
switch (CondE(TRUE)) { |
|
case True: |
|
if (CondToken(TRUE) == EndOfFile) { |
|
*value = TRUE; |
|
break; |
|
} |
|
goto err; |
|
/*FALLTHRU*/ |
|
case False: |
|
if (CondToken(TRUE) == EndOfFile) { |
|
*value = FALSE; |
|
break; |
|
} |
|
/*FALLTHRU*/ |
|
case Err: |
|
err: |
|
if (eprint) |
|
Parse_Error (PARSE_FATAL, "Malformed conditional (%s)", |
|
line); |
|
return (COND_INVALID); |
|
default: |
|
break; |
|
} |
|
|
|
return COND_PARSE; |
|
} |
|
|
|
|
/*- |
/*- |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
|
|
* and <expr> consists of &&, ||, !, make(target), defined(variable) |
* and <expr> consists of &&, ||, !, make(target), defined(variable) |
* and parenthetical groupings thereof. |
* and parenthetical groupings thereof. |
* |
* |
|
* Input: |
|
* line Line to parse |
|
* |
* Results: |
* Results: |
* COND_PARSE if should parse lines after the conditional |
* COND_PARSE if should parse lines after the conditional |
* COND_SKIP if should skip lines after the conditional |
* COND_SKIP if should skip lines after the conditional |
|
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
int |
int |
Cond_Eval (line) |
Cond_Eval(char *line) |
char *line; /* Line to parse */ |
|
{ |
{ |
struct If *ifp; |
struct If *ifp; |
Boolean isElse; |
Boolean isElse; |
Line 1108 Cond_Eval (line) |
|
Line 1214 Cond_Eval (line) |
|
} else { |
} else { |
isElse = FALSE; |
isElse = FALSE; |
} |
} |
|
|
/* |
/* |
* 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" |
Line 1168 Cond_Eval (line) |
|
Line 1274 Cond_Eval (line) |
|
*/ |
*/ |
condDefProc = ifp->defProc; |
condDefProc = ifp->defProc; |
condInvert = ifp->doNot; |
condInvert = ifp->doNot; |
|
|
line += ifp->formlen; |
line += ifp->formlen; |
|
if (Cond_EvalExpression(0, line, &value, 1) == COND_INVALID) |
while (*line == ' ' || *line == '\t') { |
return COND_INVALID; |
line++; |
|
} |
|
|
|
condExpr = line; |
|
condPushBack = None; |
|
|
|
switch (CondE(TRUE)) { |
|
case True: |
|
if (CondToken(TRUE) == EndOfFile) { |
|
value = TRUE; |
|
break; |
|
} |
|
goto err; |
|
/*FALLTHRU*/ |
|
case False: |
|
if (CondToken(TRUE) == EndOfFile) { |
|
value = FALSE; |
|
break; |
|
} |
|
/*FALLTHRU*/ |
|
case Err: |
|
err: |
|
Parse_Error (level, "Malformed conditional (%s)", |
|
line); |
|
return (COND_INVALID); |
|
default: |
|
break; |
|
} |
|
} |
} |
if (!isElse) { |
if (!isElse) { |
condTop -= 1; |
condTop -= 1; |
Line 1228 Cond_Eval (line) |
|
Line 1306 Cond_Eval (line) |
|
return (value ? COND_PARSE : COND_SKIP); |
return (value ? COND_PARSE : COND_SKIP); |
} |
} |
} |
} |
|
|
|
|
|
|
/*- |
/*- |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
Line 1243 Cond_Eval (line) |
|
Line 1323 Cond_Eval (line) |
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
void |
void |
Cond_End() |
Cond_End(void) |
{ |
{ |
if (condTop != MAXIF) { |
if (condTop != MAXIF) { |
Parse_Error(PARSE_FATAL, "%d open conditional%s", MAXIF-condTop, |
Parse_Error(PARSE_FATAL, "%d open conditional%s", MAXIF-condTop, |