configure.ac: Bump version to 1.0.6
[profile/ivi/weston.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 <string.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <assert.h>
27 #include <ctype.h>
28
29 #include "config-parser.h"
30
31 static int
32 handle_key(const struct config_key *key, const char *value)
33 {
34         char *end, *s;
35         int i, len;
36         unsigned int ui;
37         
38         switch (key->type) {
39         case CONFIG_KEY_INTEGER:
40                 i = strtol(value, &end, 0);
41                 if (*end != '\n') {
42                         fprintf(stderr, "invalid integer: %s\n", value);
43                         return -1;
44                 }
45                 *(int *)key->data = i;
46                 return 0;
47
48         case CONFIG_KEY_UNSIGNED_INTEGER:
49                 ui = strtoul(value, &end, 0);
50                 if (*end != '\n') {
51                         fprintf(stderr, "invalid integer: %s\n", value);
52                         return -1;
53                 }
54                 *(unsigned int *)key->data = ui;
55                 return 0;
56
57         case CONFIG_KEY_STRING:
58                 len = strlen(value);
59                 while (len > 0 && isspace(value[len - 1]))
60                         len--;
61                 s = malloc(len + 1);
62                 if (s == NULL)
63                         return -1;
64                 memcpy(s, value, len);
65                 s[len] = '\0';
66                 *(char **)key->data = s;
67                 return 0;
68
69         case CONFIG_KEY_BOOLEAN:
70                 if (strcmp(value, "false\n") == 0)
71                         *(int *)key->data = 0;
72                 else if (strcmp(value, "true\n") == 0)
73                         *(int *)key->data = 1;
74                 else {
75                         fprintf(stderr, "invalid bool: %s\n", value);
76                         return -1;
77                 }
78                 return 0;
79
80         default:
81                 assert(0);
82                 break;
83         }
84
85         return -1;
86 }
87
88 int
89 parse_config_file(const char *path,
90                   const struct config_section *sections, int num_sections,
91                   void *data)
92 {
93         FILE *fp;
94         char line[512], *p;
95         const struct config_section *current = NULL;
96         int i;
97
98         fp = fopen(path, "r");
99         if (fp == NULL) {
100                 fprintf(stderr, "couldn't open %s\n", path);
101                 return -1;
102         }
103
104         while (fgets(line, sizeof line, fp)) {
105                 if (line[0] == '#' || line[0] == '\n') {
106                         continue;
107                 } if (line[0] == '[') {
108                         p = strchr(&line[1], ']');
109                         if (!p || p[1] != '\n') {
110                                 fprintf(stderr, "malformed "
111                                         "section header: %s\n", line);
112                                 fclose(fp);
113                                 return -1;
114                         }
115                         if (current && current->done)
116                                 current->done(data);
117                         p[0] = '\0';
118                         for (i = 0; i < num_sections; i++) {
119                                 if (strcmp(sections[i].name, &line[1]) == 0) {
120                                         current = &sections[i];
121                                         break;
122                                 }
123                         }
124                         if (i == num_sections)
125                                 current = NULL;
126                 } else if (p = strchr(line, '='), p != NULL) {
127                         if (current == NULL)
128                                 continue;
129                         p[0] = '\0';
130                         for (i = 0; i < current->num_keys; i++) {
131                                 if (strcmp(current->keys[i].name, line) == 0) {
132                                         if (handle_key(&current->keys[i], &p[1]) < 0) {
133                                                 fclose(fp);
134                                                 return -1;
135                                         }
136                                         break;
137                                 }
138                         }
139                 } else {
140                         fprintf(stderr, "malformed config line: %s\n", line);
141                         fclose(fp);
142                         return -1;
143                 }
144         }
145
146         if (current && current->done)
147                 current->done(data);
148
149         fclose(fp);
150
151         return 0;
152 }
153
154 char *
155 config_file_path(const char *name)
156 {
157         const char dotconf[] = "/.config/";
158         const char *config_dir;
159         const char *home_dir;
160         char *path;
161         size_t size;
162
163         config_dir = getenv("XDG_CONFIG_HOME");
164         if (!config_dir) {
165                 home_dir = getenv("HOME");
166                 if (!home_dir) {
167                         fprintf(stderr, "HOME is not set, using cwd.\n");
168                         return strdup(name);
169                 }
170
171                 size = strlen(home_dir) + sizeof dotconf + strlen(name);
172                 path = malloc(size);
173                 if (!path)
174                         return NULL;
175
176                 snprintf(path, size, "%s%s%s", home_dir, dotconf, name);
177                 return path;
178         }
179
180         size = strlen(config_dir) + 1 + strlen(name) + 1;
181         path = malloc(size);
182         if (!path)
183                 return NULL;
184
185         snprintf(path, size, "%s/%s", config_dir, name);
186         return path;
187 }