aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPřemysl Janouch <p.janouch@gmail.com>2014-07-16 21:23:30 +0200
committerPřemysl Janouch <p.janouch@gmail.com>2014-07-16 21:23:30 +0200
commitd28b7224897bf6cc9c5238068b1bf33ae264591d (patch)
treece7cf0a528df43133ad6f69826408ea300bddae1
parent996e0912c26caeb08b8f3874c82177ec81aa14b3 (diff)
downloadxK-d28b7224897bf6cc9c5238068b1bf33ae264591d.tar.gz
xK-d28b7224897bf6cc9c5238068b1bf33ae264591d.tar.xz
xK-d28b7224897bf6cc9c5238068b1bf33ae264591d.zip
str_map::key_cmp -> str_map::key_xfrm
It seemed to be almost too easy to be true, and it actually was. Now it should work.
-rw-r--r--src/common.c52
-rw-r--r--src/kike.c6
2 files changed, 45 insertions, 13 deletions
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;