diff options
-rw-r--r-- | usr.bin/make/var.c | 308 | ||||
-rw-r--r-- | usr.bin/make/var.h | 1 |
2 files changed, 92 insertions, 217 deletions
diff --git a/usr.bin/make/var.c b/usr.bin/make/var.c index c791da4..fc00a88 100644 --- a/usr.bin/make/var.c +++ b/usr.bin/make/var.c @@ -677,8 +677,7 @@ SortIncreasing(const void *l, const void *r) * Pass through the tstr looking for 1) escaped delimiters, * '$'s and backslashes (place the escaped character in * uninterpreted) and 2) unescaped $'s that aren't before - * the delimiter (expand the variable substitution unless flags - * has VAR_NOSUBST set). + * the delimiter (expand the variable substitution). * Return the expanded string or NULL if the delimiter was missing * If pattern is specified, handle escaped ampersands, and replace * unescaped ampersands with the lhs of the pattern. @@ -694,108 +693,80 @@ SortIncreasing(const void *l, const void *r) *----------------------------------------------------------------------- */ static char * -VarGetPattern(VarParser *vp, const char **tstr, int delim, int *flags, - size_t *length, VarPattern *pattern) +VarGetPattern(VarParser *vp, int delim, int *flags, + size_t *length, VarPattern *patt) { - const char *cp; - Buffer *buf = Buf_Init(0); - size_t junk; - - if (length == NULL) - length = &junk; + Buffer *buf; -#define IS_A_MATCH(cp, delim) \ - ((cp[0] == '\\') && ((cp[1] == delim) || \ - (cp[1] == '\\') || (cp[1] == '$') || (pattern && (cp[1] == '&')))) + buf = Buf_Init(0); /* * Skim through until the matching delimiter is found; pick up * variable substitutions on the way. Also allow backslashes to quote * the delimiter, $, and \, but don't touch other backslashes. */ - for (cp = *tstr; *cp && (*cp != delim); cp++) { - if (IS_A_MATCH(cp, delim)) { - Buf_AddByte(buf, (Byte)cp[1]); - cp++; - } else if (*cp == '$') { - if (cp[1] == delim) { - if (flags == NULL) - Buf_AddByte(buf, (Byte)*cp); - else + while (*vp->ptr != '\0') { + if (*vp->ptr == delim) { + char *result; + + result = (char *)Buf_GetAll(buf, length); + Buf_Destroy(buf, FALSE); + return (result); + + } else if ((vp->ptr[0] == '\\') && + ((vp->ptr[1] == delim) || + (vp->ptr[1] == '\\') || + (vp->ptr[1] == '$') || + (vp->ptr[1] == '&' && patt != NULL))) { + vp->ptr++; /* consume backslash */ + Buf_AddByte(buf, (Byte)vp->ptr[0]); + vp->ptr++; + + } else if (vp->ptr[0] == '$') { + if (vp->ptr[1] == delim) { + if (flags == NULL) { + Buf_AddByte(buf, (Byte)vp->ptr[0]); + vp->ptr++; + } else { /* - * Unescaped $ at end of pattern => - * anchor pattern at end. + * Unescaped $ at end of patt => + * anchor patt at end. */ *flags |= VAR_MATCH_END; + vp->ptr++; + } } else { - if (flags == NULL || - (*flags & VAR_NOSUBST) == 0) { - char *cp2; - size_t len; - Boolean freeIt; - - /* - * If unescaped dollar sign not - * before the delimiter, assume it's - * a variable substitution and - * recurse. - */ - len = 0; - cp2 = Var_Parse(cp, vp->ctxt, vp->err, &len, &freeIt); - Buf_Append(buf, cp2); - if (freeIt) - free(cp2); - cp += len - 1; - } else { - const char *cp2 = &cp[1]; + char *cp; + size_t len; + Boolean freeIt; - if (*cp2 == OPEN_PAREN || - *cp2 == OPEN_BRACE) { - /* - * Find the end of this - * variable reference and - * suck it in without further - * ado. It will be - * interperated later. - */ - int have = *cp2; - int want = (*cp2 == OPEN_PAREN) ? CLOSE_PAREN : CLOSE_BRACE; - int depth = 1; - - for (++cp2; *cp2 != '\0' && depth > 0; ++cp2) { - if (cp2[-1] != '\\') { - if (*cp2 == have) - ++depth; - if (*cp2 == want) - --depth; - } - } - Buf_AppendRange(buf, cp, cp2); - cp = --cp2; - } else - Buf_AddByte(buf, (Byte)*cp); - } + /* + * If unescaped dollar sign not + * before the delimiter, assume it's + * a variable substitution and + * recurse. + */ + len = 0; + cp = Var_Parse(vp->ptr, vp->ctxt, vp->err, &len, &freeIt); + Buf_Append(buf, cp); + if (freeIt) + free(cp); + vp->ptr += len; } - } else if (pattern && *cp == '&') - Buf_AddBytes(buf, pattern->leftLen, (Byte *) pattern->lhs); - else - Buf_AddByte(buf, (Byte)*cp); + } else if (vp->ptr[0] == '&' && patt != NULL) { + Buf_AddBytes(buf, patt->leftLen, (Byte *)patt->lhs); + vp->ptr++; + } else { + Buf_AddByte(buf, (Byte)vp->ptr[0]); + vp->ptr++; + } } - Buf_AddByte(buf, (Byte)'\0'); - - if (*cp != delim) { - *tstr = cp; + if (length != NULL) { *length = 0; - return (NULL); - } else { - char *result; - *tstr = ++cp; - result = (char *)Buf_GetAll(buf, length); - *length -= 1; /* Don't count the NULL */ - Buf_Destroy(buf, FALSE); - return (result); } + Buf_Destroy(buf, TRUE); + return (NULL); } /*- @@ -951,13 +922,11 @@ modifier_M(VarParser *vp, const char value[], char endc) static char * modifier_S(VarParser *vp, const char value[], Var *v) { - VarPattern pattern; - Buffer *buf; /* Buffer for patterns */ + VarPattern patt; char delim; char *newValue; - pattern.flags = 0; - buf = Buf_Init(0); + patt.flags = 0; vp->ptr++; /* consume 'S' */ @@ -969,134 +938,38 @@ modifier_S(VarParser *vp, const char value[], Var *v) * word -- skip over it and flag pattern. */ if (*vp->ptr == '^') { - pattern.flags |= VAR_MATCH_START; + patt.flags |= VAR_MATCH_START; vp->ptr++; } - /* - * Pass through the lhs looking for 1) escaped delimiters, '$'s and - * backslashes (place the escaped character in uninterpreted) and 2) - * unescaped $'s that aren't before the delimiter (expand the - * variable substitution). The result is left in the Buffer buf. - */ - while (vp->ptr[0] != delim) { - if (vp->ptr[0] == '\0') { - /* - * LHS didn't end with the delim, complain and exit. - */ - Fatal("Unclosed substitution for %s (%c missing)", - v->name, delim); - - } else if ((vp->ptr[0] == '\\') && - ((vp->ptr[1] == delim) || - (vp->ptr[1] == '$') || - (vp->ptr[1] == '\\'))) { - vp->ptr++; /* consume backslash */ - Buf_AddByte(buf, (Byte)vp->ptr[0]); - vp->ptr++; - - } else if (vp->ptr[0] == '$') { - if (vp->ptr[1] == delim) { - /* - * Unescaped $ at end of pattern => anchor - * pattern at end. - */ - pattern.flags |= VAR_MATCH_END; - vp->ptr++; - } else { - /* - * If unescaped dollar sign not before the - * delimiter, assume it's a variable - * substitution and recurse. - */ - char *cp2; - size_t len; - Boolean freeIt; - - len = 0; - cp2 = Var_Parse(vp->ptr, vp->ctxt, vp->err, &len, &freeIt); - vp->ptr += len; - Buf_Append(buf, cp2); - if (freeIt) { - free(cp2); - } - } - } else { - Buf_AddByte(buf, (Byte)vp->ptr[0]); - vp->ptr++; - } + patt.lhs = VarGetPattern(vp, delim, &patt.flags, &patt.leftLen, NULL); + if (patt.lhs == NULL) { + /* + * LHS didn't end with the delim, complain and exit. + */ + Fatal("Unclosed substitution for %s (%c missing)", + v->name, delim); } - vp->ptr++; /* consume 2nd delim */ - - /* - * Fetch pattern and destroy buffer, but preserve the data in it, - * since that's our lhs. - */ - pattern.lhs = (char *)Buf_GetAll(buf, &pattern.leftLen); - Buf_Destroy(buf, FALSE); - - /* - * Now comes the replacement string. Three things need to be done - * here: 1) need to compress escaped delimiters and ampersands and 2) - * need to replace unescaped ampersands with the l.h.s. (since this - * isn't regexp, we can do it right here) and 3) expand any variable - * substitutions. - */ - buf = Buf_Init(0); - - while (vp->ptr[0] != delim) { - if (vp->ptr[0] == '\0') { - /* - * Didn't end with delim character, complain - */ - Fatal("Unclosed substitution for %s (%c missing)", - v->name, delim); - } else if ((vp->ptr[0] == '\\') && - ((vp->ptr[1] == delim) || - (vp->ptr[1] == '&') || - (vp->ptr[1] == '\\') || - (vp->ptr[1] == '$'))) { - vp->ptr++; /* skip backslash */ - Buf_AddByte(buf, (Byte)vp->ptr[0]); - vp->ptr++; - - } else if (vp->ptr[0] == '$') { - if (vp->ptr[1] == delim) { - Buf_AddByte(buf, (Byte)vp->ptr[0]); - vp->ptr++; - } else { - char *cp2; - size_t len; - Boolean freeIt; + vp->ptr++; /* consume 2nd delim */ - len = 0; - cp2 = Var_Parse(vp->ptr, vp->ctxt, vp->err, &len, &freeIt); - vp->ptr += len; - Buf_Append(buf, cp2); - if (freeIt) { - free(cp2); - } - } - } else if (vp->ptr[0] == '&') { - Buf_AddBytes(buf, pattern.leftLen, (Byte *)pattern.lhs); - vp->ptr++; - } else { - Buf_AddByte(buf, (Byte)vp->ptr[0]); - vp->ptr++; - } + patt.rhs = VarGetPattern(vp, delim, NULL, &patt.rightLen, &patt); + if (patt.rhs == NULL) { + /* + * RHS didn't end with the delim, complain and exit. + */ + Fatal("Unclosed substitution for %s (%c missing)", + v->name, delim); } - vp->ptr++; /* consume last delim */ - pattern.rhs = (char *)Buf_GetAll(buf, &pattern.rightLen); - Buf_Destroy(buf, FALSE); + vp->ptr++; /* consume last delim */ /* * Check for global substitution. If 'g' after the final delimiter, * substitution is global and is marked that way. */ if (vp->ptr[0] == 'g') { - pattern.flags |= VAR_SUB_GLOBAL; + patt.flags |= VAR_SUB_GLOBAL; vp->ptr++; } @@ -1107,16 +980,16 @@ modifier_S(VarParser *vp, const char value[], Var *v) * can only contain the 3 bits we're interested in so we don't have * to mask unrelated bits. We can test for equality. */ - if (!pattern.leftLen && pattern.flags == VAR_SUB_GLOBAL) + if (patt.leftLen == 0 && patt.flags == VAR_SUB_GLOBAL) Fatal("Global substitution of the empty string"); - newValue = VarModify(value, VarSubstitute, &pattern); + newValue = VarModify(value, VarSubstitute, &patt); /* * Free the two strings. */ - free(pattern.lhs); - free(pattern.rhs); + free(patt.lhs); + free(patt.rhs); return (newValue); } @@ -1138,18 +1011,22 @@ modifier_C(VarParser *vp, char value[], Var *v) vp->ptr++; /* consume 1st delim */ - re = VarGetPattern(vp, &vp->ptr, delim, NULL, NULL, NULL); + re = VarGetPattern(vp, delim, NULL, NULL, NULL); if (re == NULL) { Fatal("Unclosed substitution for %s (%c missing)", v->name, delim); } - patt.replace = VarGetPattern(vp, &vp->ptr, delim, NULL, NULL, NULL); + vp->ptr++; /* consume 2st delim */ + + patt.replace = VarGetPattern(vp, delim, NULL, NULL, NULL); if (patt.replace == NULL) { Fatal("Unclosed substitution for %s (%c missing)", v->name, delim); } + vp->ptr++; /* consume last delim */ + switch (*vp->ptr) { case 'g': patt.flags |= VAR_SUB_GLOBAL; @@ -1211,9 +1088,9 @@ sysVvarsub(VarParser *vp, char startc, Var *v, const char value[]) * First we make a pass through the string trying to verify it is a * SYSV-make-style translation: it must be: <string1>=<string2>) */ + eqFound = FALSE; cp = vp->ptr; cnt = 1; - eqFound = FALSE; while (*cp != '\0' && cnt) { if (*cp == '=') { eqFound = TRUE; @@ -1230,19 +1107,18 @@ sysVvarsub(VarParser *vp, char startc, Var *v, const char value[]) /* * Now we break this sucker into the lhs and rhs. */ - cp = vp->ptr; - - patt.lhs = VarGetPattern(vp, &cp, '=', &patt.flags, &patt.leftLen, NULL); + patt.lhs = VarGetPattern(vp, '=', &patt.flags, &patt.leftLen, NULL); if (patt.lhs == NULL) { Fatal("Unclosed substitution for %s (%c missing)", v->name, '='); } - patt.rhs = VarGetPattern(vp, &cp, endc, NULL, &patt.rightLen, &patt); + vp->ptr++; /* consume '=' */ + + patt.rhs = VarGetPattern(vp, endc, NULL, &patt.rightLen, &patt); if (patt.rhs == NULL) { Fatal("Unclosed substitution for %s (%c missing)", v->name, endc); } - vp->ptr = cp - 1; /* put pointer on top of endc */ /* * SYSV modifications happen through the whole string. Note diff --git a/usr.bin/make/var.h b/usr.bin/make/var.h index c1a0fb6..8a1ab85 100644 --- a/usr.bin/make/var.h +++ b/usr.bin/make/var.h @@ -71,7 +71,6 @@ typedef struct Var { #define VAR_SUB_MATCHED 0x04 /* There was a match */ #define VAR_MATCH_START 0x08 /* Match at start of word */ #define VAR_MATCH_END 0x10 /* Match at end of word */ -#define VAR_NOSUBST 0x20 /* don't expand vars in VarGetPattern */ typedef struct { char *lhs; /* String to match */ |