2 * Copyright Neil Brown ©2023 <neil@brown.name>
3 * May be distributed under terms of GPLv2 - or indeed any
4 * "Popular / Strong Community" license approved by the Open Source Initiative
5 * https://opensource.org/licenses/?categories=popular-strong-community
7 * Parse an 'ini' file calling a call-back for each value found.
10 * - individual lines must not exceed 256 chars. Longer lines are
12 * - leading white space continues the previous line, this allowing large
13 * values. The newline and leading white space are stripped.
14 * Each line is provided separately to the callback, so precise detail of
15 * how continuation lines are merged are left up to that callback.
16 * - white space around "=", at EOL, and around section name in [section]
18 * - Double quotes at both ends of a value are stripped. This allows
19 * white space at either end of a value.
20 * - If first non-white is '#', line is ignored.
21 * - Everything after closing ']' of section is ignored
22 * - If value is not quoted, everything after first '#' is ignored
23 * - blank lines are ignored
30 /* "safe" pointers can never be NULL */
34 typedef void (*ini_handle)(void *data, char *section safe,
35 char *name safe, char *value safe,
36 const char *path safe,
39 static inline void parse_ini(const char *path safe,
40 ini_handle handle, void *data)
42 FILE *f = fopen(path, "r");
44 char section[257] = "";
49 while (fgets(line, sizeof(line), f) != NULL) {
51 char *eol = strchr(line, '\n');
56 while ((ch = fgetc(f)) != '\n' &&
62 eol = strchr(line, ']');
65 while (eol > line && isblank(eol[-1]))
75 /* find/strip comment */
77 while (*st && (quote || *st != '#')) {
84 if (isblank(line[0])) {
86 /* Nothing to continue */
97 /* There must be an '=' */
98 eq = strchr(line, '=');
102 while (eq > line && isblank(eq[-1]))
106 /* No name before '=' */
111 /* A value is at 'st', to be set or appended */
112 eol = st + strlen(st);
115 while (eol > st && isblank(eol[-1]))
117 if (*st == '"' && eol > st + 1 && eol[-1] == '"') {
122 handle(data, section, name, st, path, append);