master xplshn/aruu / cmd / dev / ninqu / gate.c
  1#include "ninqu.h"
  2
  3#include <stdio.h>
  4#include <stdlib.h>
  5#include <string.h>
  6
  7struct Gate *
  8gate_new(enum GKind kind)
  9{
 10  struct Gate *g = ecalloc(1, sizeof *g);
 11  g->kind        = kind;
 12  return g;
 13}
 14
 15void
 16gate_free(struct Gate *g)
 17{
 18  int i;
 19  if (!g)
 20    return;
 21  for (i = 0; i < g->nkids; i++)
 22    gate_free(g->kids[i]);
 23  free(g->kids);
 24  free(g->var);
 25  free(g);
 26}
 27
 28struct Gate *
 29gate_parse(struct SNode *expr)
 30{
 31  const char   *h;
 32  struct Gate **kids;
 33  int           i, n;
 34
 35  if (!expr)
 36    return gate_new(G_TRUE);
 37
 38  if (expr->kind == S_ATOM) {
 39    struct Gate *g = gate_new(G_VAR);
 40    g->var         = estrdup(expr->atom);
 41    return g;
 42  }
 43
 44  h = s_head(expr);
 45  if (!h)
 46    eprintf("manifest: empty () in gate\n");
 47
 48  if (strcmp(h, "not") == 0) {
 49    struct Gate *g;
 50    if (expr->nkids != 2)
 51      eprintf("manifest: (not X) takes one operand\n");
 52    g          = gate_new(G_NOT);
 53    g->kids    = emalloc(sizeof *g->kids);
 54    g->kids[0] = gate_parse(expr->kids[1]);
 55    g->nkids   = 1;
 56    return g;
 57  }
 58  if (strcmp(h, "and") == 0 || strcmp(h, "or") == 0) {
 59    struct Gate *g = gate_new(h[0] == 'a' ? G_AND : G_OR);
 60    if (expr->nkids < 2)
 61      eprintf("manifest: (%s ...) needs one operand\n", h);
 62    n    = expr->nkids - 1;
 63    kids = emalloc((size_t)n * sizeof *kids);
 64    for (i = 0; i < n; i++)
 65      kids[i] = gate_parse(expr->kids[i + 1]);
 66    g->kids  = kids;
 67    g->nkids = n;
 68    return g;
 69  }
 70  eprintf("manifest: unknown gate operator '%s'\n", h);
 71  return NULL;
 72}
 73
 74/* true if the gate contains any $(...) that needs per-instance
 75 * expansion before it can be evaluated */
 76int
 77gate_has_dyn(struct Gate *g)
 78{
 79  int i;
 80  if (!g)
 81    return 0;
 82  if (g->kind == G_VAR)
 83    return strstr(g->var, "$(") != NULL;
 84  for (i = 0; i < g->nkids; i++)
 85    if (gate_has_dyn(g->kids[i]))
 86      return 1;
 87  return 0;
 88}
 89
 90int
 91gate_eval(struct Gate *g)
 92{
 93  int i, v;
 94  if (!g)
 95    return 1;
 96  switch (g->kind) {
 97    case G_TRUE:
 98      return 1;
 99    case G_VAR: {
100      char *vraw = kv_get(g->var);
101      return vraw && *vraw && strcmp(vraw, "0") != 0;
102    }
103    case G_NOT:
104      return !gate_eval(g->kids[0]);
105    case G_AND:
106      v = 1;
107      for (i = 0; i < g->nkids; i++)
108        v = v && gate_eval(g->kids[i]);
109      return v;
110    case G_OR:
111      v = 0;
112      for (i = 0; i < g->nkids; i++)
113        v = v || gate_eval(g->kids[i]);
114      return v;
115  }
116  return 0;
117}
118
119/* expand every $(...) so a gate like build_$(BASESTEM) resolves
120 * against the active overlay before evaluation */
121struct Gate *
122gate_materialize(struct Gate *g)
123{
124  int          i;
125  struct Gate *out;
126
127  if (!g)
128    return NULL;
129  out = gate_new(g->kind);
130  if (g->var)
131    out->var = kv_expand(g->var);
132  if (g->nkids) {
133    out->kids = emalloc((size_t)g->nkids * sizeof *out->kids);
134    for (i = 0; i < g->nkids; i++)
135      out->kids[i] = gate_materialize(g->kids[i]);
136    out->nkids = g->nkids;
137  }
138  return out;
139}