]> arthur.barton.de Git - netatalk.git/blobdiff - libatalk/iniparser/iniparser.c
afpd: check for modified included config file, FR #95
[netatalk.git] / libatalk / iniparser / iniparser.c
index 02a23b7559d482aaa062aeacff1e2c735f3c5006..343a6d063b5cbd5028934f05e5b63c9f7f567d9c 100644 (file)
@@ -1,4 +1,3 @@
-
 /*-------------------------------------------------------------------------*/
 /**
    @file    iniparser.c
@@ -7,15 +6,16 @@
    @version 3.0
    @brief   Parser for ini files.
 */
-/*--------------------------------------------------------------------------*/
-/*
-    $Id: iniparser.c,v 2.19 2011-03-02 20:15:13 ndevilla Exp $
-    $Revision: 2.19 $
-    $Date: 2011-03-02 20:15:13 $
-*/
+
 /*---------------------------- Includes ------------------------------------*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
 #include <ctype.h>
-#include "iniparser.h"
+
+#include <atalk/iniparser.h>
+#include <atalk/logger.h>
 
 /*---------------------------- Defines -------------------------------------*/
 #define ASCIILINESZ         (1024)
@@ -38,37 +38,9 @@ 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).
- */
-/*--------------------------------------------------------------------------*/
-static char * strlwc(char * s)
-{
-    static char l[ASCIILINESZ+1];
-    int i ;
-
-    if (s==NULL) return NULL ;
-    memset(l, 0, ASCIILINESZ+1);
-    i=0 ;
-    while (s[i] && i<ASCIILINESZ) {
-        l[i] = (char)tolower((int)s[i]);
-        i++ ;
-    }
-    l[ASCIILINESZ]=(char)0;
-    return l ;
-}
-
-/*-------------------------------------------------------------------------*/
-/**
-  @brief       Remove blanks at the beginning and the end of a string.
-  @param       s       String to parse.
-  @return      ptr to statically allocated string.
+  @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
@@ -81,21 +53,21 @@ static char * strlwc(char * s)
 static char * strstrip(char * s)
 {
     static char l[ASCIILINESZ+1];
-       char * last ;
-       
+    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 ;
+
+    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 ;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -116,7 +88,7 @@ static char * strstrip(char * s)
   This function returns -1 in case of error.
  */
 /*--------------------------------------------------------------------------*/
