/* we would like to subst on intervals, but it's complicated, so we cheat * by storing the interval in a static buffer. */ char * Var_Substi(const char *str, const char *estr, SymTable *ctxt, bool undefErr) { /* delimited string: no need to copy */ if (estr == NULL || *estr == '\0') return Var_Subst(str, ctxt, undefErr); Buf_Reset(&subst_buffer); Buf_Addi(&subst_buffer, str, estr); return Var_Subst(Buf_Retrieve(&subst_buffer), ctxt, undefErr); }
/*- *----------------------------------------------------------------------- * 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 CondHandleString(bool doEval) { char *lhs; const char *begin; BUFFER buf; /* find the extent of the string */ begin = ++condExpr; while (*condExpr && *condExpr != '"') { condExpr++; } Buf_Init(&buf, 0); Buf_Addi(&buf, begin, condExpr); if (*condExpr == '"') condExpr++; lhs = Var_Subst(Buf_Retrieve(&buf), NULL, doEval); Buf_Destroy(&buf); return CondHandleComparison(lhs, true, 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); } }