From ac0e83a7e22c3ed94130b2fc4de62fe38478b121 Mon Sep 17 00:00:00 2001 From: yexo Date: Wed, 8 Dec 2010 13:44:01 +0000 Subject: [PATCH] (svn r21435) -Fix: NewGRF strings that referenced a value that was set by a string command later in the string failed --- src/newgrf_text.cpp | 35 +++++++++++++++++++++++++++++++++++ src/newgrf_text.h | 3 +++ src/strings.cpp | 15 +++++++++++++-- 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/src/newgrf_text.cpp b/src/newgrf_text.cpp index a1b07ad3b5..ff77c441ce 100644 --- a/src/newgrf_text.cpp +++ b/src/newgrf_text.cpp @@ -863,6 +863,13 @@ struct TextRefStack { TextRefStack() : used(false) {} + TextRefStack(const TextRefStack &stack) : + position(stack.position), + used(stack.used) + { + memcpy(this->stack, stack.stack, sizeof(this->stack)); + } + uint8 PopUnsignedByte() { assert(this->position < lengthof(this->stack)); return this->stack[this->position++]; } int8 PopSignedByte() { return (int8)this->PopUnsignedByte(); } @@ -919,6 +926,34 @@ static TextRefStack _newgrf_error_textrefstack; /** The stack that is used for TTDP compatible string code parsing */ static TextRefStack *_newgrf_textrefstack = &_newgrf_normal_textrefstack; +/** + * Check whether the NewGRF text stack is in use. + * @return True iff the NewGRF text stack is used. + */ +bool UsingNewGRFTextStack() +{ + return _newgrf_textrefstack->used; +} + +/** + * Create a backup of the current NewGRF text stack. + * @return A copy of the current text stack. + */ +struct TextRefStack *CreateTextRefStackBackup() +{ + return new TextRefStack(*_newgrf_textrefstack); +} + +/** + * Restore a copy of the text stack to the used stack. + * @param backup The copy to restore. + */ +void RestoreTextRefStackBackup(struct TextRefStack *backup) +{ + *_newgrf_textrefstack = *backup; + delete backup; +} + /** * Prepare the TTDP compatible string code parsing * @param numEntries number of entries to copy from the registers diff --git a/src/newgrf_text.h b/src/newgrf_text.h index a4c5f61237..ac0c79130f 100644 --- a/src/newgrf_text.h +++ b/src/newgrf_text.h @@ -39,6 +39,9 @@ void StopTextRefStackUsage(); void SwitchToNormalRefStack(); void SwitchToErrorRefStack(); void RewindTextRefStack(); +bool UsingNewGRFTextStack(); +struct TextRefStack *CreateTextRefStackBackup(); +void RestoreTextRefStackBackup(struct TextRefStack *backup); uint RemapNewGRFStringControlCode(uint scc, char *buf_start, char **buff, const char **str, int64 *argv); StringID TTDPStringIDToOTTDStringIDMapping(StringID string); diff --git a/src/strings.cpp b/src/strings.cpp index f6c62a947f..f3db95fb1a 100644 --- a/src/strings.cpp +++ b/src/strings.cpp @@ -56,7 +56,7 @@ static char *StationGetSpecialString(char *buff, int x, const char *last); static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed, const char *last); static char *GetSpecialNameString(char *buff, int ind, int64 *argv, const char *last); -static char *FormatString(char *buff, const char *str, int64 *argv, uint casei, const char *last); +static char *FormatString(char *buff, const char *str, int64 *argv, uint casei, const char *last, bool dry_run = false); struct LanguagePack : public LanguagePackHeader { char data[]; // list of strings @@ -583,8 +583,19 @@ uint ConvertDisplaySpeedToSpeed(uint speed) return ((speed << units[_settings_game.locale.units].s_s) + units[_settings_game.locale.units].s_m / 2) / units[_settings_game.locale.units].s_m; } -static char *FormatString(char *buff, const char *str, int64 *argv, uint casei, const char *last) +static char *FormatString(char *buff, const char *str, int64 *argv, uint casei, const char *last, bool dry_run) { + if (UsingNewGRFTextStack() && !dry_run) { + /* Values from the NewGRF text stack are only copied to the normal + * argv array at the time they are encountered. That means that if + * another string command references a value later in the string it + * would fail. We solve that by running FormatString twice. The first + * pass makes sure the argv array is correctly filled and the second + * pass can reference later values without problems. */ + struct TextRefStack *backup = CreateTextRefStackBackup(); + FormatString(buff, str, argv, casei, last, true); + RestoreTextRefStackBackup(backup); + } WChar b; int64 *argv_orig = argv; uint modifier = 0;