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;
+}
#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];
};
/**
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