blob: 1cee946bcbcf79ff1f494039749f924c974f6d3d [file] [log] [blame]
Kristian Høgsbergac3a59a2011-11-14 22:43:37 -05001/*
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
Daniel Stonec228e232013-05-22 18:03:19 +030023#include "config.h"
24
Kristian Høgsbergac3a59a2011-11-14 22:43:37 -050025#include <string.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <assert.h>
Kristian Høgsberg3d890492012-08-03 21:56:41 -040029#include <ctype.h>
Ossama Othmana50e6e42013-05-14 09:48:26 -070030#include <limits.h>
31#include <sys/types.h>
32#include <sys/stat.h>
33#include <fcntl.h>
34#include <unistd.h>
Kristian Høgsberg73274712013-04-01 12:41:23 -040035#include <errno.h>
Kristian Høgsbergac3a59a2011-11-14 22:43:37 -050036
Kristian Høgsberg73274712013-04-01 12:41:23 -040037#include <wayland-util.h>
Kristian Høgsberg9b935c82011-12-08 12:44:27 -050038#include "config-parser.h"
Kristian Høgsbergac3a59a2011-11-14 22:43:37 -050039
Kristian Høgsbergf73f3162013-05-26 20:50:53 -040040#define container_of(ptr, type, member) ({ \
41 const __typeof__( ((type *)0)->member ) *__mptr = (ptr); \
42 (type *)( (char *)__mptr - offsetof(type,member) );})
43
Kristian Høgsberg1abe0482013-09-21 23:02:31 -070044static int
Ossama Othmana50e6e42013-05-14 09:48:26 -070045open_config_file(const char *name)
Pekka Paalanen668dd562011-11-15 11:45:40 +020046{
Ossama Othmana50e6e42013-05-14 09:48:26 -070047 const char *config_dir = getenv("XDG_CONFIG_HOME");
48 const char *home_dir = getenv("HOME");
49 const char *config_dirs = getenv("XDG_CONFIG_DIRS");
50 char path[PATH_MAX];
51 const char *p, *next;
52 int fd;
Pekka Paalanen668dd562011-11-15 11:45:40 +020053
Kristian Høgsberg1abe0482013-09-21 23:02:31 -070054 if (name[0] == '/')
55 return open(name, O_RDONLY | O_CLOEXEC);
56
Ossama Othmana50e6e42013-05-14 09:48:26 -070057 /* Precedence is given to config files in the home directory,
58 * and then to directories listed in XDG_CONFIG_DIRS and
59 * finally to the current working directory. */
Pekka Paalanen668dd562011-11-15 11:45:40 +020060
Ossama Othmana50e6e42013-05-14 09:48:26 -070061 /* $XDG_CONFIG_HOME */
62 if (config_dir) {
63 snprintf(path, sizeof path, "%s/%s", config_dir, name);
64 fd = open(path, O_RDONLY | O_CLOEXEC);
65 if (fd >= 0)
66 return fd;
Pekka Paalanen668dd562011-11-15 11:45:40 +020067 }
68
Ossama Othmana50e6e42013-05-14 09:48:26 -070069 /* $HOME/.config */
70 if (home_dir) {
71 snprintf(path, sizeof path, "%s/.config/%s", home_dir, name);
72 fd = open(path, O_RDONLY | O_CLOEXEC);
73 if (fd >= 0)
74 return fd;
75 }
Pekka Paalanen668dd562011-11-15 11:45:40 +020076
Ossama Othmana50e6e42013-05-14 09:48:26 -070077 /* For each $XDG_CONFIG_DIRS: weston/<config_file> */
78 if (!config_dirs)
79 config_dirs = "/etc/xdg"; /* See XDG base dir spec. */
80
81 for (p = config_dirs; *p != '\0'; p = next) {
82 next = strchrnul(p, ':');
83 snprintf(path, sizeof path,
84 "%.*s/weston/%s", (int)(next - p), p, name);
85 fd = open(path, O_RDONLY | O_CLOEXEC);
86 if (fd >= 0)
87 return fd;
88
89 if (*next == ':')
90 next++;
91 }
92
93 /* Current working directory. */
94 snprintf(path, sizeof path, "./%s", name);
95 fd = open(path, O_RDONLY | O_CLOEXEC);
96
97 if (fd >= 0)
98 fprintf(stderr,
99 "using config in current working directory: %s\n",
100 path);
101 else
102 fprintf(stderr, "config file \"%s\" not found.\n", name);
103
104 return fd;
Pekka Paalanen668dd562011-11-15 11:45:40 +0200105}
Kristian Høgsberg73274712013-04-01 12:41:23 -0400106
107struct weston_config_entry {
108 char *key;
109 char *value;
110 struct wl_list link;
111};
112
113struct weston_config_section {
114 char *name;
115 struct wl_list entry_list;
116 struct wl_list link;
117};
118
119struct weston_config {
120 struct wl_list section_list;
121};
122
123static struct weston_config_entry *
124config_section_get_entry(struct weston_config_section *section,
125 const char *key)
126{
127 struct weston_config_entry *e;
128
129 if (section == NULL)
130 return NULL;
131 wl_list_for_each(e, &section->entry_list, link)
132 if (strcmp(e->key, key) == 0)
133 return e;
134
135 return NULL;
136}
137
Quentin Glidic6e2c1242013-07-01 17:03:08 +0200138WL_EXPORT
Kristian Høgsberg73274712013-04-01 12:41:23 -0400139struct weston_config_section *
140weston_config_get_section(struct weston_config *config, const char *section,
141 const char *key, const char *value)
142{
143 struct weston_config_section *s;
144 struct weston_config_entry *e;
145
Mun Gwan-gyeong72a3ab72013-05-25 02:09:13 +0900146 if (config == NULL)
147 return NULL;
Kristian Høgsberg73274712013-04-01 12:41:23 -0400148 wl_list_for_each(s, &config->section_list, link) {
149 if (strcmp(s->name, section) != 0)
150 continue;
151 if (key == NULL)
152 return s;
153 e = config_section_get_entry(s, key);
154 if (e && strcmp(e->value, value) == 0)
155 return s;
156 }
157
158 return NULL;
159}
160
Quentin Glidic6e2c1242013-07-01 17:03:08 +0200161WL_EXPORT
Kristian Høgsberg73274712013-04-01 12:41:23 -0400162int
163weston_config_section_get_int(struct weston_config_section *section,
164 const char *key,
165 int32_t *value, int32_t default_value)
166{
167 struct weston_config_entry *entry;
168 char *end;
169
170 entry = config_section_get_entry(section, key);
171 if (entry == NULL) {
172 *value = default_value;
173 errno = ENOENT;
174 return -1;
175 }
176
177 *value = strtol(entry->value, &end, 0);
178 if (*end != '\0') {
179 *value = default_value;
180 errno = EINVAL;
181 return -1;
182 }
183
184 return 0;
185}
186
Quentin Glidic6e2c1242013-07-01 17:03:08 +0200187WL_EXPORT
Kristian Høgsberg73274712013-04-01 12:41:23 -0400188int
189weston_config_section_get_uint(struct weston_config_section *section,
190 const char *key,
191 uint32_t *value, uint32_t default_value)
192{
193 struct weston_config_entry *entry;
194 char *end;
195
196 entry = config_section_get_entry(section, key);
197 if (entry == NULL) {
198 *value = default_value;
199 errno = ENOENT;
200 return -1;
201 }
202
203 *value = strtoul(entry->value, &end, 0);
204 if (*end != '\0') {
205 *value = default_value;
206 errno = EINVAL;
207 return -1;
208 }
209
210 return 0;
211}
212
Quentin Glidic6e2c1242013-07-01 17:03:08 +0200213WL_EXPORT
Kristian Høgsberg73274712013-04-01 12:41:23 -0400214int
Armin Kb502f902013-07-31 01:41:03 +0200215weston_config_section_get_double(struct weston_config_section *section,
216 const char *key,
217 double *value, double default_value)
218{
219 struct weston_config_entry *entry;
220 char *end;
221
222 entry = config_section_get_entry(section, key);
223 if (entry == NULL) {
224 *value = default_value;
225 errno = ENOENT;
226 return -1;
227 }
228
229 *value = strtod(entry->value, &end);
230 if (*end != '\0') {
231 *value = default_value;
232 errno = EINVAL;
233 return -1;
234 }
235
236 return 0;
237}
238
239WL_EXPORT
240int
Kristian Høgsberg73274712013-04-01 12:41:23 -0400241weston_config_section_get_string(struct weston_config_section *section,
242 const char *key,
243 char **value, const char *default_value)
244{
245 struct weston_config_entry *entry;
246
247 entry = config_section_get_entry(section, key);
248 if (entry == NULL) {
249 if (default_value)
250 *value = strdup(default_value);
251 else
252 *value = NULL;
253 errno = ENOENT;
254 return -1;
255 }
256
257 *value = strdup(entry->value);
258
259 return 0;
260}
261
Quentin Glidic6e2c1242013-07-01 17:03:08 +0200262WL_EXPORT
Kristian Høgsberg73274712013-04-01 12:41:23 -0400263int
264weston_config_section_get_bool(struct weston_config_section *section,
265 const char *key,
266 int *value, int default_value)
267{
268 struct weston_config_entry *entry;
269
270 entry = config_section_get_entry(section, key);
271 if (entry == NULL) {
272 *value = default_value;
273 errno = ENOENT;
274 return -1;
275 }
276
277 if (strcmp(entry->value, "false") == 0)
278 *value = 0;
279 else if (strcmp(entry->value, "true") == 0)
280 *value = 1;
281 else {
282 *value = default_value;
283 errno = EINVAL;
284 return -1;
285 }
286
287 return 0;
288}
289
290static struct weston_config_section *
291config_add_section(struct weston_config *config, const char *name)
292{
293 struct weston_config_section *section;
294
295 section = malloc(sizeof *section);
296 section->name = strdup(name);
297 wl_list_init(&section->entry_list);
298 wl_list_insert(config->section_list.prev, &section->link);
299
300 return section;
301}
302
303static struct weston_config_entry *
304section_add_entry(struct weston_config_section *section,
305 const char *key, const char *value)
306{
307 struct weston_config_entry *entry;
308
309 entry = malloc(sizeof *entry);
310 entry->key = strdup(key);
311 entry->value = strdup(value);
312 wl_list_insert(section->entry_list.prev, &entry->link);
313
314 return entry;
315}
316
317struct weston_config *
Kristian Høgsberg1abe0482013-09-21 23:02:31 -0700318weston_config_parse(const char *name)
Kristian Høgsberg73274712013-04-01 12:41:23 -0400319{
320 FILE *fp;
321 char line[512], *p;
322 struct weston_config *config;
323 struct weston_config_section *section = NULL;
Kristian Høgsberg1abe0482013-09-21 23:02:31 -0700324 int i, fd;
Kristian Høgsberg73274712013-04-01 12:41:23 -0400325
326 config = malloc(sizeof *config);
327 if (config == NULL)
328 return NULL;
329
330 wl_list_init(&config->section_list);
331
Kristian Høgsberg1abe0482013-09-21 23:02:31 -0700332 fd = open_config_file(name);
333 if (fd == -1) {
Kristian Høgsberg73274712013-04-01 12:41:23 -0400334 free(config);
335 return NULL;
336 }
337
Kristian Høgsberg1abe0482013-09-21 23:02:31 -0700338 fp = fdopen(fd, "r");
339 if (fp == NULL) {
340 free(config);
341 return NULL;
342 }
Kristian Høgsberg73274712013-04-01 12:41:23 -0400343
344 while (fgets(line, sizeof line, fp)) {
345 switch (line[0]) {
346 case '#':
347 case '\n':
348 continue;
349 case '[':
350 p = strchr(&line[1], ']');
351 if (!p || p[1] != '\n') {
352 fprintf(stderr, "malformed "
353 "section header: %s\n", line);
354 fclose(fp);
355 weston_config_destroy(config);
356 return NULL;
357 }
358 p[0] = '\0';
359 section = config_add_section(config, &line[1]);
360 continue;
361 default:
362 p = strchr(line, '=');
363 if (!p || p == line || !section) {
364 fprintf(stderr, "malformed "
365 "config line: %s\n", line);
366 fclose(fp);
367 weston_config_destroy(config);
368 return NULL;
369 }
370
371 p[0] = '\0';
372 p++;
373 while (isspace(*p))
374 p++;
375 i = strlen(p);
376 while (i > 0 && isspace(p[i - 1])) {
377 p[i - 1] = '\0';
378 i--;
379 }
380 section_add_entry(section, line, p);
381 continue;
382 }
383 }
384
385 fclose(fp);
386
387 return config;
388}
389
Kristian Høgsbergf73f3162013-05-26 20:50:53 -0400390int
391weston_config_next_section(struct weston_config *config,
392 struct weston_config_section **section,
393 const char **name)
394{
Mun Gwan-gyeong151a5282013-05-28 00:04:26 +0900395 if (config == NULL)
396 return 0;
397
Kristian Høgsbergf73f3162013-05-26 20:50:53 -0400398 if (*section == NULL)
399 *section = container_of(config->section_list.next,
400 struct weston_config_section, link);
401 else
402 *section = container_of((*section)->link.next,
403 struct weston_config_section, link);
404
405 if (&(*section)->link == &config->section_list)
406 return 0;
407
408 *name = (*section)->name;
409
410 return 1;
411}
412
Kristian Høgsberg73274712013-04-01 12:41:23 -0400413void
414weston_config_destroy(struct weston_config *config)
415{
416 struct weston_config_section *s, *next_s;
417 struct weston_config_entry *e, *next_e;
418
Mun Gwan-gyeong77325402013-05-28 00:20:04 +0900419 if (config == NULL)
420 return;
421
Kristian Høgsberg73274712013-04-01 12:41:23 -0400422 wl_list_for_each_safe(s, next_s, &config->section_list, link) {
423 wl_list_for_each_safe(e, next_e, &s->entry_list, link) {
424 free(e->key);
425 free(e->value);
426 free(e);
427 }
428 free(s->name);
429 free(s);
430 }
431
432 free(config);
433}