diff --git a/src/common.c b/src/common.c index fecaa92..eb69b80 100644 --- a/src/common.c +++ b/src/common.c @@ -578,10 +578,9 @@ struct str_map size_t len; ///< Number of entries in the table void (*free) (void *); ///< Callback to destruct the payload - /// Callback to compare keys for equivalence - // FIXME: they may still end up on a different index, and actually should; - // delete this callback and put strxfrm() in its place - int (*key_cmp) (const char *, const char *); + /// Callback that transforms all key values for storage and comparison; + /// has to behave exactly like strxfrm(). + size_t (*key_xfrm) (char *dest, const char *src, size_t n); }; // As long as you don't remove the current entry, you can modify the map. @@ -604,7 +603,7 @@ str_map_init (struct str_map *self) self->alloc = STR_MAP_MIN_ALLOC; self->len = 0; self->free = NULL; - self->key_cmp = strcmp; + self->key_xfrm = NULL; self->map = xcalloc (self->alloc, sizeof *self->map); } @@ -698,13 +697,13 @@ str_map_resize (struct str_map *self, size_t new_size) } static void -str_map_set (struct str_map *self, const char *key, void *value) +str_map_set_real (struct str_map *self, const char *key, void *value) { uint64_t pos = str_map_pos (self, key); struct str_map_link *iter = self->map[pos]; for (; iter; iter = iter->next) { - if (self->key_cmp (key, iter->key)) + if (strcmp (key, iter->key)) continue; // Storing the same data doesn't destroy it @@ -748,16 +747,40 @@ str_map_set (struct str_map *self, const char *key, void *value) self->len++; } +static void +str_map_set (struct str_map *self, const char *key, void *value) +{ + if (!self->key_xfrm) + { + str_map_set_real (self, key, value); + return; + } + char tmp[self->key_xfrm (NULL, key, 0) + 1]; + self->key_xfrm (tmp, key, sizeof tmp); + str_map_set_real (self, tmp, value); +} + static void * -str_map_find (struct str_map *self, const char *key) +str_map_find_real (struct str_map *self, const char *key) { struct str_map_link *iter = self->map[str_map_pos (self, key)]; for (; iter; iter = iter->next) - if (!self->key_cmp (key, (const char *) iter + sizeof *iter)) + if (!strcmp (key, (const char *) iter + sizeof *iter)) return iter->data; return NULL; } +static void * +str_map_find (struct str_map *self, const char *key) +{ + if (!self->key_xfrm) + return str_map_find_real (self, key); + + char tmp[self->key_xfrm (NULL, key, 0) + 1]; + self->key_xfrm (tmp, key, sizeof tmp); + return str_map_find_real (self, tmp); +} + // --- File descriptor utilities ----------------------------------------------- static void @@ -1727,7 +1750,7 @@ irc_process_buffer (struct str *buf, } static int -irc_tolower (char c) +irc_tolower (int c) { if (c == '[') return '{'; if (c == ']') return '}'; @@ -1736,6 +1759,15 @@ irc_tolower (char c) return c >= 'A' && c <= 'Z' ? c + ('a' - 'A') : c; } +static size_t +irc_strxfrm (char *dest, const char *src, size_t n) +{ + size_t len = strlen (src); + while (n-- && (*dest++ = irc_tolower (*src++))) + ; + return len; +} + static int irc_strcmp (const char *a, const char *b) { diff --git a/src/kike.c b/src/kike.c index 0325e41..207ff76 100644 --- a/src/kike.c +++ b/src/kike.c @@ -378,12 +378,12 @@ server_context_init (struct server_context *self) self->server_name = NULL; str_map_init (&self->users); - self->users.key_cmp = irc_strcmp; + self->users.key_xfrm = irc_strxfrm; // TODO: set channel_free() as the free function? str_map_init (&self->channels); - self->channels.key_cmp = irc_strcmp; + self->channels.key_xfrm = irc_strxfrm; str_map_init (&self->handlers); - self->handlers.key_cmp = irc_strcmp; + self->handlers.key_xfrm = irc_strxfrm; poller_init (&self->poller); self->quitting = false;