]> git.neil.brown.name Git - edlib.git/blob - parse-ini.h
TODO: clean out done items.
[edlib.git] / parse-ini.h
1 /*
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
6  *
7  * Parse an 'ini' file calling a call-back for each value found.
8  *
9  * Syntax for ini file
10  * - individual lines must not exceed 256 chars.  Longer lines are
11  *   silently truncated.
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]
17  *   is stripped
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
24  */
25 #include <stdio.h>
26 #include <string.h>
27 #include <ctype.h>
28
29 #ifndef safe
30 /* "safe" pointers can never be NULL */
31 #define safe
32 #endif
33
34 typedef void (*ini_handle)(void *data, char *section safe,
35                            char *name safe, char *value safe,
36                            const char *path safe,
37                            int append);
38
39 static inline void parse_ini(const char *path safe,
40                              ini_handle handle, void *data)
41 {
42         FILE *f = fopen(path, "r");
43         char line[257];
44         char section[257] = "";
45         char name[257] = "";
46
47         if (!f)
48                 return;
49         while (fgets(line, sizeof(line), f) != NULL) {
50                 char *st, *eq;
51                 char *eol = strchr(line, '\n');
52                 int append, quote;
53
54                 if (!eol) {
55                         int ch;
56                         while ((ch = fgetc(f)) != '\n' &&
57                                ch != EOF)
58                                 ;
59                 } else
60                         *eol = 0;
61                 if (line[0] == '[') {
62                         eol = strchr(line, ']');
63                         if (!eol)
64                                 continue;
65                         while (eol > line && isblank(eol[-1]))
66                                 eol -= 1;
67                         *eol = 0;
68                         st = line+1;
69                         while (isblank(*st))
70                                 st += 1;
71                         strcpy(section, st);
72                         name[0] = 0;
73                         continue;
74                 }
75                 /* find/strip comment */
76                 st = line; quote = 0;
77                 while (*st && (quote || *st != '#')) {
78                         if (*st == '"')
79                                 quote = !quote;
80                         st += 1;
81                 }
82                 if (*st  == '#')
83                         *st = 0;
84                 if (isblank(line[0])) {
85                         if (!name[0])
86                                 /* Nothing to continue */
87                                 continue;
88                         st = line;
89                         while (isblank(*st))
90                                 st += 1;
91                         if (!*st)
92                                 /* Blank line */
93                                 continue;
94                         append = 1;
95                 } else {
96                         name[0] = 0;
97                         /* There must be an '=' */
98                         eq = strchr(line, '=');
99                         if (!eq)
100                                 continue;
101                         st = eq + 1;
102                         while (eq > line && isblank(eq[-1]))
103                                 eq -= 1;
104                         *eq = 0;
105                         if (!line[0])
106                                 /* No name before '=' */
107                                 continue;
108                         strcpy(name, line);
109                         append = 0;
110                 }
111                 /* A value is at 'st', to be set or appended */
112                 eol = st + strlen(st);
113                 while (isblank(*st))
114                         st += 1;
115                 while (eol > st && isblank(eol[-1]))
116                         eol -= 1;
117                 if (*st == '"' && eol > st + 1 && eol[-1] == '"') {
118                         st += 1;
119                         eol -= 1;
120                 }
121                 *eol = 0;
122                 handle(data, section, name, st, path, append);
123         }
124         fclose(f);
125 }