]> granicus.if.org Git - mutt/commitdiff
Restore $reverse_alias feature by using case-insensitive hash keys
authorRocco Rutte <pdmef@gmx.net>
Mon, 9 Mar 2009 10:11:51 +0000 (11:11 +0100)
committerRocco Rutte <pdmef@gmx.net>
Mon, 9 Mar 2009 10:11:51 +0000 (11:11 +0100)
The fix is implemented as callbacks in the hash table so we can avoid
working with copies of the mailbox keys but work on the originals
instead and don't pollute the code with lower-case conversions all over
the place.

While I'm at it, turn int hashes into unsigned values since the hash
function returns unsigned values now, too.

Closes #3185.

hash.c
hash.h
init.c
mh.c
thread.c

diff --git a/hash.c b/hash.c
index 7e4e19fd6f8ce4770b6ef79b44b8fd154cd1daf1..08f717179b91d1dea2e280d2fd0e03378acc5e26 100644 (file)
--- a/hash.c
+++ b/hash.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org>
+ * Copyright (C) 1996-2009 Michael R. Elkins <me@mutt.org>
  *
  *     This program is free software; you can redistribute it and/or modify
  *     it under the terms of the GNU General Public License as published by
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
+#include <ctype.h>
 
 #include "mutt.h"
 
 #define SOMEPRIME 149711
 
-unsigned int hash_string (const unsigned char *s, unsigned int n)
+static unsigned int hash_string (const unsigned char *s, unsigned int n)
 {
   unsigned int h = 0;
 
@@ -39,13 +40,34 @@ unsigned int hash_string (const unsigned char *s, unsigned int n)
   return h;
 }
 
-HASH *hash_create (int nelem)
+static unsigned int hash_case_string (const unsigned char *s, unsigned int n)
+{
+  unsigned int h = 0;
+
+  while (*s)
+    h += (h << 7) + tolower (*s++);
+  h = (h * SOMEPRIME) % n;
+
+  return h;
+}
+
+HASH *hash_create (int nelem, int lower)
 {
   HASH *table = safe_malloc (sizeof (HASH));
   if (nelem == 0)
     nelem = 2;
   table->nelem = nelem;
   table->table = safe_calloc (nelem, sizeof (struct hash_elem *));
+  if (lower)
+  {
+    table->hash_string = hash_case_string;
+    table->cmp_string = mutt_strcasecmp;
+  }
+  else
+  {
+    table->hash_string = hash_string;
+    table->cmp_string = mutt_strcmp;
+  }
   return table;
 }
 
