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+}