commit bcdf49f

shrub  ·  2026-04-07 21:40:11 +0000 UTC
parent 248e4cc
feat: substitutions
1 files changed,  +138, -2
+138, -2
  1@@ -858,12 +858,123 @@ isplainvar(const char *s, size_t n)
  2 	return 1;
  3 }
  4 
  5+static char *
  6+substword(const char *word, size_t n, const char *from, const char *to)
  7+{
  8+	size_t nfrom, nto;
  9+	const char *pct;
 10+	char *out;
 11+
 12+	nfrom = strlen(from);
 13+	nto = strlen(to);
 14+	pct = strchr(from, '%');
 15+	if (!pct) {
 16+		if (n < nfrom || memcmp(word + n - nfrom, from, nfrom) != 0)
 17+			return xstrndup(word, n);
 18+		out = xmalloc(n - nfrom + nto + 1);
 19+		memcpy(out, word, n - nfrom);
 20+		memcpy(out + n - nfrom, to, nto);
 21+		out[n - nfrom + nto] = 0;
 22+		return out;
 23+	}
 24+	{
 25+		size_t pre, suf, stem;
 26+		const char *tpct;
 27+
 28+		pre = (size_t)(pct - from);
 29+		suf = nfrom - pre - 1;
 30+		if (n < pre + suf)
 31+			return xstrndup(word, n);
 32+		if (memcmp(word, from, pre) != 0 || memcmp(word + n - suf, pct + 1, suf) != 0)
 33+			return xstrndup(word, n);
 34+		stem = n - pre - suf;
 35+		tpct = strchr(to, '%');
 36+		if (!tpct) {
 37+			out = xstrdup(to);
 38+			return out;
 39+		}
 40+		{
 41+			size_t tpre, tsuf;
 42+
 43+			tpre = (size_t)(tpct - to);
 44+			tsuf = nto - tpre - 1;
 45+			out = xmalloc(tpre + stem + tsuf + 1);
 46+			memcpy(out, to, tpre);
 47+			memcpy(out + tpre, word + pre, stem);
 48+			memcpy(out + tpre + stem, tpct + 1, tsuf);
 49+			out[tpre + stem + tsuf] = 0;
 50+			return out;
 51+		}
 52+	}
 53+}
 54+
 55+static char *
 56+substval(const char *val, const char *from, const char *to)
 57+{
 58+	size_t i, j, n, cap, len, wn;
 59+	char *out, *part;
 60+
 61+	n = strlen(val);
 62+	cap = n + 1;
 63+	len = 0;
 64+	out = xmalloc(cap);
 65+	for (i = 0; i < n;) {
 66+		if (isspace((unsigned char)val[i])) {
 67+			if (len + 2 > cap) {
 68+				cap *= 2;
 69+				out = xrealloc(out, cap);
 70+			}
 71+			out[len++] = val[i++];
 72+			continue;
 73+		}
 74+		j = i;
 75+		while (j < n && !isspace((unsigned char)val[j]))
 76+			j++;
 77+		part = substword(val + i, j - i, from, to);
 78+		wn = strlen(part);
 79+		if (len + wn + 1 > cap) {
 80+			cap = len + wn + 1;
 81+			out = xrealloc(out, cap);
 82+		}
 83+		memcpy(out + len, part, wn);
 84+		len += wn;
 85+		free(part);
 86+		i = j;
 87+	}
 88+	out[len] = 0;
 89+	return out;
 90+}
 91+
 92+static int
 93+issubstref(const char *s, size_t n, size_t *colon, size_t *eq)
 94+{
 95+	size_t i;
 96+
 97+	for (i = 0; i < n; i++) {
 98+		if (s[i] == ':') {
 99+			*colon = i;
100+			break;
101+		}
102+		if (!(isalnum((unsigned char)s[i]) || s[i] == '_'))
103+			return 0;
104+	}
105+	if (i == 0 || i >= n)
106+		return 0;
107+	for (i = *colon + 1; i < n; i++) {
108+		if (s[i] == '=') {
109+			*eq = i;
110+			return i > *colon + 1;
111+		}
112+	}
113+	return 0;
114+}
115+
116 static char *
117 expandstr(struct Env *env, const char *s)
118 {
119-	size_t i, j, k, n, cap, len, inner, start;
120+	size_t i, j, k, n, cap, len, inner, start, colon, eq;
121 	char close;
122-	char *out, *name, *val;
123+	char *out, *name, *val, *from, *to;
124 	struct Var *v;
125 
126 	n = strlen(s);
127@@ -915,6 +1026,31 @@ expandstr(struct Env *env, const char *s)
128 			memcpy(out + len, val, k);
129 			len += k;
130 			free(val);
131+		} else if (issubstref(s + i + 2, j - i - 3, &colon, &eq)) {
132+			name = xstrndup(s + i + 2, colon);
133+			from = xstrndup(s + i + 2 + colon + 1, eq - colon - 1);
134+			to = xstrndup(s + i + 2 + eq + 1, j - i - 4 - eq);
135+			v = findvar(env, name);
136+			free(name);
137+			if (v) {
138+				char *base;
139+
140+				base = expandstr(env, v->val);
141+				val = substval(base, from, to);
142+				free(base);
143+			} else {
144+				val = xstrdup("");
145+			}
146+			free(from);
147+			free(to);
148+			k = strlen(val);
149+			if (len + k + 1 > cap) {
150+				cap = len + k + 1;
151+				out = xrealloc(out, cap);
152+			}
153+			memcpy(out + len, val, k);
154+			len += k;
155+			free(val);
156 		} else {
157 			k = j - start;
158 			if (len + k + 1 > cap) {