16 for (
int i = 0; i <
ini->section_count; i++) {
18 return &
ini->sections[i];
24struct section *get_or_create_section(
struct ini *
ini,
const char *name)
29 ini->sections = g_realloc(
ini->sections,
sizeof(
struct section) *
ini->section_count);
31 s = &
ini->sections[
ini->section_count - 1];
32 s->name = g_strdup(name);
39void add_entry(
struct ini *
ini,
const char *section_name,
const char *key,
const char *value)
41 struct section *s = get_or_create_section(
ini, section_name);
44 int len = s->entry_count;
45 s->entries = g_realloc(s->entries,
sizeof(
struct entry) * len);
46 s->entries[s->entry_count - 1].key = g_strdup(key);
50const char *section_get_value(
struct ini *
ini,
const struct section *s,
const char *key)
54 for (
int i = 0; i < s->entry_count; i++) {
55 if (
STR_EQ(s->entries[i].key, key)) {
56 return s->entries[i].value;
62const char *get_value(
struct ini *
ini,
const char *
section,
const char *key)
65 return section_get_value(
ini, s, key);
68bool ini_is_set(
struct ini *
ini,
const char *ini_section,
const char *ini_key)
70 return get_value(
ini, ini_section, ini_key) != NULL;
78 for (
int i = 0; i <
ini->section_count; i++) {
80 if (i + 1 >=
ini->section_count)
83 return ini->sections[i + 1].name;
89struct ini *load_ini_file(FILE *fp)
94 struct ini *
ini = g_malloc0(
sizeof(
struct ini));
99 char *current_section = NULL;
100 while (getline(&line, &line_len, fp) != -1) {
103 char *start = g_strstrip(line);
105 if (*start ==
';' || *start ==
'#' ||
STR_EMPTY(start))
109 char *end = strchr(start + 1,
']');
111 LOG_W(
"Invalid config file at line %d: Missing ']'.", line_num);
117 g_free(current_section);
118 current_section = g_strdup(start + 1);
122 char *equal = strchr(start + 1,
'=');
124 LOG_W(
"Invalid config file at line %d: Missing '='.", line_num);
129 char *key = g_strstrip(start);
130 char *value = g_strstrip(equal + 1);
132 char *quote = strchr(value,
'"');
133 char *value_end = NULL;
135 value_end = strchr(quote + 1,
'"');
137 LOG_W(
"Invalid config file at line %d: Missing '\"'.", line_num);
144 char *comment = strpbrk(value_end,
"#;");
148 value = g_strstrip(value);
150 if (!current_section) {
151 LOG_W(
"Invalid config file at line %d: Key value pair without a section.", line_num);
155 add_entry(
ini, current_section, key, value);
158 g_free(current_section);
163void finish_ini(
struct ini *
ini)
165 for (
int i = 0; i <
ini->section_count; i++) {
166 for (
int j = 0; j <
ini->sections[i].entry_count; j++) {
167 g_free(
ini->sections[i].entries[j].key);
168 g_free(
ini->sections[i].entries[j].value);
170 g_free(
ini->sections[i].entries);
171 g_free(
ini->sections[i].name);
173 g_clear_pointer(&
ini->sections, g_free);
174 ini->section_count = 0;
const char * next_section(const struct ini *ini, const char *section)
Parser for INI config files.
Logging subsystem and helpers.
Type definitions for settings.
char * string_strip_quotes(const char *value)
Strip quotes from a string, ignoring inner quotes.
String, time and other various helpers.
#define STR_EMPTY(s)
Test if a string is NULL or empty.
#define STR_EQ(a, b)
Test if string a and b contain the same chars.
#define ASSERT_OR_RET(expr, val)
Assert that expr evaluates to true, if not return val.