From 1030dc837b10a03a02a85d5504cbeec168ce49e2 Mon Sep 17 00:00:00 2001 From: Bernie Innocenti Date: Mon, 03 May 2010 21:53:47 +0000 Subject: Import XaoS r489 (trunk after version 3.5) --- (limited to 'src/util/catalog.c') diff --git a/src/util/catalog.c b/src/util/catalog.c new file mode 100644 index 0000000..76cfa69 --- /dev/null +++ b/src/util/catalog.c @@ -0,0 +1,253 @@ +#include +#ifndef _plan9_ +#include +#ifndef NO_MALLOC_H +#include +#endif +#include +#else +#include +#include +#endif +#include +#include +/* Well, just simple implementation of unbalanced trees in combination + * of small hash table. I am lazy :) but should be OK for my purposes + * + * This function is used for both-lookups and adds into table (since most of + * code is the same, depends whether newvalue is NULL. If newvalue is nonNULL, + * new variable is added into table, if name is not present here or value is + * changed othewise. + */ +static char *find_variable(catalog_t * context, CONST char *name, + CONST char *newvalue) +{ + int r = 0; + int hash = (int) strlen(name); + struct varnames *current, *last, *newp; + hash = + ((unsigned char) (name[0]) + (unsigned char) (name[hash - 1]) + + hash) % (unsigned int) CHASHMAX; + current = last = context->root[hash]; + while (current != NULL) { + last = current; + r = strcmp(current->name, name); + if (!r) { + if (newvalue != NULL) { /*overwrite value */ + free(current->value); + current->value = mystrdup(newvalue); + } + return (current->value); + } + if (r > 0) + current = current->left; + else + current = current->right; + } + /*Entry is new */ + if (newvalue == NULL) + return (NULL); + newp = (struct varnames *) calloc(1, sizeof(struct varnames)); + newp->name = mystrdup(name); + newp->value = mystrdup(newvalue); + /*FIXME. Should take a care to full memory */ + newp->left = NULL; + newp->right = NULL; + if (last == NULL) { + context->root[hash] = newp; + } else { + if (r > 0) + last->left = newp; + else + last->right = newp; + } + return (newp->value); +} + +/* + * free memory used by node and its sons + */ +static void free_node(struct varnames *node) +{ + while (node != NULL) { + struct varnames *nextnode; + free_node(node->left); + nextnode = node->right; + free(node->name); + free(node->value); + free(node); + node = nextnode; + } +} + +/* + * free catalog + */ +void free_catalog(catalog_t * context) +{ + int i; + for (i = 0; i < CHASHMAX; i++) { + free_node(context->root[i]); + context->root[i] = NULL; + } + free(context); +} + +static catalog_t *alloc_catalog(void) +{ + int i; + catalog_t *c; + c = (catalog_t *) calloc(1, sizeof(catalog_t)); + if (c == NULL) + return NULL; + for (i = 0; i < CHASHMAX; i++) + c->root[i] = NULL; + return c; +} + +/* + * Parse an catalog file and save values into memory + */ +// FIXME: this macro gives a segfault if \" is used in text. kovzol, 2009-06-29 +#define seterror(text) sprintf(errort,"line %i:%s",line,text),*error=errort +catalog_t *load_catalog(xio_file f, CONST char **error) +{ + int i; + int line = 1; + int size; + int c; + catalog_t *catalog = alloc_catalog(); + static char errort[40]; + char name[1024]; + char value[1024]; + if (catalog == NULL) { + *error = "Out of memory"; + } + if (f == NULL) { + *error = "File could not be opened"; + free_catalog(catalog); + return NULL; + } + /* Just very simple parsing loop of format + * [blanks]name[blanks]"value"[blanks] + * Blanks should be comments using # or space, newline, \r and tabulator + * Value shoud contain and \ seqences where \\ means \ and + * \[something] means something. Should be used for character " + */ + while (!xio_feof(f)) { + + do { + c = xio_getc(f); + if (c == '\n') + line++; + if (c == '#') { + while ((c = xio_getc(f)) != '\n' && c != XIO_EOF); + line++; + } + } + while (c == ' ' || c == '\n' || c == '\r' || c == '\t'); + + /*Skip blanks */ + if (c == XIO_EOF) { + if (xio_feof(f)) + break; + free_catalog(catalog); + seterror("read error"); + xio_close(f); + return NULL; + } + i = 0; + + /*read name */ + do { + name[i] = c; + i++; + c = xio_getc(f); + if (c == '\n') + line++; + if (i == 1024) { + seterror("Name is too long (>=1024 characters)"); + free_catalog(catalog); + xio_close(f); + return NULL; + } + } + + while (c != '\n' && c != ' ' && c != '\t' && c != XIO_EOF); + + /*Skip blanks */ + while (c == ' ' || c == '\n' || c == '\r' || c == '\t') { + c = xio_getc(f); + if (c == '\n') + line++; + if (c == '#') { + while ((c = xio_getc(f)) != '\n' && c != XIO_EOF); + line++; + } + } + + /*Skip blanks */ + if (c == XIO_EOF) { + if (xio_feof(f)) + seterror("Unexpected end of file after name field"); + else + seterror("read error"); + free_catalog(catalog); + xio_close(f); + return NULL; + } + + name[i] = 0; + if (c != '"') { + seterror("Begin of value field expected"); // Text modified due to segfault problem, see above (kovzol) + free_catalog(catalog); + xio_close(f); + return NULL; + } + c = xio_getc(f); + if (c == '\n') + line++; + i = 0; + + size = 0; + do { + if (c == '\\') + value[i] = xio_getc(f); + else + value[i] = c; + i++; + c = xio_getc(f); + if (c == '\n') + line++, size = 0; + if (size == 40 && c != '"') { + fprintf(stderr, "Warning - too long text at line %i\n", + line); + } + size++; + if (i == 1024) { + seterror("Value is too long (>=1024 characters)"); + free_catalog(catalog); + xio_close(f); + return NULL; + } + } + while (c != '"' && c != XIO_EOF); + + if (c == XIO_EOF) { + seterror("Unexpected EOF in value field"); + free_catalog(catalog); + xio_close(f); + return NULL; + } + + value[i] = 0; + find_variable(catalog, name, value); + } /*while */ + xio_close(f); + return (catalog); +} /*load_catalog */ + +char *find_text(catalog_t * catalog, CONST char *name) +{ + return (find_variable(catalog, name, NULL)); +} -- cgit v0.9.1