database.c 7.07 KB
Newer Older
1
2
3
4
5
6
7
8
9
#include "defs.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>

typedef struct {
  char *name;
  char *desc;
Cedric Roux's avatar
Cedric Roux committed
10
11
  char **groups;
  int size;
Cedric Roux's avatar
Cedric Roux committed
12
  int id;
13
14
15
16
17
18
19
20
21
} id;

typedef struct {
  char *name;
  char **ids;
  int size;
} group;

typedef struct {
Cedric Roux's avatar
Cedric Roux committed
22
  char *name;
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
  id *i;
  int isize;
  group *g;
  int gsize;
} database;

typedef struct {
  char *data;
  int size;
  int maxsize;
} buffer;

typedef struct {
  buffer name;
  buffer value;
} parser;

void put(buffer *b, int c)
{
  if (b->size == b->maxsize) {
    b->maxsize += 256;
    b->data = realloc(b->data, b->maxsize);
    if (b->data == NULL) { printf("memory allocation error\n"); exit(1); }
  }
  b->data[b->size] = c;
  b->size++;
}

void smash_spaces(FILE *f)
{
  int c;
  while (1) {
    c = fgetc(f);
    if (isspace(c)) continue;
    if (c == ' ') continue;
    if (c == '\t') continue;
    if (c == '\n') continue;
    if (c == 10 || c == 13) continue;
    if (c == '#') {
      while (1) {
        c = fgetc(f);
        if (c == '\n' || c == EOF) break;
      }
      continue;
    }
    break;
  }
  if (c != EOF) ungetc(c, f);
}

void get_line(parser *p, FILE *f, char **name, char **value)
{
  int c;
  p->name.size = 0;
  p->value.size = 0;
  *name = NULL;
  *value = NULL;
  smash_spaces(f);
  c = fgetc(f);
  while (!(c == '=' || isspace(c) || c == EOF))
    { put(&p->name, c); c = fgetc(f); }
  if (c == EOF) return;
  put(&p->name, 0);
  while (!(c == EOF || c == '=')) c = fgetc(f);
  if (c == EOF) return;
  smash_spaces(f);
  c = fgetc(f);
  while (!(c == 10 || c == 13 || c == EOF))
    { put(&p->value, c); c = fgetc(f); }
  put(&p->value, 0);
  if (p->name.size <= 1) return;
  if (p->value.size <= 1) return;
  *name = p->name.data;
  *value = p->value.data;
}

Cedric Roux's avatar
Cedric Roux committed
99
100
101
102
103
104
105
106
int group_cmp(const void *_p1, const void *_p2)
{
  const group *p1 = _p1;
  const group *p2 = _p2;
  return strcmp(p1->name, p2->name);
}

int id_cmp(const void *_p1, const void *_p2)
107
{
Cedric Roux's avatar
Cedric Roux committed
108
109
110
111
112
113
114
115
116
117
118
119
  const id *p1 = _p1;
  const id *p2 = _p2;
  return strcmp(p1->name, p2->name);
}

int string_cmp(const void *_p1, const void *_p2)
{
  char * const *p1 = _p1;
  char * const *p2 = _p2;
  return strcmp(*p1, *p2);
}

Cedric Roux's avatar
Cedric Roux committed
120
id *add_id(database *r, char *idname, int i)
Cedric Roux's avatar
Cedric Roux committed
121
122
123
{
  if (bsearch(&(id){name:idname}, r->i, r->isize, sizeof(id), id_cmp) != NULL)
    { printf("ERROR: ID '%s' declared more than once\n", idname); exit(1); }
124
125
126
127
  if ((r->isize & 1023) == 0) {
    r->i = realloc(r->i, (r->isize + 1024) * sizeof(id));
    if (r->i == NULL) { printf("out of memory\n"); exit(1); }
  }
Cedric Roux's avatar
Cedric Roux committed
128
  r->i[r->isize].name = strdup(idname);
129
  if (r->i[r->isize].name == NULL) { printf("out of memory\n"); exit(1); }
Cedric Roux's avatar
Cedric Roux committed
130
131
132
  r->i[r->isize].desc = NULL;
  r->i[r->isize].groups = NULL;
  r->i[r->isize].size = 0;
Cedric Roux's avatar
Cedric Roux committed
133
  r->i[r->isize].id = i;
134
  r->isize++;
Cedric Roux's avatar
Cedric Roux committed
135
136
  qsort(r->i, r->isize, sizeof(id), id_cmp);
  return (id*)bsearch(&(id){name:idname}, r->i, r->isize, sizeof(id), id_cmp);
137
138
139
140
141
142
}

