From e61d7399e7963437339d8c4185e1dbc4e5e05489 Mon Sep 17 00:00:00 2001 From: Dino Date: Thu, 25 Dec 2025 21:14:21 -0500 Subject: [PATCH] Improve error reporting of invalid reqs in rulesets HR #1842 --- common/requirements.c | 72 +++++++++++++++++++++++++++++++++++++------ common/requirements.h | 5 +++ server/ruleset.c | 19 +++++++----- 3 files changed, 79 insertions(+), 17 deletions(-) diff --git a/common/requirements.c b/common/requirements.c index 0cef3fcf16..b72d7e474d 100644 --- a/common/requirements.c +++ b/common/requirements.c @@ -1033,15 +1033,15 @@ const char *req_to_fstring(const struct requirement *req, } /**********************************************************************//** - Parse a requirement type and value string into a requirement structure. - Returns the invalid element for enum universal_n on error. Passing in a - NULL type is considered VUT_NONE (not an error). + Common code for req_from_str_with_err_msg() & req_from_str() - Pass this some values like "Building", "Factory". + If you want the error message from an invalid req, pass the err_msg_ptr + param a value x of a char x[256], else pass nullptr. **************************************************************************/ -struct requirement req_from_str(const char *type, const char *range, - bool survives, bool present, bool quiet, - const char *value) +static struct requirement + req_from_str_internal(const char *type, const char *range, + bool survives, bool present, bool quiet, + const char *value, char *err_msg_ptr ) { struct requirement req; bool invalid; @@ -1395,15 +1395,67 @@ struct requirement req_from_str(const char *type, const char *range, } if (invalid) { - log_error("Invalid requirement %s | %s | %s | %s | %s: %s", - type, range, survives ? "survives" : "", - present ? "present" : "", value, error); + char err_msg[256]; + + sprintf(err_msg, "Invalid requirement: | type = %s | value = %s | range = %s " + "| present = %s | survives = %s| - %s", + type, value, range, + present ? "TRUE" : "FALSE", + survives ? "TRUE" : "FALSE", + error); + if (err_msg_ptr == nullptr) { + log_error("%s", err_msg); + } else { + /* caller will report the error */ + strncpy(err_msg_ptr, err_msg, 256); + } req.source.kind = universals_n_invalid(); } return req; } +/**********************************************************************//** + A version of req_from_str() that returns an error message for + invalid reqs. + Pass the err_msg_ptr param a value x of a char x[256] + + Parse a requirement type and value string into a requirement structure. + Returns the invalid element for enum universal_n on error. Passing in a + NULL type is considered VUT_NONE (not an error). + + Pass this some values like "Building", "Factory". +**************************************************************************/ +struct requirement + req_from_str_with_err_msg(const char *type, const char *range, + bool survives, bool present, bool quiet, + const char *value, char *err_msg_ptr) +{ + struct requirement req = + req_from_str_internal(type, range, survives, present, + quiet, value, err_msg_ptr); + + return req; +} + +/**********************************************************************//** + Parse a requirement type and value string into a requirement structure. + Returns the invalid element for enum universal_n on error. Passing in a + NULL type is considered VUT_NONE (not an error). + + Pass this some values like "Building", "Factory". +**************************************************************************/ +struct requirement req_from_str(const char *type, const char *range, + bool survives, bool present, bool quiet, + const char *value) +{ + struct requirement req = + req_from_str_internal(type, range, survives, present, + quiet, value, nullptr); + + return req; +} + /**********************************************************************//** Set the values of a req from serializable integers. This is the opposite of req_get_values. diff --git a/common/requirements.h b/common/requirements.h index 60783f7548..2912493afe 100644 --- a/common/requirements.h +++ b/common/requirements.h @@ -140,6 +140,11 @@ const struct req_context *req_context_empty(void); struct requirement req_from_str(const char *type, const char *range, bool survives, bool present, bool quiet, const char *value); +struct requirement req_from_str_with_err_msg(const char *type, + const char *range, + bool survives, bool present, + bool quiet, const char *value, + char *err_msg_ptr); const char *req_to_fstring(const struct requirement *req, struct astring *astr); diff --git a/server/ruleset.c b/server/ruleset.c index f77a042290..3bada486b5 100644 --- a/server/ruleset.c +++ b/server/ruleset.c @@ -771,14 +771,19 @@ struct requirement_vector *lookup_req_list(struct section_file *file, rscompat_req_adjust_3_2(compat, &type, &name, &present, sec); } - req = req_from_str(type, range, survives, present, quiet, name); - if (req.source.kind == universals_n_invalid()) { - ruleset_error(NULL, LOG_ERROR, - "\"%s\" [%s] has invalid or unknown req: " - "\"%s\" \"%s\".", - filename, sec, type, name); + { + char err_msg[256]; - return NULL; + req = req_from_str_with_err_msg(type, range, survives, present, + quiet, name, err_msg); + if (req.source.kind == universals_n_invalid()) { + ruleset_error(NULL, LOG_ERROR, + "\"%s\" [%s]" + " %s.", + filename, sec, err_msg); + + return NULL; + } } requirement_vector_append(&reqs_list, req); -- 2.31.0