From 7c52a3cf5243b42b632fd73789d1b484e81b9b0c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 22 Aug 2013 15:07:48 +0100 Subject: overlay: Rudiments of config files and option parsing Signed-off-by: Chris Wilson --- overlay/config.c | 282 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 282 insertions(+) create mode 100644 overlay/config.c (limited to 'overlay/config.c') diff --git a/overlay/config.c b/overlay/config.c new file mode 100644 index 00000000..f0f7ce8b --- /dev/null +++ b/overlay/config.c @@ -0,0 +1,282 @@ +/* + * Copyright © 2013 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "overlay.h" + +#define DEFAULT_SECTION "window" + +static const char *skip_whitespace(const char *s, const char *end) +{ + while (s < end && isspace(*s)) + s++; + return s; +} + +static const char *trim_whitespace(const char *s, const char *end) +{ + if (end == NULL) + return end; + + while (end > s && isspace(*--end)) + ; + + return end + 1; +} + +static const char *skip_past_newline(const char *s, const char *end) +{ + while (s < end && *s++ != '\n') + ; + + return s; +} + +static const char *find(const char *s, const char *end, int c) +{ + while (s < end && *s != c) { + if (*s == '#') + break; + + if (*s == '\n') + return NULL; + s++; + } + + return s; +} + +static int parse(const char *buf, int len, + int (*func)(const char *section, + const char *name, + const char *value, + void *data), + void *data) +{ + char section[128] = DEFAULT_SECTION, name[128], value[128]; + const char *buf_end = buf + len; + const char *end; + int line = 0; + + for (line = 0 ; ++line; buf = skip_past_newline(buf, buf_end)) { + ++line; + buf = skip_whitespace(buf, buf_end); + if (buf >= buf_end) + break; + + if (*buf == ';' || *buf == '#') { + /* comment */ + } else if (*buf == '[') { /* new section */ + end = find(++buf, buf_end, ']'); + end = trim_whitespace(buf, end); + if (end <= buf) + continue; + + len = end - buf; + if (len == 0 || len >= sizeof(section)) + return line; + + memcpy(section, buf, len); + section[len] = '\0'; + } else { /* name = value */ + const char *sep; + int has_value = 1; + + sep = find(buf, buf_end, '='); + if (sep == NULL) + sep = find(buf, buf_end, ':'); + if (sep == NULL) { + sep = find(buf, buf_end, '\n'); + has_value = 0; + } + end = trim_whitespace(buf, sep); + if (end <= buf) + continue; + + len = end - buf; + if (len == 0 || len >= sizeof(name)) + return line; + + memcpy(name, buf, len); + name[len] = '\0'; + + if (has_value) { + buf = skip_whitespace(sep + 1, buf_end); + end = find(buf, buf_end, '\n'); + end = trim_whitespace(buf, end); + + len = end - buf; + if (len >= sizeof(name)) + return line; + + memcpy(value, buf, len); + value[len] = '\0'; + } else + value[0] = '\0'; + + if (!func(section, name, value, data)) + return line; + } + } + + return 0; +} + +static int add_value(const char *section, + const char *name, + const char *value, + void *data) +{ + struct config *c = data; + struct config_section *s; + struct config_value *v, **prev; + + for (s = c->sections; s != NULL; s = s->next) + if (strcmp(s->name, section) == 0) + break; + if (s == NULL) { + int len = strlen(section) + 1; + + s = malloc(sizeof(*s)+len); + if (s == NULL) + return 0; + + memcpy(s->name, section, len); + s->next = c->sections; + c->sections = s; + } + + for (prev = &s->values; (v = *prev) != NULL; prev = &v->next) { + if (strcmp(v->name, name) == 0) { + *prev = v->next; + free(v); + break; + } + } + { + int name_len = strlen(name) + 1; + int value_len = *value ? strlen(value) + 1 : 0; + + v = malloc(sizeof(*v) + name_len + value_len); + if (v == NULL) + return 0; + + v->name = memcpy(v+1, name, name_len); + + if (*value) + v->value = memcpy(v->name + name_len, value, value_len); + else + v->value = NULL; + + v->next = s->values; + s->values = v; + } + + return 1; +} + +static int config_init_from_file(struct config *config, const char *filename) +{ + struct stat st; + int fd, err = -1; + char *str; + + fd = open(filename, 0); + if (fd < 0) + return -1; + + if (fstat(fd, &st) < 0) + goto err_fd; + + if ((str = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == (void *)-1) + goto err_fd; + + err = parse(str, st.st_size, add_value, config); + munmap(str, st.st_size); + +err_fd: + close(fd); + return err; +} + +void config_init(struct config *config) +{ + memset(config, 0, sizeof(*config)); +} + +void config_parse_string(struct config *config, const char *str) +{ + int err; + + if (str == NULL) + return; + + err = config_init_from_file(config, str); + if (err == -1) + err = parse(str, strlen(str), add_value, config); + if (err) { + fprintf(stderr, "Failed to parse config string at line %d\n", err); + exit(1); + } +} + +void config_set_value(struct config *c, + const char *section, + const char *name, + const char *value) +{ + add_value(section, name, value, c); +} + +const char *config_get_value(struct config *c, + const char *section, + const char *name) +{ + struct config_section *s; + struct config_value *v; + + for (s = c->sections; s != NULL; s = s->next) { + if (strcmp(s->name, section)) + continue; + + for (v = s->values; v != NULL; v = v->next) { + if (strcmp(v->name, name)) + continue; + + return v->value; + } + } + + return NULL; +} -- cgit v1.2.3