source: trunk/src/ifd/conf.c @ 964

Revision 964, 8.8 KB checked in by aj, 5 years ago (diff)

indent changes only.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 * libifd configuration handling
3 *
4 * Copyright (C) 2003, Olaf Kirch <okir@suse.de>
5 */
6
7#include "internal.h"
8#include <stdlib.h>
9#include <unistd.h>
10#include <fcntl.h>
11#include <string.h>
12#include <stdio.h>
13#include <errno.h>
14#include <ctype.h>
15
16#include <openct/conf.h>
17#include <openct/buffer.h>
18
19struct ct_config ct_config = {
20        0,                      /* debug */
21        1,                      /* autoload */
22        1,                      /* hotplug */
23        0,                      /* suppress_errors */
24        OPENCT_IFDHANDLER_PATH, /* ifdhandler */
25        OPENCT_MODULES_PATH,    /* modules_dir */
26        NULL,                   /* driver_modules_dir */
27        NULL,                   /* protocol_modules_dir */
28        OPENCT_SOCKET_PATH,     /* socket_dir */
29};
30
31#define issepa(c)       (strchr("=;,{}", (c)) != NULL)
32
33enum {
34        GROUP_BEGIN = '{',
35        GROUP_END = '}',
36        COMMA = ',',
37        SEMICOLON = ';',
38        EQUALS = '=',
39        END_OF_FILE = -1
40};
41
42static const char *config_filename = NULL;
43static ct_buf_t config_buf;
44static int config_fd = -1;
45static int config_line = 0;
46static ifd_conf_node_t config_top;
47
48static int conf_parse_group(ifd_conf_node_t *, char);
49static void conf_dump(ifd_conf_node_t *, int);
50static ifd_conf_node_t *conf_add_node(ifd_conf_node_t *, const char *);
51
52static int get_token(char **);
53static int skipws(void);
54static int ateof(void);
55
56/*
57 * Parse the ifd config file
58 */
59int ifd_config_parse(const char *filename)
60{
61        char buffer[512];
62        int rc;
63
64        if ((config_filename = filename) == NULL)
65                config_filename = OPENCT_CONF_PATH;
66
67        /* If config file doesn't exist, quietly sneak out of here */
68        if ((config_fd = open(config_filename, O_RDONLY)) < 0) {
69                if (errno == ENOENT)
70                        return 0;
71                ct_error("Unable to open %s: %m", filename);
72                return -1;
73        }
74
75        /* Init parse buffer. */
76        ct_buf_init(&config_buf, buffer, sizeof(buffer));
77        config_line = 1;
78
79        config_top.name = "<config>";
80        rc = conf_parse_group(&config_top, END_OF_FILE);
81
82        close(config_fd);
83        config_fd = -1;
84
85        if (ct_config.debug > 2)
86                conf_dump(&config_top, 0);
87
88        return rc;
89}
90
91/*
92 * Parse list of statements
93 */
94static int conf_parse_group(ifd_conf_node_t * group, char closing)
95{
96        ifd_conf_node_t *node;
97        char *token;
98        int rc = 0;
99
100        while (1) {
101                if (ateof()) {
102                        if (closing == (char)END_OF_FILE)
103                                break;
104                        ct_error("%s:%u: unexpected end of file",
105                                 config_filename, config_line);
106                        return -1;
107                }
108
109                if ((rc = get_token(&token)) < 0)
110                        break;
111
112                /* Check if this is the closing group character; if
113                 * so, return. No other separators allowed here */
114                if (*token == closing)
115                        break;
116                if (issepa(*token))
117                        goto unexpected;
118
119                node = conf_add_node(group, token);
120
121                if ((rc = get_token(&token)) < 0)
122                        break;
123
124                /* Get the value - the following are valid
125                 *   name = value;
126                 *   name value { ... };
127                 *   name { ... };
128                 *   value, value, ...
129                 */
130                if (*token == EQUALS) {
131                        /* name = value case */
132                        if ((rc = get_token(&token)) < 0)
133                                break;
134                }
135
136                if (!issepa(*token)) {
137                        node->value = strdup(token);
138
139                        /* Get the next token */
140                        if ((rc = get_token(&token)) < 0)
141                                break;
142                } else if (*token == GROUP_BEGIN || *token == COMMA) {
143                        /* Do-nothing cases:
144                         *      name { ... }
145                         *      foo, bar, baz, ...
146                         */
147                } else {
148                        /* everything else illegal here */
149                        goto unexpected;
150                }
151
152                if (*token == GROUP_BEGIN) {
153                        /* Parse the group, then get the next
154                         * token */
155                        if ((rc = conf_parse_group(node, GROUP_END)) < 0
156                            || (rc = get_token(&token)) < 0)
157                                break;
158                }
159
160                if (*token != SEMICOLON && *token != COMMA)
161                        goto unexpected;
162        }
163
164        return rc;
165
166      unexpected:
167        ct_error("%s: line %d: unexpected token \"%s\"",
168                 config_filename, config_line, token);
169        return -1;
170}
171
172/*
173 * Debugging - dump the config tree
174 */
175static void conf_dump(ifd_conf_node_t * node, int indent)
176{
177        for (; node; node = node->next) {
178                printf("%*.*s%s", indent, indent, "", node->name);
179                if (node->value) {
180                        if (!node->children)
181                                printf(" =");
182                        printf(" %s", node->value);
183                }
184                if (node->children) {
185                        printf(" %c\n", GROUP_BEGIN);
186                        conf_dump(node->children, indent + 2);
187                        printf("%*.*s%c", indent, indent, "", GROUP_END);
188                } else {
189                        printf("%c", SEMICOLON);
190                }
191                printf("\n");
192        }
193}
194
195/*
196 * Config node handling
197 */
198static ifd_conf_node_t *conf_add_node(ifd_conf_node_t * parent,
199                                      const char *name)
200{
201        ifd_conf_node_t **p, *node;
202
203        node = (ifd_conf_node_t *) calloc(1, sizeof(*node));
204        if (!node) {
205                ct_error("out of memory");
206                return NULL;
207        }
208        node->name = strdup(name);
209
210        for (p = &parent->children; *p; p = &(*p)->next) ;
211        *p = node;
212
213        return node;
214}
215
216static ifd_conf_node_t *conf_find_node(ifd_conf_node_t * node, const char *name)
217{
218        unsigned int len;
219
220        if (!name)
221                return node;
222        while (*name == '.')
223                name++;
224        if (!*name)
225                return node;
226
227        len = strcspn(name, ".");
228
229        for (node = node->children; node; node = node->next) {
230                if (!strncmp(node->name, name, len)
231                    && node->name[len] == '\0')
232                        return conf_find_node(node, name + len);
233        }
234
235        return NULL;
236}
237
238int ifd_conf_get_string(const char *name, char **result)
239{
240        return ifd_conf_node_get_string(&config_top, name, result);
241}
242
243int ifd_conf_get_bool(const char *name, unsigned int *result)
244{
245        return ifd_conf_node_get_bool(&config_top, name, result);
246}
247
248int ifd_conf_get_integer(const char *name, unsigned int *result)
249{
250        return ifd_conf_node_get_integer(&config_top, name, result);
251}
252
253int ifd_conf_get_string_list(const char *name, char **list, size_t max)
254{
255        return ifd_conf_node_get_string_list(&config_top, name, list, max);
256}
257
258int ifd_conf_get_nodes(const char *name, ifd_conf_node_t ** list, size_t max)
259{
260        return ifd_conf_node_get_nodes(&config_top, name, list, max);
261}
262
263int
264ifd_conf_node_get_string(ifd_conf_node_t * node,
265                         const char *name, char **result)
266{
267        if (!(node = conf_find_node(node, name))
268            || !node->value)
269                return -1;
270
271        *result = node->value;
272        return 0;
273}
274
275int
276ifd_conf_node_get_integer(ifd_conf_node_t * node,
277                          const char *name, unsigned int *result)
278{
279        if (!(node = conf_find_node(node, name))
280            || !node->value)
281                return -1;
282
283        *result = strtoul(node->value, NULL, 0);
284        return 0;
285}
286
287int
288ifd_conf_node_get_bool(ifd_conf_node_t * node,
289                       const char *name, unsigned int *result)
290{
291        const char *v;
292
293        if (!(node = conf_find_node(node, name))
294            || !(v = node->value))
295                return -1;
296
297        if (!strcmp(v, "0")
298            || !strcmp(v, "off")
299            || !strcmp(v, "no")) {
300                *result = 0;
301        } else if (!strcmp(v, "1")
302                   || !strcmp(v, "on")
303                   || !strcmp(v, "yes")) {
304                *result = 1;
305        } else {
306                return -1;
307        }
308
309        return 0;
310}
311
312int
313ifd_conf_node_get_string_list(ifd_conf_node_t * node,
314                              const char *name, char **list, size_t max)
315{
316        unsigned int j = 0;
317
318        if (!(node = conf_find_node(node, name)))
319                return -1;
320
321        for (node = node->children; node; node = node->next) {
322                if (list && j < max)
323                        list[j] = node->name;
324                j += 1;
325        }
326
327        return j;
328}
329
330int
331ifd_conf_node_get_nodes(ifd_conf_node_t * node,
332                        const char *name, ifd_conf_node_t ** list, size_t max)
333{
334        unsigned int j = 0;
335
336        for (node = node->children; node; node = node->next) {
337                if (strcmp(node->name, name))
338                        continue;
339                if (list && j < max)
340                        list[j] = node;
341                j += 1;
342        }
343
344        return j;
345}
346
347/*
348 * Tokenizer
349 */
350static int get_token(char **tok)
351{
352        static char buffer[512];
353        unsigned int m, n, copy, retry = 1;
354        char *s;
355
356        /* consume initial white space */
357        if (skipws() < 0)
358                return -1;
359
360      again:
361        s = (char *)ct_buf_head(&config_buf);
362        n = ct_buf_avail(&config_buf);
363
364        if (n && issepa(*s)) {
365                m = 1;
366        } else {
367                for (m = 0; !isspace((int)s[m]) && !issepa(s[m]) && m < n;
368                     m++) ;
369        }
370
371        /* If we hit the end of the buffer while scanning
372         * for white space, read more data and try
373         * again */
374        if (m >= n && retry) {
375                if (ct_buf_read(&config_buf, config_fd) < 0) {
376                        ct_error("%s: error while reading file: %m",
377                                 config_filename);
378                        return -1;
379                }
380                retry = 0;
381                goto again;
382        }
383
384        if (m == 0)
385                return -1;
386
387        if ((copy = m) >= sizeof(buffer))
388                copy = sizeof(buffer) - 1;
389        memcpy(buffer, s, copy);
390        buffer[copy] = '\0';
391        ct_buf_get(&config_buf, NULL, m);
392
393        ifd_debug(5, "ifd_config_parse: token=\"%s\"", buffer);
394
395        *tok = buffer;
396        return 0;
397}
398
399/*
400 * Check if we're at the end of the file
401 */
402static int ateof(void)
403{
404        int retry = 1;
405
406      again:
407        if (skipws() < 0)
408                return -1;
409
410        if (ct_buf_avail(&config_buf) == 0) {
411                if (!retry)
412                        return 1;
413
414                if (ct_buf_read(&config_buf, config_fd) < 0) {
415                        ct_error("%s: error while reading file: %m",
416                                 config_filename);
417                        return -1;
418                }
419                retry = 0;
420                goto again;
421        }
422
423        return 0;
424}
425
426/*
427 * Eat initial white space from buffer
428 */
429static int skipws(void)
430{
431        unsigned int m, n, in_comment = 0;
432        char *s;
433
434      again:
435        s = (char *)ct_buf_head(&config_buf);
436        n = ct_buf_avail(&config_buf);
437
438        for (m = 0; m < n; m++, s++) {
439                if (*s == '#') {
440                        in_comment = 1;
441                } else if (!in_comment && !isspace((int)*s)) {
442                        break;
443                } else if (*s == '\n') {
444                        config_line++;
445                        in_comment = 0;
446                }
447        }
448
449        ct_buf_get(&config_buf, NULL, m);
450        if (in_comment) {
451                if (ct_buf_read(&config_buf, config_fd) < 0) {
452                        ct_error("%s: error while reading file: %m",
453                                 config_filename);
454                        return -1;
455                }
456                goto again;
457        }
458
459        return 0;
460}
Note: See TracBrowser for help on using the repository browser.