char * Var_Parse(const char *str, /* The string to parse */ SymTable *ctxt, /* The context for the variable */ bool err, /* true if undefined variables are an error */ size_t *lengthPtr, /* OUT: The length of the specification */ bool *freePtr) /* OUT: true if caller should free result */ { const char *tstr; struct Name name; char *val; uint32_t k; int idx; bool has_modifier; *freePtr = false; tstr = str; if (str[1] == 0) { *lengthPtr = 1; *freePtr = false; return err ? var_Error : varNoError; } has_modifier = parse_base_variable_name(&tstr, &name, ctxt); idx = classify_var(name.s, &name.e, &k); val = get_expanded_value(name.s, name.e, idx, k, ctxt, err, freePtr); if (has_modifier) { val = VarModifiers_Apply(val, &name, ctxt, err, freePtr, &tstr, str[1]); } if (val == NULL) { val = err ? var_Error : varNoError; /* If it comes from a dynamic source, and it doesn't have * a context, copy the spec instead. * Specifically, this make allows constructs like: * target.o: $*.c * Absence of a context means "parsing". But these can't * be expanded during parsing, to be consistent with the * way .SUFFIXES work. * .SUFFIXES may be added/reset/removed during parsing, * but in the end, the final list is what's considered for * handling targets. So those dynamic variables must be * handled lazily too. */ if (idx != GLOBAL_INDEX) { if (ctxt == NULL) { *freePtr = true; val = Str_dupi(str, tstr); } else { bad_dynamic_variable(idx); } } } VarName_Free(&name); *lengthPtr = tstr - str; return val; }
char * Var_Parse(const char *str, /* The string to parse */ SymTable *ctxt, /* The context for the variable */ bool err, /* true if undefined variables are an error */ size_t *lengthPtr, /* OUT: The length of the specification */ bool *freePtr) /* OUT: true if caller should free result */ { const char *tstr; struct Name name; char *val; uint32_t k; int idx; bool has_modifier; *freePtr = false; tstr = str; has_modifier = parse_base_variable_name(&tstr, &name, ctxt); idx = classify_var(name.s, &name.e, &k); val = get_expanded_value(name.s, name.e, idx, k, ctxt, err, freePtr); if (has_modifier) { val = VarModifiers_Apply(val, &name, ctxt, err, freePtr, &tstr, str[1]); } if (val == NULL) { val = err ? var_Error : varNoError; /* Dynamic source */ if (idx != GLOBAL_INDEX) { /* can't be expanded for now: copy the spec instead. */ if (ctxt == NULL) { *freePtr = true; val = Str_dupi(str, tstr); } else { /* somehow, this should have been expanded already. */ GNode *n; /* XXX */ 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->origin.lineno, n->origin.fname); break; default: Error( "Using undefined dynamic variable $%s (line %lu of %s)", varnames[idx], n->origin.lineno, n->origin.fname); break; } } } } VarName_Free(&name); *lengthPtr = tstr - str; return val; }