diff options
author | David Oberhollenzer <david.oberhollenzer@tele2.at> | 2018-10-10 11:28:46 +0200 |
---|---|---|
committer | David Oberhollenzer <david.oberhollenzer@tele2.at> | 2018-10-10 16:45:11 +0200 |
commit | 24c90b7700e18d0668799f8f343bc854a42dea20 (patch) | |
tree | 224d9b5e81a46e27f354c6975fc3fa4cd1f1fb79 /lib/libcfg | |
parent | 7b647eefef00afb6104e84fae2a2fbf0481d4364 (diff) |
Configuration parser cleanup
- Do a getline() & process in rdline instead of doing a read per character
and feeding it through a state machine.
- Move splitkv to rdcfg.c, the only place where it is used
Signed-off-by: David Oberhollenzer <david.oberhollenzer@tele2.at>
Diffstat (limited to 'lib/libcfg')
-rw-r--r-- | lib/libcfg/rdcfg.c | 32 | ||||
-rw-r--r-- | lib/libcfg/rdline.c | 227 | ||||
-rw-r--r-- | lib/libcfg/splitkv.c | 48 |
3 files changed, 140 insertions, 167 deletions
diff --git a/lib/libcfg/rdcfg.c b/lib/libcfg/rdcfg.c index 71a994f..ccbcf7b 100644 --- a/lib/libcfg/rdcfg.c +++ b/lib/libcfg/rdcfg.c @@ -19,6 +19,7 @@ #include <string.h> #include <stdio.h> +#include <ctype.h> static const cfg_param_t *find_param(rdline_t *rd, const char *name, const cfg_param_t *params, size_t count) @@ -35,6 +36,33 @@ static const cfg_param_t *find_param(rdline_t *rd, const char *name, return NULL; } +static int splitkv(rdline_t *rd, char **k, char **v) +{ + char *key = rd->line, *value = rd->line; + + while (*value != ' ' && *value != '\0') { + if (!isalpha(*value)) { + fprintf(stderr, + "%s: %zu: unexpected '%c' in keyword\n", + rd->filename, rd->lineno, *value); + return -1; + } + ++value; + } + + if (*value != ' ') { + fprintf(stderr, "%s: %zu: expected argument after '%s'\n", + rd->filename, rd->lineno, key); + return -1; + } + + *(value++) = '\0'; + + *k = key; + *v = value; + return 0; +} + int rdcfg(void *cfgobj, rdline_t *rd, const cfg_param_t *params, size_t count, int flags) { @@ -61,9 +89,9 @@ int rdcfg(void *cfgobj, rdline_t *rd, const cfg_param_t *params, size_t count, } while ((ret = rdline(rd)) == 0) { - if (strcmp(rd->buffer, "}") == 0) + if (strcmp(rd->line, "}") == 0) break; - if (p->handle(cfgobj, rd->buffer, rd, flags)) + if (p->handle(cfgobj, rd->line, rd, flags)) return -1; } diff --git a/lib/libcfg/rdline.c b/lib/libcfg/rdline.c index ffbfd89..16ca5cf 100644 --- a/lib/libcfg/rdline.c +++ b/lib/libcfg/rdline.c @@ -24,151 +24,144 @@ #include "libcfg.h" -static int rdline_getc(rdline_t *t) +void rdline_init(rdline_t *t, int fd, const char *filename, + int argc, const char *const *argv) { - int ret; - char c; + memset(t, 0, sizeof(*t)); + t->fp = fdopen(fd, "r"); + t->filename = filename; + t->argc = argc; + t->argv = argv; +} - if (t->argstr != NULL) { - c = *(t->argstr++); - if (c != '\0') - goto out; +void rdline_cleanup(rdline_t *t) +{ + free(t->line); + fclose(t->fp); +} - t->argstr = NULL; - } +static int read_raw_line(rdline_t *t) +{ + size_t len = 0; - do { - ret = read(t->fd, &c, 1); - } while (ret < 0 && errno == EINTR); + free(t->line); + t->line = NULL; - if (ret < 0) - return -1; + errno = 0; - if (ret == 0) { - if (t->i == 0) { - errno = 0; + if (getline(&t->line, &len, t->fp) < 0) { + if (errno) { + fprintf(stderr, "%s: %zu: %s\n", t->filename, + t->lineno, strerror(errno)); return -1; } - c = '\0'; + return 1; } -out: - return (c == '\n') ? '\0' : c; + + t->lineno += 1; + return 0; } -static int rdline_append(rdline_t *t, int c) +static int normalize_line(rdline_t *t) { - if (t->comment) { - if (c != '\0') - return 0; - } else if (t->string) { - if (t->escape) { - t->escape = false; - } else { - if (c == '\\') - t->escape = true; - if (c == '"') - t->string = false; - } - } else { - if (isspace(c)) + char *dst = t->line, *src = t->line; + bool string = false; + const char *errstr; + int c, ret = 0; + + while (isspace(*src)) + ++src; + + while (*src != '\0' && (string || *src != '#')) { + c = *(src++); + + if (c == '"') { + string = !string; + } else if (!string && isspace(c)) { c = ' '; - if (c == ' ' && (t->i == 0 || t->buffer[t->i - 1] == ' ')) - return 0; - if (c == '#') { - t->comment = true; - return 0; + if (dst > t->line && dst[-1] == ' ') + continue; + } else if (c == '%') { + *(dst++) = c; + c = *(src++); + if (c != '%' && !isdigit(c)) { + errstr = "expected digit after '%%'"; + goto fail; + } + if (isdigit(c) && (c - '0') >= t->argc) { + errstr = "argument out of range"; + goto fail; + } + ret += strlen(t->argv[c - '0']); + } else if (string && c == '\\' && *src != '\0') { + *(dst++) = c; + c = *(src++); } - if (c == '"') - t->string = true; - } - if (c == '\0') { - while (t->i > 0 && t->buffer[t->i - 1] == ' ') - t->i -= 1; + *(dst++) = c; } - if (t->i == sizeof(t->buffer)) - return -1; + if (string) { + errstr = "missing \""; + goto fail; + } - t->buffer[t->i++] = c; - return 0; + while (dst > t->line && dst[-1] == ' ') + --dst; + *dst = '\0'; + return ret; +fail: + fprintf(stderr, "%s: %zu: %s\n", t->filename, t->lineno, errstr); + return -1; } -void rdline_init(rdline_t *t, int fd, const char *filename, - int argc, const char *const *argv) +static void substitute(rdline_t *t, char *dst, char *src) { - memset(t, 0, sizeof(*t)); - t->fd = fd; - t->filename = filename; - t->argc = argc; - t->argv = argv; + bool string = false; + + while (*src != '\0') { + if (src[0] == '%' && isdigit(src[1])) { + strcpy(dst, t->argv[src[1] - '0']); + src += 2; + while (*dst != '\0') + ++dst; + } else { + if (*src == '"') + string = !string; + if (string && *src == '\\') + *(dst++) = *(src++); + *(dst++) = *(src++); + } + } } int rdline(rdline_t *t) { - const char *errstr; - int c; -retry: - t->i = 0; - t->argstr = NULL; - t->string = t->escape = t->comment = false; - t->lineno += 1; + char *buffer = NULL; + int ret; do { - errno = 0; - c = rdline_getc(t); - if (c < 0) { - if (errno == 0) - return 1; - errstr = strerror(errno); - goto fail; - } - if (c == 0 && t->string) { - errstr = "missing \""; - goto fail; - } - - if (c == '%') { - c = rdline_getc(t); - if (c == 0) { - errstr = "unexpected end of line after '%%'"; - goto fail; - } - if (c < 0) { - errstr = strerror(errno); - goto fail; - } - - if (c != '%') { - if (!isdigit(c)) { - errstr = "exptected digit after '%%'"; - goto fail; - } - if ((c - '0') >= t->argc) { - errstr = "argument out of range"; - goto fail; - } - if (t->argstr != NULL) { - errstr = "recursive argument " - "expansion"; - goto fail; - } - t->argstr = t->argv[c - '0']; - continue; - } - } + if ((ret = read_raw_line(t))) + goto out; + if ((ret = normalize_line(t)) < 0) + goto out; + } while (t->line[0] == '\0'); - if (rdline_append(t, c)) { - errstr = "line too long"; - goto fail; - } - } while (c != '\0'); + if (ret == 0) + return 0; - if (t->buffer[0] == '\0') - goto retry; + buffer = calloc(1, strlen(t->line) + ret + 1); + if (buffer == NULL) { + fprintf(stderr, "%s: %zu: out of memory\n", + t->filename, t->lineno); + ret = -1; + goto out; + } - return 0; -fail: - fprintf(stderr, "%s: %zu: %s\n", t->filename, t->lineno, errstr); - return -1; + substitute(t, buffer, t->line); + ret = 0; +out: + free(t->line); + t->line = buffer; + return ret; } diff --git a/lib/libcfg/splitkv.c b/lib/libcfg/splitkv.c deleted file mode 100644 index 49f8ebe..0000000 --- a/lib/libcfg/splitkv.c +++ /dev/null @@ -1,48 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ -/* - * Copyright (C) 2018 - David Oberhollenzer - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - */ -#include <ctype.h> -#include <stdio.h> - -#include "libcfg.h" - -int splitkv(rdline_t *rd, char **k, char **v) -{ - char *key = rd->buffer, *value = rd->buffer; - - while (*value != ' ' && *value != '\0') { - if (!isalpha(*value)) { - fprintf(stderr, - "%s: %zu: unexpected '%c' in keyword\n", - rd->filename, rd->lineno, *value); - return -1; - } - ++value; - } - - if (*value != ' ') { - fprintf(stderr, "%s: %zu: expected argument after '%s'\n", - rd->filename, rd->lineno, key); - return -1; - } - - *(value++) = '\0'; - - *k = key; - *v = value; - return 0; -} |