commit 1c4d5c7
shrub
·
2026-05-19 19:39:17 +0000 UTC
parent c6bde0a
move include gating to preproc and parse time
6 files changed,
+84,
-60
+1,
-1
1@@ -382,7 +382,7 @@ main(int argc, char **argv)
2 {
3 int rc;
4
5- rc = parse(path, src, &ast);
6+ rc = parse(path, src, &ast, mode);
7 if (rc < 0) {
8 free(assigns);
9 free(goals);
+1,
-1
1@@ -79,7 +79,7 @@ loadimprules(struct SufRules *rules, const char *src)
2 size_t i;
3 int rc;
4
5- rc = parse("<built-in-rules>", src, &ast);
6+ rc = parse("<built-in-rules>", src, &ast, MODE_GNU);
7 if (rc < 0)
8 return -1;
9 for (i = 0; i < ast.n; i++) {
+1,
-26
1@@ -440,31 +440,6 @@ evalinclude(struct EvalCtx *ctx, const struct IncludeNode *inc)
2 memset(&paths, 0, sizeof(paths));
3 splitwords(&paths, exp, strlen(exp));
4 free(exp);
5- /* posix 2008 only allows plain includes with one file, posix 2024 allows both
6- * include and -include with multiple files, but no sinclude. */
7- if (ctx->mode == MODE_POSIX_2008) {
8- if (inc->optional) {
9- dielikemake(ctx->cur_path, ctx->cur_line,
10- "optional includes are not valid in POSIX 2008", 0);
11- ctx->errors++;
12- freestrs(&paths);
13- return 0;
14- }
15- if (paths.n != 1) {
16- dielikemake(ctx->cur_path, ctx->cur_line,
17- "include in POSIX 2008 must specify exactly one file", 0);
18- ctx->errors++;
19- freestrs(&paths);
20- return 0;
21- }
22- }
23- if (ctx->mode == MODE_POSIX_2024 && inc->sinclude) {
24- dielikemake(ctx->cur_path, ctx->cur_line,
25- "'sinclude' is not valid in POSIX 2024; use '-include'", 0);
26- ctx->errors++;
27- freestrs(&paths);
28- return 0;
29- }
30 for (i = 0; i < paths.n; i++) {
31 size_t j, nmatch;
32 char *single;
33@@ -711,7 +686,7 @@ evalsnippet(struct EvalCtx *ctx, const char *path, const char *src)
34 const char *saved_path;
35 int rc;
36
37- if (parse(path, src, &ast) < 0)
38+ if (parse(path, src, &ast, ctx->mode) < 0)
39 return -1;
40 saved_path = ctx->cur_path;
41 ctx->cur_path = path;
+2,
-2
1@@ -649,7 +649,7 @@ buildsubgraph0(struct SubGraph *sg, struct SubGraphStack *stack)
2 char *assignsrc;
3
4 assignsrc = appendassigns(xstrdup(""), &sg->assigns);
5- rc = parse("<command line>", assignsrc, &pre);
6+ rc = parse("<command line>", assignsrc, &pre, sg->mode);
7 free(assignsrc);
8 if (rc < 0)
9 goto out;
10@@ -658,7 +658,7 @@ buildsubgraph0(struct SubGraph *sg, struct SubGraphStack *stack)
11 pre.v[i].data.assign.origin = ORIGIN_COMMAND;
12 }
13 }
14- rc = parse(path, src, &ast);
15+ rc = parse(path, src, &ast, sg->mode);
16 if (rc < 0)
17 goto out;
18 rc = eval(path, &ast, sg->assigns.n ? &pre : 0, envoverride, sg->mode, &rs);
+76,
-27
1@@ -33,9 +33,12 @@ static int parseerrs;
2 static int deadlikemake;
3 static struct Arena *g_ast_arena;
4
5-static int preprocfile(const char *path, const char *src_override, struct Pre *pre, struct Inc *inc);
6+static int preprocfile(const char *path, const char *src_override, struct Pre *pre, struct Inc *inc,
7+ enum ShinMode mode);
8 static int preprocfile0(const char *path, const char *src_override, struct Pre *pre, struct Inc *inc,
9- struct SpecialTargets *targets);
10+ struct SpecialTargets *targets, enum ShinMode mode);
11+static int preprocinclude(const char *dir, const char *incarg, struct Pre *pre, struct Inc *inc,
12+ struct SpecialTargets *targets, enum ShinMode mode);
13
14 static char *
15 astdup(const char *s, size_t n)
16@@ -512,11 +515,11 @@ dirpart(const char *path)
17
18 static int
19 preprocinclude(const char *dir, const char *incarg, struct Pre *pre, struct Inc *inc,
20- struct SpecialTargets *targets)
21+ struct SpecialTargets *targets, enum ShinMode mode)
22 {
23 int rc;
24
25- rc = preprocfile0(incarg, 0, pre, inc, targets);
26+ rc = preprocfile0(incarg, 0, pre, inc, targets, mode);
27 if (rc == 0)
28 return 0;
29 if (strcmp(dir, ".") == 0)
30@@ -525,7 +528,7 @@ preprocinclude(const char *dir, const char *incarg, struct Pre *pre, struct Inc
31 char *full;
32
33 full = joinpath(dir, incarg);
34- rc = preprocfile0(full, 0, pre, inc, targets);
35+ rc = preprocfile0(full, 0, pre, inc, targets, mode);
36 free(full);
37 return rc;
38 }
39@@ -533,7 +536,7 @@ preprocinclude(const char *dir, const char *incarg, struct Pre *pre, struct Inc
40
41 static int
42 preprocfile0(const char *path, const char *src_override, struct Pre *pre, struct Inc *inc,
43- struct SpecialTargets *targets)
44+ struct SpecialTargets *targets, enum ShinMode mode)
45 {
46 char *src, *dir;
47 const char *p;
48@@ -564,15 +567,37 @@ preprocfile0(const char *path, const char *src_override, struct Pre *pre, struct
49
50 stripcomment(line.text);
51 trim = trimdup(line.text, strlen(line.text));
52- if (haskw(trim, "include") || haskw(trim, "-include")) {
53+ if (haskw(trim, "include") || haskw(trim, "-include") || haskw(trim, "sinclude")) {
54 int rc;
55 size_t kwlen;
56
57- opt = haskw(trim, "-include");
58- kwlen = haskw(trim, "-include") ? 8 : 7;
59+ opt = haskw(trim, "-include") || haskw(trim, "sinclude");
60+ if (mode == MODE_POSIX_2008 && opt) {
61+ dielikemake(path, line.line0,
62+ "optional includes are not valid in POSIX 2008", 0);
63+ free(trim);
64+ free(line.path);
65+ free(line.text);
66+ free(dir);
67+ free(src);
68+ popinc(inc);
69+ return -2;
70+ }
71+ if (mode == MODE_POSIX_2024 && haskw(trim, "sinclude")) {
72+ dielikemake(path, line.line0,
73+ "'sinclude' is not valid in POSIX 2024; use '-include'", 0);
74+ free(trim);
75+ free(line.path);
76+ free(line.text);
77+ free(dir);
78+ free(src);
79+ popinc(inc);
80+ return -2;
81+ }
82+ kwlen = (haskw(trim, "-include") || haskw(trim, "sinclude")) ? 8 : 7;
83 incarg = trimdup(trim + kwlen, strlen(trim + kwlen));
84 if (isplainpath(incarg)) {
85- rc = preprocinclude(dir, incarg, pre, inc, targets);
86+ rc = preprocinclude(dir, incarg, pre, inc, targets, mode);
87 if (rc == 0) {
88 free(incarg);
89 free(line.path);
90@@ -620,22 +645,23 @@ preprocfile0(const char *path, const char *src_override, struct Pre *pre, struct
91 }
92
93 static int
94-preprocfile(const char *path, const char *src_override, struct Pre *pre, struct Inc *inc)
95+preprocfile(const char *path, const char *src_override, struct Pre *pre, struct Inc *inc,
96+ enum ShinMode mode)
97 {
98 struct SpecialTargets targets;
99
100 initspecialtargets(&targets);
101- return preprocfile0(path, src_override, pre, inc, &targets);
102+ return preprocfile0(path, src_override, pre, inc, &targets, mode);
103 }
104
105 int
106-preproc(const char *path, struct Pre *pre)
107+preproc(const char *path, struct Pre *pre, enum ShinMode mode)
108 {
109 struct Inc inc;
110
111 memset(pre, 0, sizeof(*pre));
112 memset(&inc, 0, sizeof(inc));
113- if (preprocfile(path, 0, pre, &inc) < 0) {
114+ if (preprocfile(path, 0, pre, &inc, mode) < 0) {
115 free(inc.v);
116 freepre(pre);
117 return -1;
118@@ -659,10 +685,12 @@ freepre(struct Pre *pre)
119 }
120
121 static struct Node
122-parseinclude(const struct PreLine *line, const char *s)
123+parseinclude(const struct PreLine *line, const char *s, enum ShinMode mode)
124 {
125 struct Node state;
126 size_t off;
127+ size_t i, nwords;
128+ const char *p;
129
130 memset(&state, 0, sizeof(state));
131 state.kind = NODE_INCLUDE;
132@@ -680,6 +708,27 @@ parseinclude(const struct PreLine *line, const char *s)
133 off = strlen("include");
134 }
135 state.data.include.path = atrimdup(s + off, strlen(s + off));
136+ if (mode == MODE_POSIX_2008) {
137+ p = state.data.include.path;
138+ nwords = 0;
139+ for (i = 0; p[i];) {
140+ while (p[i] && isspace((unsigned char)p[i]))
141+ i++;
142+ if (!p[i])
143+ break;
144+ nwords++;
145+ while (p[i] && !isspace((unsigned char)p[i]))
146+ i++;
147+ }
148+ if (nwords != 1) {
149+ memset(&state, 0, sizeof(state));
150+ state.kind = NODE_BLANK;
151+ state.loc.line0 = line->line0;
152+ state.loc.line1 = line->line1;
153+ parseerr(line, "include in POSIX 2008 must specify exactly one file", 0);
154+ return state;
155+ }
156+ }
157 return state;
158 }
159
160@@ -996,7 +1045,7 @@ parsedefine(const struct Pre *pre, size_t *i, struct Node *out)
161 }
162
163 static struct Node
164-parseline(const struct PreLine *line, const struct SpecialTargets *targets)
165+parseline(const struct PreLine *line, const struct SpecialTargets *targets, enum ShinMode mode)
166 {
167 struct Node state;
168 struct AssignScan as;
169@@ -1068,7 +1117,7 @@ parseline(const struct PreLine *line, const struct SpecialTargets *targets)
170 return state;
171 }
172 if (haskw(trim, "include") || haskw(trim, "-include") || haskw(trim, "sinclude")) {
173- state = parseinclude(line, trim);
174+ state = parseinclude(line, trim, mode);
175 free(trim);
176 return state;
177 }
178@@ -1158,7 +1207,7 @@ parseline(const struct PreLine *line, const struct SpecialTargets *targets)
179
180 static int
181 parseblock(const struct Pre *pre, size_t *i, struct NodeList *out, struct Node **last_rulep,
182- struct SpecialTargets *targets)
183+ struct SpecialTargets *targets, enum ShinMode mode)
184 {
185 struct Node state;
186 struct Node *last_rule;
187@@ -1233,7 +1282,7 @@ parseblock(const struct Pre *pre, size_t *i, struct NodeList *out, struct Node *
188 state = parsecond(line, trim);
189 free(trim);
190 (*i)++;
191- if (parseblock(pre, i, &state.data.cond.thenpart, &last_rule, targets) < 0)
192+ if (parseblock(pre, i, &state.data.cond.thenpart, &last_rule, targets, mode) < 0)
193 return -1;
194 if (*i < pre->n) {
195 struct PreLine *endline;
196@@ -1253,7 +1302,7 @@ parseblock(const struct Pre *pre, size_t *i, struct NodeList *out, struct Node *
197 free(endline->text);
198 endline->text = rep;
199 free(endtrim);
200- if (parseblock(pre, i, &state.data.cond.elsepart, &last_rule, targets) < 0)
201+ if (parseblock(pre, i, &state.data.cond.elsepart, &last_rule, targets, mode) < 0)
202 return -1;
203 state.loc.line1 = endline->line1;
204 addnode(out, state);
205@@ -1263,7 +1312,7 @@ parseblock(const struct Pre *pre, size_t *i, struct NodeList *out, struct Node *
206 }
207 free(endtrim);
208 (*i)++;
209- if (parseblock(pre, i, &state.data.cond.elsepart, &last_rule, targets) < 0)
210+ if (parseblock(pre, i, &state.data.cond.elsepart, &last_rule, targets, mode) < 0)
211 return -1;
212 if (*i >= pre->n) {
213 parseerr(&pre->v[pre->n - 1], "missing 'endif'", 0);
214@@ -1296,7 +1345,7 @@ parseblock(const struct Pre *pre, size_t *i, struct NodeList *out, struct Node *
215 }
216 free(trim);
217
218- state = parseline(line, targets);
219+ state = parseline(line, targets, mode);
220 if (deadlikemake)
221 return -1;
222 if (state.kind == NODE_ASSIGN)
223@@ -1314,7 +1363,7 @@ parseblock(const struct Pre *pre, size_t *i, struct NodeList *out, struct Node *
224 }
225
226 int
227-buildast(const char *path, const struct Pre *pre, struct Ast *ast)
228+buildast(const char *path, const struct Pre *pre, struct Ast *ast, enum ShinMode mode)
229 {
230 size_t i;
231 struct SpecialTargets targets;
232@@ -1328,7 +1377,7 @@ buildast(const char *path, const struct Pre *pre, struct Ast *ast)
233 deadlikemake = 0;
234 initspecialtargets(&targets);
235 i = 0;
236- rc = parseblock(pre, &i, (struct NodeList *)ast, 0, &targets);
237+ rc = parseblock(pre, &i, (struct NodeList *)ast, 0, &targets, mode);
238 g_ast_arena = 0;
239 if (rc < 0)
240 return deadlikemake ? -2 : -1;
241@@ -1350,7 +1399,7 @@ buildast(const char *path, const struct Pre *pre, struct Ast *ast)
242
243 /* preprocess and parse */
244 int
245-parse(const char *path, const char *src, struct Ast *ast)
246+parse(const char *path, const char *src, struct Ast *ast, enum ShinMode mode)
247 {
248 struct Pre pre;
249 struct Inc inc;
250@@ -1358,13 +1407,13 @@ parse(const char *path, const char *src, struct Ast *ast)
251
252 memset(&pre, 0, sizeof(pre));
253 memset(&inc, 0, sizeof(inc));
254- rc = preprocfile(path, src, &pre, &inc);
255+ rc = preprocfile(path, src, &pre, &inc, mode);
256 free(inc.v);
257 if (rc < 0) {
258 freepre(&pre);
259 return rc;
260 }
261- rc = buildast(path, &pre, ast);
262+ rc = buildast(path, &pre, ast, mode);
263 freepre(&pre);
264 return rc;
265 }
+3,
-3
1@@ -247,11 +247,11 @@ struct SubGraph {
2 enum ShinMode mode;
3 };
4
5-int preproc(const char *path, struct Pre *pre);
6+int preproc(const char *path, struct Pre *pre, enum ShinMode mode);
7 void freepre(struct Pre *pre);
8-int buildast(const char *path, const struct Pre *pre, struct Ast *ast);
9+int buildast(const char *path, const struct Pre *pre, struct Ast *ast, enum ShinMode mode);
10 int eval(const char *path, const struct Ast *ast, const struct Ast *pre, int envoverride, enum ShinMode mode, struct RuleSet *out);
11-int parse(const char *path, const char *src, struct Ast *ast);
12+int parse(const char *path, const char *src, struct Ast *ast, enum ShinMode mode);
13 void freeast(struct Ast *ast);
14 void freeruleset(struct RuleSet *ruleset);
15 int buildgraph(const struct RuleSet *ruleset, const struct StrList *goals, struct Graph *graph, enum ShinMode mode);