326 lines
7.4 KiB
C
326 lines
7.4 KiB
C
#include "defs.h"
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
|
|
typedef struct {
|
|
char *name;
|
|
char *desc;
|
|
char **groups;
|
|
int size;
|
|
int id;
|
|
} id;
|
|
|
|
typedef struct {
|
|
char *name;
|
|
char **ids;
|
|
int size;
|
|
} group;
|
|
|
|
typedef struct {
|
|
char *name;
|
|
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;
|
|
}
|
|
|
|
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)
|
|
{
|
|
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, int i)
|
|
{
|
|
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); }
|
|
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); }
|
|
}
|
|
r->i[r->isize].name = strdup(idname);
|
|
if (r->i[r->isize].name == NULL) { printf("out of memory\n"); exit(1); }
|
|
r->i[r->isize].desc = NULL;
|
|
r->i[r->isize].groups = NULL;
|
|
r->i[r->isize].size = 0;
|
|
r->i[r->isize].id = i;
|
|
r->isize++;
|
|
qsort(r->i, r->isize, sizeof(id), id_cmp);
|
|
return (id*)bsearch(&(id){name:idname}, r->i, r->isize, sizeof(id), id_cmp);
|
|
}
|
|
|
|
group *get_group(database *r, char *group_name)
|
|
{
|
|
group *ret;
|
|
|
|
ret = bsearch(&(group){name:group_name},
|
|
r->g, r->gsize, sizeof(group), group_cmp);
|
|
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);
|
|
|
|
return bsearch(&(group){name:group_name},
|
|
r->g, r->gsize, sizeof(group), group_cmp);
|
|
}
|
|
|
|
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++;
|
|
}
|
|
|
|
void id_add_group(id *i, char *group)
|
|
{
|
|
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);
|
|
}
|
|
|
|
void add_groups(database *r, id *i, char *groups)
|
|
{
|
|
group *g;
|
|
if (i == NULL) {printf("ERROR: GROUP line before ID line\n");exit(1);}
|
|
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);
|
|
group_add_id(g, i->name);
|
|
id_add_group(i, g->name);
|
|
|
|
if (end == NULL) break;
|
|
end++;
|
|
while ((isspace(*end) || *end == ':') && *end != 0) end++;
|
|
if (*end == 0) break;
|
|
groups = end;
|
|
}
|
|
}
|
|
|
|
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();
|
|
}
|
|
|
|
void *parse_database(char *filename)
|
|
{
|
|
FILE *in;
|
|
parser p;
|
|
database *r;
|
|
char *name, *value;
|
|
id *last_id = NULL;
|
|
int i;
|
|
|
|
r = calloc(1, sizeof(*r)); if (r == NULL) abort();
|
|
memset(&p, 0, sizeof(p));
|
|
|
|
r->name = strdup(filename); if (r->name == NULL) abort();
|
|
|
|
in = fopen(filename, "r"); if (in == NULL) { perror(filename); abort(); }
|
|
|
|
i = 0;
|
|
|
|
while (1) {
|
|
get_line(&p, in, &name, &value);
|
|
if (name == NULL) break;
|
|
//printf("%s %s\n", name, value);
|
|
if (!strcmp(name, "ID")) { last_id = add_id(r, value, i); i++; }
|
|
if (!strcmp(name, "GROUP")) add_groups(r, last_id, value);
|
|
if (!strcmp(name, "DESC")) add_desc(last_id, value);
|
|
}
|
|
|
|
fclose(in);
|
|
free(p.name.data);
|
|
free(p.value.data);
|
|
|
|
return r;
|
|
}
|
|
|
|
void dump_database(void *_d)
|
|
{
|
|
database *d = _d;
|
|
int i;
|
|
|
|
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]);
|
|
}
|
|
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++)
|
|
printf(" contains ID: %s\n", d->g[i].ids[j]);
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
static int 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 0;
|
|
a[i->id] = onoff;
|
|
printf("turning %s %s\n", onoff ? "ON" : "OFF", name);
|
|
return 1;
|
|
}
|
|
|
|
static int 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 0;
|
|
for (i = 0; i < g->size; i++) onoff_id(d, g->ids[i], a, onoff);
|
|
return 1;
|
|
}
|
|
|
|
void on_off(void *_d, char *item, int *a, int onoff)
|
|
{
|
|
int done;
|
|
database *d = _d;
|
|
int i;
|
|
if (item == NULL) {
|
|
for (i = 0; i < d->isize; i++) a[i] = onoff;
|
|
printf("turning %s all traces\n", onoff ? "ON" : "OFF");
|
|
return;
|
|
}
|
|
done = onoff_group(d, item, a, onoff);
|
|
done += onoff_id(d, item, a, onoff);
|
|
if (done == 0) {
|
|
printf("ERROR: ID/group '%s' not found in database\n", item);
|
|
exit(1);
|
|
}
|
|
}
|