aboutsummaryrefslogtreecommitdiffstats
path: root/camel/camel-charset-map.c
diff options
context:
space:
mode:
author2 <NotZed@Ximian.com>2001-10-03 08:12:49 +0800
committerMichael Zucci <zucchi@src.gnome.org>2001-10-03 08:12:49 +0800
commit65014a74aa55209e8e5b65549be26645dabd7cba (patch)
treeb64e6409bde5e0b0310df1928b30fd3d85c831cd /camel/camel-charset-map.c
parent7d2487975feeee0be69890e92fe3eca609fe25c3 (diff)
downloadgsoc2013-evolution-65014a74aa55209e8e5b65549be26645dabd7cba.tar.gz
gsoc2013-evolution-65014a74aa55209e8e5b65549be26645dabd7cba.tar.zst
gsoc2013-evolution-65014a74aa55209e8e5b65549be26645dabd7cba.zip
Change to camel_charset_iconv_open/close.
2001-10-02 <NotZed@Ximian.com> * camel-sasl-digest-md5.c (digest_response): Change to camel_charset_iconv_open/close. * camel-pgp-context.c (pgp_verify): Change to camel_charset_iconv_open/close. * camel-mime-part-utils.c (convert_buffer): Change to camel_charset_iconv_open(). * camel-mime-filter-charset.c (camel_mime_filter_charset_new_convert, finalise): Change to camel_charset_iconv_open, etc. * camel-mime-utils.c: Use the camel_charset_iconv_open/close() functions to open/close it. * camel-charset-map.c (camel_charset_iconv_open): New function, wrap iconv_open, so we can cache ic's. (camel_charset_iconv_close): Likewise for close. (camel_charset_map_init,shutdown): Init/free iconv cache. svn path=/trunk/; revision=13361
Diffstat (limited to 'camel/camel-charset-map.c')
-rw-r--r--camel/camel-charset-map.c160
1 files changed, 159 insertions, 1 deletions
diff --git a/camel/camel-charset-map.c b/camel/camel-charset-map.c
index d25cf2cabc..39904b71e3 100644
--- a/camel/camel-charset-map.c
+++ b/camel/camel-charset-map.c
@@ -203,10 +203,15 @@ void main(void)
#include <string.h>
#include <ctype.h>
#include <glib.h>
+#include <e-util/e-msgport.h>
#ifdef ENABLE_THREADS
#include <pthread.h>
#endif
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#endif
+#define cd(x) /* 'cache debug' */
#ifdef ENABLE_THREADS
static pthread_mutex_t iconv_charsets_lock = PTHREAD_MUTEX_INITIALIZER;
@@ -217,6 +222,25 @@ static pthread_mutex_t iconv_charsets_lock = PTHREAD_MUTEX_INITIALIZER;
#define ICONV_CHARSETS_UNLOCK()
#endif /* ENABLE_THREADS */
+struct _iconv_cache_node {
+ EDListNode ln;
+
+ iconv_t ip;
+};
+
+struct _iconv_cache {
+ EDListNode ln;
+
+ char *conv;
+
+ EDList inuse; /* opened ic's in use - if both these lists empty == failed to open conversion */
+ EDList free; /* opened ic's free */
+};
+
+#define CAMEL_ICONV_CACHE_SIZE (16)
+
+static EDList iconv_cache_list;
+
static GHashTable *iconv_charsets = NULL;
static char *locale_charset = NULL;
@@ -252,11 +276,40 @@ shutdown_foreach (gpointer key, gpointer value, gpointer data)
}
static void
+flush_iconv_entry(struct _iconv_cache *ic)
+{
+ struct _iconv_cache_node *node;
+
+ cd(printf("Flushing iconv cache entry: %s\n", ic->conv));
+
+ while ( (node = (struct _iconv_cache_node *)e_dlist_remhead(&ic->inuse)) ) {
+ iconv_close(node->ip);
+ g_free(node);
+ }
+ while ( (node = (struct _iconv_cache_node *)e_dlist_remhead(&ic->free)) ) {
+ iconv_close(node->ip);
+ g_free(node);
+ }
+ g_free(ic->conv);
+ g_free(ic);
+}
+
+static void
camel_charset_map_shutdown (void)
{
+ struct _iconv_cache *ic, *in;
+
g_hash_table_foreach (iconv_charsets, shutdown_foreach, NULL);
g_hash_table_destroy (iconv_charsets);
g_free (locale_charset);
+
+ ic = (struct _iconv_cache *)iconv_cache_list.head;
+ in = (struct _iconv_cache *)ic->ln.next;
+ while (in) {
+ flush_iconv_entry(ic);
+ ic = in;
+ in = (struct _iconv_cache *)in->ln.next;
+ }
}
void
@@ -273,7 +326,9 @@ camel_charset_map_init (void)
g_hash_table_insert (iconv_charsets, g_strdup (known_iconv_charsets[i].charset),
g_strdup (known_iconv_charsets[i].iconv_name));
}
-
+
+ e_dlist_init(&iconv_cache_list);
+
locale = setlocale (LC_ALL, NULL);
if (!locale || !strcmp (locale, "C") || !strcmp (locale, "POSIX")) {
@@ -439,5 +494,108 @@ camel_charset_to_iconv (const char *name)
return charset;
}
+iconv_t camel_charset_iconv_open(const char *oto, const char *ofrom)
+{
+ const char *to, *from;
+ char *tofrom;
+ struct _iconv_cache *ic, *icnew = NULL;
+ struct _iconv_cache_node *node;
+ iconv_t ip;
+
+ to = camel_charset_to_iconv(oto);
+ from = camel_charset_to_iconv(ofrom);
+ tofrom = alloca(strlen(to) +strlen(from) + 1);
+ sprintf(tofrom, "%s%s", to, from);
+
+ ICONV_CHARSETS_LOCK();
+ ic = (struct _iconv_cache *)iconv_cache_list.head;
+ while (ic->ln.next) {
+ if (!strcasecmp(ic->conv, tofrom))
+ break;
+ ic = (struct _iconv_cache *)ic->ln.next;
+ }
+
+ if (ic->ln.next == NULL) {
+ int extra = e_dlist_length(&iconv_cache_list) - CAMEL_ICONV_CACHE_SIZE;
+ struct _iconv_cache *old = (struct _iconv_cache *)iconv_cache_list.head,
+ *next = (struct _iconv_cache *)old->ln.next;
+
+ /* flush any 'old' entries out, if we can */
+ while (extra>0 && next) {
+ if (e_dlist_empty(&old->inuse)) {
+ e_dlist_remove(&old->ln);
+ flush_iconv_entry(old);
+ extra--;
+ }
+ old = next;
+ next = (struct _iconv_cache *)old->ln.next;
+ }
+
+ icnew = ic = g_malloc(sizeof(*ic));
+ e_dlist_init(&ic->inuse);
+ e_dlist_init(&ic->free);
+ ic->conv = g_strdup(tofrom);
+ } else {
+ e_dlist_remove(&ic->ln);
+ }
+
+ node = (struct _iconv_cache_node *)e_dlist_remhead(&ic->free);
+ if (node) {
+ cd(printf("Returning cached success of: %s to %s\n", from, to));
+ e_dlist_addhead(&ic->inuse, &node->ln);
+ ip = node->ip;
+ } else {
+ if (e_dlist_empty(&ic->inuse) && icnew == NULL) {
+ cd(printf("returning cached failure of conversion: %s to %s\n", from, to));
+ ip = (iconv_t)-1;
+ } else {
+ ip = iconv_open(to, from);
+ if (ip != (iconv_t)-1) {
+ cd(printf("Creating cached opening of: %s to %s = %p\n", from, to, ip));
+ node = g_malloc(sizeof(*node));
+ node->ip = ip;
+ e_dlist_addhead(&ic->inuse, &node->ln);
+ }
+ }
+ }
+
+ e_dlist_addtail(&iconv_cache_list, &ic->ln);
+
+ ICONV_CHARSETS_UNLOCK();
+
+ return ip;
+}
+
+void camel_charset_iconv_close(iconv_t ip)
+{
+ struct _iconv_cache *ic;
+ struct _iconv_cache_node *node;
+
+ if (ip == (iconv_t)-1)
+ return;
+
+ ICONV_CHARSETS_LOCK();
+ ic = (struct _iconv_cache *)iconv_cache_list.tailpred;
+ while (ic->ln.prev) {
+ cd(printf("closing iconv %p, checking against name '%s'\n", ip, ic->conv));
+ node = (struct _iconv_cache_node *)ic->inuse.head;
+ while (node->ln.next) {
+ cd(printf("closing iconv %p, checking against node '%p'\n", ip, node->ip));
+ if (node->ip == ip) {
+ e_dlist_remove(&node->ln);
+ e_dlist_addhead(&ic->free, &node->ln);
+ ICONV_CHARSETS_UNLOCK();
+ return;
+ }
+ node = (struct _iconv_cache_node *)node->ln.next;
+ }
+ ic = (struct _iconv_cache *)ic->ln.prev;
+ }
+
+ ICONV_CHARSETS_UNLOCK();
+
+ g_warning("Trying to close iconv i dont know about: %p", ip);
+}
+
#endif /* !BUILD_MAP */