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