bool Var_ParseSkip(const char **pstr, SymTable *ctxt) { const char *str = *pstr; struct Name name; bool result; bool has_modifier; const char *tstr = str; if (str[1] == 0) { *pstr = str+1; return false; } has_modifier = parse_base_variable_name(&tstr, &name, ctxt); VarName_Free(&name); result = true; if (has_modifier) { bool freePtr = false; char *s = VarModifiers_Apply(NULL, NULL, ctxt, true, &freePtr, &tstr, str[1]); if (s == var_Error) result = false; if (freePtr) free(s); } *pstr = tstr; return result; }
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; }
/* Very quick version of the variable scanner that just looks for target * variables, and never ever errors out */ bool Var_Check_for_target(const char *str) { bool seen_target = false; for (;;) { const char *tstr; uint32_t k; int idx; bool has_modifier; struct Name name; /* skip over uninteresting stuff */ for (; *str != '\0' && *str != '$'; str++) ; if (*str == '\0') break; if (str[1] == '$') { /* A $ may be escaped with another $. */ str += 2; continue; } tstr = str; has_modifier = parse_base_variable_name(&tstr, &name, NULL); idx = classify_var(name.s, &name.e, &k); if (has_modifier) { bool doFree = false; char *val = VarModifiers_Apply(NULL, NULL, NULL, false, &doFree, &tstr, str[1]); if (doFree) free(val); } if (tlist[idx]) seen_target = true; VarName_Free(&name); str = tstr; } return seen_target; }
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; }
void Var_SubstVar(Buffer buf, /* To store result */ const char *str, /* The string in which to substitute */ struct LoopVar *l, /* Handle */ const char *val) /* Its value */ { const char *var = l->me->name; var_set_value(l->me, val); for (;;) { const char *start; /* Copy uninteresting stuff */ for (start = str; *str != '\0' && *str != '$'; str++) ; Buf_Addi(buf, start, str); start = str; if (*str++ == '\0') break; str++; /* and escaped dollars */ if (start[1] == '$') { Buf_Addi(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); continue; } } else { const char *p; char paren = start[1]; /* Find the end of the variable specification. */ p = find_pos(paren)(str); /* 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_Addi(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_Addi(buf, start, p); str = p; continue; } if (*p == ':') { bool doFree; /* should val be freed ? */ char *newval; struct Name name; doFree = false; name.s = var; name.e = var + (p-str); /* val won't be freed since !doFree, but * VarModifiers_Apply doesn't know that, * hence the cast. */ newval = VarModifiers_Apply((char *)val, &name, NULL, false, &doFree, &p, paren); Buf_AddString(buf, newval); if (doFree) free(newval); str = p; continue; } else str = p+1; } Buf_AddString(buf, val); } }