ini-parser: add libsys_config_parse_by_section() 72/268472/4 accepted/tizen/unified/20220117.135033 submit/tizen/20220112.015321 submit/tizen/20220113.004629
authorYoungjae Cho <y0.cho@samsung.com>
Thu, 23 Dec 2021 07:33:30 +0000 (16:33 +0900)
committerYoungjae Cho <y0.cho@samsung.com>
Mon, 3 Jan 2022 06:51:48 +0000 (15:51 +0900)
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 <y0.cho@samsung.com>
src/libcommon/ini-parser.c
src/libcommon/ini-parser.h

index f3ed8c7..a82192c 100644 (file)
@@ -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;
+}
index f30096c..7af9f42 100644 (file)
 #ifndef __INI_PARSER_H__
 #define __INI_PARSER_H__
 
+#include <glib.h>
+
 #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