version 1.54, 2001/05/15 13:31:03 |
version 1.55, 2001/05/23 12:34:51 |
|
|
* SUCH DAMAGE. |
* SUCH DAMAGE. |
*/ |
*/ |
|
|
/*- |
#include <sys/types.h> |
* var.c -- |
#include <assert.h> |
* Variable-handling functions |
#include <stddef.h> |
* |
#include <stdio.h> |
* Basic interface: |
#include <stdlib.h> |
* Var_Set Set the value of a variable in the given |
#include <string.h> |
* 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. |
|
* |
|
* 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_Init Initialize this module. |
|
* |
|
* Fast interface: |
|
* Varq_Set, Varq_Append, Varq_Value: |
|
* Use index form of local variables |
|
* |
|
* 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_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_Parse Parse a variable expansion from a string and |
|
* return the result and the number of characters |
|
* consumed. |
|
* |
|
* Debugging: |
|
* Var_Dump Print out all global variables. |
|
*/ |
|
|
|
#include <assert.h> |
#include "config.h" |
#include <ctype.h> |
#include "defines.h" |
#include <stdlib.h> |
#include "buf.h" |
#include <stddef.h> |
#include "stats.h" |
#include <string.h> |
#include "ohash.h" |
#include "make.h" |
#include "varmodifiers.h" |
#include "buf.h" |
#include "var.h" |
#include "stats.h" |
#include "varname.h" |
#include "ohash.h" |
#include "error.h" |
#include "varmodifiers.h" |
#include "str.h" |
|
#include "var_int.h" |
|
#include "memory.h" |
|
#include "symtable.h" |
|
#include "gnode.h" |
|
|
#ifndef lint |
/* extended indices for System V stuff */ |
#if 0 |
#define FTARGET_INDEX 7 |
static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 3/19/94"; |
#define DTARGET_INDEX 8 |
#else |
#define FPREFIX_INDEX 9 |
UNUSED |
#define DPREFIX_INDEX 10 |
static char rcsid[] = "$OpenBSD$"; |
#define FARCHIVE_INDEX 11 |
#endif |
#define DARCHIVE_INDEX 12 |
#endif /* not lint */ |
#define FMEMBER_INDEX 13 |
|
#define DMEMBER_INDEX 14 |
|
|
|
#define EXTENDED2SIMPLE(i) (((i)-LOCAL_SIZE)/2) |
|
#define IS_EXTENDED_F(i) ((i)%2 == 1) |
|
|
/* |
/* |
* This is a harmless return value for Var_Parse that can be used by Var_Subst |
* This is a harmless return value for Var_Parse that can be used by Var_Subst |
|
|
static int quick_lookup(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)) |
#define VarValue(v) Buf_Retrieve(&((v)->val)) |
static Var *varfind(const char *, const char *, SymTable *, int, int, u_int32_t); |
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 *VarFindi(const char *, const char *, SymTable *, int); |
static Var *VarAdd(const char *, const char *, u_int32_t, const char *, GSymT *); |
static Var *VarAdd(const char *, const char *, u_int32_t, const char *, GSymT *); |
static void VarDelete(void *); |
static void VarDelete(void *); |
static void VarPrintVar(Var *); |
static void VarPrintVar(Var *); |
|
|
/* retrieve the hashed values for well-known variables. */ |
/* retrieve the hashed values for well-known variables. */ |
#include "varhashconsts.h" |
#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 |
void |
Var_Name_Free(name) |
|
struct Name *name; |
|
{ |
|
if (name->tofree) |
|
free((char *)name->s); |
|
} |
|
|
|
void |
|
SymTable_Init(ctxt) |
SymTable_Init(ctxt) |
SymTable *ctxt; |
SymTable *ctxt; |
{ |
{ |
|
|
|
|
/*- |
/*- |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
* VarFind_interval -- |
* VarFindi -- |
* Find the given variable in the given context and any other contexts |
* Find the given variable in the given context and any other contexts |
* indicated. if end is NULL, name is a string, otherwise, only |
* indicated. if end is NULL, name is a string, otherwise, only |
* the interval name - end is concerned. |
* the interval name - end is concerned. |
|
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
static Var * |
static Var * |
VarFind_interval(name, end, ctxt, flags) |
VarFindi(name, end, ctxt, flags) |
const char *name; /* name to find */ |
const char *name; /* name to find */ |
const char *end; /* 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 */ |
|
|
|
|
|
|
|
|
/*- |
|
*----------------------------------------------------------------------- |
|
* Var_Delete -- |
|
* Remove a global variable. |
|
* |
|
* Side Effects: |
|
* The Var structure is removed and freed. |
|
*----------------------------------------------------------------------- |
|
*/ |
|
void |
void |
Var_Delete(name) |
Var_Delete(name) |
const char *name; |
const char *name; |
|
|
} |
} |
} |
} |
|
|
/*- |
/* The variable is searched for only in its context before being |
*----------------------------------------------------------------------- |
|
* Var_Set -- |
|
* Set the variable name to the value val in the given context. |
|
* |
|
* Side Effects: |
|
* If the variable doesn't yet exist, a new record is created for it. |
|
* Else the old value is freed and the new one stuck in its place |
|
* |
|
* Notes: |
|
* The variable is searched for only in its context before being |
|
* created in that context. I.e. if the context is CTXT_GLOBAL, |
* created in that context. I.e. if the context is CTXT_GLOBAL, |
* only CTXT_GLOBAL is searched. Likewise if it is CTXT_CMD, only |
* only CTXT_GLOBAL is searched. Likewise if it is CTXT_CMD, only |
* CTXT_CMD is searched. |
* CTXT_CMD is searched. |
*----------------------------------------------------------------------- |
|
*/ |
*/ |
void |
void |
Var_Set_interval(name, end, val, ctxt) |
Var_Seti(name, end, val, ctxt) |
const char *name; /* name of variable to set */ |
const char *name; /* name of variable to set */ |
const char *end; |
const char *end; |
const char *val; /* value to give to the variable */ |
const char *val; /* value to give to the variable */ |
|
|
esetenv(v->name, val); |
esetenv(v->name, val); |
} |
} |
|
|
/*- |
|
*----------------------------------------------------------------------- |
|
* Var_Append -- |
|
* The variable of the given name has the given value appended to it in |
|
* the given context. |
|
* |
|
* Side Effects: |
|
* If the variable doesn't exist, it is created. Else the strings |
|
* are concatenated (with a space in between). |
|
* |
|
*----------------------------------------------------------------------- |
|
*/ |
|
void |
void |
Var_Append_interval(name, end, val, ctxt) |
Var_Appendi(name, end, val, ctxt) |
const char *name; /* Name of variable to modify */ |
const char *name; /* Name of variable to modify */ |
const char *end; |
const char *end; |
const char *val; /* String to append to it */ |
const char *val; /* String to append to it */ |
|
|
printf("%s:%s = %s\n", context_name(ctxt), v->name, VarValue(v)); |
printf("%s:%s = %s\n", context_name(ctxt), v->name, VarValue(v)); |
} |
} |
|
|
/*- |
|
*----------------------------------------------------------------------- |
|
* Var_Value -- |
|
* Return the value of a global named variable |
|
* |
|
* Results: |
|
* The value if the variable exists, NULL if it doesn't |
|
*----------------------------------------------------------------------- |
|
*/ |
|
char * |
char * |
Var_Value_interval(name, end) |
Var_Valuei(name, end) |
const char *name; /* name to find */ |
const char *name; /* name to find */ |
const char *end; |
const char *end; |
{ |
{ |
Var *v; |
Var *v; |
|
|
v = VarFind_interval(name, end, NULL, FIND_ENV | FIND_MINE); |
v = VarFindi(name, end, 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 |
|
|
} |
} |
} |
} |
|
|
/*- |
|
*----------------------------------------------------------------------- |
|
* 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. |
|
* |
|
* Return value: the amount to skip |
|
*----------------------------------------------------------------------- |
|
*/ |
|
size_t |
size_t |
Var_ParseSkip(str, ctxt, result) |
Var_ParseSkip(str, ctxt, result) |
const char *str; |
const char *str; |
SymTable *ctxt; |
SymTable *ctxt; |
ReturnStatus *result; |
bool *result; |
{ |
{ |
const char *tstr; /* Pointer into str */ |
const char *tstr; /* Pointer into str */ |
Var *v; /* Variable in invocation */ |
Var *v; /* Variable in invocation */ |
|
|
str++; |
str++; |
|
|
if (*str != '(' && *str != '{') { |
if (*str != '(' && *str != '{') { |
name.tofree = FALSE; |
name.tofree = false; |
tstr = str + 1; |
tstr = str + 1; |
length = 2; |
length = 2; |
endc = '\0'; |
endc = '\0'; |
|
|
str++; |
str++; |
|
|
/* Find eventual modifiers in the variable */ |
/* Find eventual modifiers in the variable */ |
tstr = Var_Name_Get(str, &name, ctxt, FALSE, find_pos(endc)); |
tstr = VarName_Get(str, &name, ctxt, false, find_pos(endc)); |
Var_Name_Free(&name); |
VarName_Free(&name); |
length = tstr - start; |
length = tstr - start; |
/* Terminated correctly */ |
if (*tstr != 0) |
if (*tstr != '\0') |
length++; |
length++; |
|
} |
} |
|
|
if (result != NULL) |
if (result != NULL) |
*result = SUCCESS; |
*result = true; |
if (*tstr == ':' && endc != '\0') |
if (*tstr == ':' && endc != '\0') |
if (VarModifiers_Apply(NULL, NULL, ctxt, TRUE, NULL, tstr, endc, |
if (VarModifiers_Apply(NULL, NULL, ctxt, true, NULL, tstr, endc, |
&length) == var_Error) |
&length) == var_Error) |
*result = FAILURE; |
*result = false; |
return length; |
return length; |
} |
} |
|
|
/*- |
/* As of now, Var_ParseBuffer is just a wrapper around Var_Parse. For |
*----------------------------------------------------------------------- |
* speed, it may be better to revisit the implementation to do things |
* Var_ParseBuffer -- |
* directly. */ |
* Given the start of a variable invocation, extract the variable |
bool |
* 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...?). |
|
*----------------------------------------------------------------------- |
|
*/ |
|
ReturnStatus |
|
Var_ParseBuffer(buf, str, ctxt, err, lengthPtr) |
Var_ParseBuffer(buf, str, ctxt, err, lengthPtr) |
Buffer buf; |
Buffer buf; |
const char *str; |
const char *str; |
SymTable *ctxt; |
SymTable *ctxt; |
Boolean err; |
bool err; |
size_t *lengthPtr; |
size_t *lengthPtr; |
{ |
{ |
char *result; |
char *result; |
Boolean freeIt; |
bool freeIt; |
|
|
result = Var_Parse(str, ctxt, err, lengthPtr, &freeIt); |
result = Var_Parse(str, ctxt, err, lengthPtr, &freeIt); |
if (result == var_Error) |
if (result == var_Error) |
return FAILURE; |
return false; |
|
|
Buf_AddString(buf, result); |
Buf_AddString(buf, result); |
if (freeIt) |
if (freeIt) |
free(result); |
free(result); |
return SUCCESS; |
return true; |
} |
} |
|
|
/*- |
|
*----------------------------------------------------------------------- |
|
* Var_Parse -- |
|
* Given the start of a variable invocation, extract the variable |
|
* name and find its value, then modify it according to the |
|
* specification. |
|
* |
|
* Results: |
|
* The (possibly-modified) value of the variable or var_Error if the |
|
* specification is invalid. The length of the specification is |
|
* placed in *lengthPtr (for invalid specifications, this is just |
|
* 2...?). |
|
* A Boolean in *freePtr telling whether the returned string should |
|
* be freed by the caller. |
|
*----------------------------------------------------------------------- |
|
*/ |
|
char * |
char * |
Var_Parse(str, ctxt, err, lengthPtr, freePtr) |
Var_Parse(str, ctxt, err, lengthPtr, freePtr) |
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 */ |
Boolean 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 */ |
Boolean *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 */ |
|
|
u_int32_t k; |
u_int32_t k; |
int idx; |
int idx; |
|
|
*freePtr = FALSE; |
*freePtr = false; |
start = str++; |
start = str++; |
|
|
val = NULL; |
val = NULL; |
|
|
if (*str != '(' && *str != '{') { |
if (*str != '(' && *str != '{') { |
name.s = str; |
name.s = str; |
name.e = str+1; |
name.e = str+1; |
name.tofree = FALSE; |
name.tofree = false; |
tstr = str + 1; |
tstr = str + 1; |
*lengthPtr = 2; |
*lengthPtr = 2; |
endc = '\0'; |
endc = '\0'; |
|
|
str++; |
str++; |
|
|
/* Find eventual modifiers in the variable */ |
/* Find eventual modifiers in the variable */ |
tstr = Var_Name_Get(str, &name, ctxt, FALSE, find_pos(endc)); |
tstr = VarName_Get(str, &name, ctxt, false, find_pos(endc)); |
*lengthPtr = tstr - start; |
*lengthPtr = tstr - start; |
if (*tstr != '\0') |
if (*tstr != '\0') |
(*lengthPtr)++; |
(*lengthPtr)++; |
|
|
if (idx == -1) { |
if (idx == -1) { |
if (strchr(val, '$') != NULL) { |
if (strchr(val, '$') != NULL) { |
val = Var_Subst(val, ctxt, err); |
val = Var_Subst(val, ctxt, err); |
*freePtr = TRUE; |
*freePtr = true; |
} |
} |
} else if (idx >= LOCAL_SIZE) { |
} else if (idx >= LOCAL_SIZE) { |
if (IS_EXTENDED_F(idx)) |
if (IS_EXTENDED_F(idx)) |
val = Var_GetTail(val); |
val = Var_GetTail(val); |
else |
else |
val = Var_GetHead(val); |
val = Var_GetHead(val); |
*freePtr = TRUE; |
*freePtr = true; |
} |
} |
v->flags &= ~VAR_IN_USE; |
v->flags &= ~VAR_IN_USE; |
} |
} |
|
|
if (idx != -1) { |
if (idx != -1) { |
/* can't be expanded for now: copy the var spec instead. */ |
/* can't be expanded for now: copy the var spec instead. */ |
if (ctxt == NULL || ctxt == CTXT_GLOBAL || ctxt == CTXT_CMD) { |
if (ctxt == NULL || ctxt == CTXT_GLOBAL || ctxt == CTXT_CMD) { |
*freePtr = TRUE; |
*freePtr = true; |
val = interval_dup(start, start+ *lengthPtr); |
val = Str_dupi(start, start+ *lengthPtr); |
} else { |
} else { |
/* somehow, this should have been expanded already. */ |
/* somehow, this should have been expanded already. */ |
GNode *n; |
GNode *n; |
|
|
} |
} |
} |
} |
} |
} |
Var_Name_Free(&name); |
VarName_Free(&name); |
return val; |
return val; |
} |
} |
|
|
/*- |
|
*----------------------------------------------------------------------- |
|
* Var_Subst -- |
|
* Substitute for all variables in a string in a context |
|
* If undefErr is TRUE, Parse_Error will be called when an undefined |
|
* variable is encountered. |
|
* |
|
* Results: |
|
* The resulting string. |
|
* |
|
* Side Effects: |
|
* The new string must be freed by the caller |
|
*----------------------------------------------------------------------- |
|
*/ |
|
char * |
char * |
Var_Subst(str, ctxt, undefErr) |
Var_Subst(str, ctxt, undefErr) |
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 */ |
Boolean 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 Boolean 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 */ |
Boolean doFree; /* Set true if val should be freed */ |
bool doFree; /* Set true if val should be freed */ |
const char *cp; |
const char *cp; |
|
|
/* copy uninteresting stuff */ |
/* copy uninteresting stuff */ |
for (cp = str; *str != '\0' && *str != '$'; str++) |
for (cp = str; *str != '\0' && *str != '$'; str++) |
; |
; |
Buf_AddInterval(&buf, cp, str); |
Buf_Addi(&buf, cp, str); |
if (*str == '\0') |
if (*str == '\0') |
break; |
break; |
if (str[1] == '$') { |
if (str[1] == '$') { |
|
|
Parse_Error(PARSE_FATAL, |
Parse_Error(PARSE_FATAL, |
"Undefined variable \"%.*s\"",length,str); |
"Undefined variable \"%.*s\"",length,str); |
str += length; |
str += length; |
errorReported = TRUE; |
errorReported = true; |
} else { |
} else { |
Buf_AddChar(&buf, *str); |
Buf_AddChar(&buf, *str); |
str++; |
str++; |
|
|
return Buf_Retrieve(&buf); |
return Buf_Retrieve(&buf); |
} |
} |
|
|
/*- |
|
*----------------------------------------------------------------------- |
|
* 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. Add the substituted string to buffer. |
|
*----------------------------------------------------------------------- |
|
*/ |
|
void |
void |
Var_SubstVar(buf, str, var, val) |
Var_SubstVar(buf, str, var, val) |
Buffer buf; |
Buffer buf; |
|
|
/* Copy uninteresting stuff */ |
/* Copy uninteresting stuff */ |
for (start = str; *str != '\0' && *str != '$'; str++) |
for (start = str; *str != '\0' && *str != '$'; str++) |
; |
; |
Buf_AddInterval(buf, start, str); |
Buf_Addi(buf, start, str); |
|
|
start = str; |
start = str; |
if (*str++ == '\0') |
if (*str++ == '\0') |
|
|
str++; |
str++; |
/* and escaped dollars */ |
/* and escaped dollars */ |
if (start[1] == '$') { |
if (start[1] == '$') { |
Buf_AddInterval(buf, start, start+2); |
Buf_Addi(buf, start, start+2); |
continue; |
continue; |
} |
} |
/* Simple variable, if it's not us, copy. */ |
/* Simple variable, if it's not us, copy. */ |
|
|
* expand the external variable at this point, so we try |
* expand the external variable at this point, so we try |
* again with the nested variable. */ |
* again with the nested variable. */ |
if (*p == '$') { |
if (*p == '$') { |
Buf_AddInterval(buf, start, p); |
Buf_Addi(buf, start, p); |
str = p; |
str = p; |
continue; |
continue; |
} |
} |
|
|
if (strncmp(var, str, p - str) != 0 || |
if (strncmp(var, str, p - str) != 0 || |
var[p - str] != '\0') { |
var[p - str] != '\0') { |
/* Not the variable we want to expand. */ |
/* Not the variable we want to expand. */ |
Buf_AddInterval(buf, start, p); |
Buf_Addi(buf, start, p); |
str = p; |
str = p; |
continue; |
continue; |
} |
} |
if (*p == ':') { |
if (*p == ':') { |
size_t length; /* Length of the variable invocation */ |
size_t length; /* Length of the variable invocation */ |
Boolean doFree; /* Set true if val should be freed */ |
bool doFree; /* Set true if val should be freed */ |
char *newval; /* Value substituted for a variable */ |
char *newval; /* Value substituted for a variable */ |
struct Name name; |
struct Name name; |
|
|
length = p - str + 1; |
length = p - str + 1; |
doFree = FALSE; |
doFree = false; |
name.s = var; |
name.s = var; |
name.e = var + (p-str); |
name.e = var + (p-str); |
|
|
/* val won't be freed since doFree == FALSE, but |
/* val won't be freed since doFree == false, but |
* VarModifiers_Apply doesn't know that, hence the cast. */ |
* VarModifiers_Apply doesn't know that, hence the cast. */ |
newval = VarModifiers_Apply((char *)val, &name, NULL, FALSE, |
newval = VarModifiers_Apply((char *)val, &name, NULL, false, |
&doFree, p, endc, &length); |
&doFree, p, endc, &length); |
Buf_AddString(buf, newval); |
Buf_AddString(buf, newval); |
if (doFree) |
if (doFree) |
|
|
} |
} |
|
|
|
|
|
#ifdef CLEANUP |
void |
void |
Var_End() |
Var_End() |
{ |
{ |
#ifdef CLEANUP |
|
Var *v; |
Var *v; |
unsigned int i; |
unsigned int i; |
|
|
|
|
for (v = ohash_first(VAR_CMD, &i); v != NULL; |
for (v = ohash_first(VAR_CMD, &i); v != NULL; |
v = ohash_next(VAR_CMD, &i)) |
v = ohash_next(VAR_CMD, &i)) |
VarDelete(v); |
VarDelete(v); |
#endif |
|
} |
} |
|
#endif |
|
|
static const char *interpret(int); |
static const char *interpret(int); |
|
|
|
|
(v->flags & VAR_DUMMY) == 0 ? VarValue(v) : "(none)"); |
(v->flags & VAR_DUMMY) == 0 ? VarValue(v) : "(none)"); |
} |
} |
|
|
/*- |
|
*----------------------------------------------------------------------- |
|
* Var_Dump -- |
|
* print all variables |
|
*----------------------------------------------------------------------- |
|
*/ |
|
void |
void |
Var_Dump() |
Var_Dump() |
{ |
{ |