testing/mozbase/mozprocess/tests/iniparser/iniparser.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial