mirror of
				https://github.com/nyanmisaka/mpp.git
				synced 2025-10-31 20:42:53 +08:00 
			
		
		
		
	 52c93a4955
			
		
	
	52c93a4955
	
	
	
		
			
			Change-Id: Id29dc65a732aa62f4614f1d602545c04e7de054b Signed-off-by: Herman Chen <herman.chen@rock-chips.com>
		
			
				
	
	
		
			837 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			837 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| 
 | |
| /*-------------------------------------------------------------------------*/
 | |
| /**
 | |
|    @file    iniparser.c
 | |
|    @author  N. Devillard
 | |
|    @brief   Parser for ini files.
 | |
| */
 | |
| /*--------------------------------------------------------------------------*/
 | |
| /*---------------------------- Includes ------------------------------------*/
 | |
| #include <ctype.h>
 | |
| #include <stdarg.h>
 | |
| #include "iniparser.h"
 | |
| 
 | |
| /*---------------------------- Defines -------------------------------------*/
 | |
| #define ASCIILINESZ         (1024)
 | |
| #define INI_INVALID_KEY     ((char*)-1)
 | |
| 
 | |
| /*---------------------------------------------------------------------------
 | |
|                         Private to this module
 | |
|  ---------------------------------------------------------------------------*/
 | |
| /**
 | |
|  * This enum stores the status for each parsed line (internal use only).
 | |
|  */
 | |
| typedef enum _line_status_ {
 | |
|     LINE_UNPROCESSED,
 | |
|     LINE_ERROR,
 | |
|     LINE_EMPTY,
 | |
|     LINE_COMMENT,
 | |
|     LINE_SECTION,
 | |
|     LINE_VALUE
 | |
| } line_status ;
 | |
| 
 | |
| /*-------------------------------------------------------------------------*/
 | |
| /**
 | |
|   @brief    Convert a string to lowercase.
 | |
|   @param    in   String to convert.
 | |
|   @param    out Output buffer.
 | |
|   @param    len Size of the out buffer.
 | |
|   @return   ptr to the out buffer or NULL if an error occured.
 | |
| 
 | |
|   This function convert a string into lowercase.
 | |
|   At most len - 1 elements of the input string will be converted.
 | |
|  */
 | |
| /*--------------------------------------------------------------------------*/
 | |
| static const char * strlwc(const char * in, char *out, unsigned len)
 | |
| {
 | |
|     unsigned i ;
 | |
| 
 | |
|     if (in == NULL || out == NULL || len == 0) return NULL ;
 | |
|     i = 0 ;
 | |
|     while (in[i] != '\0' && i < len - 1) {
 | |
|         out[i] = (char)tolower((int)in[i]);
 | |
|         i++ ;
 | |
|     }
 | |
|     out[i] = '\0';
 | |
|     return out ;
 | |
| }
 | |
| 
 | |
| /*-------------------------------------------------------------------------*/
 | |
| /**
 | |
|   @brief    Duplicate a string
 | |
|   @param    s String to duplicate
 | |
|   @return   Pointer to a newly allocated string, to be freed with free()
 | |
| 
 | |
|   This is a replacement for strdup(). This implementation is provided
 | |
|   for systems that do not have it.
 | |
|  */
 | |
| /*--------------------------------------------------------------------------*/
 | |
| static char * xstrdup(const char * s)
 | |
| {
 | |
|     char * t ;
 | |
|     size_t len ;
 | |
|     if (!s)
 | |
|         return NULL ;
 | |
| 
 | |
|     len = strlen(s) + 1 ;
 | |
|     t = (char*) malloc(len) ;
 | |
|     if (t) {
 | |
|         memcpy(t, s, len) ;
 | |
|     }
 | |
|     return t ;
 | |
| }
 | |
| 
 | |
| /*-------------------------------------------------------------------------*/
 | |
| /**
 | |
|   @brief    Remove blanks at the beginning and the end of a string.
 | |
|   @param    str  String to parse and alter.
 | |
|   @return   unsigned New size of the string.
 | |
|  */
 | |
| /*--------------------------------------------------------------------------*/
 | |
| static unsigned strstrip(char * s)
 | |
| {
 | |
|     char *last = NULL ;
 | |
|     char *dest = s;
 | |
| 
 | |
|     if (s == NULL) return 0;
 | |
| 
 | |
|     last = s + strlen(s);
 | |
|     while (isspace((int)*s) && *s) s++;
 | |
|     while (last > s) {
 | |
|         if (!isspace((int) * (last - 1)))
 | |
|             break ;
 | |
|         last -- ;
 | |
|     }
 | |
|     *last = (char)0;
 | |
| 
 | |
|     memmove(dest, s, last - s + 1);
 | |
|     return last - s;
 | |
| }
 | |