-int iniparser_getnsec(dictionary * d)
+int atalk_iniparser_getnsec(const dictionary * d)
 {
     int i ;
     int nsec ;
@@ -147,7 +119,7 @@ int iniparser_getnsec(dictionary * d)
   This function returns NULL in case of error.
  */
 /*--------------------------------------------------------------------------*/
-char * iniparser_getsecname(dictionary * d, int n)
+const char * atalk_iniparser_getsecname(const dictionary * d, int n)
 {
     int i ;
     int foundsec ;
@@ -182,7 +154,7 @@ char * iniparser_getsecname(dictionary * d, int n)
   purposes mostly.
  */
 /*--------------------------------------------------------------------------*/
-void iniparser_dump(dictionary * d, FILE * f)
+void atalk_iniparser_dump(const dictionary * d, FILE * f)
 {
     int     i ;
 
@@ -210,17 +182,17 @@ 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 atalk_iniparser_dump_ini(const dictionary * d, FILE * f)
 {
     int     i, j ;
     char    keym[ASCIILINESZ+1];
     int     nsec ;
-    char *  secname ;
+    const char *  secname ;
     int     seclen ;
 
     if (d==NULL || f==NULL) return ;
 
-    nsec = iniparser_getnsec(d);
+    nsec = atalk_iniparser_getnsec(d);
     if (nsec<1) {
         /* No section in file: dump all keys as they are */
         for (i=0 ; i<d->size ; i++) {
@@ -231,7 +203,7 @@ void iniparser_dump_ini(dictionary * d, FILE * f)
         return ;
     }
     for (i=0 ; i<nsec ; i++) {
-        secname = iniparser_getsecname(d, i) ;
+        secname = atalk_iniparser_getsecname(d, i) ;
         seclen  = (int)strlen(secname);
         fprintf(f, "\n[%s]\n", secname);
         sprintf(keym, "%s:", secname);
@@ -254,6 +226,7 @@ void iniparser_dump_ini(dictionary * d, FILE * f)
 /**
   @brief    Get the string associated to a key
   @param    d       Dictionary to search
+  @param    section Section 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
@@ -265,24 +238,50 @@ void iniparser_dump_ini(dictionary * d, FILE * f)
   the dictionary, do not free or modify it.
  */
 /*--------------------------------------------------------------------------*/
-char * iniparser_getstring(dictionary * d, char * key, char * def)
+const char * atalk_iniparser_getstring(const dictionary * d, const char *section, const char * key, const char * def)
 {
-    char * lc_key ;
-    char * sval ;
+    const char * sval ;
 
     if (d==NULL || key==NULL)
         return def ;
 
-    lc_key = strlwc(key);
-    sval = dictionary_get(d, lc_key, def);
+    sval = atalkdict_get(d, section, key, def);
     return sval ;
 }
 
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Get the string associated to a key
+  @param    d       Dictionary to search
+  @param    section Section 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 a strdup'ed allocated string, so the caller must free it.
+ */
+/*--------------------------------------------------------------------------*/
+char * atalk_iniparser_getstrdup(const dictionary * d, const char *section, const char * key, const char * def)
+{
+    const char * sval ;
+
+    if (d==NULL || key==NULL)
+        return NULL;
+
+    if ((sval = atalkdict_get(d, section, key, def)))
+        return strdup(sval);
+    return NULL;
+}
+
 /*-------------------------------------------------------------------------*/
 /**
   @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    d        Dictionary to search
+  @param    section  Section to search
+  @param    key      Key string to look for
   @param    notfound Value to return in case of error
   @return   integer
 
@@ -305,11 +304,11 @@ char * iniparser_getstring(dictionary * d, char * key, char * def)
   Credits: Thanks to A. Becker for suggesting strtol()
  */
 /*--------------------------------------------------------------------------*/
-int iniparser_getint(dictionary * d, char * key, int notfound)
+int atalk_iniparser_getint(const dictionary * d, const char *section, const char * key, int notfound)
 {
-    char    *   str ;
+    const char    *   str ;
 
-    str = iniparser_getstring(d, key, INI_INVALID_KEY);
+    str = atalk_iniparser_getstring(d, section, key, INI_INVALID_KEY);
     if (str==INI_INVALID_KEY) return notfound ;
     return (int)strtol(str, NULL, 0);
 }
@@ -317,8 +316,9 @@ int iniparser_getint(dictionary * d, char * key, int 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    d        Dictionary to search
+  @param    section  Section to search
+  @param    key      Key string to look for
   @param    notfound Value to return in case of error
   @return   double
 
@@ -327,11 +327,11 @@ int iniparser_getint(dictionary * d, char * key, int notfound)
   the notfound value is returned.
  */
 /*--------------------------------------------------------------------------*/
-double iniparser_getdouble(dictionary * d, char * key, double notfound)
+double atalk_iniparser_getdouble(const dictionary * d, const char *section, const char * key, double notfound)
 {
-    char    *   str ;
+    const char    *   str ;
 
-    str = iniparser_getstring(d, key, INI_INVALID_KEY);
+    str = atalk_iniparser_getstring(d, section, key, INI_INVALID_KEY);
     if (str==INI_INVALID_KEY) return notfound ;
     return atof(str);
 }
@@ -339,8 +339,9 @@ double iniparser_getdouble(dictionary * d, char * key, double notfound)
 /*-------------------------------------------------------------------------*/
 /**
   @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    d        Dictionary to search
+  @param    section  Section to search
+  @param    key      Key string to look for
   @param    notfound Value to return in case of error
   @return   integer
 
@@ -368,12 +369,12 @@ double iniparser_getdouble(dictionary * d, char * key, double notfound)
   necessarily have to be 0 or 1.
  */
 /*--------------------------------------------------------------------------*/
-int iniparser_getboolean(dictionary * d, char * key, int notfound)
+int atalk_iniparser_getboolean(const dictionary * d, const char *section, const char * key, int notfound)
 {
-    char    *   c ;
+    const char    *   c ;
     int         ret ;
 
-    c = iniparser_getstring(d, key, INI_INVALID_KEY);
+    c = atalk_iniparser_getstring(d, section, 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 ;
@@ -397,13 +398,10 @@ int iniparser_getboolean(dictionary * d, char * key, int notfound)
   of querying for the presence of sections in a dictionary.
  */
 /*--------------------------------------------------------------------------*/
-int iniparser_find_entry(
-    dictionary  *   ini,
-    char        *   entry
-)
+int atalk_iniparser_find_entry(const dictionary *ini, const char *entry)
 {
     int found=0 ;
-    if (iniparser_getstring(ini, entry, INI_INVALID_KEY)!=INI_INVALID_KEY) {
+    if (atalk_iniparser_getstring(ini, entry, NULL, INI_INVALID_KEY)!=INI_INVALID_KEY) {
         found = 1 ;
     }
     return found ;
@@ -413,7 +411,8 @@ int iniparser_find_entry(
 /**
   @brief    Set an entry in a dictionary.
   @param    ini     Dictionary to modify.
-  @param    entry   Entry to modify (entry name)
+  @param    section Entry to modify (entry section)
+  @param    key     Entry to modify (entry key)
   @param    val     New value to associate to the entry.
   @return   int 0 if Ok, -1 otherwise.
 
@@ -422,29 +421,30 @@ int iniparser_find_entry(
   It is Ok to set val to NULL.
  */
 /*--------------------------------------------------------------------------*/
-int iniparser_set(dictionary * ini, char * entry, char * val)
+int atalk_iniparser_set(dictionary * ini, char *section, char * key, char * val)
 {
-    return dictionary_set(ini, strlwc(entry), val) ;
+    return atalkdict_set(ini, section, key, val) ;
 }
 
 /*-------------------------------------------------------------------------*/
 /**
   @brief    Delete an entry in a dictionary
   @param    ini     Dictionary to modify
-  @param    entry   Entry to delete (entry name)
+  @param    section Entry to delete (entry section)
+  @param    key     Entry to delete (entry key)
   @return   void
 
   If the given entry can be found, it is deleted from the dictionary.
  */
 /*--------------------------------------------------------------------------*/
-void iniparser_unset(dictionary * ini, char * entry)
+void atalk_iniparser_unset(dictionary * ini, char *section, char * key)
 {
-    dictionary_unset(ini, strlwc(entry));
+    atalkdict_unset(ini, section, key);
 }
 
 /*-------------------------------------------------------------------------*/
 /**
-  @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
@@ -452,12 +452,12 @@ void iniparser_unset(dictionary * ini, char * entry)
   @return   line_status value
  */
 /*--------------------------------------------------------------------------*/
-static line_status iniparser_line(
+static line_status atalk_iniparser_line(
     char * input_line,
     char * section,
     char * key,
     char * value)
-{   
+{
     line_status sta ;
     char        line[ASCIILINESZ+1];
     int         len ;
@@ -471,19 +471,18 @@ static line_status iniparser_line(
         sta = LINE_EMPTY ;
     } else if (line[0]=='#' || line[0]==';') {
         /* Comment line */
-        sta = LINE_COMMENT ; 
+        sta = LINE_COMMENT ;
     } else if (line[0]=='[' && line[len-1]==']') {
         /* Section name */
         sscanf(line, "[%[^]]", section);
         strcpy(section, strstrip(section));
-        strcpy(section, strlwc(section));
+        strcpy(section, section);
         sta = LINE_SECTION ;
-    } else if (sscanf (line, "%[^=] = \"%[^\"]\"", key, value) == 2
-           ||  sscanf (line, "%[^=] = '%[^\']'",   key, value) == 2
+    } else if (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(key, key);
         strcpy(value, strstrip(value));
         /*
          * sscanf cannot handle '' or "" as empty values
@@ -502,7 +501,7 @@ static line_status iniparser_line(
          * key=#
          */
         strcpy(key, strstrip(key));
-        strcpy(key, strlwc(key));
+        strcpy(key, key);
         value[0]=0 ;
         sta = LINE_VALUE ;
     } else {
@@ -523,17 +522,16 @@ static line_status iniparser_line(
   should not be accessed directly, but through accessor functions
   instead.
 
-  The returned dictionary must be freed using iniparser_freedict().
+  The returned dictionary must be freed using atalk_iniparser_freedict().
  */
 /*--------------------------------------------------------------------------*/
-dictionary * iniparser_load(char * ininame)
+dictionary * atalk_iniparser_load(const char * ininame)
 {
-    FILE * in ;
+    FILE *in, *include = NULL, *inifile;
 
     char line    [ASCIILINESZ+1] ;
     char section [ASCIILINESZ+1] ;
     char key     [ASCIILINESZ+1] ;
-    char tmp     [ASCIILINESZ+1] ;
     char val     [ASCIILINESZ+1] ;
 
     int  last=0 ;
@@ -543,14 +541,14 @@ dictionary * iniparser_load(char * ininame)
 
     dictionary * dict ;
 
-    if ((in=fopen(ininame, "r"))==NULL) {
-        fprintf(stderr, "iniparser: cannot open %s\n", ininame);
+    if ((inifile=fopen(ininame, "r"))==NULL) {
+        LOG(log_error, logtype_default, "iniparser: cannot open \"%s\"", ininame);
         return NULL ;
     }
 
-    dict = dictionary_new(0) ;
+    dict = atalkdict_new(0) ;
     if (!dict) {
-        fclose(in);
+        fclose(inifile);
         return NULL ;
     }
 
@@ -560,21 +558,21 @@ dictionary * iniparser_load(char * ininame)
     memset(val,     0, ASCIILINESZ);
     last=0 ;
 
-    while (fgets(line+last, ASCIILINESZ-last, in)!=NULL) {
+    in = inifile;
+    while (1) {
+        if (fgets(line+last, ASCIILINESZ-last, in) == NULL) {
+            if (include) {
+                fclose(include);
+                include = NULL;
+                in = inifile;
+                continue;
+            }
+            break;
+        }
         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);
-            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])))) {
@@ -589,40 +587,47 @@ dictionary * iniparser_load(char * ininame)
         } else {
             last=0 ;
         }
-        switch (iniparser_line(line, section, key, val)) {
-            case LINE_EMPTY:
-            case LINE_COMMENT:
+        switch (atalk_iniparser_line(line, section, key, val)) {
+        case LINE_EMPTY:
+        case LINE_COMMENT:
             break ;
-
-            case LINE_SECTION:
-            errs = dictionary_set(dict, section, NULL);
+        case LINE_SECTION:
+            if (strchr(section, ':') != NULL)
+                LOG(log_error, logtype_default, "iniparser: syntax error \"%s\" section name must not contain \":\".", section);
+            errs = atalkdict_set(dict, section, NULL, NULL);
             break ;
-
-            case LINE_VALUE:
-            sprintf(tmp, "%s:%s", section, key);
-            errs = dictionary_set(dict, tmp, val) ;
+        case LINE_VALUE:
+            if (strcmp(key, "include") == 0) {
+                errs = atalkdict_set(dict, section, key, val);
+                if (errs < 0) {
+                    LOG(log_error, logtype_default, "iniparser: memory allocation failure");
+                }
+                if ((include = fopen(val, "r")) == NULL) {
+                    LOG(log_error, logtype_default, "iniparser: cannot open \"%s\"", val);
+                    continue;
+                }
+                in = include;
+                continue;
+            }
+            errs = atalkdict_set(dict, section, key, val) ;
             break ;
-
-            case LINE_ERROR:
-            fprintf(stderr, "iniparser: syntax error in %s (%d):\n",
-                    ininame,
-                    lineno);
-            fprintf(stderr, "-> %s\n", line);
+        case LINE_ERROR:
+            LOG(log_error, logtype_default, "iniparser: syntax error in %s (lineno: %d): %s",
+                ininame, lineno, line);
             errs++ ;
             break;
-
-            default:
+        default:
             break ;
         }
         memset(line, 0, ASCIILINESZ);
         last=0;
         if (errs<0) {
-            fprintf(stderr, "iniparser: memory allocation failure\n");
+            LOG(log_error, logtype_default, "iniparser: memory allocation failure");
             break ;
         }
     }
     if (errs) {
-        dictionary_del(dict);
+        atalkdict_del(dict);
         dict = NULL ;
     }
     fclose(in);
@@ -640,9 +645,8 @@ dictionary * iniparser_load(char * ininame)
   gets out of the current context.
  */
 /*--------------------------------------------------------------------------*/
-void iniparser_freedict(dictionary * d)
+void atalk_iniparser_freedict(dictionary * d)
 {
-    dictionary_del(d);
+    atalkdict_del(d);
 }
 
-/* vim: set ts=4 et sw=4 tw=75 */