group *get_group(database *r, char *group_name)
{
  group *ret;

Cedric Roux's avatar
Cedric Roux committed
143
144
  ret = bsearch(&(group){name:group_name},
                r->g, r->gsize, sizeof(group), group_cmp);
145
146
147
148
149
150
151
152
153
154
155
156
157
158
  if (ret != NULL) return ret;

  if ((r->gsize & 1023) == 0) {
    r->g = realloc(r->g, (r->gsize + 1024) * sizeof(group));
    if (r->g == NULL) abort();
  }
  r->g[r->gsize].name = strdup(group_name);
  if (r->g[r->gsize].name == NULL) abort();
  r->g[r->gsize].ids = NULL;
  r->g[r->gsize].size = 0;
  r->gsize++;

  qsort(r->g, r->gsize, sizeof(group), group_cmp);

Cedric Roux's avatar
Cedric Roux committed
159
160
  return bsearch(&(group){name:group_name},
                 r->g, r->gsize, sizeof(group), group_cmp);
161
162
163
164
165
166
167
168
169
170
171
172
}

void group_add_id(group *g, char *id)
{
  if ((g->size & 1023) == 0) {
    g->ids = realloc(g->ids, (g->size + 1024) * sizeof(char *));
    if (g->ids == NULL) abort();
  }
  g->ids[g->size] = id;
  g->size++;
}

Cedric Roux's avatar
Cedric Roux committed
173
void id_add_group(id *i, char *group)
174
{
Cedric Roux's avatar
Cedric Roux committed
175
176
177
178
179
180
181
182
183
184
185
  char *g = bsearch(&group, i->groups, i->size, sizeof(char *), string_cmp);
  if (g != NULL) return;

  if ((i->size & 1023) == 0) {
    i->groups = realloc(i->groups, (i->size+1024) * sizeof(char *));
    if (i->groups == NULL) abort();
  }
  i->groups[i->size] = group;
  i->size++;
  qsort(i->groups, i->size, sizeof(char *), string_cmp);
}
186

Cedric Roux's avatar
Cedric Roux committed
187
188
189
190
void add_groups(database *r, id *i, char *groups)
{
  group *g;
  if (i == NULL) {printf("ERROR: GROUP line before ID line\n");exit(1);}
191
192
193
194
195
196
197
198
199
200
201
  while (1) {
    char *start = groups;
    char *end = start;
    while (!isspace(*end) && *end != ':' && *end != 0) end++;
    if (end == start) {
      printf("bad group line: groups are seperated by ':'\n");
      abort();
    }
    if (*end == 0) end = NULL; else *end = 0;

    g = get_group(r, start);
Cedric Roux's avatar
Cedric Roux committed
202
203
    group_add_id(g, i->name);
    id_add_group(i, g->name);
204
205
206
207
208
209
210
211
212

    if (end == NULL) break;
    end++;
    while ((isspace(*end) || *end == ':') && *end != 0) end++;
    if (*end == 0) break;
    groups = end;
  }
}

Cedric Roux's avatar
Cedric Roux committed
213
214
215
216
217
218
void add_desc(id *i, char *desc)
{
  if (i == NULL) {printf("ERROR: DESC line before ID line\n");exit(1);}
  i->desc = strdup(desc); if (i->desc == NULL) abort();
}

