From 5cabb89907f70abffcdafd1ea8c05da4a6e25159 Mon Sep 17 00:00:00 2001 From: Dino Date: Thu, 25 Dec 2025 23:17:07 -0500 Subject: [PATCH] Improve error reporting of invalid reqs in rulesets HR #1842 --- common/requirements.c | 72 +++++++++++++++++++++++++++++++++------ common/requirements.h | 5 +++ server/ruleset/ruleload.c | 18 ++++++---- 3 files changed, 78 insertions(+), 17 deletions(-) diff --git a/common/requirements.c b/common/requirements.c index 930fbfebd3..83c04e03bb 100644 --- a/common/requirements.c +++ b/common/requirements.c @@ -1122,15 +1122,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 nullptr 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; @@ -1538,15 +1538,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 + nullptr 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 + nullptr 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 209f543bc2..686380ad4b 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/ruleload.c b/server/ruleset/ruleload.c index b182f7a58e..796dcbbce2 100644 --- a/server/ruleset/ruleload.c +++ b/server/ruleset/ruleload.c @@ -772,14 +772,18 @@ struct requirement_vector *lookup_req_list(struct section_file *file, "'%s.%s%d'.", filename, sec, sub, j); } - 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