| 
 | |
| /*-------------------------------------------------------------------------*/
 | |
| /**
 | |
|   @brief    Default error callback for iniparser: wraps `fprintf(stderr, ...)`.
 | |
|  */
 | |
| /*--------------------------------------------------------------------------*/
 | |
| static int default_error_callback(const char *format, ...)
 | |
| {
 | |
|     int ret;
 | |
|     va_list argptr;
 | |
|     va_start(argptr, format);
 | |
|     ret = vfprintf(stderr, format, argptr);
 | |
|     va_end(argptr);
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| static int (*iniparser_error_callback)(const char*, ...) = default_error_callback;
 | |
| 
 | |
| /*-------------------------------------------------------------------------*/
 | |
| /**
 | |
|   @brief    Configure a function to receive the error messages.
 | |
|   @param    errback  Function to call.
 | |
| 
 | |
|   By default, the error will be printed on stderr. If a null pointer is passed
 | |
|   as errback the error callback will be switched back to default.
 | |
|  */
 | |
| /*--------------------------------------------------------------------------*/
 | |
| void iniparser_set_error_callback(int (*errback)(const char *, ...))
 | |
| {
 | |
|     if (errback) {
 | |
|         iniparser_error_callback = errback;
 | |
|     } else {
 | |
|         iniparser_error_callback = default_error_callback;
 | |
|     }
 | |
| }
 | |
| 
 | |
| /*-------------------------------------------------------------------------*/
 | |
| /**
 | |
|   @brief    Get number of sections in a dictionary
 | |
|   @param    d   Dictionary to examine
 | |
|   @return   int Number of sections found in dictionary
 | |
| 
 | |
|   This function returns the number of sections found in a dictionary.
 | |
|   The test to recognize sections is done on the string stored in the
 | |
|   dictionary: a section name is given as "section" whereas a key is
 | |
|   stored as "section:key", thus the test looks for entries that do not
 | |
|   contain a colon.
 | |
| 
 | |
|   This clearly fails in the case a section name contains a colon, but
 | |
|   this should simply be avoided.
 | |
| 
 | |
|   This function returns -1 in case of error.
 | |
|  */
 | |
| /*--------------------------------------------------------------------------*/
 | |
| int iniparser_getnsec(const dictionary * d)
 | |
| {
 | |
|     int i ;
 | |
|     int nsec ;
 | |
| 
 | |
|     if (d == NULL) return -1 ;
 | |
|     nsec = 0 ;
 | |
|     for (i = 0 ; i < d->size ; i++) {
 | |
|         if (d->key[i] == NULL)
 | |
|             continue ;
 | |
|         if (strchr(d->key[i], ':') == NULL) {
 | |
|             nsec ++ ;
 | |
|         }
 | |
|     }
 | |
|     return nsec ;
 | |
| }
 | |
| 
 | |
| /*-------------------------------------------------------------------------*/
 | |
| /**
 | |
|   @brief    Get name for section n in a dictionary.
 | |
|   @param    d   Dictionary to examine
 | |
|   @param    n   Section number (from 0 to nsec-1).
 | |
|   @return   Pointer to char string
 | |
| 
 | |
|   This function locates the n-th section in a dictionary and returns
 | |
|   its name as a pointer to a string statically allocated inside the
 | |
|   dictionary. Do not free or modify the returned string!
 | |
| 
 | |
|   This function returns NULL in case of error.
 | |
|  */
 | |
| /*--------------------------------------------------------------------------*/
 | |
| const char * iniparser_getsecname(const dictionary * d, int n)
 | |
| {
 | |
|     int i ;
 | |
|     int foundsec ;
 | |
| 
 | |
|     if (d == NULL || n < 0) return NULL ;
 | |
|     foundsec = 0 ;
 | |
|     for (i = 0 ; i < d->size ; i++) {
 | |
|         if (d->key[i] == NULL)
 | |
|             continue ;
 | |
|         if (strchr(d->key[i], ':') == NULL) {
 | |
|             foundsec++ ;
 | |
|             if (foundsec > n)
 | |
|                 break ;
 | |
|         }
 | |
|     }
 | |
|     if (foundsec <= n) {
 | |
|         return NULL ;
 | |
|     }
 | |
|     return d->key[i] ;
 | |
| }
 | |
| 
 | |
| /*-------------------------------------------------------------------------*/
 | |
| /**
 | |
|   @brief    Dump a dictionary to an opened file pointer.
 | |
|   @param    d   Dictionary to dump.
 | |
|   @param    f   Opened file pointer to dump to.
 | |
|   @return   void
 | |
| 
 | |
|   This function prints out the contents of a dictionary, one element by
 | |
|   line, onto the provided file pointer. It is OK to specify @c stderr
 | |
|   or @c stdout as output files. This function is meant for debugging
 | |
|   purposes mostly.
 | |
|  */
 | |
| /*--------------------------------------------------------------------------*/
 | |
| void iniparser_dump(const dictionary * d, FILE * f)
 | |
| {
 | |
|     int     i ;
 | |
| 
 | |
|     if (d == NULL || f == NULL) return ;
 | |
|     for (i = 0 ; i < d->size ; i++) {
 | |
|         if (d->key[i] == NULL)
 | |
|             continue ;
 | |
|         if (d->val[i] != NULL) {
 | |
|             fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]);
 | |
|         } else {
 | |
|             fprintf(f, "[%s]=UNDEF\n", d->key[i]);
 | |
|         }
 | |
|     }
 | |
