config parser improvements - saait - the most boring static page generator | |
git clone git://git.codemadness.org/saait | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit ea16f6b7c0fe3be5f0d9ee633ea5b4438fa8b034 | |
parent 48b39941bf4a22e7d485155f8a16577bbd543f2d | |
Author: Hiltjo Posthuma <[email protected]> | |
Date: Tue, 7 Aug 2018 13:48:41 +0200 | |
config parser improvements | |
- fix invalid read past bounds on invalid config input, minimal test-case: | |
printf 'a'. | |
- allow and ignore spaces and TABs before variable name, now allowed: | |
printf '\ta=' | |
- invalid config input is now fatal and outputs a verbose message with the | |
file, linenumber and error. | |
- code-style consistency: rename filename variable to file. | |
Diffstat: | |
M saait.c | 47 ++++++++++++++++++++---------… | |
1 file changed, 30 insertions(+), 17 deletions(-) | |
--- | |
diff --git a/saait.c b/saait.c | |
@@ -218,40 +218,53 @@ freevars(struct variable *vars) | |
} | |
struct variable * | |
-parsevars(const char *s) | |
+parsevars(const char *file, const char *s) | |
{ | |
struct variable *vars = NULL, *v; | |
const char *keystart, *keyend, *valuestart, *valueend; | |
+ size_t line = 0; | |
for (; *s; ) { | |
- /* comment start with #, skip to newline */ | |
- if (*s == '#') { | |
- s = &s[strcspn(s + 1, "\n")]; | |
+ if (*s == '\r' || *s == '\n') { | |
+ line += (*s == '\n'); | |
+ s++; | |
continue; | |
} | |
- if (*s == '\r' || *s == '\n') { | |
+ | |
+ /* comment start with #, skip to newline */ | |
+ if (*s == '#') { | |
s++; | |
+ s = &s[strcspn(s, "\n")]; | |
continue; | |
} | |
+ /* trim whitespace before key */ | |
+ s = &s[strspn(s, " \t")]; | |
+ | |
keystart = s; | |
s = &s[strcspn(s, "=\r\n")]; | |
if (*s != '=') { | |
- s++; | |
- continue; | |
+ fprintf(stderr, "%s:%zu: error: no variable\n", | |
+ file, line + 1); | |
+ exit(1); | |
} | |
- for (keyend = s; keyend > keystart && | |
+ | |
+ /* trim whitespace at end of key: but whitespace in names are | |
+ allowed */ | |
+ for (keyend = s++; keyend > keystart && | |
(keyend[-1] == ' ' || keyend[-1] == '\t'); | |
keyend--) | |
; | |
/* no variable name: skip */ | |
- if (keystart == keyend) | |
- continue; | |
+ if (keystart == keyend) { | |
+ fprintf(stderr, "%s:%zu: error: invalid variable\n", | |
+ file, line + 1); | |
+ exit(1); | |
+ } | |
- for (s++; *s && (*s == ' ' || *s == '\t'); s++) | |
- ; | |
valuestart = s; | |
- valueend = &s[strcspn(s, "\r\n")]; | |
+ s = &s[strcspn(s, "\r\n")]; | |
+ valueend = s; | |
v = ecalloc(1, sizeof(*v)); | |
v->key = ecalloc(1, keyend - keystart + 1); | |
@@ -271,14 +284,14 @@ readconfig(const char *file) | |
char *data; | |
data = readfile(file); | |
- c = parsevars(data); | |
+ c = parsevars(file, data); | |
free(data); | |
return c; | |
} | |
void | |
-writepage(FILE *fp, const char *filename, struct variable *c, char *s) | |
+writepage(FILE *fp, const char *file, struct variable *c, char *s) | |
{ | |
FILE *fpin; | |
struct variable *v; | |
@@ -325,7 +338,7 @@ writepage(FILE *fp, const char *filename, struct variable *… | |
if (!v) { | |
fprintf(stderr, "%s:%zu: error: undefined variable: '%… | |
- filename, line + 1, (int)keylen, key); | |
+ file, line + 1, (int)keylen, key); | |
exit(1); | |
} | |
@@ -334,7 +347,7 @@ writepage(FILE *fp, const char *filename, struct variable *… | |
if (!v->value[0]) | |
break; | |
fpin = efopen(v->value, "rb"); | |
- catfile(fpin, v->value, fp, filename); | |
+ catfile(fpin, v->value, fp, file); | |
fclose(fpin); | |
break; | |
case '$': |