commit fa3993a

shrub  ·  2026-05-14 20:30:33 +0000 UTC
parent ab67d72
eval: correctly expand substitution refs on automatic vars and add test for it
4 files changed,  +67, -4
+41, -4
 1@@ -167,7 +167,7 @@ issubstref(const char *s, size_t n, size_t *colon, size_t *eq)
 2 			*colon = i;
 3 			break;
 4 		}
 5-		if (!(isalnum((unsigned char)s[i]) || s[i] == '_'))
 6+		if (isspace((unsigned char)s[i]))
 7 			return 0;
 8 	}
 9 	if (i == 0 || i >= n)
10@@ -364,6 +364,8 @@ expandsubstref(struct EvalCtx *ctx, const char *s, size_t colon, size_t eq, size
11 {
12 	char *name, *from, *to, *val;
13 	struct Var *v;
14+	char *base;
15+	int auto_name;
16 
17 	{
18 		char *nameraw, *toraw, *fromraw;
19@@ -378,14 +380,49 @@ expandsubstref(struct EvalCtx *ctx, const char *s, size_t colon, size_t eq, size
20 		free(fromraw);
21 		free(toraw);
22 		v = findvar(ctx->env, name);
23-		free(name);
24 	}
25+	base = 0;
26+	auto_name = 0;
27 	if (v) {
28-		char *base;
29-
30 		base = expandstr(ctx, v->val);
31+	} else if (name[0] && name[1] == 0) {
32+		/* we handle some substitution refs on automatic vars like $(@:.o=.c). */
33+		switch (name[0]) {
34+		case '@':
35+			auto_name = 1;
36+			if (ctx->auto_target)
37+				base = xstrdup(ctx->auto_target);
38+			break;
39+		case '<':
40+			auto_name = 1;
41+			if (ctx->auto_prereqs && ctx->auto_prereqs->n > 0)
42+				base = xstrdup(ctx->auto_prereqs->v[0]);
43+			break;
44+		case '^':
45+		case '+':
46+		case '?':
47+			auto_name = 1;
48+			if (ctx->auto_prereqs)
49+				base = autoprereqsval(ctx->auto_prereqs, name[0]);
50+			break;
51+		case '*':
52+			auto_name = 1;
53+			if (ctx->auto_stem)
54+				base = xstrdup(ctx->auto_stem);
55+			break;
56+		}
57+	}
58+	free(name);
59+
60+	if (base) {
61 		val = substval(base, from, to);
62 		free(base);
63+	} else if (auto_name) {
64+		char *inner;
65+
66+		inner = xstrndup(s, n);
67+		val = cat3("$(", inner, ")");
68+		free(inner);
69 	} else {
70 		val = xstrdup("");
71 	}
+8, -0
1@@ -0,0 +1,8 @@
2+OBJ = foo.o bar.o
3+
4+all: $(OBJ)
5+
6+bar.o: foo.o
7+
8+$(OBJ):
9+	@echo src=$(@:.o=.c)
+2, -0
1@@ -0,0 +1,2 @@
2+src=foo.c
3+src=bar.c
+16, -0
 1@@ -0,0 +1,16 @@
 2+{
 3+  "case": "t002",
 4+  "category": "variables",
 5+  "compare_output": true,
 6+  "description": "substitution refs work on automatic target variable",
 7+  "details": "",
 8+  "env": {},
 9+  "expected_exit": 0,
10+  "options": "",
11+  "options_mode": "argv",
12+  "output_mode": "exact",
13+  "setup": [],
14+  "stdin": "",
15+  "suite": "shin",
16+  "timeout_seconds": 60
17+}