testing/mozbase/mozprocess/tests/iniparser/dictionary.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /*-------------------------------------------------------------------------*/
michael@0 2 /**
michael@0 3 @file dictionary.c
michael@0 4 @author N. Devillard
michael@0 5 @date Sep 2007
michael@0 6 @version $Revision: 1.27 $
michael@0 7 @brief Implements a dictionary for string variables.
michael@0 8
michael@0 9 This module implements a simple dictionary object, i.e. a list
michael@0 10 of string/string associations. This object is useful to store e.g.
michael@0 11 informations retrieved from a configuration file (ini files).
michael@0 12 */
michael@0 13 /*--------------------------------------------------------------------------*/
michael@0 14
michael@0 15 /*
michael@0 16 $Id: dictionary.c,v 1.27 2007-11-23 21:39:18 ndevilla Exp $
michael@0 17 $Revision: 1.27 $
michael@0 18 */
michael@0 19 /*---------------------------------------------------------------------------
michael@0 20 Includes
michael@0 21 ---------------------------------------------------------------------------*/
michael@0 22 #include "dictionary.h"
michael@0 23
michael@0 24 #include <stdio.h>
michael@0 25 #include <stdlib.h>
michael@0 26 #include <string.h>
michael@0 27 #ifndef _WIN32
michael@0 28 #include <unistd.h>
michael@0 29 #endif
michael@0 30
michael@0 31 /** Maximum value size for integers and doubles. */
michael@0 32 #define MAXVALSZ 1024
michael@0 33
michael@0 34 /** Minimal allocated number of entries in a dictionary */
michael@0 35 #define DICTMINSZ 128
michael@0 36
michael@0 37 /** Invalid key token */
michael@0 38 #define DICT_INVALID_KEY ((char*)-1)
michael@0 39
michael@0 40 /*---------------------------------------------------------------------------
michael@0 41 Private functions
michael@0 42 ---------------------------------------------------------------------------*/
michael@0 43
michael@0 44 /* Doubles the allocated size associated to a pointer */
michael@0 45 /* 'size' is the current allocated size. */
michael@0 46 static void * mem_double(void * ptr, int size)
michael@0 47 {
michael@0 48 void * newptr ;
michael@0 49
michael@0 50 newptr = calloc(2*size, 1);
michael@0 51 if (newptr==NULL) {
michael@0 52 return NULL ;
michael@0 53 }
michael@0 54 memcpy(newptr, ptr, size);
michael@0 55 free(ptr);
michael@0 56 return newptr ;
michael@0 57 }
michael@0 58
michael@0 59 /*-------------------------------------------------------------------------*/
michael@0 60 /**
michael@0 61 @brief Duplicate a string
michael@0 62 @param s String to duplicate
michael@0 63 @return Pointer to a newly allocated string, to be freed with free()
michael@0 64
michael@0 65 This is a replacement for strdup(). This implementation is provided
michael@0 66 for systems that do not have it.
michael@0 67 */
michael@0 68 /*--------------------------------------------------------------------------*/
michael@0 69 static char * xstrdup(char * s)
michael@0 70 {
michael@0 71 char * t ;
michael@0 72 if (!s)
michael@0 73 return NULL ;
michael@0 74 t = malloc(strlen(s)+1) ;
michael@0 75 if (t) {
michael@0 76 strcpy(t,s);
michael@0 77 }
michael@0 78 return t ;
michael@0 79 }
michael@0 80
michael@0 81 /*---------------------------------------------------------------------------
michael@0 82 Function codes
michael@0 83 ---------------------------------------------------------------------------*/
michael@0 84 /*-------------------------------------------------------------------------*/
michael@0 85 /**
michael@0 86 @brief Compute the hash key for a string.
michael@0 87 @param key Character string to use for key.
michael@0 88 @return 1 unsigned int on at least 32 bits.
michael@0 89
michael@0 90 This hash function has been taken from an Article in Dr Dobbs Journal.
michael@0 91 This is normally a collision-free function, distributing keys evenly.
michael@0 92 The key is stored anyway in the struct so that collision can be avoided
michael@0 93 by comparing the key itself in last resort.
michael@0 94 */
michael@0 95 /*--------------------------------------------------------------------------*/
michael@0 96 unsigned dictionary_hash(char * key)
michael@0 97 {
michael@0 98 int len ;
michael@0 99 unsigned hash ;
michael@0 100 int i ;
michael@0 101
michael@0 102 len = strlen(key);
michael@0 103 for (hash=0, i=0 ; i<len ; i++) {
michael@0 104 hash += (unsigned)key[i] ;
michael@0 105 hash += (hash<<10);
michael@0 106 hash ^= (hash>>6) ;
michael@0 107 }
michael@0 108 hash += (hash <<3);
michael@0 109 hash ^= (hash >>11);
michael@0 110 hash += (hash <<15);
michael@0 111 return hash ;
michael@0 112 }
michael@0 113
michael@0 114 /*-------------------------------------------------------------------------*/
michael@0 115 /**
michael@0 116 @brief Create a new dictionary object.
michael@0 117 @param size Optional initial size of the dictionary.
michael@0 118 @return 1 newly allocated dictionary objet.
michael@0 119
michael@0 120 This function allocates a new dictionary object of given size and returns
michael@0 121 it. If you do not know in advance (roughly) the number of entries in the
michael@0 122 dictionary, give size=0.
michael@0 123 */
michael@0 124 /*--------------------------------------------------------------------------*/
michael@0 125 dictionary * dictionary_new(int size)
michael@0 126 {
michael@0 127 dictionary * d ;
michael@0 128
michael@0 129 /* If no size was specified, allocate space for DICTMINSZ */
michael@0 130 if (size<DICTMINSZ) size=DICTMINSZ ;
michael@0 131
michael@0 132 if (!(d = (dictionary *)calloc(1, sizeof(dictionary)))) {
michael@0 133 return NULL;
michael@0 134 }
michael@0 135 d->size = size ;
michael@0 136 d->val = (char **)calloc(size, sizeof(char*));
michael@0 137 d->key = (char **)calloc(size, sizeof(char*));
michael@0 138 d->hash = (unsigned int *)calloc(size, sizeof(unsigned));
michael@0 139 return d ;
michael@0 140 }
michael@0 141
michael@0 142 /*-------------------------------------------------------------------------*/
michael@0 143 /**
michael@0 144 @brief Delete a dictionary object
michael@0 145 @param d dictionary object to deallocate.
michael@0 146 @return void
michael@0 147
michael@0 148 Deallocate a dictionary object and all memory associated to it.
michael@0 149 */
michael@0 150 /*--------------------------------------------------------------------------*/
michael@0 151 void dictionary_del(dictionary * d)
michael@0 152 {
michael@0 153 int i ;
michael@0 154
michael@0 155 if (d==NULL) return ;
michael@0 156 for (i=0 ; i<d->size ; i++) {
michael@0 157 if (d->key[i]!=NULL)
michael@0 158 free(d->key[i]);
michael@0 159 if (d->val[i]!=NULL)
michael@0 160 free(d->val[i]);
michael@0 161 }
michael@0 162 free(d->val);
michael@0 163 free(d->key);
michael@0 164 free(d->hash);
michael@0 165 free(d);
michael@0 166 return ;
michael@0 167 }
michael@0 168
michael@0 169 /*-------------------------------------------------------------------------*/
michael@0 170 /**
michael@0 171 @brief Get a value from a dictionary.
michael@0 172 @param d dictionary object to search.
michael@0 173 @param key Key to look for in the dictionary.
michael@0 174 @param def Default value to return if key not found.
michael@0 175 @return 1 pointer to internally allocated character string.
michael@0 176
michael@0 177 This function locates a key in a dictionary and returns a pointer to its
michael@0 178 value, or the passed 'def' pointer if no such key can be found in
michael@0 179 dictionary. The returned character pointer points to data internal to the
michael@0 180 dictionary object, you should not try to free it or modify it.
michael@0 181 */
michael@0 182 /*--------------------------------------------------------------------------*/
michael@0 183 char * dictionary_get(dictionary * d, char * key, char * def)
michael@0 184 {
michael@0 185 unsigned hash ;
michael@0 186 int i ;
michael@0 187
michael@0 188 hash = dictionary_hash(key);
michael@0 189 for (i=0 ; i<d->size ; i++) {
michael@0 190 if (d->key[i]==NULL)
michael@0 191 continue ;
michael@0 192 /* Compare hash */
michael@0 193 if (hash==d->hash[i]) {
michael@0 194 /* Compare string, to avoid hash collisions */
michael@0 195 if (!strcmp(key, d->key[i])) {
michael@0 196 return d->val[i] ;
michael@0 197 }
michael@0 198 }
michael@0 199 }
michael@0 200 return def ;
michael@0 201 }
michael@0 202
michael@0 203 /*-------------------------------------------------------------------------*/
michael@0 204 /**
michael@0 205 @brief Set a value in a dictionary.
michael@0 206 @param d dictionary object to modify.
michael@0 207 @param key Key to modify or add.
michael@0 208 @param val Value to add.
michael@0 209 @return int 0 if Ok, anything else otherwise
michael@0 210
michael@0 211 If the given key is found in the dictionary, the associated value is
michael@0 212 replaced by the provided one. If the key cannot be found in the
michael@0 213 dictionary, it is added to it.
michael@0 214
michael@0 215 It is Ok to provide a NULL value for val, but NULL values for the dictionary
michael@0 216 or the key are considered as errors: the function will return immediately
michael@0 217 in such a case.
michael@0 218
michael@0 219 Notice that if you dictionary_set a variable to NULL, a call to
michael@0 220 dictionary_get will return a NULL value: the variable will be found, and
michael@0 221 its value (NULL) is returned. In other words, setting the variable
michael@0 222 content to NULL is equivalent to deleting the variable from the
michael@0 223 dictionary. It is not possible (in this implementation) to have a key in
michael@0 224 the dictionary without value.
michael@0 225
michael@0 226 This function returns non-zero in case of failure.
michael@0 227 */
michael@0 228 /*--------------------------------------------------------------------------*/
michael@0 229 int dictionary_set(dictionary * d, char * key, char * val)
michael@0 230 {
michael@0 231 int i ;
michael@0 232 unsigned hash ;
michael@0 233
michael@0 234 if (d==NULL || key==NULL) return -1 ;
michael@0 235
michael@0 236 /* Compute hash for this key */
michael@0 237 hash = dictionary_hash(key) ;
michael@0 238 /* Find if value is already in dictionary */
michael@0 239 if (d->n>0) {
michael@0 240 for (i=0 ; i<d->size ; i++) {
michael@0 241 if (d->key[i]==NULL)
michael@0 242 continue ;
michael@0 243 if (hash==d->hash[i]) { /* Same hash value */
michael@0 244 if (!strcmp(key, d->key[i])) { /* Same key */
michael@0 245 /* Found a value: modify and return */
michael@0 246 if (d->val[i]!=NULL)
michael@0 247 free(d->val[i]);
michael@0 248 d->val[i] = val ? xstrdup(val) : NULL ;
michael@0 249 /* Value has been modified: return */
michael@0 250 return 0 ;
michael@0 251 }
michael@0 252 }
michael@0 253 }
michael@0 254 }
michael@0 255 /* Add a new value */
michael@0 256 /* See if dictionary needs to grow */
michael@0 257 if (d->n==d->size) {
michael@0 258
michael@0 259 /* Reached maximum size: reallocate dictionary */
michael@0 260 d->val = (char **)mem_double(d->val, d->size * sizeof(char*)) ;
michael@0 261 d->key = (char **)mem_double(d->key, d->size * sizeof(char*)) ;
michael@0 262 d->hash = (unsigned int *)mem_double(d->hash, d->size * sizeof(unsigned)) ;
michael@0 263 if ((d->val==NULL) || (d->key==NULL) || (d->hash==NULL)) {
michael@0 264 /* Cannot grow dictionary */
michael@0 265 return -1 ;
michael@0 266 }
michael@0 267 /* Double size */
michael@0 268 d->size *= 2 ;
michael@0 269 }
michael@0 270
michael@0 271 /* Insert key in the first empty slot */
michael@0 272 for (i=0 ; i<d->size ; i++) {
michael@0 273 if (d->key[i]==NULL) {
michael@0 274 /* Add key here */
michael@0 275 break ;
michael@0 276 }
michael@0 277 }
michael@0 278 /* Copy key */
michael@0 279 d->key[i] = xstrdup(key);
michael@0 280 d->val[i] = val ? xstrdup(val) : NULL ;
michael@0 281 d->hash[i] = hash;
michael@0 282 d->n ++ ;
michael@0 283 return 0 ;
michael@0 284 }
michael@0 285
michael@0 286 /*-------------------------------------------------------------------------*/
michael@0 287 /**
michael@0 288 @brief Delete a key in a dictionary
michael@0 289 @param d dictionary object to modify.
michael@0 290 @param key Key to remove.
michael@0 291 @return void
michael@0 292
michael@0 293 This function deletes a key in a dictionary. Nothing is done if the
michael@0 294 key cannot be found.
michael@0 295 */
michael@0 296 /*--------------------------------------------------------------------------*/
michael@0 297 void dictionary_unset(dictionary * d, char * key)
michael@0 298 {
michael@0 299 unsigned hash ;
michael@0 300 int i ;
michael@0 301
michael@0 302 if (key == NULL) {
michael@0 303 return;
michael@0 304 }
michael@0 305
michael@0 306 hash = dictionary_hash(key);
michael@0 307 for (i=0 ; i<d->size ; i++) {
michael@0 308 if (d->key[i]==NULL)
michael@0 309 continue ;
michael@0 310 /* Compare hash */
michael@0 311 if (hash==d->hash[i]) {
michael@0 312 /* Compare string, to avoid hash collisions */
michael@0 313 if (!strcmp(key, d->key[i])) {
michael@0 314 /* Found key */
michael@0 315 break ;
michael@0 316 }
michael@0 317 }
michael@0 318 }
michael@0 319 if (i>=d->size)
michael@0 320 /* Key not found */
michael@0 321 return ;
michael@0 322
michael@0 323 free(d->key[i]);
michael@0 324 d->key[i] = NULL ;
michael@0 325 if (d->val[i]!=NULL) {
michael@0 326 free(d->val[i]);
michael@0 327 d->val[i] = NULL ;
michael@0 328 }
michael@0 329 d->hash[i] = 0 ;
michael@0 330 d->n -- ;
michael@0 331 return ;
michael@0 332 }
michael@0 333
michael@0 334 /*-------------------------------------------------------------------------*/
michael@0 335 /**
michael@0 336 @brief Dump a dictionary to an opened file pointer.
michael@0 337 @param d Dictionary to dump
michael@0 338 @param f Opened file pointer.
michael@0 339 @return void
michael@0 340
michael@0 341 Dumps a dictionary onto an opened file pointer. Key pairs are printed out
michael@0 342 as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as
michael@0 343 output file pointers.
michael@0 344 */
michael@0 345 /*--------------------------------------------------------------------------*/
michael@0 346 void dictionary_dump(dictionary * d, FILE * out)
michael@0 347 {
michael@0 348 int i ;
michael@0 349
michael@0 350 if (d==NULL || out==NULL) return ;
michael@0 351 if (d->n<1) {
michael@0 352 fprintf(out, "empty dictionary\n");
michael@0 353 return ;
michael@0 354 }
michael@0 355 for (i=0 ; i<d->size ; i++) {
michael@0 356 if (d->key[i]) {
michael@0 357 fprintf(out, "%20s\t[%s]\n",
michael@0 358 d->key[i],
michael@0 359 d->val[i] ? d->val[i] : "UNDEF");
michael@0 360 }
michael@0 361 }
michael@0 362 return ;
michael@0 363 }
michael@0 364
michael@0 365
michael@0 366 /* Test code */
michael@0 367 #ifdef TESTDIC
michael@0 368 #define NVALS 20000
michael@0 369 int main(int argc, char *argv[])
michael@0 370 {
michael@0 371 dictionary * d ;
michael@0 372 char * val ;
michael@0 373 int i ;
michael@0 374 char cval[90] ;
michael@0 375
michael@0 376 /* Allocate dictionary */
michael@0 377 printf("allocating...\n");
michael@0 378 d = dictionary_new(0);
michael@0 379
michael@0 380 /* Set values in dictionary */
michael@0 381 printf("setting %d values...\n", NVALS);
michael@0 382 for (i=0 ; i<NVALS ; i++) {
michael@0 383 sprintf(cval, "%04d", i);
michael@0 384 dictionary_set(d, cval, "salut");
michael@0 385 }
michael@0 386 printf("getting %d values...\n", NVALS);
michael@0 387 for (i=0 ; i<NVALS ; i++) {
michael@0 388 sprintf(cval, "%04d", i);
michael@0 389 val = dictionary_get(d, cval, DICT_INVALID_KEY);
michael@0 390 if (val==DICT_INVALID_KEY) {
michael@0 391 printf("cannot get value for key [%s]\n", cval);
michael@0 392 }
michael@0 393 }
michael@0 394 printf("unsetting %d values...\n", NVALS);
michael@0 395 for (i=0 ; i<NVALS ; i++) {
michael@0 396 sprintf(cval, "%04d", i);
michael@0 397 dictionary_unset(d, cval);
michael@0 398 }
michael@0 399 if (d->n != 0) {
michael@0 400 printf("error deleting values\n");
michael@0 401 }
michael@0 402 printf("deallocating...\n");
michael@0 403 dictionary_del(d);
michael@0 404 return 0 ;
michael@0 405 }
michael@0 406 #endif
michael@0 407 /* vim: set ts=4 et sw=4 tw=75 */

mercurial