|
|
@@ -15,166 +15,34 @@
|
|
|
*/
|
|
|
|
|
|
#include <ctype.h>
|
|
|
+
|
|
|
#include "dstr.h"
|
|
|
#include "text-lookup.h"
|
|
|
#include "lexer.h"
|
|
|
#include "platform.h"
|
|
|
+#include "uthash.h"
|
|
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
|
|
-struct text_leaf {
|
|
|
+struct text_item {
|
|
|
char *lookup, *value;
|
|
|
+ UT_hash_handle hh;
|
|
|
};
|
|
|
|
|
|
-static inline void text_leaf_destroy(struct text_leaf *leaf)
|
|
|
-{
|
|
|
- if (leaf) {
|
|
|
- bfree(leaf->lookup);
|
|
|
- bfree(leaf->value);
|
|
|
- bfree(leaf);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-/* ------------------------------------------------------------------------- */
|
|
|
-
|
|
|
-struct text_node {
|
|
|
- struct dstr str;
|
|
|
- struct text_node *first_subnode;
|
|
|
- struct text_leaf *leaf;
|
|
|
-
|
|
|
- struct text_node *next;
|
|
|
-};
|
|
|
-
|
|
|
-static void text_node_destroy(struct text_node *node)
|
|
|
-{
|
|
|
- struct text_node *subnode;
|
|
|
-
|
|
|
- if (!node)
|
|
|
- return;
|
|
|
-
|
|
|
- subnode = node->first_subnode;
|
|
|
- while (subnode) {
|
|
|
- struct text_node *destroy_node = subnode;
|
|
|
-
|
|
|
- subnode = subnode->next;
|
|
|
- text_node_destroy(destroy_node);
|
|
|
- }
|
|
|
-
|
|
|
- dstr_free(&node->str);
|
|
|
- if (node->leaf)
|
|
|
- text_leaf_destroy(node->leaf);
|
|
|
- bfree(node);
|
|
|
-}
|
|
|
-
|
|
|
-static struct text_node *text_node_bychar(struct text_node *node, char ch)
|
|
|
-{
|
|
|
- struct text_node *subnode = node->first_subnode;
|
|
|
-
|
|
|
- while (subnode) {
|
|
|
- if (!dstr_is_empty(&subnode->str) &&
|
|
|
- subnode->str.array[0] == ch)
|
|
|
- return subnode;
|
|
|
-
|
|
|
- subnode = subnode->next;
|
|
|
- }
|
|
|
-
|
|
|
- return NULL;
|
|
|
-}
|
|
|
-
|
|
|
-static struct text_node *text_node_byname(struct text_node *node,
|
|
|
- const char *name)
|
|
|
+static inline void text_item_destroy(struct text_item *item)
|
|
|
{
|
|
|
- struct text_node *subnode = node->first_subnode;
|
|
|
-
|
|
|
- while (subnode) {
|
|
|
- if (astrcmpi_n(subnode->str.array, name, subnode->str.len) == 0)
|
|
|
- return subnode;
|
|
|
-
|
|
|
- subnode = subnode->next;
|
|
|
- }
|
|
|
-
|
|
|
- return NULL;
|
|
|
+ bfree(item->lookup);
|
|
|
+ bfree(item->value);
|
|
|
+ bfree(item);
|
|
|
}
|
|
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
|
|
struct text_lookup {
|
|
|
struct dstr language;
|
|
|
- struct text_node *top;
|
|
|
+ struct text_item *items;
|
|
|
};
|
|
|
|
|
|
-static void lookup_createsubnode(const char *lookup_val, struct text_leaf *leaf,
|
|
|
- struct text_node *node)
|
|
|
-{
|
|
|
- struct text_node *new = bzalloc(sizeof(struct text_node));
|
|
|
- new->leaf = leaf;
|
|
|
- new->next = node->first_subnode;
|
|
|
- dstr_copy(&new->str, lookup_val);
|
|
|
-
|
|
|
- node->first_subnode = new;
|
|
|
-}
|
|
|
-
|
|
|
-static void lookup_splitnode(const char *lookup_val, size_t len,
|
|
|
- struct text_leaf *leaf, struct text_node *node)
|
|
|
-{
|
|
|
- struct text_node *split = bzalloc(sizeof(struct text_node));
|
|
|
-
|
|
|
- dstr_copy(&split->str, node->str.array + len);
|
|
|
- split->leaf = node->leaf;
|
|
|
- split->first_subnode = node->first_subnode;
|
|
|
- node->first_subnode = split;
|
|
|
-
|
|
|
- dstr_resize(&node->str, len);
|
|
|
-
|
|
|
- if (lookup_val[len] != 0) {
|
|
|
- node->leaf = NULL;
|
|
|
- lookup_createsubnode(lookup_val + len, leaf, node);
|
|
|
- } else {
|
|
|
- node->leaf = leaf;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-static inline void lookup_replaceleaf(struct text_node *node,
|
|
|
- struct text_leaf *leaf)
|
|
|
-{
|
|
|
- text_leaf_destroy(node->leaf);
|
|
|
- node->leaf = leaf;
|
|
|
-}
|
|
|
-
|
|
|
-static void lookup_addstring(const char *lookup_val, struct text_leaf *leaf,
|
|
|
- struct text_node *node)
|
|
|
-{
|
|
|
- struct text_node *child;
|
|
|
-
|
|
|
- /* value already exists, so replace */
|
|
|
- if (!lookup_val || !*lookup_val) {
|
|
|
- lookup_replaceleaf(node, leaf);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- child = text_node_bychar(node, *lookup_val);
|
|
|
- if (child) {
|
|
|
- size_t len;
|
|
|
-
|
|
|
- for (len = 0; len < child->str.len; len++) {
|
|
|
- char val1 = child->str.array[len],
|
|
|
- val2 = lookup_val[len];
|
|
|
-
|
|
|
- if (val1 != val2)
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- if (len == child->str.len) {
|
|
|
- lookup_addstring(lookup_val + len, leaf, child);
|
|
|
- return;
|
|
|
- } else {
|
|
|
- lookup_splitnode(lookup_val, len, leaf, child);
|
|
|
- }
|
|
|
- } else {
|
|
|
- lookup_createsubnode(lookup_val, leaf, node);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
static void lookup_getstringtoken(struct lexer *lex, struct strref *token)
|
|
|
{
|
|
|
const char *temp = lex->offset;
|
|
|
@@ -300,7 +168,8 @@ static void lookup_addfiledata(struct text_lookup *lookup,
|
|
|
strref_clear(&value);
|
|
|
|
|
|
while (lookup_gettoken(&lex, &name)) {
|
|
|
- struct text_leaf *leaf;
|
|
|
+ struct text_item *item;
|
|
|
+ struct text_item *old;
|
|
|
bool got_eq = false;
|
|
|
|
|
|
if (*name.array == '\n')
|
|
|
@@ -315,14 +184,14 @@ static void lookup_addfiledata(struct text_lookup *lookup,
|
|
|
goto getval;
|
|
|
}
|
|
|
|
|
|
- leaf = bmalloc(sizeof(struct text_leaf));
|
|
|
- leaf->lookup = bstrdup_n(name.array, name.len);
|
|
|
- leaf->value = convert_string(value.array, value.len);
|
|
|
+ item = bzalloc(sizeof(struct text_item));
|
|
|
+ item->lookup = bstrdup_n(name.array, name.len);
|
|
|
+ item->value = convert_string(value.array, value.len);
|
|
|
|
|
|
- for (size_t i = 0; i < name.len; i++)
|
|
|
- leaf->lookup[i] = toupper(leaf->lookup[i]);
|
|
|
+ HASH_REPLACE_STR(lookup->items, lookup, item, old);
|
|
|
|
|
|
- lookup_addstring(leaf->lookup, leaf, lookup->top);
|
|
|
+ if (old)
|
|
|
+ text_item_destroy(old);
|
|
|
|
|
|
if (!lookup_goto_nextline(&lex))
|
|
|
break;
|
|
|
@@ -332,27 +201,19 @@ static void lookup_addfiledata(struct text_lookup *lookup,
|
|
|
}
|
|
|
|
|
|
static inline bool lookup_getstring(const char *lookup_val, const char **out,
|
|
|
- struct text_node *node)
|
|
|
+ struct text_lookup *lookup)
|
|
|
{
|
|
|
- struct text_node *child;
|
|
|
- char ch;
|
|
|
-
|
|
|
- if (!node)
|
|
|
- return false;
|
|
|
+ struct text_item *item;
|
|
|
|
|
|
- child = text_node_byname(node, lookup_val);
|
|
|
- if (!child)
|
|
|
+ if (!lookup->items)
|
|
|
return false;
|
|
|
|
|
|
- lookup_val += child->str.len;
|
|
|
- ch = *lookup_val;
|
|
|
- if (ch)
|
|
|
- return lookup_getstring(lookup_val, out, child);
|
|
|
+ HASH_FIND_STR(lookup->items, lookup_val, item);
|
|
|
|
|
|
- if (!child->leaf)
|
|
|
+ if (!item)
|
|
|
return false;
|
|
|
|
|
|
- *out = child->leaf->value;
|
|
|
+ *out = item->value;
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
@@ -387,9 +248,6 @@ bool text_lookup_add(lookup_t *lookup, const char *path)
|
|
|
if (!file_str.array)
|
|
|
return false;
|
|
|
|
|
|
- if (!lookup->top)
|
|
|
- lookup->top = bzalloc(sizeof(struct text_node));
|
|
|
-
|
|
|
dstr_replace(&file_str, "\r", " ");
|
|
|
lookup_addfiledata(lookup, file_str.array);
|
|
|
dstr_free(&file_str);
|
|
|
@@ -400,9 +258,13 @@ bool text_lookup_add(lookup_t *lookup, const char *path)
|
|
|
void text_lookup_destroy(lookup_t *lookup)
|
|
|
{
|
|
|
if (lookup) {
|
|
|
- dstr_free(&lookup->language);
|
|
|
- text_node_destroy(lookup->top);
|
|
|
+ struct text_item *item, *tmp;
|
|
|
+ HASH_ITER (hh, lookup->items, item, tmp) {
|
|
|
+ HASH_DELETE(hh, lookup->items, item);
|
|
|
+ text_item_destroy(item);
|
|
|
+ }
|
|
|
|
|
|
+ dstr_free(&lookup->language);
|
|
|
bfree(lookup);
|
|
|
}
|
|
|
}
|
|
|
@@ -411,6 +273,6 @@ bool text_lookup_getstr(lookup_t *lookup, const char *lookup_val,
|
|
|
const char **out)
|
|
|
{
|
|
|
if (lookup)
|
|
|
- return lookup_getstring(lookup_val, out, lookup->top);
|
|
|
+ return lookup_getstring(lookup_val, out, lookup);
|
|
|
return false;
|
|
|
}
|