commit ec04fe8
shrub
·
2026-04-21 18:00:26 +0000 UTC
parent 5ff05ee
handle foreach strip and findstring funcs
3 files changed,
+161,
-0
+3,
-0
1@@ -331,12 +331,15 @@ static const struct func funcs[] = {
2 {"basename", FNEXP1, {.f1 = fnbasename}},
3 {"filter-out", FNEXP2, {.f2 = fnfilterout}},
4 {"filter", FNEXP2, {.f2 = fnfilter}},
5+ {"findstring", FNEXP2, {.f2 = fnfindstring}},
6 {"addprefix", FNEXP2, {.f2 = fnaddprefix}},
7 {"addsuffix", FNEXP2, {.f2 = fnaddsuffix}},
8+ {"strip", FNEXP1, {.f1 = fnstrip}},
9 {"subst", FNEXP3, {.f3 = fnsubst}},
10 {"patsubst", FNEXP3, {.f3 = fnpatsubst}},
11 {"if", FNEXP3, {.f3 = fnif}},
12 {"call", FNCTX, {.ctx = fncall}},
13+ {"foreach", FNCTX, {.ctx = fnforeach}},
14 {"eval", FNCTX, {.ctx = fneval}},
15 {"words", FNEXP1, {.f1 = fnwords}},
16 {"word", FNEXP2, {.f2 = fnword}},
+155,
-0
1@@ -262,6 +262,12 @@ fnfilterout(const char *patterns, const char *text)
2 return out;
3 }
4
5+char *
6+fnfindstring(const char *find, const char *in)
7+{
8+ return strstr(in, find) ? xstrdup(find) : xstrdup("");
9+}
10+
11 char *
12 fnaddprefix(const char *prefix, const char *names)
13 {
14@@ -350,6 +356,44 @@ fnaddsuffix(const char *suffix, const char *names)
15 return out;
16 }
17
18+char *
19+fnstrip(const char *text)
20+{
21+ char *out;
22+ size_t i, j, len, cap;
23+ int need_space;
24+
25+ cap = strlen(text) + 1;
26+ if (cap < 16)
27+ cap = 16;
28+ out = xmalloc(cap);
29+ len = 0;
30+ need_space = 0;
31+
32+ for (i = 0; text[i];) {
33+ while (text[i] && isspace((unsigned char)text[i]))
34+ i++;
35+ if (!text[i])
36+ break;
37+ if (need_space)
38+ out[len++] = ' ';
39+ j = i;
40+ while (text[j] && !isspace((unsigned char)text[j]))
41+ j++;
42+ if (len + (j - i) + 1 > cap) {
43+ while (cap < len + (j - i) + 1)
44+ cap *= 2;
45+ out = xrealloc(out, cap);
46+ }
47+ memcpy(out + len, text + i, j - i);
48+ len += j - i;
49+ need_space = 1;
50+ i = j;
51+ }
52+ out[len] = 0;
53+ return out;
54+}
55+
56 static int
57 cmpstr(const void *a, const void *b)
58 {
59@@ -896,6 +940,18 @@ freeargsraw(char **argv, size_t argc)
60 free(argv);
61 }
62
63+static char *
64+trimspacesdup(const char *s)
65+{
66+ size_t i, j;
67+
68+ for (i = 0; s[i] && isspace((unsigned char)s[i]); i++)
69+ ;
70+ for (j = strlen(s); j > i && isspace((unsigned char)s[j - 1]); j--)
71+ ;
72+ return xstrndup(s + i, j - i);
73+}
74+
75 char *
76 fncall(struct EvalCtx *ctx, const char *args)
77 {
78@@ -964,6 +1020,105 @@ fncall(struct EvalCtx *ctx, const char *args)
79 return val;
80 }
81
82+char *
83+fnforeach(struct EvalCtx *ctx, const char *args)
84+{
85+ char **raw;
86+ char *name_raw, *name, *list, *out;
87+ char *saved_name, *saved_val;
88+ struct Var *saved;
89+ size_t argc, i, j, len, cap;
90+ int saved_simple;
91+ enum Origin saved_origin;
92+ int had_saved;
93+
94+ raw = splitargsraw(args, &argc);
95+ if (argc < 3) {
96+ freeargsraw(raw, argc);
97+ return xstrdup("");
98+ }
99+
100+ name_raw = expandstr(ctx, raw[0]);
101+ name = trimspacesdup(name_raw);
102+ free(name_raw);
103+ list = expandstr(ctx, raw[1]);
104+
105+ saved = findvar(ctx->env, name);
106+ had_saved = saved != 0;
107+ if (had_saved) {
108+ saved_name = xstrdup(saved->name);
109+ saved_val = xstrdup(saved->val);
110+ saved_simple = saved->simple;
111+ saved_origin = saved->origin;
112+ } else {
113+ saved_name = 0;
114+ saved_val = 0;
115+ saved_simple = 0;
116+ saved_origin = ORIGIN_FILE;
117+ }
118+
119+ cap = strlen(list) + 1;
120+ if (cap < 16)
121+ cap = 16;
122+ len = 0;
123+ out = xmalloc(cap);
124+ out[0] = 0;
125+
126+ for (i = 0; list[i];) {
127+ char *word, *exp;
128+ size_t wn, need;
129+
130+ while (list[i] && isspace((unsigned char)list[i]))
131+ i++;
132+ if (!list[i])
133+ break;
134+ j = i;
135+ while (list[j] && !isspace((unsigned char)list[j]))
136+ j++;
137+ word = xstrndup(list + i, j - i);
138+ envsetvar(ctx->env, name, word, 1, ORIGIN_OVERRIDE);
139+ exp = expandstr(ctx, raw[2]);
140+ wn = strlen(exp);
141+ need = len + wn + 2;
142+ if (need > cap) {
143+ while (cap < need)
144+ cap *= 2;
145+ out = xrealloc(out, cap);
146+ }
147+ if (len)
148+ out[len++] = ' ';
149+ memcpy(out + len, exp, wn);
150+ len += wn;
151+ out[len] = 0;
152+ free(exp);
153+ i = j;
154+ }
155+
156+ if (had_saved) {
157+ envsetvar(ctx->env, saved_name, saved_val, saved_simple, saved_origin);
158+ free(saved_name);
159+ } else {
160+ size_t k;
161+
162+ for (k = 0; k < ctx->env->n; k++) {
163+ if (strcmp(ctx->env->v[k].name, name) == 0) {
164+ free(ctx->env->v[k].name);
165+ free(ctx->env->v[k].val);
166+ memmove(&ctx->env->v[k], &ctx->env->v[k + 1],
167+ (ctx->env->n - k - 1) * sizeof(ctx->env->v[0]));
168+ ctx->env->n--;
169+ break;
170+ }
171+ }
172+ }
173+
174+ free(saved_val);
175+ free(list);
176+ free(name);
177+ freeargsraw(raw, argc);
178+ return out;
179+}
180+
181 char *
182 fneval(struct EvalCtx *ctx, const char *args)
183 {
+3,
-0
1@@ -59,8 +59,10 @@ char *fnwildcard(const char *patterns);
2 char *fnshell(const char *cmd);
3 char *fnfilter(const char *patterns, const char *text);
4 char *fnfilterout(const char *patterns, const char *text);
5+char *fnfindstring(const char *find, const char *in);
6 char *fnaddprefix(const char *prefix, const char *names);
7 char *fnaddsuffix(const char *suffix, const char *names);
8+char *fnstrip(const char *text);
9 char *fnsort(const char *text);
10 char *fninfo(struct EvalCtx *ctx, const char *args);
11 char *fnnotdir(const char *names);
12@@ -76,6 +78,7 @@ char *fnfirstword(const char *list);
13 char *fnlastword(const char *list);
14
15 char *fncall(struct EvalCtx *ctx, const char *args);
16+char *fnforeach(struct EvalCtx *ctx, const char *args);
17 char *fneval(struct EvalCtx *ctx, const char *args);
18 int evalsnippet(struct EvalCtx *ctx, const char *path, const char *src);
19