Module Name: src
Committed By: rillig
Date: Tue Sep 22 17:42:58 UTC 2020
Modified Files:
src/usr.bin/make: var.c
Log Message:
make(1): move ParseModifierPart further down in the code
This way, it can access the ApplyModifierState, which will be used in a
follow-up commit to reduce the code duplication around the error
handling for missing delimiters.
To generate a diff of this commit:
cvs rdiff -u -r1.528 -r1.529 src/usr.bin/make/var.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/usr.bin/make/var.c
diff -u src/usr.bin/make/var.c:1.528 src/usr.bin/make/var.c:1.529
--- src/usr.bin/make/var.c:1.528 Tue Sep 22 06:23:33 2020
+++ src/usr.bin/make/var.c Tue Sep 22 17:42:57 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: var.c,v 1.528 2020/09/22 06:23:33 rillig Exp $ */
+/* $NetBSD: var.c,v 1.529 2020/09/22 17:42:57 rillig Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -121,7 +121,7 @@
#include "metachar.h"
/* "@(#)var.c 8.3 (Berkeley) 3/19/94" */
-MAKE_RCSID("$NetBSD: var.c,v 1.528 2020/09/22 06:23:33 rillig Exp $");
+MAKE_RCSID("$NetBSD: var.c,v 1.529 2020/09/22 17:42:57 rillig Exp $");
#define VAR_DEBUG_IF(cond, fmt, ...) \
if (!(DEBUG(VAR) && (cond))) \
@@ -1585,141 +1585,6 @@ VarUniq(const char *str)
}
-/*-
- * Parse a part of a modifier such as the "from" and "to" in :S/from/to/
- * or the "var" or "replacement" in :@var@replacement+${var}@, up to and
- * including the next unescaped delimiter. The delimiter, as well as the
- * backslash or the dollar, can be escaped with a backslash.
- *
- * Return the parsed (and possibly expanded) string, or NULL if no delimiter
- * was found. On successful return, the parsing position pp points right
- * after the delimiter. The delimiter is not included in the returned
- * value though.
- */
-static char *
-ParseModifierPart(
- const char **pp, /* The parsing position, updated upon return */
- int delim, /* Parsing stops at this delimiter */
- VarEvalFlags eflags, /* Flags for evaluating nested variables;
- * if VARE_WANTRES is not set, the text is
- * only parsed */
- GNode *ctxt, /* For looking up nested variables */
- size_t *out_length, /* Optionally stores the length of the returned
- * string, just to save another strlen call. */
- VarPatternFlags *out_pflags,/* For the first part of the :S modifier,
- * sets the VARP_ANCHOR_END flag if the last
- * character of the pattern is a $. */
- ModifyWord_SubstArgs *subst /* For the second part of the :S modifier,
- * allow ampersands to be escaped and replace
- * unescaped ampersands with subst->lhs. */
-) {
- Buffer buf;
- const char *p;
- char *rstr;
-
- Buf_Init(&buf, 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.
- */
- p = *pp;
- while (*p != '\0' && *p != delim) {
- const char *varstart;
-
- Boolean is_escaped = p[0] == '\\' && (
- p[1] == delim || p[1] == '\\' || p[1] == '$' ||
- (p[1] == '&' && subst != NULL));
- if (is_escaped) {
- Buf_AddByte(&buf, p[1]);
- p += 2;
- continue;
- }
-
- if (*p != '$') { /* Unescaped, simple text */
- if (subst != NULL && *p == '&')
- Buf_AddBytes(&buf, subst->lhs, subst->lhsLen);
- else
- Buf_AddByte(&buf, *p);
- p++;
- continue;
- }
-
- if (p[1] == delim) { /* Unescaped $ at end of pattern */
- if (out_pflags != NULL)
- *out_pflags |= VARP_ANCHOR_END;
- else
- Buf_AddByte(&buf, *p);
- p++;
- continue;
- }
-
- if (eflags & VARE_WANTRES) { /* Nested variable, evaluated */
- const char *nested_p = p;
- const char *nested_val;
- void *nested_val_freeIt;
- VarEvalFlags nested_eflags = eflags & ~(unsigned)VARE_ASSIGN;
-
- (void)Var_Parse(&nested_p, ctxt, nested_eflags,
- &nested_val, &nested_val_freeIt);
- /* TODO: handle errors */
- Buf_AddStr(&buf, nested_val);
- free(nested_val_freeIt);
- p += nested_p - p;
- continue;
- }
-
- /* XXX: This whole block is very similar to Var_Parse without
- * VARE_WANTRES. There may be subtle edge cases though that are
- * not yet covered in the unit tests and that are parsed differently,
- * depending on whether they are evaluated or not.
- *
- * This subtle difference is not documented in the manual page,
- * neither is the difference between parsing :D and :M documented.
- * No code should ever depend on these details, but who knows. */
-
- varstart = p; /* Nested variable, only parsed */
- if (p[1] == '(' || p[1] == '{') {
- /*
- * Find the end of this variable reference
- * and suck it in without further ado.
- * It will be interpreted later.
- */
- int have = p[1];
- int want = have == '(' ? ')' : '}';
- int depth = 1;
-
- for (p += 2; *p != '\0' && depth > 0; p++) {
- if (p[-1] != '\\') {
- if (*p == have)
- depth++;
- if (*p == want)
- depth--;
- }
- }
- Buf_AddBytesBetween(&buf, varstart, p);
- } else {
- Buf_AddByte(&buf, *varstart);
- p++;
- }
- }
-
- if (*p != delim) {
- *pp = p;
- return NULL;
- }
-
- *pp = ++p;
- if (out_length != NULL)
- *out_length = Buf_Size(&buf);
-
- rstr = Buf_Destroy(&buf, FALSE);
- VAR_DEBUG("Modifier part: \"%s\"\n", rstr);
- return rstr;
-}
-
/* Quote shell meta-characters and space characters in the string.
* If quoteDollar is set, also quote and double any '$' characters. */
static char *
@@ -1936,6 +1801,141 @@ typedef enum {
* if st->missing_delim is set. */
} ApplyModifierResult;
+/*-
+ * Parse a part of a modifier such as the "from" and "to" in :S/from/to/
+ * or the "var" or "replacement" in :@var@replacement+${var}@, up to and
+ * including the next unescaped delimiter. The delimiter, as well as the
+ * backslash or the dollar, can be escaped with a backslash.
+ *
+ * Return the parsed (and possibly expanded) string, or NULL if no delimiter
+ * was found. On successful return, the parsing position pp points right
+ * after the delimiter. The delimiter is not included in the returned
+ * value though.
+ */
+static char *
+ParseModifierPart(
+ const char **pp, /* The parsing position, updated upon return */
+ int delim, /* Parsing stops at this delimiter */
+ VarEvalFlags eflags, /* Flags for evaluating nested variables;
+ * if VARE_WANTRES is not set, the text is
+ * only parsed */
+ ApplyModifiersState *st,
+ size_t *out_length, /* Optionally stores the length of the returned
+ * string, just to save another strlen call. */
+ VarPatternFlags *out_pflags,/* For the first part of the :S modifier,
+ * sets the VARP_ANCHOR_END flag if the last
+ * character of the pattern is a $. */
+ ModifyWord_SubstArgs *subst /* For the second part of the :S modifier,
+ * allow ampersands to be escaped and replace
+ * unescaped ampersands with subst->lhs. */
+) {
+ Buffer buf;
+ const char *p;
+ char *rstr;
+
+ Buf_Init(&buf, 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.
+ */
+ p = *pp;
+ while (*p != '\0' && *p != delim) {
+ const char *varstart;
+
+ Boolean is_escaped = p[0] == '\\' && (
+ p[1] == delim || p[1] == '\\' || p[1] == '$' ||
+ (p[1] == '&' && subst != NULL));
+ if (is_escaped) {
+ Buf_AddByte(&buf, p[1]);
+ p += 2;
+ continue;
+ }
+
+ if (*p != '$') { /* Unescaped, simple text */
+ if (subst != NULL && *p == '&')
+ Buf_AddBytes(&buf, subst->lhs, subst->lhsLen);
+ else
+ Buf_AddByte(&buf, *p);
+ p++;
+ continue;
+ }
+
+ if (p[1] == delim) { /* Unescaped $ at end of pattern */
+ if (out_pflags != NULL)
+ *out_pflags |= VARP_ANCHOR_END;
+ else
+ Buf_AddByte(&buf, *p);
+ p++;
+ continue;
+ }
+
+ if (eflags & VARE_WANTRES) { /* Nested variable, evaluated */
+ const char *nested_p = p;
+ const char *nested_val;
+ void *nested_val_freeIt;
+ VarEvalFlags nested_eflags = eflags & ~(unsigned)VARE_ASSIGN;
+
+ (void)Var_Parse(&nested_p, st->ctxt, nested_eflags,
+ &nested_val, &nested_val_freeIt);
+ /* TODO: handle errors */
+ Buf_AddStr(&buf, nested_val);
+ free(nested_val_freeIt);
+ p += nested_p - p;
+ continue;
+ }
+
+ /* XXX: This whole block is very similar to Var_Parse without
+ * VARE_WANTRES. There may be subtle edge cases though that are
+ * not yet covered in the unit tests and that are parsed differently,
+ * depending on whether they are evaluated or not.
+ *
+ * This subtle difference is not documented in the manual page,
+ * neither is the difference between parsing :D and :M documented.
+ * No code should ever depend on these details, but who knows. */
+
+ varstart = p; /* Nested variable, only parsed */
+ if (p[1] == '(' || p[1] == '{') {
+ /*
+ * Find the end of this variable reference
+ * and suck it in without further ado.
+ * It will be interpreted later.
+ */
+ int have = p[1];
+ int want = have == '(' ? ')' : '}';
+ int depth = 1;
+
+ for (p += 2; *p != '\0' && depth > 0; p++) {
+ if (p[-1] != '\\') {
+ if (*p == have)
+ depth++;
+ if (*p == want)
+ depth--;
+ }
+ }
+ Buf_AddBytesBetween(&buf, varstart, p);
+ } else {
+ Buf_AddByte(&buf, *varstart);
+ p++;
+ }
+ }
+
+ if (*p != delim) {
+ *pp = p;
+ return NULL;
+ }
+
+ *pp = ++p;
+ if (out_length != NULL)
+ *out_length = Buf_Size(&buf);
+
+ rstr = Buf_Destroy(&buf, FALSE);
+ VAR_DEBUG("Modifier part: \"%s\"\n", rstr);
+ return rstr;
+}
+
/* Test whether mod starts with modname, followed by a delimiter. */
static Boolean
ModMatch(const char *mod, const char *modname, char endc)
@@ -1967,8 +1967,8 @@ ApplyModifier_Loop(const char **pp, Appl
(*pp)++; /* Skip the first '@' */
delim = '@';
- args.tvar = ParseModifierPart(pp, delim, eflags,
- st->ctxt, NULL, NULL, NULL);
+ args.tvar = ParseModifierPart(pp, delim, eflags, st,
+ NULL, NULL, NULL);
if (args.tvar == NULL) {
st->missing_delim = delim;
return AMR_CLEANUP;
@@ -1981,8 +1981,8 @@ ApplyModifier_Loop(const char **pp, Appl
return AMR_CLEANUP;
}
- args.str = ParseModifierPart(pp, delim, eflags,
- st->ctxt, NULL, NULL, NULL);
+ args.str = ParseModifierPart(pp, delim, eflags, st,
+ NULL, NULL, NULL);
if (args.str == NULL) {
st->missing_delim = delim;
return AMR_CLEANUP;
@@ -2149,7 +2149,7 @@ ApplyModifier_ShellCommand(const char **
(*pp)++;
delim = '!';
- cmd = ParseModifierPart(pp, delim, st->eflags, st->ctxt,
+ cmd = ParseModifierPart(pp, delim, st->eflags, st,
NULL, NULL, NULL);
if (cmd == NULL) {
st->missing_delim = delim;
@@ -2315,7 +2315,7 @@ ApplyModifier_Subst(const char **pp, App
(*pp)++;
}
- lhs = ParseModifierPart(pp, delim, st->eflags, st->ctxt,
+ lhs = ParseModifierPart(pp, delim, st->eflags, st,
&args.lhsLen, &args.pflags, NULL);
if (lhs == NULL) {
st->missing_delim = delim;
@@ -2323,7 +2323,7 @@ ApplyModifier_Subst(const char **pp, App
}
args.lhs = lhs;
- rhs = ParseModifierPart(pp, delim, st->eflags, st->ctxt,
+ rhs = ParseModifierPart(pp, delim, st->eflags, st,
&args.rhsLen, NULL, &args);
if (rhs == NULL) {
st->missing_delim = delim;
@@ -2375,13 +2375,14 @@ ApplyModifier_Regex(const char **pp, App
*pp += 2;
- re = ParseModifierPart(pp, delim, st->eflags, st->ctxt, NULL, NULL, NULL);
+ re = ParseModifierPart(pp, delim, st->eflags, st,
+ NULL, NULL, NULL);
if (re == NULL) {
st->missing_delim = delim;
return AMR_CLEANUP;
}
- args.replace = ParseModifierPart(pp, delim, st->eflags, st->ctxt,
+ args.replace = ParseModifierPart(pp, delim, st->eflags, st,
NULL, NULL, NULL);
if (args.replace == NULL) {
free(re);
@@ -2563,7 +2564,7 @@ ApplyModifier_Words(const char **pp, App
(*pp)++; /* skip the '[' */
delim = ']'; /* look for closing ']' */
- estr = ParseModifierPart(pp, delim, st->eflags, st->ctxt,
+ estr = ParseModifierPart(pp, delim, st->eflags, st,
NULL, NULL, NULL);
if (estr == NULL) {
st->missing_delim = delim;
@@ -2733,7 +2734,7 @@ ApplyModifier_IfElse(const char **pp, Ap
(*pp)++; /* skip past the '?' */
delim = ':';
- then_expr = ParseModifierPart(pp, delim, then_eflags, st->ctxt,
+ then_expr = ParseModifierPart(pp, delim, then_eflags, st,
NULL, NULL, NULL);
if (then_expr == NULL) {
st->missing_delim = delim;
@@ -2741,7 +2742,7 @@ ApplyModifier_IfElse(const char **pp, Ap
}
delim = st->endc; /* BRCLOSE or PRCLOSE */
- else_expr = ParseModifierPart(pp, delim, else_eflags, st->ctxt,
+ else_expr = ParseModifierPart(pp, delim, else_eflags, st,
NULL, NULL, NULL);
if (else_expr == NULL) {
st->missing_delim = delim;
@@ -2836,7 +2837,7 @@ ApplyModifier_Assign(const char **pp, Ap
}
delim = st->startc == '(' ? ')' : '}';
- val = ParseModifierPart(pp, delim, st->eflags, st->ctxt, NULL, NULL, NULL);
+ val = ParseModifierPart(pp, delim, st->eflags, st, NULL, NULL, NULL);
if (st->exprFlags & VEF_UNDEF) {
/* restore original name */
free(st->v->name);
@@ -2951,14 +2952,14 @@ ApplyModifier_SysV(const char **pp, Appl
delim = '=';
*pp = mod;
- lhs = ParseModifierPart(pp, delim, st->eflags, st->ctxt, NULL, NULL, NULL);
+ lhs = ParseModifierPart(pp, delim, st->eflags, st, NULL, NULL, NULL);
if (lhs == NULL) {
st->missing_delim = delim;
return AMR_CLEANUP;
}
delim = st->endc;
- rhs = ParseModifierPart(pp, delim, st->eflags, st->ctxt, NULL, NULL, NULL);
+ rhs = ParseModifierPart(pp, delim, st->eflags, st, NULL, NULL, NULL);
if (rhs == NULL) {
st->missing_delim = delim;
return AMR_CLEANUP;