root/source3/iniparser/src/iniparser.c

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

DEFINITIONS

This source file includes following definitions.
  1. iniparser_add_entry
  2. iniparser_getnsec
  3. iniparser_getsecname
  4. iniparser_dump
  5. iniparser_dump_ini
  6. iniparser_getstr
  7. iniparser_getstring
  8. iniparser_getint
  9. iniparser_getdouble
  10. iniparser_getboolean
  11. iniparser_find_entry
  12. iniparser_setstr
  13. iniparser_unset
  14. iniparser_load
  15. iniparser_freedict

   1 
   2 /*-------------------------------------------------------------------------*/
   3 /**
   4    @file    iniparser.c
   5    @author  N. Devillard
   6    @date    Mar 2000
   7    @version $Revision: 2.17 $
   8    @brief   Parser for ini files.
   9 */
  10 /*--------------------------------------------------------------------------*/
  11 
  12 /*
  13     $Id: iniparser.c,v 2.17 2007-05-27 13:03:43 ndevilla Exp $
  14     $Author: ndevilla $
  15     $Date: 2007-05-27 13:03:43 $
  16     $Revision: 2.17 $
  17 */
  18 
  19 /*---------------------------------------------------------------------------
  20                                 Includes
  21  ---------------------------------------------------------------------------*/
  22 
  23 #include "iniparser.h"
  24 #include "strlib.h"
  25 
  26 #define ASCIILINESZ         1024
  27 #define INI_INVALID_KEY     ((char*)-1)
  28 
  29 /*---------------------------------------------------------------------------
  30                         Private to this module
  31  ---------------------------------------------------------------------------*/
  32 
  33 /* Private: add an entry to the dictionary */
  34 static void iniparser_add_entry(
     /* [<][>][^][v][top][bottom][index][help] */
  35     dictionary * d,
  36     char * sec,
  37     char * key,
  38     char * val)
  39 {
  40     char longkey[2*ASCIILINESZ+1];
  41 
  42     /* Make a key as section:keyword */
  43     if (key!=NULL) {
  44         sprintf(longkey, "%s:%s", sec, key);
  45     } else {
  46         strcpy(longkey, sec);
  47     }
  48 
  49     /* Add (key,val) to dictionary */
  50     dictionary_set(d, longkey, val);
  51     return ;
  52 }
  53 
  54 
  55 /*-------------------------------------------------------------------------*/
  56 /**
  57   @brief    Get number of sections in a dictionary
  58   @param    d   Dictionary to examine
  59   @return   int Number of sections found in dictionary
  60 
  61   This function returns the number of sections found in a dictionary.
  62   The test to recognize sections is done on the string stored in the
  63   dictionary: a section name is given as "section" whereas a key is
  64   stored as "section:key", thus the test looks for entries that do not
  65   contain a colon.
  66 
  67   This clearly fails in the case a section name contains a colon, but
  68   this should simply be avoided.
  69 
  70   This function returns -1 in case of error.
  71  */
  72 /*--------------------------------------------------------------------------*/
  73 
  74 int iniparser_getnsec(dictionary * d)
     /* [<][>][^][v][top][bottom][index][help] */
  75 {
  76     int i ;
  77     int nsec ;
  78 
  79     if (d==NULL) return -1 ;
  80     nsec=0 ;
  81     for (i=0 ; i<d->size ; i++) {
  82         if (d->key[i]==NULL)
  83             continue ;
  84         if (strchr(d->key[i], ':')==NULL) {
  85             nsec ++ ;
  86         }
  87     }
  88     return nsec ;
  89 }
  90 
  91 
  92 /*-------------------------------------------------------------------------*/
  93 /**
  94   @brief    Get name for section n in a dictionary.
  95   @param    d   Dictionary to examine
  96   @param    n   Section number (from 0 to nsec-1).
  97   @return   Pointer to char string
  98 
  99   This function locates the n-th section in a dictionary and returns
 100   its name as a pointer to a string statically allocated inside the
 101   dictionary. Do not free or modify the returned string!
 102 
 103   This function returns NULL in case of error.
 104  */
 105 /*--------------------------------------------------------------------------*/
 106 
 107 char * iniparser_getsecname(dictionary * d, int n)
     /* [<][>][^][v][top][bottom][index][help] */
 108 {
 109     int i ;
 110     int foundsec ;
 111 
 112     if (d==NULL || n<0) return NULL ;
 113     foundsec=0 ;
 114     for (i=0 ; i<d->size ; i++) {
 115         if (d->key[i]==NULL)
 116             continue ;
 117         if (strchr(d->key[i], ':')==NULL) {
 118             foundsec++ ;
 119             if (foundsec>n)
 120                 break ;
 121         }
 122     }
 123     if (foundsec<=n) {
 124         return NULL ;
 125     }
 126     return d->key[i] ;
 127 }
 128 
 129 
 130 /*-------------------------------------------------------------------------*/
 131 /**
 132   @brief    Dump a dictionary to an opened file pointer.
 133   @param    d   Dictionary to dump.
 134   @param    f   Opened file pointer to dump to.
 135   @return   void
 136 
 137   This function prints out the contents of a dictionary, one element by
 138   line, onto the provided file pointer. It is OK to specify @c stderr
 139   or @c stdout as output files. This function is meant for debugging
 140   purposes mostly.
 141  */
 142 /*--------------------------------------------------------------------------*/
 143 void iniparser_dump(dictionary * d, FILE * f)
     /* [<][>][^][v][top][bottom][index][help] */
 144 {
 145     int     i ;
 146 
 147     if (d==NULL || f==NULL) return ;
 148     for (i=0 ; i<d->size ; i++) {
 149         if (d->key[i]==NULL)
 150             continue ;
 151         if (d->val[i]!=NULL) {
 152             fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]);
 153         } else {
 154             fprintf(f, "[%s]=UNDEF\n", d->key[i]);
 155         }
 156     }
 157     return ;
 158 }
 159 
 160 /*-------------------------------------------------------------------------*/
 161 /**
 162   @brief    Save a dictionary to a loadable ini file
 163   @param    d   Dictionary to dump
 164   @param    f   Opened file pointer to dump to
 165   @return   void
 166 
 167   This function dumps a given dictionary into a loadable ini file.
 168   It is Ok to specify @c stderr or @c stdout as output files.
 169  */
 170 /*--------------------------------------------------------------------------*/
 171 
 172 void iniparser_dump_ini(dictionary * d, FILE * f)
     /* [<][>][^][v][top][bottom][index][help] */
 173 {
 174     int     i, j ;
 175     char    keym[ASCIILINESZ+1];
 176     int     nsec ;
 177     char *  secname ;
 178     int     seclen ;
 179 
 180     if (d==NULL || f==NULL) return ;
 181 
 182     nsec = iniparser_getnsec(d);
 183     if (nsec<1) {
 184         /* No section in file: dump all keys as they are */
 185         for (i=0 ; i<d->size ; i++) {
 186             if (d->key[i]==NULL)
 187                 continue ;
 188             fprintf(f, "%s = %s\n", d->key[i], d->val[i]);
 189         }
 190         return ;
 191     }
 192     for (i=0 ; i<nsec ; i++) {
 193         secname = iniparser_getsecname(d, i) ;
 194         seclen  = (int)strlen(secname);
 195         fprintf(f, "\n[%s]\n", secname);
 196         sprintf(keym, "%s:", secname);
 197         for (j=0 ; j<d->size ; j++) {
 198             if (d->key[j]==NULL)
 199                 continue ;
 200             if (!strncmp(d->key[j], keym, seclen+1)) {
 201                 fprintf(f,
 202                         "%-30s = %s\n",
 203                         d->key[j]+seclen+1,
 204                         d->val[j] ? d->val[j] : "");
 205             }
 206         }
 207     }
 208     fprintf(f, "\n");
 209     return ;
 210 }
 211 
 212 
 213 
 214 
 215 /*-------------------------------------------------------------------------*/
 216 /**
 217   @brief        Get the string associated to a key, return NULL if not found
 218   @param    d   Dictionary to search
 219   @param    key Key string to look for
 220   @return   pointer to statically allocated character string, or NULL.
 221 
 222   This function queries a dictionary for a key. A key as read from an
 223   ini file is given as "section:key". If the key cannot be found,
 224   NULL is returned.
 225   The returned char pointer is pointing to a string allocated in
 226   the dictionary, do not free or modify it.
 227 
 228   This function is only provided for backwards compatibility with 
 229   previous versions of iniparser. It is recommended to use
 230   iniparser_getstring() instead.
 231  */
 232 /*--------------------------------------------------------------------------*/
 233 char * iniparser_getstr(dictionary * d, const char * key)
     /* [<][>][^][v][top][bottom][index][help] */
 234 {
 235     return iniparser_getstring(d, key, NULL);
 236 }
 237 
 238 
 239 /*-------------------------------------------------------------------------*/
 240 /**
 241   @brief    Get the string associated to a key
 242   @param    d       Dictionary to search
 243   @param    key     Key string to look for
 244   @param    def     Default value to return if key not found.
 245   @return   pointer to statically allocated character string
 246 
 247   This function queries a dictionary for a key. A key as read from an
 248   ini file is given as "section:key". If the key cannot be found,
 249   the pointer passed as 'def' is returned.
 250   The returned char pointer is pointing to a string allocated in
 251   the dictionary, do not free or modify it.
 252  */
 253 /*--------------------------------------------------------------------------*/
 254 char * iniparser_getstring(dictionary * d, const char * key, char * def)
     /* [<][>][^][v][top][bottom][index][help] */
 255 {
 256     char * lc_key ;
 257     char * sval ;
 258 
 259     if (d==NULL || key==NULL)
 260         return def ;
 261 
 262     if (!(lc_key = strdup(strlwc(key)))) {
 263             return NULL;
 264     }
 265     sval = dictionary_get(d, lc_key, def);
 266     free(lc_key);
 267     return sval ;
 268 }
 269 
 270 
 271 
 272 /*-------------------------------------------------------------------------*/
 273 /**
 274   @brief    Get the string associated to a key, convert to an int
 275   @param    d Dictionary to search
 276   @param    key Key string to look for
 277   @param    notfound Value to return in case of error
 278   @return   integer
 279 
 280   This function queries a dictionary for a key. A key as read from an
 281   ini file is given as "section:key". If the key cannot be found,
 282   the notfound value is returned.
 283 
 284   Supported values for integers include the usual C notation
 285   so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
 286   are supported. Examples:
 287 
 288   "42"      ->  42
 289   "042"     ->  34 (octal -> decimal)
 290   "0x42"    ->  66 (hexa  -> decimal)
 291 
 292   Warning: the conversion may overflow in various ways. Conversion is
 293   totally outsourced to strtol(), see the associated man page for overflow
 294   handling.
 295 
 296   Credits: Thanks to A. Becker for suggesting strtol()
 297  */
 298 /*--------------------------------------------------------------------------*/
 299 int iniparser_getint(dictionary * d, const char * key, int notfound)
     /* [<][>][^][v][top][bottom][index][help] */
 300 {
 301     char    *   str ;
 302 
 303     str = iniparser_getstring(d, key, INI_INVALID_KEY);
 304     if (str==INI_INVALID_KEY) return notfound ;
 305     return (int)strtol(str, NULL, 0);
 306 }
 307 
 308 
 309 /*-------------------------------------------------------------------------*/
 310 /**
 311   @brief    Get the string associated to a key, convert to a double
 312   @param    d Dictionary to search
 313   @param    key Key string to look for
 314   @param    notfound Value to return in case of error
 315   @return   double
 316 
 317   This function queries a dictionary for a key. A key as read from an
 318   ini file is given as "section:key". If the key cannot be found,
 319   the notfound value is returned.
 320  */
 321 /*--------------------------------------------------------------------------*/
 322 double iniparser_getdouble(dictionary * d, char * key, double notfound)
     /* [<][>][^][v][top][bottom][index][help] */
 323 {
 324     char    *   str ;
 325 
 326     str = iniparser_getstring(d, key, INI_INVALID_KEY);
 327     if (str==INI_INVALID_KEY) return notfound ;
 328     return atof(str);
 329 }
 330 
 331 
 332 
 333 /*-------------------------------------------------------------------------*/
 334 /**
 335   @brief    Get the string associated to a key, convert to a boolean
 336   @param    d Dictionary to search
 337   @param    key Key string to look for
 338   @param    notfound Value to return in case of error
 339   @return   integer
 340 
 341   This function queries a dictionary for a key. A key as read from an
 342   ini file is given as "section:key". If the key cannot be found,
 343   the notfound value is returned.
 344 
 345   A true boolean is found if one of the following is matched:
 346 
 347   - A string starting with 'y'
 348   - A string starting with 'Y'
 349   - A string starting with 't'
 350   - A string starting with 'T'
 351   - A string starting with '1'
 352 
 353   A false boolean is found if one of the following is matched:
 354 
 355   - A string starting with 'n'
 356   - A string starting with 'N'
 357   - A string starting with 'f'
 358   - A string starting with 'F'
 359   - A string starting with '0'
 360 
 361   The notfound value returned if no boolean is identified, does not
 362   necessarily have to be 0 or 1.
 363  */
 364 /*--------------------------------------------------------------------------*/
 365 int iniparser_getboolean(dictionary * d, const char * key, int notfound)
     /* [<][>][^][v][top][bottom][index][help] */
 366 {
 367     char    *   c ;
 368     int         ret ;
 369 
 370     c = iniparser_getstring(d, key, INI_INVALID_KEY);
 371     if (c==INI_INVALID_KEY) return notfound ;
 372     if (c[0]=='y' || c[0]=='Y' || c[0]=='1' || c[0]=='t' || c[0]=='T') {
 373         ret = 1 ;
 374     } else if (c[0]=='n' || c[0]=='N' || c[0]=='0' || c[0]=='f' || c[0]=='F') {
 375         ret = 0 ;
 376     } else {
 377         ret = notfound ;
 378     }
 379     return ret;
 380 }
 381 
 382 
 383 /*-------------------------------------------------------------------------*/
 384 /**
 385   @brief    Finds out if a given entry exists in a dictionary
 386   @param    ini     Dictionary to search
 387   @param    entry   Name of the entry to look for
 388   @return   integer 1 if entry exists, 0 otherwise
 389 
 390   Finds out if a given entry exists in the dictionary. Since sections
 391   are stored as keys with NULL associated values, this is the only way
 392   of querying for the presence of sections in a dictionary.
 393  */
 394 /*--------------------------------------------------------------------------*/
 395 
 396 int iniparser_find_entry(
     /* [<][>][^][v][top][bottom][index][help] */
 397     dictionary  *   ini,
 398     char        *   entry
 399 )
 400 {
 401     int found=0 ;
 402     if (iniparser_getstring(ini, entry, INI_INVALID_KEY)!=INI_INVALID_KEY) {
 403         found = 1 ;
 404     }
 405     return found ;
 406 }
 407 
 408 
 409 
 410 /*-------------------------------------------------------------------------*/
 411 /**
 412   @brief    Set an entry in a dictionary.
 413   @param    ini     Dictionary to modify.
 414   @param    entry   Entry to modify (entry name)
 415   @param    val     New value to associate to the entry.
 416   @return   int 0 if Ok, -1 otherwise.
 417 
 418   If the given entry can be found in the dictionary, it is modified to
 419   contain the provided value. If it cannot be found, -1 is returned.
 420   It is Ok to set val to NULL.
 421  */
 422 /*--------------------------------------------------------------------------*/
 423 
 424 int iniparser_setstr(dictionary * ini, char * entry, char * val)
     /* [<][>][^][v][top][bottom][index][help] */
 425 {
 426     dictionary_set(ini, strlwc(entry), val);
 427     return 0 ;
 428 }
 429 
 430 /*-------------------------------------------------------------------------*/
 431 /**
 432   @brief    Delete an entry in a dictionary
 433   @param    ini     Dictionary to modify
 434   @param    entry   Entry to delete (entry name)
 435   @return   void
 436 
 437   If the given entry can be found, it is deleted from the dictionary.
 438  */
 439 /*--------------------------------------------------------------------------*/
 440 void iniparser_unset(dictionary * ini, char * entry)
     /* [<][>][^][v][top][bottom][index][help] */
 441 {
 442     dictionary_unset(ini, strlwc(entry));
 443 }
 444 
 445 
 446 /*-------------------------------------------------------------------------*/
 447 /**
 448   @brief    Parse an ini file and return an allocated dictionary object
 449   @param    ininame Name of the ini file to read.
 450   @return   Pointer to newly allocated dictionary
 451 
 452   This is the parser for ini files. This function is called, providing
 453   the name of the file to be read. It returns a dictionary object that
 454   should not be accessed directly, but through accessor functions
 455   instead.
 456 
 457   The returned dictionary must be freed using iniparser_freedict().
 458  */
 459 /*--------------------------------------------------------------------------*/
 460 
 461 dictionary * iniparser_load(const char * ininame)
     /* [<][>][^][v][top][bottom][index][help] */
 462 {
 463     dictionary  *   d ;
 464     char        lin[ASCIILINESZ+1];
 465     char        sec[ASCIILINESZ+1];
 466     char        key[ASCIILINESZ+1];
 467     char        val[ASCIILINESZ+1];
 468     char    *   where ;
 469     FILE    *   ini ;
 470     int         lineno ;
 471 
 472     if ((ini=fopen(ininame, "r"))==NULL) {
 473         return NULL ;
 474     }
 475 
 476     sec[0]=0;
 477 
 478     /*
 479      * Initialize a new dictionary entry
 480      */
 481     if (!(d = dictionary_new(0))) {
 482             fclose(ini);
 483             return NULL;
 484     }
 485     lineno = 0 ;
 486     while (fgets(lin, ASCIILINESZ, ini)!=NULL) {
 487         lineno++ ;
 488         where = strskp(lin); /* Skip leading spaces */
 489         if (*where==';' || *where=='#' || *where==0)
 490             continue ; /* Comment lines */
 491         else {
 492             if (sscanf(where, "[%[^]]", sec)==1) {
 493                 /* Valid section name */
 494                 strcpy(sec, strlwc(sec));
 495                 iniparser_add_entry(d, sec, NULL, NULL);
 496             } else if (sscanf (where, "%[^=] = \"%[^\"]\"", key, val) == 2
 497                    ||  sscanf (where, "%[^=] = '%[^\']'",   key, val) == 2
 498                    ||  sscanf (where, "%[^=] = %[^;#]",     key, val) == 2) {
 499                 strcpy(key, strlwc(strcrop(key)));
 500                 /*
 501                  * sscanf cannot handle "" or '' as empty value,
 502                  * this is done here
 503                  */
 504                 if (!strcmp(val, "\"\"") || !strcmp(val, "''")) {
 505                     val[0] = (char)0;
 506                 } else {
 507                     strcpy(val, strcrop(val));
 508                 }
 509                 iniparser_add_entry(d, sec, key, val);
 510             }
 511         }
 512     }
 513     fclose(ini);
 514     return d ;
 515 }
 516 
 517 
 518 
 519 /*-------------------------------------------------------------------------*/
 520 /**
 521   @brief    Free all memory associated to an ini dictionary
 522   @param    d Dictionary to free
 523   @return   void
 524 
 525   Free all memory associated to an ini dictionary.
 526   It is mandatory to call this function before the dictionary object
 527   gets out of the current context.
 528  */
 529 /*--------------------------------------------------------------------------*/
 530 
 531 void iniparser_freedict(dictionary * d)
     /* [<][>][^][v][top][bottom][index][help] */
 532 {
 533     dictionary_del(d);
 534 }
 535 
 536 /* vim: set ts=4 et sw=4 tw=75 */

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