diff options
| author | David Härdeman <david@hardeman.nu> | 2020-06-30 10:03:07 +0200 | 
|---|---|---|
| committer | David Härdeman <david@hardeman.nu> | 2020-06-30 10:03:07 +0200 | 
| commit | b2961ea4a792fa7e5bead6e49d399dcea55b039b (patch) | |
| tree | 56e7f89f49c1281eaad1a2a0cd45db3ad723acbf | |
| parent | 4b6f946c0871d1f510135cd43d61034d55fae5fd (diff) | |
Keep track of current line number in config file parsing
| -rw-r--r-- | minecctl/misc-commands.c | 2 | ||||
| -rw-r--r-- | minecproxy/main.c | 5 | ||||
| -rw-r--r-- | shared/config-parser.c | 212 | ||||
| -rw-r--r-- | shared/config-parser.h | 4 | 
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);  | 
