Signed-off-by: Sascha Kruse <[email protected]>
---
 src/pacman/conf.c | 343 ++++++++++++++++++------------------------------------
 1 file changed, 111 insertions(+), 232 deletions(-)

diff --git a/src/pacman/conf.c b/src/pacman/conf.c
index 3f1b1c3..06a4612 100644
--- a/src/pacman/conf.c
+++ b/src/pacman/conf.c
@@ -36,6 +36,7 @@
 #include "util.h"
 #include "pacman.h"
 #include "callback.h"
+#include "ini.h"
 
 /* global config variable */
 config_t *config = NULL;
@@ -462,9 +463,21 @@ static void setrepeatingoption(char *ptr, const char 
*option,
        }
 }
 
-static int _parse_options(const char *key, char *value,
-               const char *file, int linenum)
+/** Parse one directive from the 'options' section
+ * @param directive the directive to parse
+ * @return 0 on success non-zero otherwise
+ */
+static int parse_option_directive(ini_directive_t *directive)
 {
+       const char *key = directive->key;
+       char *value = NULL;
+       const char *file = directive->file;
+       int linenum = directive->linenum;
+
+       if(directive->value != NULL) {
+               value = strdup(directive->value);
+       }
+
        if(value == NULL) {
                /* options without settings */
                if(strcmp(key, "UseSyslog") == 0) {
@@ -599,6 +612,24 @@ static int _parse_options(const char *key, char *value,
        return 0;
 }
 
+/** Parse the 'options' section from the config file
+ * @param options the option section to parse_options
+ * @return 0 on success non-zero otherwise
+ */
+static int parse_options(ini_section_t *options)
+{
+       alpm_list_t *iter;
+       int ret;
+
+       for(iter = options->directives; iter; iter = alpm_list_next(iter)) {
+               ini_directive_t *directive = (ini_directive_t *) iter->data;
+               if((ret = parse_option_directive(directive))) {
+                       return ret;
+               }
+       }
+       return 0;
+}
+
 static int _add_mirror(alpm_db_t *db, char *value)
 {
        const char *dbname = alpm_db_get_name(db);
@@ -739,43 +770,55 @@ static int setup_libalpm(void)
        return 0;
 }
 
-/**
- * Allows parsing in advance of an entire config section before we start
- * calling library methods.
- */
-struct section_t {
-       /* useful for all sections */
-       char *name;
-       int is_options;
-       /* db section option gathering */
-       alpm_siglevel_t siglevel;
-       alpm_list_t *servers;
-};
-
-/**
- * Wrap up a section once we have reached the end of it. This should be called
- * when a subsequent section is encountered, or when we have reached the end of
- * the root config file. Once called, all existing saved config pieces on the
- * section struct are freed.
- * @param section the current parsed and saved section data
- * @param parse_options whether we are parsing options or repo data
- * @return 0 on success, 1 on failure
+/** Parse an ini section that describes a repository.
+ * @param section the ini section.
+ * @return 0 on success non-zero otherwise
  */
-static int finish_section(struct section_t *section, int parse_options)
+static int parse_repository(ini_section_t *section)
 {
        int ret = 0;
        alpm_list_t *i;
        alpm_db_t *db;
+       alpm_siglevel_t siglevel = ALPM_SIG_USE_DEFAULT;
+       alpm_list_t *servers = NULL;
 
-       pm_printf(ALPM_LOG_DEBUG, "config: finish section '%s'\n", 
section->name);
+       alpm_list_t *directive_iter;
+       for(directive_iter = section->directives; directive_iter;
+                       directive_iter = alpm_list_next(directive_iter)) {
+               ini_directive_t *directive = (ini_directive_t *) 
directive_iter->data;
 
-       /* parsing options (or nothing)- nothing to do except free the pieces */
-       if(!section->name || parse_options || section->is_options) {
-               goto cleanup;
+               if(strcmp(directive->key, "Server") == 0) {
+                       if(directive->value == NULL || strlen(directive->value) 
== 0) {
+                               pm_printf(ALPM_LOG_ERROR, _("config file %s, 
line %d: directive '%s' needs a value\n"),
+                               directive->file, directive->linenum, 
directive->key);
+                       } else {
+                               servers = alpm_list_add(servers, 
strdup(directive->value));
+                       }
+               }else if(strcmp(directive->key, "SigLevel") == 0) {
+                               alpm_list_t *values = NULL;
+                               char *value = strdup(directive->value);
+                               setrepeatingoption(value, "SigLevel", &values);
+                               if(values) {
+                                       if(siglevel == ALPM_SIG_USE_DEFAULT) {
+                                               siglevel = config->siglevel;
+                                       }
+                                       if(process_siglevel(values, &siglevel, 
directive->file,
+                                                               
directive->linenum)) {
+                                               FREELIST(values);
+                                               ret = 1;
+                                               goto cleanup;
+                                       }
+                                       free(value);
+                                       FREELIST(values);
+                               }
+               } else {
+                       pm_printf(ALPM_LOG_WARNING,
+                                       _("config file %s, line %d: directive 
'%s' in section '%s' not recognized.\n"),
+                                       directive->file, directive->linenum, 
directive->key, section->name);
+               }
        }
 
-       /* if we are not looking at options sections only, register a db */
-       db = alpm_register_syncdb(config->handle, section->name, 
section->siglevel);
+       db = alpm_register_syncdb(config->handle, section->name, siglevel);
        if(db == NULL) {
                pm_printf(ALPM_LOG_ERROR, _("could not register '%s' database 
(%s)\n"),
                                section->name, 
alpm_strerror(alpm_errno(config->handle)));
@@ -783,7 +826,7 @@ static int finish_section(struct section_t *section, int 
parse_options)
                goto cleanup;
        }
 
-       for(i = section->servers; i; i = alpm_list_next(i)) {
+       for(i = servers; i; i = alpm_list_next(i)) {
                char *value = i->data;
                if(_add_mirror(db, value) != 0) {
                        pm_printf(ALPM_LOG_ERROR,
@@ -796,226 +839,62 @@ static int finish_section(struct section_t *section, int 
parse_options)
        }
 
 cleanup:
-       alpm_list_free(section->servers);
-       section->servers = NULL;
-       section->siglevel = ALPM_SIG_USE_DEFAULT;
-       free(section->name);
-       section->name = NULL;
+       alpm_list_free(servers);
        return ret;
 }
 
-/** The "real" parseconfig. Each "Include" directive will recall this method so
- * recursion and stack depth are limited to 10 levels. The publicly visible
- * parseconfig calls this with a NULL section argument so we can recall from
- * within ourself on an include.
+
+/** Parse a configuration file.
  * @param file path to the config file
- * @param section the current active section
- * @param parse_options whether to parse and call methods for the options
- * section; if 0, parse and call methods for the repos sections
- * @param depth the current recursion depth
- * @return 0 on success, 1 on failure
+ * @return 0 on success, non-zero on error
  */
-static int _parseconfig(const char *file, struct section_t *section,
-               int parse_options, int depth)
+int parseconfig(const char *file)
 {
-       FILE *fp = NULL;
-       char line[PATH_MAX];
-       int linenum = 0;
-       int ret = 0;
-       const int max_depth = 10;
-
-       if(depth >= max_depth) {
-               pm_printf(ALPM_LOG_ERROR,
-                               _("config parsing exceeded max recursion depth 
of %d.\n"), max_depth);
-               ret = 1;
-               goto cleanup;
-       }
+       alpm_list_t *sections;
+       int ret;
 
-       pm_printf(ALPM_LOG_DEBUG, "config: attempting to read file %s\n", file);
-       fp = fopen(file, "r");
-       if(fp == NULL) {
-               pm_printf(ALPM_LOG_ERROR, _("config file %s could not be read: 
%s\n"),
-                               file, strerror(errno));
-               ret = 1;
-               goto cleanup;
+       sections = ini_parse_file(file);
+       if(sections == NULL) {
+               return 1;
        }
 
-       while(fgets(line, PATH_MAX, fp)) {
-               char *key, *value, *ptr;
-               size_t line_len;
-
-               linenum++;
-
-               /* ignore whole line and end of line comments */
-               if((ptr = strchr(line, '#'))) {
-                       *ptr = '\0';
-               }
-
-               line_len = strtrim(line);
-
-               if(line_len == 0) {
-                       continue;
-               }
-
-               if(line[0] == '[' && line[line_len - 1] == ']') {
-                       char *name;
-                       /* only possibility here is a line == '[]' */
-                       if(line_len <= 2) {
-                               pm_printf(ALPM_LOG_ERROR, _("config file %s, 
line %d: bad section name.\n"),
-                                               file, linenum);
-                               ret = 1;
-                               goto cleanup;
-                       }
-                       /* new config section, skip the '[' */
-                       name = strdup(line + 1);
-                       name[line_len - 2] = '\0';
-                       /* we're at a new section; perform any post-actions for 
the prior */
-                       if(finish_section(section, parse_options)) {
-                               ret = 1;
-                               goto cleanup;
+       /* parse options section */
+       pm_printf(ALPM_LOG_DEBUG, "parseconfig: options pass\n");
+       alpm_list_t *iter;
+       for(iter = sections; iter; iter = alpm_list_next(iter)) {
+               ini_section_t *current = (ini_section_t *) iter->data;
+               if(strcmp("options", current->name) == 0) {
+                       if((ret = parse_options(current))) {
+                               ini_free(sections);
+                               return ret;
                        }
-                       pm_printf(ALPM_LOG_DEBUG, "config: new section '%s'\n", 
name);
-                       section->name = name;
-                       section->is_options = (strcmp(name, "options") == 0);
-                       continue;
+                       break;
                }
+       }
 
-               /* directive */
-               /* strsep modifies the 'line' string: 'key \0 value' */
-               key = line;
-               value = line;
-               strsep(&value, "=");
-               strtrim(key);
-               strtrim(value);
-
-               if(key == NULL) {
-                       pm_printf(ALPM_LOG_ERROR, _("config file %s, line %d: 
syntax error in config file- missing key.\n"),
-                                       file, linenum);
-                       ret = 1;
-                       goto cleanup;
-               }
-               /* For each directive, compare to the camelcase string. */
-               if(section->name == NULL) {
-                       pm_printf(ALPM_LOG_ERROR, _("config file %s, line %d: 
All directives must belong to a section.\n"),
-                                       file, linenum);
-                       ret = 1;
-                       goto cleanup;
-               }
-               /* Include is allowed in both options and repo sections */
-               if(strcmp(key, "Include") == 0) {
-                       glob_t globbuf;
-                       int globret;
-                       size_t gindex;
+       if((ret = setup_libalpm())) {
+               ini_free(sections);
+               return ret;
+       }
 
-                       if(value == NULL) {
-                               pm_printf(ALPM_LOG_ERROR, _("config file %s, 
line %d: directive '%s' needs a value\n"),
-                                               file, linenum, key);
-                               ret = 1;
-                               goto cleanup;
-                       }
-                       /* Ignore include failures... assume non-critical */
-                       globret = glob(value, GLOB_NOCHECK, NULL, &globbuf);
-                       switch(globret) {
-                               case GLOB_NOSPACE:
-                                       pm_printf(ALPM_LOG_DEBUG,
-                                                       "config file %s, line 
%d: include globbing out of space\n",
-                                                       file, linenum);
-                               break;
-                               case GLOB_ABORTED:
-                                       pm_printf(ALPM_LOG_DEBUG,
-                                                       "config file %s, line 
%d: include globbing read error for %s\n",
-                                                       file, linenum, value);
-                               break;
-                               case GLOB_NOMATCH:
-                                       pm_printf(ALPM_LOG_DEBUG,
-                                                       "config file %s, line 
%d: no include found for %s\n",
-                                                       file, linenum, value);
-                               break;
-                               default:
-                                       for(gindex = 0; gindex < 
globbuf.gl_pathc; gindex++) {
-                                               pm_printf(ALPM_LOG_DEBUG, 
"config file %s, line %d: including %s\n",
-                                                               file, linenum, 
globbuf.gl_pathv[gindex]);
-                                               
_parseconfig(globbuf.gl_pathv[gindex], section, parse_options, depth + 1);
-                                       }
-                               break;
-                       }
-                       globfree(&globbuf);
+       /* parse the rest (Repositories) */
+       pm_printf(ALPM_LOG_DEBUG, "parseconfig: repo pass\n");
+
+       for (iter = sections; iter; iter = alpm_list_next(iter)) {
+               ini_section_t *current = (ini_section_t *) iter->data;
+               if(strcmp("options", current->name) == 0) {
+                       /* skip options */
                        continue;
                }
-               if(parse_options && section->is_options) {
-                       /* we are either in options ... */
-                       if((ret = _parse_options(key, value, file, linenum)) != 
0) {
-                               goto cleanup;
-                       }
-               } else if(!parse_options && !section->is_options) {
-                       /* ... or in a repo section */
-                       if(strcmp(key, "Server") == 0) {
-                               if(value == NULL) {
-                                       pm_printf(ALPM_LOG_ERROR, _("config 
file %s, line %d: directive '%s' needs a value\n"),
-                                                       file, linenum, key);
-                                       ret = 1;
-                                       goto cleanup;
-                               }
-                               section->servers = 
alpm_list_add(section->servers, strdup(value));
-                       } else if(strcmp(key, "SigLevel") == 0) {
-                               alpm_list_t *values = NULL;
-                               setrepeatingoption(value, "SigLevel", &values);
-                               if(values) {
-                                       if(section->siglevel == 
ALPM_SIG_USE_DEFAULT) {
-                                               section->siglevel = 
config->siglevel;
-                                       }
-                                       if(process_siglevel(values, 
&section->siglevel, file, linenum)) {
-                                               FREELIST(values);
-                                               ret = 1;
-                                               goto cleanup;
-                                       }
-                                       FREELIST(values);
-                               }
-                       } else {
-                               pm_printf(ALPM_LOG_WARNING,
-                                               _("config file %s, line %d: 
directive '%s' in section '%s' not recognized.\n"),
-                                               file, linenum, key, 
section->name);
-                       }
+               if((ret = parse_repository(current))) {
+                       ini_free(sections);
+                       return ret;
                }
        }
 
-       if(depth == 0) {
-               ret = finish_section(section, parse_options);
-       }
+       ini_free(sections);
 
-cleanup:
-       if(fp) {
-               fclose(fp);
-       }
-       pm_printf(ALPM_LOG_DEBUG, "config: finished parsing %s\n", file);
-       return ret;
-}
-
-/** Parse a configuration file.
- * @param file path to the config file
- * @return 0 on success, non-zero on error
- */
-int parseconfig(const char *file)
-{
-       int ret;
-       struct section_t section;
-       memset(&section, 0, sizeof(struct section_t));
-       section.siglevel = ALPM_SIG_USE_DEFAULT;
-       /* the config parse is a two-pass affair. We first parse the entire 
thing for
-        * the [options] section so we can get all default and path options set.
-        * Next, we go back and parse everything but [options]. */
-
-       /* call the real parseconfig function with a null section & db argument 
*/
-       pm_printf(ALPM_LOG_DEBUG, "parseconfig: options pass\n");
-       if((ret = _parseconfig(file, &section, 1, 0))) {
-               return ret;
-       }
-       if((ret = setup_libalpm())) {
-               return ret;
-       }
-       /* second pass, repo section parsing */
-       pm_printf(ALPM_LOG_DEBUG, "parseconfig: repo pass\n");
-       return _parseconfig(file, &section, 0, 0);
+       return 0;
 }
 
 /* vim: set ts=2 sw=2 noet: */
-- 
1.8.2


Reply via email to