|     return ;
 | |
| }
 | |
| 
 | |
| /*-------------------------------------------------------------------------*/
 | |
| /**
 | |
|   @brief    Save a dictionary to a loadable ini file
 | |
|   @param    d   Dictionary to dump
 | |
|   @param    f   Opened file pointer to dump to
 | |
|   @return   void
 | |
| 
 | |
|   This function dumps a given dictionary into a loadable ini file.
 | |
|   It is Ok to specify @c stderr or @c stdout as output files.
 | |
|  */
 | |
| /*--------------------------------------------------------------------------*/
 | |
| void iniparser_dump_ini(const dictionary * d, FILE * f)
 | |
| {
 | |
|     int          i ;
 | |
|     int          nsec ;
 | |
|     const char * secname ;
 | |
| 
 | |
|     if (d == NULL || f == NULL) return ;
 | |
| 
 | |
|     nsec = iniparser_getnsec(d);
 | |
|     if (nsec < 1) {
 | |
|         /* No section in file: dump all keys as they are */
 | |
|         for (i = 0 ; i < d->size ; i++) {
 | |
|             if (d->key[i] == NULL)
 | |
|                 continue ;
 | |
|             fprintf(f, "%s = %s\n", d->key[i], d->val[i]);
 | |
|         }
 | |
|         return ;
 | |
|     }
 | |
|     for (i = 0 ; i < nsec ; i++) {
 | |
|         secname = iniparser_getsecname(d, i) ;
 | |
|         iniparser_dumpsection_ini(d, secname, f);
 | |
|     }
 | |
|     fprintf(f, "\n");
 | |
|     return ;
 | |
| }
 | |
| 
 | |
| /*-------------------------------------------------------------------------*/
 | |
| /**
 | |
|   @brief    Save a dictionary section to a loadable ini file
 | |
|   @param    d   Dictionary to dump
 | |
|   @param    s   Section name of dictionary to dump
 | |
|   @param    f   Opened file pointer to dump to
 | |
|   @return   void
 | |
| 
 | |
|   This function dumps a given section of a given dictionary into a loadable ini
 | |
|   file.  It is Ok to specify @c stderr or @c stdout as output files.
 | |
|  */
 | |
| /*--------------------------------------------------------------------------*/
 | |
| void iniparser_dumpsection_ini(const dictionary * d, const char * s, FILE * f)
 | |
| {
 | |
|     int     j ;
 | |
|     char    keym[ASCIILINESZ + 1];
 | |
|     int     seclen ;
 | |
| 
 | |
|     if (d == NULL || f == NULL) return ;
 | |
|     if (! iniparser_find_entry(d, s)) return ;
 | |
| 
 | |
|     seclen  = (int)strlen(s);
 | |
|     fprintf(f, "\n[%s]\n", s);
 | |
|     sprintf(keym, "%s:", s);
 | |
|     for (j = 0 ; j < d->size ; j++) {
 | |
|         if (d->key[j] == NULL)
 | |
|             continue ;
 | |
|         if (!strncmp(d->key[j], keym, seclen + 1)) {
 | |
|             fprintf(f,
 | |
|                     "%-30s = %s\n",
 | |
|                     d->key[j] + seclen + 1,
 | |
|                     d->val[j] ? d->val[j] : "");
 | |
|         }
 | |
|     }
 | |
|     fprintf(f, "\n");
 | |
|     return ;
 | |
| }
 | |
