PatchworkOS
Loading...
Searching...
No Matches
config.c
Go to the documentation of this file.
2
3#include <ctype.h>
4#include <stdarg.h>
5#include <stdbool.h>
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9#include <strings.h>
10#include <sys/io.h>
11#include <sys/list.h>
12
13typedef struct config_pair
14{
15 char* key;
16 char* value;
19
20typedef struct config_section
21{
22 char* name;
26
27typedef struct config
28{
30} config_t;
31
32static char* config_trim_whitespace(char* str)
33{
34 char* end;
35 while (isspace((unsigned char)*str))
36 {
37 str++;
38 }
39
40 if (*str == 0)
41 {
42 return str;
43 }
44
45 end = str + strlen(str) - 1;
46 while (end > str && isspace((unsigned char)*end))
47 {
48 end--;
49 }
50
51 *(end + 1) = '\0';
52 return str;
53}
54
55static config_section_t* config_find_section(config_t* cfg, const char* section)
56{
57 if (cfg == NULL || section == NULL)
58 {
59 return NULL;
60 }
61
63 LIST_FOR_EACH(sec, &cfg->sections, entry)
64 {
65 if (strcasecmp(sec->name, section) == 0)
66 {
67 return sec;
68 }
69 }
70
71 return NULL;
72}
73
74static config_pair_t* config_find_pair(config_section_t* sec, const char* key)
75{
76 if (sec == NULL || key == NULL)
77 {
78 return NULL;
79 }
80
81 config_pair_t* pair;
82 LIST_FOR_EACH(pair, &sec->pairs, entry)
83 {
84 if (strcasecmp(pair->key, key) == 0)
85 {
86 return pair;
87 }
88 }
89
90 return NULL;
91}
92
93config_t* config_open(const char* prefix, const char* name)
94{
95 if (prefix == NULL || name == NULL)
96 {
97 return NULL;
98 }
99
100 char path[MAX_PATH] = {0};
101 snprintf(path, MAX_PATH - 1, "/cfg/%s-%s.cfg", prefix, name);
102
103 FILE* file = fopen(path, "r");
104 if (file == NULL)
105 {
106 return NULL;
107 }
108
109 config_t* config = malloc(sizeof(config_t));
110 if (config == NULL)
111 {
112 fclose(file);
113 return NULL;
114 }
115 list_init(&config->sections);
116
117 char lineBuffer[1024];
118 config_section_t* currentSection = NULL;
119 while (fgets(lineBuffer, sizeof(lineBuffer), file) != NULL)
120 {
122 if (line[0] == '\0' || line[0] == '#' || line[0] == ';')
123 {
124 continue;
125 }
126
127 if (line[0] == '[')
128 {
129 char* end = strchr(line, ']');
130 if (end == NULL)
131 {
132 continue;
133 }
134 *end = '\0';
135 char* name = config_trim_whitespace(line + 1);
136 if (name[0] == '\0')
137 {
138 continue;
139 }
140
141 config_section_t* section = malloc(sizeof(config_section_t));
142 if (section == NULL)
143 {
144 goto error;
145 }
146 section->name = strdup(name);
147 if (section->name == NULL)
148 {
149 free(section);
150 goto error;
151 }
152 list_entry_init(&section->entry);
153 list_init(&section->pairs);
154
155 list_push(&config->sections, &section->entry);
156 currentSection = section;
157 }
158 else
159 {
160 char* equals = strchr(line, '=');
161 if (equals == NULL || currentSection == NULL)
162 {
163 continue;
164 }
165 *equals = '\0';
166 char* key = config_trim_whitespace(line);
167 char* value = config_trim_whitespace(equals + 1);
168 if (key[0] == '\0')
169 {
170 continue;
171 }
172
173 config_pair_t* pair = malloc(sizeof(config_pair_t));
174 if (pair == NULL)
175 {
176 goto error;
177 }
178 pair->key = strdup(key);
179 pair->value = strdup(value);
180 if (pair->key == NULL || pair->value == NULL)
181 {
182 free(pair->key);
183 free(pair->value);
184 free(pair);
185 goto error;
186 }
187 list_entry_init(&pair->entry);
188
189 list_push(&currentSection->pairs, &pair->entry);
190 }
191 }
192
193 fclose(file);
194 return config;
195
196error:
197 fclose(file);
198 config_close(config);
199 return NULL;
200}
201
203{
204 if (config == NULL)
205 {
206 return;
207 }
208
209 while (!list_is_empty(&config->sections))
210 {
212
213 while (!list_is_empty(&sec->pairs))
214 {
215 config_pair_t* pair = CONTAINER_OF(list_pop(&sec->pairs), config_pair_t, entry);
216 free(pair->key);
217 free(pair->value);
218 free(pair);
219 }
220
221 free(sec->name);
222 free(sec);
223 }
224
225 free(config);
226}
227
228const char* config_get_string(config_t* config, const char* section, const char* key, const char* fallback)
229{
230 if (config == NULL || section == NULL || key == NULL)
231 {
232 return fallback;
233 }
234
235 config_section_t* sec = config_find_section(config, section);
236 if (sec == NULL)
237 {
238 return fallback;
239 }
240
241 config_pair_t* pair = config_find_pair(sec, key);
242 if (pair == NULL)
243 {
244 return fallback;
245 }
246
247 return pair->value;
248}
249
250int64_t config_get_int(config_t* config, const char* section, const char* key, int64_t fallback)
251{
252 if (config == NULL || section == NULL || key == NULL)
253 {
254 return fallback;
255 }
256
257 const char* str = config_get_string(config, section, key, NULL);
258 if (str == NULL)
259 {
260 return fallback;
261 }
262
263 char* end;
264 int64_t value = strtoll(str, &end, 0);
265 if (end == str || *end != '\0')
266 {
267 return fallback;
268 }
269
270 return value;
271}
272
273bool config_get_bool(config_t* config, const char* section, const char* key, bool fallback)
274{
275 if (config == NULL || section == NULL || key == NULL)
276 {
277 return fallback;
278 }
279
280 const char* str = config_get_string(config, section, key, NULL);
281 if (str == NULL)
282 {
283 return fallback;
284 }
285
286 if (strcasecmp(str, "true") == 0 || strcasecmp(str, "yes") == 0 || strcasecmp(str, "on") == 0 ||
287 strcmp(str, "1") == 0)
288 {
289 return true;
290 }
291 else if (strcasecmp(str, "false") == 0 || strcasecmp(str, "no") == 0 || strcasecmp(str, "off") == 0 ||
292 strcmp(str, "0") == 0)
293 {
294 return false;
295 }
296
297 return fallback;
298}
299
300config_array_t* config_get_array(config_t* config, const char* section, const char* key)
301{
302 static config_array_t emptyArray = {.items = NULL, .length = 0};
303 if (config == NULL || section == NULL || key == NULL)
304 {
305 goto return_empty;
306 }
307
308 const char* str = config_get_string(config, section, key, NULL);
309 if (str == NULL || str[0] == '\0')
310 {
311 goto return_empty;
312 }
313
314 uint64_t length = strlen(str);
315 uint64_t maxSize = sizeof(config_array_t) + (length * sizeof(char*)) + length + 1;
316
317 config_array_t* array = malloc(maxSize);
318 if (array == NULL)
319 {
320 return NULL;
321 }
322 array->items = (char**)(array + 1);
323 array->length = 0;
324
325 char* data = (char*)(array->items + length);
326
327 uint64_t index = 0;
328 while (*str != '\0')
329 {
330 while (isspace((unsigned char)*str))
331 {
332 str++;
333 }
334
335 if (*str == '\0')
336 {
337 break;
338 }
339
340 const char* start = str;
341
342 while (*str != '\0' && *str != ',')
343 {
344 str++;
345 }
346
347 const char* end = str;
348
349 while (end > start && isspace((unsigned char)*(end - 1)))
350 {
351 end--;
352 }
353
354 uint64_t len = (end > start) ? (end - start) : 0;
355 if (len > 0)
356 {
357 memcpy(data, start, len);
358 data[len] = '\0';
359
360 array->items[index] = data;
361
362 data += len + 1;
363 index++;
364 }
365
366 if (*str == ',')
367 {
368 str++;
369 }
370 }
371
372 array->length = index;
373 return array;
374
375return_empty:
376 if (false) // to satisfy compiler
377 {
378 }
379 config_array_t* empty = malloc(sizeof(config_array_t));
380 if (empty != NULL)
381 {
382 empty->items = NULL;
383 empty->length = 0;
384 }
385 return empty;
386}
387
389{
390 if (array != NULL)
391 {
392 free(array);
393 }
394}
#define MAX_PATH
Maximum length of filepaths.
Definition MAX_PATH.h:11
static config_section_t * config_find_section(config_t *cfg, const char *section)
Definition config.c:55
static config_pair_t * config_find_pair(config_section_t *sec, const char *key)
Definition config.c:74
static char * config_trim_whitespace(char *str)
Definition config.c:32
_PUBLIC int isspace(int c)
Definition isspace.c:5
static fd_t data
Definition dwm.c:21
config_array_t * config_get_array(config_t *config, const char *section, const char *key)
Get an array of strings from a configuration file.
Definition config.c:300
config_t * config_open(const char *prefix, const char *name)
Open a configuration file.
Definition config.c:93
int64_t config_get_int(config_t *config, const char *section, const char *key, int64_t fallback)
Get an integer value from a configuration file.
Definition config.c:250
const char * config_get_string(config_t *config, const char *section, const char *key, const char *fallback)
Get a string value from a configuration file.
Definition config.c:228
void config_array_free(config_array_t *array)
Free a configuration array.
Definition config.c:388
bool config_get_bool(config_t *config, const char *section, const char *key, bool fallback)
Get a boolean value from a configuration file.
Definition config.c:273
void config_close(config_t *config)
Close a configuration file.
Definition config.c:202
#define LIST_FOR_EACH(elem, list, member)
Iterates over a list.
Definition list.h:65
static void list_push(list_t *list, list_entry_t *entry)
Pushes an entry to the end of the list.
Definition list.h:345
static bool list_is_empty(list_t *list)
Checks if a list is empty.
Definition list.h:229
static void list_entry_init(list_entry_t *entry)
Initializes a list entry.
Definition list.h:184
static void list_init(list_t *list)
Initializes a list.
Definition list.h:198
static list_entry_t * list_pop(list_t *list)
Pops the first entry from the list.
Definition list.h:361
#define NULL
Pointer error value.
Definition NULL.h:23
#define CONTAINER_OF(ptr, type, member)
Container of macro.
static char lineBuffer[LOG_MAX_BUFFER]
Definition log.c:22
static dentry_t * file
Definition log_file.c:17
static void start()
Definition main.c:542
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
__INT64_TYPE__ int64_t
Definition stdint.h:16
_PUBLIC char * fgets(char *_RESTRICT s, int n, FILE *_RESTRICT stream)
Definition fgets.c:5
_PUBLIC FILE * fopen(const char *_RESTRICT filename, const char *_RESTRICT mode)
Definition fopen.c:27
_PUBLIC int fclose(FILE *stream)
Definition fclose.c:7
_PUBLIC int snprintf(char *_RESTRICT s, size_t n, const char *_RESTRICT format,...)
Definition snprintf.c:3
_PUBLIC long long int strtoll(const char *_RESTRICT nptr, char **_RESTRICT endptr, int base)
_PUBLIC void * malloc(size_t size)
Definition malloc.c:5
_PUBLIC void free(void *ptr)
Definition free.c:11
char * strdup(const char *src)
Definition strdup.c:5
_PUBLIC void * memcpy(void *_RESTRICT s1, const void *_RESTRICT s2, size_t n)
Definition memcpy.c:4
_PUBLIC size_t strlen(const char *s)
Definition strlen.c:3
_PUBLIC int strcmp(const char *s1, const char *s2)
Definition strcmp.c:3
_PUBLIC char * strchr(const char *s, int c)
Definition strchr.c:3
int strcasecmp(const char *s1, const char *s2)
Definition strcasecmp.c:4
Definition file.h:34
Configuration array structure.
Definition config.h:38
char ** items
Definition config.h:39
uint64_t length
Definition config.h:40
char * value
Definition config.c:16
list_entry_t entry
Definition config.c:17
char * key
Definition config.c:15
char * name
Definition config.c:22
list_t pairs
Definition config.c:24
list_entry_t entry
Definition config.c:23
Opaque configuration structure.
Definition config.c:28
list_t sections
Definition config.c:29
A entry in a doubly linked list.
Definition list.h:38
A doubly linked list.
Definition list.h:51