diff --git a/src/direction.c b/src/direction.c index 0b9bb8206..5e2333bbe 100644 --- a/src/direction.c +++ b/src/direction.c @@ -12,7 +12,7 @@ void init_direction(const struct locale *lang, direction_t dir, const char *str) void **tokens = get_translations(lang, UT_DIRECTIONS); variant token; token.i = dir; - addtoken(tokens, str, token); + addtoken((struct tnode **)tokens, str, token); } void init_directions(struct locale *lang) { @@ -47,7 +47,7 @@ void init_directions(struct locale *lang) { if (str) { variant token; token.i = dirs[i].direction; - addtoken(tokens, str, token); + addtoken((struct tnode **)tokens, str, token); } } } diff --git a/src/kernel/building.c b/src/kernel/building.c index 11ab70bb1..e4ae8f991 100644 --- a/src/kernel/building.c +++ b/src/kernel/building.c @@ -311,7 +311,7 @@ const building_type *findbuildingtype(const char *name, const char *n = LOC(lang, btype->_name); type.v = (void *)btype; - addtoken(&bn->names, n, type); + addtoken((struct tnode **)&bn->names, n, type); } bnames = bn; } diff --git a/src/kernel/command.c b/src/kernel/command.c index 0642be060..a667edabc 100644 --- a/src/kernel/command.c +++ b/src/kernel/command.c @@ -78,7 +78,7 @@ const char *str, parser fun) cmd->fun = fun; cmd->nodes = tnext; var.v = cmd; - addtoken(keys, str, var); + addtoken((struct tnode **)keys, str, var); } static int do_command_i(const void *keys, struct unit *u, struct order *ord) diff --git a/src/kernel/config.c b/src/kernel/config.c index e3918557e..4758b36c8 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -471,7 +471,7 @@ void init_terrains_translation(const struct locale *lang) { var.v = (void *)terrain; name = locale_string(lang, terrain->_name, false); if (name) { - addtoken(tokens, name, var); + addtoken((struct tnode **)tokens, name, var); } else { log_debug("no translation for terrain %s in locale %s", terrain->_name, locale_name(lang)); @@ -490,7 +490,7 @@ void init_options_translation(const struct locale * lang) { if (options[i]) { const char *name = locale_string(lang, options[i], false); if (name) { - addtoken(tokens, name, var); + addtoken((struct tnode **)tokens, name, var); } else { log_debug("no translation for OPTION %s in locale %s", options[i], locale_name(lang)); @@ -525,7 +525,7 @@ void init_locale(struct locale *lang) var.i = i; name = LOC(lang, mkname("school", tok)); if (name) { - addtoken(tokens, name, var); + addtoken((struct tnode **)tokens, name, var); } else { log_warning("no translation for magic school %s in locale %s", tok, locale_name(lang)); @@ -544,9 +544,9 @@ void init_locale(struct locale *lang) const char *name; var.v = (void *)rc; name = locale_string(lang, rc_name_s(rc, NAME_PLURAL), false); - if (name) addtoken(tokens, name, var); + if (name) addtoken((struct tnode **)tokens, name, var); name = locale_string(lang, rc_name_s(rc, NAME_SINGULAR), false); - if (name) addtoken(tokens, name, var); + if (name) addtoken((struct tnode **)tokens, name, var); } init_parameters(lang); diff --git a/src/kernel/ship.c b/src/kernel/ship.c index fb2fb3906..02a980b68 100644 --- a/src/kernel/ship.c +++ b/src/kernel/ship.c @@ -78,7 +78,7 @@ const ship_type *findshiptype(const char *name, const struct locale *lang) variant var2; const char *n = LOC(lang, stype->_name); var2.v = (void *)stype; - addtoken(&sn->names, n, var2); + addtoken((struct tnode **)&sn->names, n, var2); } snames = sn; } diff --git a/src/laws.c b/src/laws.c index e41bafbec..197433bfa 100755 --- a/src/laws.c +++ b/src/laws.c @@ -1438,8 +1438,8 @@ static void init_prefixnames(void) LOC(lang, mkname("prefix", race_prefixes[key])); if (findtoken(in->names, pname, &var) == E_TOK_NOMATCH || var.i != key) { var.i = key; - addtoken(&in->names, pname, var); - addtoken(&in->names, LOC(lang, mkname("prefix", + addtoken((struct tnode **)&in->names, pname, var); + addtoken((struct tnode **)&in->names, LOC(lang, mkname("prefix", race_prefixes[key])), var); } } diff --git a/src/magic.c b/src/magic.c index d24612e06..6ff2ac8e5 100644 --- a/src/magic.c +++ b/src/magic.c @@ -2954,7 +2954,7 @@ static void select_spellbook(void **tokens, spellbook *sb, const struct locale * else { variant token; token.v = sp; - addtoken(tokens, n, token); + addtoken((struct tnode **)tokens, n, token); } } } diff --git a/src/util/umlaut.c b/src/util/umlaut.c index 9c37b852c..6be0bdde5 100644 --- a/src/util/umlaut.c +++ b/src/util/umlaut.c @@ -32,7 +32,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. typedef struct tref { struct tref *nexthash; ucs4_t ucs; - void *node; + struct tnode *node; } tref; #define LEAF 1 /* leaf node for a word. always matches */ @@ -42,6 +42,7 @@ typedef struct tnode { struct tref *next[NODEHASHSIZE]; unsigned char flags; variant id; + int refcount; } tnode; char * transliterate(char * out, size_t size, const char * in) @@ -114,7 +115,13 @@ char * transliterate(char * out, size_t size, const char * in) return *src ? 0 : out; } -void addtoken(void ** root, const char *str, variant id) +tnode * mknode(void) { + tnode * node = calloc(1, sizeof(tnode)); + node->refcount = 1; + return node; +} + +void addtoken(tnode ** root, const char *str, variant id) { tnode * tk; static const struct replace { @@ -128,7 +135,7 @@ void addtoken(void ** root, const char *str, variant id) assert(root && str); if (!*root) { - tk = *root = calloc(1, sizeof(tnode)); + tk = *root = mknode(); } else { tk = *root; @@ -161,7 +168,7 @@ void addtoken(void ** root, const char *str, variant id) next = next->nexthash; if (!next) { tref *ref; - tnode *node = (tnode *)calloc(1, sizeof(tnode)); // TODO: what is the reason for this empty node to exist? + tnode *node = mknode(); // TODO: what is the reason for this empty node to exist? if (ucs < 'a' || ucs > 'z') { lcs = towlower((wint_t)ucs); @@ -187,6 +194,7 @@ void addtoken(void ** root, const char *str, variant id) assert_alloc(ref); ref->ucs = lcs; ref->node = node; + ++node->refcount; ref->nexthash = tk->next[index]; tk->next[index] = ref; } @@ -212,23 +220,25 @@ void addtoken(void ** root, const char *str, variant id) } } -void freetokens(void * root) +void freetokens(tnode * root) { - tnode * node = (tnode *)root; + tnode * node = root; int i; for (i = 0; node && i != NODEHASHSIZE; ++i) { if (node->next[i]) { - tref ** refs = &node->next[i]; - freetokens(node->next[i]->node); - while (*refs) { - tref * ref = *refs; - *refs = ref->nexthash; -// free(ref->node); + tref * ref = node->next[i]; + while (ref) { + tref * next = ref->nexthash; + freetokens(ref->node); free(ref); + ref = next; } + node->next[i] = 0; } } - free(node); + if (--node->refcount == 0) { + free(node); + } } int findtoken(const void * root, const char *key, variant * result) diff --git a/src/util/umlaut.h b/src/util/umlaut.h index 1e6baecb4..d64df7609 100644 --- a/src/util/umlaut.h +++ b/src/util/umlaut.h @@ -29,10 +29,11 @@ extern "C" { #define E_TOK_NOMATCH (-1) #define E_TOK_SUCCESS 0 #define NODEHASHSIZE 8 + struct tnode; int findtoken(const void *tk, const char *str, variant * result); - void addtoken(void **root, const char *str, variant id); - void freetokens(void *root); + void addtoken(struct tnode **root, const char *str, variant id); + void freetokens(struct tnode *root); char * transliterate(char * out, size_t size, const char * in); diff --git a/src/util/umlaut.test.c b/src/util/umlaut.test.c index 1bb93ac4b..959960509 100644 --- a/src/util/umlaut.test.c +++ b/src/util/umlaut.test.c @@ -4,7 +4,6 @@ #include #include "umlaut.h" -#ifdef LEAK_FREE static void test_transliterate(CuTest * tc) { char buffer[32]; @@ -29,7 +28,7 @@ static void test_transliterate(CuTest * tc) static void test_transliterations(CuTest *tc) { const char * umlauts = "\xc3\xa4\xc3\xb6\xc3\xbc\xc3\x9f"; /* auml ouml uuml szlig nul */ - void * tokens = 0; + struct tnode * tokens = 0; variant id; int result; @@ -49,7 +48,7 @@ static void test_transliterations(CuTest *tc) { static void test_directions(CuTest * tc) { - void * tokens = 0; + struct tnode * tokens = 0; variant id; int result; @@ -65,7 +64,7 @@ static void test_directions(CuTest * tc) static void test_umlaut(CuTest * tc) { - void * tokens = 0; + struct tnode *tokens = 0; variant id; int result; @@ -97,14 +96,13 @@ static void test_umlaut(CuTest * tc) freetokens(tokens); } -#endif static void test_leak(CuTest *tc) { - void *tokens = NULL; + struct tnode *tokens = NULL; variant token; token.i = 42; - addtoken(&tokens, "No", token); + addtoken(&tokens, "NO", token); addtoken(&tokens, "nw", token); CuAssertIntEquals(tc, E_TOK_SUCCESS, findtoken(tokens, "n", &token)); freetokens(tokens); @@ -113,12 +111,10 @@ static void test_leak(CuTest *tc) { CuSuite *get_umlaut_suite(void) { CuSuite *suite = CuSuiteNew(); -#ifdef LEAK_FREE SUITE_ADD_TEST(suite, test_umlaut); SUITE_ADD_TEST(suite, test_directions); SUITE_ADD_TEST(suite, test_transliterate); SUITE_ADD_TEST(suite, test_transliterations); -#endif SUITE_ADD_TEST(suite, test_leak); return suite; } diff --git a/src/vortex.c b/src/vortex.c index 8aac12aec..4b512476b 100644 --- a/src/vortex.c +++ b/src/vortex.c @@ -36,7 +36,7 @@ void register_special_direction(struct locale *lang, const char *name) char *str = _strdup(name); var.v = str; - addtoken(tokens, token, var); + addtoken((struct tnode **)tokens, token, var); if (lang == locales) { dir_lookup *dl = malloc(sizeof(dir_lookup));