root/source3/iniparser/src/dictionary.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mem_double
  2. dictionary_hash
  3. dictionary_new
  4. dictionary_del
  5. dictionary_get
  6. dictionary_getchar
  7. dictionary_getint
  8. dictionary_getdouble
  9. dictionary_set
  10. dictionary_unset
  11. dictionary_setint
  12. dictionary_setdouble
  13. dictionary_dump
  14. main

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

/* [<][>][^][v][top][bottom][index][help] */