=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/make/var.c,v retrieving revision 1.52 retrieving revision 1.53 diff -u -r1.52 -r1.53 --- src/usr.bin/make/var.c 2001/03/02 16:57:26 1.52 +++ src/usr.bin/make/var.c 2001/05/03 13:41:13 1.53 @@ -1,8 +1,9 @@ -/* $OpenBSD: var.c,v 1.52 2001/03/02 16:57:26 espie Exp $ */ +/* $OpenPackages$ */ +/* $OpenBSD: var.c,v 1.53 2001/05/03 13:41:13 espie Exp $ */ /* $NetBSD: var.c,v 1.18 1997/03/18 19:24:46 christos Exp $ */ /* - * Copyright (c) 1999 Marc Espie. + * Copyright (c) 1999,2000 Marc Espie. * * Extensive code modifications for the OpenBSD project. * @@ -27,7 +28,6 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - /* * Copyright (c) 1988, 1989, 1990, 1993 * The Regents of the University of California. All rights reserved. @@ -70,60 +70,57 @@ * var.c -- * Variable-handling functions * - * Interface: - * Var_Set Set the value of a variable in the given - * context. The variable is created if it doesn't - * yet exist. The value and variable name need not - * be preserved. + * Basic interface: + * Var_Set Set the value of a variable in the given + * context. The variable is created if it doesn't + * yet exist. The value and variable name need not + * be preserved. * * Var_Append Append more characters to an existing variable - * in the given context. The variable needn't - * exist already -- it will be created if it doesn't. - * A space is placed between the old value and the - * new one. + * in the given context. The variable needn't + * exist already -- it will be created if it doesn't. + * A space is placed between the old value and the + * new one. * - * Var_Exists See if a variable exists. + * Var_Value Return the value of a variable in a context or + * NULL if the variable is undefined. * - * Var_Value Return the value of a variable in a context or - * NULL if the variable is undefined. + * Var_Delete Delete a variable in a context. * - * Var_Subst Substitute named variable, or all variables if - * NULL in a string using - * the given context as the top-most one. If the - * third argument is non-zero, Parse_Error is - * called if any variables are undefined. + * Var_Init Initialize this module. * - * Var_SubstVar Substitute a named variable in a string using - * the given context as the top-most one, - * accumulating the result into a user-supplied - * buffer. + * Fast interface: + * Varq_Set, Varq_Append, Varq_Value: + * Use index form of local variables * - * Var_Parse Parse a variable expansion from a string and - * return the result and the number of characters - * consumed. + * Higher level functions: + * Var_Subst Substitute variables in a string using + * the given context as the top-most one. If the + * third argument is non-zero, Parse_Error is + * called if any variables are undefined. * - * Var_Delete Delete a variable in a context. + * Var_SubstVar Substitute a named variable in a string using + * the given context as the top-most one, + * accumulating the result into a user-supplied + * buffer. * - * Var_Init Initialize this module. + * Var_Parse Parse a variable expansion from a string and + * return the result and the number of characters + * consumed. * * Debugging: - * Var_Dump Print out all variables defined in the given - * context. - * - * XXX: There's a lot of duplication in these functions. + * Var_Dump Print out all global variables. */ +#include #include -#ifndef MAKE_BOOTSTRAP -#include -#include -#endif #include #include +#include #include "make.h" #include "buf.h" +#include "stats.h" #include "ohash.h" -#include "hashconsts.h" #include "varmodifiers.h" #ifndef lint @@ -131,27 +128,17 @@ static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 3/19/94"; #else UNUSED -static char rcsid[] = "$OpenBSD: var.c,v 1.52 2001/03/02 16:57:26 espie Exp $"; +static char rcsid[] = "$OpenBSD: var.c,v 1.53 2001/05/03 13:41:13 espie Exp $"; #endif #endif /* not lint */ -static SymTable *CTXT_GLOBAL, *CTXT_CMD, *CTXT_ENV; -static char *varnames[] = { - TARGET, - OODATE, - ALLSRC, - IMPSRC, - PREFIX, - ARCHIVE, - MEMBER }; - /* * This is a harmless return value for Var_Parse that can be used by Var_Subst * to determine if there was an error in parsing -- easier than returning * a flag, as things outside this module don't give a hoot. */ -char var_Error[] = ""; +char var_Error[] = ""; /* * Similar to var_Error, but returned when the 'err' flag for Var_Parse is @@ -161,10 +148,11 @@ static char varNoError[] = ""; /* - * Internally, variables are contained in four different contexts. - * 1) the environment. They may not be changed. If an environment - * variable is appended-to, the result is placed in the global - * context. + * Variable values are obtained from four different contexts: + * 1) the process environment. The process environment itself + * may not be changed, but these variables may be modified, + * unless make is invoked with -e, in which case those variables + * are unmodifiable and supersede the global context. * 2) the global context. Variables set in the Makefile are located in * the global context. It is the penultimate context searched when * substituting. @@ -178,47 +166,130 @@ */ GSymT *VAR_GLOBAL; /* variables from the makefile */ GSymT *VAR_CMD; /* variables defined on the command-line */ -static GSymT *VAR_ENV; /* variables read from env */ +static SymTable *CTXT_GLOBAL, *CTXT_CMD; + + +static char *varnames[] = { + TARGET, + PREFIX, + ARCHIVE, + MEMBER, + OODATE, + ALLSRC, + IMPSRC, + FTARGET, + DTARGET, + FPREFIX, + DPREFIX, + FARCHIVE, + DARCHIVE, + FMEMBER, + DMEMBER + }; + + #define FIND_MINE 0x1 /* look in CTXT_CMD and CTXT_GLOBAL */ -#define FIND_ENV 0x2 /* look in the environment */ +#define FIND_ENV 0x2 /* look in the environment */ typedef struct Var_ { - BUFFER val; /* its value */ - int flags; /* miscellaneous status flags */ -#define VAR_IN_USE 1 /* Variable's value currently being used. - * Used to avoid recursion */ -#define VAR_JUNK 4 /* Variable is a junk variable that - * should be destroyed when done with - * it. Used by Var_Parse for undefined, - * modified variables */ - char name[1]; /* the variable's name */ + BUFFER val; /* its value */ + unsigned int flags; /* miscellaneous status flags */ +#define VAR_IN_USE 1 /* Variable's value currently being used. + * Used to avoid recursion */ +#define VAR_READ_ONLY 2 /* Environment variable not modifiable */ +#define VAR_FROM_ENV 4 /* Var was read from env */ +#define VAR_DUMMY 8 /* Var does not exist, actually */ + char name[1]; /* the variable's name */ } Var; -static struct ohash_info var_info = { - offsetof(Var, name), + +static struct ohash_info var_info = { + offsetof(Var, name), NULL, hash_alloc, hash_free, element_alloc }; -static int quick_lookup __P((const char *, const char **, u_int32_t *)); +static int quick_lookup(const char *, const char **, u_int32_t *); #define VarValue(v) Buf_Retrieve(&((v)->val)) -static Var *varfind __P((const char *, const char *, SymTable *, int, int, u_int32_t)); -static Var *VarFind_interval __P((const char *, const char *, SymTable *, int)); -#define VarFind(n, ctxt, flags) VarFind_interval(n, NULL, ctxt, flags) -static Var *VarAdd __P((const char *, const char *, GSymT *)); -static void VarDelete __P((void *)); -static void VarPrintVar __P((void *)); -static const char *context_name __P((GSymT *)); -static Var *new_var __P((const char *, const char *)); -static Var *getvar __P((GSymT *, const char *, const char *, u_int32_t)); -static Var *var_name_with_dollar __P((char *, char **, SymTable *, Boolean, char)); +static Var *varfind(const char *, const char *, SymTable *, int, int, u_int32_t); +static Var *VarFind_interval(const char *, const char *, SymTable *, int); +static Var *VarAdd(const char *, const char *, u_int32_t, const char *, GSymT *); +static void VarDelete(void *); +static void VarPrintVar(Var *); +static const char *context_name(GSymT *); +static Var *new_var(const char *, const char *, const char *); +static Var *getvar(GSymT *, const char *, const char *, u_int32_t); +static Var *create_var(const char *, const char *); +static Var *var_from_env(const char *, const char *, u_int32_t); +static void var_init_string(Var *, const char *); +static const char *find_0(const char *); +static const char *find_rparen(const char *); +static const char *find_ket(const char *); +typedef const char * (*find_t)(const char *); +static find_t find_pos(int); + +/* retrieve the hashed values for well-known variables. */ +#include "varhashconsts.h" + +/* Parse a variable name for embedded $, to handle recursive variables */ +const char * +Var_Name_Get(start, name, ctxt, err, cont) + const char *start; /* start of variable spec */ + struct Name *name; /* result, might be a copy or not */ + SymTable *ctxt; /* context in which to expand */ + Boolean err; /* whether to error out for undefined sub */ + const char *(*cont)(const char *); + /* hook: find the next interesting character */ +{ + const char *p; + size_t len; + + p = cont(start); + /* If we don't want recursive variables, we skip over '$' */ + if (!FEATURES(FEATURE_RECVARS)) { + while (*p == '$') + p = cont(p); + } + if (*p != '$') { + name->s = start; + name->e = p; + name->tofree = FALSE; + return p; + } else { + BUFFER buf; + Buf_Init(&buf, MAKE_BSIZE); + for (;;) { + Buf_AddInterval(&buf, start, p); + if (*p != '$') { + name->s = (const char *)Buf_Retrieve(&buf); + name->e = name->s + Buf_Size(&buf); + name->tofree = TRUE; + return p; + } + start = p; + Var_ParseBuffer(&buf, start, ctxt, err, &len); + start += len; + p = cont(start); + } + } +} + void +Var_Name_Free(name) + struct Name *name; +{ + if (name->tofree) + free((char *)name->s); +} + +void SymTable_Init(ctxt) SymTable *ctxt; { - static SymTable sym_template; + static SymTable sym_template; memcpy(ctxt, &sym_template, sizeof(*ctxt)); } +#ifdef CLEANUP void SymTable_Destroy(ctxt) SymTable *ctxt; @@ -229,6 +300,7 @@ if (ctxt->locals[i] != NULL) VarDelete(ctxt->locals[i]); } +#endif static int quick_lookup(name, end, pk) @@ -241,82 +313,114 @@ *pk = ohash_interval(name, end); len = *end - name; /* substitute short version for long local name */ - switch (*pk % MAGICSLOTS) { /* MAGICSLOTS should be the */ - case K_LONGALLSRC % MAGICSLOTS: /* smallest constant yielding */ - /* distinct case values */ + switch (*pk % MAGICSLOTS1) { /* MAGICSLOTS should be the */ + case K_LONGALLSRC % MAGICSLOTS1: /* smallest constant yielding */ + /* distinct case values */ if (*pk == K_LONGALLSRC && strncmp(name, LONGALLSRC, len) == 0 && len == strlen(LONGALLSRC)) return ALLSRC_INDEX; break; - case K_LONGARCHIVE % MAGICSLOTS: + case K_LONGARCHIVE % MAGICSLOTS1: if (*pk == K_LONGARCHIVE && strncmp(name, LONGARCHIVE, len) == 0 && len == strlen(LONGARCHIVE)) return ARCHIVE_INDEX; break; - case K_LONGIMPSRC % MAGICSLOTS: + case K_LONGIMPSRC % MAGICSLOTS1: if (*pk == K_LONGIMPSRC && strncmp(name, LONGIMPSRC, len) == 0 && len == strlen(LONGIMPSRC)) return IMPSRC_INDEX; break; - case K_LONGMEMBER % MAGICSLOTS: + case K_LONGMEMBER % MAGICSLOTS1: if (*pk == K_LONGMEMBER && strncmp(name, LONGMEMBER, len) == 0 && len == strlen(LONGMEMBER)) return MEMBER_INDEX; break; - case K_LONGOODATE % MAGICSLOTS: + case K_LONGOODATE % MAGICSLOTS1: if (*pk == K_LONGOODATE && strncmp(name, LONGOODATE, len) == 0 && len == strlen(LONGOODATE)) return OODATE_INDEX; break; - case K_LONGPREFIX % MAGICSLOTS: + case K_LONGPREFIX % MAGICSLOTS1: if (*pk == K_LONGPREFIX && strncmp(name, LONGPREFIX, len) == 0 && len == strlen(LONGPREFIX)) return PREFIX_INDEX; break; - case K_LONGTARGET % MAGICSLOTS: + case K_LONGTARGET % MAGICSLOTS1: if (*pk == K_LONGTARGET && strncmp(name, LONGTARGET, len) == 0 && len == strlen(LONGTARGET)) return TARGET_INDEX; break; - case K_TARGET % MAGICSLOTS: + case K_TARGET % MAGICSLOTS1: if (name[0] == TARGET[0] && len == 1) return TARGET_INDEX; break; - case K_OODATE % MAGICSLOTS: + case K_OODATE % MAGICSLOTS1: if (name[0] == OODATE[0] && len == 1) return OODATE_INDEX; break; - case K_ALLSRC % MAGICSLOTS: + case K_ALLSRC % MAGICSLOTS1: if (name[0] == ALLSRC[0] && len == 1) return ALLSRC_INDEX; break; - case K_IMPSRC % MAGICSLOTS: + case K_IMPSRC % MAGICSLOTS1: if (name[0] == IMPSRC[0] && len == 1) return IMPSRC_INDEX; break; - case K_PREFIX % MAGICSLOTS: + case K_PREFIX % MAGICSLOTS1: if (name[0] == PREFIX[0] && len == 1) return PREFIX_INDEX; break; - case K_ARCHIVE % MAGICSLOTS: + case K_ARCHIVE % MAGICSLOTS1: if (name[0] == ARCHIVE[0] && len == 1) return ARCHIVE_INDEX; break; - case K_MEMBER % MAGICSLOTS: + case K_MEMBER % MAGICSLOTS1: if (name[0] == MEMBER[0] && len == 1) return MEMBER_INDEX; break; + case K_FTARGET % MAGICSLOTS1: + if (name[0] == FTARGET[0] && name[1] == FTARGET[1] && len == 2) + return FTARGET_INDEX; + break; + case K_DTARGET % MAGICSLOTS1: + if (name[0] == DTARGET[0] && name[1] == DTARGET[1] && len == 2) + return DTARGET_INDEX; + break; + case K_FPREFIX % MAGICSLOTS1: + if (name[0] == FPREFIX[0] && name[1] == FPREFIX[1] && len == 2) + return FPREFIX_INDEX; + break; + case K_DPREFIX % MAGICSLOTS1: + if (name[0] == DPREFIX[0] && name[1] == DPREFIX[1] && len == 2) + return DPREFIX_INDEX; + break; + case K_FARCHIVE % MAGICSLOTS1: + if (name[0] == FARCHIVE[0] && name[1] == FARCHIVE[1] && len == 2) + return FARCHIVE_INDEX; + break; + case K_DARCHIVE % MAGICSLOTS1: + if (name[0] == DARCHIVE[0] && name[1] == DARCHIVE[1] && len == 2) + return DARCHIVE_INDEX; + break; + case K_FMEMBER % MAGICSLOTS1: + if (name[0] == FMEMBER[0] && name[1] == FMEMBER[1] && len == 2) + return FMEMBER_INDEX; + break; + case K_DMEMBER % MAGICSLOTS1: + if (name[0] == DMEMBER[0] && name[1] == DMEMBER[1] && len == 2) + return DMEMBER_INDEX; + break; default: break; } return -1; } -void +void Varq_Set(idx, val, gn) int idx; - const char *val; - GNode *gn; + const char *val; + GNode *gn; { /* 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 @@ -324,27 +428,28 @@ Var *v = gn->context.locals[idx]; if (v == NULL) { - v = new_var(varnames[idx], val); + v = new_var(varnames[idx], NULL, val); v->flags = 0; gn->context.locals[idx] = v; } else { Buf_Reset(&(v->val)); Buf_AddString(&(v->val), val); + } if (DEBUG(VAR)) printf("%s:%s = %s\n", gn->name, varnames[idx], val); } -void +void Varq_Append(idx, val, gn) - int idx; + int idx; const char *val; GNode *gn; { - Var *v = gn->context.locals[idx]; + Var *v = gn->context.locals[idx]; if (v == NULL) { - v = new_var(varnames[idx], val); + v = new_var(varnames[idx], NULL, val); v->flags = 0; gn->context.locals[idx] = v; } else { @@ -357,63 +462,109 @@ char * Varq_Value(idx, gn) - int idx; + int idx; GNode *gn; { Var *v = gn->context.locals[idx]; - if (v != NULL) - return VarValue(v); - else + if (v == NULL) return NULL; + else + return VarValue(v); } -Boolean -Varq_Exists(idx, gn) - int idx; - GNode *gn; -{ - return gn->context.locals[idx] != NULL; -} - - static const char * context_name(ctxt) GSymT *ctxt; { if (ctxt == VAR_GLOBAL) - return "Global"; - else if (ctxt == VAR_CMD) - return "Command"; - else - return "Environment"; + return "Global"; + if (ctxt == VAR_CMD) + return "Command"; + return "Error"; } - -/* Create a variable, to pass to VarAdd. */ + +/* We separate var creation proper from setting of initial value: + * VAR_DUMMY corresponds to `lazy' setup, e.g., always create global + * variable at first lookup, and then fill it up when value is wanted. + * This avoids looking through the environment several times. + */ static Var * -new_var(name, val) - const char *name; - const char *val; +create_var(name, end) + const char *name; + const char *end; { + return ohash_create_entry(&var_info, name, &end); +} + +/* Set the initial value a var should have */ +static void +var_init_string(v, val) Var *v; - const char *end = NULL; + const char *val; +{ + size_t len; - v = ohash_create_entry(&var_info, name, &end); + len = strlen(val); + Buf_Init(&(v->val), len+1); + Buf_AddChars(&(v->val), len, val); +} - if (val != NULL) { - size_t len = strlen(val); - Buf_Init(&(v->val), len+1); - Buf_AddChars(&(v->val), len, val); - } else - Buf_Init(&(v->val), 1); +static Var * +new_var(name, end, val) + const char *name; + const char *end; + const char *val; +{ + Var *v; + v = create_var(name, end); +#ifdef STATS_VAR_LOOKUP + STAT_VAR_CREATION++; +#endif + if (val != NULL) + var_init_string(v, val); + else + Buf_Init(&(v->val), 1); + return v; } static Var * +var_from_env(name, end, k) + const char *name; + const char *end; + u_int32_t k; +{ + char *env; + Var *v; + + /* getenv requires a null-terminated name, so we create the var + * structure first. */ + v = create_var(name, end); + env = getenv(v->name); + if (env == NULL) + v->flags = VAR_DUMMY; + else { + var_init_string(v, env); + if (checkEnvFirst) + v->flags = VAR_READ_ONLY | VAR_FROM_ENV; + else + v->flags = VAR_FROM_ENV; + } + +#ifdef STATS_VAR_LOOKUP + STAT_VAR_FROM_ENV++; +#endif + + ohash_insert(VAR_GLOBAL, ohash_lookup_interval(VAR_GLOBAL, name, end, k), v); + return v; +} + +static Var * getvar(ctxt, name, end, k) GSymT *ctxt; - const char *name; + const char *name; const char *end; u_int32_t k; { @@ -425,29 +576,30 @@ * VarFind_interval -- * Find the given variable in the given context and any other contexts * indicated. if end is NULL, name is a string, otherwise, only - * the interval name - end is concerned. + * the interval name - end is concerned. * * Results: * A pointer to the structure describing the desired variable or * NULL if the variable does not exist. - * - * Side Effects: - * Caches env variables in the VAR_ENV context. *----------------------------------------------------------------------- */ static Var * VarFind_interval(name, end, ctxt, flags) - const char *name; /* name to find */ + const char *name; /* name to find */ const char *end; /* end of name */ - SymTable *ctxt; /* context in which to find it */ - int flags; /* FIND_MINE set means to look in the + SymTable *ctxt; /* context in which to find it */ + int flags; /* FIND_MINE set means to look in the * CTXT_GLOBAL and CTXT_CMD contexts also. * FIND_ENV set means to look in the * environment */ { - int idx; u_int32_t k; + int idx; +#ifdef STATS_VAR_LOOKUP + STAT_VAR_FIND++; +#endif + idx = quick_lookup(name, &end, &k); return varfind(name, end, ctxt, flags, idx, k); } @@ -457,58 +609,66 @@ const char *name; const char *end; SymTable *ctxt; - int flags; - int idx; + int flags; + int idx; u_int32_t k; { - Var *v; + Var *v; - /* - * First look for the variable in the given context. If it's not there, - * look for it in VAR_CMD, VAR_GLOBAL and the environment, in that order, - * depending on the FIND_* flags in 'flags' - */ - if (ctxt == NULL) - v = NULL; - else if (ctxt == CTXT_GLOBAL || ctxt == CTXT_CMD || ctxt == CTXT_ENV) - v = getvar((GSymT *)ctxt, name, end, k); - else { - if (idx == -1) - v = NULL; - else - v = ctxt->locals[idx]; + /* Handle local variables first */ + if (idx != -1) { + if (ctxt != NULL && ctxt != CTXT_CMD && ctxt != CTXT_GLOBAL) { + if (idx < LOCAL_SIZE) + return ctxt->locals[idx]; + else + return ctxt->locals[EXTENDED2SIMPLE(idx)]; + } else + return NULL; } - if (v != NULL) - return v; - - if ((flags & FIND_MINE) && ctxt != CTXT_CMD) - v = getvar(VAR_CMD, name, end, k); - if (v != NULL) - return v; + /* First look for the variable in the given context. If it's not there, + look for it in CTXT_CMD, CTXT_GLOBAL and the environment, + depending on the FIND_* flags in 'flags' */ + if (ctxt == CTXT_CMD || ctxt == CTXT_GLOBAL) + v = getvar((GSymT *)ctxt, name, end, k); + else + v = NULL; - if (!checkEnvFirst && (flags & FIND_MINE) && ctxt != CTXT_GLOBAL) - v = getvar(VAR_GLOBAL, name, end, k); - if (v != NULL) - return v; + if (v == NULL) + switch (flags) { + case 0: + break; + case FIND_MINE: + if (ctxt != CTXT_CMD) + v = getvar(VAR_CMD, name, end, k); + if (v == NULL && ctxt != CTXT_GLOBAL) + v = getvar(VAR_GLOBAL, name, end, k); + break; + case FIND_ENV: + v = var_from_env(name, end, k); + break; + case FIND_ENV | FIND_MINE: + if (ctxt != CTXT_CMD) + v = getvar(VAR_CMD, name, end, k); + if (v == NULL) { + if (ctxt != CTXT_GLOBAL) + v = getvar(VAR_GLOBAL, name, end, k); + if (v == NULL) + v = var_from_env(name, end, k); + else if (checkEnvFirst && (v->flags & VAR_FROM_ENV) == 0) { + char *env; - if ((flags & FIND_ENV)) { - char *env; - char *n; - - v = getvar(VAR_ENV, name, end, k); - if (v != NULL) - return v; - - /* getenv requires a null-terminated name */ - n = interval_dup(name, end); - env = getenv(n); - free(n); - if (env != NULL) - return VarAdd(name, env, VAR_ENV); - } - - if (checkEnvFirst && (flags & FIND_MINE) && ctxt != CTXT_GLOBAL) - v = getvar(VAR_GLOBAL, name, end, k); + env = getenv(v->name); + if (env != NULL) { + Buf_Reset(&(v->val)); + Buf_AddString(&(v->val), env); + } + /* XXX even if no such env variable, fake it, to avoid + * further lookup */ + v->flags |= VAR_FROM_ENV; + } + } + break; + } return v; } @@ -518,7 +678,7 @@ * Add a new variable of name name and value val to the given context * * Results: - * The added variable + * The added variable. * * Side Effects: * The new variable is placed in the given context. @@ -527,31 +687,25 @@ *----------------------------------------------------------------------- */ static Var * -VarAdd(name, val, ctxt) +VarAdd(name, end, k, val, ctxt) const char *name; /* name of variable to add */ + 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; - const char *end = NULL; - int idx; - u_int32_t k; + Var *v; - v = new_var(name, val); + v = new_var(name, end, val); v->flags = 0; - idx = quick_lookup(name, &end, &k); - - if (idx != -1) - Parse_Error(PARSE_FATAL, "Trying to set dynamic variable %s", - v->name); - else - ohash_insert(ctxt, ohash_lookup_interval(ctxt, name, end, k), v); + ohash_insert(ctxt, ohash_lookup_interval(ctxt, name, end, k), v); + if (DEBUG(VAR)) + printf("%s:%s = %s\n", context_name(ctxt), v->name, val); return v; } - /*- *----------------------------------------------------------------------- * VarDelete -- @@ -560,11 +714,12 @@ */ static void VarDelete(vp) - void *vp; + void *vp; { - Var *v = (Var *) vp; + Var *v = (Var *)vp; - Buf_Destroy(&(v->val)); + if ((v->flags & VAR_DUMMY) == 0) + Buf_Destroy(&(v->val)); free(v); } @@ -573,28 +728,35 @@ /*- *----------------------------------------------------------------------- * Var_Delete -- - * Remove a variable from a context. + * Remove a global variable. * * Side Effects: * The Var structure is removed and freed. *----------------------------------------------------------------------- */ void -Var_Delete(name, ctxt) - const char *name; - GSymT *ctxt; +Var_Delete(name) + const char *name; { Var *v; u_int32_t k; + unsigned int slot; const char *end = NULL; + int idx; + if (DEBUG(VAR)) - printf("%s:delete %s\n", context_name(ctxt), name); - (void)quick_lookup(name, &end, &k); - v = ohash_remove(ctxt, ohash_lookup_interval(ctxt, name, end, k)); + printf("delete %s\n", name); - if (v != NULL) + idx = quick_lookup(name, &end, &k); + if (idx != -1) + Parse_Error(PARSE_FATAL, "Trying to delete dynamic variable"); + slot = ohash_lookup_interval(VAR_GLOBAL, name, end, k); + v = ohash_find(VAR_GLOBAL, slot); + if (v != NULL && (v->flags & VAR_READ_ONLY) == 0) { + ohash_remove(VAR_GLOBAL, slot); VarDelete(v); + } } /*- @@ -608,46 +770,51 @@ * * Notes: * The variable is searched for only in its context before being - * created in that context. I.e. if the context is VAR_GLOBAL, - * only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMD, only - * VAR_CMD->context is searched. This is done to avoid the literally - * thousands of unnecessary strcmp's that used to be done to - * set, say, $(@) or $(<). + * created in that context. I.e. if the context is CTXT_GLOBAL, + * only CTXT_GLOBAL is searched. Likewise if it is CTXT_CMD, only + * CTXT_CMD is searched. *----------------------------------------------------------------------- */ void -Var_Set(name, val, ctxt) +Var_Set_interval(name, end, val, 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 */ + GSymT *ctxt; /* context in which to set it */ { Var *v; + u_int32_t k; + int idx; - /* - * We only look for a variable in the given context since anything set + idx = quick_lookup(name, &end, &k); + if (idx != -1) + Parse_Error(PARSE_FATAL, "Trying to set dynamic variable $%s", + varnames[idx]); + + /* 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 - * point in searching them all just to save a bit of memory... - */ - v = VarFind(name, (SymTable *)ctxt, 0); + * point in searching them all just to save a bit of memory... */ + v = varfind(name, end, (SymTable *)ctxt, 0, idx, k); if (v == NULL) - (void)VarAdd(name, val, ctxt); + v = VarAdd(name, end, k, val, ctxt); else { - Buf_Reset(&(v->val)); - Buf_AddString(&(v->val), val); + if ((v->flags & VAR_READ_ONLY) == 0) { + if ((v->flags & VAR_DUMMY) == 0) { + Buf_Reset(&(v->val)); + Buf_AddString(&(v->val), val); + } else { + var_init_string(v, val); + v->flags &= ~VAR_DUMMY; + } + + } } if (DEBUG(VAR)) - printf("%s:%s = %s\n", context_name(ctxt), name, val); - /* - * Any variables given on the command line are automatically exported - * to the environment (as per POSIX standard). - * We put them into the env cache directly. - * (Note that additions to VAR_CMD occur very early, so VAR_ENV is - * actually empty at this point). - */ - if (ctxt == VAR_CMD) { - esetenv(name, val); - (void)VarAdd(name, val, VAR_ENV); - } + printf("%s:%s = %s\n", context_name(ctxt), v->name, val); + /* Any variables given on the command line are automatically exported + * to the environment (as per POSIX standard). */ + if (ctxt == VAR_CMD) + esetenv(v->name, val); } /*- @@ -660,126 +827,193 @@ * If the variable doesn't exist, it is created. Else the strings * are concatenated (with a space in between). * - * Notes: - * Only if the variable is being sought in the global context is the - * environment searched. - * XXX: Knows its calling circumstances in that if called with ctxt - * an actual target, it will only search that context since only - * a local variable could be being appended to. This is actually - * a big win and must be tolerated. *----------------------------------------------------------------------- */ void -Var_Append(name, val, ctxt) +Var_Append_interval(name, end, val, 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; + int idx; - v = VarFind(name, (SymTable *)ctxt, (ctxt == VAR_GLOBAL) ? FIND_ENV : 0); + assert(ctxt == VAR_GLOBAL || ctxt == VAR_CMD); - if (v == NULL) { - v = VarAdd(name, val, ctxt); - } else { - Buf_AddSpace(&(v->val)); - Buf_AddString(&(v->val), val); + idx = quick_lookup(name, &end, &k); + if (idx != -1) + Parse_Error(PARSE_FATAL, "Trying to append to dynamic variable $%s", + varnames[idx]); + + v = varfind(name, end, (SymTable *)ctxt, FIND_ENV, idx, k); + + if ((v->flags & VAR_READ_ONLY) == 0) { + if ((v->flags & VAR_DUMMY) == 0) { + Buf_AddSpace(&(v->val)); + Buf_AddString(&(v->val), val); + } else { + var_init_string(v, val); + v->flags &= ~VAR_DUMMY; + } + } if (DEBUG(VAR)) - printf("%s:%s = %s\n", context_name(ctxt), name, VarValue(v)); + printf("%s:%s = %s\n", context_name(ctxt), v->name, VarValue(v)); } /*- *----------------------------------------------------------------------- - * Var_Exists -- - * See if the given variable exists. + * Var_Value -- + * Return the value of a global named variable * * Results: - * TRUE if it does, FALSE if it doesn't + * The value if the variable exists, NULL if it doesn't *----------------------------------------------------------------------- */ -Boolean -Var_Exists(name, ctxt) - const char *name; /* Variable to find */ - GSymT *ctxt; /* Context in which to start search */ +char * +Var_Value_interval(name, end) + const char *name; /* name to find */ + const char *end; { - Var *v; + Var *v; - v = VarFind(name, (SymTable *)ctxt, FIND_MINE|FIND_ENV); - - if (v == NULL) - return FALSE; + v = VarFind_interval(name, end, NULL, FIND_ENV | FIND_MINE); + if (v != NULL && (v->flags & VAR_DUMMY) == 0) + return VarValue(v); else - return TRUE; + return NULL; } +static const char * +find_0(p) + const char *p; +{ + while (*p != '$' && *p != '\0' && *p != ':') + p++; + return p; +} + +static const char * +find_rparen(p) + const char *p; +{ + while (*p != '$' && *p != '\0' && *p != ')' && *p != ':') + p++; + return p; +} + +static const char * +find_ket(p) + const char *p; +{ + while (*p != '$' && *p != '\0' && *p != '}' && *p != ':') + p++; + return p; +} + +static find_t +find_pos(c) + int c; +{ + switch(c) { + case '\0': + return find_0; + case ')': + return find_rparen; + case '}': + return find_ket; + default: + return 0; + } +} + /*- *----------------------------------------------------------------------- - * Var_Value -- - * Return the value of the named variable in the given context + * Var_ParseSkip -- + * Do whatever is needed to skip over a var specification. Since the + * result is not needed at this point, some shortcuts may be taken. * - * Results: - * The value if the variable exists, NULL if it doesn't + * Return value: the amount to skip *----------------------------------------------------------------------- */ -char * -Var_Value(name, ctxt) - const char *name; /* name to find */ - GSymT *ctxt; /* context in which to search for it */ +size_t +Var_ParseSkip(str, ctxt, result) + const char *str; + SymTable *ctxt; + ReturnStatus *result; { - Var *v; + const char *tstr; /* Pointer into str */ + Var *v; /* Variable in invocation */ + char endc; /* Ending character when variable in parens + * or braces */ + const char *start; + size_t length; + struct Name name; - v = VarFind(name, (SymTable *)ctxt, FIND_ENV | FIND_MINE); - if (v != NULL) - return VarValue(v); - else - return NULL; + v = NULL; + start = str; + str++; + + if (*str != '(' && *str != '{') { + name.tofree = FALSE; + tstr = str + 1; + length = 2; + endc = '\0'; + } else { + endc = *str == '(' ? ')' : '}'; + str++; + + /* Find eventual modifiers in the variable */ + tstr = Var_Name_Get(str, &name, ctxt, FALSE, find_pos(endc)); + Var_Name_Free(&name); + length = tstr+1 - start; + } + + if (result != NULL) + *result = SUCCESS; + if (*tstr == ':' && endc != '\0') + if (VarModifiers_Apply(NULL, NULL, ctxt, TRUE, NULL, tstr, endc, + &length) == var_Error) + *result = FAILURE; + return length; } -/* +/*- *----------------------------------------------------------------------- - * v = var_name_with_dollar(str, &pos, ctxt, err, endc) - * handle variable name that contains a dollar - * str points to the first letter of the variable name, - * &pos to the current position in the name (first dollar at invocation, - * end of name specification at return). - * returns the corresponding variable. + * Var_ParseBuffer -- + * Given the start of a variable invocation, extract the variable + * name and find its value, then modify it according to the + * specification, and add the result to the buffer. + * + * Results: + * FAILURE for invalid specifications. + * + * Side-effects: + * The length of the specification is placed in *lengthPtr + * (for invalid specifications, this is just 2...?). *----------------------------------------------------------------------- */ -static Var * -var_name_with_dollar(str, pos, ctxt, err, endc) - char *str; /* First dollar in variable name */ - char **pos; /* Current position in variable spec */ - SymTable *ctxt; /* The context for the variable */ - Boolean err; /* TRUE if undefined variables are an error */ - char endc; /* End character for spec */ +ReturnStatus +Var_ParseBuffer(buf, str, ctxt, err, lengthPtr) + Buffer buf; + const char *str; + SymTable *ctxt; + Boolean err; + size_t *lengthPtr; { - BUFFER buf; /* Store the variable name */ - size_t sublen; /* Deal with recursive expansions */ - Boolean subfree; - char *n; /* Sub name */ - Var *v; + char *result; + Boolean freeIt; - Buf_Init(&buf, MAKE_BSIZE); + result = Var_Parse(str, ctxt, err, lengthPtr, &freeIt); + if (result == var_Error) + return FAILURE; - for (;;) { - Buf_AddInterval(&buf, str, *pos); - n = Var_Parse(*pos, ctxt, err, &sublen, &subfree); - if (n != NULL) - Buf_AddString(&buf, n); - if (subfree) - free(n); - *pos += sublen; - str = *pos; - for (; **pos != '$'; (*pos)++) { - if (**pos == '\0' || **pos == endc || **pos == ':') { - Buf_AddInterval(&buf, str, *pos); - v = VarFind(Buf_Retrieve(&buf), ctxt, FIND_ENV | FIND_MINE); - Buf_Destroy(&buf); - return v; - } - } - } + Buf_AddString(buf, result); + if (freeIt) + free(result); + return SUCCESS; } /*- @@ -800,96 +1034,54 @@ */ char * Var_Parse(str, ctxt, err, lengthPtr, freePtr) - char *str; /* The string to parse */ - SymTable *ctxt; /* The context for the variable */ - Boolean err; /* TRUE if undefined variables are an error */ + const char *str; /* The string to parse */ + SymTable *ctxt; /* The context for the variable */ + Boolean err; /* TRUE if undefined variables are an error */ size_t *lengthPtr; /* OUT: The length of the specification */ - Boolean *freePtr; /* OUT: TRUE if caller should free result */ + Boolean *freePtr; /* OUT: TRUE if caller should free result */ { - char *tstr; /* Pointer into str */ - Var *v; /* Variable in invocation */ - char endc; /* Ending character when variable in parens + const char *tstr; /* Pointer into str */ + Var *v; /* Variable in invocation */ + char endc; /* Ending character when variable in parens * or braces */ - char *start; + struct Name name; + const char *start; char *val; /* Variable value */ u_int32_t k; - int idx; + int idx; *freePtr = FALSE; start = str++; val = NULL; v = NULL; - idx = 0; + idx = -1; if (*str != '(' && *str != '{') { - tstr = str + 1; + name.s = str; + name.e = str+1; + name.tofree = FALSE; + tstr = str + 1; *lengthPtr = 2; endc = '\0'; } else { endc = *str == '(' ? ')' : '}'; - str++; + str++; /* Find eventual modifiers in the variable */ - for (tstr = str; *tstr != ':'; tstr++) { - if (*tstr == '$') { - v = var_name_with_dollar(str, &tstr, ctxt, err, endc); - if (*tstr == '\0' || *tstr == endc) - endc = '\0'; - break; - } else if (*tstr == '\0' || *tstr == endc) { - endc = '\0'; - break; - } - } + tstr = Var_Name_Get(str, &name, ctxt, FALSE, find_pos(endc)); *lengthPtr = tstr+1 - start; } - if (v == NULL) { - idx = quick_lookup(str, &tstr, &k); - v = varfind(str, tstr, ctxt, FIND_ENV | FIND_MINE, idx, k); - } - if (v == NULL) { - /* Find out about D and F forms of local variables. */ - if (idx == -1 && tstr == str+2 && (str[1] == 'D' || str[1] == 'F')) { - switch (*str) { - case '@': - idx = TARGET_INDEX; - break; - case '!': - idx = ARCHIVE_INDEX; - break; - case '*': - idx = PREFIX_INDEX; - break; - case '%': - idx = MEMBER_INDEX; - break; - default: - break; - } - /* This is a DF form, check if we can expand it now. */ - if (idx != -1 && ctxt != NULL && ctxt != CTXT_GLOBAL) { - v = varfind(str, str+1, ctxt, 0, idx, 0); - /* No need for nested expansion or anything, as we're - * the only one who sets these things and we sure don't - * do nested invocations in them... */ - if (v != NULL) { - val = VarValue(v); - if (str[1] == 'D') - val = Var_GetHead(val); - else - val = Var_GetTail(val); - *freePtr = TRUE; - } - } - } - } else { + idx = quick_lookup(name.s, &name.e, &k); + v = varfind(name.s, name.e, ctxt, FIND_ENV | FIND_MINE, idx, k); + if (v != NULL && (v->flags & VAR_DUMMY) == 0) { if (v->flags & VAR_IN_USE) Fatal("Variable %s is recursive.", v->name); /*NOTREACHED*/ else v->flags |= VAR_IN_USE; + /* Before doing any modification, we have to make sure the value * has been fully expanded. If it looks like recursion might be * necessary (there's a dollar sign somewhere in the variable's value) @@ -898,26 +1090,51 @@ * been dynamically-allocated, so it will need freeing when we * return. */ val = VarValue(v); - if (strchr(val, '$') != NULL) { - val = Var_Subst(val, ctxt, err); + if (idx == -1) { + if (strchr(val, '$') != NULL) { + val = Var_Subst(val, ctxt, err); + *freePtr = TRUE; + } + } else if (idx >= LOCAL_SIZE) { + if (IS_EXTENDED_F(idx)) + val = Var_GetTail(val); + else + val = Var_GetHead(val); *freePtr = TRUE; } - v->flags &= ~VAR_IN_USE; } - if (endc != '\0') - val = VarModifiers_Apply(val, ctxt, err, freePtr, tstr+1, endc, + if (*tstr == ':' && endc != '\0') + val = VarModifiers_Apply(val, &name, ctxt, err, freePtr, tstr, endc, lengthPtr); if (val == NULL) { - /* Dynamic source that can't be expanded for now: copy the var - * specification instead. */ - if (idx != -1 && (ctxt == NULL || ctxt == CTXT_GLOBAL)) { - *freePtr = TRUE; - val = interval_dup(start, start+ *lengthPtr); - } else - val = err ? var_Error : varNoError; - } + val = err ? var_Error : varNoError; + /* Dynamic source */ + if (idx != -1) { + /* can't be expanded for now: copy the var spec instead. */ + if (ctxt == NULL || ctxt == CTXT_GLOBAL || ctxt == CTXT_CMD) { + *freePtr = TRUE; + val = interval_dup(start, start+ *lengthPtr); + } else { + /* somehow, this should have been expanded already. */ + GNode *n; + n = (GNode *)(((char *)ctxt) - offsetof(GNode, context)); + if (idx >= LOCAL_SIZE) + idx = EXTENDED2SIMPLE(idx); + switch(idx) { + case IMPSRC_INDEX: + Fatal("Using $< in a non-suffix rule context is a GNUmake idiom (line %lu of %s)", + n->lineno, n->fname); + default: + Error("Using undefined dynamic variable $%s (line %lu of %s)", + varnames[idx], n->lineno, n->fname); + break; + } + } + } + } + Var_Name_Free(&name); return val; } @@ -932,16 +1149,16 @@ * The resulting string. * * Side Effects: - * None. The old string must be freed by the caller + * The new string must be freed by the caller *----------------------------------------------------------------------- */ char * Var_Subst(str, ctxt, undefErr) - char *str; /* the string in which to substitute */ - SymTable *ctxt; /* the context wherein to find variables */ - Boolean undefErr; /* TRUE if undefineds are an error */ + const char *str; /* the string in which to substitute */ + SymTable *ctxt; /* the context wherein to find variables */ + Boolean undefErr; /* TRUE if undefineds are an error */ { - BUFFER buf; /* Buffer for forming things */ + BUFFER buf; /* Buffer for forming things */ static Boolean errorReported; /* Set true if an error has already * been reported to prevent a plethora * of messages when recursing */ @@ -951,8 +1168,8 @@ for (;;) { char *val; /* Value to substitute for a variable */ - size_t length; /* Length of the variable invocation */ - Boolean doFree; /* Set true if val should be freed */ + size_t length; /* Length of the variable invocation */ + Boolean doFree; /* Set true if val should be freed */ const char *cp; /* copy uninteresting stuff */ @@ -977,21 +1194,20 @@ * the variable and continue with the substitution. Otherwise, * store the dollar sign and advance str so we continue with * the string... */ - if (oldVars) { + if (oldVars) str += length; - } else if (undefErr) { + else if (undefErr) { /* If variable is undefined, complain and skip the * variable. The complaint will stop us from doing anything * when the file is parsed. */ - if (!errorReported) { + if (!errorReported) Parse_Error(PARSE_FATAL, "Undefined variable \"%.*s\"",length,str); - } str += length; errorReported = TRUE; } else { Buf_AddChar(&buf, *str); - str += 1; + str++; } } else { /* We've now got a variable structure to store in. But first, @@ -1013,25 +1229,25 @@ * Var_SubstVar -- * Substitute for one variable in the given string in the given context * If undefErr is TRUE, Parse_Error will be called when an undefined - * variable is encountered. Returns the string with substitutions. + * variable is encountered. Add the substituted string to buffer. *----------------------------------------------------------------------- */ -char * -Var_SubstVar(str, var, val, estimate) - const char *str; /* The string in which to substitute */ +void +Var_SubstVar(buf, str, var, val) + Buffer buf; + const char *str; /* The string in which to substitute */ const char *var; /* Named variable */ const char *val; /* Its value */ - size_t estimate; /* Size estimate for the result buffer */ { - BUFFER buf; /* Where to store the result */ - Buf_Init(&buf, estimate); + assert(*var != '\0'); + for (;;) { const char *start; /* Copy uninteresting stuff */ for (start = str; *str != '\0' && *str != '$'; str++) ; - Buf_AddInterval(&buf, start, str); + Buf_AddInterval(buf, start, str); start = str; if (*str++ == '\0') @@ -1039,13 +1255,13 @@ str++; /* and escaped dollars */ if (start[1] == '$') { - Buf_AddInterval(&buf, start, start+2); + Buf_AddInterval(buf, start, start+2); continue; } /* Simple variable, if it's not us, copy. */ if (start[1] != '(' && start[1] != '{') { if (start[1] != *var || var[1] != '\0') { - Buf_AddChars(&buf, 2, start); + Buf_AddChars(buf, 2, start); continue; } } else { @@ -1054,52 +1270,54 @@ if (start[1] == '(') endc = ')'; - else + else endc = '}'; /* Find the end of the variable specification. */ p = str; while (*p != '\0' && *p != ':' && *p != endc && *p != '$') p++; - /* A variable inside the variable. We don't know how to - * expand the external variable at this point, so we try - * again with the nested variable. */ + /* A variable inside the variable. We don't know how to + * expand the external variable at this point, so we try + * again with the nested variable. */ if (*p == '$') { - Buf_AddInterval(&buf, start, p); + Buf_AddInterval(buf, start, p); str = p; continue; } if (strncmp(var, str, p - str) != 0 || var[p - str] != '\0') { - /* Not the variable we want to expand. */ - Buf_AddInterval(&buf, start, p); + /* Not the variable we want to expand. */ + Buf_AddInterval(buf, start, p); str = p; continue; - } + } if (*p == ':') { - size_t length; /* Length of the variable invocation */ - Boolean doFree; /* Set true if val should be freed */ + size_t length; /* Length of the variable invocation */ + Boolean doFree; /* Set true if val should be freed */ char *newval; /* Value substituted for a variable */ + struct Name name; - length = p - str + 1; + length = p - str + 1; doFree = FALSE; + name.s = var; + name.e = var + (p-str); /* val won't be freed since doFree == FALSE, but * VarModifiers_Apply doesn't know that, hence the cast. */ - newval = VarModifiers_Apply((char *)val, NULL, FALSE, - &doFree, p+1, endc, &length); - Buf_AddString(&buf, newval); + newval = VarModifiers_Apply((char *)val, &name, NULL, FALSE, + &doFree, p, endc, &length); + Buf_AddString(buf, newval); if (doFree) free(newval); str += length; continue; } else - str = p+1; + str = p+1; } - Buf_AddString(&buf, val); + Buf_AddString(buf, val); } - return Buf_Retrieve(&buf); } /*- @@ -1108,23 +1326,22 @@ * Initialize the module * * Side Effects: - * The VAR_CMD and VAR_GLOBAL contexts are created + * The CTXT_CMD and CTXT_GLOBAL contexts are initialized *----------------------------------------------------------------------- */ void Var_Init() { - static GSymT global_vars, cmd_vars, env_vars; + static GSymT global_vars, cmd_vars; VAR_GLOBAL = &global_vars; VAR_CMD = &cmd_vars; - VAR_ENV = &env_vars; ohash_init(VAR_GLOBAL, 10, &var_info); ohash_init(VAR_CMD, 5, &var_info); - ohash_init(VAR_ENV, 5, &var_info); CTXT_GLOBAL = (SymTable *)VAR_GLOBAL; CTXT_CMD = (SymTable *)VAR_CMD; - CTXT_ENV = (SymTable *)VAR_ENV; + + VarModifiers_Init(); } @@ -1135,50 +1352,60 @@ Var *v; unsigned int i; - for (v = ohash_first(VAR_GLOBAL, &i); v != NULL; + for (v = ohash_first(VAR_GLOBAL, &i); v != NULL; v = ohash_next(VAR_GLOBAL, &i)) VarDelete(v); - for (v = ohash_first(VAR_CMD, &i); v != NULL; + for (v = ohash_first(VAR_CMD, &i); v != NULL; v = ohash_next(VAR_CMD, &i)) VarDelete(v); - for (v = ohash_first(VAR_ENV, &i); v != NULL; - v = ohash_next(VAR_ENV, &i)) - VarDelete(v); #endif } +static const char *interpret(int); +static const char * +interpret(f) + int f; +{ + if (f & VAR_DUMMY) + return "(D)"; + return ""; +} + + /****************** PRINT DEBUGGING INFO *****************/ static void -VarPrintVar(vp) - void *vp; +VarPrintVar(v) + Var *v; { - Var *v = (Var *)vp; - - printf("%-16s = %s\n", v->name, VarValue(v)); + printf("%-16s%s = %s\n", v->name, interpret(v->flags), + (v->flags & VAR_DUMMY) == 0 ? VarValue(v) : "(none)"); } /*- *----------------------------------------------------------------------- * Var_Dump -- - * print all variables in a context + * print all variables *----------------------------------------------------------------------- */ void -Var_Dump(ctxt) - GSymT *ctxt; +Var_Dump() { - Var *v; - unsigned int i; + Var *v; + unsigned int i; - for (v = ohash_first(ctxt, &i); v != NULL; - v = ohash_next(ctxt, &i)) - VarPrintVar(v); -} + printf("#*** Global Variables:\n"); + for (v = ohash_first(VAR_GLOBAL, &i); v != NULL; + v = ohash_next(VAR_GLOBAL, &i)) + VarPrintVar(v); -#ifdef POSIX + printf("#*** Command-line Variables:\n"); + for (v = ohash_first(VAR_CMD, &i); v != NULL; v = ohash_next(VAR_CMD, &i)) + VarPrintVar(v); +} + static const char *quotable = " \t\n\\'\""; /* In POSIX mode, variable assignments passed on the command line are @@ -1195,8 +1422,8 @@ Buf_Init(&buf, MAKE_BSIZE); - for (v = ohash_first(VAR_CMD, &i); v != NULL; - v = ohash_next(VAR_CMD, &i)) { + for (v = ohash_first(VAR_CMD, &i); v != NULL; + v = ohash_next(VAR_CMD, &i)) { /* We assume variable names don't need quoting */ Buf_AddString(&buf, v->name); Buf_AddChar(&buf, '='); @@ -1210,4 +1437,3 @@ Var_Append(name, Buf_Retrieve(&buf), VAR_GLOBAL); Buf_Destroy(&buf); } -#endif