database.c 6.38 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;
12
13
14
15
16
17
18
19
20
} id;

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

typedef struct {
Cedric Roux's avatar
Cedric Roux committed
21
  char *name;
22
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
  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
98
99
100
101
102
103
104
105
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)
106
{
Cedric Roux's avatar
Cedric Roux committed
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
  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);
}

id *add_id(database *r, char *idname)
{
  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); }
123
124
125
126
  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
127
  r->i[r->isize].name = strdup(idname);
128
  if (r->i[r->isize].name == NULL) { printf("out of memory\n"); exit(1); }
Cedric Roux's avatar
Cedric Roux committed
129
130
131
  r->i[r->isize].desc = NULL;
  r->i[r->isize].groups = NULL;
  r->i[r->isize].size = 0;
132
  r->isize++;
Cedric Roux's avatar
Cedric Roux committed
133
134
  qsort(r->i, r->isize, sizeof(id), id_cmp);
  return (id*)bsearch(&(id){name:idname}, r->i, r->isize, sizeof(id), id_cmp);
135
136
137
138
139
140
}

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

Cedric Roux's avatar
Cedric Roux committed
141
142
  ret = bsearch(&(group){name:group_name},
                r->g, r->gsize, sizeof(group), group_cmp);
143
144
145
146
147
148
149
150
151
152
153
154
155
156
  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
157
158
  return bsearch(&(group){name:group_name},
                 r->g, r->gsize, sizeof(group), group_cmp);
159
160
161
162
163
164
165
166
167
168
169
170
}

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
171
void id_add_group(id *i, char *group)
172
{
Cedric Roux's avatar
Cedric Roux committed
173
174
175
176
177
178
179
180
181
182
183
  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);
}
184

Cedric Roux's avatar
Cedric Roux committed
185
186
187
188
void add_groups(database *r, id *i, char *groups)
{
  group *g;
  if (i == NULL) {printf("ERROR: GROUP line before ID line\n");exit(1);}
189
190
191
192
193
194
195
196
197
198
199
  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
200
201
    group_add_id(g, i->name);
    id_add_group(i, g->name);
202
203
204
205
206
207
208
209
210

    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
211
212
213
214
215
216
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();
}

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

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

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

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

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

  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
253
254
255
256
257
258
259
260
261
  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]);
  }
262
263
264
265
  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
266
      printf("  contains ID: %s\n", d->g[i].ids[j]);
267
268
  }
}
Cedric Roux's avatar
Cedric Roux committed
269
270
271
272
273
274
275
276
277
278
279
280
281
282

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);
}