commit 77fb0bd

shrub  ·  2026-05-14 00:10:28 +0000 UTC
parent 12b8673
fix some prefix stripping and lhs assignment edge cases
3 files changed,  +51, -29
+0, -1
1@@ -1,6 +1,5 @@
2 build.dot
3 *.o
4-shin
5 tests/runner/runner
6 tests/runner/testhelper
7 tests/work
+10, -8
 1@@ -137,28 +137,29 @@ evalassign(struct EvalCtx *ctx, const struct AssignNode *in)
 2 {
 3 	struct Env *env;
 4 	struct Var *v;
 5-	char *rhs, *joined;
 6+	char *lhs, *rhs, *joined;
 7 	enum Origin o;
 8 	int exported;
 9 
10 	env = ctx->env;
11 	o = in->origin ? in->origin : ORIGIN_FILE;
12 	exported = assignexported(ctx, in);
13+	lhs = expandstr(ctx, in->lhs);
14 	switch (in->op) {
15 	case ASSIGN_EQ:
16-		envsetvar(env, in->lhs, xstrdup(in->rhs), 0, o, exported);
17+		envsetvar(env, lhs, xstrdup(in->rhs), 0, o, exported);
18 		break;
19 	case ASSIGN_COLON_EQ:
20-		envsetvar(env, in->lhs, expandstr(ctx, in->rhs), 1, o, exported);
21+		envsetvar(env, lhs, expandstr(ctx, in->rhs), 1, o, exported);
22 		break;
23 	case ASSIGN_QMARK_EQ:
24-		if (!findvar(env, in->lhs))
25-			envsetvar(env, in->lhs, xstrdup(in->rhs), 0, o, exported);
26+		if (!findvar(env, lhs))
27+			envsetvar(env, lhs, xstrdup(in->rhs), 0, o, exported);
28 		break;
29 	case ASSIGN_PLUS_EQ:
30-		v = findvar(env, in->lhs);
31+		v = findvar(env, lhs);
32 		if (!v) {
33-			envsetvar(env, in->lhs, xstrdup(in->rhs), 0, o, in->exported);
34+			envsetvar(env, lhs, xstrdup(in->rhs), 0, o, in->exported);
35 			break;
36 		}
37 		if ((int)o < (int)v->origin)
38@@ -176,9 +177,10 @@ evalassign(struct EvalCtx *ctx, const struct AssignNode *in)
39 		rhs = expandstr(ctx, in->rhs);
40 		joined = runshellassign(rhs);
41 		free(rhs);
42-		envsetvar(env, in->lhs, joined, 1, o, exported);
43+		envsetvar(env, lhs, joined, 1, o, exported);
44 		break;
45 	}
46+	free(lhs);
47 }
48 
49 static void
+41, -20
 1@@ -400,27 +400,48 @@ expandgraph(struct Graph *graph)
 2 				struct Recipe *r = &t->recipes.v[k];
 3 				char *exp;
 4 
 5-				freestrs(&side_effects);
 6-				exp = expandstr(&ctx, r->body);
 7-				for (j = 0; j < side_effects.n; j++) {
 8-					struct Recipe *nr;
 9-
10-					new_recipes.v = xrealloc(new_recipes.v,
11-					                         (new_recipes.n + 1) * sizeof(new_recipes.v[0]));
12-					nr = &new_recipes.v[new_recipes.n++];
13-					memset(nr, 0, sizeof(*nr));
14-					nr->body = xstrdup(side_effects.v[j]);
15-					nr->silent = r->silent;
16-					nr->ignore = r->ignore;
17+			freestrs(&side_effects);
18+			exp = expandstr(&ctx, r->body);
19+			/* strip recipe prefixes that may have been
20+			 * introduced by variable expansion, eg something like Q_CC = @echo ... */
21+			{
22+				const char *s = exp;
23+				while (*s == '@' || *s == '-' || *s == '+') {
24+					if (*s == '@')
25+						r->silent = 1;
26+					else if (*s == '-')
27+						r->ignore = 1;
28+					else if (*s == '+')
29+						r->recursive = 1;
30+					s++;
31+					while (*s == ' ' || *s == '\t')
32+						s++;
33 				}
34-				if (exp[0]) {
35-					struct Recipe *nr;
36-
37-					new_recipes.v = xrealloc(new_recipes.v,
38-					                         (new_recipes.n + 1) * sizeof(new_recipes.v[0]));
39-					nr = &new_recipes.v[new_recipes.n++];
40-					*nr = *r;
41-					nr->body = exp;
42+				if (s != exp) {
43+					char *trimmed = xstrdup(s);
44+					free(exp);
45+					exp = trimmed;
46+				}
47+			}
48+			for (j = 0; j < side_effects.n; j++) {
49+				struct Recipe *nr;
50+
51+				new_recipes.v = xrealloc(new_recipes.v,
52+				                         (new_recipes.n + 1) * sizeof(new_recipes.v[0]));
53+				nr = &new_recipes.v[new_recipes.n++];
54+				memset(nr, 0, sizeof(*nr));
55+				nr->body = xstrdup(side_effects.v[j]);
56+				nr->silent = r->silent;
57+				nr->ignore = r->ignore;
58+			}
59+			if (exp[0]) {
60+				struct Recipe *nr;
61+
62+				new_recipes.v = xrealloc(new_recipes.v,
63+				                         (new_recipes.n + 1) * sizeof(new_recipes.v[0]));
64+				nr = &new_recipes.v[new_recipes.n++];
65+				*nr = *r;
66+				nr->body = exp;
67 					freesubmake(&nr->sm);
68 					nr->submake = parsesubmake(&nr->sm, nr->body);
69 					free(r->body);