diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp index 06836855da..dc611adf26 100644 --- a/src/saveload/saveload.cpp +++ b/src/saveload/saveload.cpp @@ -534,17 +534,22 @@ static void SlNullPointers() * @note This function does never return as it throws an exception to * break out of all the saveload code. */ -void NORETURN SlError(StringID string, const char *extra_msg) +void NORETURN SlError(StringID string, const char *extra_msg, bool already_malloced) { + char *str = NULL; + if (extra_msg != NULL) { + str = already_malloced ? const_cast(extra_msg) : stredup(extra_msg); + } + /* Distinguish between loading into _load_check_data vs. normal save/load. */ if (_sl.action == SLA_LOAD_CHECK) { _load_check_data.error = string; free(_load_check_data.error_data); - _load_check_data.error_data = (extra_msg == NULL) ? NULL : stredup(extra_msg); + _load_check_data.error_data = str; } else { _sl.error_str = string; free(_sl.extra_msg); - _sl.extra_msg = (extra_msg == NULL) ? NULL : stredup(extra_msg); + _sl.extra_msg = str; } /* We have to NULL all pointers here; we might be in a state where @@ -555,6 +560,18 @@ void NORETURN SlError(StringID string, const char *extra_msg) throw std::exception(); } +/** + * As SlError, except that it takes a format string and additional parameters + */ +void CDECL NORETURN SlErrorFmt(StringID string, const char *msg, ...) +{ + va_list va; + va_start(va, msg); + char *str = str_vfmt(msg, va); + va_end(va); + SlError(string, str, true); +} + /** * Error handler for corrupt savegames. Sets everything up to show the * error message and to clean up the mess of a partial savegame load. @@ -562,9 +579,21 @@ void NORETURN SlError(StringID string, const char *extra_msg) * @note This function does never return as it throws an exception to * break out of all the saveload code. */ -void NORETURN SlErrorCorrupt(const char *msg) +void NORETURN SlErrorCorrupt(const char *msg, bool already_malloced) { - SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, msg); + SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, msg, already_malloced); +} + +/** + * As SlErrorCorruptFmt, except that it takes a format string and additional parameters + */ +void CDECL NORETURN SlErrorCorruptFmt(const char *msg, ...) +{ + va_list va; + va_start(va, msg); + char *str = str_vfmt(msg, va); + va_end(va); + SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, str, true); } diff --git a/src/saveload/saveload.h b/src/saveload/saveload.h index 230203b4e7..9c1d9615f5 100644 --- a/src/saveload/saveload.h +++ b/src/saveload/saveload.h @@ -16,6 +16,8 @@ #include "../strings_type.h" #include "extended_ver_sl.h" +#include + /** Save or load result codes. */ enum SaveOrLoadResult { SL_OK = 0, ///< completed successfully @@ -570,8 +572,10 @@ void SlGlobList(const SaveLoadGlobVarList *sldg); void SlArray(void *array, size_t length, VarType conv); void SlObject(void *object, const SaveLoad *sld); bool SlObjectMember(void *object, const SaveLoad *sld); -void NORETURN SlError(StringID string, const char *extra_msg = NULL); -void NORETURN SlErrorCorrupt(const char *msg); +void NORETURN SlError(StringID string, const char *extra_msg = NULL, bool already_malloced = false); +void NORETURN SlErrorCorrupt(const char *msg, bool already_malloced = false); +void CDECL NORETURN SlErrorFmt(StringID string, const char *msg, ...) WARN_FORMAT(2, 3); +void CDECL NORETURN SlErrorCorruptFmt(const char *msg, ...) WARN_FORMAT(1, 2); bool SaveloadCrashWithMissingNewGRFs(); diff --git a/src/string.cpp b/src/string.cpp index 6bc9319c1c..4bcd0cf805 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -131,6 +131,16 @@ char *stredup(const char *s, const char *last) return tmp; } +char *str_vfmt(const char *str, va_list va) +{ + char buf[4096]; + + int len = vseprintf(buf, lastof(buf), str, va); + char *p = MallocT(len + 1); + memcpy(p, buf, len + 1); + return p; +} + /** * Format, "printf", into a newly allocated string. * @param str The formatting string. @@ -138,15 +148,11 @@ char *stredup(const char *s, const char *last) */ char *CDECL str_fmt(const char *str, ...) { - char buf[4096]; va_list va; - va_start(va, str); - int len = vseprintf(buf, lastof(buf), str, va); + char *output = str_vfmt(str, va); va_end(va); - char *p = MallocT(len + 1); - memcpy(p, buf, len + 1); - return p; + return output; } /** diff --git a/src/string_func.h b/src/string_func.h index ff12f3747a..dd9b42600d 100644 --- a/src/string_func.h +++ b/src/string_func.h @@ -39,6 +39,7 @@ int CDECL seprintf(char *str, const char *last, const char *format, ...) WARN_FO int CDECL vseprintf(char *str, const char *last, const char *format, va_list ap); char *CDECL str_fmt(const char *str, ...) WARN_FORMAT(1, 2); +char *str_vfmt(const char *str, va_list ap); void str_validate(char *str, const char *last, StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK); void ValidateString(const char *str);