downstream: cosmetic changes (tabulation etc)
[profile/ivi/weston-ivi-shell.git] / shared / config-parser.c
1 /*
2  * Copyright © 2011 Intel Corporation
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that copyright
7  * notice and this permission notice appear in supporting documentation, and
8  * that the name of the copyright holders not be used in advertising or
9  * publicity pertaining to distribution of the software without specific,
10  * written prior permission.  The copyright holders make no representations
11  * about the suitability of this software for any purpose.  It is provided "as
12  * is" without express or implied warranty.
13  *
14  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20  * OF THIS SOFTWARE.
21  */
22
23 #include "config.h"
24
25 #include <string.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <assert.h>
29 #include <ctype.h>
30 #include <limits.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <fcntl.h>
34 #include <unistd.h>
35 #include <errno.h>
36
37 #include <wayland-util.h>
38
39 #include "config-parser.h"
40 #include "str-util.h"
41
42 #define container_of(ptr, type, member) ({                              \
43         const __typeof__( ((type *)0)->member ) *__mptr = (ptr);        \
44         (type *)( (char *)__mptr - offsetof(type,member) );})
45
46 struct weston_config_entry {
47         char *key;
48         char *value;
49         struct wl_list link;
50 };
51
52 struct weston_config_section {
53         char *name;
54         struct wl_list entry_list;
55         struct wl_list link;
56 };
57
58 struct weston_config {
59         struct wl_list section_list;
60         char path[PATH_MAX];
61 };
62
63 static int
64 open_config_file(struct weston_config *c, const char *name)
65 {
66         const char *config_dir  = getenv("XDG_CONFIG_HOME");
67         const char *home_dir    = getenv("HOME");
68         const char *config_dirs = getenv("XDG_CONFIG_DIRS");
69         const char *p, *next;
70         int fd;
71
72         if (name[0] == '/') {
73                 snprintf(c->path, sizeof c->path, "%s", name);
74                 return open(name, O_RDONLY | O_CLOEXEC);
75         }
76
77         /* Precedence is given to config files in the home directory,
78          * and then to directories listed in XDG_CONFIG_DIRS and
79          * finally to the current working directory. */
80
81         /* $XDG_CONFIG_HOME */
82         if (config_dir) {
83                 snprintf(c->path, sizeof c->path, "%s/%s", config_dir, name);
84                 fd = open(c->path, O_RDONLY | O_CLOEXEC);
85                 if (fd >= 0)
86                         return fd;
87         }
88
89         /* $HOME/.config */
90         if (home_dir) {
91                 snprintf(c->path, sizeof c->path,
92                          "%s/.config/%s", home_dir, name);
93                 fd = open(c->path, O_RDONLY | O_CLOEXEC);
94                 if (fd >= 0)
95                         return fd;
96         }
97
98         /* For each $XDG_CONFIG_DIRS: weston/<config_file> */
99         if (!config_dirs)
100                 config_dirs = "/etc/xdg";  /* See XDG base dir spec. */
101
102         for (p = config_dirs; *p != '\0'; p = next) {
103                 next = strchrnul(p, ':');
104                 snprintf(c->path, sizeof c->path,
105                          "%.*s/weston/%s", (int)(next - p), p, name);
106                 fd = open(c->path, O_RDONLY | O_CLOEXEC);
107                 if (fd >= 0)
108                         return fd;
109
110                 if (*next == ':')
111                         next++;
112         }
113
114         /* Current working directory. */
115         snprintf(c->path, sizeof c->path, "./%s", name);
116
117         return open(c->path, O_RDONLY | O_CLOEXEC);
118 }
119
120 static struct weston_config_entry *
121 config_section_get_entry(struct weston_config_section *section,
122                          const char *key)
123 {
124         struct weston_config_entry *e;
125
126         if (section == NULL)
127                 return NULL;
128         wl_list_for_each(e, &section->entry_list, link)
129                 if (strcmp(e->key, key) == 0)
130                         return e;
131
132         return NULL;
133 }
134
135 WL_EXPORT
136 struct weston_config_section *
137 weston_config_get_section(struct weston_config *config, const char *section,
138                           const char *key, const char *value)
139 {
140         struct weston_config_section *s;
141         struct weston_config_entry *e;
142
143         if (config == NULL)
144                 return NULL;
145         wl_list_for_each(s, &config->section_list, link) {
146                 if (strcmp(s->name, section) != 0)
147                         continue;
148                 if (key == NULL)
149                         return s;
150                 e = config_section_get_entry(s, key);
151                 if (e && strcmp(e->value, value) == 0)
152                         return s;
153         }
154
155         return NULL;
156 }
157
158 WL_EXPORT
159 int
160 weston_config_section_get_int(struct weston_config_section *section,
161                               const char *key,
162                               int32_t *value, int32_t default_value)
163 {
164         struct weston_config_entry *entry;
165
166         entry = config_section_get_entry(section, key);
167         if (entry == NULL) {
168                 *value = default_value;
169                 errno = ENOENT;
170                 return -1;
171         }
172
173         if (!weston_strtoi(entry->value, NULL, 0, value)) {
174                 *value = default_value;
175                 errno = EINVAL;
176                 return -1;
177         }
178
179         return 0;
180 }
181
182 WL_EXPORT
183 int
184 weston_config_section_get_uint(struct weston_config_section *section,
185                                const char *key,
186                                uint32_t *value, uint32_t default_value)
187 {
188         struct weston_config_entry *entry;
189
190         entry = config_section_get_entry(section, key);
191         if (entry == NULL) {
192                 *value = default_value;
193                 errno = ENOENT;
194                 return -1;
195         }
196
197         if (!weston_strtoui(entry->value, NULL, 0, value)) {
198                 *value = default_value;
199                 errno = EINVAL;
200                 return -1;
201         }
202
203         return 0;
204 }
205
206 WL_EXPORT
207 int
208 weston_config_section_get_double(struct weston_config_section *section,
209                                  const char *key,
210                                  double *value, double default_value)
211 {
212         struct weston_config_entry *entry;
213         char *end;
214
215         entry = config_section_get_entry(section, key);
216         if (entry == NULL) {
217                 *value = default_value;
218                 errno = ENOENT;
219                 return -1;
220         }
221
222         *value = strtod(entry->value, &end);
223         if (*end != '\0') {
224                 *value = default_value;
225                 errno = EINVAL;
226                 return -1;
227         }
228
229         return 0;
230 }
231
232 WL_EXPORT
233 int
234 weston_config_section_get_string(struct weston_config_section *section,
235                                  const char *key,
236                                  char **value, const char *default_value)
237 {
238         struct weston_config_entry *entry;
239
240         entry = config_section_get_entry(section, key);
241         if (entry == NULL) {
242                 if (default_value)
243                         *value = strdup(default_value);
244                 else
245                         *value = NULL;
246                 errno = ENOENT;
247                 return -1;
248         }
249
250         *value = strdup(entry->value);
251
252         return 0;
253 }
254
255 WL_EXPORT
256 int
257 weston_config_section_get_bool(struct weston_config_section *section,
258                                const char *key,
259                                int *value, int default_value)
260 {
261         struct weston_config_entry *entry;
262
263         entry = config_section_get_entry(section, key);
264         if (entry == NULL) {
265                 *value = default_value;
266                 errno = ENOENT;
267                 return -1;
268         }
269
270         if (strcmp(entry->value, "false") == 0)
271                 *value = 0;
272         else if (strcmp(entry->value, "true") == 0)
273                 *value = 1;
274         else {
275                 *value = default_value;
276                 errno = EINVAL;
277                 return -1;
278         }
279
280         return 0;
281 }
282
283 WL_EXPORT
284 const char *
285 weston_config_get_libexec_dir(void)
286 {
287         const char *path = getenv("WESTON_BUILD_DIR");
288
289         if (path)
290                 return path;
291
292         return LIBEXECDIR;
293 }
294
295 static struct weston_config_section *
296 config_add_section(struct weston_config *config, const char *name)
297 {
298         struct weston_config_section *section;
299
300         section = malloc(sizeof *section);
301         section->name = strdup(name);
302         wl_list_init(&section->entry_list);
303         wl_list_insert(config->section_list.prev, &section->link);
304
305         return section;
306 }
307
308 static struct weston_config_entry *
309 section_add_entry(struct weston_config_section *section,
310                   const char *key, const char *value)
311 {
312         struct weston_config_entry *entry;
313
314         entry = malloc(sizeof *entry);
315         entry->key = strdup(key);
316         entry->value = strdup(value);
317         wl_list_insert(section->entry_list.prev, &entry->link);
318
319         return entry;
320 }
321
322 struct weston_config *
323 weston_config_parse(const char *name)
324 {
325         FILE *fp;
326         char line[512], *p;
327         struct weston_config *config;
328         struct weston_config_section *section = NULL;
329         int i, fd;
330
331         config = malloc(sizeof *config);
332         if (config == NULL)
333                 return NULL;
334
335         wl_list_init(&config->section_list);
336
337         fd = open_config_file(config, name);
338         if (fd == -1) {
339                 free(config);
340                 return NULL;
341         }
342
343         fp = fdopen(fd, "r");
344         if (fp == NULL) {
345                 free(config);
346                 return NULL;
347         }
348
349         while (fgets(line, sizeof line, fp)) {
350                 switch (line[0]) {
351                 case '#':
352                 case '\n':
353                         continue;
354                 case '[':
355                         p = strchr(&line[1], ']');
356                         if (!p || p[1] != '\n') {
357                                 fprintf(stderr, "malformed "
358                                         "section header: %s\n", line);
359                                 fclose(fp);
360                                 weston_config_destroy(config);
361                                 return NULL;
362                         }
363                         p[0] = '\0';
364                         section = config_add_section(config, &line[1]);
365                         continue;
366                 default:
367                         p = strchr(line, '=');
368                         if (!p || p == line || !section) {
369                                 fprintf(stderr, "malformed "
370                                         "config line: %s\n", line);
371                                 fclose(fp);
372                                 weston_config_destroy(config);
373                                 return NULL;
374                         }
375
376                         p[0] = '\0';
377                         p++;
378                         while (isspace(*p))
379                                 p++;
380                         i = strlen(p);
381                         while (i > 0 && isspace(p[i - 1])) {
382                                 p[i - 1] = '\0';
383                                 i--;
384                         }
385                         section_add_entry(section, line, p);
386                         continue;
387                 }
388         }
389
390         fclose(fp);
391
392         return config;
393 }
394
395 const char *
396 weston_config_get_full_path(struct weston_config *config)
397 {
398         return config == NULL ? NULL : config->path;
399 }
400
401 int
402 weston_config_next_section(struct weston_config *config,
403                            struct weston_config_section **section,
404                            const char **name)
405 {
406         if (config == NULL)
407                 return 0;
408
409         if (*section == NULL)
410                 *section = container_of(config->section_list.next,
411                                         struct weston_config_section, link);
412         else
413                 *section = container_of((*section)->link.next,
414                                         struct weston_config_section, link);
415
416         if (&(*section)->link == &config->section_list)
417                 return 0;
418
419         *name = (*section)->name;
420
421         return 1;
422 }
423
424 void
425 weston_config_destroy(struct weston_config *config)
426 {
427         struct weston_config_section *s, *next_s;
428         struct weston_config_entry *e, *next_e;
429
430         if (config == NULL)
431                 return;
432
433         wl_list_for_each_safe(s, next_s, &config->section_list, link) {
434                 wl_list_for_each_safe(e, next_e, &s->entry_list, link) {
435                         free(e->key);
436                         free(e->value);
437                         free(e);
438                 }
439                 free(s->name);
440                 free(s);
441         }
442
443         free(config);
444 }