/* Normal version of var_set_value(), to be called after variable is fully * initialized. */ static void var_set_value(Var *v, const char *val) { if ((v->flags & VAR_DUMMY) == 0) { Buf_Reset(&(v->val)); Buf_AddString(&(v->val), val); } else { var_set_initial_value(v, val); v->flags &= ~VAR_DUMMY; } }
/* 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 * directly. */ bool Var_ParseBuffer(Buffer buf, const char *str, SymTable *ctxt, bool err, size_t *lengthPtr) { char *result; bool freeIt; result = Var_Parse(str, ctxt, err, lengthPtr, &freeIt); if (result == var_Error) return false; Buf_AddString(buf, result); if (freeIt) free(result); return true; }
/*- *----------------------------------------------------------------------- * Str_SYSVSubst -- * Substitute '%' in the pattern with len characters from src. * If the pattern does not contain a '%' prepend len characters * from src. * * Side Effects: * Adds result to buf *----------------------------------------------------------------------- */ void Str_SYSVSubst(Buffer buf, const char *pat, const char *src, size_t len) { const char *m; if ((m = strchr(pat, '%')) != NULL) { /* Copy the prefix. */ Buf_Addi(buf, pat, m); /* Skip the %. */ pat = m + 1; } /* Copy the pattern. */ Buf_AddChars(buf, len, src); /* Append the rest. */ Buf_AddString(buf, pat); }
static Token CondHandleVarSpec(bool doEval) { char *lhs; size_t varSpecLen; bool doFree; /* Parse the variable spec and skip over it, saving its * value in lhs. */ lhs = Var_Parse(condExpr, NULL, doEval,&varSpecLen,&doFree); if (lhs == var_Error) /* Even if !doEval, we still report syntax errors, which * is what getting var_Error back with !doEval means. */ return Err; condExpr += varSpecLen; if (!isspace(*condExpr) && strchr("!=><", *condExpr) == NULL) { BUFFER buf; Buf_Init(&buf, 0); Buf_AddString(&buf, lhs); if (doFree) free(lhs); for (;*condExpr && !isspace(*condExpr); condExpr++) Buf_AddChar(&buf, *condExpr); lhs = Var_Subst(Buf_Retrieve(&buf), NULL, doEval); Buf_Destroy(&buf); doFree = true; } return CondHandleComparison(lhs, doFree, doEval); }
char * Var_Subst(const char *str, /* the string in which to substitute */ SymTable *ctxt, /* the context wherein to find variables */ bool undefErr) /* true if undefineds are an error */ { BUFFER buf; /* Buffer for forming things */ static bool errorReported; Buf_Init(&buf, MAKE_BSIZE); errorReported = false; for (;;) { char *val; /* Value to substitute for a variable */ size_t length; /* Length of the variable invocation */ bool doFree; /* Set true if val should be freed */ const char *cp; /* copy uninteresting stuff */ for (cp = str; *str != '\0' && *str != '$'; str++) ; Buf_Addi(&buf, cp, str); if (*str == '\0') break; if (str[1] == '$') { /* A $ may be escaped with another $. */ Buf_AddChar(&buf, '$'); str += 2; continue; } val = Var_Parse(str, ctxt, undefErr, &length, &doFree); /* When we come down here, val should either point to the * value of this variable, suitably modified, or be NULL. * Length should be the total length of the potential * variable invocation (from $ to end character...) */ if (val == var_Error || val == varNoError) { /* If errors are not an issue, skip over the variable * and continue with the substitution. Otherwise, store * the dollar sign and advance str so we continue with * the string... */ if (errorIsOkay) str += length; else if (undefErr) { /* If variable is undefined, complain and * skip the variable name. The complaint * will stop us from doing anything when * the file is parsed. */ if (!errorReported) Parse_Error(PARSE_FATAL, "Undefined variable \"%.*s\"", length, str); str += length; errorReported = true; } else { Buf_AddChar(&buf, *str); str++; } } else { /* We've now got a variable structure to store in. * But first, advance the string pointer. */ str += length; /* Copy all the characters from the variable value * straight into the new string. */ Buf_AddString(&buf, val); if (doFree) free(val); } } return Buf_Retrieve(&buf); }
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); } }
void Make_DoAllVar(GNode *gn) { GNode *child; LstNode ln; BUFFER allsrc, oodate; char *target; bool do_oodate; int oodate_count, allsrc_count = 0; oodate_count = 0; allsrc_count = 0; for (ln = Lst_First(&gn->children); ln != NULL; ln = Lst_Adv(ln)) { child = (GNode *)Lst_Datum(ln); if ((child->type & (OP_EXEC|OP_USE|OP_INVISIBLE)) != 0) continue; if (OP_NOP(child->type) || (target = Var(TARGET_INDEX, child)) == NULL) { /* * this node is only source; use the specific pathname * for it */ target = child->path != NULL ? child->path : child->name; } /* * It goes in the OODATE variable if the parent is younger than * the child or if the child has been modified more recently * than the start of the make. This is to keep make from * getting confused if something else updates the parent after * the make starts (shouldn't happen, I know, but sometimes it * does). In such a case, if we've updated the kid, the parent * is likely to have a modification time later than that of the * kid and anything that relies on the OODATE variable will be * hosed. */ do_oodate = false; if (gn->type & OP_JOIN) { if (child->built_status == MADE) do_oodate = true; } else if (is_strictly_before(gn->mtime, child->mtime) || (!is_strictly_before(child->mtime, now) && child->built_status == MADE)) do_oodate = true; if (do_oodate) { oodate_count++; if (oodate_count == 1) Var(OODATE_INDEX, gn) = target; else { if (oodate_count == 2) { Buf_Init(&oodate, 0); Buf_AddString(&oodate, Var(OODATE_INDEX, gn)); } Buf_AddSpace(&oodate); Buf_AddString(&oodate, target); } } allsrc_count++; if (allsrc_count == 1) Var(ALLSRC_INDEX, gn) = target; else { if (allsrc_count == 2) { Buf_Init(&allsrc, 0); Buf_AddString(&allsrc, Var(ALLSRC_INDEX, gn)); } Buf_AddSpace(&allsrc); Buf_AddString(&allsrc, target); } } if (allsrc_count > 1) Var(ALLSRC_INDEX, gn) = Buf_Retrieve(&allsrc); if (oodate_count > 1) Var(OODATE_INDEX, gn) = Buf_Retrieve(&oodate); if (gn->impliedsrc) Var(IMPSRC_INDEX, gn) = Var(TARGET_INDEX, gn->impliedsrc); if (gn->type & OP_JOIN) Var(TARGET_INDEX, gn) = Var(ALLSRC_INDEX, gn); }