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