Dunst
Lightweight notification daemon
Loading...
Searching...
No Matches
ini.c
Go to the documentation of this file.
1/* SPDX-License-Identifier: BSD-3-Clause */
8
9#include "ini.h"
10#include "utils.h"
11#include "log.h"
12#include "settings.h"
13
14struct section *get_section(struct ini *ini, const char *name)
15{
16 for (int i = 0; i < ini->section_count; i++) {
17 if (STR_EQ(ini->sections[i].name, name))
18 return &ini->sections[i];
19 }
20
21 return NULL;
22}
23
24struct section *get_or_create_section(struct ini *ini, const char *name)
25{
26 struct section *s = get_section(ini, name);
27 if (!s) {
28 ini->section_count++;
29 ini->sections = g_realloc(ini->sections, sizeof(struct section) * ini->section_count);
30
31 s = &ini->sections[ini->section_count - 1];
32 s->name = g_strdup(name);
33 s->entries = NULL;
34 s->entry_count = 0;
35 }
36 return s;
37}
38
39void add_entry(struct ini *ini, const char *section_name, const char *key, const char *value)
40{
41 struct section *s = get_or_create_section(ini, section_name);
42
43 s->entry_count++;
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);
47 s->entries[s->entry_count - 1].value = string_strip_quotes(value);
48}
49
50const char *section_get_value(struct ini *ini, const struct section *s, const char *key)
51{
52 ASSERT_OR_RET(s, NULL);
53
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;
57 }
58 }
59 return NULL;
60}
61
62const char *get_value(struct ini *ini, const char *section, const char *key)
63{
64 struct section *s = get_section(ini, section);
65 return section_get_value(ini, s, key);
66}
67
68bool ini_is_set(struct ini *ini, const char *ini_section, const char *ini_key)
69{
70 return get_value(ini, ini_section, ini_key) != NULL;
71}
72
73const char *next_section(const struct ini *ini, const char *section)
74{
75 ASSERT_OR_RET(ini->section_count > 0, NULL);
76 ASSERT_OR_RET(section, ini->sections[0].name);
77
78 for (int i = 0; i < ini->section_count; i++) {
79 if (STR_EQ(section, ini->sections[i].name)) {
80 if (i + 1 >= ini->section_count)
81 return NULL;
82 else
83 return ini->sections[i + 1].name;
84 }
85 }
86 return NULL;
87}
88
89struct ini *load_ini_file(FILE *fp)
90{
91 if (!fp)
92 return NULL;
93
94 struct ini *ini = g_malloc0(sizeof(struct ini));
95 char *line = NULL;
96 size_t line_len = 0;
97
98 int line_num = 0;
99 char *current_section = NULL;
100 while (getline(&line, &line_len, fp) != -1) {
101 line_num++;
102
103 char *start = g_strstrip(line);
104
105 if (*start == ';' || *start == '#' || STR_EMPTY(start))
106 continue;
107
108 if (*start == '[') {
109 char *end = strchr(start + 1, ']');
110 if (!end) {
111 LOG_W("Invalid config file at line %d: Missing ']'.", line_num);
112 continue;
113 }
114
115 *end = '\0';
116
117 g_free(current_section);
118 current_section = g_strdup(start + 1);
119 continue;
120 }
121
122 char *equal = strchr(start + 1, '=');
123 if (!equal) {
124 LOG_W("Invalid config file at line %d: Missing '='.", line_num);
125 continue;
126 }
127
128 *equal = '\0';
129 char *key = g_strstrip(start);
130 char *value = g_strstrip(equal + 1);
131
132 char *quote = strchr(value, '"');
133 char *value_end = NULL;
134 if (quote) {
135 value_end = strchr(quote + 1, '"');
136 if (!value_end) {
137 LOG_W("Invalid config file at line %d: Missing '\"'.", line_num);
138 continue;
139 }
140 } else {
141 value_end = value;
142 }
143
144 char *comment = strpbrk(value_end, "#;");
145 if (comment)
146 *comment = '\0';
147
148 value = g_strstrip(value);
149
150 if (!current_section) {
151 LOG_W("Invalid config file at line %d: Key value pair without a section.", line_num);
152 continue;
153 }
154
155 add_entry(ini, current_section, key, value);
156 }
157 free(line);
158 g_free(current_section);
159 return ini;
160}
161
162
163void finish_ini(struct ini *ini)
164{
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);
169 }
170 g_free(ini->sections[i].entries);
171 g_free(ini->sections[i].name);
172 }
173 g_clear_pointer(&ini->sections, g_free);
174 ini->section_count = 0;
175}
const char * next_section(const struct ini *ini, const char *section)
Definition ini.c:73
Parser for INI config files.
Logging subsystem and helpers.
Type definitions for settings.
Definition ini.h:17
Definition ini.h:28
Definition ini.h:22
char * string_strip_quotes(const char *value)
Strip quotes from a string, ignoring inner quotes.
Definition utils.c:111
String, time and other various helpers.
#define STR_EMPTY(s)
Test if a string is NULL or empty.
Definition utils.h:20
#define STR_EQ(a, b)
Test if string a and b contain the same chars.
Definition utils.h:26
#define ASSERT_OR_RET(expr, val)
Assert that expr evaluates to true, if not return val.
Definition utils.h:42