From: Youngjae Cho Date: Thu, 23 Dec 2021 07:33:30 +0000 (+0900) Subject: ini-parser: add libsys_config_parse_by_section() X-Git-Tag: submit/tizen/20220112.015321^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F72%2F268472%2F4;p=platform%2Fcore%2Fsystem%2Flibsyscommon.git ini-parser: add libsys_config_parse_by_section() The original function, config_parse(), parses configuration file line by line. Due to this, a parser, which is registered by the config_parse(), can hardly handle out-of-ordered section/property or multiple sections with same name. The libsys_config_parse_by_section() now parses configuration file by section. Therefore a parser can now find whole properties of a section when the section is conveyed to the parser. Change-Id: I08f09e2f6aefabea497393edb3c1f88dbe2d8850 Signed-off-by: Youngjae Cho --- diff --git a/src/libcommon/ini-parser.c b/src/libcommon/ini-parser.c index f3ed8c7..a82192c 100644 --- a/src/libcommon/ini-parser.c +++ b/src/libcommon/ini-parser.c @@ -129,3 +129,95 @@ error: return ret; } +/* scan format after trimming leading/trailing whitespace, comment */ +static int sscanf_trim_whitespace_comment(const char *str, const char *format, ...) +{ + char trimmed_str[1024] = { 0, }; + va_list ap; + int ret; + + str += strspn(str, " \t"); + ret = sscanf(str, "%1023[^ \t\n\r#]", trimmed_str); + if (ret != 1) + return 0; + + va_start(ap, format); + ret = vsscanf(trimmed_str, format, ap); + va_end(ap); + + return ret; +} + +static void free_data(gpointer data) +{ + free(data); +} + +int libsys_config_parse_by_section(const char *fname, int cb(const struct parse_result *, void *), void *user_data) +{ + FILE *fp = NULL; + char *line = NULL; + size_t len = 0; + size_t n_read; + int ret = 0; + int retval; + struct parse_result result = { 0, }; + struct section_property *prop; + char tmp_sectname[128]; + char tmp_key[128]; + char tmp_value[128]; + + if (!fname || !cb) + return -EINVAL; + + fp = fopen(fname, "r"); + if (!fp) { + _E("Failed to open file '%s'.", fname); + return -errno; + } + + while (getline(&line, &len, fp) != EOF) { + // find section + retval = sscanf_trim_whitespace_comment(line, "[%127[^]]]", tmp_sectname); + if (retval != 1) + continue; + + result.section = strndup(tmp_sectname, sizeof(tmp_sectname)); + + // parse properties within the section + while((n_read = getline(&line, &len, fp)) != EOF) { + retval = sscanf_trim_whitespace_comment(line, "[%127[^]]]", tmp_sectname); + if (retval == 1) { // found next section. stop parsing properties + fseek(fp, -n_read, SEEK_CUR); + break; + } + + retval = sscanf_trim_whitespace_comment(line, "%127[^=]=%127s", tmp_key, tmp_value); + if (retval == 2) { // found property + prop = calloc(1, sizeof(struct section_property)); + if (!prop) + continue; + strncpy(prop->key, tmp_key, sizeof(prop->key) - 1); + strncpy(prop->value, tmp_value, sizeof(prop->value) - 1); + result.props = g_list_append(result.props, prop); + } + } + + ret = cb(&result, user_data); + + free(result.section); + result.section = NULL; + + g_list_free_full(result.props, free_data); + result.props = NULL; + + if (ret != 0) + break; + } + + if (fp) + fclose(fp); + free(line); + + return ret; +} diff --git a/src/libcommon/ini-parser.h b/src/libcommon/ini-parser.h index f30096c..7af9f42 100644 --- a/src/libcommon/ini-parser.h +++ b/src/libcommon/ini-parser.h @@ -20,13 +20,28 @@ #ifndef __INI_PARSER_H__ #define __INI_PARSER_H__ +#include + #define MATCH(a, b) (!strncmp(a, b, strlen(a))) #define SET_CONF(a, b) (a = (b > 0.0 ? b : a)) struct parse_result { char *section; - char *name; - char *value; + union { + // config_parse() + struct { + char *name; + char *value; + }; + + // config_parse_by_section() + GList *props; + }; +}; + +struct section_property { + char key[128]; + char value[128]; }; /** @@ -39,4 +54,13 @@ struct parse_result { int config_parse(const char *file_name, int cb(struct parse_result *result, void *user_data), void *user_data); + +/** + * @brief Parse config file and call callback\n + * @param[in] file_name conf file. + * @param[in] cb cb is called when conf file is parsed by section + * @param[in] user_data user data is passed to cb. + * @return 0 on success, negative if failed + */ +int libsys_config_parse_by_section(const char *file_name, int cb(const struct parse_result *, void *), void *user_data); #endif