commit fd3a8d1

shrub  ·  2026-05-05 14:49:17 +0000 UTC
parent d304126
handle [], fix auto var handling in function expansion, dedup $^
2 files changed,  +106, -8
+50, -2
 1@@ -229,6 +229,28 @@ findclose(const char *s, size_t i, size_t n, char close)
 2 static char *expandvarref(struct EvalCtx *ctx, const char *s, size_t n);
 3 static char *expandref(struct EvalCtx *ctx, const char *s, size_t n);
 4 
 5+static char *
 6+autoprereqsval(const struct StrList *prereqs, char kind)
 7+{
 8+	if (kind == '+')
 9+		return joinstrs(prereqs, " ");
10+
11+	{
12+		size_t i;
13+		struct StrList uniq;
14+		char *joined;
15+
16+		memset(&uniq, 0, sizeof(uniq));
17+		for (i = 0; i < prereqs->n; i++) {
18+			if (!hasword(&uniq, prereqs->v[i]))
19+				addstr(&uniq, prereqs->v[i]);
20+		}
21+		joined = joinstrs(&uniq, " ");
22+		freestrs(&uniq);
23+		return joined;
24+	}
25+}
26+
27 static char *
28 expandname(struct EvalCtx *ctx, const char *s)
29 {
30@@ -264,7 +286,7 @@ expandname(struct EvalCtx *ctx, const char *s)
31 		    ctx->auto_prereqs) {
32 			char *joined;
33 
34-			joined = joinstrs(ctx->auto_prereqs, " ");
35+			joined = autoprereqsval(ctx->auto_prereqs, s[i + 1]);
36 			bufappend(&out, joined);
37 			free(joined);
38 			i++;
39@@ -555,7 +577,33 @@ expandstr(struct EvalCtx *ctx, const char *s)
40 			continue;
41 		}
42 		if (s[i + 1] != '(' && s[i + 1] != '{') {
43-			/* leave automatic variables for expandauto and translateauto */
44+			if (s[i + 1] == '@' && ctx->auto_target) {
45+				bufappend(&out, ctx->auto_target);
46+				i++;
47+				continue;
48+			}
49+			if (s[i + 1] == '<' && ctx->auto_prereqs) {
50+				if (ctx->auto_prereqs->n > 0)
51+					bufappend(&out, ctx->auto_prereqs->v[0]);
52+				i++;
53+				continue;
54+			}
55+			if ((s[i + 1] == '^' || s[i + 1] == '+' || s[i + 1] == '?') &&
56+			    ctx->auto_prereqs) {
57+				char *joined;
58+
59+				joined = autoprereqsval(ctx->auto_prereqs, s[i + 1]);
60+				bufappend(&out, joined);
61+				free(joined);
62+				i++;
63+				continue;
64+			}
65+			if (s[i + 1] == '*' && ctx->auto_stem) {
66+				bufappend(&out, ctx->auto_stem);
67+				i++;
68+				continue;
69+			}
70+			/* leave unresolved automatic vars for later translation */
71 			if (s[i + 1] == '@' || s[i + 1] == '<' || s[i + 1] == '^' ||
72 			    s[i + 1] == '+' || s[i + 1] == '?' || s[i + 1] == '*' ||
73 			    s[i + 1] == '%') {
+56, -6
  1@@ -3,6 +3,7 @@
  2 #include "posix.h"
  3 #include "gnu/pattern.h"
  4 
  5+#include <glob.h>
  6 #include <stdio.h>
  7 #include <stdlib.h>
  8 #include <string.h>
  9@@ -107,6 +108,45 @@ targetenv(struct GraphState *gs, struct EvalCtx *ctx, const struct Env *base, co
 10 	applytassigns(gs, ctx, name);
 11 }
 12 
 13+static int
 14+hasglobmeta(const char *s)
 15+{
 16+	size_t i;
 17+
 18+	for (i = 0; s[i]; i++) {
 19+		if (s[i] == '\\' && s[i + 1]) {
 20+			i++;
 21+			continue;
 22+		}
 23+		if (s[i] == '*' || s[i] == '?' || s[i] == '[')
 24+			return 1;
 25+	}
 26+	return 0;
 27+}
 28+
 29+static void
 30+addglobword(struct StrList *out, const char *s)
 31+{
 32+	glob_t g;
 33+	size_t i;
 34+	int rc;
 35+
 36+	if (!hasglobmeta(s)) {
 37+		addstr(out, s);
 38+		return;
 39+	}
 40+
 41+	memset(&g, 0, sizeof(g));
 42+	rc = glob(s, 0, 0, &g);
 43+	if (rc == 0 && g.gl_pathc > 0) {
 44+		for (i = 0; i < g.gl_pathc; i++)
 45+			addstr(out, g.gl_pathv[i]);
 46+	} else {
 47+		addstr(out, s);
 48+	}
 49+	globfree(&g);
 50+}
 51+
 52 /* add an explicit target rule to the graph, and add all
 53  * non-pattern prereqs also as placeholder nodes. later
 54  * we discorver how to build them if they need to be built */
 55@@ -117,8 +157,12 @@ addrule(struct GraphState *gs, const char *name, const struct RuleNode *rule)
 56 	struct Target *t;
 57 	struct Env env;
 58 	struct EvalCtx ctx;
 59+	struct StrList prereqs;
 60+	struct StrList order_only;
 61 
 62 	memset(&ctx, 0, sizeof(ctx));
 63+	memset(&prereqs, 0, sizeof(prereqs));
 64+	memset(&order_only, 0, sizeof(order_only));
 65 	ctx.env = &env;
 66 
 67 	t = findtarget(gs->graph, name);
 68@@ -134,25 +178,29 @@ addrule(struct GraphState *gs, const char *name, const struct RuleNode *rule)
 69 	}
 70 	t->defined = 1;
 71 	t->dcolon = rule->dcolon;
 72-	addwords(&t->prereqs, &rule->prereqs);
 73-	addwords(&t->order_only, &rule->order_only);
 74+	for (i = 0; i < rule->prereqs.n; i++)
 75+		addglobword(&prereqs, rule->prereqs.v[i]);
 76+	for (i = 0; i < rule->order_only.n; i++)
 77+		addglobword(&order_only, rule->order_only.v[i]);
 78+	addwords(&t->prereqs, &prereqs);
 79+	addwords(&t->order_only, &order_only);
 80 	targetenv(gs, &ctx, t->env.n ? &t->env : 0, name);
 81 	addrecipes(&t->recipes, &rule->recipes);
 82 	freeenv(&t->env);
 83 	copyenv(&t->env, &env);
 84 
 85-	for (i = 0; i < rule->prereqs.n; i++) {
 86+	for (i = 0; i < prereqs.n; i++) {
 87 		struct Env penv;
 88 		struct EvalCtx pctx;
 89 
 90-		if (strchr(rule->prereqs.v[i], '%'))
 91+		if (strchr(prereqs.v[i], '%'))
 92 			continue;
 93-		t = findtarget(gs->graph, rule->prereqs.v[i]);
 94+		t = findtarget(gs->graph, prereqs.v[i]);
 95 		if (!t) {
 96 			gs->graph->v = xrealloc(gs->graph->v, (gs->graph->n + 1) * sizeof(gs->graph->v[0]));
 97 			t = &gs->graph->v[gs->graph->n++];
 98 			memset(t, 0, sizeof(*t));
 99-			t->name = intern(rule->prereqs.v[i]);
100+			t->name = intern(prereqs.v[i]);
101 		}
102 		memset(&penv, 0, sizeof(penv));
103 		memset(&pctx, 0, sizeof(pctx));
104@@ -162,6 +210,8 @@ addrule(struct GraphState *gs, const char *name, const struct RuleNode *rule)
105 		copyenv(&t->env, pctx.env);
106 		freeenv(&penv);
107 	}
108+	freestrs(&prereqs);
109+	freestrs(&order_only);
110 	freeenv(&env);
111 }
112 static void