1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/testing/mozbase/mozprocess/tests/iniparser/dictionary.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,407 @@ 1.4 +/*-------------------------------------------------------------------------*/ 1.5 +/** 1.6 + @file dictionary.c 1.7 + @author N. Devillard 1.8 + @date Sep 2007 1.9 + @version $Revision: 1.27 $ 1.10 + @brief Implements a dictionary for string variables. 1.11 + 1.12 + This module implements a simple dictionary object, i.e. a list 1.13 + of string/string associations. This object is useful to store e.g. 1.14 + informations retrieved from a configuration file (ini files). 1.15 +*/ 1.16 +/*--------------------------------------------------------------------------*/ 1.17 + 1.18 +/* 1.19 + $Id: dictionary.c,v 1.27 2007-11-23 21:39:18 ndevilla Exp $ 1.20 + $Revision: 1.27 $ 1.21 +*/ 1.22 +/*--------------------------------------------------------------------------- 1.23 + Includes 1.24 + ---------------------------------------------------------------------------*/ 1.25 +#include "dictionary.h" 1.26 + 1.27 +#include <stdio.h> 1.28 +#include <stdlib.h> 1.29 +#include <string.h> 1.30 +#ifndef _WIN32 1.31 +#include <unistd.h> 1.32 +#endif 1.33 + 1.34 +/** Maximum value size for integers and doubles. */ 1.35 +#define MAXVALSZ 1024 1.36 + 1.37 +/** Minimal allocated number of entries in a dictionary */ 1.38 +#define DICTMINSZ 128 1.39 + 1.40 +/** Invalid key token */ 1.41 +#define DICT_INVALID_KEY ((char*)-1) 1.42 + 1.43 +/*--------------------------------------------------------------------------- 1.44 + Private functions 1.45 + ---------------------------------------------------------------------------*/ 1.46 + 1.47 +/* Doubles the allocated size associated to a pointer */ 1.48 +/* 'size' is the current allocated size. */ 1.49 +static void * mem_double(void * ptr, int size) 1.50 +{ 1.51 + void * newptr ; 1.52 + 1.53 + newptr = calloc(2*size, 1); 1.54 + if (newptr==NULL) { 1.55 + return NULL ; 1.56 + } 1.57 + memcpy(newptr, ptr, size); 1.58 + free(ptr); 1.59 + return newptr ; 1.60 +} 1.61 + 1.62 +/*-------------------------------------------------------------------------*/ 1.63 +/** 1.64 + @brief Duplicate a string 1.65 + @param s String to duplicate 1.66 + @return Pointer to a newly allocated string, to be freed with free() 1.67 + 1.68 + This is a replacement for strdup(). This implementation is provided 1.69 + for systems that do not have it. 1.70 + */ 1.71 +/*--------------------------------------------------------------------------*/ 1.72 +static char * xstrdup(char * s) 1.73 +{ 1.74 + char * t ; 1.75 + if (!s) 1.76 + return NULL ; 1.77 + t = malloc(strlen(s)+1) ; 1.78 + if (t) { 1.79 + strcpy(t,s); 1.80 + } 1.81 + return t ; 1.82 +} 1.83 + 1.84 +/*--------------------------------------------------------------------------- 1.85 + Function codes 1.86 + ---------------------------------------------------------------------------*/ 1.87 +/*-------------------------------------------------------------------------*/ 1.88 +/** 1.89 + @brief Compute the hash key for a string. 1.90 + @param key Character string to use for key. 1.91 + @return 1 unsigned int on at least 32 bits. 1.92 + 1.93 + This hash function has been taken from an Article in Dr Dobbs Journal. 1.94 + This is normally a collision-free function, distributing keys evenly. 1.95 + The key is stored anyway in the struct so that collision can be avoided 1.96 + by comparing the key itself in last resort. 1.97 + */ 1.98 +/*--------------------------------------------------------------------------*/ 1.99 +unsigned dictionary_hash(char * key) 1.100 +{ 1.101 + int len ; 1.102 + unsigned hash ; 1.103 + int i ; 1.104 + 1.105 + len = strlen(key); 1.106 + for (hash=0, i=0 ; i<len ; i++) { 1.107 + hash += (unsigned)key[i] ; 1.108 + hash += (hash<<10); 1.109 + hash ^= (hash>>6) ; 1.110 + } 1.111 + hash += (hash <<3); 1.112 + hash ^= (hash >>11); 1.113 + hash += (hash <<15); 1.114 + return hash ; 1.115 +} 1.116 + 1.117 +/*-------------------------------------------------------------------------*/ 1.118 +/** 1.119 + @brief Create a new dictionary object. 1.120 + @param size Optional initial size of the dictionary. 1.121 + @return 1 newly allocated dictionary objet. 1.122 + 1.123 + This function allocates a new dictionary object of given size and returns 1.124 + it. If you do not know in advance (roughly) the number of entries in the 1.125 + dictionary, give size=0. 1.126 + */ 1.127 +/*--------------------------------------------------------------------------*/ 1.128 +dictionary * dictionary_new(int size) 1.129 +{ 1.130 + dictionary * d ; 1.131 + 1.132 + /* If no size was specified, allocate space for DICTMINSZ */ 1.133 + if (size<DICTMINSZ) size=DICTMINSZ ; 1.134 + 1.135 + if (!(d = (dictionary *)calloc(1, sizeof(dictionary)))) { 1.136 + return NULL; 1.137 + } 1.138 + d->size = size ; 1.139 + d->val = (char **)calloc(size, sizeof(char*)); 1.140 + d->key = (char **)calloc(size, sizeof(char*)); 1.141 + d->hash = (unsigned int *)calloc(size, sizeof(unsigned)); 1.142 + return d ; 1.143 +} 1.144 + 1.145 +/*-------------------------------------------------------------------------*/ 1.146 +/** 1.147 + @brief Delete a dictionary object 1.148 + @param d dictionary object to deallocate. 1.149 + @return void 1.150 + 1.151 + Deallocate a dictionary object and all memory associated to it. 1.152 + */ 1.153 +/*--------------------------------------------------------------------------*/ 1.154 +void dictionary_del(dictionary * d) 1.155 +{ 1.156 + int i ; 1.157 + 1.158 + if (d==NULL) return ; 1.159 + for (i=0 ; i<d->size ; i++) { 1.160 + if (d->key[i]!=NULL) 1.161 + free(d->key[i]); 1.162 + if (d->val[i]!=NULL) 1.163 + free(d->val[i]); 1.164 + } 1.165 + free(d->val); 1.166 + free(d->key); 1.167 + free(d->hash); 1.168 + free(d); 1.169 + return ; 1.170 +} 1.171 + 1.172 +/*-------------------------------------------------------------------------*/ 1.173 +/** 1.174 + @brief Get a value from a dictionary. 1.175 + @param d dictionary object to search. 1.176 + @param key Key to look for in the dictionary. 1.177 + @param def Default value to return if key not found. 1.178 + @return 1 pointer to internally allocated character string. 1.179 + 1.180 + This function locates a key in a dictionary and returns a pointer to its 1.181 + value, or the passed 'def' pointer if no such key can be found in 1.182 + dictionary. The returned character pointer points to data internal to the 1.183 + dictionary object, you should not try to free it or modify it. 1.184 + */ 1.185 +/*--------------------------------------------------------------------------*/ 1.186 +char * dictionary_get(dictionary * d, char * key, char * def) 1.187 +{ 1.188 + unsigned hash ; 1.189 + int i ; 1.190 + 1.191 + hash = dictionary_hash(key); 1.192 + for (i=0 ; i<d->size ; i++) { 1.193 + if (d->key[i]==NULL) 1.194 + continue ; 1.195 + /* Compare hash */ 1.196 + if (hash==d->hash[i]) { 1.197 + /* Compare string, to avoid hash collisions */ 1.198 + if (!strcmp(key, d->key[i])) { 1.199 + return d->val[i] ; 1.200 + } 1.201 + } 1.202 + } 1.203 + return def ; 1.204 +} 1.205 + 1.206 +/*-------------------------------------------------------------------------*/ 1.207 +/** 1.208 + @brief Set a value in a dictionary. 1.209 + @param d dictionary object to modify. 1.210 + @param key Key to modify or add. 1.211 + @param val Value to add. 1.212 + @return int 0 if Ok, anything else otherwise 1.213 + 1.214 + If the given key is found in the dictionary, the associated value is 1.215 + replaced by the provided one. If the key cannot be found in the 1.216 + dictionary, it is added to it. 1.217 + 1.218 + It is Ok to provide a NULL value for val, but NULL values for the dictionary 1.219 + or the key are considered as errors: the function will return immediately 1.220 + in such a case. 1.221 + 1.222 + Notice that if you dictionary_set a variable to NULL, a call to 1.223 + dictionary_get will return a NULL value: the variable will be found, and 1.224 + its value (NULL) is returned. In other words, setting the variable 1.225 + content to NULL is equivalent to deleting the variable from the 1.226 + dictionary. It is not possible (in this implementation) to have a key in 1.227 + the dictionary without value. 1.228 + 1.229 + This function returns non-zero in case of failure. 1.230 + */ 1.231 +/*--------------------------------------------------------------------------*/ 1.232 +int dictionary_set(dictionary * d, char * key, char * val) 1.233 +{ 1.234 + int i ; 1.235 + unsigned hash ; 1.236 + 1.237 + if (d==NULL || key==NULL) return -1 ; 1.238 + 1.239 + /* Compute hash for this key */ 1.240 + hash = dictionary_hash(key) ; 1.241 + /* Find if value is already in dictionary */ 1.242 + if (d->n>0) { 1.243 + for (i=0 ; i<d->size ; i++) { 1.244 + if (d->key[i]==NULL) 1.245 + continue ; 1.246 + if (hash==d->hash[i]) { /* Same hash value */ 1.247 + if (!strcmp(key, d->key[i])) { /* Same key */ 1.248 + /* Found a value: modify and return */ 1.249 + if (d->val[i]!=NULL) 1.250 + free(d->val[i]); 1.251 + d->val[i] = val ? xstrdup(val) : NULL ; 1.252 + /* Value has been modified: return */ 1.253 + return 0 ; 1.254 + } 1.255 + } 1.256 + } 1.257 + } 1.258 + /* Add a new value */ 1.259 + /* See if dictionary needs to grow */ 1.260 + if (d->n==d->size) { 1.261 + 1.262 + /* Reached maximum size: reallocate dictionary */ 1.263 + d->val = (char **)mem_double(d->val, d->size * sizeof(char*)) ; 1.264 + d->key = (char **)mem_double(d->key, d->size * sizeof(char*)) ; 1.265 + d->hash = (unsigned int *)mem_double(d->hash, d->size * sizeof(unsigned)) ; 1.266 + if ((d->val==NULL) || (d->key==NULL) || (d->hash==NULL)) { 1.267 + /* Cannot grow dictionary */ 1.268 + return -1 ; 1.269 + } 1.270 + /* Double size */ 1.271 + d->size *= 2 ; 1.272 + } 1.273 + 1.274 + /* Insert key in the first empty slot */ 1.275 + for (i=0 ; i<d->size ; i++) { 1.276 + if (d->key[i]==NULL) { 1.277 + /* Add key here */ 1.278 + break ; 1.279 + } 1.280 + } 1.281 + /* Copy key */ 1.282 + d->key[i] = xstrdup(key); 1.283 + d->val[i] = val ? xstrdup(val) : NULL ; 1.284 + d->hash[i] = hash; 1.285 + d->n ++ ; 1.286 + return 0 ; 1.287 +} 1.288 + 1.289 +/*-------------------------------------------------------------------------*/ 1.290 +/** 1.291 + @brief Delete a key in a dictionary 1.292 + @param d dictionary object to modify. 1.293 + @param key Key to remove. 1.294 + @return void 1.295 + 1.296 + This function deletes a key in a dictionary. Nothing is done if the 1.297 + key cannot be found. 1.298 + */ 1.299 +/*--------------------------------------------------------------------------*/ 1.300 +void dictionary_unset(dictionary * d, char * key) 1.301 +{ 1.302 + unsigned hash ; 1.303 + int i ; 1.304 + 1.305 + if (key == NULL) { 1.306 + return; 1.307 + } 1.308 + 1.309 + hash = dictionary_hash(key); 1.310 + for (i=0 ; i<d->size ; i++) { 1.311 + if (d->key[i]==NULL) 1.312 + continue ; 1.313 + /* Compare hash */ 1.314 + if (hash==d->hash[i]) { 1.315 + /* Compare string, to avoid hash collisions */ 1.316 + if (!strcmp(key, d->key[i])) { 1.317 + /* Found key */ 1.318 + break ; 1.319 + } 1.320 + } 1.321 + } 1.322 + if (i>=d->size) 1.323 + /* Key not found */ 1.324 + return ; 1.325 + 1.326 + free(d->key[i]); 1.327 + d->key[i] = NULL ; 1.328 + if (d->val[i]!=NULL) { 1.329 + free(d->val[i]); 1.330 + d->val[i] = NULL ; 1.331 + } 1.332 + d->hash[i] = 0 ; 1.333 + d->n -- ; 1.334 + return ; 1.335 +} 1.336 + 1.337 +/*-------------------------------------------------------------------------*/ 1.338 +/** 1.339 + @brief Dump a dictionary to an opened file pointer. 1.340 + @param d Dictionary to dump 1.341 + @param f Opened file pointer. 1.342 + @return void 1.343 + 1.344 + Dumps a dictionary onto an opened file pointer. Key pairs are printed out 1.345 + as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as 1.346 + output file pointers. 1.347 + */ 1.348 +/*--------------------------------------------------------------------------*/ 1.349 +void dictionary_dump(dictionary * d, FILE * out) 1.350 +{ 1.351 + int i ; 1.352 + 1.353 + if (d==NULL || out==NULL) return ; 1.354 + if (d->n<1) { 1.355 + fprintf(out, "empty dictionary\n"); 1.356 + return ; 1.357 + } 1.358 + for (i=0 ; i<d->size ; i++) { 1.359 + if (d->key[i]) { 1.360 + fprintf(out, "%20s\t[%s]\n", 1.361 + d->key[i], 1.362 + d->val[i] ? d->val[i] : "UNDEF"); 1.363 + } 1.364 + } 1.365 + return ; 1.366 +} 1.367 + 1.368 + 1.369 +/* Test code */ 1.370 +#ifdef TESTDIC 1.371 +#define NVALS 20000 1.372 +int main(int argc, char *argv[]) 1.373 +{ 1.374 + dictionary * d ; 1.375 + char * val ; 1.376 + int i ; 1.377 + char cval[90] ; 1.378 + 1.379 + /* Allocate dictionary */ 1.380 + printf("allocating...\n"); 1.381 + d = dictionary_new(0); 1.382 + 1.383 + /* Set values in dictionary */ 1.384 + printf("setting %d values...\n", NVALS); 1.385 + for (i=0 ; i<NVALS ; i++) { 1.386 + sprintf(cval, "%04d", i); 1.387 + dictionary_set(d, cval, "salut"); 1.388 + } 1.389 + printf("getting %d values...\n", NVALS); 1.390 + for (i=0 ; i<NVALS ; i++) { 1.391 + sprintf(cval, "%04d", i); 1.392 + val = dictionary_get(d, cval, DICT_INVALID_KEY); 1.393 + if (val==DICT_INVALID_KEY) { 1.394 + printf("cannot get value for key [%s]\n", cval); 1.395 + } 1.396 + } 1.397 + printf("unsetting %d values...\n", NVALS); 1.398 + for (i=0 ; i<NVALS ; i++) { 1.399 + sprintf(cval, "%04d", i); 1.400 + dictionary_unset(d, cval); 1.401 + } 1.402 + if (d->n != 0) { 1.403 + printf("error deleting values\n"); 1.404 + } 1.405 + printf("deallocating...\n"); 1.406 + dictionary_del(d); 1.407 + return 0 ; 1.408 +} 1.409 +#endif 1.410 +/* vim: set ts=4 et sw=4 tw=75 */