summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Härdeman <david@hardeman.nu>2020-06-30 10:03:07 +0200
committerDavid Härdeman <david@hardeman.nu>2020-06-30 10:03:07 +0200
commitb2961ea4a792fa7e5bead6e49d399dcea55b039b (patch)
tree56e7f89f49c1281eaad1a2a0cd45db3ad723acbf
parent4b6f946c0871d1f510135cd43d61034d55fae5fd (diff)
Keep track of current line number in config file parsing
-rw-r--r--minecctl/misc-commands.c2
-rw-r--r--minecproxy/main.c5
-rw-r--r--shared/config-parser.c212
-rw-r--r--shared/config-parser.h4
4 files changed, 114 insertions, 109 deletions
diff --git a/minecctl/misc-commands.c b/minecctl/misc-commands.c
index 1268138..f7f2dea 100644
--- a/minecctl/misc-commands.c
+++ b/minecctl/misc-commands.c
@@ -27,7 +27,7 @@ bool do_lint(struct cfg *cfg)
if (!server->scfg.filename)
continue;
- info("%s", server->name);
+ info("• %s", server->name);
/* FIXME: should return bool */
server_read_config(cfg, server);
diff --git a/minecproxy/main.c b/minecproxy/main.c
index b5a195b..92961e2 100644
--- a/minecproxy/main.c
+++ b/minecproxy/main.c
@@ -255,6 +255,7 @@ static void cfg_read()
char *pos = buf;
size_t rd = 0;
size_t r;
+ unsigned lineno;
assert_return(cfg);
@@ -294,7 +295,7 @@ static void cfg_read()
*pos = '\0';
pos = buf;
- if (!config_parse_header("mcproxy", &pos))
+ if (!config_parse_header("mcproxy", &pos, &lineno))
die("main config file (%s) missing/invalid header", path);
while (true) {
@@ -303,7 +304,7 @@ static void cfg_read()
struct cfg_value value;
if (!config_parse_line(path, &pos, mcfg_key_map, &key, &keyname,
- &value, false))
+ &value, false, &lineno))
break;
if (key == MCFG_KEY_INVALID)
diff --git a/shared/config-parser.c b/shared/config-parser.c
index 6c2d33d..850bae8 100644
--- a/shared/config-parser.c
+++ b/shared/config-parser.c
@@ -372,6 +372,7 @@ do { \
bool scfg_parse(struct server_config *scfg, char *buf,
notification_cb_t notification_cb)
{
+ unsigned lineno;
char *pos;
bool valid = true;
@@ -379,7 +380,7 @@ bool scfg_parse(struct server_config *scfg, char *buf,
pos = buf;
- if (!config_parse_header(SERVER_CFG_HEADER, &pos)) {
+ if (!config_parse_header(SERVER_CFG_HEADER, &pos, &lineno)) {
INVALID("missing/invalid header");
goto out;
}
@@ -390,7 +391,7 @@ bool scfg_parse(struct server_config *scfg, char *buf,
struct cfg_value value;
if (!config_parse_line(scfg->filename, &pos, scfg_key_map, &key,
- &keyname, &value, !!notification_cb))
+ &keyname, &value, !!notification_cb, &lineno))
break;
/* FIXME: Improve error reporting */
@@ -603,33 +604,43 @@ bool scfg_init(struct server_config *scfg, const char *filename)
return true;
}
-static void eat_whitespace_and_comments(char **pos)
+static void eat_whitespace_and_comments(char **pos, unsigned *lineno)
{
- assert_return(pos && *pos);
+ assert_return(pos && *pos && lineno);
while (true) {
- while (isspace(**pos))
+ while (**pos == ' ' ||
+ **pos == '\f' ||
+ **pos == '\r' ||
+ **pos == '\t' ||
+ **pos == '\v')
(*pos)++;
+ if (**pos == '\n') {
+ (*lineno)++;
+ (*pos)++;
+ continue;
+ }
+
if (**pos != '#')
return;
- while (**pos != '\r' && **pos != '\n' && **pos != '\0')
+ while (**pos != '\n' && **pos != '\0')
(*pos)++;
}
}
-static char *get_line(char **pos)
+static char *get_line(char **pos, unsigned *lineno)
{
char *begin, *end;
- assert_return(pos && *pos, NULL);
+ assert_return(pos && *pos && lineno, NULL);
- eat_whitespace_and_comments(pos);
+ (*lineno)++;
+
+ eat_whitespace_and_comments(pos, lineno);
begin = *pos;
- while (isspace(*begin))
- begin++;
if (*begin == '\0')
return NULL;
@@ -916,155 +927,148 @@ error:
bool config_parse_line(const char *filename, char **buf,
struct cfg_key_value_map *kvmap, int *rkey,
const char **rkeyname, struct cfg_value *rvalue,
- bool async_dns)
+ bool async_dns, unsigned *lineno)
{
- char *line, *tmp, *key;
+ char *line, *pos, *key, *value;
+ size_t linelen;
int i;
- assert_return(buf && *buf && kvmap && rkey && rkeyname && rvalue,
+ assert_return(buf && *buf && kvmap && rkey && rkeyname && rvalue && lineno,
false);
- line = get_line(buf);
+ line = get_line(buf, lineno);
if (!line)
return false;
- debug(DBG_CFG, "%s: parsing config line: %s", filename, line);
+ debug(DBG_CFG, "%s: parsing cfg line %u: %s", filename, *lineno, line);
- tmp = line;
- while (isspace(*tmp))
- tmp++;
+ linelen = strlen(line);
+ key = line;
- if (*tmp == '\0')
+ pos = memchr(line, '=', linelen);
+ if (!pos)
goto error;
- key = tmp;
- while (*tmp != '\0' && !isspace(*tmp))
- tmp++;
+ value = pos + 1;
+ *pos = '\0';
- if (*tmp == '\0')
- goto error;
-
- *tmp = '\0';
- tmp++;
+ while (isspace(*(--pos)))
+ *pos = '\0';
- while (isspace(*tmp))
- tmp++;
+ while (isspace(*value))
+ value++;
- if (*tmp != '=')
+ if (*value == '\0')
goto error;
- tmp++;
- while (isspace(*tmp))
- tmp++;
+ for (i = 0; kvmap[i].key_name; i++) {
+ if (streq(kvmap[i].key_name, key))
+ break;
+ }
- if (*tmp == '\0')
+ if (!kvmap[i].key_name)
goto error;
- for (i = 0; kvmap[i].key_name; i++) {
- if (!streq(kvmap[i].key_name, key))
- continue;
+ switch (kvmap[i].value_type) {
+ case CFG_VAL_TYPE_STRING:
+ rvalue->type = CFG_VAL_TYPE_STRING;
+ rvalue->str = value;
+ break;
- switch (kvmap[i].value_type) {
- case CFG_VAL_TYPE_STRING:
- rvalue->type = CFG_VAL_TYPE_STRING;
- rvalue->str = tmp;
- break;
+ case CFG_VAL_TYPE_UINT16: {
+ uint16_t v;
- case CFG_VAL_TYPE_UINT16: {
- uint16_t v;
+ if (strtou16_strict(value, &v) < 0)
+ goto error;
- if (strtou16_strict(tmp, &v) < 0)
- goto error;
+ rvalue->type = CFG_VAL_TYPE_UINT16;
+ rvalue->uint16 = v;
+ break;
+ }
- rvalue->type = CFG_VAL_TYPE_UINT16;
- rvalue->uint16 = v;
- break;
- }
+ case CFG_VAL_TYPE_ASYNC_ADDRS:
+ error("CFG_VAL_TYPE_ASYNC_ADDRS is a return value");
+ _fallthrough_;
- case CFG_VAL_TYPE_ASYNC_ADDRS:
- error("CFG_VAL_TYPE_ASYNC_ADDRS is a return value");
- _fallthrough_;
+ case CFG_VAL_TYPE_ADDRS:
+ if (!strtosockaddrs(value, rvalue, async_dns))
+ goto error;
+ switch (rvalue->type) {
case CFG_VAL_TYPE_ADDRS:
- if (!strtosockaddrs(tmp, rvalue, async_dns))
+ if (list_empty(&rvalue->saddrs)) {
+ error("empty address list");
goto error;
+ }
+ break;
- switch (rvalue->type) {
- case CFG_VAL_TYPE_ADDRS:
- if (list_empty(&rvalue->saddrs)) {
- error("empty address list");
- goto error;
- }
- break;
-
- case CFG_VAL_TYPE_ASYNC_ADDRS:
- if (!async_dns) {
- error("unexpected async dns result");
- goto error;
- }
-
- if (!rvalue->dns_async) {
- error("dns_async not set");
- goto error;
- }
- break;
-
- default:
- error("invalid type returned from strtosockaddrs");
+ case CFG_VAL_TYPE_ASYNC_ADDRS:
+ if (!async_dns) {
+ error("unexpected async dns result");
goto error;
}
- break;
- case CFG_VAL_TYPE_BOOL:
- if (strcaseeq(tmp, "yes") || strcaseeq(tmp, "true")) {
- rvalue->type = CFG_VAL_TYPE_BOOL;
- rvalue->boolean = true;
- } else if (strcaseeq(tmp, "no") ||
- strcaseeq(tmp, "false")) {
- rvalue->type = CFG_VAL_TYPE_BOOL;
- rvalue->boolean = false;
- } else {
- error("invalid boolean value (%s)", tmp);
+ if (!rvalue->dns_async) {
+ error("dns_async not set");
goto error;
}
break;
- case CFG_VAL_TYPE_INVALID:
- _fallthrough_;
default:
+ error("invalid type returned from strtosockaddrs");
goto error;
}
+ break;
- /* sanity check */
- if ((rvalue->type != kvmap[i].value_type) &&
- ((kvmap[i].value_type != CFG_VAL_TYPE_ASYNC_ADDRS) &&
- (rvalue->type != CFG_VAL_TYPE_ADDRS))) {
- error("rvalue->type != kvmap->type");
+ case CFG_VAL_TYPE_BOOL:
+ if (strcaseeq(value, "yes") || strcaseeq(value, "true")) {
+ rvalue->type = CFG_VAL_TYPE_BOOL;
+ rvalue->boolean = true;
+ } else if (strcaseeq(value, "no") ||
+ strcaseeq(value, "false")) {
+ rvalue->type = CFG_VAL_TYPE_BOOL;
+ rvalue->boolean = false;
+ } else {
+ error("invalid boolean value (%s)", value);
goto error;
}
+ break;
- *rkey = kvmap[i].key_value;
- *rkeyname = kvmap[i].key_name;
- return true;
+ case CFG_VAL_TYPE_INVALID:
+ _fallthrough_;
+ default:
+ goto error;
}
+ /* sanity check */
+ if ((rvalue->type != kvmap[i].value_type) &&
+ ((kvmap[i].value_type != CFG_VAL_TYPE_ASYNC_ADDRS) &&
+ (rvalue->type != CFG_VAL_TYPE_ADDRS))) {
+ error("rvalue->type != kvmap->type");
+ goto error;
+ }
+
+ *rkey = kvmap[i].key_value;
+ *rkeyname = kvmap[i].key_name;
+ return true;
+
error:
- /* FIXME: the line is already mangled here, a line number would be nice
- */
- error("%s: invalid config line: %s", filename, line);
+ error("%s: invalid config line: %u:%s", filename, *lineno, line);
rvalue->type = CFG_VAL_TYPE_INVALID;
*rkey = 0;
*rkeyname = NULL;
return true;
}
-bool config_parse_header(const char *title, char **buf)
+bool config_parse_header(const char *title, char **buf, unsigned *lineno)
{
char *line;
- assert_return(!empty_str(title) && buf && *buf, false);
+ assert_return(!empty_str(title) && buf && *buf && lineno, false);
+
+ *lineno = 0;
- line = get_line(buf);
+ line = get_line(buf, lineno);
if (line) {
char titlehdr[strlen(title) + 3];
diff --git a/shared/config-parser.h b/shared/config-parser.h
index 2990349..262fe09 100644
--- a/shared/config-parser.h
+++ b/shared/config-parser.h
@@ -99,9 +99,9 @@ bool strtosockaddrs(const char *str, struct cfg_value *rvalue, bool async);
bool config_parse_line(const char *filename, char **buf,
struct cfg_key_value_map *kvmap, int *rkey,
const char **rkeyname, struct cfg_value *rvalue,
- bool async_dns);
+ bool async_dns, unsigned *lineno);
-bool config_parse_header(const char *title, char **buf);
+bool config_parse_header(const char *title, char **buf, unsigned *lineno);
bool is_valid_server_config_filename(struct dirent *dent, const char *filename);