| 
 | |
| /*-------------------------------------------------------------------------*/
 | |
| /**
 | |
|   @brief    Get the number of keys in a section of a dictionary.
 | |
|   @param    d   Dictionary to examine
 | |
|   @param    s   Section name of dictionary to examine
 | |
|   @return   Number of keys in section
 | |
|  */
 | |
| /*--------------------------------------------------------------------------*/
 | |
| int iniparser_getsecnkeys(const dictionary * d, const char * s)
 | |
| {
 | |
|     int     seclen, nkeys ;
 | |
|     char    keym[ASCIILINESZ + 1];
 | |
|     int j ;
 | |
| 
 | |
|     nkeys = 0;
 | |
| 
 | |
|     if (d == NULL) return nkeys;
 | |
|     if (! iniparser_find_entry(d, s)) return nkeys;
 | |
| 
 | |
|     seclen  = (int)strlen(s);
 | |
|     strlwc(s, keym, sizeof(keym));
 | |
|     keym[seclen] = ':';
 | |
| 
 | |
|     for (j = 0 ; j < d->size ; j++) {
 | |
|         if (d->key[j] == NULL)
 | |
|             continue ;
 | |
|         if (!strncmp(d->key[j], keym, seclen + 1))
 | |
|             nkeys++;
 | |
|     }
 | |
| 
 | |
|     return nkeys;
 | |
| 
 | |
| }
 | |
| 
 | |
| /*-------------------------------------------------------------------------*/
 | |
| /**
 | |
|   @brief    Get the number of keys in a section of a dictionary.
 | |
|   @param    d    Dictionary to examine
 | |
|   @param    s    Section name of dictionary to examine
 | |
|   @param    keys Already allocated array to store the keys in
 | |
|   @return   The pointer passed as `keys` argument or NULL in case of error
 | |
| 
 | |
|   This function queries a dictionary and finds all keys in a given section.
 | |
|   The keys argument should be an array of pointers which size has been
 | |
|   determined by calling `iniparser_getsecnkeys` function prior to this one.
 | |
| 
 | |
|   Each pointer in the returned char pointer-to-pointer is pointing to
 | |
|   a string allocated in the dictionary; do not free or modify them.
 | |
|  */
 | |
| /*--------------------------------------------------------------------------*/
 | |
| const char ** iniparser_getseckeys(const dictionary * d, const char * s, const char ** keys)
 | |
