project_files/frontlib/iniparser/iniparser.c
changeset 7175 038e3415100a
child 8100 0e6fadf81a2c
child 10017 de822cd3df3a
equal deleted inserted replaced
7173:7c2eb284f9f1 7175:038e3415100a
       
     1 
       
     2 /*-------------------------------------------------------------------------*/
       
     3 /**
       
     4    @file    iniparser.c
       
     5    @author  N. Devillard
       
     6    @brief   Parser for ini files.
       
     7 */
       
     8 /*--------------------------------------------------------------------------*/
       
     9 /*---------------------------- Includes ------------------------------------*/
       
    10 #include <ctype.h>
       
    11 #include "iniparser.h"
       
    12 
       
    13 /*---------------------------- Defines -------------------------------------*/
       
    14 #define ASCIILINESZ         (1024)
       
    15 #define INI_INVALID_KEY     ((char*)-1)
       
    16 
       
    17 /*---------------------------------------------------------------------------
       
    18                         Private to this module
       
    19  ---------------------------------------------------------------------------*/
       
    20 /**
       
    21  * This enum stores the status for each parsed line (internal use only).
       
    22  */
       
    23 typedef enum _line_status_ {
       
    24     LINE_UNPROCESSED,
       
    25     LINE_ERROR,
       
    26     LINE_EMPTY,
       
    27     LINE_COMMENT,
       
    28     LINE_SECTION,
       
    29     LINE_VALUE
       
    30 } line_status ;
       
    31 
       
    32 /*-------------------------------------------------------------------------*/
       
    33 /**
       
    34   @brief    Convert a string to lowercase.
       
    35   @param    s   String to convert.
       
    36   @return   ptr to statically allocated string.
       
    37 
       
    38   This function returns a pointer to a statically allocated string
       
    39   containing a lowercased version of the input string. Do not free
       
    40   or modify the returned string! Since the returned string is statically
       
    41   allocated, it will be modified at each function call (not re-entrant).
       
    42  */
       
    43 /*--------------------------------------------------------------------------*/
       
    44 static char * strlwc(const char * s)
       
    45 {
       
    46     static char l[ASCIILINESZ+1];
       
    47     int i ;
       
    48 
       
    49     if (s==NULL) return NULL ;
       
    50     memset(l, 0, ASCIILINESZ+1);
       
    51     i=0 ;
       
    52     while (s[i] && i<ASCIILINESZ) {
       
    53         l[i] = (char)tolower((int)s[i]);
       
    54         i++ ;
       
    55     }
       
    56     l[ASCIILINESZ]=(char)0;
       
    57     return l ;
       
    58 }
       
    59 
       
    60 /*-------------------------------------------------------------------------*/
       
    61 /**
       
    62   @brief    Remove blanks at the beginning and the end of a string.
       
    63   @param    s   String to parse.
       
    64   @return   ptr to statically allocated string.
       
    65 
       
    66   This function returns a pointer to a statically allocated string,
       
    67   which is identical to the input string, except that all blank
       
    68   characters at the end and the beg. of the string have been removed.
       
    69   Do not free or modify the returned string! Since the returned string
       
    70   is statically allocated, it will be modified at each function call
       
    71   (not re-entrant).
       
    72  */
       
    73 /*--------------------------------------------------------------------------*/
       
    74 static char * strstrip(const char * s)
       
    75 {
       
    76     static char l[ASCIILINESZ+1];
       
    77     char * last ;
       
    78     
       
    79     if (s==NULL) return NULL ;
       
    80     
       
    81     while (isspace((int)*s) && *s) s++;
       
    82     memset(l, 0, ASCIILINESZ+1);
       
    83     strcpy(l, s);
       
    84     last = l + strlen(l);
       
    85     while (last > l) {
       
    86         if (!isspace((int)*(last-1)))
       
    87             break ;
       
    88         last -- ;
       
    89     }
       
    90     *last = (char)0;
       
    91     return (char*)l ;
       
    92 }
       
    93 
       
    94 /*-------------------------------------------------------------------------*/
       
    95 /**
       
    96   @brief    Get number of sections in a dictionary
       
    97   @param    d   Dictionary to examine
       
    98   @return   int Number of sections found in dictionary
       
    99 
       
   100   This function returns the number of sections found in a dictionary.
       
   101   The test to recognize sections is done on the string stored in the
       
   102   dictionary: a section name is given as "section" whereas a key is
       
   103   stored as "section:key", thus the test looks for entries that do not
       
   104   contain a colon.
       
   105 
       
   106   This clearly fails in the case a section name contains a colon, but
       
   107   this should simply be avoided.
       
   108 
       
   109   This function returns -1 in case of error.
       
   110  */
       
   111 /*--------------------------------------------------------------------------*/
       
   112 int iniparser_getnsec(dictionary * d)
       
   113 {
       
   114     int i ;
       
   115     int nsec ;
       
   116 
       
   117     if (d==NULL) return -1 ;
       
   118     nsec=0 ;
       
   119     for (i=0 ; i<d->size ; i++) {
       
   120         if (d->key[i]==NULL)
       
   121             continue ;
       
   122         if (strchr(d->key[i], ':')==NULL) {
       
   123             nsec ++ ;
       
   124         }
       
   125     }
       
   126     return nsec ;
       
   127 }
       
   128 
       
   129 /*-------------------------------------------------------------------------*/
       
   130 /**
       
   131   @brief    Get name for section n in a dictionary.
       
   132   @param    d   Dictionary to examine
       
   133   @param    n   Section number (from 0 to nsec-1).
       
   134   @return   Pointer to char string
       
   135 
       
   136   This function locates the n-th section in a dictionary and returns
       
   137   its name as a pointer to a string statically allocated inside the
       
   138   dictionary. Do not free or modify the returned string!
       
   139 
       
   140   This function returns NULL in case of error.
       
   141  */
       
   142 /*--------------------------------------------------------------------------*/
       
   143 char * iniparser_getsecname(dictionary * d, int n)
       
   144 {
       
   145     int i ;
       
   146     int foundsec ;
       
   147 
       
   148     if (d==NULL || n<0) return NULL ;
       
   149     foundsec=0 ;
       
   150     for (i=0 ; i<d->size ; i++) {
       
   151         if (d->key[i]==NULL)
       
   152             continue ;
       
   153         if (strchr(d->key[i], ':')==NULL) {
       
   154             foundsec++ ;
       
   155             if (foundsec>n)
       
   156                 break ;
       
   157         }
       
   158     }
       
   159     if (foundsec<=n) {
       
   160         return NULL ;
       
   161     }
       
   162     return d->key[i] ;
       
   163 }
       
   164 
       
   165 /*-------------------------------------------------------------------------*/
       
   166 /**
       
   167   @brief    Dump a dictionary to an opened file pointer.
       
   168   @param    d   Dictionary to dump.
       
   169   @param    f   Opened file pointer to dump to.
       
   170   @return   void
       
   171 
       
   172   This function prints out the contents of a dictionary, one element by
       
   173   line, onto the provided file pointer. It is OK to specify @c stderr
       
   174   or @c stdout as output files. This function is meant for debugging
       
   175   purposes mostly.
       
   176  */
       
   177 /*--------------------------------------------------------------------------*/
       
   178 void iniparser_dump(dictionary * d, FILE * f)
       
   179 {
       
   180     int     i ;
       
   181 
       
   182     if (d==NULL || f==NULL) return ;
       
   183     for (i=0 ; i<d->size ; i++) {
       
   184         if (d->key[i]==NULL)
       
   185             continue ;
       
   186         if (d->val[i]!=NULL) {
       
   187             fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]);
       
   188         } else {
       
   189             fprintf(f, "[%s]=UNDEF\n", d->key[i]);
       
   190         }
       
   191     }
       
   192     return ;
       
   193 }
       
   194 
       
   195 /*-------------------------------------------------------------------------*/
       
   196 /**
       
   197   @brief    Save a dictionary to a loadable ini file
       
   198   @param    d   Dictionary to dump
       
   199   @param    f   Opened file pointer to dump to
       
   200   @return   void
       
   201 
       
   202   This function dumps a given dictionary into a loadable ini file.
       
   203   It is Ok to specify @c stderr or @c stdout as output files.
       
   204  */
       
   205 /*--------------------------------------------------------------------------*/
       
   206 void iniparser_dump_ini(dictionary * d, FILE * f)
       
   207 {
       
   208     int     i ;
       
   209     int     nsec ;
       
   210     char *  secname ;
       
   211 
       
   212     if (d==NULL || f==NULL) return ;
       
   213 
       
   214     nsec = iniparser_getnsec(d);
       
   215     if (nsec<1) {
       
   216         /* No section in file: dump all keys as they are */
       
   217         for (i=0 ; i<d->size ; i++) {
       
   218             if (d->key[i]==NULL)
       
   219                 continue ;
       
   220             fprintf(f, "%s = %s\n", d->key[i], d->val[i]);
       
   221         }
       
   222         return ;
       
   223     }
       
   224     for (i=0 ; i<nsec ; i++) {
       
   225         secname = iniparser_getsecname(d, i) ;
       
   226         iniparser_dumpsection_ini(d, secname, f) ;
       
   227     }
       
   228     fprintf(f, "\n");
       
   229     return ;
       
   230 }
       
   231 
       
   232 /*-------------------------------------------------------------------------*/
       
   233 /**
       
   234   @brief    Save a dictionary section to a loadable ini file
       
   235   @param    d   Dictionary to dump
       
   236   @param    s   Section name of dictionary to dump
       
   237   @param    f   Opened file pointer to dump to
       
   238   @return   void
       
   239 
       
   240   This function dumps a given section of a given dictionary into a loadable ini
       
   241   file.  It is Ok to specify @c stderr or @c stdout as output files.
       
   242  */
       
   243 /*--------------------------------------------------------------------------*/
       
   244 void iniparser_dumpsection_ini(dictionary * d, char * s, FILE * f)
       
   245 {
       
   246     int     j ;
       
   247     char    keym[ASCIILINESZ+1];
       
   248     int     seclen ;
       
   249 
       
   250     if (d==NULL || f==NULL) return ;
       
   251     if (! iniparser_find_entry(d, s)) return ;
       
   252 
       
   253     seclen  = (int)strlen(s);
       
   254     fprintf(f, "\n[%s]\n", s);
       
   255     sprintf(keym, "%s:", s);
       
   256     for (j=0 ; j<d->size ; j++) {
       
   257         if (d->key[j]==NULL)
       
   258             continue ;
       
   259         if (!strncmp(d->key[j], keym, seclen+1)) {
       
   260             fprintf(f,
       
   261                     "%-30s = %s\n",
       
   262                     d->key[j]+seclen+1,
       
   263                     d->val[j] ? d->val[j] : "");
       
   264         }
       
   265     }
       
   266     fprintf(f, "\n");
       
   267     return ;
       
   268 }
       
   269 
       
   270 /*-------------------------------------------------------------------------*/
       
   271 /**
       
   272   @brief    Get the number of keys in a section of a dictionary.
       
   273   @param    d   Dictionary to examine
       
   274   @param    s   Section name of dictionary to examine
       
   275   @return   Number of keys in section
       
   276  */
       
   277 /*--------------------------------------------------------------------------*/
       
   278 int iniparser_getsecnkeys(dictionary * d, char * s)
       
   279 {
       
   280     int     seclen, nkeys ;
       
   281     char    keym[ASCIILINESZ+1];
       
   282     int j ;
       
   283 
       
   284     nkeys = 0;
       
   285 
       
   286     if (d==NULL) return nkeys;
       
   287     if (! iniparser_find_entry(d, s)) return nkeys;
       
   288 
       
   289     seclen  = (int)strlen(s);
       
   290     sprintf(keym, "%s:", s);
       
   291 
       
   292     for (j=0 ; j<d->size ; j++) {
       
   293         if (d->key[j]==NULL)
       
   294             continue ;
       
   295         if (!strncmp(d->key[j], keym, seclen+1)) 
       
   296             nkeys++;
       
   297     }
       
   298 
       
   299     return nkeys;
       
   300 
       
   301 }
       
   302 
       
   303 /*-------------------------------------------------------------------------*/
       
   304 /**
       
   305   @brief    Get the number of keys in a section of a dictionary.
       
   306   @param    d   Dictionary to examine
       
   307   @param    s   Section name of dictionary to examine
       
   308   @return   pointer to statically allocated character strings
       
   309 
       
   310   This function queries a dictionary and finds all keys in a given section.
       
   311   Each pointer in the returned char pointer-to-pointer is pointing to
       
   312   a string allocated in the dictionary; do not free or modify them.
       
   313   
       
   314   This function returns NULL in case of error.
       
   315  */
       
   316 /*--------------------------------------------------------------------------*/
       
   317 char ** iniparser_getseckeys(dictionary * d, char * s)
       
   318 {
       
   319 
       
   320     char **keys;
       
   321 
       
   322     int i, j ;
       
   323     char    keym[ASCIILINESZ+1];
       
   324     int     seclen, nkeys ;
       
   325 
       
   326     keys = NULL;
       
   327 
       
   328     if (d==NULL) return keys;
       
   329     if (! iniparser_find_entry(d, s)) return keys;
       
   330 
       
   331     nkeys = iniparser_getsecnkeys(d, s);
       
   332 
       
   333     keys = (char**) malloc(nkeys*sizeof(char*));
       
   334 
       
   335     seclen  = (int)strlen(s);
       
   336     sprintf(keym, "%s:", s);
       
   337     
       
   338     i = 0;
       
   339 
       
   340     for (j=0 ; j<d->size ; j++) {
       
   341         if (d->key[j]==NULL)
       
   342             continue ;
       
   343         if (!strncmp(d->key[j], keym, seclen+1)) {
       
   344             keys[i] = d->key[j];
       
   345             i++;
       
   346         }
       
   347     }
       
   348 
       
   349     return keys;
       
   350 
       
   351 }
       
   352 
       
   353 /*-------------------------------------------------------------------------*/
       
   354 /**
       
   355   @brief    Get the string associated to a key
       
   356   @param    d       Dictionary to search
       
   357   @param    key     Key string to look for
       
   358   @param    def     Default value to return if key not found.
       
   359   @return   pointer to statically allocated character string
       
   360 
       
   361   This function queries a dictionary for a key. A key as read from an
       
   362   ini file is given as "section:key". If the key cannot be found,
       
   363   the pointer passed as 'def' is returned.
       
   364   The returned char pointer is pointing to a string allocated in
       
   365   the dictionary, do not free or modify it.
       
   366  */
       
   367 /*--------------------------------------------------------------------------*/
       
   368 char * iniparser_getstring(dictionary * d, const char * key, char * def)
       
   369 {
       
   370     char * lc_key ;
       
   371     char * sval ;
       
   372 
       
   373     if (d==NULL || key==NULL)
       
   374         return def ;
       
   375 
       
   376     lc_key = strlwc(key);
       
   377     sval = dictionary_get(d, lc_key, def);
       
   378     return sval ;
       
   379 }
       
   380 
       
   381 /*-------------------------------------------------------------------------*/
       
   382 /**
       
   383   @brief    Get the string associated to a key, convert to an int
       
   384   @param    d Dictionary to search
       
   385   @param    key Key string to look for
       
   386   @param    notfound Value to return in case of error
       
   387   @return   integer
       
   388 
       
   389   This function queries a dictionary for a key. A key as read from an
       
   390   ini file is given as "section:key". If the key cannot be found,
       
   391   the notfound value is returned.
       
   392 
       
   393   Supported values for integers include the usual C notation
       
   394   so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
       
   395   are supported. Examples:
       
   396 
       
   397   "42"      ->  42
       
   398   "042"     ->  34 (octal -> decimal)
       
   399   "0x42"    ->  66 (hexa  -> decimal)
       
   400 
       
   401   Warning: the conversion may overflow in various ways. Conversion is
       
   402   totally outsourced to strtol(), see the associated man page for overflow
       
   403   handling.
       
   404 
       
   405   Credits: Thanks to A. Becker for suggesting strtol()
       
   406  */
       
   407 /*--------------------------------------------------------------------------*/
       
   408 int iniparser_getint(dictionary * d, const char * key, int notfound)
       
   409 {
       
   410     char    *   str ;
       
   411 
       
   412     str = iniparser_getstring(d, key, INI_INVALID_KEY);
       
   413     if (str==INI_INVALID_KEY) return notfound ;
       
   414     return (int)strtol(str, NULL, 0);
       
   415 }
       
   416 
       
   417 /*-------------------------------------------------------------------------*/
       
   418 /**
       
   419   @brief    Get the string associated to a key, convert to a double
       
   420   @param    d Dictionary to search
       
   421   @param    key Key string to look for
       
   422   @param    notfound Value to return in case of error
       
   423   @return   double
       
   424 
       
   425   This function queries a dictionary for a key. A key as read from an
       
   426   ini file is given as "section:key". If the key cannot be found,
       
   427   the notfound value is returned.
       
   428  */
       
   429 /*--------------------------------------------------------------------------*/
       
   430 double iniparser_getdouble(dictionary * d, const char * key, double notfound)
       
   431 {
       
   432     char    *   str ;
       
   433 
       
   434     str = iniparser_getstring(d, key, INI_INVALID_KEY);
       
   435     if (str==INI_INVALID_KEY) return notfound ;
       
   436     return atof(str);
       
   437 }
       
   438 
       
   439 /*-------------------------------------------------------------------------*/
       
   440 /**
       
   441   @brief    Get the string associated to a key, convert to a boolean
       
   442   @param    d Dictionary to search
       
   443   @param    key Key string to look for
       
   444   @param    notfound Value to return in case of error
       
   445   @return   integer
       
   446 
       
   447   This function queries a dictionary for a key. A key as read from an
       
   448   ini file is given as "section:key". If the key cannot be found,
       
   449   the notfound value is returned.
       
   450 
       
   451   A true boolean is found if one of the following is matched:
       
   452 
       
   453   - A string starting with 'y'
       
   454   - A string starting with 'Y'
       
   455   - A string starting with 't'
       
   456   - A string starting with 'T'
       
   457   - A string starting with '1'
       
   458 
       
   459   A false boolean is found if one of the following is matched:
       
   460 
       
   461   - A string starting with 'n'
       
   462   - A string starting with 'N'
       
   463   - A string starting with 'f'
       
   464   - A string starting with 'F'
       
   465   - A string starting with '0'
       
   466 
       
   467   The notfound value returned if no boolean is identified, does not
       
   468   necessarily have to be 0 or 1.
       
   469  */
       
   470 /*--------------------------------------------------------------------------*/
       
   471 int iniparser_getboolean(dictionary * d, const char * key, int notfound)
       
   472 {
       
   473     char    *   c ;
       
   474     int         ret ;
       
   475 
       
   476     c = iniparser_getstring(d, key, INI_INVALID_KEY);
       
   477     if (c==INI_INVALID_KEY) return notfound ;
       
   478     if (c[0]=='y' || c[0]=='Y' || c[0]=='1' || c[0]=='t' || c[0]=='T') {
       
   479         ret = 1 ;
       
   480     } else if (c[0]=='n' || c[0]=='N' || c[0]=='0' || c[0]=='f' || c[0]=='F') {
       
   481         ret = 0 ;
       
   482     } else {
       
   483         ret = notfound ;
       
   484     }
       
   485     return ret;
       
   486 }
       
   487 
       
   488 /*-------------------------------------------------------------------------*/
       
   489 /**
       
   490   @brief    Finds out if a given entry exists in a dictionary
       
   491   @param    ini     Dictionary to search
       
   492   @param    entry   Name of the entry to look for
       
   493   @return   integer 1 if entry exists, 0 otherwise
       
   494 
       
   495   Finds out if a given entry exists in the dictionary. Since sections
       
   496   are stored as keys with NULL associated values, this is the only way
       
   497   of querying for the presence of sections in a dictionary.
       
   498  */
       
   499 /*--------------------------------------------------------------------------*/
       
   500 int iniparser_find_entry(
       
   501     dictionary  *   ini,
       
   502     const char  *   entry
       
   503 )
       
   504 {
       
   505     int found=0 ;
       
   506     if (iniparser_getstring(ini, entry, INI_INVALID_KEY)!=INI_INVALID_KEY) {
       
   507         found = 1 ;
       
   508     }
       
   509     return found ;
       
   510 }
       
   511 
       
   512 /*-------------------------------------------------------------------------*/
       
   513 /**
       
   514   @brief    Set an entry in a dictionary.
       
   515   @param    ini     Dictionary to modify.
       
   516   @param    entry   Entry to modify (entry name)
       
   517   @param    val     New value to associate to the entry.
       
   518   @return   int 0 if Ok, -1 otherwise.
       
   519 
       
   520   If the given entry can be found in the dictionary, it is modified to
       
   521   contain the provided value. If it cannot be found, -1 is returned.
       
   522   It is Ok to set val to NULL.
       
   523  */
       
   524 /*--------------------------------------------------------------------------*/
       
   525 int iniparser_set(dictionary * ini, const char * entry, const char * val)
       
   526 {
       
   527     return dictionary_set(ini, strlwc(entry), val) ;
       
   528 }
       
   529 
       
   530 /*-------------------------------------------------------------------------*/
       
   531 /**
       
   532   @brief    Delete an entry in a dictionary
       
   533   @param    ini     Dictionary to modify
       
   534   @param    entry   Entry to delete (entry name)
       
   535   @return   void
       
   536 
       
   537   If the given entry can be found, it is deleted from the dictionary.
       
   538  */
       
   539 /*--------------------------------------------------------------------------*/
       
   540 void iniparser_unset(dictionary * ini, const char * entry)
       
   541 {
       
   542     dictionary_unset(ini, strlwc(entry));
       
   543 }
       
   544 
       
   545 /*-------------------------------------------------------------------------*/
       
   546 /**
       
   547   @brief    Load a single line from an INI file
       
   548   @param    input_line  Input line, may be concatenated multi-line input
       
   549   @param    section     Output space to store section
       
   550   @param    key         Output space to store key
       
   551   @param    value       Output space to store value
       
   552   @return   line_status value
       
   553  */
       
   554 /*--------------------------------------------------------------------------*/
       
   555 static line_status iniparser_line(
       
   556     const char * input_line,
       
   557     char * section,
       
   558     char * key,
       
   559     char * value)
       
   560 {   
       
   561     line_status sta ;
       
   562     char        line[ASCIILINESZ+1];
       
   563     int         len ;
       
   564 
       
   565     strcpy(line, strstrip(input_line));
       
   566     len = (int)strlen(line);
       
   567 
       
   568     sta = LINE_UNPROCESSED ;
       
   569     if (len<1) {
       
   570         /* Empty line */
       
   571         sta = LINE_EMPTY ;
       
   572     } else if (line[0]=='#' || line[0]==';') {
       
   573         /* Comment line */
       
   574         sta = LINE_COMMENT ; 
       
   575     } else if (line[0]=='[' && line[len-1]==']') {
       
   576         /* Section name */
       
   577         sscanf(line, "[%[^]]", section);
       
   578         strcpy(section, strstrip(section));
       
   579         strcpy(section, strlwc(section));
       
   580         sta = LINE_SECTION ;
       
   581     } else if (sscanf (line, "%[^=] = \"%[^\"]\"", key, value) == 2
       
   582            ||  sscanf (line, "%[^=] = '%[^\']'",   key, value) == 2
       
   583            ||  sscanf (line, "%[^=] = %[^;#]",     key, value) == 2) {
       
   584         /* Usual key=value, with or without comments */
       
   585         strcpy(key, strstrip(key));
       
   586         strcpy(key, strlwc(key));
       
   587         strcpy(value, strstrip(value));
       
   588         /*
       
   589          * sscanf cannot handle '' or "" as empty values
       
   590          * this is done here
       
   591          */
       
   592         if (!strcmp(value, "\"\"") || (!strcmp(value, "''"))) {
       
   593             value[0]=0 ;
       
   594         }
       
   595         sta = LINE_VALUE ;
       
   596     } else if (sscanf(line, "%[^=] = %[;#]", key, value)==2
       
   597            ||  sscanf(line, "%[^=] %[=]", key, value) == 2) {
       
   598         /*
       
   599          * Special cases:
       
   600          * key=
       
   601          * key=;
       
   602          * key=#
       
   603          */
       
   604         strcpy(key, strstrip(key));
       
   605         strcpy(key, strlwc(key));
       
   606         value[0]=0 ;
       
   607         sta = LINE_VALUE ;
       
   608     } else {
       
   609         /* Generate syntax error */
       
   610         sta = LINE_ERROR ;
       
   611     }
       
   612     return sta ;
       
   613 }
       
   614 
       
   615 /*-------------------------------------------------------------------------*/
       
   616 /**
       
   617   @brief    Parse an ini file and return an allocated dictionary object
       
   618   @param    ininame Name of the ini file to read.
       
   619   @return   Pointer to newly allocated dictionary
       
   620 
       
   621   This is the parser for ini files. This function is called, providing
       
   622   the name of the file to be read. It returns a dictionary object that
       
   623   should not be accessed directly, but through accessor functions
       
   624   instead.
       
   625 
       
   626   The returned dictionary must be freed using iniparser_freedict().
       
   627  */
       
   628 /*--------------------------------------------------------------------------*/
       
   629 dictionary * iniparser_load(const char * ininame)
       
   630 {
       
   631     FILE * in ;
       
   632 
       
   633     char line    [ASCIILINESZ+1] ;
       
   634     char section [ASCIILINESZ+1] ;
       
   635     char key     [ASCIILINESZ+1] ;
       
   636     char tmp     [ASCIILINESZ+1] ;
       
   637     char val     [ASCIILINESZ+1] ;
       
   638 
       
   639     int  last=0 ;
       
   640     int  len ;
       
   641     int  lineno=0 ;
       
   642     int  errs=0;
       
   643 
       
   644     dictionary * dict ;
       
   645 
       
   646     if ((in=fopen(ininame, "r"))==NULL) {
       
   647         fprintf(stderr, "iniparser: cannot open %s\n", ininame);
       
   648         return NULL ;
       
   649     }
       
   650 
       
   651     dict = dictionary_new(0) ;
       
   652     if (!dict) {
       
   653         fclose(in);
       
   654         return NULL ;
       
   655     }
       
   656 
       
   657     memset(line,    0, ASCIILINESZ);
       
   658     memset(section, 0, ASCIILINESZ);
       
   659     memset(key,     0, ASCIILINESZ);
       
   660     memset(val,     0, ASCIILINESZ);
       
   661     last=0 ;
       
   662 
       
   663     while (fgets(line+last, ASCIILINESZ-last, in)!=NULL) {
       
   664         lineno++ ;
       
   665         len = (int)strlen(line)-1;
       
   666         if (len==0)
       
   667             continue;
       
   668         /* Safety check against buffer overflows */
       
   669         if (line[len]!='\n') {
       
   670             fprintf(stderr,
       
   671                     "iniparser: input line too long in %s (%d)\n",
       
   672                     ininame,
       
   673                     lineno);
       
   674             dictionary_del(dict);
       
   675             fclose(in);
       
   676             return NULL ;
       
   677         }
       
   678         /* Get rid of \n and spaces at end of line */
       
   679         while ((len>=0) &&
       
   680                 ((line[len]=='\n') || (isspace(line[len])))) {
       
   681             line[len]=0 ;
       
   682             len-- ;
       
   683         }
       
   684         /* Detect multi-line */
       
   685         if (line[len]=='\\') {
       
   686             /* Multi-line value */
       
   687             last=len ;
       
   688             continue ;
       
   689         } else {
       
   690             last=0 ;
       
   691         }
       
   692         switch (iniparser_line(line, section, key, val)) {
       
   693             case LINE_EMPTY:
       
   694             case LINE_COMMENT:
       
   695             break ;
       
   696 
       
   697             case LINE_SECTION:
       
   698             errs = dictionary_set(dict, section, NULL);
       
   699             break ;
       
   700 
       
   701             case LINE_VALUE:
       
   702             sprintf(tmp, "%s:%s", section, key);
       
   703             errs = dictionary_set(dict, tmp, val) ;
       
   704             break ;
       
   705 
       
   706             case LINE_ERROR:
       
   707             fprintf(stderr, "iniparser: syntax error in %s (%d):\n",
       
   708                     ininame,
       
   709                     lineno);
       
   710             fprintf(stderr, "-> %s\n", line);
       
   711             errs++ ;
       
   712             break;
       
   713 
       
   714             default:
       
   715             break ;
       
   716         }
       
   717         memset(line, 0, ASCIILINESZ);
       
   718         last=0;
       
   719         if (errs<0) {
       
   720             fprintf(stderr, "iniparser: memory allocation failure\n");
       
   721             break ;
       
   722         }
       
   723     }
       
   724     if (errs) {
       
   725         dictionary_del(dict);
       
   726         dict = NULL ;
       
   727     }
       
   728     fclose(in);
       
   729     return dict ;
       
   730 }
       
   731 
       
   732 /*-------------------------------------------------------------------------*/
       
   733 /**
       
   734   @brief    Free all memory associated to an ini dictionary
       
   735   @param    d Dictionary to free
       
   736   @return   void
       
   737 
       
   738   Free all memory associated to an ini dictionary.
       
   739   It is mandatory to call this function before the dictionary object
       
   740   gets out of the current context.
       
   741  */
       
   742 /*--------------------------------------------------------------------------*/
       
   743 void iniparser_freedict(dictionary * d)
       
   744 {
       
   745     dictionary_del(d);
       
   746 }
       
   747 
       
   748 /* vim: set ts=4 et sw=4 tw=75 */