version 1.58, 2003/10/07 18:33:08 |
version 1.59, 2004/04/07 13:11:36 |
|
|
#include "varhashconsts.h" |
#include "varhashconsts.h" |
|
|
void |
void |
SymTable_Init(ctxt) |
SymTable_Init(SymTable *ctxt) |
SymTable *ctxt; |
|
{ |
{ |
static SymTable sym_template; |
static SymTable sym_template; |
memcpy(ctxt, &sym_template, sizeof(*ctxt)); |
memcpy(ctxt, &sym_template, sizeof(*ctxt)); |
|
|
|
|
#ifdef CLEANUP |
#ifdef CLEANUP |
void |
void |
SymTable_Destroy(ctxt) |
SymTable_Destroy(SymTable *ctxt) |
SymTable *ctxt; |
|
{ |
{ |
int i; |
int i; |
|
|
|
|
#endif |
#endif |
|
|
static int |
static int |
quick_lookup(name, end, pk) |
quick_lookup(const char *name, const char **enamePtr, u_int32_t *pk) |
const char *name; |
|
const char **end; |
|
u_int32_t *pk; |
|
{ |
{ |
size_t len; |
size_t len; |
|
|
*pk = ohash_interval(name, end); |
*pk = ohash_interval(name, enamePtr); |
len = *end - name; |
len = *enamePtr - name; |
/* substitute short version for long local name */ |
/* substitute short version for long local name */ |
switch (*pk % MAGICSLOTS1) { /* MAGICSLOTS should be the */ |
switch (*pk % MAGICSLOTS1) { /* MAGICSLOTS should be the */ |
case K_LONGALLSRC % MAGICSLOTS1: /* smallest constant yielding */ |
case K_LONGALLSRC % MAGICSLOTS1: /* smallest constant yielding */ |
|
|
} |
} |
|
|
void |
void |
Varq_Set(idx, val, gn) |
Varq_Set(int idx, const char *val, GNode *gn) |
int idx; |
|
const char *val; |
|
GNode *gn; |
|
{ |
{ |
/* We only look for a variable in the given context since anything set |
/* We only look for a variable in the given context since anything set |
* here will override anything in a lower context, so there's not much |
* here will override anything in a lower context, so there's not much |
|
|
} |
} |
|
|
void |
void |
Varq_Append(idx, val, gn) |
Varq_Append(int idx, const char *val, GNode *gn) |
int idx; |
|
const char *val; |
|
GNode *gn; |
|
{ |
{ |
Var *v = gn->context.locals[idx]; |
Var *v = gn->context.locals[idx]; |
|
|
|
|
} |
} |
|
|
char * |
char * |
Varq_Value(idx, gn) |
Varq_Value(int idx, GNode *gn) |
int idx; |
|
GNode *gn; |
|
{ |
{ |
Var *v = gn->context.locals[idx]; |
Var *v = gn->context.locals[idx]; |
|
|
|
|
} |
} |
|
|
static const char * |
static const char * |
context_name(ctxt) |
context_name(GSymT *ctxt) |
GSymT *ctxt; |
|
{ |
{ |
if (ctxt == VAR_GLOBAL) |
if (ctxt == VAR_GLOBAL) |
return "Global"; |
return "Global"; |
|
|
* This avoids looking through the environment several times. |
* This avoids looking through the environment several times. |
*/ |
*/ |
static Var * |
static Var * |
create_var(name, end) |
create_var(const char *name, const char *ename) |
const char *name; |
|
const char *end; |
|
{ |
{ |
return ohash_create_entry(&var_info, name, &end); |
return ohash_create_entry(&var_info, name, &ename); |
} |
} |
|
|
/* Set the initial value a var should have */ |
/* Set the initial value a var should have */ |
static void |
static void |
var_init_string(v, val) |
var_init_string(Var *v, const char *val) |
Var *v; |
|
const char *val; |
|
{ |
{ |
size_t len; |
size_t len; |
|
|
|
|
} |
} |
|
|
static Var * |
static Var * |
new_var(name, end, val) |
new_var(const char *name, const char *ename, const char *val) |
const char *name; |
|
const char *end; |
|
const char *val; |
|
{ |
{ |
Var *v; |
Var *v; |
|
|
v = create_var(name, end); |
v = create_var(name, ename); |
#ifdef STATS_VAR_LOOKUP |
#ifdef STATS_VAR_LOOKUP |
STAT_VAR_CREATION++; |
STAT_VAR_CREATION++; |
#endif |
#endif |
|
|
} |
} |
|
|
static Var * |
static Var * |
var_from_env(name, end, k) |
var_from_env(const char *name, const char *ename, u_int32_t k) |
const char *name; |
|
const char *end; |
|
u_int32_t k; |
|
{ |
{ |
char *env; |
char *env; |
Var *v; |
Var *v; |
|
|
/* getenv requires a null-terminated name, so we create the var |
/* getenv requires a null-terminated name, so we create the var |
* structure first. */ |
* structure first. */ |
v = create_var(name, end); |
v = create_var(name, ename); |
env = getenv(v->name); |
env = getenv(v->name); |
if (env == NULL) |
if (env == NULL) |
v->flags = VAR_DUMMY; |
v->flags = VAR_DUMMY; |
|
|
STAT_VAR_FROM_ENV++; |
STAT_VAR_FROM_ENV++; |
#endif |
#endif |
|
|
ohash_insert(VAR_GLOBAL, ohash_lookup_interval(VAR_GLOBAL, name, end, k), v); |
ohash_insert(VAR_GLOBAL, ohash_lookup_interval(VAR_GLOBAL, name, ename, k), v); |
return v; |
return v; |
} |
} |
|
|
static Var * |
static Var * |
getvar(ctxt, name, end, k) |
getvar(GSymT *ctxt, const char *name, const char *ename, u_int32_t k) |
GSymT *ctxt; |
|
const char *name; |
|
const char *end; |
|
u_int32_t k; |
|
{ |
{ |
return ohash_find(ctxt, ohash_lookup_interval(ctxt, name, end, k)); |
return ohash_find(ctxt, ohash_lookup_interval(ctxt, name, ename, k)); |
} |
} |
|
|
/*- |
/*- |
|
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
static Var * |
static Var * |
VarFindi(name, end, ctxt, flags) |
VarFindi(const char *name, /* name to find */ |
const char *name; /* name to find */ |
const char *ename, /* end of name */ |
const char *end; /* end of name */ |
SymTable *ctxt, /* context in which to find it */ |
SymTable *ctxt; /* context in which to find it */ |
int flags) /* FIND_MINE set means to look in the |
int flags; /* FIND_MINE set means to look in the |
|
* CTXT_GLOBAL and CTXT_CMD contexts also. |
* CTXT_GLOBAL and CTXT_CMD contexts also. |
* FIND_ENV set means to look in the |
* FIND_ENV set means to look in the |
* environment */ |
* environment */ |
|
|
STAT_VAR_FIND++; |
STAT_VAR_FIND++; |
#endif |
#endif |
|
|
idx = quick_lookup(name, &end, &k); |
idx = quick_lookup(name, &ename, &k); |
return varfind(name, end, ctxt, flags, idx, k); |
return varfind(name, ename, ctxt, flags, idx, k); |
} |
} |
|
|
static Var * |
static Var * |
varfind(name, end, ctxt, flags, idx, k) |
varfind(const char *name, const char *ename, SymTable *ctxt, int flags, |
const char *name; |
int idx, u_int32_t k) |
const char *end; |
|
SymTable *ctxt; |
|
int flags; |
|
int idx; |
|
u_int32_t k; |
|
{ |
{ |
Var *v; |
Var *v; |
|
|
|
|
look for it in CTXT_CMD, CTXT_GLOBAL and the environment, |
look for it in CTXT_CMD, CTXT_GLOBAL and the environment, |
depending on the FIND_* flags in 'flags' */ |
depending on the FIND_* flags in 'flags' */ |
if (ctxt == CTXT_CMD || ctxt == CTXT_GLOBAL) |
if (ctxt == CTXT_CMD || ctxt == CTXT_GLOBAL) |
v = getvar((GSymT *)ctxt, name, end, k); |
v = getvar((GSymT *)ctxt, name, ename, k); |
else |
else |
v = NULL; |
v = NULL; |
|
|
|
|
break; |
break; |
case FIND_MINE: |
case FIND_MINE: |
if (ctxt != CTXT_CMD) |
if (ctxt != CTXT_CMD) |
v = getvar(VAR_CMD, name, end, k); |
v = getvar(VAR_CMD, name, ename, k); |
if (v == NULL && ctxt != CTXT_GLOBAL) |
if (v == NULL && ctxt != CTXT_GLOBAL) |
v = getvar(VAR_GLOBAL, name, end, k); |
v = getvar(VAR_GLOBAL, name, ename, k); |
break; |
break; |
case FIND_ENV: |
case FIND_ENV: |
v = var_from_env(name, end, k); |
v = var_from_env(name, ename, k); |
break; |
break; |
case FIND_ENV | FIND_MINE: |
case FIND_ENV | FIND_MINE: |
if (ctxt != CTXT_CMD) |
if (ctxt != CTXT_CMD) |
v = getvar(VAR_CMD, name, end, k); |
v = getvar(VAR_CMD, name, ename, k); |
if (v == NULL) { |
if (v == NULL) { |
if (ctxt != CTXT_GLOBAL) |
if (ctxt != CTXT_GLOBAL) |
v = getvar(VAR_GLOBAL, name, end, k); |
v = getvar(VAR_GLOBAL, name, ename, k); |
if (v == NULL) |
if (v == NULL) |
v = var_from_env(name, end, k); |
v = var_from_env(name, ename, k); |
else if (checkEnvFirst && (v->flags & VAR_FROM_ENV) == 0) { |
else if (checkEnvFirst && (v->flags & VAR_FROM_ENV) == 0) { |
char *env; |
char *env; |
|
|
|
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
static Var * |
static Var * |
VarAdd(name, end, k, val, ctxt) |
VarAdd(const char *name, const char *ename, u_int32_t k, const char *val, |
const char *name; /* name of variable to add */ |
GSymT *ctxt) |
const char *end; |
|
u_int32_t k; |
|
const char *val; /* value to set it to */ |
|
GSymT *ctxt; /* context in which to set it */ |
|
{ |
{ |
Var *v; |
Var *v; |
|
|
v = new_var(name, end, val); |
v = new_var(name, ename, val); |
|
|
v->flags = 0; |
v->flags = 0; |
|
|
ohash_insert(ctxt, ohash_lookup_interval(ctxt, name, end, k), v); |
ohash_insert(ctxt, ohash_lookup_interval(ctxt, name, ename, k), v); |
if (DEBUG(VAR)) |
if (DEBUG(VAR)) |
printf("%s:%s = %s\n", context_name(ctxt), v->name, val); |
printf("%s:%s = %s\n", context_name(ctxt), v->name, val); |
return v; |
return v; |
|
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
static void |
static void |
VarDelete(vp) |
VarDelete(void *vp) |
void *vp; |
|
{ |
{ |
Var *v = (Var *)vp; |
Var *v = (Var *)vp; |
|
|
|
|
|
|
|
|
void |
void |
Var_Delete(name) |
Var_Delete(const char *name) |
const char *name; |
|
{ |
{ |
Var *v; |
Var *v; |
u_int32_t k; |
u_int32_t k; |
unsigned int slot; |
unsigned int slot; |
const char *end = NULL; |
const char *ename = NULL; |
int idx; |
int idx; |
|
|
|
|
if (DEBUG(VAR)) |
if (DEBUG(VAR)) |
printf("delete %s\n", name); |
printf("delete %s\n", name); |
|
|
idx = quick_lookup(name, &end, &k); |
idx = quick_lookup(name, &ename, &k); |
if (idx != -1) |
if (idx != -1) |
Parse_Error(PARSE_FATAL, "Trying to delete dynamic variable"); |
Parse_Error(PARSE_FATAL, "Trying to delete dynamic variable"); |
slot = ohash_lookup_interval(VAR_GLOBAL, name, end, k); |
slot = ohash_lookup_interval(VAR_GLOBAL, name, ename, k); |
v = ohash_find(VAR_GLOBAL, slot); |
v = ohash_find(VAR_GLOBAL, slot); |
if (v != NULL && (v->flags & VAR_READ_ONLY) == 0) { |
if (v != NULL && (v->flags & VAR_READ_ONLY) == 0) { |
ohash_remove(VAR_GLOBAL, slot); |
ohash_remove(VAR_GLOBAL, slot); |
|
|
* CTXT_CMD is searched. |
* CTXT_CMD is searched. |
*/ |
*/ |
void |
void |
Var_Seti(name, end, val, ctxt) |
Var_Seti(const char *name, const char *ename, const char *val, GSymT *ctxt) |
const char *name; /* name of variable to set */ |
|
const char *end; |
|
const char *val; /* value to give to the variable */ |
|
GSymT *ctxt; /* context in which to set it */ |
|
{ |
{ |
Var *v; |
Var *v; |
u_int32_t k; |
u_int32_t k; |
int idx; |
int idx; |
|
|
idx = quick_lookup(name, &end, &k); |
idx = quick_lookup(name, &ename, &k); |
if (idx != -1) |
if (idx != -1) |
Parse_Error(PARSE_FATAL, "Trying to set dynamic variable $%s", |
Parse_Error(PARSE_FATAL, "Trying to set dynamic variable $%s", |
varnames[idx]); |
varnames[idx]); |
|
|
/* We only look for a variable in the given context since anything set |
/* We only look for a variable in the given context since anything set |
* here will override anything in a lower context, so there's not much |
* here will override anything in a lower context, so there's not much |
* point in searching them all just to save a bit of memory... */ |
* point in searching them all just to save a bit of memory... */ |
v = varfind(name, end, (SymTable *)ctxt, 0, idx, k); |
v = varfind(name, ename, (SymTable *)ctxt, 0, idx, k); |
if (v == NULL) |
if (v == NULL) |
v = VarAdd(name, end, k, val, ctxt); |
v = VarAdd(name, ename, k, val, ctxt); |
else { |
else { |
if ((v->flags & VAR_READ_ONLY) == 0) { |
if ((v->flags & VAR_READ_ONLY) == 0) { |
if ((v->flags & VAR_DUMMY) == 0) { |
if ((v->flags & VAR_DUMMY) == 0) { |
|
|
} |
} |
|
|
void |
void |
Var_Appendi(name, end, val, ctxt) |
Var_Appendi(const char *name, const char *ename, const char *val, GSymT *ctxt) |
const char *name; /* Name of variable to modify */ |
|
const char *end; |
|
const char *val; /* String to append to it */ |
|
GSymT *ctxt; /* Context in which this should occur */ |
|
{ |
{ |
Var *v; |
Var *v; |
u_int32_t k; |
u_int32_t k; |
|
|
|
|
assert(ctxt == VAR_GLOBAL || ctxt == VAR_CMD); |
assert(ctxt == VAR_GLOBAL || ctxt == VAR_CMD); |
|
|
idx = quick_lookup(name, &end, &k); |
idx = quick_lookup(name, &ename, &k); |
if (idx != -1) |
if (idx != -1) |
Parse_Error(PARSE_FATAL, "Trying to append to dynamic variable $%s", |
Parse_Error(PARSE_FATAL, "Trying to append to dynamic variable $%s", |
varnames[idx]); |
varnames[idx]); |
|
|
v = varfind(name, end, (SymTable *)ctxt, FIND_ENV, idx, k); |
v = varfind(name, ename, (SymTable *)ctxt, FIND_ENV, idx, k); |
|
|
if ((v->flags & VAR_READ_ONLY) == 0) { |
if ((v->flags & VAR_READ_ONLY) == 0) { |
if ((v->flags & VAR_DUMMY) == 0) { |
if ((v->flags & VAR_DUMMY) == 0) { |
|
|
} |
} |
|
|
char * |
char * |
Var_Valuei(name, end) |
Var_Valuei(const char *name, const char *ename) |
const char *name; /* name to find */ |
|
const char *end; |
|
{ |
{ |
Var *v; |
Var *v; |
|
|
v = VarFindi(name, end, NULL, FIND_ENV | FIND_MINE); |
v = VarFindi(name, ename, NULL, FIND_ENV | FIND_MINE); |
if (v != NULL && (v->flags & VAR_DUMMY) == 0) |
if (v != NULL && (v->flags & VAR_DUMMY) == 0) |
return VarValue(v); |
return VarValue(v); |
else |
else |
|
|
} |
} |
|
|
static const char * |
static const char * |
find_0(p) |
find_0(const char *p) |
const char *p; |
|
{ |
{ |
while (*p != '$' && *p != '\0' && *p != ':') |
while (*p != '$' && *p != '\0' && *p != ':') |
p++; |
p++; |
|
|
} |
} |
|
|
static const char * |
static const char * |
find_rparen(p) |
find_rparen(const char *p) |
const char *p; |
|
{ |
{ |
while (*p != '$' && *p != '\0' && *p != ')' && *p != ':') |
while (*p != '$' && *p != '\0' && *p != ')' && *p != ':') |
p++; |
p++; |
|
|
} |
} |
|
|
static const char * |
static const char * |
find_ket(p) |
find_ket(const char *p) |
const char *p; |
|
{ |
{ |
while (*p != '$' && *p != '\0' && *p != '}' && *p != ':') |
while (*p != '$' && *p != '\0' && *p != '}' && *p != ':') |
p++; |
p++; |
|
|
} |
} |
|
|
static find_t |
static find_t |
find_pos(c) |
find_pos(int c) |
int c; |
|
{ |
{ |
switch(c) { |
switch(c) { |
case '\0': |
case '\0': |
|
|
} |
} |
|
|
size_t |
size_t |
Var_ParseSkip(str, ctxt, result) |
Var_ParseSkip(const char *str, SymTable *ctxt, bool *result) |
const char *str; |
|
SymTable *ctxt; |
|
bool *result; |
|
{ |
{ |
const char *tstr; /* Pointer into str */ |
const char *tstr; /* Pointer into str */ |
Var *v; /* Variable in invocation */ |
Var *v; /* Variable in invocation */ |
|
|
* speed, it may be better to revisit the implementation to do things |
* speed, it may be better to revisit the implementation to do things |
* directly. */ |
* directly. */ |
bool |
bool |
Var_ParseBuffer(buf, str, ctxt, err, lengthPtr) |
Var_ParseBuffer(Buffer buf, const char *str, SymTable *ctxt, bool err, |
Buffer buf; |
size_t *lengthPtr) |
const char *str; |
|
SymTable *ctxt; |
|
bool err; |
|
size_t *lengthPtr; |
|
{ |
{ |
char *result; |
char *result; |
bool freeIt; |
bool freeIt; |
|
|
} |
} |
|
|
char * |
char * |
Var_Parse(str, ctxt, err, lengthPtr, freePtr) |
Var_Parse(const char *str, /* The string to parse */ |
const char *str; /* The string to parse */ |
SymTable *ctxt, /* The context for the variable */ |
SymTable *ctxt; /* The context for the variable */ |
bool err, /* true if undefined variables are an error */ |
bool err; /* true if undefined variables are an error */ |
size_t *lengthPtr, /* OUT: The length of the specification */ |
size_t *lengthPtr; /* OUT: The length of the specification */ |
bool *freePtr) /* OUT: true if caller should free result */ |
bool *freePtr; /* OUT: true if caller should free result */ |
|
{ |
{ |
const char *tstr; /* Pointer into str */ |
const char *tstr; /* Pointer into str */ |
Var *v; /* Variable in invocation */ |
Var *v; /* Variable in invocation */ |
|
|
} |
} |
|
|
char * |
char * |
Var_Subst(str, ctxt, undefErr) |
Var_Subst(const char *str, /* the string in which to substitute */ |
const char *str; /* the string in which to substitute */ |
SymTable *ctxt, /* the context wherein to find variables */ |
SymTable *ctxt; /* the context wherein to find variables */ |
bool undefErr) /* true if undefineds are an error */ |
bool undefErr; /* true if undefineds are an error */ |
|
{ |
{ |
BUFFER buf; /* Buffer for forming things */ |
BUFFER buf; /* Buffer for forming things */ |
static bool errorReported; /* Set true if an error has already |
static bool errorReported; /* Set true if an error has already |
* been reported to prevent a plethora |
* been reported to prevent a plethora |
* of messages when recursing */ |
* of messages when recursing */ |
|
|
Buf_Init(&buf, MAKE_BSIZE); |
Buf_Init(&buf, MAKE_BSIZE); |
errorReported = false; |
errorReported = false; |
|
|
for (;;) { |
for (;;) { |
char *val; /* Value to substitute for a variable */ |
char *val; /* Value to substitute for a variable */ |
size_t length; /* Length of the variable invocation */ |
size_t length; /* Length of the variable invocation */ |
bool doFree; /* Set true if val should be freed */ |
bool doFree; /* Set true if val should be freed */ |
const char *cp; |
const char *cp; |
|
|
|
|
} |
} |
|
|
void |
void |
Var_SubstVar(buf, str, var, val) |
Var_SubstVar(Buffer buf, /* To store result */ |
Buffer buf; |
const char *str, /* The string in which to substitute */ |
const char *str; /* The string in which to substitute */ |
const char *var, /* Named variable */ |
const char *var; /* Named variable */ |
const char *val) /* Its value */ |
const char *val; /* Its value */ |
|
{ |
{ |
|
|
assert(*var != '\0'); |
assert(*var != '\0'); |
|
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
void |
void |
Var_Init() |
Var_Init(void) |
{ |
{ |
static GSymT global_vars, cmd_vars; |
static GSymT global_vars, cmd_vars; |
|
|
|
|
|
|
#ifdef CLEANUP |
#ifdef CLEANUP |
void |
void |
Var_End() |
Var_End(void) |
{ |
{ |
Var *v; |
Var *v; |
unsigned int i; |
unsigned int i; |
|
|
static const char *interpret(int); |
static const char *interpret(int); |
|
|
static const char * |
static const char * |
interpret(f) |
interpret(int f) |
int f; |
|
{ |
{ |
if (f & VAR_DUMMY) |
if (f & VAR_DUMMY) |
return "(D)"; |
return "(D)"; |
|
|
|
|
/****************** PRINT DEBUGGING INFO *****************/ |
/****************** PRINT DEBUGGING INFO *****************/ |
static void |
static void |
VarPrintVar(v) |
VarPrintVar(Var *v) |
Var *v; |
|
{ |
{ |
printf("%-16s%s = %s\n", v->name, interpret(v->flags), |
printf("%-16s%s = %s\n", v->name, interpret(v->flags), |
(v->flags & VAR_DUMMY) == 0 ? VarValue(v) : "(none)"); |
(v->flags & VAR_DUMMY) == 0 ? VarValue(v) : "(none)"); |
} |
} |
|
|
void |
void |
Var_Dump() |
Var_Dump(void) |
{ |
{ |
Var *v; |
Var *v; |
unsigned int i; |
unsigned int i; |
|
|
* propagated to sub makes through MAKEFLAGS. |
* propagated to sub makes through MAKEFLAGS. |
*/ |
*/ |
void |
void |
Var_AddCmdline(name) |
Var_AddCmdline(const char *name) |
const char *name; |
|
{ |
{ |
Var *v; |
Var *v; |
unsigned int i; |
unsigned int i; |