1#include "ninqu.h"
2
3#include <stdio.h>
4#include <stdlib.h>
5#include <string.h>
6
7/* walk every gate tree, collect the static var names and the rules
8 * each one gates. skips $(...) vars since those are per-instance */
9static void
10collect_gate_vars(struct StrList *out, struct StrList *affects, struct StrList *rules_affected)
11{
12 int i;
13 for (i = 0; i < nrules; i++) {
14 struct Rule *r = &rules[i];
15 struct Gate *g = r->gate;
16 struct StrList seen = {0};
17 struct Gate **stack;
18 int sp = 0;
19
20 if (!g)
21 continue;
22 stack = emalloc(64 * sizeof *stack);
23 stack[sp++] = g;
24 while (sp > 0) {
25 struct Gate *cur = stack[--sp];
26 int k;
27 if (cur->kind == G_VAR) {
28 if (strstr(cur->var, "$("))
29 continue;
30 if (!sl_has(&seen, cur->var)) {
31 sl_push(&seen, cur->var);
32 if (!sl_has(out, cur->var))
33 sl_push(out, cur->var);
34 sl_push(affects, cur->var);
35 sl_push(rules_affected, r->name);
36 }
37 continue;
38 }
39 for (k = 0; k < cur->nkids; k++)
40 stack[sp++] = cur->kids[k];
41 }
42 free(stack);
43 }
44}
45
46/* (feature NAME) tags, separate from gate vars. a rule can carry
47 * more than one, so the pairing is flattened */
48static void
49collect_named_features(struct StrList *out, struct StrList *owns, struct StrList *rules_tagged)
50{
51 int i, j;
52 for (i = 0; i < nrules; i++) {
53 struct Rule *r = &rules[i];
54 for (j = 0; j < r->features.n; j++) {
55 const char *feat = r->features.v[j];
56 if (!sl_has(out, feat))
57 sl_push(out, feat);
58 sl_push(owns, feat);
59 sl_push(rules_tagged, r->name);
60 }
61 }
62}
63
64void
65do_features(void)
66{
67 struct StrList gatevars = {0}, affects = {0}, affected = {0};
68 struct StrList featnames = {0}, feat_owns = {0}, feat_rules = {0};
69 int i, j;
70
71 printf("variables (override with -Dname=value):\n");
72 for (i = 0; i < kv.n; i++)
73 printf(
74 " %s=%s%s\n",
75 kv.v[i].key,
76 kv.v[i].val,
77 sl_has(&kv_locked, kv.v[i].key) ? " [locked by -D]" : ""
78 );
79
80 collect_gate_vars(&gatevars, &affects, &affected);
81 printf("\nfeature gates (override with -Dname=0 or -Dname=1):\n");
82 for (i = 0; i < gatevars.n; i++) {
83 printf(" %s=%s\n", gatevars.v[i], kv_get_or(gatevars.v[i], ""));
84 for (j = 0; j < affects.n; j++)
85 if (strcmp(affects.v[j], gatevars.v[i]) == 0)
86 printf(" gates rule: %s\n", affected.v[j]);
87 }
88
89 collect_named_features(&featnames, &feat_owns, &feat_rules);
90 if (featnames.n > 0) {
91 printf("\nnamed features (declared with (feature NAME)):\n");
92 for (i = 0; i < featnames.n; i++) {
93 printf(" %s\n", featnames.v[i]);
94 for (j = 0; j < feat_owns.n; j++)
95 if (strcmp(feat_owns.v[j], featnames.v[i]) == 0)
96 printf(" rule: %s\n", feat_rules.v[j]);
97 }
98 }
99
100 printf("\ngroups:\n");
101 for (i = 0; i < ngroups; i++)
102 printf(" %s\n", groups[i].name);
103
104 printf("\nrules:\n");
105 for (i = 0; i < nrules; i++) {
106 struct Rule *r = &rules[i];
107 printf(" %s%s\n", r->name, r->globs.n > 0 ? " (pattern rule)" : "");
108 if (r->description[0])
109 printf(" # %s\n", r->description);
110 if (r->group_name[0])
111 printf(" group: %s\n", r->group_name);
112 if (r->member_of[0])
113 printf(" member: %s/%s\n", r->member_of, r->member_alias[0] ? r->member_alias : r->name);
114 for (j = 0; j < r->features.n; j++)
115 printf(" feature: %s\n", r->features.v[j]);
116 }
117}
118
119void
120do_query(const char *sub, const char *arg)
121{
122 int i, j;
123
124 if (strcmp(sub, "features") == 0) {
125 do_features();
126 return;
127 }
128 if (strcmp(sub, "groups") == 0) {
129 for (i = 0; i < ngroups; i++) {
130 printf("%s\n", groups[i].name);
131 for (j = 0; j < groups[i].refs.n; j++)
132 printf(" %s\n", groups[i].refs.v[j]);
133 }
134 return;
135 }
136 if (strcmp(sub, "metas") == 0) {
137 for (i = 0; i < nmetas; i++) {
138 printf("%s\n", metas[i].name);
139 for (j = 0; j < metas[i].keys.n; j++)
140 printf(" %s=%s\n", metas[i].keys.v[j], metas[i].vals.v[j]);
141 }
142 return;
143 }
144 if (strcmp(sub, "rules") == 0) {
145 for (i = 0; i < nrules; i++) {
146 printf("%s", rules[i].name);
147 if (rules[i].globs.n > 0) {
148 printf(" glob:");
149 for (j = 0; j < rules[i].globs.n; j++)
150 printf(" %s", rules[i].globs.v[j]);
151 }
152 if (rules[i].produces[0])
153 printf(" produces=%s", rules[i].produces);
154 if (rules[i].group_name[0])
155 printf(" group=%s", rules[i].group_name);
156 if (rules[i].member_of[0])
157 printf(
158 " member=%s/%s",
159 rules[i].member_of,
160 rules[i].member_alias[0] ? rules[i].member_alias : rules[i].name
161 );
162 for (j = 0; j < rules[i].features.n; j++)
163 printf(" feature=%s", rules[i].features.v[j]);
164 if (rules[i].description[0])
165 printf(" # %s", rules[i].description);
166 printf("\n");
167 }
168 return;
169 }
170 if (strcmp(sub, "graph") == 0) {
171 printf("digraph ninqu {\n");
172 if (arg) {
173 struct Group *g = group_find(arg);
174 if (!g)
175 eprintf("query graph: no such group '%s'\n", arg);
176 for (i = 0; i < g->refs.n; i++) {
177 struct Rule *r = rule_find(g->refs.v[i]);
178 if (!r)
179 continue;
180 for (j = 0; j < r->in.n; j++)
181 if (r->in.v[j][0] == '@')
182 printf(" \"%s\" -> \"%s\";\n", r->in.v[j] + 1, r->name);
183 for (j = 0; j < r->extra_deps.n; j++)
184 if (r->extra_deps.v[j][0] == '@')
185 printf(" \"%s\" -> \"%s\" [style=dashed];\n", r->extra_deps.v[j] + 1, r->name);
186 }
187 } else {
188 for (i = 0; i < nrules; i++) {
189 for (j = 0; j < rules[i].in.n; j++)
190 if (rules[i].in.v[j][0] == '@')
191 printf(" \"%s\" -> \"%s\";\n", rules[i].in.v[j] + 1, rules[i].name);
192 for (j = 0; j < rules[i].extra_deps.n; j++)
193 if (rules[i].extra_deps.v[j][0] == '@')
194 printf(
195 " \"%s\" -> \"%s\" [style=dashed];\n", rules[i].extra_deps.v[j] + 1, rules[i].name
196 );
197 }
198 }
199 printf("}\n");
200 return;
201 }
202 eprintf("query: unknown subcommand '%s' (try features, groups, metas, rules, graph)\n", sub);
203}