1#include "ninqu.h"
2
3#include <ctype.h>
4#include <limits.h>
5#include <stdio.h>
6#include <stdlib.h>
7#include <string.h>
8
9struct StrList files_read;
10
11/* second child must be an atom, more children may follow */
12const char *
13first_atom(struct SNode *node, const char *msg)
14{
15 if (node->nkids < 2 || node->kids[1]->kind != S_ATOM)
16 eprintf("manifest: %s\n", msg);
17 return node->kids[1]->atom;
18}
19
20/* second child must be the only other child, and an atom */
21const char *
22sole_atom(struct SNode *node, const char *msg)
23{
24 if (node->nkids != 2 || node->kids[1]->kind != S_ATOM)
25 eprintf("manifest: %s\n", msg);
26 return node->kids[1]->atom;
27}
28
29/* a dep operand is a bare atom, a (rule NAME) stored as @NAME, or
30 * an (after X...) whose operands are order-only */
31static void
32parse_dep_item(struct SNode *item, struct StrList *hard, struct StrList *ord, int allow_after)
33{
34 const char *h;
35
36 if (item->kind == S_ATOM) {
37 sl_push(hard, item->atom);
38 return;
39 }
40 h = s_head(item);
41 if (!h)
42 eprintf("manifest: empty () in dep\n");
43 if (strcmp(h, "rule") == 0) {
44 char buf[256];
45 snprintf(buf, sizeof buf, "@%s", sole_atom(item, "(rule NAME) takes one name"));
46 sl_push(hard, buf);
47 return;
48 }
49 if (strcmp(h, "after") == 0) {
50 int i;
51 if (!allow_after)
52 eprintf("manifest: (after ...) not allowed here\n");
53 for (i = 1; i < item->nkids; i++)
54 parse_dep_item(item->kids[i], ord, ord, 0);
55 return;
56 }
57 eprintf("manifest: unknown dep operand '%s'\n", h);
58}
59
60static void
61parse_dep_clause(struct SNode *clause, struct StrList *hard, struct StrList *ord)
62{
63 int i;
64 for (i = 1; i < clause->nkids; i++)
65 parse_dep_item(clause->kids[i], hard, ord, 1);
66}
67
68void
69parse_exec_clause(struct SNode *clause, struct Cmd *cmd)
70{
71 int i;
72 memset(cmd, 0, sizeof *cmd);
73 for (i = 1; i < clause->nkids; i++) {
74 if (clause->kids[i]->kind != S_ATOM)
75 eprintf("manifest: (exec ...) operands must be atoms\n");
76 sl_push(&cmd->argv, clause->kids[i]->atom);
77 }
78 if (cmd->argv.n == 0)
79 eprintf("manifest: (exec ...) needs one operand\n");
80}
81
82/* desugar to (exec sh -c STR). sh is the posix shell, overridable
83 * by writing (exec ...) directly */
84void
85parse_shell_clause(struct SNode *clause, struct Cmd *cmd)
86{
87 memset(cmd, 0, sizeof *cmd);
88 sl_push(&cmd->argv, "sh");
89 sl_push(&cmd->argv, "-c");
90 sl_push(&cmd->argv, sole_atom(clause, "(shell \"...\") takes one string"));
91}
92
93static void
94parse_pipe_stage(struct SNode *stage, struct StrList *argv)
95{
96 const char *h = s_head(stage);
97 int j;
98
99 if (!h)
100 eprintf("manifest: (pipe ...) stage must be a form\n");
101 if (strcmp(h, "exec") == 0) {
102 for (j = 1; j < stage->nkids; j++) {
103 if (stage->kids[j]->kind != S_ATOM)
104 eprintf("manifest: (exec ...) operands must be atoms\n");
105 sl_push(argv, stage->kids[j]->atom);
106 }
107 } else if (strcmp(h, "shell") == 0) {
108 sl_push(argv, "sh");
109 sl_push(argv, "-c");
110 sl_push(argv, sole_atom(stage, "(shell \"...\") takes one string"));
111 } else {
112 eprintf("manifest: (pipe) stage must be exec or shell, got '%s'\n", h);
113 }
114 if (argv->n == 0)
115 eprintf("manifest: (pipe) stage cannot be empty\n");
116}
117
118void
119parse_pipe_clause(struct SNode *clause, struct Cmd *cmd)
120{
121 int i, j;
122 memset(cmd, 0, sizeof *cmd);
123 cmd->is_pipe = 1;
124 for (i = 1; i < clause->nkids; i++) {
125 struct StrList argv = {0};
126 struct StrList *slot;
127
128 parse_pipe_stage(clause->kids[i], &argv);
129
130 slot = emalloc(sizeof *slot);
131 memset(slot, 0, sizeof *slot);
132 for (j = 0; j < argv.n; j++)
133 sl_push(slot, argv.v[j]);
134 if (cmd->nstages == 0)
135 cmd->stages = emalloc(8 * sizeof *cmd->stages);
136 else if (cmd->nstages >= 8)
137 cmd->stages = erealloc(cmd->stages, (size_t)cmd->nstages * 2 * sizeof *cmd->stages);
138 cmd->stages[cmd->nstages++] = slot;
139 }
140 if (cmd->nstages < 2)
141 eprintf("manifest: (pipe ...) needs two stages\n");
142 for (i = 0; i < cmd->nstages; i++) {
143 char *joined = sl_join(cmd->stages[i]);
144 if (i > 0)
145 sl_push(&cmd->argv, "|");
146 sl_push(&cmd->argv, joined);
147 free(joined);
148 }
149}
150
151static void apply_rule_clause(struct Rule *r, const char *name, struct SNode *clause);
152
153static void
154process_rule_body(struct Rule *r, const char *name, struct SNode *form, int start)
155{
156 int i;
157 for (i = start; i < form->nkids; i++)
158 apply_rule_clause(r, name, form->kids[i]);
159}
160
161/* (if EXPR clause...) splices its clauses in when EXPR is true.
162 * reuses the gate grammar so there is one condition language.
163 * a $(...) in the condition is rejected: splicing per glob match
164 * would mean deferring cmd/dep construction, which no rule needs.
165 * use (gate ...) on a separate rule for a per-instance condition */
166static void
167apply_if_clause(struct Rule *r, const char *name, struct SNode *clause)
168{
169 struct Gate *cond;
170
171 if (clause->nkids < 2)
172 eprintf("manifest: rule %s: (if EXPR clause...) needs a condition\n", name);
173 cond = gate_parse(clause->kids[1]);
174 if (gate_has_dyn(cond))
175 eprintf(
176 "manifest: rule %s: (if ...) condition cannot reference $(...), "
177 "only (gate ...) on the whole rule supports a per-instance condition\n",
178 name
179 );
180 if (gate_eval(cond))
181 process_rule_body(r, name, clause, 2);
182 gate_free(cond);
183}
184
185static void
186apply_rule_clause(struct Rule *r, const char *name, struct SNode *clause)
187{
188 const char *h = s_head(clause);
189 if (!h)
190 eprintf("manifest: rule %s: empty () clause\n", name);
191
192 if (strcmp(h, "if") == 0) {
193 apply_if_clause(r, name, clause);
194 } else if (strcmp(h, "glob") == 0) {
195 int j;
196 for (j = 1; j < clause->nkids; j++) {
197 if (clause->kids[j]->kind != S_ATOM)
198 eprintf("manifest: (glob ...) operands must be atoms\n");
199 sl_push(&r->globs, clause->kids[j]->atom);
200 }
201 } else if (strcmp(h, "skip") == 0) {
202 int j;
203 for (j = 1; j < clause->nkids; j++) {
204 if (clause->kids[j]->kind != S_ATOM)
205 eprintf("manifest: (skip ...) operands must be atoms\n");
206 sl_push(&r->skip, clause->kids[j]->atom);
207 }
208 } else if (strcmp(h, "mark") == 0) {
209 strlcpy(
210 r->require_marker,
211 sole_atom(clause, "(mark STR) takes one string"),
212 sizeof r->require_marker
213 );
214 } else if (strcmp(h, "req") == 0) {
215 strlcpy(
216 r->require_file, sole_atom(clause, "(req PATH) takes one path"), sizeof r->require_file
217 );
218 } else if (strcmp(h, "gate") == 0) {
219 if (clause->nkids != 2)
220 eprintf("manifest: (gate EXPR) takes one expression\n");
221 r->gate = gate_parse(clause->kids[1]);
222 } else if (strcmp(h, "dep") == 0) {
223 parse_dep_clause(clause, &r->in, &r->extra_deps);
224 } else if (strcmp(h, "after") == 0) {
225 parse_dep_clause(clause, &r->extra_deps, &r->extra_deps);
226 } else if (strcmp(h, "out") == 0) {
227 strlcpy(r->out, sole_atom(clause, "(out TEMPLATE) takes one template"), sizeof r->out);
228 } else if (strcmp(h, "exec") == 0) {
229 parse_exec_clause(clause, &r->cmd);
230 } else if (strcmp(h, "shell") == 0) {
231 parse_shell_clause(clause, &r->cmd);
232 } else if (strcmp(h, "pipe") == 0) {
233 parse_pipe_clause(clause, &r->cmd);
234 } else if (strcmp(h, "dir") == 0) {
235 strlcpy(r->workdir, sole_atom(clause, "(dir PATH) takes one path"), sizeof r->workdir);
236 } else if (strcmp(h, "phony") == 0) {
237 r->phony = 1;
238 } else if (strcmp(h, "redirect") == 0) {
239 r->redirect = 1;
240 } else if (strcmp(h, "produces") == 0) {
241 strlcpy(r->produces, sole_atom(clause, "(produces NAME) takes one name"), sizeof r->produces);
242 } else if (strcmp(h, "description") == 0) {
243 strlcpy(
244 r->description,
245 sole_atom(clause, "(description STR) takes one string"),
246 sizeof r->description
247 );
248 } else if (strcmp(h, "group") == 0) {
249 /* display-only: shows up in (query rules) output, no effect on
250 * resolution. (member ...) below is the enforcing one. the two
251 * are separate because several rules used (group ...) this way
252 * before namespacing existed */
253 strlcpy(r->group_name, sole_atom(clause, "(group NAME) takes one name"), sizeof r->group_name);
254 } else if (strcmp(h, "member") == 0) {
255 /* (member GROUP [ALIAS]) hides the bare name from the command
256 * line. ALIAS defaults to the rule own name */
257 if (clause->nkids < 2 || clause->nkids > 3 || clause->kids[1]->kind != S_ATOM)
258 eprintf("manifest: rule %s: (member GROUP [ALIAS]) needs a group name\n", name);
259 strlcpy(r->member_of, clause->kids[1]->atom, sizeof r->member_of);
260 if (clause->nkids == 3) {
261 if (clause->kids[2]->kind != S_ATOM)
262 eprintf("manifest: rule %s: (member GROUP ALIAS) alias must be an atom\n", name);
263 strlcpy(r->member_alias, clause->kids[2]->atom, sizeof r->member_alias);
264 }
265 } else if (strcmp(h, "feature") == 0) {
266 sl_push(&r->features, sole_atom(clause, "(feature NAME) takes one name"));
267 } else {
268 eprintf("manifest: rule %s: unknown clause '%s'\n", name, h);
269 }
270}
271
272static void
273parse_rule(struct SNode *form)
274{
275 struct Rule *r;
276 const char *name;
277
278 name = first_atom(form, "(rule NAME ...) needs a name");
279 r = rule_new(name);
280 process_rule_body(r, name, form, 2);
281}
282
283static void
284parse_group(struct SNode *form)
285{
286 struct Group *g;
287 int i;
288 const char *name;
289
290 name = first_atom(form, "(group NAME ...) needs a name");
291 g = group_new(name);
292
293 for (i = 2; i < form->nkids; i++) {
294 struct SNode *ref = form->kids[i];
295 const char *h;
296
297 if (ref->kind == S_ATOM) {
298 sl_push(&g->refs, ref->atom);
299 continue;
300 }
301 h = s_head(ref);
302 if (!h)
303 eprintf("manifest: group %s: empty () ref\n", name);
304 if ((strcmp(h, "rule") == 0 || strcmp(h, "group") == 0) && ref->nkids == 2
305 && ref->kids[1]->kind == S_ATOM) {
306 sl_push(&g->refs, ref->kids[1]->atom);
307 continue;
308 }
309 eprintf("manifest: group %s: unknown ref '%s'\n", name, h);
310 }
311}
312
313/* stores K/V verbatim, unexpanded. expansion happens in meta_apply
314 * at target-resolution time, so a value picks up whatever its vars
315 * hold then, not what they held at load time */
316static void
317parse_meta(struct SNode *form)
318{
319 struct Meta *m;
320 int i;
321 const char *name;
322
323 name = first_atom(form, "(meta NAME ...) needs a name");
324 m = meta_new(name);
325
326 for (i = 2; i < form->nkids; i++) {
327 struct SNode *clause = form->kids[i];
328 const char *h = s_head(clause);
329 if (!h || strcmp(h, "set") != 0)
330 eprintf("manifest: meta %s: only (set NAME VAL) clauses are allowed\n", name);
331 if (clause->nkids != 3 || clause->kids[1]->kind != S_ATOM || clause->kids[2]->kind != S_ATOM)
332 eprintf("manifest: meta %s: (set NAME VAL) needs a name and an atom value\n", name);
333 sl_push(&m->keys, clause->kids[1]->atom);
334 sl_push(&m->vals, clause->kids[2]->atom);
335 }
336}
337
338void
339meta_apply(struct Meta *m)
340{
341 int i;
342 for (i = 0; i < m->keys.n; i++) {
343 char *exp = kv_expand(m->vals.v[i]);
344 kv_set_manifest(m->keys.v[i], exp);
345 free(exp);
346 }
347}
348
349static void
350parse_set(struct SNode *form)
351{
352 char buf[8192];
353
354 first_atom(form, "(set NAME VAL) needs a name");
355 if (form->nkids != 3)
356 eprintf("manifest: (set NAME VAL) takes one value\n");
357
358 if (form->kids[2]->kind == S_LIST) {
359 const char *h = s_head(form->kids[2]);
360 if (h && strcmp(h, "capture") == 0) {
361 struct SNode *cap = form->kids[2];
362 struct Cmd cmd;
363 char *out;
364
365 if (cap->nkids != 2)
366 eprintf("manifest: (capture (exec ...)) takes one form\n");
367 h = s_head(cap->kids[1]);
368 if (!h)
369 eprintf("manifest: capture operand must be a form\n");
370 if (strcmp(h, "exec") == 0)
371 parse_exec_clause(cap->kids[1], &cmd);
372 else if (strcmp(h, "shell") == 0)
373 parse_shell_clause(cap->kids[1], &cmd);
374 else
375 eprintf("manifest: capture operand must be exec or shell\n");
376 out = capture_argv(&cmd.argv);
377 strlcpy(buf, out, sizeof buf);
378 free(out);
379 kv_set_manifest(form->kids[1]->atom, buf);
380 return;
381 }
382 eprintf("manifest: (set NAME VAL): value must be atom or (capture ...)\n");
383 }
384 kv_set_manifest(form->kids[1]->atom, form->kids[2]->atom);
385}
386
387/* (list) and (append) keep a space-joined string in the kv store.
388 * a $(NAME) alone in a command splits back into argv entries */
389static void
390parse_list_or_append(struct SNode *form, int append)
391{
392 const char *name;
393 char buf[8192];
394 char msg[64];
395 size_t len = 0;
396 int i;
397 char *prev;
398
399 snprintf(msg, sizeof msg, "(%s NAME tok...) needs a name", form->kids[0]->atom);
400 name = first_atom(form, msg);
401 buf[0] = '\0';
402
403 if (append) {
404 prev = kv_get(name);
405 if (prev)
406 len = strlcpy(buf, prev, sizeof buf);
407 }
408 for (i = 2; i < form->nkids; i++) {
409 struct SNode *tok = form->kids[i];
410 char *exp;
411 if (tok->kind != S_ATOM)
412 eprintf("manifest: (%s NAME tok...): tokens must be atoms\n", form->kids[0]->atom);
413 if (len > 0 && len + 1 < sizeof buf)
414 buf[len++] = ' ';
415 exp = kv_expand(tok->atom);
416 len += strlcpy(buf + len, exp, sizeof buf - len);
417 free(exp);
418 }
419 kv_set_manifest(name, buf);
420}
421
422static void
423parse_map(struct SNode *form)
424{
425 struct Map *m;
426 int i;
427 const char *name;
428
429 name = first_atom(form, "(map NAME (k v)...) needs a name");
430 m = map_find(name);
431 if (!m)
432 m = map_new(name);
433
434 for (i = 2; i < form->nkids; i++) {
435 struct SNode *pair = form->kids[i];
436 if (!s_is_list(pair) || pair->nkids != 2 || pair->kids[0]->kind != S_ATOM
437 || pair->kids[1]->kind != S_ATOM)
438 eprintf("manifest: (map %s ...) entries must be (key value)\n", name);
439 kv_set_raw(&m->entries, pair->kids[0]->atom, pair->kids[1]->atom);
440 }
441}
442
443static void
444parse_import(struct SNode *form)
445{
446 char rp[PATH_MAX];
447 const char *path;
448
449 path = sole_atom(form, "(import PATH) takes one path");
450
451 if (realpath(path, rp) && sl_has(&files_read, rp))
452 return;
453
454 materialize_if_missing(path);
455 if (!file_exists(path))
456 eprintf("manifest: (import %s): missing and no rule produces it\n", path);
457 load_file(path);
458}
459
460static void
461parse_set_file(struct SNode *form)
462{
463 const char *path;
464 FILE *fp;
465 char line[8192];
466 char rp[PATH_MAX];
467
468 path = sole_atom(form, "(set-file PATH) takes one path");
469
470 materialize_if_missing(path);
471 if (!file_exists(path))
472 eprintf("manifest: (set-file %s): missing and no rule produces it\n", path);
473
474 fp = fopen(path, "r");
475 if (!fp)
476 eprintf("manifest: (set-file %s):", path);
477 if (realpath(path, rp))
478 sl_push(&files_read, rp);
479
480 while (fgets(line, sizeof line, fp)) {
481 char *s = line, *eq, *end;
482 while (isspace((unsigned char)*s))
483 s++;
484 if (*s == '\0' || *s == '#')
485 continue;
486 eq = strchr(s, '=');
487 if (!eq)
488 continue;
489 *eq = '\0';
490 end = eq - 1;
491 while (end > s && isspace((unsigned char)*end))
492 *end-- = '\0';
493 eq++;
494 while (isspace((unsigned char)*eq))
495 eq++;
496 end = eq + strlen(eq);
497 while (end > eq && (isspace((unsigned char)end[-1]) || end[-1] == '\n'))
498 *--end = '\0';
499 kv_set_manifest(s, eq);
500 }
501 fclose(fp);
502}
503
504/* (template NAME (PARAM...) FORM...): the body is cloned so it stays
505 * valid regardless of when or how many times (use ...) instantiates
506 * it */
507static void
508parse_template(struct SNode *form)
509{
510 struct Template *t;
511 struct SNode *params;
512 const char *name;
513 int i;
514
515 name = first_atom(form, "(template NAME (PARAM...) FORM...) needs a name");
516 if (form->nkids < 3 || form->kids[2]->kind != S_LIST)
517 eprintf("manifest: template %s: needs a (PARAM...) list\n", name);
518 params = form->kids[2];
519
520 t = template_new(name);
521 for (i = 0; i < params->nkids; i++) {
522 if (params->kids[i]->kind != S_ATOM)
523 eprintf("manifest: template %s: param names must be atoms\n", name);
524 sl_push(&t->params, params->kids[i]->atom);
525 }
526 t->body = snode_list(form->line);
527 for (i = 3; i < form->nkids; i++)
528 snode_push(t->body, snode_clone(form->kids[i]));
529}
530
531/* clone the template body, substitute each $(PARAM), then dispatch
532 * every substituted form as a normal top-level form */
533static void
534parse_use(struct SNode *form)
535{
536 struct Template *t;
537 struct SNode *clone;
538 const char *name;
539 char **vals;
540 int i, nargs;
541
542 name = first_atom(form, "(use NAME arg...) needs a name");
543 t = template_find(name);
544 if (!t)
545 eprintf("manifest: (use %s ...): no such template\n", name);
546
547 nargs = form->nkids - 2;
548 if (nargs != t->params.n)
549 eprintf("manifest: (use %s ...): takes %d argument(s), got %d\n", name, t->params.n, nargs);
550
551 vals = emalloc((size_t)(nargs ? nargs : 1) * sizeof *vals);
552 for (i = 0; i < nargs; i++) {
553 if (form->kids[i + 2]->kind != S_ATOM)
554 eprintf("manifest: (use %s ...): arguments must be atoms\n", name);
555 vals[i] = form->kids[i + 2]->atom;
556 }
557
558 clone = snode_clone(t->body);
559 snode_subst(clone, &t->params, vals);
560 for (i = 0; i < clone->nkids; i++)
561 dispatch_top_form(clone->kids[i]);
562 snode_free(clone);
563 free(vals);
564}
565
566void
567dispatch_top_form(struct SNode *form)
568{
569 const char *h = s_head(form);
570 if (!h)
571 eprintf("manifest: top-level form has no head\n");
572 if (strcmp(h, "set") == 0)
573 parse_set(form);
574 else if (strcmp(h, "list") == 0)
575 parse_list_or_append(form, 0);
576 else if (strcmp(h, "append") == 0)
577 parse_list_or_append(form, 1);
578 else if (strcmp(h, "map") == 0)
579 parse_map(form);
580 else if (strcmp(h, "rule") == 0)
581 parse_rule(form);
582 else if (strcmp(h, "group") == 0)
583 parse_group(form);
584 else if (strcmp(h, "meta") == 0)
585 parse_meta(form);
586 else if (strcmp(h, "import") == 0)
587 parse_import(form);
588 else if (strcmp(h, "set-file") == 0)
589 parse_set_file(form);
590 else if (strcmp(h, "template") == 0)
591 parse_template(form);
592 else if (strcmp(h, "use") == 0)
593 parse_use(form);
594 else
595 eprintf("manifest: unknown top-level form '%s'\n", h);
596}
597
598void
599load_manifest(struct SNode *root)
600{
601 int i;
602 for (i = 0; i < root->nkids; i++)
603 dispatch_top_form(root->kids[i]);
604}
605
606void
607load_file(const char *path)
608{
609 FILE *fp;
610 char *buf;
611 size_t cap, len;
612 char rp[PATH_MAX];
613 struct SLex lx;
614 struct SNode *root;
615
616 if (realpath(path, rp)) {
617 if (sl_has(&files_read, rp))
618 return;
619 sl_push(&files_read, rp);
620 }
621
622 fp = fopen(path, "r");
623 if (!fp)
624 eprintf("cannot open manifest %s:", path);
625
626 cap = 65536;
627 len = 0;
628 buf = emalloc(cap);
629 for (;;) {
630 size_t n;
631 if (len + 65536 > cap) {
632 cap *= 2;
633 buf = erealloc(buf, cap);
634 }
635 n = fread(buf + len, 1, cap - len - 1, fp);
636 len += n;
637 if (n == 0)
638 break;
639 }
640 buf[len] = '\0';
641 fclose(fp);
642
643 lx.src = buf;
644 lx.pos = 0;
645 lx.line = 1;
646 root = snode_parse(&lx);
647 free(buf);
648 load_manifest(root);
649 snode_free(root);
650}