diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/dictionary.c | 428 | ||||
| -rw-r--r-- | lib/libiniparser.c | 502 | 
2 files changed, 558 insertions, 372 deletions
| diff --git a/lib/dictionary.c b/lib/dictionary.c index f4b7468..85dfdc0 100644 --- a/lib/dictionary.c +++ b/lib/dictionary.c @@ -1,10 +1,8 @@  /*-------------------------------------------------------------------------*/  /** -   @file	dictionary.c -   @author	N. Devillard -   @date	Sep 2007 -   @version	$Revision: 1.27 $ -   @brief	Implements a dictionary for string variables. +   @file    dictionary.c +   @author  N. Devillard +   @brief   Implements a dictionary for string variables.     This module implements a simple dictionary object, i.e. a list     of string/string associations. This object is useful to store e.g. @@ -12,48 +10,22 @@  */  /*--------------------------------------------------------------------------*/ -/* -	$Id: dictionary.c,v 1.27 2007-11-23 21:39:18 ndevilla Exp $ -	$Revision: 1.27 $ -*/  /*--------------------------------------------------------------------------- -   								Includes +                                Includes   ---------------------------------------------------------------------------*/  #include "dictionary.h"  #include <stdio.h>  #include <stdlib.h>  #include <string.h> -#include <unistd.h> - -/** Maximum value size for integers and doubles. */ -#define MAXVALSZ	1024  /** Minimal allocated number of entries in a dictionary */ -#define DICTMINSZ	128 - -/** Invalid key token */ -#define DICT_INVALID_KEY    ((char*)-1) +#define DICTMINSZ   128  /*--------------------------------------------------------------------------- -  							Private functions +                            Private functions   ---------------------------------------------------------------------------*/ -/* Doubles the allocated size associated to a pointer */ -/* 'size' is the current allocated size. */ -static void * mem_double(void * ptr, int size) -{ -    void * newptr ; - -    newptr = calloc(2*size, 1); -    if (newptr==NULL) { -        return NULL ; -    } -    memcpy(newptr, ptr, size); -    free(ptr); -    return newptr ; -} -  /*-------------------------------------------------------------------------*/  /**    @brief    Duplicate a string @@ -64,26 +36,71 @@ static void * mem_double(void * ptr, int size)    for systems that do not have it.   */  /*--------------------------------------------------------------------------*/ -static char * xstrdup(char * s) +static char * xstrdup(const char * s)  {      char * t ; +    size_t len ;      if (!s)          return NULL ; -    t = malloc(strlen(s)+1) ; + +    len = strlen(s) + 1 ; +    t = (char*) malloc(len) ;      if (t) { -        strcpy(t,s); +        memcpy(t, s, len) ;      }      return t ;  } +/*-------------------------------------------------------------------------*/ +/** +  @brief    Double the size of the dictionary +  @param    d Dictionary to grow +  @return   This function returns non-zero in case of failure + */ +/*--------------------------------------------------------------------------*/ +static int dictionary_grow(dictionary * d) +{ +    char        ** new_val ; +    char        ** new_key ; +    unsigned     * new_hash ; + +    new_val  = (char**) calloc(d->size * 2, sizeof *d->val); +    new_key  = (char**) calloc(d->size * 2, sizeof *d->key); +    new_hash = (unsigned*) calloc(d->size * 2, sizeof *d->hash); +    if (!new_val || !new_key || !new_hash) { +        /* An allocation failed, leave the dictionary unchanged */ +        if (new_val) +            free(new_val); +        if (new_key) +            free(new_key); +        if (new_hash) +            free(new_hash); +        return -1 ; +    } +    /* Initialize the newly allocated space */ +    memcpy(new_val, d->val, d->size * sizeof(char *)); +    memcpy(new_key, d->key, d->size * sizeof(char *)); +    memcpy(new_hash, d->hash, d->size * sizeof(unsigned)); +    /* Delete previous data */ +    free(d->val); +    free(d->key); +    free(d->hash); +    /* Actually update the dictionary */ +    d->size *= 2 ; +    d->val = new_val; +    d->key = new_key; +    d->hash = new_hash; +    return 0 ; +} +  /*--------------------------------------------------------------------------- -  							Function codes +                            Function codes   ---------------------------------------------------------------------------*/  /*-------------------------------------------------------------------------*/  /** -  @brief	Compute the hash key for a string. -  @param	key		Character string to use for key. -  @return	1 unsigned int on at least 32 bits. +  @brief    Compute the hash key for a string. +  @param    key     Character string to use for key. +  @return   1 unsigned int on at least 32 bits.    This hash function has been taken from an Article in Dr Dobbs Journal.    This is normally a collision-free function, distributing keys evenly. @@ -91,86 +108,97 @@ static char * xstrdup(char * s)    by comparing the key itself in last resort.   */  /*--------------------------------------------------------------------------*/ -unsigned dictionary_hash(char * key) +unsigned dictionary_hash(const char * key)  { -	int			len ; -	unsigned	hash ; -	int			i ; - -	len = strlen(key); -	for (hash=0, i=0 ; i<len ; i++) { -		hash += (unsigned)key[i] ; -		hash += (hash<<10); -		hash ^= (hash>>6) ; -	} -	hash += (hash <<3); -	hash ^= (hash >>11); -	hash += (hash <<15); -	return hash ; +    size_t      len ; +    unsigned    hash ; +    size_t      i ; + +    if (!key) +        return 0 ; + +    len = strlen(key); +    for (hash=0, i=0 ; i<len ; i++) { +        hash += (unsigned)key[i] ; +        hash += (hash<<10); +        hash ^= (hash>>6) ; +    } +    hash += (hash <<3); +    hash ^= (hash >>11); +    hash += (hash <<15); +    return hash ;  }  /*-------------------------------------------------------------------------*/  /** -  @brief	Create a new dictionary object. -  @param	size	Optional initial size of the dictionary. -  @return	1 newly allocated dictionary objet. +  @brief    Create a new dictionary object. +  @param    size    Optional initial size of the dictionary. +  @return   1 newly allocated dictionary object.    This function allocates a new dictionary object of given size and returns    it. If you do not know in advance (roughly) the number of entries in the    dictionary, give size=0.   */ -/*--------------------------------------------------------------------------*/ -dictionary * dictionary_new(int size) +/*-------------------------------------------------------------------------*/ +dictionary * dictionary_new(size_t size)  { -	dictionary	*	d ; - -	/* If no size was specified, allocate space for DICTMINSZ */ -	if (size<DICTMINSZ) size=DICTMINSZ ; - -	if (!(d = (dictionary *)calloc(1, sizeof(dictionary)))) { -		return NULL; -	} -	d->size = size ; -	d->val  = (char **)calloc(size, sizeof(char*)); -	d->key  = (char **)calloc(size, sizeof(char*)); -	d->hash = (unsigned int *)calloc(size, sizeof(unsigned)); -	return d ; +    dictionary  *   d ; + +    /* If no size was specified, allocate space for DICTMINSZ */ +    if (size<DICTMINSZ) size=DICTMINSZ ; + +    d = (dictionary*) calloc(1, sizeof *d) ; + +    if (d) { +        d->size = size ; +        d->val  = (char**) calloc(size, sizeof *d->val); +        d->key  = (char**) calloc(size, sizeof *d->key); +        d->hash = (unsigned*) calloc(size, sizeof *d->hash); +        if (!d->size || !d->val || !d->hash) { +            free((void *) d->size); +            free((void *) d->val); +            free((void *) d->hash); +            free(d); +            d = NULL; +        } +    } +    return d ;  }  /*-------------------------------------------------------------------------*/  /** -  @brief	Delete a dictionary object -  @param	d	dictionary object to deallocate. -  @return	void +  @brief    Delete a dictionary object +  @param    d   dictionary object to deallocate. +  @return   void    Deallocate a dictionary object and all memory associated to it.   */  /*--------------------------------------------------------------------------*/  void dictionary_del(dictionary * d)  { -	int		i ; - -	if (d==NULL) return ; -	for (i=0 ; i<d->size ; i++) { -		if (d->key[i]!=NULL) -			free(d->key[i]); -		if (d->val[i]!=NULL) -			free(d->val[i]); -	} -	free(d->val); -	free(d->key); -	free(d->hash); -	free(d); -	return ; +    size_t  i ; + +    if (d==NULL) return ; +    for (i=0 ; i<d->size ; i++) { +        if (d->key[i]!=NULL) +            free(d->key[i]); +        if (d->val[i]!=NULL) +            free(d->val[i]); +    } +    free(d->val); +    free(d->key); +    free(d->hash); +    free(d); +    return ;  }  /*-------------------------------------------------------------------------*/  /** -  @brief	Get a value from a dictionary. -  @param	d		dictionary object to search. -  @param	key		Key to look for in the dictionary. +  @brief    Get a value from a dictionary. +  @param    d       dictionary object to search. +  @param    key     Key to look for in the dictionary.    @param    def     Default value to return if key not found. -  @return	1 pointer to internally allocated character string. +  @return   1 pointer to internally allocated character string.    This function locates a key in a dictionary and returns a pointer to its    value, or the passed 'def' pointer if no such key can be found in @@ -178,24 +206,27 @@ void dictionary_del(dictionary * d)    dictionary object, you should not try to free it or modify it.   */  /*--------------------------------------------------------------------------*/ -char * dictionary_get(dictionary * d, char * key, char * def) +const char * dictionary_get(const dictionary * d, const char * key, const char * def)  { -	unsigned	hash ; -	int			i ; +    unsigned    hash ; +    size_t      i ; -	hash = dictionary_hash(key); -	for (i=0 ; i<d->size ; i++) { +    if(d == NULL || key == NULL) +       return def ; + +    hash = dictionary_hash(key); +    for (i=0 ; i<d->size ; i++) {          if (d->key[i]==NULL)              continue ;          /* Compare hash */ -		if (hash==d->hash[i]) { +        if (hash==d->hash[i]) {              /* Compare string, to avoid hash collisions */              if (!strcmp(key, d->key[i])) { -				return d->val[i] ; -			} -		} -	} -	return def ; +                return d->val[i] ; +            } +        } +    } +    return def ;  }  /*-------------------------------------------------------------------------*/ @@ -224,96 +255,87 @@ char * dictionary_get(dictionary * d, char * key, char * def)    This function returns non-zero in case of failure.   */  /*--------------------------------------------------------------------------*/ -int dictionary_set(dictionary * d, char * key, char * val) +int dictionary_set(dictionary * d, const char * key, const char * val)  { -	int			i ; -	unsigned	hash ; +    size_t         i ; +    unsigned       hash ; -	if (d==NULL || key==NULL) return -1 ; +    if (d==NULL || key==NULL) return -1 ; -	/* Compute hash for this key */ -	hash = dictionary_hash(key) ; -	/* Find if value is already in dictionary */ -	if (d->n>0) { -		for (i=0 ; i<d->size ; i++) { +    /* Compute hash for this key */ +    hash = dictionary_hash(key) ; +    /* Find if value is already in dictionary */ +    if (d->n>0) { +        for (i=0 ; i<d->size ; i++) {              if (d->key[i]==NULL)                  continue ; -			if (hash==d->hash[i]) { /* Same hash value */ -				if (!strcmp(key, d->key[i])) {	 /* Same key */ -					/* Found a value: modify and return */ -					if (d->val[i]!=NULL) -						free(d->val[i]); -                    d->val[i] = val ? xstrdup(val) : NULL ; +            if (hash==d->hash[i]) { /* Same hash value */ +                if (!strcmp(key, d->key[i])) {   /* Same key */ +                    /* Found a value: modify and return */ +                    if (d->val[i]!=NULL) +                        free(d->val[i]); +                    d->val[i] = (val ? xstrdup(val) : NULL);                      /* Value has been modified: return */ -					return 0 ; -				} -			} -		} -	} -	/* Add a new value */ -	/* See if dictionary needs to grow */ -	if (d->n==d->size) { - -		/* Reached maximum size: reallocate dictionary */ -		d->val  = (char **)mem_double(d->val,  d->size * sizeof(char*)) ; -		d->key  = (char **)mem_double(d->key,  d->size * sizeof(char*)) ; -		d->hash = (unsigned int *)mem_double(d->hash, d->size * sizeof(unsigned)) ; -        if ((d->val==NULL) || (d->key==NULL) || (d->hash==NULL)) { -            /* Cannot grow dictionary */ -            return -1 ; +                    return 0 ; +                } +            }          } -		/* Double size */ -		d->size *= 2 ; -	} +    } +    /* Add a new value */ +    /* See if dictionary needs to grow */ +    if (d->n==d->size) { +        /* Reached maximum size: reallocate dictionary */ +        if (dictionary_grow(d) != 0) +            return -1; +    } -    /* Insert key in the first empty slot */ -    for (i=0 ; i<d->size ; i++) { -        if (d->key[i]==NULL) { -            /* Add key here */ -            break ; -        } +    /* Insert key in the first empty slot. Start at d->n and wrap at +       d->size. Because d->n < d->size this will necessarily +       terminate. */ +    for (i=d->n ; d->key[i] ; ) { +        if(++i == d->size) i = 0;      } -	/* Copy key */ -	d->key[i]  = xstrdup(key); -    d->val[i]  = val ? xstrdup(val) : NULL ; -	d->hash[i] = hash; -	d->n ++ ; -	return 0 ; +    /* Copy key */ +    d->key[i]  = xstrdup(key); +    d->val[i]  = (val ? xstrdup(val) : NULL) ; +    d->hash[i] = hash; +    d->n ++ ; +    return 0 ;  }  /*-------------------------------------------------------------------------*/  /** -  @brief	Delete a key in a dictionary -  @param	d		dictionary object to modify. -  @param	key		Key to remove. +  @brief    Delete a key in a dictionary +  @param    d       dictionary object to modify. +  @param    key     Key to remove.    @return   void    This function deletes a key in a dictionary. Nothing is done if the    key cannot be found.   */  /*--------------------------------------------------------------------------*/ -void dictionary_unset(dictionary * d, char * key) +void dictionary_unset(dictionary * d, const char * key)  { -	unsigned	hash ; -	int			i ; +    unsigned    hash ; +    size_t      i ; -	if (key == NULL) { -		return; -	} +    if (key == NULL || d == NULL) { +        return; +    } -	hash = dictionary_hash(key); -	for (i=0 ; i<d->size ; i++) { +    hash = dictionary_hash(key); +    for (i=0 ; i<d->size ; i++) {          if (d->key[i]==NULL)              continue ;          /* Compare hash */ -		if (hash==d->hash[i]) { +        if (hash==d->hash[i]) {              /* Compare string, to avoid hash collisions */              if (!strcmp(key, d->key[i])) {                  /* Found key */                  break ; -			} -		} -	} +            } +        } +    }      if (i>=d->size)          /* Key not found */          return ; @@ -331,75 +353,31 @@ void dictionary_unset(dictionary * d, char * key)  /*-------------------------------------------------------------------------*/  /** -  @brief	Dump a dictionary to an opened file pointer. -  @param	d	Dictionary to dump -  @param	f	Opened file pointer. -  @return	void +  @brief    Dump a dictionary to an opened file pointer. +  @param    d   Dictionary to dump +  @param    f   Opened file pointer. +  @return   void    Dumps a dictionary onto an opened file pointer. Key pairs are printed out    as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as    output file pointers.   */  /*--------------------------------------------------------------------------*/ -void dictionary_dump(dictionary * d, FILE * out) +void dictionary_dump(const dictionary * d, FILE * out)  { -	int		i ; - -	if (d==NULL || out==NULL) return ; -	if (d->n<1) { -		fprintf(out, "empty dictionary\n"); -		return ; -	} -	for (i=0 ; i<d->size ; i++) { +    size_t  i ; + +    if (d==NULL || out==NULL) return ; +    if (d->n<1) { +        fprintf(out, "empty dictionary\n"); +        return ; +    } +    for (i=0 ; i<d->size ; i++) {          if (d->key[i]) {              fprintf(out, "%20s\t[%s]\n",                      d->key[i],                      d->val[i] ? d->val[i] : "UNDEF");          } -	} -	return ; -} - - -/* Test code */ -#ifdef TESTDIC -#define NVALS 20000 -int main(int argc, char *argv[]) -{ -	dictionary	*	d ; -	char	*	val ; -	int			i ; -	char		cval[90] ; - -	/* Allocate dictionary */ -	printf("allocating...\n"); -	d = dictionary_new(0); - -	/* Set values in dictionary */ -	printf("setting %d values...\n", NVALS); -	for (i=0 ; i<NVALS ; i++) { -		sprintf(cval, "%04d", i); -		dictionary_set(d, cval, "salut"); -	} -	printf("getting %d values...\n", NVALS); -	for (i=0 ; i<NVALS ; i++) { -		sprintf(cval, "%04d", i); -		val = dictionary_get(d, cval, DICT_INVALID_KEY); -		if (val==DICT_INVALID_KEY) { -			printf("cannot get value for key [%s]\n", cval); -		} -	} -    printf("unsetting %d values...\n", NVALS); -	for (i=0 ; i<NVALS ; i++) { -		sprintf(cval, "%04d", i); -		dictionary_unset(d, cval); -	} -    if (d->n != 0) { -        printf("error deleting values\n");      } -	printf("deallocating...\n"); -	dictionary_del(d); -	return 0 ; +    return ;  } -#endif -/* vim: set ts=4 et sw=4 tw=75 */ diff --git a/lib/libiniparser.c b/lib/libiniparser.c index a6ddcc7..4b21b34 100644 --- a/lib/libiniparser.c +++ b/lib/libiniparser.c @@ -3,19 +3,16 @@  /**     @file    iniparser.c     @author  N. Devillard -   @date    Sep 2007 -   @version 3.0     @brief   Parser for ini files.  */  /*--------------------------------------------------------------------------*/ -/* -    $Id: iniparser.c,v 2.18 2008-01-03 18:35:39 ndevilla Exp $ -    $Revision: 2.18 $ -    $Date: 2008-01-03 18:35:39 $ -*/  /*---------------------------- Includes ------------------------------------*/  #include <ctype.h> -#include <libiniparser.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <inttypes.h> +#include "libiniparser.h"  /*---------------------------- Defines -------------------------------------*/  #define ASCIILINESZ         (1024) @@ -38,68 +35,101 @@ typedef enum _line_status_ {  /*-------------------------------------------------------------------------*/  /** -  @brief	Convert a string to lowercase. -  @param	s	String to convert. -  @return	ptr to statically allocated string. - -  This function returns a pointer to a statically allocated string -  containing a lowercased version of the input string. Do not free -  or modify the returned string! Since the returned string is statically -  allocated, it will be modified at each function call (not re-entrant). +  @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 char * strlwc(const char * s) +static const char * strlwc(const char * in, char *out, unsigned len)  { -    static char l[ASCIILINESZ+1]; -    int i ; +    unsigned i ; -    if (s==NULL) return NULL ; -    memset(l, 0, ASCIILINESZ+1); +    if (in==NULL || out == NULL || len==0) return NULL ;      i=0 ; -    while (s[i] && i<ASCIILINESZ) { -        l[i] = (char)tolower((int)s[i]); +    while (in[i] != '\0' && i < len-1) { +        out[i] = (char)tolower((int)in[i]);          i++ ;      } -    l[ASCIILINESZ]=(char)0; -    return l ; +    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	s	String to parse. -  @return	ptr to statically allocated string. - -  This function returns a pointer to a statically allocated string, -  which is identical to the input string, except that all blank -  characters at the end and the beg. of the string have been removed. -  Do not free or modify the returned string! Since the returned string -  is statically allocated, it will be modified at each function call -  (not re-entrant). +  @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 char * strstrip(char * s) +static unsigned strstrip(char * s)  { -    static char l[ASCIILINESZ+1]; -	char * last ; - -    if (s==NULL) return NULL ; - -	while (isspace((int)*s) && *s) s++; -	memset(l, 0, ASCIILINESZ+1); -	strcpy(l, s); -	last = l + strlen(l); -	while (last > l) { -		if (!isspace((int)*(last-1))) -			break ; -		last -- ; -	} -	*last = (char)0; -	return (char*)l ; +    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    Get number of sections in a dictionary    @param    d   Dictionary to examine    @return   int Number of sections found in dictionary @@ -116,9 +146,9 @@ static char * strstrip(char * s)    This function returns -1 in case of error.   */  /*--------------------------------------------------------------------------*/ -int iniparser_getnsec(dictionary * d) +int iniparser_getnsec(const dictionary * d)  { -    int i ; +    size_t i ;      int nsec ;      if (d==NULL) return -1 ; @@ -147,9 +177,9 @@ int iniparser_getnsec(dictionary * d)    This function returns NULL in case of error.   */  /*--------------------------------------------------------------------------*/ -char * iniparser_getsecname(dictionary * d, int n) +const char * iniparser_getsecname(const dictionary * d, int n)  { -    int i ; +    size_t i ;      int foundsec ;      if (d==NULL || n<0) return NULL ; @@ -182,9 +212,9 @@ char * iniparser_getsecname(dictionary * d, int n)    purposes mostly.   */  /*--------------------------------------------------------------------------*/ -void iniparser_dump(dictionary * d, FILE * f) +void iniparser_dump(const dictionary * d, FILE * f)  { -    int     i ; +    size_t i ;      if (d==NULL || f==NULL) return ;      for (i=0 ; i<d->size ; i++) { @@ -199,6 +229,26 @@ void iniparser_dump(dictionary * d, FILE * f)      return ;  } +static void escape_value(char *escaped, char *value) { +    char c; +    int v = 0; +    int e = 0; + +    if(!escaped || !value) +        return; + +    while((c = value[v]) != '\0') { +        if(c == '\\' || c == '"') { +            escaped[e] = '\\'; +            e++; +        } +        escaped[e] = c; +        v++; +        e++; +    } +    escaped[e] = '\0'; +} +  /*-------------------------------------------------------------------------*/  /**    @brief    Save a dictionary to a loadable ini file @@ -210,13 +260,12 @@ void iniparser_dump(dictionary * d, FILE * f)    It is Ok to specify @c stderr or @c stdout as output files.   */  /*--------------------------------------------------------------------------*/ -void iniparser_dump_ini(dictionary * d, FILE * f) +void iniparser_dump_ini(const dictionary * d, FILE * f)  { -    int     i, j ; -    char    keym[ASCIILINESZ+1]; -    int     nsec ; -    char *  secname ; -    int     seclen ; +    size_t       i ; +    size_t       nsec ; +    const char * secname ; +    char escaped[ASCIILINESZ+1] = "";      if (d==NULL || f==NULL) return ; @@ -226,24 +275,50 @@ void iniparser_dump_ini(dictionary * d, FILE * f)          for (i=0 ; i<d->size ; i++) {              if (d->key[i]==NULL)                  continue ; -            fprintf(f, "%s = %s\n", d->key[i], d->val[i]); +            escape_value(escaped, d->val[i]); +            fprintf(f, "%s = \"%s\"\n", d->key[i], escaped);          }          return ;      }      for (i=0 ; i<nsec ; i++) {          secname = iniparser_getsecname(d, i) ; -        seclen  = (int)strlen(secname); -        fprintf(f, "\n[%s]\n", secname); -        sprintf(keym, "%s:", secname); -        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] : ""); -            } +        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) +{ +    size_t  j ; +    char    keym[ASCIILINESZ+1]; +    int     seclen ; +    char escaped[ASCIILINESZ+1] = ""; + +    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)) { +            escape_value(escaped, d->val[j]); +            fprintf(f, "%-30s = \"%s\"\n", d->key[j]+seclen+1, escaped);          }      }      fprintf(f, "\n"); @@ -265,26 +340,27 @@ void iniparser_dump_ini(dictionary * d, FILE * f)    the dictionary, do not free or modify it.   */  /*--------------------------------------------------------------------------*/ -char * iniparser_getstring(dictionary * d, const char * key, char * def) +const char * iniparser_getstring(const dictionary * d, const char * key, const char * def)  { -    char * lc_key ; -    char * sval ; +    const char * lc_key ; +    const char * sval ; +    char tmp_str[ASCIILINESZ+1];      if (d==NULL || key==NULL)          return def ; -    lc_key = strlwc(key); +    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 int +  @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   integer +  @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, @@ -305,13 +381,65 @@ char * iniparser_getstring(dictionary * d, const char * key, char * def)    Credits: Thanks to A. Becker for suggesting strtol()   */  /*--------------------------------------------------------------------------*/ -int iniparser_getint(dictionary * d, const char * key, int notfound) +long int iniparser_getlongint(const dictionary * d, const char * key, long int notfound)  { -    char    *   str ; +    const char * str ;      str = iniparser_getstring(d, key, INI_INVALID_KEY); -    if (str==INI_INVALID_KEY) return notfound ; -    return (int)strtol(str, NULL, 0); +    if (str==NULL || str==INI_INVALID_KEY) return notfound ; +    return strtol(str, NULL, 0); +} + +int64_t iniparser_getint64(const dictionary * d, const char * key, int64_t notfound) +{ +    const char * str ; + +    str = iniparser_getstring(d, key, INI_INVALID_KEY); +    if (str==NULL || str==INI_INVALID_KEY) return notfound ; +    return strtoimax(str, NULL, 0); +} + +uint64_t iniparser_getuint64(const dictionary * d, const char * key, uint64_t notfound) +{ +    const char * str ; + +    str = iniparser_getstring(d, key, INI_INVALID_KEY); +    if (str==NULL || str==INI_INVALID_KEY) return notfound ; +    return strtoumax(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);  }  /*-------------------------------------------------------------------------*/ @@ -346,13 +474,13 @@ int iniparser_getint(dictionary * d, const char * key, int notfound)    necessarily have to be 0 or 1.   */  /*--------------------------------------------------------------------------*/ -int iniparser_getboolean(dictionary * d, const char * key, int notfound) +int iniparser_getboolean(const dictionary * d, const char * key, int notfound)  { -    char    *   c ; -    int         ret ; +    int          ret ; +    const char * c ;      c = iniparser_getstring(d, key, INI_INVALID_KEY); -    if (c==INI_INVALID_KEY) return notfound ; +    if (c==NULL || 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') { @@ -375,10 +503,7 @@ int iniparser_getboolean(dictionary * d, const char * key, int notfound)    of querying for the presence of sections in a dictionary.   */  /*--------------------------------------------------------------------------*/ -int iniparser_find_entry( -    dictionary  *   ini, -    char        *   entry -) +int iniparser_find_entry(const dictionary * ini, const char * entry)  {      int found=0 ;      if (iniparser_getstring(ini, entry, INI_INVALID_KEY)!=INI_INVALID_KEY) { @@ -397,14 +522,53 @@ int iniparser_find_entry(    If the given entry can be found, it is deleted from the dictionary.   */  /*--------------------------------------------------------------------------*/ -void iniparser_unset(dictionary * ini, char * entry) +void iniparser_unset(dictionary * ini, const char * entry)  { -    dictionary_unset(ini, strlwc(entry)); +    char tmp_str[ASCIILINESZ+1]; +    dictionary_unset(ini, strlwc(entry, tmp_str, sizeof(tmp_str))); +} + +static void parse_quoted_value(char *value, char quote) { +    char c; +    char *quoted; +    int q = 0, v = 0; +    int esc = 0; + +    if(!value) +        return; + +    quoted = xstrdup(value); + +    if(!quoted) { +        iniparser_error_callback("iniparser: memory allocation failure\n"); +        goto end_of_value; +    } + +    while((c = quoted[q]) != '\0') { +        if(!esc) { +            if(c == '\\') { +                esc = 1; +                q++; +                continue; +            } + +            if(c == quote) { +                goto end_of_value; +            } +        } +        esc = 0; +        value[v] = c; +        v++; +        q++; +    } +end_of_value: +    value[v] = '\0'; +    free(quoted);  }  /*-------------------------------------------------------------------------*/  /** -  @brief	Load a single line from an INI file +  @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 @@ -413,38 +577,54 @@ void iniparser_unset(dictionary * ini, char * entry)   */  /*--------------------------------------------------------------------------*/  static line_status iniparser_line( -    char * input_line, +    const char * input_line,      char * section,      char * key,      char * value)  {      line_status sta ; -    char        line[ASCIILINESZ+1]; -    int         len ; +    char * line = NULL; +    size_t      len ; +    int d_quote; -    strcpy(line, strstrip(input_line)); -    len = (int)strlen(line); +    line = xstrdup(input_line); +    len = strstrip(line);      sta = LINE_UNPROCESSED ;      if (len<1) {          /* Empty line */          sta = LINE_EMPTY ; -    } else if (line[0]=='#') { +    } else if (line[0]=='#' || line[0]==';') {          /* Comment line */          sta = LINE_COMMENT ;      } else if (line[0]=='[' && line[len-1]==']') { -        /* Section name */ -        sscanf(line, "[%[^]]", section); -        strcpy(section, strstrip(section)); -        strcpy(section, strlwc(section)); +        /* Section name without opening square bracket */ +        sscanf(line, "[%[^\n]", section); +        len = strlen(section); +        /* Section name without closing square bracket */ +        if(section[len-1] == ']') +        { +            section[len-1] = '\0'; +        } +        strstrip(section); +        strlwc(section, section, len);          sta = LINE_SECTION ; -    } else if (sscanf (line, "%[^=] = \"%[^\"]\"", key, value) == 2 -           ||  sscanf (line, "%[^=] = '%[^\']'",   key, value) == 2 -           ||  sscanf (line, "%[^=] = %[^;#]",     key, value) == 2) { -        /* Usual key=value, with or without comments */ -        strcpy(key, strstrip(key)); -        strcpy(key, strlwc(key)); -        strcpy(value, strstrip(value)); +    } else if ((d_quote = sscanf (line, "%[^=] = \"%[^\n]\"", key, value)) == 2 +               ||  sscanf (line, "%[^=] = '%[^\n]'",   key, value) == 2) { +        /* Usual key=value with quotes, with or without comments */ +        strstrip(key); +        strlwc(key, key, len); +        if(d_quote == 2) +            parse_quoted_value(value, '"'); +        else +            parse_quoted_value(value, '\''); +        /* 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 @@ -461,56 +641,51 @@ static line_status iniparser_line(           * key=;           * key=#           */ -        strcpy(key, strstrip(key)); -        strcpy(key, strlwc(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. +  @param    in File to read. +  @param    ininame Name of the ini file to read (only used for nicer error messages)    @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 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) +dictionary * iniparser_load_file(FILE * in, const char * ininame)  { -    FILE * in ; -      char line    [ASCIILINESZ+1] ;      char section [ASCIILINESZ+1] ;      char key     [ASCIILINESZ+1] ; -    char tmp     [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) { -        fprintf(stderr, "iniparser: cannot open %s\n", ininame); -        return NULL ; -    } -      dict = dictionary_new(0) ;      if (!dict) { -        fclose(in);          return NULL ;      } @@ -523,14 +698,15 @@ dictionary * iniparser_load(const char * ininame)      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') { -            fprintf(stderr, -                    "iniparser: input line too long in %s (%d)\n", -                    ininame, -                    lineno); +        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 */ @@ -539,6 +715,9 @@ dictionary * iniparser_load(const char * ininame)              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 */ @@ -553,19 +732,20 @@ dictionary * iniparser_load(const char * ininame)              break ;              case LINE_SECTION: -            errs = dictionary_set(dict, section, NULL); +            mem_err = dictionary_set(dict, section, NULL);              break ;              case LINE_VALUE:              sprintf(tmp, "%s:%s", section, key); -            errs = dictionary_set(dict, tmp, val) ; +            mem_err = dictionary_set(dict, tmp, val);              break ;              case LINE_ERROR: -            fprintf(stderr, "iniparser: syntax error in %s (%d):\n", -                    ininame, -                    lineno); -            fprintf(stderr, "-> %s\n", line); +            iniparser_error_callback( +              "iniparser: syntax error in %s (%d):\n-> %s\n", +              ininame, +              lineno, +              line);              errs++ ;              break; @@ -574,8 +754,8 @@ dictionary * iniparser_load(const char * ininame)          }          memset(line, 0, ASCIILINESZ);          last=0; -        if (errs<0) { -            fprintf(stderr, "iniparser: memory allocation failure\n"); +        if (mem_err<0) { +            iniparser_error_callback("iniparser: memory allocation failure\n");              break ;          }      } @@ -583,10 +763,40 @@ dictionary * iniparser_load(const char * ininame)          dictionary_del(dict);          dict = NULL ;      } +    return dict ; +} + +/*-------------------------------------------------------------------------*/ +/** +  @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 ; +    dictionary * dict ; + +    if ((in=fopen(ininame, "r"))==NULL) { +        iniparser_error_callback("iniparser: cannot open %s\n", ininame); +        return NULL ; +    } + +    dict = iniparser_load_file(in, ininame);      fclose(in); +      return dict ;  } +  /*-------------------------------------------------------------------------*/  /**    @brief    Free all memory associated to an ini dictionary @@ -602,5 +812,3 @@ void iniparser_freedict(dictionary * d)  {      dictionary_del(d);  } - -/* vim: set ts=4 et sw=4 tw=75 */ | 
