Fix FSF address (Tobias Mueller, #470445)
[platform/upstream/evolution-data-server.git] / camel / camel-string-utils.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  *  Authors: Jeffrey Stedfast <fejj@ximian.com>
4  *
5  *  Copyright 2002 Ximian, Inc. (www.ximian.com)
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU Lesser General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU Lesser General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Lesser General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <string.h>
29 #include <pthread.h>
30
31 #include "camel-string-utils.h"
32
33 int
34 camel_strcase_equal (gconstpointer a, gconstpointer b)
35 {
36         return (g_ascii_strcasecmp ((const char *) a, (const char *) b) == 0);
37 }
38
39 guint
40 camel_strcase_hash (gconstpointer v)
41 {
42         const char *p = (char *) v;
43         guint h = 0, g;
44         
45         for ( ; *p != '\0'; p++) {
46                 h = (h << 4) + g_ascii_toupper (*p);
47                 if ((g = h & 0xf0000000)) {
48                         h = h ^ (g >> 24);
49                         h = h ^ g;
50                 }
51         }
52         
53         return h;
54 }
55
56
57 static void
58 free_string (gpointer string, gpointer user_data)
59 {
60         g_free (string);
61 }
62
63 void
64 camel_string_list_free (GList *string_list)
65 {
66         if (string_list == NULL)
67                 return; 
68         
69         g_list_foreach (string_list, free_string, NULL);
70         g_list_free (string_list);
71 }
72
73 char *
74 camel_strstrcase (const char *haystack, const char *needle)
75 {
76         /* find the needle in the haystack neglecting case */
77         const char *ptr;
78         guint len;
79         
80         g_return_val_if_fail (haystack != NULL, NULL);
81         g_return_val_if_fail (needle != NULL, NULL);
82         
83         len = strlen (needle);
84         if (len > strlen (haystack))
85                 return NULL;
86         
87         if (len == 0)
88                 return (char *) haystack;
89         
90         for (ptr = haystack; *(ptr + len - 1) != '\0'; ptr++)
91                 if (!g_ascii_strncasecmp (ptr, needle, len))
92                         return (char *) ptr;
93         
94         return NULL;
95 }
96
97
98 const char *
99 camel_strdown (char *str)
100 {
101         register char *s = str;
102         
103         while (*s) {
104                 if (*s >= 'A' && *s <= 'Z')
105                         *s += 0x20;
106                 s++;
107         }
108         
109         return str;
110 }
111
112 /**
113  * camel_tolower:
114  * @c: 
115  * 
116  * ASCII to-lower function.
117  * 
118  * Return value: 
119  **/
120 char camel_tolower(char c)
121 {
122         if (c >= 'A' && c <= 'Z')
123                 c |= 0x20;
124
125         return c;
126 }
127
128 /**
129  * camel_toupper:
130  * @c: 
131  * 
132  * ASCII to-upper function.
133  * 
134  * Return value: 
135  **/
136 char camel_toupper(char c)
137 {
138         if (c >= 'a' && c <= 'z')
139                 c &= ~0x20;
140
141         return c;
142 }
143
144 /* working stuff for pstrings */
145 static pthread_mutex_t pstring_lock = PTHREAD_MUTEX_INITIALIZER;
146 static GHashTable *pstring_table = NULL;
147
148 /**
149  * camel_pstring_add:
150  * @str: string to add to the string pool
151  * @own: whether the string pool will own the memory pointed to by @str, if @str is not yet in the pool
152  *
153  * Add the string to the pool.
154  *
155  * The NULL and empty strings are special cased to constant values.
156  *
157  * Return value: A pointer to an equivalent string of @s.  Use
158  * camel_pstring_free() when it is no longer needed.
159  **/
160 const char *
161 camel_pstring_add (char *str, gboolean own)
162 {
163         void *pcount;
164         char *pstr;
165         int count;
166         
167         if (str == NULL)
168                 return NULL;
169         
170         if (str[0] == '\0') {
171                 if (own)
172                         g_free (str);
173                 return "";
174         }
175         
176         pthread_mutex_lock (&pstring_lock);
177         if (pstring_table == NULL)
178                 pstring_table = g_hash_table_new (g_str_hash, g_str_equal);
179         
180         if (g_hash_table_lookup_extended (pstring_table, str, (void **) &pstr, &pcount)) {
181                 count = GPOINTER_TO_INT (pcount) + 1;
182                 g_hash_table_insert (pstring_table, pstr, GINT_TO_POINTER (count));
183                 if (own)
184                         g_free (str);
185         } else {
186                 pstr = own ? str : g_strdup (str);
187                 g_hash_table_insert (pstring_table, pstr, GINT_TO_POINTER (1));
188         }
189         
190         pthread_mutex_unlock (&pstring_lock);
191         
192         return pstr;
193 }
194
195
196 /**
197  * camel_pstring_strdup:
198  * @s: String to copy.
199  * 
200  * Create a new pooled string entry for the string @s.  A pooled
201  * string is a table where common strings are uniquified to the same
202  * pointer value.  They are also refcounted, so freed when no longer
203  * in use.  In a thread-safe manner.
204  * 
205  * The NULL and empty strings are special cased to constant values.
206  *
207  * Return value: A pointer to an equivalent string of @s.  Use
208  * camel_pstring_free() when it is no longer needed.
209  **/
210 const char *
211 camel_pstring_strdup (const char *s)
212 {
213         return camel_pstring_add ((char *) s, FALSE);
214 }
215
216
217 /**
218  * camel_pstring_free:
219  * @s: String to free.
220  * 
221  * De-ref a pooled string. If no more refs exist to this string, it will be deallocated.
222  *
223  * NULL and the empty string are special cased.
224  **/
225 void
226 camel_pstring_free(const char *s)
227 {
228         char *p;
229         void *pcount;
230         int count;
231
232         if (pstring_table == NULL)
233                 return;
234         if (s == NULL || s[0] == 0)
235                 return;
236
237         pthread_mutex_lock(&pstring_lock);
238         if (g_hash_table_lookup_extended(pstring_table, s, (void **)&p, &pcount)) {
239                 count = GPOINTER_TO_INT(pcount)-1;
240                 if (count == 0) {
241                         g_hash_table_remove(pstring_table, p);
242                         g_free(p);
243                 } else {
244                         g_hash_table_insert(pstring_table, p, GINT_TO_POINTER(count));
245                 }
246         } else {
247                 g_warning("Trying to free string not allocated from the pool '%s'", s);
248         }
249         pthread_mutex_unlock(&pstring_lock);
250 }