Audacious
$Id:Doxyfile42802007-03-2104:39:00Znenolod$
|
00001 /* 00002 * strpool.c 00003 * Copyright 2011 John Lindgren 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions are met: 00007 * 00008 * 1. Redistributions of source code must retain the above copyright notice, 00009 * this list of conditions, and the following disclaimer. 00010 * 00011 * 2. Redistributions in binary form must reproduce the above copyright notice, 00012 * this list of conditions, and the following disclaimer in the documentation 00013 * provided with the distribution. 00014 * 00015 * This software is provided "as is" and without any warranty, express or 00016 * implied. In no event shall the authors be liable for any damages arising from 00017 * the use of this software. 00018 */ 00019 00020 #include <glib.h> 00021 #include <pthread.h> 00022 #include <stdarg.h> 00023 #include <stdio.h> 00024 #include <stdint.h> 00025 #include <stdlib.h> 00026 #include <string.h> 00027 00028 #include "config.h" 00029 #include "core.h" 00030 00031 /* Each string in the pool is allocated with five leading bytes: a 32-bit 00032 * reference count and a one-byte signature, the '@' character. */ 00033 00034 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 00035 static GHashTable * table; 00036 00037 #ifdef STRPOOL_DEBUG 00038 static GHashTable * logged; 00039 00040 static void str_log (const char * str, const char * op, const char * file, int line) 00041 { 00042 if (! logged) 00043 logged = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); 00044 00045 GList * list = g_hash_table_lookup (logged, str); 00046 list = g_list_prepend (list, g_strdup_printf ("%s by %s:%d", op, file, line)); 00047 g_hash_table_insert (logged, g_strdup (str), list); 00048 } 00049 00050 static void str_log_dump (const char * str) 00051 { 00052 if (! logged) 00053 return; 00054 00055 for (GList * node = g_hash_table_lookup (logged, str); node; node = node->next) 00056 printf (" - %s\n", (char *) node->data); 00057 } 00058 #endif 00059 00060 static void str_destroy (void * str) 00061 { 00062 * ((char *) str - 1) = 0; 00063 free ((char *) str - 5); 00064 } 00065 00066 #ifdef STRPOOL_DEBUG 00067 EXPORT char * str_get_debug (const char * str, const char * file, int line) 00068 #else 00069 EXPORT char * str_get (const char * str) 00070 #endif 00071 { 00072 if (! str) 00073 return NULL; 00074 00075 char * copy; 00076 pthread_mutex_lock (& mutex); 00077 00078 #ifdef STRPOOL_DEBUG 00079 str_log (str, "get", file, line); 00080 #endif 00081 00082 if (! table) 00083 table = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, str_destroy); 00084 00085 if ((copy = g_hash_table_lookup (table, str))) 00086 { 00087 void * mem = copy - 5; 00088 (* (int32_t *) mem) ++; 00089 } 00090 else 00091 { 00092 void * mem = malloc (6 + strlen (str)); 00093 (* (int32_t *) mem) = 1; 00094 00095 copy = (char *) mem + 5; 00096 copy[-1] = '@'; 00097 strcpy (copy, str); 00098 00099 g_hash_table_insert (table, copy, copy); 00100 } 00101 00102 pthread_mutex_unlock (& mutex); 00103 return copy; 00104 } 00105 00106 #ifdef STRPOOL_DEBUG 00107 EXPORT char * str_ref_debug (char * str, const char * file, int line) 00108 #else 00109 EXPORT char * str_ref (char * str) 00110 #endif 00111 { 00112 if (! str) 00113 return NULL; 00114 00115 pthread_mutex_lock (& mutex); 00116 STR_CHECK (str); 00117 00118 #ifdef STRPOOL_DEBUG 00119 str_log (str, "ref", file, line); 00120 #endif 00121 00122 void * mem = str - 5; 00123 (* (int32_t *) mem) ++; 00124 00125 pthread_mutex_unlock (& mutex); 00126 return str; 00127 } 00128 00129 #ifdef STRPOOL_DEBUG 00130 EXPORT void str_unref_debug (char * str, const char * file, int line) 00131 #else 00132 EXPORT void str_unref (char * str) 00133 #endif 00134 { 00135 if (! str) 00136 return; 00137 00138 pthread_mutex_lock (& mutex); 00139 STR_CHECK (str); 00140 00141 #ifdef STRPOOL_DEBUG 00142 str_log (str, "unref", file, line); 00143 #endif 00144 00145 void * mem = str - 5; 00146 if (! -- (* (int32_t *) mem)) 00147 g_hash_table_remove (table, str); 00148 00149 pthread_mutex_unlock (& mutex); 00150 } 00151 00152 EXPORT char * str_nget (const char * str, int len) 00153 { 00154 if (strlen (str) <= len) 00155 return str_get (str); 00156 00157 char buf[len + 1]; 00158 memcpy (buf, str, len); 00159 buf[len] = 0; 00160 00161 return str_get (buf); 00162 } 00163 00164 EXPORT char * str_printf (const char * format, ...) 00165 { 00166 va_list args; 00167 00168 va_start (args, format); 00169 int len = vsnprintf (NULL, 0, format, args); 00170 va_end (args); 00171 00172 char buf[len + 1]; 00173 00174 va_start (args, format); 00175 vsnprintf (buf, sizeof buf, format, args); 00176 va_end (args); 00177 00178 return str_get (buf); 00179 } 00180 00181 EXPORT void strpool_abort (char * str) 00182 { 00183 fprintf (stderr, "String not in pool: %s\n", str); 00184 #ifdef STRPOOL_DEBUG 00185 str_log_dump (str); 00186 #endif 00187 abort (); 00188 } 00189 00190 static void str_leaked (void * key, void * str, void * unused) 00191 { 00192 fprintf (stderr, "String not freed: %s\n", (char *) str); 00193 #ifdef STRPOOL_DEBUG 00194 str_log_dump (str); 00195 #endif 00196 } 00197 00198 EXPORT void strpool_shutdown (void) 00199 { 00200 if (! table) 00201 return; 00202 00203 g_hash_table_foreach (table, str_leaked, NULL); 00204 g_hash_table_destroy (table); 00205 table = NULL; 00206 }