219
220
221
222
223
224
void *parse_database(char *filename)
{
  FILE *in;
  parser p;
  database *r;
  char *name, *value;
Cedric Roux's avatar
Cedric Roux committed
225
  id *last_id = NULL;
Cedric Roux's avatar
Cedric Roux committed
226
  int i;
227
228
229
230

  r = calloc(1, sizeof(*r)); if (r == NULL) abort();
  memset(&p, 0, sizeof(p));

Cedric Roux's avatar
Cedric Roux committed
231
232
  r->name = strdup(filename); if (r->name == NULL) abort();

233
234
  in = fopen(filename, "r"); if (in == NULL) { perror(filename); abort(); }

Cedric Roux's avatar
Cedric Roux committed
235
236
  i = 0;

237
238
239
  while (1) {
    get_line(&p, in, &name, &value);
    if (name == NULL) break;
Cedric Roux's avatar
Cedric Roux committed
240
//printf("%s %s\n", name, value);
Cedric Roux's avatar
Cedric Roux committed
241
    if (!strcmp(name, "ID")) { last_id = add_id(r, value, i); i++; }
Cedric Roux's avatar
Cedric Roux committed
242
243
    if (!strcmp(name, "GROUP")) add_groups(r, last_id, value);
    if (!strcmp(name, "DESC")) add_desc(last_id, value);
244
245
246
247
248
249
250
251
252
253
254
255
256
257
  }

  fclose(in);
  free(p.name.data);
  free(p.value.data);

  return r;
}

void dump_database(void *_d)
{
  database *d = _d;
  int i;

Cedric Roux's avatar
Cedric Roux committed
258
259
260
261
262
263
264
265
266
  printf("database %s: %d IDs, %d GROUPs\n", d->name, d->isize, d->gsize);
  for (i = 0; i < d->isize; i++) {
    int j;
    printf("ID %s [%s] [in %d group%s]\n",
           d->i[i].name, d->i[i].desc ? d->i[i].desc : "",
           d->i[i].size, d->i[i].size > 1 ? "s" : "");
    for (j = 0; j < d->i[i].size; j++)
      printf("    in GROUP: %s\n", d->i[i].groups[j]);
  }
267
268
269
270
  for (i = 0; i < d->gsize; i++) {
    int j;
    printf("GROUP %s [size %d]\n", d->g[i].name, d->g[i].size);
    for (j = 0; j < d->g[i].size; j++)
Cedric Roux's avatar
Cedric Roux committed
271
      printf("  contains ID: %s\n", d->g[i].ids[j]);
272
273
  }
}
Cedric Roux's avatar
Cedric Roux committed
274
275
276
277
278
279
280
281
282
283
284
285
286
287

void list_ids(void *_d)
{
  database *d = _d;
  int i;
  for (i = 0; i < d->isize; i++) printf("%s\n", d->i[i].name);
}

void list_groups(void *_d)
{
  database *d = _d;
  int i;
  for (i = 0; i < d->gsize; i++) printf("%s\n", d->g[i].name);
}
Cedric Roux's avatar
Cedric Roux committed
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311

static void onoff_id(database *d, char *name, int *a, int onoff)
{
  id *i;
  i = bsearch(&(id){name:name}, d->i, d->isize, sizeof(id), id_cmp);
  if (i == NULL) return;
  a[i->id] = onoff;
  printf("turning %s %s\n", name, onoff ? "ON" : "OFF");
}

static void onoff_group(database *d, char *name, int *a, int onoff)
{
  group *g;
  int i;
  g = bsearch(&(group){name:name}, d->g, d->gsize, sizeof(group), group_cmp);
  if (g == NULL) return;
  for (i = 0; i < g->size; i++) onoff_id(d, g->ids[i], a, onoff);
}

void on_off(void *d, char *item, int *a, int onoff)
{
  onoff_group(d, item, a, onoff);
  onoff_id(d, item, a, onoff);
}