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) {