mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-04-04 07:15:29 -04:00
conf: improve configuration file parsing
* Strip whitespaces from keys and values * Detect (and ignore) comments * Detect syntax errors (no value specified etc) * Error out on syntax errors and invalid keys
This commit is contained in:
parent
c11cc2be57
commit
de575ac58e
3 changed files with 66 additions and 16 deletions
74
config.c
74
config.c
|
|
@ -4,6 +4,7 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <ctype.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
@ -81,13 +82,9 @@ get_config_path(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
parse_section_main(char *line, struct config *conf, const char *path, unsigned lineno)
|
parse_section_main(const char *key, const char *value, struct config *conf,
|
||||||
|
const char *path, unsigned lineno)
|
||||||
{
|
{
|
||||||
const char *key = strtok(line, "=");
|
|
||||||
const char *value = strtok(NULL, "\n");
|
|
||||||
|
|
||||||
LOG_DBG("%s:%u: key = %s, value=%s", path, lineno, key, value);
|
|
||||||
|
|
||||||
if (strcmp(key, "font") == 0) {
|
if (strcmp(key, "font") == 0) {
|
||||||
free(conf->font);
|
free(conf->font);
|
||||||
conf->font = strdup(value);
|
conf->font = strdup(value);
|
||||||
|
|
@ -99,7 +96,7 @@ parse_section_main(char *line, struct config *conf, const char *path, unsigned l
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
LOG_ERR("%s:%u: invalid key: %s", path, lineno, key);
|
LOG_WARN("%s:%u: invalid key: %s", path, lineno, key);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -115,13 +112,20 @@ parse_config_file(FILE *f, struct config *conf, const char *path)
|
||||||
|
|
||||||
/* Function pointer, called for each key/value line */
|
/* Function pointer, called for each key/value line */
|
||||||
typedef bool (*parser_fun_t)(
|
typedef bool (*parser_fun_t)(
|
||||||
char *line, struct config *conf, const char *path, unsigned lineno);
|
const char *key, const char *value, struct config *conf,
|
||||||
|
const char *path, unsigned lineno);
|
||||||
|
|
||||||
/* Maps sections to line parser functions */
|
/* Maps sections to line parser functions */
|
||||||
static const parser_fun_t section_parser_map[] = {
|
static const parser_fun_t section_parser_map[] = {
|
||||||
[SECTION_MAIN] = &parse_section_main,
|
[SECTION_MAIN] = &parse_section_main,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if defined(_DEBUG)
|
||||||
|
static const char *const section_names[] = {
|
||||||
|
[SECTION_MAIN] = "main",
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
unsigned lineno = 0;
|
unsigned lineno = 0;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
@ -147,10 +151,50 @@ parse_config_file(FILE *f, struct config *conf, const char *path)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *key = strtok(line, "=");
|
||||||
|
char *value = strtok(NULL, "\n");
|
||||||
|
|
||||||
|
{
|
||||||
|
while (isspace(*key))
|
||||||
|
key++;
|
||||||
|
char *end = key + strlen(key) - 1;
|
||||||
|
while (isspace(*end))
|
||||||
|
end--;
|
||||||
|
*(end + 1) = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value == NULL) {
|
||||||
|
if (key != NULL && strlen(key) > 0 && key[0] != '#') {
|
||||||
|
LOG_ERR("%s:%d: syntax error: %s", path, lineno, line);
|
||||||
|
free(line);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(line);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
while (isspace(*value))
|
||||||
|
value++;
|
||||||
|
char *end = value + strlen(value) - 1;
|
||||||
|
while (isspace(*end))
|
||||||
|
end--;
|
||||||
|
*(end + 1) = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key[0] == '#') {
|
||||||
|
free(line);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DBG("section=%s, key='%s', value='%s'",
|
||||||
|
section_names[section], key, value);
|
||||||
|
|
||||||
parser_fun_t section_parser = section_parser_map[section];
|
parser_fun_t section_parser = section_parser_map[section];
|
||||||
assert(section_parser != NULL);
|
assert(section_parser != NULL);
|
||||||
|
|
||||||
if (!section_parser(line, conf, path, lineno)) {
|
if (!section_parser(key, value, conf, path, lineno)) {
|
||||||
free(line);
|
free(line);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -161,10 +205,12 @@ parse_config_file(FILE *f, struct config *conf, const char *path)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct config
|
bool
|
||||||
config_load(void)
|
config_load(struct config *conf)
|
||||||
{
|
{
|
||||||
struct config conf = {
|
bool ret = false;
|
||||||
|
|
||||||
|
*conf = (struct config) {
|
||||||
.shell = get_shell(),
|
.shell = get_shell(),
|
||||||
.font = strdup("monospace"),
|
.font = strdup("monospace"),
|
||||||
};
|
};
|
||||||
|
|
@ -184,12 +230,12 @@ config_load(void)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
parse_config_file(f, &conf, path);
|
ret = parse_config_file(f, conf, path);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
free(path);
|
free(path);
|
||||||
return conf;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
||||||
4
config.h
4
config.h
|
|
@ -1,9 +1,11 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
struct config {
|
struct config {
|
||||||
char *shell;
|
char *shell;
|
||||||
char *font;
|
char *font;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct config config_load(void);
|
bool config_load(struct config *conf);
|
||||||
void config_free(struct config conf);
|
void config_free(struct config conf);
|
||||||
|
|
|
||||||
4
main.c
4
main.c
|
|
@ -273,7 +273,9 @@ main(int argc, char *const *argv)
|
||||||
{
|
{
|
||||||
int ret = EXIT_FAILURE;
|
int ret = EXIT_FAILURE;
|
||||||
|
|
||||||
struct config conf = config_load();
|
struct config conf = {NULL};
|
||||||
|
if (!config_load(&conf))
|
||||||
|
return ret;
|
||||||
|
|
||||||
static const struct option longopts[] = {
|
static const struct option longopts[] = {
|
||||||
{"font", required_argument, 0, 'f'},
|
{"font", required_argument, 0, 'f'},
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue