diff --git a/src/openrct2-ui/UiContext.Linux.cpp b/src/openrct2-ui/UiContext.Linux.cpp index 212b4b21a7..e7d5b74713 100644 --- a/src/openrct2-ui/UiContext.Linux.cpp +++ b/src/openrct2-ui/UiContext.Linux.cpp @@ -99,14 +99,14 @@ namespace OpenRCT2::Ui { case DIALOG_TYPE::KDIALOG: { - std::string cmd = String::Format( + std::string cmd = String::StdFormat( "%s --title \"OpenRCT2\" --msgbox \"%s\"", executablePath.c_str(), message.c_str()); Platform::Execute(cmd); break; } case DIALOG_TYPE::ZENITY: { - std::string cmd = String::Format( + std::string cmd = String::StdFormat( "%s --title=\"OpenRCT2\" --info --text=\"%s\"", executablePath.c_str(), message.c_str()); Platform::Execute(cmd); break; @@ -119,13 +119,13 @@ namespace OpenRCT2::Ui void OpenFolder(const std::string& path) override { - std::string cmd = String::Format("xdg-open %s", EscapePathForShell(path).c_str()); + std::string cmd = String::StdFormat("xdg-open %s", EscapePathForShell(path).c_str()); Platform::Execute(cmd); } void OpenURL(const std::string& url) override { - std::string cmd = String::Format("xdg-open %s", url.c_str()); + std::string cmd = String::StdFormat("xdg-open %s", url.c_str()); Platform::Execute(cmd); } @@ -227,7 +227,7 @@ namespace OpenRCT2::Ui case DIALOG_TYPE::KDIALOG: { std::string output; - std::string cmd = String::Format( + std::string cmd = String::StdFormat( "%s --title '%s' --getexistingdirectory /", executablePath.c_str(), title.c_str()); if (Platform::Execute(cmd, &output) == 0) { @@ -238,7 +238,7 @@ namespace OpenRCT2::Ui case DIALOG_TYPE::ZENITY: { std::string output; - std::string cmd = String::Format( + std::string cmd = String::StdFormat( "%s --title='%s' --file-selection --directory /", executablePath.c_str(), title.c_str()); if (Platform::Execute(cmd, &output) == 0) { @@ -295,14 +295,12 @@ namespace OpenRCT2::Ui case DIALOG_TYPE::ZENITY: { auto sb = StringBuilder(); - sb.Append(reinterpret_cast( - String::Format("zenity --list --column '' --width=%d --height=%d", width, height))); + sb.Append(String::StdFormat("zenity --list --column '' --width=%d --height=%d", width, height)); for (const auto& option : options) { - sb.Append(reinterpret_cast(String::Format(" '%s'", option.c_str()))); + sb.Append(String::StdFormat(" '%s'", option.c_str())); } - sb.Append( - reinterpret_cast(String::Format(" --title '%s' --text '%s'", title.c_str(), text.c_str()))); + sb.Append(String::StdFormat(" --title '%s' --text '%s'", title.c_str(), text.c_str())); std::string buff; Platform::Execute(sb.GetBuffer(), &buff); @@ -311,12 +309,11 @@ namespace OpenRCT2::Ui case DIALOG_TYPE::KDIALOG: { auto sb = StringBuilder(); - sb.Append(reinterpret_cast( - String::Format("kdialog --geometry %dx%d --title '%s' --menu ", width, height, title.c_str()))); - sb.Append(reinterpret_cast(String::Format(" '%s'", text.c_str()))); + sb.Append(String::StdFormat("kdialog --geometry %dx%d --title '%s' --menu ", width, height, title.c_str())); + sb.Append(String::StdFormat(" '%s'", text.c_str())); for (const auto& option : options) { - sb.Append(reinterpret_cast(String::Format(" '%s' '%s'", option.c_str(), option.c_str()))); + sb.Append(String::StdFormat(" '%s' '%s'", option.c_str(), option.c_str())); } std::string buff; diff --git a/src/openrct2/Diagnostic.cpp b/src/openrct2/Diagnostic.cpp index 0ec589871f..93a9203b8a 100644 --- a/src/openrct2/Diagnostic.cpp +++ b/src/openrct2/Diagnostic.cpp @@ -95,7 +95,7 @@ void diagnostic_log(DiagnosticLevel diagnosticLevel, const char* format, ...) // Message va_start(args, format); - auto msg = String::StdFormat_VA(format, args); + auto msg = String::Format_VA(format, args); va_end(args); diagnostic_print(diagnosticLevel, prefix, msg); @@ -122,7 +122,7 @@ void diagnostic_log_with_location( // Message va_start(args, format); - auto msg = String::StdFormat_VA(format, args); + auto msg = String::Format_VA(format, args); va_end(args); diagnostic_print(diagnosticLevel, prefix, msg); diff --git a/src/openrct2/config/Config.cpp b/src/openrct2/config/Config.cpp index 924ddc1f23..b9b852671f 100644 --- a/src/openrct2/config/Config.cpp +++ b/src/openrct2/config/Config.cpp @@ -755,7 +755,8 @@ namespace Config return false; } int32_t exit_status = Platform::Execute( - String::Format("%s '%s' --exclude-temp --output-dir '%s'", path.c_str(), installerPath.c_str(), targetPath.c_str()), + String::StdFormat( + "%s '%s' --exclude-temp --output-dir '%s'", path.c_str(), installerPath.c_str(), targetPath.c_str()), &output); log_info("Exit status %d", exit_status); return exit_status == 0; diff --git a/src/openrct2/core/Guard.cpp b/src/openrct2/core/Guard.cpp index 95a9790275..a65db44db1 100644 --- a/src/openrct2/core/Guard.cpp +++ b/src/openrct2/core/Guard.cpp @@ -78,15 +78,11 @@ namespace Guard Console::Error::WriteLine("Version: %s", gVersionInfoFull); // This is never freed, but acceptable considering we are about to crash out - utf8* formattedMessage = nullptr; + std::string formattedMessage; if (message != nullptr) { formattedMessage = String::Format_VA(message, args); - Console::Error::WriteLine(formattedMessage); - } - - if (formattedMessage != nullptr) - { + Console::Error::WriteLine(formattedMessage.c_str()); _lastAssertMessage = std::make_optional(formattedMessage); } @@ -107,7 +103,7 @@ namespace Guard { // Show message box if we are not building for testing char buffer[512]; - GetAssertMessage(buffer, sizeof(buffer), formattedMessage); + GetAssertMessage(buffer, sizeof(buffer), formattedMessage.c_str()); int32_t result = MessageBoxA(nullptr, buffer, OPENRCT2_NAME, MB_ABORTRETRYIGNORE | MB_ICONEXCLAMATION); if (result == IDABORT) { diff --git a/src/openrct2/core/String.cpp b/src/openrct2/core/String.cpp index dba3b928c9..61b86fcedb 100644 --- a/src/openrct2/core/String.cpp +++ b/src/openrct2/core/String.cpp @@ -43,25 +43,6 @@ namespace String return std::string(str); } - std::string StdFormat_VA(const utf8* format, va_list args) - { - auto buffer = Format_VA(format, args); - auto returnValue = ToStd(buffer); - Memory::Free(buffer); - return returnValue; - } - - std::string StdFormat(const utf8* format, ...) - { - va_list args; - va_start(args, format); - const utf8* buffer = Format_VA(format, args); - va_end(args); - std::string returnValue = ToStd(buffer); - Memory::Free(buffer); - return returnValue; - } - std::string ToUtf8(std::wstring_view src) { #ifdef _WIN32 @@ -343,66 +324,41 @@ namespace String return buffer; } - utf8* Format(const utf8* format, ...) + u8string StdFormat(const utf8* format, ...) { va_list args; va_start(args, format); - utf8* result = Format_VA(format, args); + auto result = Format_VA(format, args); va_end(args); return result; } - utf8* Format_VA(const utf8* format, va_list args) + u8string Format_VA(const utf8* format, va_list args) { - va_list args1, args2; - va_copy(args1, args); - va_copy(args2, args); + va_list copy; - // Try to format to a initial buffer, enlarge if not big enough - size_t bufferSize = 4096; - utf8* buffer = Memory::Allocate(bufferSize); + va_copy(copy, args); - // Start with initial buffer - int32_t len = vsnprintf(buffer, bufferSize, format, args); - if (len < 0) + // Find the required buffer length + const int32_t len = vsnprintf(nullptr, 0, format, copy); + + va_end(copy); + + if (len >= 0) { - Memory::Free(buffer); - va_end(args1); - va_end(args2); + // Create a buffer that is of the required length + std::string buffer(std::size_t(len) + 1, '\0'); - // An error occurred... - return nullptr; + vsnprintf(buffer.data(), buffer.size(), format, args); + + // vsnprintf writes a null terminator character, but std::string doesn't need one, so this resize is required + buffer.resize(len); + + return buffer; } - size_t requiredSize = static_cast(len) + 1; - if (requiredSize > bufferSize) - { - // Try again with bigger buffer - buffer = Memory::Reallocate(buffer, bufferSize); - len = vsnprintf(buffer, bufferSize, format, args); - if (len < 0) - { - Memory::Free(buffer); - va_end(args1); - va_end(args2); - - // An error occurred... - return nullptr; - } - } - else - { - // Reduce buffer size to only what was required - bufferSize = requiredSize; - buffer = Memory::Reallocate(buffer, bufferSize); - } - - // Ensure buffer is terminated - buffer[bufferSize - 1] = '\0'; - - va_end(args1); - va_end(args2); - return buffer; + log_warning("Encoding error occured"); + return u8string{}; } utf8* AppendFormat(utf8* buffer, size_t bufferSize, const utf8* format, ...) diff --git a/src/openrct2/core/String.hpp b/src/openrct2/core/String.hpp index e6eba8640c..549469389d 100644 --- a/src/openrct2/core/String.hpp +++ b/src/openrct2/core/String.hpp @@ -44,8 +44,6 @@ namespace String constexpr const utf8* Empty = ""; std::string ToStd(const utf8* str); - std::string StdFormat_VA(const utf8* format, va_list args); - std::string StdFormat(const utf8* format, ...); std::string ToUtf8(std::wstring_view src); std::wstring ToWideChar(std::string_view src); @@ -80,8 +78,8 @@ namespace String utf8* Set(utf8* buffer, size_t bufferSize, const utf8* src, size_t srcSize); utf8* Append(utf8* buffer, size_t bufferSize, const utf8* src); utf8* Format(utf8* buffer, size_t bufferSize, const utf8* format, ...); - utf8* Format(const utf8* format, ...); - utf8* Format_VA(const utf8* format, va_list args); + u8string StdFormat(const utf8* format, ...); + u8string Format_VA(const utf8* format, va_list args); utf8* AppendFormat(utf8* buffer, size_t bufferSize, const utf8* format, ...); utf8* Duplicate(const std::string& src); utf8* Duplicate(const utf8* src); diff --git a/src/openrct2/core/StringBuilder.cpp b/src/openrct2/core/StringBuilder.cpp index 4c7b9839fb..45fcd186ee 100644 --- a/src/openrct2/core/StringBuilder.cpp +++ b/src/openrct2/core/StringBuilder.cpp @@ -32,10 +32,10 @@ void StringBuilder::Append(codepoint_t codepoint) _buffer.insert(_buffer.end(), data.begin(), data.end()); } -void StringBuilder::Append(const utf8* text) +void StringBuilder::Append(std::string_view text) { - size_t textLength = String::SizeOf(text); - Append(text, textLength); + size_t textLength = text.length(); + Append(text.data(), textLength); } void StringBuilder::Append(const utf8* text, size_t textLength) diff --git a/src/openrct2/core/StringBuilder.h b/src/openrct2/core/StringBuilder.h index 1eab90ddd2..654c39259b 100644 --- a/src/openrct2/core/StringBuilder.h +++ b/src/openrct2/core/StringBuilder.h @@ -35,7 +35,7 @@ public: /** * Appends the given string to the current string. */ - void Append(const utf8* text); + void Append(std::string_view text); /** * Appends the given string of the given length to the current string. Essentially used to ignore null terminators or copy diff --git a/src/openrct2/interface/InteractiveConsole.cpp b/src/openrct2/interface/InteractiveConsole.cpp index 11e74eac9d..4019e855e9 100644 --- a/src/openrct2/interface/InteractiveConsole.cpp +++ b/src/openrct2/interface/InteractiveConsole.cpp @@ -2146,8 +2146,5 @@ void InteractiveConsole::WriteFormatLine(const char* format, ...) va_start(list, format); auto buffer = String::Format_VA(format, list); va_end(list); - - auto s = std::string(buffer); - std::free(buffer); - WriteLine(s); + WriteLine(buffer); } diff --git a/src/openrct2/title/TitleSequence.cpp b/src/openrct2/title/TitleSequence.cpp index 35bc7c1fed..ee7ea7a23c 100644 --- a/src/openrct2/title/TitleSequence.cpp +++ b/src/openrct2/title/TitleSequence.cpp @@ -501,16 +501,14 @@ namespace OpenRCT2::Title static std::string LegacyScriptWrite(const TitleSequence& seq) { - utf8 buffer[128]; auto sb = StringBuilder(128); - sb.Append("# SCRIPT FOR "); sb.Append(seq.Name.c_str()); sb.Append("\n"); for (const auto& seqCommand : seq.Commands) { std::visit( - [&buffer, &seq, &sb](auto&& command) { + [&seq, &sb](auto&& command) { using T = std::decay_t; if constexpr (std::is_same_v) { @@ -538,34 +536,28 @@ namespace OpenRCT2::Title } else if constexpr (std::is_same_v) { - String::Format(buffer, sizeof(buffer), "LOCATION %u %u", command.Location.X, command.Location.Y); - sb.Append(buffer); + sb.Append(String::StdFormat("LOCATION %u %u", command.Location.X, command.Location.Y)); } else if constexpr (std::is_same_v) { - String::Format(buffer, sizeof(buffer), "ROTATE %u", command.Rotations); - sb.Append(buffer); + sb.Append(String::StdFormat("ROTATE %u", command.Rotations)); } else if constexpr (std::is_same_v) { - String::Format(buffer, sizeof(buffer), "ZOOM %u", command.Zoom); - sb.Append(buffer); + sb.Append(String::StdFormat("ZOOM %u", command.Zoom)); } else if constexpr (std::is_same_v) { - String::Format(buffer, sizeof(buffer), "FOLLOW %u ", command.Follow.SpriteIndex); - sb.Append(buffer); + sb.Append(String::StdFormat("FOLLOW %u ", command.Follow.SpriteIndex)); sb.Append(command.Follow.SpriteName); } else if constexpr (std::is_same_v) { - String::Format(buffer, sizeof(buffer), "SPEED %u", command.Speed); - sb.Append(buffer); + sb.Append(String::StdFormat("SPEED %u", command.Speed)); } else if constexpr (std::is_same_v) { - String::Format(buffer, sizeof(buffer), "WAIT %u", command.Milliseconds); - sb.Append(buffer); + sb.Append(String::StdFormat("WAIT %u", command.Milliseconds)); } else if constexpr (std::is_same_v) {