commit db1efaa

shrub  ·  2026-05-16 19:01:22 +0000 UTC
parent 11f2e54
handle glob include
4 files changed,  +121, -34
+85, -34
  1@@ -2,6 +2,7 @@
  2 #include "internal.h"
  3 #include "posix.h"
  4 
  5+#include <glob.h>
  6 #include <stdio.h>
  7 #include <stdlib.h>
  8 #include <string.h>
  9@@ -381,6 +382,16 @@ addrulesetrule(struct RuleSet *out, const struct RuleNode *src, struct EvalCtx *
 10 	addrecipes(&dst->recipes, &src->recipes);
 11 }
 12 
 13+static int
 14+hasglobmeta(const char *s)
 15+{
 16+	for (; *s; s++) {
 17+		if (*s == '*' || *s == '?' || *s == '[')
 18+			return 1;
 19+	}
 20+	return 0;
 21+}
 22+
 23 static int
 24 evalinclude(struct EvalCtx *ctx, const struct IncludeNode *inc)
 25 {
 26@@ -397,49 +408,89 @@ evalinclude(struct EvalCtx *ctx, const struct IncludeNode *inc)
 27 	splitwords(&paths, exp, strlen(exp));
 28 	free(exp);
 29 	for (i = 0; i < paths.n; i++) {
 30-		char *src;
 31+		size_t j, nmatch;
 32+		char *single;
 33+		const char *word;
 34+		glob_t g;
 35+		int grc;
 36+
 37+		memset(&g, 0, sizeof(g));
 38+		single = 0;
 39+		word = paths.v[i];
 40+		nmatch = 0;
 41+		grc = 0;
 42+		if (hasglobmeta(word))
 43+			grc = glob(word, 0, 0, &g);
 44+		if (hasglobmeta(word) && grc == 0 && g.gl_pathc > 0) {
 45+			nmatch = g.gl_pathc;
 46+		} else if (hasglobmeta(word)) {
 47+			nmatch = 0;
 48+		} else {
 49+			nmatch = 1;
 50+			single = xstrdup(word);
 51+		}
 52+
 53+		if (nmatch == 0) {
 54+			if (!inc->optional)
 55+				fprintf(stderr, "%s:%d: %s: No such file or directory\n",
 56+				        ctx->cur_path, ctx->cur_line, word);
 57+			globfree(&g);
 58+			continue;
 59+		}
 60+
 61+		for (j = 0; j < nmatch; j++) {
 62+			char *src;
 63+			const char *path;
 64 
 65-		src = readfile(paths.v[i]);
 66-		if (!src) {
 67-			size_t r, k;
 68+			path = single ? single : g.gl_pathv[j];
 69+			src = readfile(path);
 70+			if (!src) {
 71+				size_t r, k;
 72 
 73-			makerule = 0;
 74-			for (r = 0; r < ctx->out->nrules && !makerule; r++) {
 75-				struct RuleNode *rule = &ctx->out->rules[r];
 76+				makerule = 0;
 77+				for (r = 0; r < ctx->out->nrules && !makerule; r++) {
 78+					struct RuleNode *rule = &ctx->out->rules[r];
 79 
 80-				for (k = 0; k < rule->targets.n; k++) {
 81-					if (strcmp(rule->targets.v[k], paths.v[i]) == 0) {
 82-						makerule = rule;
 83-						break;
 84+					for (k = 0; k < rule->targets.n; k++) {
 85+						if (strcmp(rule->targets.v[k], path) == 0) {
 86+							makerule = rule;
 87+							break;
 88+						}
 89 					}
 90 				}
 91-			}
 92-			if (makerule) {
 93-				for (k = 0; k < makerule->recipes.n; k++) {
 94-					char *cmd;
 95-					int rc;
 96-
 97-					cmd = expandstr(ctx, makerule->recipes.v[k].body);
 98-					rc = system(cmd);
 99-					free(cmd);
100-					if (rc != 0)
101-						break;
102+				if (makerule) {
103+					for (k = 0; k < makerule->recipes.n; k++) {
104+						char *cmd;
105+						int rc;
106+
107+						cmd = expandstr(ctx, makerule->recipes.v[k].body);
108+						rc = system(cmd);
109+						free(cmd);
110+						if (rc != 0)
111+							break;
112+					}
113+					src = readfile(path);
114 				}
115-				src = readfile(paths.v[i]);
116 			}
117-		}
118-		if (!src) {
119-			if (!inc->optional)
120-				fprintf(stderr, "%s:%d: %s: No such file or directory\n",
121-				        ctx->cur_path, ctx->cur_line, paths.v[i]);
122-			continue;
123-		}
124-		if (evalsnippet(ctx, paths.v[i], src) < 0) {
125+			if (!src) {
126+				if (!inc->optional)
127+					fprintf(stderr, "%s:%d: %s: No such file or directory\n",
128+					        ctx->cur_path, ctx->cur_line, path);
129+				continue;
130+			}
131+			if (evalsnippet(ctx, path, src) < 0) {
132+				free(src);
133+				if (single)
134+					free(single);
135+				globfree(&g);
136+				freestrs(&paths);
137+				return -1;
138+			}
139 			free(src);
140-			freestrs(&paths);
141-			return -1;
142 		}
143-		free(src);
144+		if (single)
145+			free(single);
146+		globfree(&g);
147 	}
148 	freestrs(&paths);
149 	return 0;
+4, -0
1@@ -0,0 +1,4 @@
2+include mk/*
3+
4+all:
5+	@echo A=$(A) B=$(B)
+1, -0
1@@ -0,0 +1 @@
2+A=one B=two
+31, -0
 1@@ -0,0 +1,31 @@
 2+{
 3+  "case": "t001",
 4+  "category": "include",
 5+  "compare_output": true,
 6+  "description": "glob include expands and loads all matching include fragments",
 7+  "details": "",
 8+  "env": {},
 9+  "expected_exit": 0,
10+  "options": "",
11+  "options_mode": "argv",
12+  "output_mode": "exact",
13+  "setup": [
14+    {
15+      "kind": "file",
16+      "mode": "0644",
17+      "mtime": 0,
18+      "path": "mk/a.mk",
19+      "content": "A=one\n"
20+    },
21+    {
22+      "kind": "file",
23+      "mode": "0644",
24+      "mtime": 0,
25+      "path": "mk/b.mk",
26+      "content": "B=two\n"
27+    }
28+  ],
29+  "stdin": "",
30+  "suite": "shin",
31+  "timeout_seconds": 60
32+}