common, tests, resourced-dbus, utils: Apply Tizen coding rule
[platform/core/system/resourced.git] / src / common / config-parser.c
1 /*
2  * resourced
3  *
4  * Copyright (c) 2013 Samsung Electronics Co., Ltd.
5  *
6  * Licensed under the Apache License, Version 2.0 (the License);
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 #include <stdio.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <assert.h>
23 #include <limits.h>
24
25 #include "util.h"
26 #include "trace.h"
27 #include "config-parser.h"
28
29 #define MAX_SECTION     64
30
31 static inline char *trim_str(char *s)
32 {
33         char *t;
34         /* left trim */
35         s += strspn(s, WHITESPACE);
36
37         /* right trim */
38         for (t = strchr(s, 0); t > s; t--)
39                 if (!strchr(WHITESPACE, t[-1]))
40                         break;
41         *t = 0;
42         return s;
43 }
44
45 int config_parse(const char *file_name, int cb(struct parse_result *result,
46                         void *user_data), void *user_data)
47 {
48         FILE *f = NULL;
49         struct parse_result result;
50         /* use stack for parsing */
51         char line[LINE_MAX];
52         char section[MAX_SECTION];
53         char *start, *end, *name, *value;
54         int lineno = 0, ret = 0;
55
56         if (!file_name || !cb) {
57                 ret = -EINVAL;
58                 goto error;
59         }
60
61         /* open conf file */
62         f = fopen(file_name, "r");
63         if (!f) {
64                 _E("Failed to open file %s", file_name);
65                 ret = -EIO;
66                 goto error;
67         }
68
69         /* parsing line by line */
70         while (fgets(line, LINE_MAX, f) != NULL) {
71                 lineno++;
72
73                 start = line;
74                 start[strcspn(start, NEWLINE)] = '\0';
75                 start = trim_str(start);
76
77                 if (*start == COMMENT) {
78                         continue;
79                 } else if (*start == '[') {
80                         /* parse section */
81                         end = strchr(start, ']');
82                         if (!end || *end != ']') {
83                                 ret = -EBADMSG;
84                                 goto error;
85                         }
86
87                         *end = '\0';
88                         strncpy(section, start + 1, sizeof(section)-1);
89                         section[MAX_SECTION-1] = '\0';
90                 } else if (*start) {
91                         /* parse name & value */
92                         end = strchr(start, '=');
93                         if (!end || *end != '=') {
94                                 ret = -EBADMSG;
95                                 goto error;
96                         }
97                         *end = '\0';
98                         name = trim_str(start);
99                         value = trim_str(end + 1);
100                         end = strchr(value, COMMENT);
101                         if (end && *end == COMMENT) {
102                                 *end = '\0';
103                                 value = trim_str(value);
104                         }
105
106                         result.section = section;
107                         result.name = name;
108                         result.value = value;
109                         /* callback with parse result */
110                         ret = cb(&result, user_data);
111                         if (ret < 0) {
112                                 ret = -EBADMSG;
113                                 goto error;
114                         }
115                 }
116         }
117         _D("Success to load %s", file_name);
118         fclose(f);
119         return 0;
120
121 error:
122         if (f)
123                 fclose(f);
124         _E("Failed to read %s:%d!", file_name, lineno);
125         return ret;
126 }
127
128 static int config_table_lookup(void *table,
129                                const char *section,
130                                const char *lvalue,
131                                ConfigParserCallback *func,
132                                int *ltype,
133                                void **data)
134 {
135         ConfigTableItem *t;
136
137         assert(table);
138         assert(lvalue);
139         assert(func);
140         assert(ltype);
141         assert(data);
142
143         for (t = table; t->lvalue; t++) {
144
145                 if (!streq(lvalue, t->lvalue))
146                         continue;
147
148                 if (!streq_ptr(section, t->section))
149                         continue;
150
151                 *func = t->cb;
152                 *ltype = t->ltype;
153                 *data = t->data;
154                 return 1;
155         }
156
157         return 0;
158 }
159
160 /* Run the user supplied parser for an assignment */
161 static int config_parse_table(const char *filename,
162                               unsigned line,
163                               void *table,
164                               const char *section,
165                               const char *lvalue,
166                               const char *rvalue)
167 {
168         ConfigParserCallback cb = NULL;
169         int ltype = 0;
170         void *data = NULL;
171         int r;
172
173         assert(filename);
174         assert(section);
175         assert(lvalue);
176         assert(rvalue);
177
178         r = config_table_lookup(table,
179                                 section,
180                                 lvalue,
181                                 &cb,
182                                 &ltype,
183                                 &data);
184         if (r <= 0)
185                 return r;
186
187         if (cb)
188                 return cb(filename,
189                           line,
190                           section,
191                           lvalue,
192                           ltype,
193                           rvalue,
194                           data);
195
196         return 0;
197 }
198
199 int config_parse_new(const char *filename, void *table)
200 {
201         _cleanup_fclose_ FILE *f = NULL;
202         char *sections[MAX_SECTION] = { 0 };
203         char *section = NULL, *n, *e, l[LINE_MAX];
204         size_t len;
205         int i, r, num_section = 0;
206         bool already;
207         unsigned line = 0;
208
209         assert(filename);
210
211         f = fopen(filename, "r");
212         if (!f) {
213                 _E("Failed to open file %s", filename);
214                 return -errno;
215         }
216
217         while (!feof(f)) {
218                 _cleanup_free_ char *lvalue = NULL, *rvalue = NULL;
219                 char *rs = NULL;
220
221                 if (fgets(l, LINE_MAX, f) == NULL) {
222                         if (feof(f))
223                                 break;
224
225                         _E("Failed to parse configuration file '%s': %m", filename);
226                         r = -errno;
227                         goto finish;
228                 }
229
230                 line++;
231                 truncate_nl(l);
232
233                 if (strchr(COMMENTS NEWLINE, *l))
234                         continue;
235
236                 if (*l == '[') {
237                         len = strlen(l);
238                         if (l[len-1] != ']') {
239                                 _E("Error: Invalid section header: %s", l);
240                                 r = -EBADMSG;
241                                 goto finish;
242                         }
243
244                         n = strndup(l+1, len-2);
245                         if (!n) {
246                                 r = -ENOMEM;
247                                 goto finish;
248                         }
249
250                         already = false;
251                         for (i = 0; i < num_section; i++) {
252                                 if (streq(n, sections[i])) {
253                                         section = sections[i];
254                                         already = true;
255                                         free(n);
256                                         break;
257                                 }
258                         }
259
260                         if (already)
261                                 continue;
262
263                         section = n;
264                         sections[num_section] = n;
265                         num_section++;
266                         if (num_section > MAX_SECTION) {
267                                 _E("Error: max number of section reached: %d", num_section);
268                                 r = -EOVERFLOW;
269                                 goto finish;
270                         }
271
272                         continue;
273                 }
274
275                 if (!section)
276                         continue;
277
278                 e = strchr(l, '=');
279                 if (e == NULL) {
280                         _D("Warning: config: no '=' character in line '%s'.", l);
281                         continue;
282                 }
283
284                 lvalue = strndup(l, e-l);
285                 strstrip(lvalue);
286
287                 rs = strstrip(e+1);
288                 rvalue = strndup(rs, strlen(rs));
289                 strstrip(rvalue);
290
291                 r = config_parse_table(filename,
292                                        line,
293                                        table,
294                                        section,
295                                        lvalue,
296                                        rvalue);
297                 if (r < 0)
298                         goto finish;
299         }
300
301         r = 0;
302
303 finish:
304         for (i = 0; i < num_section; i++)
305                 if (sections[i])
306                         free(sections[i]);
307
308         return r;
309 }
310
311 int config_parse_dir(const char *dir, ConfigParseFunc fp, void *data)
312 {
313         _cleanup_closedir_ DIR *d = NULL;
314         struct dirent de;
315         struct dirent *result;
316
317         d = opendir(dir);
318         if (!d) {
319                 _E("Failed to open dir: %s", dir);
320                 return errno;
321         }
322
323         FOREACH_DIRENT(de, d, result, return -errno) {
324                 _cleanup_free_ char *path = NULL;
325                 int r;
326
327                 if (de.d_type != DT_REG)
328                         continue;
329
330                 r = asprintf(&path, "%s/%s", dir, de.d_name);
331                 if (r < 0)
332                         return -ENOMEM;
333
334                 r = fp(path, data);
335                 /* Do not just break loop until parse all file of
336                  * dir. Just only put log */
337                 if (r < 0)
338                         _D("Failed to parse config: %s", de.d_name);
339         }
340
341         return 0;
342 }
343
344 int config_parse_bool(const char *filename,
345                       unsigned line,
346                       const char *section,
347                       const char *lvalue,
348                       int ltype,
349                       const char *rvalue,
350                       void *data)
351 {
352         int k;
353         bool *b = data;
354
355         assert(filename);
356         assert(lvalue);
357         assert(rvalue);
358         assert(data);
359
360         k = parse_boolean(rvalue);
361         if (k < 0) {
362                 _E("Failed to parse boolean value, ignoring: %s", rvalue);
363                 return 0;
364         }
365
366         *b = !!k;
367
368         return 0;
369 }
370
371
372 int config_parse_int(const char *filename,
373                      unsigned line,
374                      const char *section,
375                      const char *lvalue,
376                      int ltype,
377                      const char *rvalue,
378                      void *data)
379 {
380         int *i = data;
381
382         assert(filename);
383         assert(lvalue);
384         assert(rvalue);
385         assert(data);
386
387         *i = atoi(rvalue);
388
389         return 0;
390 }
391
392 int config_parse_string(const char *filename,
393                         unsigned line,
394                         const char *section,
395                         const char *lvalue,
396                         int ltype,
397                         const char *rvalue,
398                         void *data)
399 {
400         char **s = data, *n;
401
402         assert(filename);
403         assert(lvalue);
404         assert(rvalue);
405         assert(data);
406
407         if (is_empty(rvalue))
408                 n = NULL;
409         else {
410                 n = strndup(rvalue, strlen(rvalue));
411                 if (!n)
412                         return -ENOMEM;
413         }
414
415         free(*s);
416         *s = n;
417
418         return 0;
419 }
420
421 int config_parse_bytes(const char *filename,
422                        unsigned line,
423                        const char *section,
424                        const char *lvalue,
425                        int ltype,
426                        const char *rvalue,
427                        void *data)
428 {
429         size_t *s = data;
430         int r;
431
432         assert(filename);
433         assert(lvalue);
434         assert(rvalue);
435         assert(data);
436
437         if (is_empty(rvalue))
438                 *s = 0;
439         else {
440                 r = parse_bytes(rvalue, s);
441                 if (r < 0)
442                         return r;
443         }
444
445         return 0;
446 }
447
448 int config_parse_strv(const char *filename,
449                       unsigned line,
450                       const char *section,
451                       const char *lvalue,
452                       int ltype,
453                       const char *rvalue,
454                       void *data)
455 {
456         char ***strv = data;
457         char **o = NULL, **v = NULL, **vv = NULL;
458         int r;
459
460         assert(filename);
461         assert(lvalue);
462         assert(rvalue);
463         assert(data);
464
465         if (is_empty(rvalue))
466                 return 0;
467
468         r = str_to_strv(rvalue, &v, WHITESPACE);
469         if (r < 0)
470                 return r;
471
472         o = *strv;
473
474         r = strv_attach(o, v, &vv, true);
475         if (r < 0)
476                 return r;
477
478         *strv = vv;
479
480         return 0;
481 }