@@ -57,10 +79,10 @@ HASH *hash_create (int nelem)
 int hash_insert (HASH * table, const char *key, void *data, int allow_dup)
 {
   struct hash_elem *ptr;
-  int h;
+  unsigned int h;
 
   ptr = (struct hash_elem *) safe_malloc (sizeof (struct hash_elem));
-  h = hash_string ((unsigned char *) key, table->nelem);
+  h = table->hash_string ((unsigned char *) key, table->nelem);
   ptr->key = key;
   ptr->data = data;
 
@@ -76,7 +98,7 @@ int hash_insert (HASH * table, const char *key, void *data, int allow_dup)
 
     for (tmp = table->table[h], last = NULL; tmp; last = tmp, tmp = tmp->next)
     {
-      r = mutt_strcmp (tmp->key, key);
+      r = table->cmp_string (tmp->key, key);
       if (r == 0)
       {
        FREE (&ptr);
@@ -99,7 +121,7 @@ void *hash_find_hash (const HASH * table, int hash, const char *key)
   struct hash_elem *ptr = table->table[hash];
   for (; ptr; ptr = ptr->next)
   {
-    if (mutt_strcmp (key, ptr->key) == 0)
+    if (table->cmp_string (key, ptr->key) == 0)
       return (ptr->data);
   }
   return NULL;
@@ -114,7 +136,7 @@ void hash_delete_hash (HASH * table, int hash, const char *key, const void *data
   while (ptr) 
   {
     if ((data == ptr->data || !data)
-       && mutt_strcmp (ptr->key, key) == 0)
+       && table->cmp_string (ptr->key, key) == 0)
     {
       *last = ptr->next;
       if (destroy)
diff --git a/hash.h b/hash.h
index 5338aca45e90cc8c3f3bcbb13bef692321e1f166..fb77d0c14c5cc5d81668612f2ea44e8a2811e45a 100644 (file)
--- a/hash.h
+++ b/hash.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org>
+ * Copyright (C) 1996-2009 Michael R. Elkins <me@mutt.org>
  *
  *     This program is free software; you can redistribute it and/or modify
  *     it under the terms of the GNU General Public License as published by
@@ -30,15 +30,16 @@ typedef struct
 {
   int nelem;
   struct hash_elem **table;
+  unsigned int (*hash_string)(const unsigned char *, unsigned int);
+  int (*cmp_string)(const char *, const char *);
 }
 HASH;
 
-#define hash_find(table, key) hash_find_hash(table, hash_string ((unsigned char *)key, table->nelem), key)
+#define hash_find(table, key) hash_find_hash(table, table->hash_string ((unsigned char *)key, table->nelem), key)
 
-#define hash_delete(table,key,data,destroy) hash_delete_hash(table, hash_string ((unsigned char *)key, table->nelem), key, data, destroy)
+#define hash_delete(table,key,data,destroy) hash_delete_hash(table, table->hash_string ((unsigned char *)key, table->nelem), key, data, destroy)
 
-HASH *hash_create (int nelem);
-unsigned int hash_string (const unsigned char *s, unsigned int n);
+HASH *hash_create (int nelem, int lower);
 int hash_insert (HASH * table, const char *key, void *data, int allow_dup);
 void *hash_find_hash (const HASH * table, int hash, const char *key);
 void hash_delete_hash (HASH * table, int hash, const char *key, const void *data,
diff --git a/init.c b/init.c
index 9b98d770c0a2bc91c7d8d4866b8fd38a1d0e8a99..199a7f0bce6913b2fe72f1cae30d0b8ef530e5a3 100644 (file)
--- a/init.c
+++ b/init.c
@@ -2885,8 +2885,8 @@ void mutt_init (int skip_sys_rc, LIST *commands)
   err.data = error;
   err.dsize = sizeof (error);
 
-  Groups = hash_create (1031);
-  ReverseAlias = hash_create (1031);
+  Groups = hash_create (1031, 0);
+  ReverseAlias = hash_create (1031, 1);
   
   mutt_menu_init ();
 
diff --git a/mh.c b/mh.c
index b019fa676507464086bfa871c0697ecaa5ae7ebd..53df87565cc31373308ad2d474acb84eb5115f1b 100644 (file)
--- a/mh.c
+++ b/mh.c
@@ -1870,7 +1870,7 @@ int maildir_check_mailbox (CONTEXT * ctx, int *index_hint)
    * of each message we scanned.  This is used in the loop over the
    * existing messages below to do some correlation.
    */
-  fnames = hash_create (1031);
+  fnames = hash_create (1031, 0);
 
   for (p = md; p; p = p->next)
   {
@@ -2019,7 +2019,7 @@ int mh_check_mailbox (CONTEXT * ctx, int *index_hint)
   mhs_free_sequences (&mhs);
 
   /* check for modifications and adjust flags */
-  fnames = hash_create (1031);
+  fnames = hash_create (1031, 0);
 
   for (p = md; p; p = p->next)
     hash_insert (fnames, p->h->path, p, 0);
index 957acc0e94b6e699a6c5e97a617b0feb904dfa1a..7382bad0ed887a7667503642ab7a91bfa638acd1 100644 (file)
--- a/thread.c
+++ b/thread.c
@@ -416,7 +416,7 @@ static THREAD *find_subject (CONTEXT *ctx, THREAD *cur)
 {
   struct hash_elem *ptr;
   THREAD *tmp, *last = NULL;
-  int hash;
+  unsigned int hash;
   LIST *subjects = NULL, *oldlist;
   time_t date = 0;  
 
@@ -424,8 +424,8 @@ static THREAD *find_subject (CONTEXT *ctx, THREAD *cur)
 
   while (subjects)
   {
-    hash = hash_string ((unsigned char *) subjects->data,
-                       ctx->subj_hash->nelem);
+    hash = ctx->subj_hash->hash_string ((unsigned char *) subjects->data,
+                                       ctx->subj_hash->nelem);
     for (ptr = ctx->subj_hash->table[hash]; ptr; ptr = ptr->next)
     {
       tmp = ((HEADER *) ptr->data)->thread;
@@ -766,7 +766,7 @@ void mutt_sort_threads (CONTEXT *ctx, int init)
     init = 1;
 
   if (init)
-    ctx->thread_hash = hash_create (ctx->msgcount * 2);
+    ctx->thread_hash = hash_create (ctx->msgcount * 2, 0);
 
   /* we want a quick way to see if things are actually attached to the top of the
    * thread tree or if they're just dangling, so we attach everything to a top
@@ -1319,7 +1319,7 @@ HASH *mutt_make_id_hash (CONTEXT *ctx)
   HEADER *hdr;
   HASH *hash;
 
-  hash = hash_create (ctx->msgcount * 2);
+  hash = hash_create (ctx->msgcount * 2, 0);
 
   for (i = 0; i < ctx->msgcount; i++)
   {
@@ -1337,7 +1337,7 @@ HASH *mutt_make_subj_hash (CONTEXT *ctx)
   HEADER *hdr;
   HASH *hash;
 
-  hash = hash_create (ctx->msgcount * 2);
+  hash = hash_create (ctx->msgcount * 2, 0);
 
   for (i = 0; i < ctx->msgcount; i++)
   {