| {
 | |
|     int i, j, seclen ;
 | |
|     char keym[ASCIILINESZ + 1];
 | |
| 
 | |
|     if (d == NULL || keys == NULL) return NULL;
 | |
|     if (! iniparser_find_entry(d, s)) return NULL;
 | |
| 
 | |
|     seclen  = (int)strlen(s);
 | |
|     strlwc(s, keym, sizeof(keym));
 | |
|     keym[seclen] = ':';
 | |
| 
 | |
|     i = 0;
 | |
| 
 | |
|     for (j = 0 ; j < d->size ; j++) {
 | |
|         if (d->key[j] == NULL)
 | |
|             continue ;
 | |
|         if (!strncmp(d->key[j], keym, seclen + 1)) {
 | |
|             keys[i] = d->key[j];
 | |
|             i++;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return keys;
 | |
| }
 | |
| 
 | |
| /*-------------------------------------------------------------------------*/
 | |
| /**
 | |
|   @brief    Get the string associated to a key
 | |
|   @param    d       Dictionary to search
 | |
|   @param    key     Key string to look for
 | |
|   @param    def     Default value to return if key not found.
 | |
|   @return   pointer to statically allocated character string
 | |
| 
 | |
|   This function queries a dictionary for a key. A key as read from an
 | |
|   ini file is given as "section:key". If the key cannot be found,
 | |
|   the pointer passed as 'def' is returned.
 | |
|   The returned char pointer is pointing to a string allocated in
 | |
|   the dictionary, do not free or modify it.
 | |
|  */
 | |
| /*--------------------------------------------------------------------------*/
 | |
| const char * iniparser_getstring(const dictionary * d, const char * key, const char * def)
 | |
| {
 | |
|     const char * lc_key ;
 | |
|     const char * sval ;
 | |
|     char tmp_str[ASCIILINESZ + 1];
 | |
| 
 | |
|     if (d == NULL || key == NULL)
 | |
|         return def ;
 | |
| 
 | |
|     lc_key = strlwc(key, tmp_str, sizeof(tmp_str));
 | |
|     sval = dictionary_get(d, lc_key, def);
 | |
|     return sval ;
 | |
| }
 | |
| 
 | |
| /*-------------------------------------------------------------------------*/
 | |
| /**
 | |
|   @brief    Get the string associated to a key, convert to an long int
 | |
|   @param    d Dictionary to search
 | |
|   @param    key Key string to look for
 | |
|   @param    notfound Value to return in case of error
 | |
|   @return   long integer
 | |
| 
 | |
|   This function queries a dictionary for a key. A key as read from an
 | |
|   ini file is given as "section:key". If the key cannot be found,
 | |
|   the notfound value is returned.
 | |
| 
 | |
|   Supported values for integers include the usual C notation
 | |
|   so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
 | |
|   are supported. Examples:
 | |
| 
 | |
|   "42"      ->  42
 | |
|   "042"     ->  34 (octal -> decimal)
 | |
|   "0x42"    ->  66 (hexa  -> decimal)
 | |
| 
 | |
|   Warning: the conversion may overflow in various ways. Conversion is
 | |
|   totally outsourced to strtol(), see the associated man page for overflow
 | |
|   handling.
 | |
| 
 | |
|   Credits: Thanks to A. Becker for suggesting strtol()
 | |
|  */
 | |
| /*--------------------------------------------------------------------------*/
 | |
| long int iniparser_getlongint(const dictionary * d, const char * key, long int notfound)
 | |
| {
 | |
|     const char * str ;
 | |
| 
 | |
|     str = iniparser_getstring(d, key, INI_INVALID_KEY);
 | |
|     if (str == INI_INVALID_KEY) return notfound ;
 | |
|     return strtol(str, NULL, 0);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*-------------------------------------------------------------------------*/
 | |
| /**
 | |
|   @brief    Get the string associated to a key, convert to an int
 | |
|   @param    d Dictionary to search
 | |
|   @param    key Key string to look for
 | |
|   @param    notfound Value to return in case of error
 | |
|   @return   integer
 | |
| 
 | |
|   This function queries a dictionary for a key. A key as read from an
 | |
|   ini file is given as "section:key". If the key cannot be found,
 | |
|   the notfound value is returned.
 | |
| 
 | |
|   Supported values for integers include the usual C notation
 | |
|   so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
 | |
|   are supported. Examples:
 | |
| 
 | |
|   "42"      ->  42
 | |
|   "042"     ->  34 (octal -> decimal)
 | |
|   "0x42"    ->  66 (hexa  -> decimal)
 | |
| 
 | |
|   Warning: the conversion may overflow in various ways. Conversion is
 | |
|   totally outsourced to strtol(), see the associated man page for overflow
 | |
|   handling.
 | |
| 
 | |
|   Credits: Thanks to A. Becker for suggesting strtol()
 | |
|  */
 | |
| /*--------------------------------------------------------------------------*/
 | |
| int iniparser_getint(const dictionary * d, const char * key, int notfound)
 | |
| {
 | |
|     return (int)iniparser_getlongint(d, key, notfound);
 | |
| }
 | |
| 
 | |
| /*-------------------------------------------------------------------------*/
 | |
| /**
 | |
|   @brief    Get the string associated to a key, convert to a double
 | |
|   @param    d Dictionary to search
 | |
|   @param    key Key string to look for
 | |
|   @param    notfound Value to return in case of error
 | |
|   @return   double
 | |
| 
 | |
|   This function queries a dictionary for a key. A key as read from an
 | |
|   ini file is given as "section:key". If the key cannot be found,
 | |
|   the notfound value is returned.
 | |
|  */
 | |
| /*--------------------------------------------------------------------------*/
 | |
| double iniparser_getdouble(const dictionary * d, const char * key, double notfound)
 | |
| {
 | |
|     const char * str ;
 | |
| 
 | |
|     str = iniparser_getstring(d, key, INI_INVALID_KEY);
 | |
|     if (str == INI_INVALID_KEY) return notfound ;
 | |
|     return atof(str);
 | |
| }
 | |
| 
 | |
| /*-------------------------------------------------------------------------*/
 | |
| /**
 | |
|   @brief    Get the string associated to a key, convert to a boolean
 | |
|   @param    d Dictionary to search
 | |
|   @param    key Key string to look for
 | |
|   @param    notfound Value to return in case of error
 | |
|   @return   integer
 | |
| 
 | |
|   This function queries a dictionary for a key. A key as read from an
 | |
|   ini file is given as "section:key". If the key cannot be found,
 | |
|   the notfound value is returned.
 | |
| 
 | |
|   A true boolean is found if one of the following is matched:
 | |
| 
 | |
|   - A string starting with 'y'
 | |
|   - A string starting with 'Y'
 | |
|   - A string starting with 't'
 | |
|   - A string starting with 'T'
 | |
|   - A string starting with '1'
 | |
| 
 | |
|   A false boolean is found if one of the following is matched:
 | |
| 
 | |
|   - A string starting with 'n'
 | |
|   - A string starting with 'N'
 | |
|   - A string starting with 'f'
 | |
|   - A string starting with 'F'
 | |
|   - A string starting with '0'
 | |
| 
 | |
|   The notfound value returned if no boolean is identified, does not
 | |
|   necessarily have to be 0 or 1.
 | |
|  */
 | |
| /*--------------------------------------------------------------------------*/
 | |
| int iniparser_getboolean(const dictionary * d, const char * key, int notfound)
 | |
| {
 | |
|     int          ret ;
 | |
|     const char * c ;
 | |
| 
 | |
|     c = iniparser_getstring(d, key, INI_INVALID_KEY);
 | |
|     if (c == INI_INVALID_KEY) return notfound ;
 | |
|     if (c[0] == 'y' || c[0] == 'Y' || c[0] == '1' || c[0] == 't' || c[0] == 'T') {
 | |
|         ret = 1 ;
 | |
|     } else if (c[0] == 'n' || c[0] == 'N' || c[0] == '0' || c[0] == 'f' || c[0] == 'F') {
 | |
|         ret = 0 ;
 | |
|     } else {
 | |
|         ret = notfound ;
 | |
|     }
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| /*-------------------------------------------------------------------------*/
 | |
| /**
 | |
|   @brief    Finds out if a given entry exists in a dictionary
 | |
|   @param    ini     Dictionary to search
 | |
|   @param    entry   Name of the entry to look for
 | |
|   @return   integer 1 if entry exists, 0 otherwise
 | |
| 
 | |
|   Finds out if a given entry exists in the dictionary. Since sections
 | |
|   are stored as keys with NULL associated values, this is the only way
 | |
|   of querying for the presence of sections in a dictionary.
 | |
|  */
 | |
| /*--------------------------------------------------------------------------*/
 | |
| int iniparser_find_entry(const dictionary * ini, const char * entry)
 | |
| {
 | |
|     int found = 0 ;
 | |
|     if (iniparser_getstring(ini, entry, INI_INVALID_KEY) != INI_INVALID_KEY) {
 | |
|         found = 1 ;
 | |
|     }
 | |
|     return found ;
 | |
| }
 | |
| 
 | |
| /*-------------------------------------------------------------------------*/
 | |
| /**
 | |
|   @brief    Set an entry in a dictionary.
 | |
|   @param    ini     Dictionary to modify.
 | |
|   @param    entry   Entry to modify (entry name)
 | |
|   @param    val     New value to associate to the entry.
 | |
|   @return   int 0 if Ok, -1 otherwise.
 | |
| 
 | |
|   If the given entry can be found in the dictionary, it is modified to
 | |
|   contain the provided value. If it cannot be found, the entry is created.
 | |
|   It is Ok to set val to NULL.
 | |
|  */
 | |
| /*--------------------------------------------------------------------------*/
 | |
| int iniparser_set(dictionary * ini, const char * entry, const char * val)
 | |
| {
 | |
|     char tmp_str[ASCIILINESZ + 1];
 | |
|     return dictionary_set(ini, strlwc(entry, tmp_str, sizeof(tmp_str)), val) ;
 | |
| }
 | |
| 
 | |
| /*-------------------------------------------------------------------------*/
 | |
| /**
 | |
|   @brief    Delete an entry in a dictionary
 | |
|   @param    ini     Dictionary to modify
 | |
|   @param    entry   Entry to delete (entry name)
 | |
|   @return   void
 | |
| 
 | |
|   If the given entry can be found, it is deleted from the dictionary.
 | |
|  */
 | |
| /*--------------------------------------------------------------------------*/
 | |
| void iniparser_unset(dictionary * ini, const char * entry)
 | |
| {
 | |
|     char tmp_str[ASCIILINESZ + 1];
 | |
|     dictionary_unset(ini, strlwc(entry, tmp_str, sizeof(tmp_str)));
 | |
| }
 | |
| 
 | |
| /*-------------------------------------------------------------------------*/
 | |
| /**
 | |
|   @brief    Load a single line from an INI file
 | |
|   @param    input_line  Input line, may be concatenated multi-line input
 | |
|   @param    section     Output space to store section
 | |
|   @param    key         Output space to store key
 | |
|   @param    value       Output space to store value
 | |
|   @return   line_status value
 | |
|  */
 | |
| /*--------------------------------------------------------------------------*/
 | |
| static line_status iniparser_line(
 | |
|     const char * input_line,
 | |
|     char * section,
 | |
|     char * key,
 | |
|     char * value)
 | |
| {
 | |
|     line_status sta ;
 | |
|     char * line = NULL;
 | |
|     size_t      len ;
 | |
| 
 | |
|     line = xstrdup(input_line);
 | |
|     len = strstrip(line);
 | |
| 
 | |
|     sta = LINE_UNPROCESSED ;
 | |
|     if (len < 1) {
 | |
|         /* Empty line */
 | |
|         sta = LINE_EMPTY ;
 | |
|     } else if (line[0] == '#' || line[0] == ';') {
 | |
|         /* Comment line */
 | |
|         sta = LINE_COMMENT ;
 | |
|     } else if (line[0] == '[' && line[len - 1] == ']') {
 | |
|         /* Section name */
 | |
|         sscanf(line, "[%[^]]", section);
 | |
|         strstrip(section);
 | |
|         strlwc(section, section, len);
 | |
|         sta = LINE_SECTION ;
 | |
|     } else if (sscanf (line, "%[^=] = \"%[^\"]\"", key, value) == 2
 | |
|                ||  sscanf (line, "%[^=] = '%[^\']'",   key, value) == 2) {
 | |
|         /* Usual key=value with quotes, with or without comments */
 | |
|         strstrip(key);
 | |
|         strlwc(key, key, len);
 | |
|         /* Don't strip spaces from values surrounded with quotes */
 | |
|         sta = LINE_VALUE ;
 | |
|     } else if (sscanf (line, "%[^=] = %[^;#]", key, value) == 2) {
 | |
|         /* Usual key=value without quotes, with or without comments */
 | |
|         strstrip(key);
 | |
|         strlwc(key, key, len);
 | |
|         strstrip(value);
 | |
|         /*
 | |
|          * sscanf cannot handle '' or "" as empty values
 | |
|          * this is done here
 | |
|          */
 | |
|         if (!strcmp(value, "\"\"") || (!strcmp(value, "''"))) {
 | |
|             value[0] = 0 ;
 | |
|         }
 | |
|         sta = LINE_VALUE ;
 | |
|     } else if (sscanf(line, "%[^=] = %[;#]", key, value) == 2
 | |
|                ||  sscanf(line, "%[^=] %[=]", key, value) == 2) {
 | |
|         /*
 | |
|          * Special cases:
 | |
|          * key=
 | |
|          * key=;
 | |
|          * key=#
 | |
|          */
 | |
|         strstrip(key);
 | |
|         strlwc(key, key, len);
 | |
|         value[0] = 0 ;
 | |
|         sta = LINE_VALUE ;
 | |
|     } else {
 | |
|         /* Generate syntax error */
 | |
|         sta = LINE_ERROR ;
 | |
|     }
 | |
| 
 | |
|     free(line);
 | |
|     return sta ;
 | |
| }
 | |
| 
 | |
| /*-------------------------------------------------------------------------*/
 | |
| /**
 | |
|   @brief    Parse an ini file and return an allocated dictionary object
 | |
|   @param    ininame Name of the ini file to read.
 | |
|   @return   Pointer to newly allocated dictionary
 | |
| 
 | |
|   This is the parser for ini files. This function is called, providing
 | |
|   the name of the file to be read. It returns a dictionary object that
 | |
|   should not be accessed directly, but through accessor functions
 | |
|   instead.
 | |
| 
 | |
|   The returned dictionary must be freed using iniparser_freedict().
 | |
|  */
 | |
| /*--------------------------------------------------------------------------*/
 | |
| dictionary * iniparser_load(const char * ininame)
 | |
| {
 | |
|     FILE * in ;
 | |
| 
 | |
|     char line    [ASCIILINESZ + 1] ;
 | |
|     char section [ASCIILINESZ + 1] ;
 | |
|     char key     [ASCIILINESZ + 1] ;
 | |
|     char tmp     [(ASCIILINESZ * 2) + 2] ;
 | |
|     char val     [ASCIILINESZ + 1] ;
 | |
| 
 | |
|     int  last = 0 ;
 | |
|     int  len ;
 | |
|     int  lineno = 0 ;
 | |
|     int  errs = 0;
 | |
|     int  mem_err = 0;
 | |
| 
 | |
|     dictionary * dict ;
 | |
| 
 | |
|     if ((in = fopen(ininame, "r")) == NULL) {
 | |
|         iniparser_error_callback("iniparser: cannot open %s\n", ininame);
 | |
|         return NULL ;
 | |
|     }
 | |
| 
 | |
|     dict = dictionary_new(0) ;
 | |
|     if (!dict) {
 | |
|         fclose(in);
 | |
|         return NULL ;
 | |
|     }
 | |
| 
 | |
|     memset(line,    0, ASCIILINESZ);
 | |
|     memset(section, 0, ASCIILINESZ);
 | |
|     memset(key,     0, ASCIILINESZ);
 | |
|     memset(val,     0, ASCIILINESZ);
 | |
|     last = 0 ;
 | |
| 
 | |
|     while (fgets(line + last, ASCIILINESZ - last, in) != NULL) {
 | |
|         lineno++ ;
 | |
|         len = (int)strlen(line) - 1;
 | |
|         if (len <= 0)
 | |
|             continue;
 | |
|         /* Safety check against buffer overflows */
 | |
|         if (line[len] != '\n' && !feof(in)) {
 | |
|             iniparser_error_callback(
 | |
|                 "iniparser: input line too long in %s (%d)\n",
 | |
|                 ininame,
 | |
|                 lineno);
 | |
|             dictionary_del(dict);
 | |
|             fclose(in);
 | |
|             return NULL ;
 | |
|         }
 | |
|         /* Get rid of \n and spaces at end of line */
 | |
|         while ((len >= 0) &&
 | |
|                ((line[len] == '\n') || (isspace(line[len])))) {
 | |
|             line[len] = 0 ;
 | |
|             len-- ;
 | |
|         }
 | |
|         if (len < 0) { /* Line was entirely \n and/or spaces */
 | |
|             len = 0;
 | |
|         }
 | |
|         /* Detect multi-line */
 | |
|         if (line[len] == '\\') {
 | |
|             /* Multi-line value */
 | |
|             last = len ;
 | |
|             continue ;
 | |
|         } else {
 | |
|             last = 0 ;
 | |
|         }
 | |
|         switch (iniparser_line(line, section, key, val)) {
 | |
|         case LINE_EMPTY:
 | |
|         case LINE_COMMENT:
 | |
|             break ;
 | |
| 
 | |
|         case LINE_SECTION:
 | |
|             mem_err = dictionary_set(dict, section, NULL);
 | |
|             break ;
 | |
| 
 | |
|         case LINE_VALUE:
 | |
|             sprintf(tmp, "%s:%s", section, key);
 | |
|             mem_err = dictionary_set(dict, tmp, val);
 | |
|             break ;
 | |
| 
 | |
|         case LINE_ERROR:
 | |
|             iniparser_error_callback(
 | |
|                 "iniparser: syntax error in %s (%d):\n-> %s\n",
 | |
|                 ininame,
 | |
|                 lineno,
 | |
|                 line);
 | |
|             errs++ ;
 | |
|             break;
 | |
| 
 | |
|         default:
 | |
|             break ;
 | |
|         }
 | |
|         memset(line, 0, ASCIILINESZ);
 | |
|         last = 0;
 | |
|         if (mem_err < 0) {
 | |
|             iniparser_error_callback("iniparser: memory allocation failure\n");
 | |
|             break ;
 | |
|         }
 | |
|     }
 | |
|     if (errs) {
 | |
|         dictionary_del(dict);
 | |
|         dict = NULL ;
 | |
|     }
 | |
|     fclose(in);
 | |
|     return dict ;
 | |
| }
 | |
| 
 | |
| /*-------------------------------------------------------------------------*/
 | |
| /**
 | |
|   @brief    Free all memory associated to an ini dictionary
 | |
|   @param    d Dictionary to free
 | |
|   @return   void
 | |
| 
 | |
|   Free all memory associated to an ini dictionary.
 | |
|   It is mandatory to call this function before the dictionary object
 | |
|   gets out of the current context.
 | |
|  */
 | |
| /*--------------------------------------------------------------------------*/
 | |
| void iniparser_freedict(dictionary * d)
 | |
| {
 | |
|     dictionary_del(d);
 | |
| }
 |