1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Authors: Jeffrey Stedfast <fejj@ximian.com>
5 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
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.
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.
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.
29 #include "camel-string-utils.h"
32 camel_strcase_equal (gconstpointer a,
35 return (g_ascii_strcasecmp ((const gchar *) a, (const gchar *) b) == 0);
39 camel_strcase_hash (gconstpointer v)
41 const gchar *p = (gchar *) v;
44 for (; *p != '\0'; p++) {
45 h = (h << 4) + g_ascii_toupper (*p);
46 if ((g = h & 0xf0000000)) {
56 free_string (gpointer string,
63 camel_string_list_free (GList *string_list)
65 if (string_list == NULL)
68 g_list_foreach (string_list, free_string, NULL);
69 g_list_free (string_list);
73 camel_strstrcase (const gchar *haystack,
76 /* find the needle in the haystack neglecting case */
80 g_return_val_if_fail (haystack != NULL, NULL);
81 g_return_val_if_fail (needle != NULL, NULL);
83 len = strlen (needle);
84 if (len > strlen (haystack))
88 return (gchar *) haystack;
90 for (ptr = haystack; *(ptr + len - 1) != '\0'; ptr++)
91 if (!g_ascii_strncasecmp (ptr, needle, len))
98 camel_strdown (gchar *str)
100 register gchar *s = str;
103 if (*s >= 'A' && *s <= 'Z')
115 * ASCII to-lower function.
119 gchar camel_tolower (gchar c)
121 if (c >= 'A' && c <= 'Z')
131 * ASCII to-upper function.
135 gchar camel_toupper (gchar c)
137 if (c >= 'a' && c <= 'z')
143 /* working stuff for pstrings */
144 static GMutex string_pool_lock;
145 static GHashTable *string_pool = NULL;
147 typedef struct _StringPoolNode StringPoolNode;
149 struct _StringPoolNode {
154 static StringPoolNode *
155 string_pool_node_new (gchar *string)
157 StringPoolNode *node;
159 node = g_slice_new (StringPoolNode);
160 node->string = string; /* takes ownership */
167 string_pool_node_free (StringPoolNode *node)
169 g_free (node->string);
171 g_slice_free (StringPoolNode, node);
175 string_pool_node_hash (const StringPoolNode *node)
177 return g_str_hash (node->string);
181 string_pool_node_equal (const StringPoolNode *node_a,
182 const StringPoolNode *node_b)
184 return g_str_equal (node_a->string, node_b->string);
188 string_pool_init (void)
190 if (G_UNLIKELY (string_pool == NULL))
191 string_pool = g_hash_table_new_full (
192 (GHashFunc) string_pool_node_hash,
193 (GEqualFunc) string_pool_node_equal,
194 (GDestroyNotify) string_pool_node_free,
195 (GDestroyNotify) NULL);
200 * @string: string to add to the string pool
201 * @own: whether the string pool will own the memory pointed to by
202 * @string, if @string is not yet in the pool
204 * Add @string to the pool.
206 * The %NULL and empty strings are special cased to constant values.
208 * Unreference the returned string with camel_pstring_free().
210 * Returns: a canonicalized copy of @string
213 camel_pstring_add (gchar *string,
216 StringPoolNode static_node = { string, };
217 StringPoolNode *node;
218 const gchar *interned;
223 if (*string == '\0') {
229 g_mutex_lock (&string_pool_lock);
233 node = g_hash_table_lookup (string_pool, &static_node);
241 string = g_strdup (string);
242 node = string_pool_node_new (string);
243 g_hash_table_add (string_pool, node);
246 interned = node->string;
248 g_mutex_unlock (&string_pool_lock);
254 * camel_pstring_peek:
255 * @string: string to fetch from the string pool
257 * Returns the canonicalized copy of @string without increasing its
258 * reference count in the string pool. If necessary, @string is first
259 * added to the string pool.
261 * The %NULL and empty strings are special cased to constant values.
263 * Returns: a canonicalized copy of @string
268 camel_pstring_peek (const gchar *string)
270 StringPoolNode static_node = { (gchar *) string, };
271 StringPoolNode *node;
272 const gchar *interned;
280 g_mutex_lock (&string_pool_lock);
284 node = g_hash_table_lookup (string_pool, &static_node);
287 node = string_pool_node_new (g_strdup (string));
288 g_hash_table_add (string_pool, node);
291 interned = node->string;
293 g_mutex_unlock (&string_pool_lock);
299 * camel_pstring_strdup:
300 * @string: string to copy
302 * Create a new pooled string entry for @strings. A pooled string
303 * is a table where common strings are canonicalized. They are also
304 * reference counted and freed when no longer referenced.
306 * The %NULL and empty strings are special cased to constant values.
308 * Unreference the returned string with camel_pstring_free().
310 * Returns: a canonicalized copy of @string
313 camel_pstring_strdup (const gchar *string)
315 return camel_pstring_add ((gchar *) string, FALSE);
319 * camel_pstring_free:
320 * @string: string to free
322 * Unreferences a pooled string. If the string's reference count drops to
323 * zero it will be deallocated. %NULL and the empty string are special cased.
326 camel_pstring_free (const gchar *string)
328 StringPoolNode static_node = { (gchar *) string, };
329 StringPoolNode *node;
331 if (string_pool == NULL)
334 if (string == NULL || *string == '\0')
337 g_mutex_lock (&string_pool_lock);
339 node = g_hash_table_lookup (string_pool, &static_node);
342 g_warning ("%s: String not in pool: %s", G_STRFUNC, string);
343 } else if (node->string != string) {
344 g_warning ("%s: String is not ours: %s", G_STRFUNC, string);
345 } else if (node->ref_count == 0) {
346 g_warning ("%s: Orphaned pool node: %s", G_STRFUNC, string);
349 if (node->ref_count == 0)
350 g_hash_table_remove (string_pool, node);
353 g_mutex_unlock (&string_pool_lock);
357 * camel_pstring_dump_stat:
359 * Dumps to stdout memory statistic about the string pool.
364 camel_pstring_dump_stat (void)
366 g_mutex_lock (&string_pool_lock);
368 g_print (" String Pool Statistics: ");
370 if (string_pool == NULL) {
371 g_print ("Not used yet\n");
378 g_hash_table_iter_init (&iter, string_pool);
380 while (g_hash_table_iter_next (&iter, &key, NULL))
381 bytes += strlen (((StringPoolNode *) key)->string);
383 format_size = g_format_size_full (
384 bytes, G_FORMAT_SIZE_LONG_FORMAT);
387 "Holds %d strings totaling %s\n",
388 g_hash_table_size (string_pool),
391 g_free (format_size);
394 g_mutex_unlock (&string_pool_lock);