master xplshn/aruu / cmd / dev / ninqu / query.c
  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}