diff --git a/README.md b/README.md index 7417327982..bfa68cf05a 100644 --- a/README.md +++ b/README.md @@ -528,6 +528,9 @@ See the comments in the source files in `src/3rdparty/md5` for the complete lice The implementations of Posix `getaddrinfo` and `getnameinfo` for OS/2 in `src/3rdparty/os2` are distributed partly under the GNU Lesser General Public License 2.1, and partly under the (3-clause) BSD license. The exact licensing terms can be found in `src/3rdparty/os2/getaddrinfo.c` resp. `src/3rdparty/os2/getnameinfo.c`. +The implementation of C++17 `std::optional` in `src/3rdparty/optional` is licensed under the Boost Software License - Version 1.0. +See `src/3rdparty/optional/LICENSE_1_0.txt` for the complete license text. + ## 4.0 Credits diff --git a/azure-pipelines/manifest.sh b/azure-pipelines/manifest.sh index 730a09283f..2703b37e56 100755 --- a/azure-pipelines/manifest.sh +++ b/azure-pipelines/manifest.sh @@ -65,6 +65,7 @@ output_files() { if [ ! -e ${FOLDER}/${filename}.md5sum ] || [ ! -e ${FOLDER}/${filename}.sha1sum ] || [ ! -e ${FOLDER}/${filename}.sha256sum ]; then echo "ERROR: missing checksum file for ${filename}" 1>&2 error="y" + shift continue fi diff --git a/media/baseset/translations.vbs b/media/baseset/translations.vbs index fffb577482..c167886930 100644 --- a/media/baseset/translations.vbs +++ b/media/baseset/translations.vbs @@ -63,10 +63,14 @@ Sub Lookup(ini_key, str_id, outfile) For Each file In folder.Files If UCase(FSO.GetExtensionName(file.Name)) = "TXT" Then Dim f - Set f = FSO.OpenTextFile(file.Path) + Set f = CreateObject("ADODB.Stream") + f.Charset = "utf-8" + f.LineSeparator = 10 ' Assume lines end with \n even for \r\n files + f.Open + f.LoadFromFile(file.Path) - Do Until f.atEndOfStream - line = f.ReadLine() + Do Until f.EOS + line = Replace(f.ReadText(-2), Chr(13), "") ' Read a line and remove any \r If InStr(1, line, "##isocode ") = 1 Then p = Split(line) @@ -80,8 +84,9 @@ Sub Lookup(ini_key, str_id, outfile) End If i = i + 1 End If - Loop + + f.Close End If Next @@ -89,7 +94,7 @@ Sub Lookup(ini_key, str_id, outfile) ISort output For Each line In output - outfile.Write line & vbCrLf + outfile.WriteText line, 1 Next End Sub @@ -100,7 +105,9 @@ Dim infile Set infile = FSO.OpenTextFile(inputfile) Dim outfile -Set outfile = FSO.CreateTextFile(outputfile, True) +Set outfile = CreateObject("ADODB.Stream") +outfile.Charset = "utf-8" +outfile.Open Do Until infile.atEndOfStream @@ -109,15 +116,30 @@ Do Until infile.atEndOfStream If InStr(1, line, "ORIG_EXTRA.GRF ") = 1 Then p = Split(line, "=") If Trim(p(1)) = "" Then - outfile.Write("ORIG_EXTRA.GRF = " & GetExtraGrfHash() & vbCrLf) + outfile.WriteText "ORIG_EXTRA.GRF = " & GetExtraGrfHash(), 1 Else - outfile.Write(line & vbCrLf) + outfile.WriteText line, 1 End If ElseIf InStr(1, line, "!! ") = 1 Then p = Split(line) Lookup p(1), p(2), outfile Else - outfile.Write(line & vbCrLf) + outfile.WriteText line, 1 End If Loop + +' UTF-8 Text ADO Stream includes BOM, so we need to remove it +Dim outfile_noBOM +Set outfile_noBOM = CreateObject("ADODB.Stream") +outfile_noBOM.Type = 1 +outfile_noBOM.Open + +' Copy Text stream to Binary stream, skiping the BOM +outfile.Position = 3 +outfile.CopyTo outfile_noBOM +outfile.Close + +' Write the Binary stream +outfile_noBOM.SaveToFile outputfile, 2 +outfile_noBOM.Close diff --git a/projects/openttd_vs140.vcxproj b/projects/openttd_vs140.vcxproj index 5265baeea3..72e561d522 100644 --- a/projects/openttd_vs140.vcxproj +++ b/projects/openttd_vs140.vcxproj @@ -1029,6 +1029,8 @@ + + diff --git a/projects/openttd_vs140.vcxproj.filters b/projects/openttd_vs140.vcxproj.filters index 9074375c01..fdc6af3d93 100644 --- a/projects/openttd_vs140.vcxproj.filters +++ b/projects/openttd_vs140.vcxproj.filters @@ -28,84 +28,87 @@ {c76ff9f1-1e62-46d8-8d55-000000000008} - + {c76ff9f1-1e62-46d8-8d55-000000000009} - + {c76ff9f1-1e62-46d8-8d55-000000000010} - + {c76ff9f1-1e62-46d8-8d55-000000000011} - + {c76ff9f1-1e62-46d8-8d55-000000000012} - + {c76ff9f1-1e62-46d8-8d55-000000000013} - + {c76ff9f1-1e62-46d8-8d55-000000000014} - + {c76ff9f1-1e62-46d8-8d55-000000000015} - + {c76ff9f1-1e62-46d8-8d55-000000000016} - + {c76ff9f1-1e62-46d8-8d55-000000000017} - + {c76ff9f1-1e62-46d8-8d55-000000000018} - + {c76ff9f1-1e62-46d8-8d55-000000000019} - + {c76ff9f1-1e62-46d8-8d55-000000000020} - + {c76ff9f1-1e62-46d8-8d55-000000000021} - + {c76ff9f1-1e62-46d8-8d55-000000000022} - + {c76ff9f1-1e62-46d8-8d55-000000000023} - + {c76ff9f1-1e62-46d8-8d55-000000000024} - + {c76ff9f1-1e62-46d8-8d55-000000000025} - + {c76ff9f1-1e62-46d8-8d55-000000000026} - + {c76ff9f1-1e62-46d8-8d55-000000000027} - + {c76ff9f1-1e62-46d8-8d55-000000000028} - + {c76ff9f1-1e62-46d8-8d55-000000000029} - + {c76ff9f1-1e62-46d8-8d55-000000000030} - + {c76ff9f1-1e62-46d8-8d55-000000000031} - + {c76ff9f1-1e62-46d8-8d55-000000000032} - + {c76ff9f1-1e62-46d8-8d55-000000000033} - + {c76ff9f1-1e62-46d8-8d55-000000000034} + + {c76ff9f1-1e62-46d8-8d55-000000000035} + @@ -2181,6 +2184,12 @@ MD5 + + Compat + + + Compat + Script diff --git a/projects/openttd_vs141.vcxproj b/projects/openttd_vs141.vcxproj index 1080c598b5..4a1c7f7364 100644 --- a/projects/openttd_vs141.vcxproj +++ b/projects/openttd_vs141.vcxproj @@ -1029,6 +1029,8 @@ + + diff --git a/projects/openttd_vs141.vcxproj.filters b/projects/openttd_vs141.vcxproj.filters index 9074375c01..fdc6af3d93 100644 --- a/projects/openttd_vs141.vcxproj.filters +++ b/projects/openttd_vs141.vcxproj.filters @@ -28,84 +28,87 @@ {c76ff9f1-1e62-46d8-8d55-000000000008} - + {c76ff9f1-1e62-46d8-8d55-000000000009} - + {c76ff9f1-1e62-46d8-8d55-000000000010} - + {c76ff9f1-1e62-46d8-8d55-000000000011} - + {c76ff9f1-1e62-46d8-8d55-000000000012} - + {c76ff9f1-1e62-46d8-8d55-000000000013} - + {c76ff9f1-1e62-46d8-8d55-000000000014} - + {c76ff9f1-1e62-46d8-8d55-000000000015} - + {c76ff9f1-1e62-46d8-8d55-000000000016} - + {c76ff9f1-1e62-46d8-8d55-000000000017} - + {c76ff9f1-1e62-46d8-8d55-000000000018} - + {c76ff9f1-1e62-46d8-8d55-000000000019} - + {c76ff9f1-1e62-46d8-8d55-000000000020} - + {c76ff9f1-1e62-46d8-8d55-000000000021} - + {c76ff9f1-1e62-46d8-8d55-000000000022} - + {c76ff9f1-1e62-46d8-8d55-000000000023} - + {c76ff9f1-1e62-46d8-8d55-000000000024} - + {c76ff9f1-1e62-46d8-8d55-000000000025} - + {c76ff9f1-1e62-46d8-8d55-000000000026} - + {c76ff9f1-1e62-46d8-8d55-000000000027} - + {c76ff9f1-1e62-46d8-8d55-000000000028} - + {c76ff9f1-1e62-46d8-8d55-000000000029} - + {c76ff9f1-1e62-46d8-8d55-000000000030} - + {c76ff9f1-1e62-46d8-8d55-000000000031} - + {c76ff9f1-1e62-46d8-8d55-000000000032} - + {c76ff9f1-1e62-46d8-8d55-000000000033} - + {c76ff9f1-1e62-46d8-8d55-000000000034} + + {c76ff9f1-1e62-46d8-8d55-000000000035} + @@ -2181,6 +2184,12 @@ MD5 + + Compat + + + Compat + Script diff --git a/projects/openttd_vs142.vcxproj b/projects/openttd_vs142.vcxproj index d667d77153..2655508e3b 100644 --- a/projects/openttd_vs142.vcxproj +++ b/projects/openttd_vs142.vcxproj @@ -100,7 +100,7 @@ - /J /Zc:throwingNew /std:c++latest %(AdditionalOptions) + /J /Zc:throwingNew /std:c++latest /Zc:__cplusplus %(AdditionalOptions) Full AnySuitable true @@ -168,7 +168,7 @@ - /J /Zc:throwingNew /std:c++latest %(AdditionalOptions) + /J /Zc:throwingNew /std:c++latest /Zc:__cplusplus %(AdditionalOptions) Disabled true ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories) @@ -223,7 +223,7 @@ - /J /Zc:throwingNew /std:c++latest %(AdditionalOptions) + /J /Zc:throwingNew /std:c++latest /Zc:__cplusplus %(AdditionalOptions) Full AnySuitable true @@ -289,7 +289,7 @@ - /J /Zc:throwingNew /std:c++latest %(AdditionalOptions) + /J /Zc:throwingNew /std:c++latest /Zc:__cplusplus %(AdditionalOptions) Disabled true ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories) @@ -1029,6 +1029,8 @@ + + diff --git a/projects/openttd_vs142.vcxproj.filters b/projects/openttd_vs142.vcxproj.filters index 9074375c01..fdc6af3d93 100644 --- a/projects/openttd_vs142.vcxproj.filters +++ b/projects/openttd_vs142.vcxproj.filters @@ -28,84 +28,87 @@ {c76ff9f1-1e62-46d8-8d55-000000000008} - + {c76ff9f1-1e62-46d8-8d55-000000000009} - + {c76ff9f1-1e62-46d8-8d55-000000000010} - + {c76ff9f1-1e62-46d8-8d55-000000000011} - + {c76ff9f1-1e62-46d8-8d55-000000000012} - + {c76ff9f1-1e62-46d8-8d55-000000000013} - + {c76ff9f1-1e62-46d8-8d55-000000000014} - + {c76ff9f1-1e62-46d8-8d55-000000000015} - + {c76ff9f1-1e62-46d8-8d55-000000000016} - + {c76ff9f1-1e62-46d8-8d55-000000000017} - + {c76ff9f1-1e62-46d8-8d55-000000000018} - + {c76ff9f1-1e62-46d8-8d55-000000000019} - + {c76ff9f1-1e62-46d8-8d55-000000000020} - + {c76ff9f1-1e62-46d8-8d55-000000000021} - + {c76ff9f1-1e62-46d8-8d55-000000000022} - + {c76ff9f1-1e62-46d8-8d55-000000000023} - + {c76ff9f1-1e62-46d8-8d55-000000000024} - + {c76ff9f1-1e62-46d8-8d55-000000000025} - + {c76ff9f1-1e62-46d8-8d55-000000000026} - + {c76ff9f1-1e62-46d8-8d55-000000000027} - + {c76ff9f1-1e62-46d8-8d55-000000000028} - + {c76ff9f1-1e62-46d8-8d55-000000000029} - + {c76ff9f1-1e62-46d8-8d55-000000000030} - + {c76ff9f1-1e62-46d8-8d55-000000000031} - + {c76ff9f1-1e62-46d8-8d55-000000000032} - + {c76ff9f1-1e62-46d8-8d55-000000000033} - + {c76ff9f1-1e62-46d8-8d55-000000000034} + + {c76ff9f1-1e62-46d8-8d55-000000000035} + @@ -2181,6 +2184,12 @@ MD5 + + Compat + + + Compat + Script diff --git a/projects/openttd_vs142.vcxproj.in b/projects/openttd_vs142.vcxproj.in index 83befcd8d0..6941b3450b 100644 --- a/projects/openttd_vs142.vcxproj.in +++ b/projects/openttd_vs142.vcxproj.in @@ -100,7 +100,7 @@ - /J /Zc:throwingNew /std:c++latest %(AdditionalOptions) + /J /Zc:throwingNew /std:c++latest /Zc:__cplusplus %(AdditionalOptions) Full AnySuitable true @@ -168,7 +168,7 @@ - /J /Zc:throwingNew /std:c++latest %(AdditionalOptions) + /J /Zc:throwingNew /std:c++latest /Zc:__cplusplus %(AdditionalOptions) Disabled true ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories) @@ -223,7 +223,7 @@ - /J /Zc:throwingNew /std:c++latest %(AdditionalOptions) + /J /Zc:throwingNew /std:c++latest /Zc:__cplusplus %(AdditionalOptions) Full AnySuitable true @@ -289,7 +289,7 @@ - /J /Zc:throwingNew /std:c++latest %(AdditionalOptions) + /J /Zc:throwingNew /std:c++latest /Zc:__cplusplus %(AdditionalOptions) Disabled true ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories) diff --git a/projects/settingsgen_vs142.vcxproj b/projects/settingsgen_vs142.vcxproj index 23a4e18562..fb2f7a731e 100644 --- a/projects/settingsgen_vs142.vcxproj +++ b/projects/settingsgen_vs142.vcxproj @@ -39,6 +39,7 @@ %(Inputs) + /std:c++latest /Zc:__cplusplus %(AdditionalOptions) MinSpace Size SETTINGSGEN;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) diff --git a/source.list b/source.list index b7d2f21fd9..49fc02accc 100644 --- a/source.list +++ b/source.list @@ -747,6 +747,10 @@ table/water_land.h 3rdparty/md5/md5.cpp 3rdparty/md5/md5.h +# Compat +3rdparty/optional/optional.hpp +3rdparty/optional/ottd_optional.h + # Script script/script_config.cpp script/script_config.hpp diff --git a/src/3rdparty/optional/LICENSE_1_0.txt b/src/3rdparty/optional/LICENSE_1_0.txt new file mode 100644 index 0000000000..36b7cd93cd --- /dev/null +++ b/src/3rdparty/optional/LICENSE_1_0.txt @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/3rdparty/optional/optional.hpp b/src/3rdparty/optional/optional.hpp new file mode 100644 index 0000000000..fe1832b2ae --- /dev/null +++ b/src/3rdparty/optional/optional.hpp @@ -0,0 +1,1066 @@ +// Copyright (C) 2011 - 2012 Andrzej Krzemienski. +// +// Use, modification, and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// The idea and interface is based on Boost.Optional library +// authored by Fernando Luis Cacciola Carballal + +# ifndef ___OPTIONAL_HPP___ +# define ___OPTIONAL_HPP___ + +# include +# include +# include +# include +# include +# include +# include + +# define TR2_OPTIONAL_REQUIRES(...) typename enable_if<__VA_ARGS__::value, bool>::type = false + +# if defined __GNUC__ // NOTE: GNUC is also defined for Clang +# if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 8) +# define TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ +# elif (__GNUC__ > 4) +# define TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ +# endif +# +# if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 7) +# define TR2_OPTIONAL_GCC_4_7_AND_HIGHER___ +# elif (__GNUC__ > 4) +# define TR2_OPTIONAL_GCC_4_7_AND_HIGHER___ +# endif +# +# if (__GNUC__ == 4) && (__GNUC_MINOR__ == 8) && (__GNUC_PATCHLEVEL__ >= 1) +# define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ +# elif (__GNUC__ == 4) && (__GNUC_MINOR__ >= 9) +# define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ +# elif (__GNUC__ > 4) +# define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ +# endif +# endif +# +# if defined __clang_major__ +# if (__clang_major__ == 3 && __clang_minor__ >= 5) +# define TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ +# elif (__clang_major__ > 3) +# define TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ +# endif +# if defined TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ +# define TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ +# elif (__clang_major__ == 3 && __clang_minor__ == 4 && __clang_patchlevel__ >= 2) +# define TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ +# endif +# endif +# +# if defined _MSC_VER +# if (_MSC_VER >= 1900) +# define TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ +# endif +# endif + +# if defined __clang__ +# if (__clang_major__ > 2) || (__clang_major__ == 2) && (__clang_minor__ >= 9) +# define OPTIONAL_HAS_THIS_RVALUE_REFS 1 +# else +# define OPTIONAL_HAS_THIS_RVALUE_REFS 0 +# endif +# elif defined TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ +# define OPTIONAL_HAS_THIS_RVALUE_REFS 1 +# elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ +# define OPTIONAL_HAS_THIS_RVALUE_REFS 1 +# else +# define OPTIONAL_HAS_THIS_RVALUE_REFS 0 +# endif + + +# if defined TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ +# define OPTIONAL_HAS_CONSTEXPR_INIT_LIST 1 +# define OPTIONAL_CONSTEXPR_INIT_LIST constexpr +# else +# define OPTIONAL_HAS_CONSTEXPR_INIT_LIST 0 +# define OPTIONAL_CONSTEXPR_INIT_LIST +# endif + +# if defined TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ && (defined __cplusplus) && (__cplusplus != 201103L) +# define OPTIONAL_HAS_MOVE_ACCESSORS 1 +# else +# define OPTIONAL_HAS_MOVE_ACCESSORS 0 +# endif + +# // In C++11 constexpr implies const, so we need to make non-const members also non-constexpr +# if (defined __cplusplus) && (__cplusplus == 201103L) +# define OPTIONAL_MUTABLE_CONSTEXPR +# else +# define OPTIONAL_MUTABLE_CONSTEXPR constexpr +# endif + +namespace std{ + +namespace experimental{ + +// BEGIN workaround for missing is_trivially_destructible +# if defined TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ + // leave it: it is already there +# elif defined TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ + // leave it: it is already there +# elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ + // leave it: it is already there +# elif defined TR2_OPTIONAL_DISABLE_EMULATION_OF_TYPE_TRAITS + // leave it: the user doesn't want it +# else + template + using is_trivially_destructible = std::has_trivial_destructor; +# endif +// END workaround for missing is_trivially_destructible + +# if (defined TR2_OPTIONAL_GCC_4_7_AND_HIGHER___) + // leave it; our metafunctions are already defined. +# elif defined TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ + // leave it; our metafunctions are already defined. +# elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ + // leave it: it is already there +# elif defined TR2_OPTIONAL_DISABLE_EMULATION_OF_TYPE_TRAITS + // leave it: the user doesn't want it +# else + + +// workaround for missing traits in GCC and CLANG +template +struct is_nothrow_move_constructible +{ + constexpr static bool value = std::is_nothrow_constructible::value; +}; + + +template +struct is_assignable +{ + template + constexpr static bool has_assign(...) { return false; } + + template () = std::declval(), true)) > + // the comma operator is necessary for the cases where operator= returns void + constexpr static bool has_assign(bool) { return true; } + + constexpr static bool value = has_assign(true); +}; + + +template +struct is_nothrow_move_assignable +{ + template + struct has_nothrow_move_assign { + constexpr static bool value = false; + }; + + template + struct has_nothrow_move_assign { + constexpr static bool value = noexcept( std::declval() = std::declval() ); + }; + + constexpr static bool value = has_nothrow_move_assign::value>::value; +}; +// end workaround + + +# endif + + + +// 20.5.4, optional for object types +template class optional; + +// 20.5.5, optional for lvalue reference types +template class optional; + + +// workaround: std utility functions aren't constexpr yet +template inline constexpr T&& constexpr_forward(typename std::remove_reference::type& t) noexcept +{ + return static_cast(t); +} + +template inline constexpr T&& constexpr_forward(typename std::remove_reference::type&& t) noexcept +{ + static_assert(!std::is_lvalue_reference::value, "!!"); + return static_cast(t); +} + +template inline constexpr typename std::remove_reference::type&& constexpr_move(T&& t) noexcept +{ + return static_cast::type&&>(t); +} + + +#if defined NDEBUG +# define TR2_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) (EXPR) +#else +# define TR2_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) ((CHECK) ? (EXPR) : ([]{assert(!#CHECK);}(), (EXPR))) +#endif + + +namespace detail_ +{ + +// static_addressof: a constexpr version of addressof +template +struct has_overloaded_addressof +{ + template + constexpr static bool has_overload(...) { return false; } + + template ().operator&()) > + constexpr static bool has_overload(bool) { return true; } + + constexpr static bool value = has_overload(true); +}; + +template )> +constexpr T* static_addressof(T& ref) +{ + return &ref; +} + +template )> +T* static_addressof(T& ref) +{ + return std::addressof(ref); +} + + +// the call to convert(b) has return type A and converts b to type A iff b decltype(b) is implicitly convertible to A +template +constexpr U convert(U v) { return v; } + + +namespace swap_ns +{ + using std::swap; + + template + void adl_swap(T& t, T& u) noexcept(noexcept(swap(t, u))) + { + swap(t, u); + } + +} // namespace swap_ns + +} // namespace detail + + +constexpr struct trivial_init_t{} trivial_init{}; + + +// 20.5.6, In-place construction +constexpr struct in_place_t{} in_place{}; + + +// 20.5.7, Disengaged state indicator +struct nullopt_t +{ + struct init{}; + constexpr explicit nullopt_t(init){} +}; +constexpr nullopt_t nullopt{nullopt_t::init()}; + + +// 20.5.8, class bad_optional_access +class bad_optional_access : public logic_error { +public: + explicit bad_optional_access(const string& what_arg) : logic_error{what_arg} {} + explicit bad_optional_access(const char* what_arg) : logic_error{what_arg} {} +}; + + +template +union storage_t +{ + unsigned char dummy_; + T value_; + + constexpr storage_t( trivial_init_t ) noexcept : dummy_() {}; + + template + constexpr storage_t( Args&&... args ) : value_(constexpr_forward(args)...) {} + + ~storage_t(){} +}; + + +template +union constexpr_storage_t +{ + unsigned char dummy_; + T value_; + + constexpr constexpr_storage_t( trivial_init_t ) noexcept : dummy_() {}; + + template + constexpr constexpr_storage_t( Args&&... args ) : value_(constexpr_forward(args)...) {} + + ~constexpr_storage_t() = default; +}; + + +template +struct optional_base +{ + bool init_; + storage_t storage_; + + constexpr optional_base() noexcept : init_(false), storage_(trivial_init) {}; + + explicit constexpr optional_base(const T& v) : init_(true), storage_(v) {} + + explicit constexpr optional_base(T&& v) : init_(true), storage_(constexpr_move(v)) {} + + template explicit optional_base(in_place_t, Args&&... args) + : init_(true), storage_(constexpr_forward(args)...) {} + + template >)> + explicit optional_base(in_place_t, std::initializer_list il, Args&&... args) + : init_(true), storage_(il, std::forward(args)...) {} + + ~optional_base() { if (init_) storage_.value_.T::~T(); } +}; + + +template +struct constexpr_optional_base +{ + bool init_; + constexpr_storage_t storage_; + + constexpr constexpr_optional_base() noexcept : init_(false), storage_(trivial_init) {}; + + explicit constexpr constexpr_optional_base(const T& v) : init_(true), storage_(v) {} + + explicit constexpr constexpr_optional_base(T&& v) : init_(true), storage_(constexpr_move(v)) {} + + template explicit constexpr constexpr_optional_base(in_place_t, Args&&... args) + : init_(true), storage_(constexpr_forward(args)...) {} + + template >)> + OPTIONAL_CONSTEXPR_INIT_LIST explicit constexpr_optional_base(in_place_t, std::initializer_list il, Args&&... args) + : init_(true), storage_(il, std::forward(args)...) {} + + ~constexpr_optional_base() = default; +}; + +template +using OptionalBase = typename std::conditional< + is_trivially_destructible::value, // if possible + constexpr_optional_base::type>, // use base with trivial destructor + optional_base::type> +>::type; + + + +template +class optional : private OptionalBase +{ + static_assert( !std::is_same::type, nullopt_t>::value, "bad T" ); + static_assert( !std::is_same::type, in_place_t>::value, "bad T" ); + + + constexpr bool initialized() const noexcept { return OptionalBase::init_; } + typename std::remove_const::type* dataptr() { return std::addressof(OptionalBase::storage_.value_); } + constexpr const T* dataptr() const { return detail_::static_addressof(OptionalBase::storage_.value_); } + +# if OPTIONAL_HAS_THIS_RVALUE_REFS == 1 + constexpr const T& contained_val() const& { return OptionalBase::storage_.value_; } +# if OPTIONAL_HAS_MOVE_ACCESSORS == 1 + OPTIONAL_MUTABLE_CONSTEXPR T&& contained_val() && { return std::move(OptionalBase::storage_.value_); } + OPTIONAL_MUTABLE_CONSTEXPR T& contained_val() & { return OptionalBase::storage_.value_; } +# else + T& contained_val() & { return OptionalBase::storage_.value_; } + T&& contained_val() && { return std::move(OptionalBase::storage_.value_); } +# endif +# else + constexpr const T& contained_val() const { return OptionalBase::storage_.value_; } + T& contained_val() { return OptionalBase::storage_.value_; } +# endif + + void clear() noexcept { + if (initialized()) dataptr()->T::~T(); + OptionalBase::init_ = false; + } + + template + void initialize(Args&&... args) noexcept(noexcept(T(std::forward(args)...))) + { + assert(!OptionalBase::init_); + ::new (static_cast(dataptr())) T(std::forward(args)...); + OptionalBase::init_ = true; + } + + template + void initialize(std::initializer_list il, Args&&... args) noexcept(noexcept(T(il, std::forward(args)...))) + { + assert(!OptionalBase::init_); + ::new (static_cast(dataptr())) T(il, std::forward(args)...); + OptionalBase::init_ = true; + } + +public: + typedef T value_type; + + // 20.5.5.1, constructors + constexpr optional() noexcept : OptionalBase() {}; + constexpr optional(nullopt_t) noexcept : OptionalBase() {}; + + optional(const optional& rhs) + : OptionalBase() + { + if (rhs.initialized()) { + ::new (static_cast(dataptr())) T(*rhs); + OptionalBase::init_ = true; + } + } + + optional(optional&& rhs) noexcept(is_nothrow_move_constructible::value) + : OptionalBase() + { + if (rhs.initialized()) { + ::new (static_cast(dataptr())) T(std::move(*rhs)); + OptionalBase::init_ = true; + } + } + + constexpr optional(const T& v) : OptionalBase(v) {} + + constexpr optional(T&& v) : OptionalBase(constexpr_move(v)) {} + + template + explicit constexpr optional(in_place_t, Args&&... args) + : OptionalBase(in_place_t{}, constexpr_forward(args)...) {} + + template >)> + OPTIONAL_CONSTEXPR_INIT_LIST explicit optional(in_place_t, std::initializer_list il, Args&&... args) + : OptionalBase(in_place_t{}, il, constexpr_forward(args)...) {} + + // 20.5.4.2, Destructor + ~optional() = default; + + // 20.5.4.3, assignment + optional& operator=(nullopt_t) noexcept + { + clear(); + return *this; + } + + optional& operator=(const optional& rhs) + { + if (initialized() == true && rhs.initialized() == false) clear(); + else if (initialized() == false && rhs.initialized() == true) initialize(*rhs); + else if (initialized() == true && rhs.initialized() == true) contained_val() = *rhs; + return *this; + } + + optional& operator=(optional&& rhs) + noexcept(is_nothrow_move_assignable::value && is_nothrow_move_constructible::value) + { + if (initialized() == true && rhs.initialized() == false) clear(); + else if (initialized() == false && rhs.initialized() == true) initialize(std::move(*rhs)); + else if (initialized() == true && rhs.initialized() == true) contained_val() = std::move(*rhs); + return *this; + } + + template + auto operator=(U&& v) + -> typename enable_if + < + is_same::type, T>::value, + optional& + >::type + { + if (initialized()) { contained_val() = std::forward(v); } + else { initialize(std::forward(v)); } + return *this; + } + + + template + void emplace(Args&&... args) + { + clear(); + initialize(std::forward(args)...); + } + + template + void emplace(initializer_list il, Args&&... args) + { + clear(); + initialize(il, std::forward(args)...); + } + + // 20.5.4.4, Swap + void swap(optional& rhs) noexcept(is_nothrow_move_constructible::value + && noexcept(detail_::swap_ns::adl_swap(declval(), declval()))) + { + if (initialized() == true && rhs.initialized() == false) { rhs.initialize(std::move(**this)); clear(); } + else if (initialized() == false && rhs.initialized() == true) { initialize(std::move(*rhs)); rhs.clear(); } + else if (initialized() == true && rhs.initialized() == true) { using std::swap; swap(**this, *rhs); } + } + + // 20.5.4.5, Observers + + explicit constexpr operator bool() const noexcept { return initialized(); } + constexpr bool has_value() const noexcept { return initialized(); } + + constexpr T const* operator ->() const { + return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), dataptr()); + } + +# if OPTIONAL_HAS_MOVE_ACCESSORS == 1 + + OPTIONAL_MUTABLE_CONSTEXPR T* operator ->() { + assert (initialized()); + return dataptr(); + } + + constexpr T const& operator *() const& { + return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), contained_val()); + } + + OPTIONAL_MUTABLE_CONSTEXPR T& operator *() & { + assert (initialized()); + return contained_val(); + } + + OPTIONAL_MUTABLE_CONSTEXPR T&& operator *() && { + assert (initialized()); + return constexpr_move(contained_val()); + } + + constexpr T const& value() const& { + return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); + } + + OPTIONAL_MUTABLE_CONSTEXPR T& value() & { + return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); + } + + OPTIONAL_MUTABLE_CONSTEXPR T&& value() && { + if (!initialized()) throw bad_optional_access("bad optional access"); + return std::move(contained_val()); + } + +# else + + T* operator ->() { + assert (initialized()); + return dataptr(); + } + + constexpr T const& operator *() const { + return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), contained_val()); + } + + T& operator *() { + assert (initialized()); + return contained_val(); + } + + constexpr T const& value() const { + return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); + } + + T& value() { + return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); + } + +# endif + +# if OPTIONAL_HAS_THIS_RVALUE_REFS == 1 + + template + constexpr T value_or(V&& v) const& + { + return *this ? **this : detail_::convert(constexpr_forward(v)); + } + +# if OPTIONAL_HAS_MOVE_ACCESSORS == 1 + + template + OPTIONAL_MUTABLE_CONSTEXPR T value_or(V&& v) && + { + return *this ? constexpr_move(const_cast&>(*this).contained_val()) : detail_::convert(constexpr_forward(v)); + } + +# else + + template + T value_or(V&& v) && + { + return *this ? constexpr_move(const_cast&>(*this).contained_val()) : detail_::convert(constexpr_forward(v)); + } + +# endif + +# else + + template + constexpr T value_or(V&& v) const + { + return *this ? **this : detail_::convert(constexpr_forward(v)); + } + +# endif + + // 20.6.3.6, modifiers + void reset() noexcept { clear(); } +}; + + +template +class optional +{ + static_assert( !std::is_same::value, "bad T" ); + static_assert( !std::is_same::value, "bad T" ); + T* ref; + +public: + + // 20.5.5.1, construction/destruction + constexpr optional() noexcept : ref(nullptr) {} + + constexpr optional(nullopt_t) noexcept : ref(nullptr) {} + + constexpr optional(T& v) noexcept : ref(detail_::static_addressof(v)) {} + + optional(T&&) = delete; + + constexpr optional(const optional& rhs) noexcept : ref(rhs.ref) {} + + explicit constexpr optional(in_place_t, T& v) noexcept : ref(detail_::static_addressof(v)) {} + + explicit optional(in_place_t, T&&) = delete; + + ~optional() = default; + + // 20.5.5.2, mutation + optional& operator=(nullopt_t) noexcept { + ref = nullptr; + return *this; + } + + // optional& operator=(const optional& rhs) noexcept { + // ref = rhs.ref; + // return *this; + // } + + // optional& operator=(optional&& rhs) noexcept { + // ref = rhs.ref; + // return *this; + // } + + template + auto operator=(U&& rhs) noexcept + -> typename enable_if + < + is_same::type, optional>::value, + optional& + >::type + { + ref = rhs.ref; + return *this; + } + + template + auto operator=(U&& rhs) noexcept + -> typename enable_if + < + !is_same::type, optional>::value, + optional& + >::type + = delete; + + void emplace(T& v) noexcept { + ref = detail_::static_addressof(v); + } + + void emplace(T&&) = delete; + + + void swap(optional& rhs) noexcept + { + std::swap(ref, rhs.ref); + } + + // 20.5.5.3, observers + constexpr T* operator->() const { + return TR2_OPTIONAL_ASSERTED_EXPRESSION(ref, ref); + } + + constexpr T& operator*() const { + return TR2_OPTIONAL_ASSERTED_EXPRESSION(ref, *ref); + } + + constexpr T& value() const { + return ref ? *ref : (throw bad_optional_access("bad optional access"), *ref); + } + + explicit constexpr operator bool() const noexcept { + return ref != nullptr; + } + + constexpr bool has_value() const noexcept { + return ref != nullptr; + } + + template + constexpr typename decay::type value_or(V&& v) const + { + return *this ? **this : detail_::convert::type>(constexpr_forward(v)); + } + + // x.x.x.x, modifiers + void reset() noexcept { ref = nullptr; } +}; + + +template +class optional +{ + static_assert( sizeof(T) == 0, "optional rvalue references disallowed" ); +}; + + +// 20.5.8, Relational operators +template constexpr bool operator==(const optional& x, const optional& y) +{ + return bool(x) != bool(y) ? false : bool(x) == false ? true : *x == *y; +} + +template constexpr bool operator!=(const optional& x, const optional& y) +{ + return !(x == y); +} + +template constexpr bool operator<(const optional& x, const optional& y) +{ + return (!y) ? false : (!x) ? true : *x < *y; +} + +template constexpr bool operator>(const optional& x, const optional& y) +{ + return (y < x); +} + +template constexpr bool operator<=(const optional& x, const optional& y) +{ + return !(y < x); +} + +template constexpr bool operator>=(const optional& x, const optional& y) +{ + return !(x < y); +} + + +// 20.5.9, Comparison with nullopt +template constexpr bool operator==(const optional& x, nullopt_t) noexcept +{ + return (!x); +} + +template constexpr bool operator==(nullopt_t, const optional& x) noexcept +{ + return (!x); +} + +template constexpr bool operator!=(const optional& x, nullopt_t) noexcept +{ + return bool(x); +} + +template constexpr bool operator!=(nullopt_t, const optional& x) noexcept +{ + return bool(x); +} + +template constexpr bool operator<(const optional&, nullopt_t) noexcept +{ + return false; +} + +template constexpr bool operator<(nullopt_t, const optional& x) noexcept +{ + return bool(x); +} + +template constexpr bool operator<=(const optional& x, nullopt_t) noexcept +{ + return (!x); +} + +template constexpr bool operator<=(nullopt_t, const optional&) noexcept +{ + return true; +} + +template constexpr bool operator>(const optional& x, nullopt_t) noexcept +{ + return bool(x); +} + +template constexpr bool operator>(nullopt_t, const optional&) noexcept +{ + return false; +} + +template constexpr bool operator>=(const optional&, nullopt_t) noexcept +{ + return true; +} + +template constexpr bool operator>=(nullopt_t, const optional& x) noexcept +{ + return (!x); +} + + + +// 20.5.10, Comparison with T +template constexpr bool operator==(const optional& x, const T& v) +{ + return bool(x) ? *x == v : false; +} + +template constexpr bool operator==(const T& v, const optional& x) +{ + return bool(x) ? v == *x : false; +} + +template constexpr bool operator!=(const optional& x, const T& v) +{ + return bool(x) ? *x != v : true; +} + +template constexpr bool operator!=(const T& v, const optional& x) +{ + return bool(x) ? v != *x : true; +} + +template constexpr bool operator<(const optional& x, const T& v) +{ + return bool(x) ? *x < v : true; +} + +template constexpr bool operator>(const T& v, const optional& x) +{ + return bool(x) ? v > *x : true; +} + +template constexpr bool operator>(const optional& x, const T& v) +{ + return bool(x) ? *x > v : false; +} + +template constexpr bool operator<(const T& v, const optional& x) +{ + return bool(x) ? v < *x : false; +} + +template constexpr bool operator>=(const optional& x, const T& v) +{ + return bool(x) ? *x >= v : false; +} + +template constexpr bool operator<=(const T& v, const optional& x) +{ + return bool(x) ? v <= *x : false; +} + +template constexpr bool operator<=(const optional& x, const T& v) +{ + return bool(x) ? *x <= v : true; +} + +template constexpr bool operator>=(const T& v, const optional& x) +{ + return bool(x) ? v >= *x : true; +} + + +// Comparison of optional with T +template constexpr bool operator==(const optional& x, const T& v) +{ + return bool(x) ? *x == v : false; +} + +template constexpr bool operator==(const T& v, const optional& x) +{ + return bool(x) ? v == *x : false; +} + +template constexpr bool operator!=(const optional& x, const T& v) +{ + return bool(x) ? *x != v : true; +} + +template constexpr bool operator!=(const T& v, const optional& x) +{ + return bool(x) ? v != *x : true; +} + +template constexpr bool operator<(const optional& x, const T& v) +{ + return bool(x) ? *x < v : true; +} + +template constexpr bool operator>(const T& v, const optional& x) +{ + return bool(x) ? v > *x : true; +} + +template constexpr bool operator>(const optional& x, const T& v) +{ + return bool(x) ? *x > v : false; +} + +template constexpr bool operator<(const T& v, const optional& x) +{ + return bool(x) ? v < *x : false; +} + +template constexpr bool operator>=(const optional& x, const T& v) +{ + return bool(x) ? *x >= v : false; +} + +template constexpr bool operator<=(const T& v, const optional& x) +{ + return bool(x) ? v <= *x : false; +} + +template constexpr bool operator<=(const optional& x, const T& v) +{ + return bool(x) ? *x <= v : true; +} + +template constexpr bool operator>=(const T& v, const optional& x) +{ + return bool(x) ? v >= *x : true; +} + +// Comparison of optional with T +template constexpr bool operator==(const optional& x, const T& v) +{ + return bool(x) ? *x == v : false; +} + +template constexpr bool operator==(const T& v, const optional& x) +{ + return bool(x) ? v == *x : false; +} + +template constexpr bool operator!=(const optional& x, const T& v) +{ + return bool(x) ? *x != v : true; +} + +template constexpr bool operator!=(const T& v, const optional& x) +{ + return bool(x) ? v != *x : true; +} + +template constexpr bool operator<(const optional& x, const T& v) +{ + return bool(x) ? *x < v : true; +} + +template constexpr bool operator>(const T& v, const optional& x) +{ + return bool(x) ? v > *x : true; +} + +template constexpr bool operator>(const optional& x, const T& v) +{ + return bool(x) ? *x > v : false; +} + +template constexpr bool operator<(const T& v, const optional& x) +{ + return bool(x) ? v < *x : false; +} + +template constexpr bool operator>=(const optional& x, const T& v) +{ + return bool(x) ? *x >= v : false; +} + +template constexpr bool operator<=(const T& v, const optional& x) +{ + return bool(x) ? v <= *x : false; +} + +template constexpr bool operator<=(const optional& x, const T& v) +{ + return bool(x) ? *x <= v : true; +} + +template constexpr bool operator>=(const T& v, const optional& x) +{ + return bool(x) ? v >= *x : true; +} + + +// 20.5.12, Specialized algorithms +template +void swap(optional& x, optional& y) noexcept(noexcept(x.swap(y))) +{ + x.swap(y); +} + + +template +constexpr optional::type> make_optional(T&& v) +{ + return optional::type>(constexpr_forward(v)); +} + +template +constexpr optional make_optional(reference_wrapper v) +{ + return optional(v.get()); +} + + +} // namespace experimental +} // namespace std + +namespace std +{ + template + struct hash> + { + typedef typename hash::result_type result_type; + typedef std::experimental::optional argument_type; + + constexpr result_type operator()(argument_type const& arg) const { + return arg ? std::hash{}(*arg) : result_type{}; + } + }; + + template + struct hash> + { + typedef typename hash::result_type result_type; + typedef std::experimental::optional argument_type; + + constexpr result_type operator()(argument_type const& arg) const { + return arg ? std::hash{}(*arg) : result_type{}; + } + }; +} + +# undef TR2_OPTIONAL_REQUIRES +# undef TR2_OPTIONAL_ASSERTED_EXPRESSION + +# endif //___OPTIONAL_HPP___ diff --git a/src/3rdparty/optional/ottd_optional.h b/src/3rdparty/optional/ottd_optional.h new file mode 100644 index 0000000000..19b44c5055 --- /dev/null +++ b/src/3rdparty/optional/ottd_optional.h @@ -0,0 +1,33 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file ottd_optional.h Header to select between native. */ + +#ifndef OTTD_OPTIONAL_H +#define OTTD_OPTIONAL_H + +#if defined(__has_include) +# if __has_include() +# include +# endif +#endif + +#if (__cplusplus >= 201703L) || (defined(__cpp_lib_optional) && __cpp_lib_optional >= 201606L) + +/* Native std::optional. */ +#include +namespace opt = std; + +#else + +/* No std::optional, use local copy instead. */ +#include "optional.hpp" +namespace opt = std::experimental; + +#endif + +#endif /* OTTD_OPTIONAL_H */ diff --git a/src/aircraft_cmd.cpp b/src/aircraft_cmd.cpp index bfed28b455..eaef2d9e2d 100644 --- a/src/aircraft_cmd.cpp +++ b/src/aircraft_cmd.cpp @@ -309,7 +309,7 @@ CommandCost CmdBuildAircraft(TileIndex tile, DoCommandFlag flags, const Engine * v->cargo_type = e->GetDefaultCargoType(); u->cargo_type = CT_MAIL; - v->name = nullptr; + v->name.clear(); v->last_station_visited = INVALID_STATION; v->last_loading_station = INVALID_STATION; diff --git a/src/base_consist.cpp b/src/base_consist.cpp index 6b7a6e49be..b1925a0fb7 100644 --- a/src/base_consist.cpp +++ b/src/base_consist.cpp @@ -14,10 +14,6 @@ #include "safeguards.h" -BaseConsist::~BaseConsist() -{ - free(this->name); -} /** * Copy properties of other BaseConsist. @@ -27,8 +23,7 @@ void BaseConsist::CopyConsistPropertiesFrom(const BaseConsist *src) { if (this == src) return; - free(this->name); - this->name = src->name != nullptr ? stredup(src->name) : nullptr; + this->name = src->name; this->current_order_time = src->current_order_time; this->lateness_counter = src->lateness_counter; diff --git a/src/base_consist.h b/src/base_consist.h index f7a06efb38..0cac82aacd 100644 --- a/src/base_consist.h +++ b/src/base_consist.h @@ -13,10 +13,11 @@ #include "order_type.h" #include "date_type.h" #include "timetable.h" +#include /** Various front vehicle properties that are preserved when autoreplacing, using order-backup or switching front engines within a consist. */ struct BaseConsist { - char *name; ///< Name of vehicle + std::string name; ///< Name of vehicle /* Used for timetabling. */ uint32 current_order_time; ///< How many ticks have passed since this order started. @@ -32,8 +33,7 @@ struct BaseConsist { uint16 vehicle_flags; ///< Used for gradual loading and other miscellaneous things (@see VehicleFlags enum) - BaseConsist() : name(nullptr) {} - virtual ~BaseConsist(); + virtual ~BaseConsist() {} void CopyConsistPropertiesFrom(const BaseConsist *src); }; diff --git a/src/base_media_base.h b/src/base_media_base.h index 0b006efbea..881fdc3f38 100644 --- a/src/base_media_base.h +++ b/src/base_media_base.h @@ -15,6 +15,7 @@ #include "gfx_type.h" #include "textfile_type.h" #include "textfile_gui.h" +#include /* Forward declare these; can't do 'struct X' in functions as older GCCs barf on that */ struct IniFile; @@ -46,7 +47,7 @@ struct MD5File { */ template struct BaseSet { - typedef SmallMap TranslatedStrings; + typedef std::unordered_map TranslatedStrings; /** Number of files in this set */ static const size_t NUM_FILES = Tnum_files; @@ -57,7 +58,7 @@ struct BaseSet { /** Internal names of the files in this set. */ static const char * const *file_names; - const char *name; ///< The name of the base set + std::string name; ///< The name of the base set TranslatedStrings description; ///< Description of the base set uint32 shortname; ///< Four letter short variant of the name uint32 version; ///< The version of this base set @@ -72,13 +73,6 @@ struct BaseSet { /** Free everything we allocated */ ~BaseSet() { - free(this->name); - - for (auto &pair : this->description) { - free(pair.first); - free(pair.second); - } - for (uint i = 0; i < NUM_FILES; i++) { free(this->files[i].filename); free(this->files[i].missing_warning); @@ -116,20 +110,19 @@ struct BaseSet { * @param isocode the isocode to search for * @return the description */ - const char *GetDescription(const char *isocode = nullptr) const + const char *GetDescription(const std::string &isocode) const { - if (isocode != nullptr) { + if (!isocode.empty()) { /* First the full ISO code */ - for (const auto &pair : this->description) { - if (strcmp(pair.first, isocode) == 0) return pair.second; - } + auto desc = this->description.find(isocode); + if (desc != this->description.end()) return desc->second.c_str(); + /* Then the first two characters */ - for (const auto &pair : this->description) { - if (strncmp(pair.first, isocode, 2) == 0) return pair.second; - } + desc = this->description.find(isocode.substr(0, 2)); + if (desc != this->description.end()) return desc->second.c_str(); } /* Then fall back */ - return this->description.front().second; + return this->description.at(std::string{}).c_str(); } /** @@ -183,7 +176,7 @@ protected: static const char *GetExtension(); public: /** The set as saved in the config file. */ - static const char *ini_set; + static std::string ini_set; /** * Determine the graphics pack that has to be used. @@ -203,7 +196,7 @@ public: static Tbase_set *GetAvailableSets(); - static bool SetSet(const char *name); + static bool SetSet(const std::string &name); static char *GetSetsList(char *p, const char *last); static int GetNumSets(); static int GetIndexOfUsedSet(); @@ -219,7 +212,7 @@ public: static bool HasSet(const ContentInfo *ci, bool md5sum); }; -template /* static */ const char *BaseMedia::ini_set; +template /* static */ std::string BaseMedia::ini_set; template /* static */ const Tbase_set *BaseMedia::used_set; template /* static */ Tbase_set *BaseMedia::available_sets; template /* static */ Tbase_set *BaseMedia::duplicate_sets; diff --git a/src/base_media_func.h b/src/base_media_func.h index 01e184f8ca..02c445c21a 100644 --- a/src/base_media_func.h +++ b/src/base_media_func.h @@ -21,7 +21,7 @@ */ #define fetch_metadata(name) \ item = metadata->GetItem(name, false); \ - if (item == nullptr || StrEmpty(item->value)) { \ + if (item == nullptr || !item->value.has_value() || item->value->empty()) { \ DEBUG(grf, 0, "Base " SET_TYPE "set detail loading: %s field missing.", name); \ DEBUG(grf, 0, " Is %s readable for the user running OpenTTD?", full_filename); \ return false; \ @@ -42,28 +42,28 @@ bool BaseSet::FillSetDetails(IniFile *ini, const IniItem *item; fetch_metadata("name"); - this->name = stredup(item->value); + this->name = *item->value; fetch_metadata("description"); - this->description[stredup("")] = stredup(item->value); + this->description[std::string{}] = *item->value; /* Add the translations of the descriptions too. */ for (const IniItem *item = metadata->item; item != nullptr; item = item->next) { - if (strncmp("description.", item->name, 12) != 0) continue; + if (item->name.compare(0, 12, "description.") != 0) continue; - this->description[stredup(item->name + 12)] = stredup(item->value); + this->description[item->name.substr(12)] = item->value.value_or(""); } fetch_metadata("shortname"); - for (uint i = 0; item->value[i] != '\0' && i < 4; i++) { - this->shortname |= ((uint8)item->value[i]) << (i * 8); + for (uint i = 0; item->value.value()[i] != '\0' && i < 4; i++) { + this->shortname |= ((uint8)item->value.value()[i]) << (i * 8); } fetch_metadata("version"); - this->version = atoi(item->value); + this->version = atoi(item->value->c_str()); item = metadata->GetItem("fallback", false); - this->fallback = (item != nullptr && strcmp(item->value, "0") != 0 && strcmp(item->value, "false") != 0); + this->fallback = (item != nullptr && item->value && item->value.value() != "0" && item->value.value() != "false"); /* For each of the file types we want to find the file, MD5 checksums and warning messages. */ IniGroup *files = ini->GetGroup("files"); @@ -73,13 +73,12 @@ bool BaseSet::FillSetDetails(IniFile *ini, const MD5File *file = &this->files[i]; /* Find the filename first. */ item = files->GetItem(BaseSet::file_names[i], false); - if (item == nullptr || (item->value == nullptr && !allow_empty_filename)) { + if (item == nullptr || (!item->value.has_value() && !allow_empty_filename)) { DEBUG(grf, 0, "No " SET_TYPE " file for: %s (in %s)", BaseSet::file_names[i], full_filename); return false; } - const char *filename = item->value; - if (filename == nullptr) { + if (!item->value.has_value()) { file->filename = nullptr; /* If we list no file, that file must be valid */ this->valid_files++; @@ -87,15 +86,16 @@ bool BaseSet::FillSetDetails(IniFile *ini, const continue; } + const char *filename = item->value->c_str(); file->filename = str_fmt("%s%s", path, filename); /* Then find the MD5 checksum */ item = md5s->GetItem(filename, false); - if (item == nullptr || item->value == nullptr) { + if (item == nullptr || !item->value.has_value()) { DEBUG(grf, 0, "No MD5 checksum specified for: %s (in %s)", filename, full_filename); return false; } - char *c = item->value; + const char *c = item->value->c_str(); for (uint i = 0; i < sizeof(file->hash) * 2; i++, c++) { uint j; if ('0' <= *c && *c <= '9') { @@ -118,11 +118,11 @@ bool BaseSet::FillSetDetails(IniFile *ini, const /* Then find the warning message when the file's missing */ item = origin->GetItem(filename, false); if (item == nullptr) item = origin->GetItem("default", false); - if (item == nullptr) { + if (item == nullptr || !item->value.has_value()) { DEBUG(grf, 1, "No origin warning message specified for: %s", filename); file->missing_warning = stredup(""); } else { - file->missing_warning = stredup(item->value); + file->missing_warning = stredup(item->value->c_str()); } file->check_result = T::CheckMD5(file, BASESET_DIR); @@ -170,7 +170,7 @@ bool BaseMedia::AddFile(const char *filename, size_t basepath_length, if (set->FillSetDetails(ini, path, filename)) { Tbase_set *duplicate = nullptr; for (Tbase_set *c = BaseMedia::available_sets; c != nullptr; c = c->next) { - if (strcmp(c->name, set->name) == 0 || c->shortname == set->shortname) { + if (c->name == set->name || c->shortname == set->shortname) { duplicate = c; break; } @@ -179,7 +179,7 @@ bool BaseMedia::AddFile(const char *filename, size_t basepath_length, /* The more complete set takes precedence over the version number. */ if ((duplicate->valid_files == set->valid_files && duplicate->version >= set->version) || duplicate->valid_files > set->valid_files) { - DEBUG(grf, 1, "Not adding %s (%i) as base " SET_TYPE " set (duplicate, %s)", set->name, set->version, + DEBUG(grf, 1, "Not adding %s (%i) as base " SET_TYPE " set (duplicate, %s)", set->name.c_str(), set->version, duplicate->valid_files > set->valid_files ? "less valid files" : "lower version"); set->next = BaseMedia::duplicate_sets; BaseMedia::duplicate_sets = set; @@ -195,7 +195,7 @@ bool BaseMedia::AddFile(const char *filename, size_t basepath_length, * version number until a new game is started which isn't a big problem */ if (BaseMedia::used_set == duplicate) BaseMedia::used_set = set; - DEBUG(grf, 1, "Removing %s (%i) as base " SET_TYPE " set (duplicate, %s)", duplicate->name, duplicate->version, + DEBUG(grf, 1, "Removing %s (%i) as base " SET_TYPE " set (duplicate, %s)", duplicate->name.c_str(), duplicate->version, duplicate->valid_files < set->valid_files ? "less valid files" : "lower version"); duplicate->next = BaseMedia::duplicate_sets; BaseMedia::duplicate_sets = duplicate; @@ -209,7 +209,7 @@ bool BaseMedia::AddFile(const char *filename, size_t basepath_length, ret = true; } if (ret) { - DEBUG(grf, 1, "Adding %s (%i) as base " SET_TYPE " set", set->name, set->version); + DEBUG(grf, 1, "Adding %s (%i) as base " SET_TYPE " set", set->name.c_str(), set->version); } } else { delete set; @@ -226,18 +226,18 @@ bool BaseMedia::AddFile(const char *filename, size_t basepath_length, * @return true if it could be loaded */ template -/* static */ bool BaseMedia::SetSet(const char *name) +/* static */ bool BaseMedia::SetSet(const std::string &name) { extern void CheckExternalFiles(); - if (StrEmpty(name)) { + if (name.empty()) { if (!BaseMedia::DetermineBestSet()) return false; CheckExternalFiles(); return true; } for (const Tbase_set *s = BaseMedia::available_sets; s != nullptr; s = s->next) { - if (strcmp(name, s->name) == 0) { + if (name == s->name) { BaseMedia::used_set = s; CheckExternalFiles(); return true; @@ -257,7 +257,7 @@ template { p += seprintf(p, last, "List of " SET_TYPE " sets:\n"); for (const Tbase_set *s = BaseMedia::available_sets; s != nullptr; s = s->next) { - p += seprintf(p, last, "%18s: %s", s->name, s->GetDescription()); + p += seprintf(p, last, "%18s: %s", s->name.c_str(), s->GetDescription({})); int invalid = s->GetNumInvalid(); if (invalid != 0) { int missing = s->GetNumMissing(); @@ -376,11 +376,11 @@ template * @param set_type the type of the BaseSet to instantiate */ #define INSTANTIATE_BASE_MEDIA_METHODS(repl_type, set_type) \ - template const char *repl_type::ini_set; \ + template std::string repl_type::ini_set; \ template const char *repl_type::GetExtension(); \ template bool repl_type::AddFile(const char *filename, size_t pathlength, const char *tar_filename); \ template bool repl_type::HasSet(const struct ContentInfo *ci, bool md5sum); \ - template bool repl_type::SetSet(const char *name); \ + template bool repl_type::SetSet(const std::string &name); \ template char *repl_type::GetSetsList(char *p, const char *last); \ template int repl_type::GetNumSets(); \ template int repl_type::GetIndexOfUsedSet(); \ diff --git a/src/base_station_base.h b/src/base_station_base.h index 5c8e9314aa..d14e53ebe5 100644 --- a/src/base_station_base.h +++ b/src/base_station_base.h @@ -56,7 +56,7 @@ struct BaseStation : StationPool::PoolItem<&_station_pool> { TrackedViewportSign sign; ///< NOSAVE: Dimensions of sign byte delete_ctr; ///< Delete counter. If greater than 0 then it is decremented until it reaches 0; the waypoint is then is deleted. - char *name; ///< Custom name + std::string name; ///< Custom name StringID string_id; ///< Default name (town area) of station mutable std::string cached_name; ///< NOSAVE: Cache of the resolved name of the station, if not using a custom name @@ -113,7 +113,7 @@ struct BaseStation : StationPool::PoolItem<&_station_pool> { inline const char *GetCachedName() const { - if (this->name != nullptr) return this->name; + if (!this->name.empty()) return this->name.c_str(); if (this->cached_name.empty()) this->FillCachedName(); return this->cached_name.c_str(); } diff --git a/src/blitter/factory.hpp b/src/blitter/factory.hpp index 30a70570be..c7776f4a46 100644 --- a/src/blitter/factory.hpp +++ b/src/blitter/factory.hpp @@ -22,10 +22,10 @@ */ class BlitterFactory { private: - const char *name; ///< The name of the blitter factory. - const char *description; ///< The description of the blitter. + const std::string name; ///< The name of the blitter factory. + const std::string description; ///< The description of the blitter. - typedef std::map Blitters; ///< Map of blitter factories. + typedef std::map Blitters; ///< Map of blitter factories. /** * Get the map with currently known blitters. @@ -58,7 +58,7 @@ protected: * @pre There is no blitter registered with this name. */ BlitterFactory(const char *name, const char *description, bool usable = true) : - name(stredup(name)), description(stredup(description)) + name(name), description(description) { if (usable) { /* @@ -78,9 +78,6 @@ public: { GetBlitters().erase(this->name); if (GetBlitters().empty()) delete &GetBlitters(); - - free(this->name); - free(this->description); } /** @@ -88,7 +85,7 @@ public: * @param name the blitter to select. * @post Sets the blitter so GetCurrentBlitter() returns it too. */ - static Blitter *SelectBlitter(const char *name) + static Blitter *SelectBlitter(const std::string &name) { BlitterFactory *b = GetBlitterFactory(name); if (b == nullptr) return nullptr; @@ -97,7 +94,7 @@ public: delete *GetActiveBlitter(); *GetActiveBlitter() = newb; - DEBUG(driver, 1, "Successfully %s blitter '%s'", StrEmpty(name) ? "probed" : "loaded", newb->GetName()); + DEBUG(driver, 1, "Successfully %s blitter '%s'", name.empty() ? "probed" : "loaded", newb->GetName()); return newb; } @@ -106,7 +103,7 @@ public: * @param name the blitter factory to select. * @return The blitter factory, or nullptr when there isn't one with the wanted name. */ - static BlitterFactory *GetBlitterFactory(const char *name) + static BlitterFactory *GetBlitterFactory(const std::string &name) { #if defined(DEDICATED) const char *default_blitter = "null"; @@ -116,12 +113,12 @@ public: const char *default_blitter = "8bpp-optimized"; #endif if (GetBlitters().size() == 0) return nullptr; - const char *bname = (StrEmpty(name)) ? default_blitter : name; + const char *bname = name.empty() ? default_blitter : name.c_str(); Blitters::iterator it = GetBlitters().begin(); for (; it != GetBlitters().end(); it++) { BlitterFactory *b = (*it).second; - if (strcasecmp(bname, b->name) == 0) { + if (strcasecmp(bname, b->name.c_str()) == 0) { return b; } } @@ -148,7 +145,7 @@ public: Blitters::iterator it = GetBlitters().begin(); for (; it != GetBlitters().end(); it++) { BlitterFactory *b = (*it).second; - p += seprintf(p, last, "%18s: %s\n", b->name, b->GetDescription()); + p += seprintf(p, last, "%18s: %s\n", b->name.c_str(), b->GetDescription().c_str()); } p += seprintf(p, last, "\n"); @@ -158,7 +155,7 @@ public: /** * Get the long, human readable, name for the Blitter-class. */ - const char *GetName() const + const std::string &GetName() const { return this->name; } @@ -166,7 +163,7 @@ public: /** * Get a nice description of the blitter-class. */ - const char *GetDescription() const + const std::string &GetDescription() const { return this->description; } @@ -177,7 +174,7 @@ public: virtual Blitter *CreateInstance() = 0; }; -extern char *_ini_blitter; +extern std::string _ini_blitter; extern bool _blitter_autodetected; #endif /* BLITTER_FACTORY_HPP */ diff --git a/src/company_base.h b/src/company_base.h index b75aeb094e..3f40af8387 100644 --- a/src/company_base.h +++ b/src/company_base.h @@ -16,6 +16,7 @@ #include "tile_type.h" #include "settings_type.h" #include "group.h" +#include /** Statistics about the economy. */ struct CompanyEconomyEntry { @@ -56,11 +57,11 @@ extern CompanyPool _company_pool; struct CompanyProperties { uint32 name_2; ///< Parameter of #name_1. StringID name_1; ///< Name of the company if the user did not change it. - char *name; ///< Name of the company if the user changed it. + std::string name; ///< Name of the company if the user changed it. StringID president_name_1; ///< Name of the president if the user did not change it. uint32 president_name_2; ///< Parameter of #president_name_1 - char *president_name; ///< Name of the president if the user changed it. + std::string president_name; ///< Name of the president if the user changed it. CompanyManagerFace face; ///< Face description of the president. @@ -102,17 +103,11 @@ struct CompanyProperties { // TODO: Change some of these member variables to use relevant INVALID_xxx constants CompanyProperties() - : name_2(0), name_1(0), name(nullptr), president_name_1(0), president_name_2(0), president_name(nullptr), + : name_2(0), name_1(0), president_name_1(0), president_name_2(0), face(0), money(0), money_fraction(0), current_loan(0), colour(0), block_preview(0), location_of_HQ(0), last_build_coordinate(0), share_owners(), inaugurated_year(0), months_of_bankruptcy(0), bankrupt_asked(0), bankrupt_timeout(0), bankrupt_value(0), terraform_limit(0), clear_limit(0), tree_limit(0), purchase_land_limit(0), is_ai(false) {} - - ~CompanyProperties() - { - free(this->name); - free(this->president_name); - } }; struct Company : CompanyPool::PoolItem<&_company_pool>, CompanyProperties { diff --git a/src/company_cmd.cpp b/src/company_cmd.cpp index 35557d753c..f9e73cac1c 100644 --- a/src/company_cmd.cpp +++ b/src/company_cmd.cpp @@ -359,7 +359,7 @@ static void GenerateCompanyName(Company *c) StringID str; uint32 strp; - if (t->name == nullptr && IsInsideMM(t->townnametype, SPECSTR_TOWNNAME_START, SPECSTR_TOWNNAME_LAST + 1)) { + if (t->name.empty() && IsInsideMM(t->townnametype, SPECSTR_TOWNNAME_START, SPECSTR_TOWNNAME_LAST + 1)) { str = t->townnametype - SPECSTR_TOWNNAME_START + SPECSTR_COMPANY_NAME_START; strp = t->townnameparts; @@ -1062,7 +1062,7 @@ CommandCost CmdSetCompanyColour(TileIndex tile, DoCommandFlag flags, uint32 p1, static bool IsUniqueCompanyName(const char *name) { for (const Company *c : Company::Iterate()) { - if (c->name != nullptr && strcmp(c->name, name) == 0) return false; + if (!c->name.empty() && c->name == name) return false; } return true; @@ -1088,8 +1088,11 @@ CommandCost CmdRenameCompany(TileIndex tile, DoCommandFlag flags, uint32 p1, uin if (flags & DC_EXEC) { Company *c = Company::Get(_current_company); - free(c->name); - c->name = reset ? nullptr : stredup(text); + if (reset) { + c->name.clear(); + } else { + c->name = text; + } MarkWholeScreenDirty(); CompanyAdminUpdate(c); } @@ -1105,7 +1108,7 @@ CommandCost CmdRenameCompany(TileIndex tile, DoCommandFlag flags, uint32 p1, uin static bool IsUniquePresidentName(const char *name) { for (const Company *c : Company::Iterate()) { - if (c->president_name != nullptr && strcmp(c->president_name, name) == 0) return false; + if (!c->president_name.empty() && c->president_name == name) return false; } return true; @@ -1131,14 +1134,13 @@ CommandCost CmdRenamePresident(TileIndex tile, DoCommandFlag flags, uint32 p1, u if (flags & DC_EXEC) { Company *c = Company::Get(_current_company); - free(c->president_name); if (reset) { - c->president_name = nullptr; + c->president_name.clear(); } else { - c->president_name = stredup(text); + c->president_name = text; - if (c->name_1 == STR_SV_UNNAMED && c->name == nullptr) { + if (c->name_1 == STR_SV_UNNAMED && c->name.empty()) { char buf[80]; seprintf(buf, lastof(buf), "%s Transport", text); diff --git a/src/core/smallmap_type.hpp b/src/core/smallmap_type.hpp index d28041506c..5c8d437f64 100644 --- a/src/core/smallmap_type.hpp +++ b/src/core/smallmap_type.hpp @@ -11,40 +11,26 @@ #define SMALLMAP_TYPE_HPP #include "smallvec_type.hpp" +#include /** - * Simple pair of data. Both types have to be POD ("Plain Old Data")! - * @tparam T Key type. - * @tparam U Value type. - */ -template -struct SmallPair { - T first; - U second; - - /** Initializes this Pair with data */ - inline SmallPair(const T &first, const U &second) : first(first), second(second) { } - SmallPair() = default; -}; - -/** - * Implementation of simple mapping class. Both types have to be POD ("Plain Old Data")! - * It has inherited accessors from SmallVector(). + * Implementation of simple mapping class. + * It has inherited accessors from std::vector(). * @tparam T Key type. * @tparam U Value type. * @tparam S Unit of allocation. * - * @see SmallVector + * @see std::vector */ template -struct SmallMap : std::vector > { - typedef ::SmallPair Pair; +struct SmallMap : std::vector > { + typedef std::pair Pair; typedef Pair *iterator; typedef const Pair *const_iterator; - /** Creates new SmallMap. Data are initialized in SmallVector constructor */ + /** Creates new SmallMap. Data are initialized in std::vector constructor */ inline SmallMap() { } - /** Data are freed in SmallVector destructor */ + /** Data are freed in std::vector destructor */ inline ~SmallMap() { } /** diff --git a/src/crashlog.cpp b/src/crashlog.cpp index 818adeee29..6b5090fe04 100644 --- a/src/crashlog.cpp +++ b/src/crashlog.cpp @@ -199,15 +199,15 @@ char *CrashLog::LogConfiguration(char *buffer, const char *last) const " Video driver: %s\n" " Pathfinder: %s %s %s\n\n", BlitterFactory::GetCurrentBlitter() == nullptr ? "none" : BlitterFactory::GetCurrentBlitter()->GetName(), - BaseGraphics::GetUsedSet() == nullptr ? "none" : BaseGraphics::GetUsedSet()->name, + BaseGraphics::GetUsedSet() == nullptr ? "none" : BaseGraphics::GetUsedSet()->name.c_str(), BaseGraphics::GetUsedSet() == nullptr ? UINT32_MAX : BaseGraphics::GetUsedSet()->version, _current_language == nullptr ? "none" : _current_language->file, MusicDriver::GetInstance() == nullptr ? "none" : MusicDriver::GetInstance()->GetName(), - BaseMusic::GetUsedSet() == nullptr ? "none" : BaseMusic::GetUsedSet()->name, + BaseMusic::GetUsedSet() == nullptr ? "none" : BaseMusic::GetUsedSet()->name.c_str(), BaseMusic::GetUsedSet() == nullptr ? UINT32_MAX : BaseMusic::GetUsedSet()->version, _networking ? (_network_server ? "server" : "client") : "no", SoundDriver::GetInstance() == nullptr ? "none" : SoundDriver::GetInstance()->GetName(), - BaseSounds::GetUsedSet() == nullptr ? "none" : BaseSounds::GetUsedSet()->name, + BaseSounds::GetUsedSet() == nullptr ? "none" : BaseSounds::GetUsedSet()->name.c_str(), BaseSounds::GetUsedSet() == nullptr ? UINT32_MAX : BaseSounds::GetUsedSet()->version, VideoDriver::GetInstance() == nullptr ? "none" : VideoDriver::GetInstance()->GetName(), pathfinder_name(_settings_game.pf.pathfinder_for_trains), pathfinder_name(_settings_game.pf.pathfinder_for_roadvehs), pathfinder_name(_settings_game.pf.pathfinder_for_ships) diff --git a/src/dedicated.cpp b/src/dedicated.cpp index 8ab035e61d..fe3cd7cfb8 100644 --- a/src/dedicated.cpp +++ b/src/dedicated.cpp @@ -8,9 +8,11 @@ /** @file dedicated.cpp Forking support for dedicated servers. */ #include "stdafx.h" +#include "fileio_func.h" +#include -char *_log_file = nullptr; ///< File to reroute output of a forked OpenTTD to -FILE *_log_fd = nullptr; ///< File to reroute output of a forked OpenTTD to +std::string _log_file; ///< File to reroute output of a forked OpenTTD to +std::unique_ptr _log_fd; ///< File to reroute output of a forked OpenTTD to #if defined(UNIX) @@ -38,17 +40,17 @@ void DedicatedFork() case 0: { // We're the child /* Open the log-file to log all stuff too */ - _log_fd = fopen(_log_file, "a"); - if (_log_fd == nullptr) { + _log_fd.reset(fopen(_log_file.c_str(), "a")); + if (!_log_fd) { perror("Unable to open logfile"); exit(1); } /* Redirect stdout and stderr to log-file */ - if (dup2(fileno(_log_fd), fileno(stdout)) == -1) { + if (dup2(fileno(_log_fd.get()), fileno(stdout)) == -1) { perror("Rerouting stdout"); exit(1); } - if (dup2(fileno(_log_fd), fileno(stderr)) == -1) { + if (dup2(fileno(_log_fd.get()), fileno(stderr)) == -1) { perror("Rerouting stderr"); exit(1); } diff --git a/src/departures_gui.cpp b/src/departures_gui.cpp index 2d48cd7fcc..8a5b9dad6f 100644 --- a/src/departures_gui.cpp +++ b/src/departures_gui.cpp @@ -154,7 +154,7 @@ protected: && order->GetDestination() == this->station) { this->vehicles.push_back(v); - if (v->name == nullptr) { + if (v->name.empty()) { if (v->unitnumber > unitnumber_max[v->type]) unitnumber_max[v->type] = v->unitnumber; } else { SetDParam(0, (uint64)(v->index)); diff --git a/src/depot.cpp b/src/depot.cpp index 35dcadbdb3..5819c3b0fd 100644 --- a/src/depot.cpp +++ b/src/depot.cpp @@ -28,8 +28,6 @@ INSTANTIATE_POOL_METHODS(Depot) */ Depot::~Depot() { - free(this->name); - if (CleaningPool()) return; if (!IsDepotTile(this->xy) || GetDepotIndex(this->xy) != this->index) { diff --git a/src/depot_base.h b/src/depot_base.h index aab2b2ae42..f4c52cffe8 100644 --- a/src/depot_base.h +++ b/src/depot_base.h @@ -18,7 +18,7 @@ extern DepotPool _depot_pool; struct Depot : DepotPool::PoolItem<&_depot_pool> { Town *town; - char *name; + std::string name; TileIndex xy; uint16 town_cn; ///< The N-1th depot for this town (consecutive number) diff --git a/src/depot_cmd.cpp b/src/depot_cmd.cpp index a142fbe7d3..9379afb82f 100644 --- a/src/depot_cmd.cpp +++ b/src/depot_cmd.cpp @@ -29,7 +29,7 @@ static bool IsUniqueDepotName(const char *name) { for (const Depot *d : Depot::Iterate()) { - if (d->name != nullptr && strcmp(d->name, name) == 0) return false; + if (!d->name.empty() && d->name == name) return false; } return true; @@ -60,13 +60,11 @@ CommandCost CmdRenameDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 } if (flags & DC_EXEC) { - free(d->name); - if (reset) { - d->name = nullptr; + d->name.clear(); MakeDefaultName(d); } else { - d->name = stredup(text); + d->name = text; } /* Update the orders and depot */ diff --git a/src/driver.cpp b/src/driver.cpp index a642a2f867..c4efd35692 100644 --- a/src/driver.cpp +++ b/src/driver.cpp @@ -13,19 +13,21 @@ #include "music/music_driver.hpp" #include "video/video_driver.hpp" #include "string_func.h" +#include +#include #include "safeguards.h" -char *_ini_videodriver; ///< The video driver a stored in the configuration file. +std::string _ini_videodriver; ///< The video driver a stored in the configuration file. std::vector _resolutions; ///< List of resolutions. Dimension _cur_resolution; ///< The current resolution. bool _rightclick_emulate; ///< Whether right clicking is emulated. -char *_ini_sounddriver; ///< The sound driver a stored in the configuration file. +std::string _ini_sounddriver; ///< The sound driver a stored in the configuration file. -char *_ini_musicdriver; ///< The music driver a stored in the configuration file. +std::string _ini_musicdriver; ///< The music driver a stored in the configuration file. -char *_ini_blitter; ///< The blitter as stored in the configuration file. +std::string _ini_blitter; ///< The blitter as stored in the configuration file. bool _blitter_autodetected; ///< Was the blitter autodetected or specified by the user? /** @@ -34,19 +36,15 @@ bool _blitter_autodetected; ///< Was the blitter autodetected or specif * @param name The parameter name we're looking for. * @return The parameter value. */ -const char *GetDriverParam(const char * const *parm, const char *name) +const char *GetDriverParam(const StringList &parm, const char *name) { - size_t len; + if (parm.empty()) return nullptr; - if (parm == nullptr) return nullptr; - - len = strlen(name); - for (; *parm != nullptr; parm++) { - const char *p = *parm; - - if (strncmp(p, name, len) == 0) { - if (p[len] == '=') return p + len + 1; - if (p[len] == '\0') return p + len; + size_t len = strlen(name); + for (auto &p : parm) { + if (p.compare(0, len, name) == 0) { + if (p.length() == len) return ""; + if (p[len] == '=') return p.c_str() + len + 1; } } return nullptr; @@ -58,7 +56,7 @@ const char *GetDriverParam(const char * const *parm, const char *name) * @param name The parameter name we're looking for. * @return The parameter value. */ -bool GetDriverParamBool(const char * const *parm, const char *name) +bool GetDriverParamBool(const StringList &parm, const char *name) { return GetDriverParam(parm, name) != nullptr; } @@ -70,7 +68,7 @@ bool GetDriverParamBool(const char * const *parm, const char *name) * @param def The default value if the parameter doesn't exist. * @return The parameter value. */ -int GetDriverParamInt(const char * const *parm, const char *name, int def) +int GetDriverParamInt(const StringList &parm, const char *name, int def) { const char *p = GetDriverParam(parm, name); return p != nullptr ? atoi(p) : def; @@ -82,12 +80,12 @@ int GetDriverParamInt(const char * const *parm, const char *name, int def) * @param type the type of driver to select * @post Sets the driver so GetCurrentDriver() returns it too. */ -void DriverFactoryBase::SelectDriver(const char *name, Driver::Type type) +void DriverFactoryBase::SelectDriver(const std::string &name, Driver::Type type) { if (!DriverFactoryBase::SelectDriverImpl(name, type)) { - StrEmpty(name) ? + name.empty() ? usererror("Failed to autoprobe %s driver", GetDriverTypeName(type)) : - usererror("Failed to select requested %s driver '%s'", GetDriverTypeName(type), name); + usererror("Failed to select requested %s driver '%s'", GetDriverTypeName(type), name.c_str()); } } @@ -98,11 +96,11 @@ void DriverFactoryBase::SelectDriver(const char *name, Driver::Type type) * @post Sets the driver so GetCurrentDriver() returns it too. * @return True upon success, otherwise false. */ -bool DriverFactoryBase::SelectDriverImpl(const char *name, Driver::Type type) +bool DriverFactoryBase::SelectDriverImpl(const std::string &name, Driver::Type type) { if (GetDrivers().size() == 0) return false; - if (StrEmpty(name)) { + if (name.empty()) { /* Probe for this driver, but do not fall back to dedicated/null! */ for (int priority = 10; priority > 0; priority--) { Drivers::iterator it = GetDrivers().begin(); @@ -117,7 +115,7 @@ bool DriverFactoryBase::SelectDriverImpl(const char *name, Driver::Type type) Driver *newd = d->CreateInstance(); *GetActiveDriver(type) = newd; - const char *err = newd->Start(nullptr); + const char *err = newd->Start({}); if (err == nullptr) { DEBUG(driver, 1, "Successfully probed %s driver '%s'", GetDriverTypeName(type), d->name); delete oldd; @@ -131,23 +129,15 @@ bool DriverFactoryBase::SelectDriverImpl(const char *name, Driver::Type type) } usererror("Couldn't find any suitable %s driver", GetDriverTypeName(type)); } else { - char *parm; - char buffer[256]; - const char *parms[32]; - /* Extract the driver name and put parameter list in parm */ - strecpy(buffer, name, lastof(buffer)); - parm = strchr(buffer, ':'); - parms[0] = nullptr; - if (parm != nullptr) { - uint np = 0; - /* Tokenize the parm. */ - do { - *parm++ = '\0'; - if (np < lengthof(parms) - 1) parms[np++] = parm; - while (*parm != '\0' && *parm != ',') parm++; - } while (*parm == ','); - parms[np] = nullptr; + std::istringstream buffer(name); + std::string dname; + std::getline(buffer, dname, ':'); + + std::string param; + std::vector parms; + while (std::getline(buffer, param, ',')) { + parms.push_back(param); } /* Find this driver */ @@ -159,7 +149,7 @@ bool DriverFactoryBase::SelectDriverImpl(const char *name, Driver::Type type) if (d->type != type) continue; /* Check driver name */ - if (strcasecmp(buffer, d->name) != 0) continue; + if (strcasecmp(dname.c_str(), d->name) != 0) continue; /* Found our driver, let's try it */ Driver *newd = d->CreateInstance(); @@ -175,7 +165,7 @@ bool DriverFactoryBase::SelectDriverImpl(const char *name, Driver::Type type) *GetActiveDriver(type) = newd; return true; } - usererror("No such %s driver: %s\n", GetDriverTypeName(type), buffer); + usererror("No such %s driver: %s\n", GetDriverTypeName(type), dname.c_str()); } } @@ -221,9 +211,7 @@ DriverFactoryBase::DriverFactoryBase(Driver::Type type, int priority, const char strecpy(buf, GetDriverTypeName(type), lastof(buf)); strecpy(buf + 5, name, lastof(buf)); - const char *longname = stredup(buf); - - std::pair P = GetDrivers().insert(Drivers::value_type(longname, this)); + std::pair P = GetDrivers().insert(Drivers::value_type(buf, this)); assert(P.second); } @@ -240,10 +228,6 @@ DriverFactoryBase::~DriverFactoryBase() Drivers::iterator it = GetDrivers().find(buf); assert(it != GetDrivers().end()); - const char *longname = (*it).first; - GetDrivers().erase(it); - free(longname); - if (GetDrivers().empty()) delete &GetDrivers(); } diff --git a/src/driver.h b/src/driver.h index 3ac4f7f8a4..68d9fac929 100644 --- a/src/driver.h +++ b/src/driver.h @@ -12,11 +12,12 @@ #include "core/enum_type.hpp" #include "core/string_compare_type.hpp" +#include "string_type.h" #include -const char *GetDriverParam(const char * const *parm, const char *name); -bool GetDriverParamBool(const char * const *parm, const char *name); -int GetDriverParamInt(const char * const *parm, const char *name, int def); +const char *GetDriverParam(const StringList &parm, const char *name); +bool GetDriverParamBool(const StringList &parm, const char *name); +int GetDriverParamInt(const StringList &parm, const char *name, int def); /** A driver for communicating with the user. */ class Driver { @@ -26,7 +27,7 @@ public: * @param parm Parameters passed to the driver. * @return nullptr if everything went okay, otherwise an error message. */ - virtual const char *Start(const char * const *parm) = 0; + virtual const char *Start(const StringList &parm) = 0; /** * Stop this driver. @@ -66,7 +67,7 @@ private: const char *name; ///< The name of the drivers of this factory. const char *description; ///< The description of this driver. - typedef std::map Drivers; ///< Type for a map of drivers. + typedef std::map Drivers; ///< Type for a map of drivers. /** * Get the map with drivers. @@ -99,7 +100,7 @@ private: return driver_type_name[type]; } - static bool SelectDriverImpl(const char *name, Driver::Type type); + static bool SelectDriverImpl(const std::string &name, Driver::Type type); protected: DriverFactoryBase(Driver::Type type, int priority, const char *name, const char *description); @@ -118,7 +119,7 @@ public: } } - static void SelectDriver(const char *name, Driver::Type type); + static void SelectDriver(const std::string &name, Driver::Type type); static char *GetDriversInfo(char *p, const char *last); /** diff --git a/src/engine.cpp b/src/engine.cpp index f04664117c..7334564e39 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -68,7 +68,6 @@ assert_compile(lengthof(_orig_rail_vehicle_info) + lengthof(_orig_road_vehicle_i const uint EngineOverrideManager::NUM_DEFAULT_ENGINES = _engine_counts[VEH_TRAIN] + _engine_counts[VEH_ROAD] + _engine_counts[VEH_SHIP] + _engine_counts[VEH_AIRCRAFT]; Engine::Engine() : - name(nullptr), overrides_count(0), overrides(nullptr) { @@ -141,7 +140,6 @@ Engine::Engine(VehicleType type, EngineID base) Engine::~Engine() { UnloadWagonOverrides(this); - free(this->name); } /** @@ -1079,7 +1077,7 @@ void EnginesMonthlyLoop() static bool IsUniqueEngineName(const char *name) { for (const Engine *e : Engine::Iterate()) { - if (e->name != nullptr && strcmp(e->name, name) == 0) return false; + if (!e->name.empty() && e->name == name) return false; } return true; @@ -1107,12 +1105,10 @@ CommandCost CmdRenameEngine(TileIndex tile, DoCommandFlag flags, uint32 p1, uint } if (flags & DC_EXEC) { - free(e->name); - if (reset) { - e->name = nullptr; + e->name.clear(); } else { - e->name = stredup(text); + e->name = text; } MarkWholeScreenDirty(); diff --git a/src/engine_base.h b/src/engine_base.h index c5ce16fccc..883926a25d 100644 --- a/src/engine_base.h +++ b/src/engine_base.h @@ -19,7 +19,7 @@ typedef Pool EnginePool; extern EnginePool _engine_pool; struct Engine : EnginePool::PoolItem<&_engine_pool> { - char *name; ///< Custom name of engine. + std::string name; ///< Custom name of engine. Date intro_date; ///< Date of introduction of the engine. Date age; uint16 reliability; ///< Current reliability of the engine. diff --git a/src/fileio.cpp b/src/fileio.cpp index 8e756d9463..343d21c9c2 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -1251,8 +1251,9 @@ void DeterminePaths(const char *exe) free(tmp); } - extern char *_log_file; - _log_file = str_fmt("%sopenttd.log", _personal_dir); + extern std::string _log_file; + _log_file = _personal_dir; + _log_file += "openttd.log"; } /** diff --git a/src/fileio_func.h b/src/fileio_func.h index 221df80b37..92f7cd3026 100644 --- a/src/fileio_func.h +++ b/src/fileio_func.h @@ -159,4 +159,12 @@ public: } }; +/** Helper to manage a FILE with a \c std::unique_ptr. */ +struct FileDeleter { + void operator()(FILE *f) + { + if (f) fclose(f); + } +}; + #endif /* FILEIO_FUNC_H */ diff --git a/src/fios_gui.cpp b/src/fios_gui.cpp index 1fec660f59..b8437607d6 100644 --- a/src/fios_gui.cpp +++ b/src/fios_gui.cpp @@ -548,9 +548,9 @@ public: for (auto &pair : _load_check_data.companies) { SetDParam(0, pair.first + 1); const CompanyProperties &c = *pair.second; - if (c.name != nullptr) { + if (!c.name.empty()) { SetDParam(1, STR_JUST_RAW_STRING); - SetDParamStr(2, c.name); + SetDParamStr(2, c.name.c_str()); } else { SetDParam(1, c.name_1); SetDParam(2, c.name_2); diff --git a/src/fontcache.cpp b/src/fontcache.cpp index 0df785a9d6..c4aa32253b 100644 --- a/src/fontcache.cpp +++ b/src/fontcache.cpp @@ -94,13 +94,13 @@ SpriteFontCache::~SpriteFontCache() this->ClearGlyphToSpriteMap(); } -SpriteID SpriteFontCache::GetUnicodeGlyph(GlyphID key) +SpriteID SpriteFontCache::GetUnicodeGlyph(WChar key) { if (this->glyph_to_spriteid_map[GB(key, 8, 8)] == nullptr) return 0; return this->glyph_to_spriteid_map[GB(key, 8, 8)][GB(key, 0, 8)]; } -void SpriteFontCache::SetUnicodeGlyph(GlyphID key, SpriteID sprite) +void SpriteFontCache::SetUnicodeGlyph(WChar key, SpriteID sprite) { if (this->glyph_to_spriteid_map == nullptr) this->glyph_to_spriteid_map = CallocT(256); if (this->glyph_to_spriteid_map[GB(key, 8, 8)] == nullptr) this->glyph_to_spriteid_map[GB(key, 8, 8)] = CallocT(256); @@ -209,7 +209,7 @@ protected: int req_size; ///< Requested font size. int used_size; ///< Used font size. - typedef SmallMap > FontTable; ///< Table with font table cache + typedef SmallMap > FontTable; ///< Table with font table cache FontTable font_tables; ///< Cached font tables. /** Container for information about a glyph. */ @@ -438,7 +438,7 @@ const void *TrueTypeFontCache::GetFontTable(uint32 tag, size_t &length) const void *result = this->InternalGetFontTable(tag, length); - this->font_tables.Insert(tag, SmallPair(length, result)); + this->font_tables.Insert(tag, std::pair(length, result)); return result; } diff --git a/src/game/game_text.cpp b/src/game/game_text.cpp index 64281c60cb..39732f7898 100644 --- a/src/game/game_text.cpp +++ b/src/game/game_text.cpp @@ -58,70 +58,47 @@ void NORETURN CDECL strgen_fatal(const char *s, ...) throw std::exception(); } -/** - * Create a new container for language strings. - * @param language The language name. - * @param end If not nullptr, terminate \a language at this position. - */ -LanguageStrings::LanguageStrings(const char *language, const char *end) -{ - this->language = stredup(language, end != nullptr ? end - 1 : nullptr); -} - -/** Free everything. */ -LanguageStrings::~LanguageStrings() -{ - free(this->language); -} - /** * Read all the raw language strings from the given file. * @param file The file to read from. * @return The raw strings, or nullptr upon error. */ -std::unique_ptr ReadRawLanguageStrings(const char *file) +LanguageStrings ReadRawLanguageStrings(const std::string &file) { - try { - size_t to_read; - FILE *fh = FioFOpenFile(file, "rb", GAME_DIR, &to_read); - if (fh == nullptr) return nullptr; + size_t to_read; + FILE *fh = FioFOpenFile(file.c_str(), "rb", GAME_DIR, &to_read); + if (fh == nullptr) return LanguageStrings(); - FileCloser fhClose(fh); + FileCloser fhClose(fh); - const char *langname = strrchr(file, PATHSEPCHAR); - if (langname == nullptr) { - langname = file; + auto pos = file.rfind(PATHSEPCHAR); + if (pos == std::string::npos) return LanguageStrings(); + std::string langname = file.substr(pos + 1); + + /* Check for invalid empty filename */ + if (langname.empty() || langname.front() == '.') return LanguageStrings(); + + LanguageStrings ret(langname.substr(0, langname.find('.'))); + + char buffer[2048]; + while (to_read != 0 && fgets(buffer, sizeof(buffer), fh) != nullptr) { + size_t len = strlen(buffer); + + /* Remove trailing spaces/newlines from the string. */ + size_t i = len; + while (i > 0 && (buffer[i - 1] == '\r' || buffer[i - 1] == '\n' || buffer[i - 1] == ' ')) i--; + buffer[i] = '\0'; + + ret.lines.emplace_back(buffer, i); + + if (len > to_read) { + to_read = 0; } else { - langname++; + to_read -= len; } - - /* Check for invalid empty filename */ - if (*langname == '.' || *langname == 0) return nullptr; - - std::unique_ptr ret(new LanguageStrings(langname, strchr(langname, '.'))); - - char buffer[2048]; - while (to_read != 0 && fgets(buffer, sizeof(buffer), fh) != nullptr) { - size_t len = strlen(buffer); - - /* Remove trailing spaces/newlines from the string. */ - size_t i = len; - while (i > 0 && (buffer[i - 1] == '\r' || buffer[i - 1] == '\n' || buffer[i - 1] == ' ')) i--; - buffer[i] = '\0'; - - ret->lines.emplace_back(buffer, i); - - if (len > to_read) { - to_read = 0; - } else { - to_read -= len; - } - } - - return ret; - } catch (...) { - return nullptr; } + + return ret; } @@ -138,7 +115,7 @@ struct StringListReader : StringReader { * @param translation Are we reading a translation? */ StringListReader(StringData &data, const LanguageStrings &strings, bool master, bool translation) : - StringReader(data, strings.language, master, translation), p(strings.lines.begin()), end(strings.lines.end()) + StringReader(data, strings.language.c_str(), master, translation), p(strings.lines.begin()), end(strings.lines.end()) { } @@ -215,12 +192,11 @@ struct StringNameWriter : HeaderWriter { class LanguageScanner : protected FileScanner { private: GameStrings *gs; - char *exclude; + std::string exclude; public: /** Initialise */ - LanguageScanner(GameStrings *gs, const char *exclude) : gs(gs), exclude(stredup(exclude)) {} - ~LanguageScanner() { free(exclude); } + LanguageScanner(GameStrings *gs, const std::string &exclude) : gs(gs), exclude(exclude) {} /** * Scan. @@ -232,10 +208,10 @@ public: bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename) override { - if (strcmp(filename, exclude) == 0) return true; + if (exclude == filename) return true; auto ls = ReadRawLanguageStrings(filename); - if (ls == nullptr) return false; + if (!ls.IsValid()) return false; gs->raw_strings.push_back(std::move(ls)); return true; @@ -249,17 +225,16 @@ public: GameStrings *LoadTranslations() { const GameInfo *info = Game::GetInfo(); - char filename[512]; - strecpy(filename, info->GetMainScript(), lastof(filename)); - char *e = strrchr(filename, PATHSEPCHAR); - if (e == nullptr) return nullptr; - e++; // Make 'e' point after the PATHSEPCHAR + std::string basename(info->GetMainScript()); + auto e = basename.rfind(PATHSEPCHAR); + if (e == std::string::npos) return nullptr; + basename.erase(e + 1); - strecpy(e, "lang" PATHSEP "english.txt", lastof(filename)); - if (!FioCheckFileExists(filename, GAME_DIR)) return nullptr; + std::string filename = basename + "lang" PATHSEP "english.txt"; + if (!FioCheckFileExists(filename.c_str() , GAME_DIR)) return nullptr; auto ls = ReadRawLanguageStrings(filename); - if (ls == nullptr) return nullptr; + if (!ls.IsValid()) return nullptr; GameStrings *gs = new GameStrings(); try { @@ -267,8 +242,7 @@ GameStrings *LoadTranslations() /* Scan for other language files */ LanguageScanner scanner(gs, filename); - strecpy(e, "lang" PATHSEP, lastof(filename)); - size_t len = strlen(filename); + std::string ldir = basename + "lang" PATHSEP; const char *tar_filename = info->GetTarFile(); TarList::iterator iter; @@ -281,14 +255,14 @@ GameStrings *LoadTranslations() if (tar->second.tar_filename != iter->first) continue; /* Check the path and extension. */ - if (tar->first.size() <= len || tar->first.compare(0, len, filename) != 0) continue; + if (tar->first.size() <= ldir.size() || tar->first.compare(0, ldir.size(), ldir) != 0) continue; if (tar->first.compare(tar->first.size() - 4, 4, ".txt") != 0) continue; scanner.AddFile(tar->first.c_str(), 0, tar_filename); } } else { /* Scan filesystem */ - scanner.Scan(filename); + scanner.Scan(ldir.c_str()); } gs->Compile(); @@ -303,7 +277,7 @@ GameStrings *LoadTranslations() void GameStrings::Compile() { StringData data(32); - StringListReader master_reader(data, *this->raw_strings[0], true, false); + StringListReader master_reader(data, this->raw_strings[0], true, false); master_reader.ParseFile(); if (_errors != 0) throw std::exception(); @@ -314,12 +288,12 @@ void GameStrings::Compile() for (const auto &p : this->raw_strings) { data.FreeTranslation(); - StringListReader translation_reader(data, *p, false, strcmp(p->language, "english") != 0); + StringListReader translation_reader(data, p, false, p.language != "english"); translation_reader.ParseFile(); if (_errors != 0) throw std::exception(); - this->compiled_strings.emplace_back(new LanguageStrings(p->language)); - TranslationWriter writer(this->compiled_strings.back()->lines); + this->compiled_strings.emplace_back(p.language); + TranslationWriter writer(this->compiled_strings.back().lines); writer.WriteLang(data); } } @@ -387,11 +361,11 @@ void ReconsiderGameScriptLanguage() language++; for (auto &p : _current_data->compiled_strings) { - if (strcmp(p->language, language) == 0) { - _current_data->cur_language = p; + if (p.language == language) { + _current_data->cur_language = &p; return; } } - _current_data->cur_language = _current_data->compiled_strings[0]; + _current_data->cur_language = &_current_data->compiled_strings[0]; } diff --git a/src/game/game_text.hpp b/src/game/game_text.hpp index 20cccff54c..91d85847df 100644 --- a/src/game/game_text.hpp +++ b/src/game/game_text.hpp @@ -18,23 +18,34 @@ void ReconsiderGameScriptLanguage(); /** Container for the raw (unencoded) language strings of a language. */ struct LanguageStrings { - const char *language; ///< Name of the language (base filename). - StringList lines; ///< The lines of the file to pass into the parser/encoder. + std::string language; ///< Name of the language (base filename). Empty string if invalid. + StringList lines; ///< The lines of the file to pass into the parser/encoder. - LanguageStrings(const char *language, const char *end = nullptr); - ~LanguageStrings(); + LanguageStrings() {} + LanguageStrings(const std::string &lang) : language(lang) {} + LanguageStrings(const LanguageStrings &other) : language(other.language), lines(other.lines) {} + LanguageStrings(LanguageStrings &&other) : language(std::move(other.language)), lines(std::move(other.lines)) {} + + bool IsValid() const { return !this->language.empty(); } }; /** Container for all the game strings. */ struct GameStrings { - uint version; ///< The version of the language strings. - std::shared_ptr cur_language; ///< The current (compiled) language. + uint version; ///< The version of the language strings. + LanguageStrings *cur_language; ///< The current (compiled) language. - std::vector> raw_strings; ///< The raw strings per language, first must be English/the master language!. - std::vector> compiled_strings; ///< The compiled strings per language, first must be English/the master language!. - StringList string_names; ///< The names of the compiled strings. + std::vector raw_strings; ///< The raw strings per language, first must be English/the master language!. + std::vector compiled_strings; ///< The compiled strings per language, first must be English/the master language!. + StringList string_names; ///< The names of the compiled strings. void Compile(); + + GameStrings() = default; + + GameStrings(const GameStrings &) = delete; + GameStrings(GameStrings &&) = delete; + GameStrings &operator=(const GameStrings &) = delete; + GameStrings &operator=(GameStrings &&) = delete; }; #endif /* GAME_TEXT_HPP */ diff --git a/src/gfx_func.h b/src/gfx_func.h index 70c0ea4569..ec105f286a 100644 --- a/src/gfx_func.h +++ b/src/gfx_func.h @@ -114,7 +114,7 @@ int DrawString(int left, int right, int top, StringID str, TextColour colour = T int DrawStringMultiLine(int left, int right, int top, int bottom, const char *str, TextColour colour = TC_FROMSTRING, StringAlignment align = (SA_TOP | SA_LEFT), bool underline = false, FontSize fontsize = FS_NORMAL); int DrawStringMultiLine(int left, int right, int top, int bottom, StringID str, TextColour colour = TC_FROMSTRING, StringAlignment align = (SA_TOP | SA_LEFT), bool underline = false, FontSize fontsize = FS_NORMAL); -void DrawCharCentered(uint32 c, int x, int y, TextColour colour); +void DrawCharCentered(WChar c, int x, int y, TextColour colour); void GfxFillRect(int left, int top, int right, int bottom, int colour, FillRectMode mode = FILLRECT_OPAQUE); void GfxFillPolygon(const std::vector &shape, int colour, FillRectMode mode = FILLRECT_OPAQUE); @@ -168,7 +168,7 @@ void SortResolutions(); bool ToggleFullScreen(bool fs); /* gfx.cpp */ -byte GetCharacterWidth(FontSize size, uint32 key); +byte GetCharacterWidth(FontSize size, WChar key); byte GetDigitWidth(FontSize size = FS_NORMAL); void GetBroadestDigit(uint *front, uint *next, FontSize size = FS_NORMAL); diff --git a/src/gfxinit.cpp b/src/gfxinit.cpp index 80c730dd06..a371305999 100644 --- a/src/gfxinit.cpp +++ b/src/gfxinit.cpp @@ -134,7 +134,7 @@ void CheckExternalFiles() const GraphicsSet *used_set = BaseGraphics::GetUsedSet(); - DEBUG(grf, 1, "Using the %s base graphics set", used_set->name); + DEBUG(grf, 1, "Using the %s base graphics set", used_set->name.c_str()); static const size_t ERROR_MESSAGE_LENGTH = 256; static const size_t MISSING_FILE_MESSAGE_LENGTH = 128; @@ -149,7 +149,7 @@ void CheckExternalFiles() if (used_set->GetNumInvalid() != 0) { /* Not all files were loaded successfully, see which ones */ - add_pos += seprintf(add_pos, last, "Trying to load graphics set '%s', but it is incomplete. The game will probably not run correctly until you properly install this set or select another one. See section 4.1 of README.md.\n\nThe following files are corrupted or missing:\n", used_set->name); + add_pos += seprintf(add_pos, last, "Trying to load graphics set '%s', but it is incomplete. The game will probably not run correctly until you properly install this set or select another one. See section 4.1 of README.md.\n\nThe following files are corrupted or missing:\n", used_set->name.c_str()); for (uint i = 0; i < GraphicsSet::NUM_FILES; i++) { MD5File::ChecksumResult res = GraphicsSet::CheckMD5(&used_set->files[i], BASESET_DIR); if (res != MD5File::CR_MATCH) add_pos += seprintf(add_pos, last, "\t%s is %s (%s)\n", used_set->files[i].filename, res == MD5File::CR_MISMATCH ? "corrupt" : "missing", used_set->files[i].missing_warning); @@ -159,7 +159,7 @@ void CheckExternalFiles() const SoundsSet *sounds_set = BaseSounds::GetUsedSet(); if (sounds_set->GetNumInvalid() != 0) { - add_pos += seprintf(add_pos, last, "Trying to load sound set '%s', but it is incomplete. The game will probably not run correctly until you properly install this set or select another one. See section 4.1 of README.md.\n\nThe following files are corrupted or missing:\n", sounds_set->name); + add_pos += seprintf(add_pos, last, "Trying to load sound set '%s', but it is incomplete. The game will probably not run correctly until you properly install this set or select another one. See section 4.1 of README.md.\n\nThe following files are corrupted or missing:\n", sounds_set->name.c_str()); assert_compile(SoundsSet::NUM_FILES == 1); /* No need to loop each file, as long as there is only a single @@ -503,11 +503,11 @@ bool GraphicsSet::FillSetDetails(IniFile *ini, const char *path, const char *ful IniItem *item; fetch_metadata("palette"); - this->palette = (*item->value == 'D' || *item->value == 'd') ? PAL_DOS : PAL_WINDOWS; + this->palette = (item->value.value()[0] == 'D' || item->value.value()[0] == 'd') ? PAL_DOS : PAL_WINDOWS; /* Get optional blitter information. */ item = metadata->GetItem("blitter", false); - this->blitter = (item != nullptr && *item->value == '3') ? BLT_32BPP : BLT_8BPP; + this->blitter = (item != nullptr && item->value.value()[0] == '3') ? BLT_32BPP : BLT_8BPP; } return ret; } diff --git a/src/group.h b/src/group.h index 4a16d47b18..c944764dd2 100644 --- a/src/group.h +++ b/src/group.h @@ -16,6 +16,7 @@ #include "vehicle_type.h" #include "engine_type.h" #include "livery.h" +#include typedef Pool GroupPool; extern GroupPool _group_pool; ///< Pool of groups. @@ -63,7 +64,7 @@ struct GroupStatistics { /** Group data. */ struct Group : GroupPool::PoolItem<&_group_pool> { - char *name; ///< Group Name + std::string name; ///< Group Name Owner owner; ///< Group Owner VehicleType vehicle_type; ///< Vehicle type of the group @@ -76,7 +77,6 @@ struct Group : GroupPool::PoolItem<&_group_pool> { GroupID parent; ///< Parent group Group(CompanyID owner = INVALID_COMPANY); - ~Group(); }; diff --git a/src/group_cmd.cpp b/src/group_cmd.cpp index 8e5dd29d8a..ab57ace201 100644 --- a/src/group_cmd.cpp +++ b/src/group_cmd.cpp @@ -298,11 +298,6 @@ Group::Group(Owner owner) this->folded = false; } -Group::~Group() -{ - free(this->name); -} - /** * Create a new vehicle group. @@ -436,10 +431,12 @@ CommandCost CmdAlterGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 } if (flags & DC_EXEC) { - /* Delete the old name */ - free(g->name); /* Assign the new one */ - g->name = reset ? nullptr : stredup(text); + if (reset) { + g->name.clear(); + } else { + g->name = text; + } } } else { /* Set group parent */ diff --git a/src/hotkeys.cpp b/src/hotkeys.cpp index 290a202017..90b7a09997 100644 --- a/src/hotkeys.cpp +++ b/src/hotkeys.cpp @@ -292,7 +292,7 @@ void HotkeyList::Load(IniFile *ini) IniItem *item = group->GetItem(hotkey->name, false); if (item != nullptr) { hotkey->keycodes.clear(); - if (item->value != nullptr) ParseHotkeys(hotkey, item->value); + if (item->value.has_value()) ParseHotkeys(hotkey, item->value->c_str()); } } } diff --git a/src/ini.cpp b/src/ini.cpp index a02d4c14da..f81d109ff2 100644 --- a/src/ini.cpp +++ b/src/ini.cpp @@ -12,9 +12,11 @@ #include "ini_type.h" #include "string_func.h" #include "fileio_func.h" +#include #if (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309L) || (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 500) # include +# include #endif #ifdef _WIN32 @@ -45,31 +47,33 @@ bool IniFile::SaveToDisk(const char *filename) * that file. This to prevent that when OpenTTD crashes during the save * you end up with a truncated configuration file. */ - char file_new[MAX_PATH]; + std::string file_new{ filename }; + file_new.append(".new"); - strecpy(file_new, filename, lastof(file_new)); - strecat(file_new, ".new", lastof(file_new)); - FILE *f = fopen(file_new, "w"); - if (f == nullptr) return false; + std::ofstream os(OTTD2FS(file_new.c_str())); + if (os.fail()) return false; for (const IniGroup *group = this->group; group != nullptr; group = group->next) { - if (group->comment) fputs(group->comment, f); - fprintf(f, "[%s]\n", group->name); + os << group->comment << "[" << group->name << "]\n"; for (const IniItem *item = group->item; item != nullptr; item = item->next) { - if (item->comment != nullptr) fputs(item->comment, f); + os << item->comment; /* protect item->name with quotes if needed */ - if (strchr(item->name, ' ') != nullptr || - item->name[0] == '[') { - fprintf(f, "\"%s\"", item->name); + if (item->name.find(' ') != std::string::npos || + item->name[0] == '[') { + os << "\"" << item->name << "\""; } else { - fprintf(f, "%s", item->name); + os << item->name; } - fprintf(f, " = %s\n", item->value == nullptr ? "" : item->value); + os << " = " << item->value.value_or("") << "\n"; } } - if (this->comment) fputs(this->comment, f); + os << this->comment; + + os.flush(); + os.close(); + if (os.fail()) return false; /* * POSIX (and friends) do not guarantee that when a file is closed it is @@ -78,11 +82,10 @@ bool IniFile::SaveToDisk(const char *filename) * (modification date etc.) is not important to us; only the real data is. */ #if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0 - int ret = fdatasync(fileno(f)); - fclose(f); + int f = open(file_new.c_str(), O_RDWR); + int ret = fdatasync(f); + close(f); if (ret != 0) return false; -#else - fclose(f); #endif #if defined(_WIN32) @@ -91,7 +94,7 @@ bool IniFile::SaveToDisk(const char *filename) /* Allocate space for one more \0 character. */ TCHAR tfilename[MAX_PATH + 1], tfile_new[MAX_PATH + 1]; _tcsncpy(tfilename, OTTD2FS(filename), MAX_PATH); - _tcsncpy(tfile_new, OTTD2FS(file_new), MAX_PATH); + _tcsncpy(tfile_new, OTTD2FS(file_new.c_str()), MAX_PATH); /* SHFileOperation wants a double '\0' terminated string. */ tfilename[MAX_PATH - 1] = '\0'; tfile_new[MAX_PATH - 1] = '\0'; @@ -107,8 +110,8 @@ bool IniFile::SaveToDisk(const char *filename) shfopt.pTo = tfilename; SHFileOperation(&shfopt); #else - if (rename(file_new, filename) < 0) { - DEBUG(misc, 0, "Renaming %s to %s failed; configuration not saved", file_new, filename); + if (rename(file_new.c_str(), filename) < 0) { + DEBUG(misc, 0, "Renaming %s to %s failed; configuration not saved", file_new.c_str(), filename); } #endif diff --git a/src/ini_load.cpp b/src/ini_load.cpp index 0ab4967736..15e947618a 100644 --- a/src/ini_load.cpp +++ b/src/ini_load.cpp @@ -19,12 +19,10 @@ * Construct a new in-memory item of an Ini file. * @param parent the group we belong to * @param name the name of the item - * @param last the last element of the name of the item */ -IniItem::IniItem(IniGroup *parent, const char *name, const char *last) : next(nullptr), value(nullptr), comment(nullptr) +IniItem::IniItem(IniGroup *parent, const std::string &name) : next(nullptr) { - this->name = stredup(name, last); - str_validate(this->name, this->name + strlen(this->name)); + this->name = str_validate(name); *parent->last_item = this; parent->last_item = &this->next; @@ -33,10 +31,6 @@ IniItem::IniItem(IniGroup *parent, const char *name, const char *last) : next(nu /** Free everything we loaded. */ IniItem::~IniItem() { - free(this->name); - free(this->value); - free(this->comment); - delete this->next; } @@ -46,20 +40,21 @@ IniItem::~IniItem() */ void IniItem::SetValue(const char *value) { - free(this->value); - this->value = stredup(value); + if (value == nullptr) { + this->value.reset(); + } else { + this->value.emplace(value); + } } /** * Construct a new in-memory group of an Ini file. * @param parent the file we belong to * @param name the name of the group - * @param last the last element of the name of the group */ -IniGroup::IniGroup(IniLoadFile *parent, const char *name, const char *last) : next(nullptr), type(IGT_VARIABLES), item(nullptr), comment(nullptr) +IniGroup::IniGroup(IniLoadFile *parent, const std::string &name) : next(nullptr), type(IGT_VARIABLES), item(nullptr) { - this->name = stredup(name, last); - str_validate(this->name, this->name + strlen(this->name)); + this->name = str_validate(name); this->last_item = &this->item; *parent->last_group = this; @@ -67,7 +62,7 @@ IniGroup::IniGroup(IniLoadFile *parent, const char *name, const char *last) : ne if (parent->list_group_names != nullptr) { for (uint i = 0; parent->list_group_names[i] != nullptr; i++) { - if (strcmp(this->name, parent->list_group_names[i]) == 0) { + if (this->name == parent->list_group_names[i]) { this->type = IGT_LIST; return; } @@ -75,7 +70,7 @@ IniGroup::IniGroup(IniLoadFile *parent, const char *name, const char *last) : ne } if (parent->seq_group_names != nullptr) { for (uint i = 0; parent->seq_group_names[i] != nullptr; i++) { - if (strcmp(this->name, parent->seq_group_names[i]) == 0) { + if (this->name == parent->seq_group_names[i]) { this->type = IGT_SEQUENCE; return; } @@ -86,9 +81,6 @@ IniGroup::IniGroup(IniLoadFile *parent, const char *name, const char *last) : ne /** Free everything we loaded. */ IniGroup::~IniGroup() { - free(this->name); - free(this->comment); - delete this->item; delete this->next; } @@ -100,16 +92,16 @@ IniGroup::~IniGroup() * @param create whether to create an item when not found or not. * @return the requested item or nullptr if not found. */ -IniItem *IniGroup::GetItem(const char *name, bool create) +IniItem *IniGroup::GetItem(const std::string &name, bool create) { for (IniItem *item = this->item; item != nullptr; item = item->next) { - if (strcmp(item->name, name) == 0) return item; + if (item->name == name) return item; } if (!create) return nullptr; /* otherwise make a new one */ - return new IniItem(this, name, nullptr); + return new IniItem(this, name); } /** @@ -129,7 +121,6 @@ void IniGroup::Clear() */ IniLoadFile::IniLoadFile(const char * const *list_group_names, const char * const *seq_group_names) : group(nullptr), - comment(nullptr), list_group_names(list_group_names), seq_group_names(seq_group_names) { @@ -139,7 +130,6 @@ IniLoadFile::IniLoadFile(const char * const *list_group_names, const char * cons /** Free everything we loaded. */ IniLoadFile::~IniLoadFile() { - free(this->comment); delete this->group; } @@ -147,26 +137,21 @@ IniLoadFile::~IniLoadFile() * Get the group with the given name. If it doesn't exist * and \a create_new is \c true create a new group. * @param name name of the group to find. - * @param len the maximum length of said name (\c 0 means length of the string). * @param create_new Allow creation of group if it does not exist. * @return The requested group if it exists or was created, else \c nullptr. */ -IniGroup *IniLoadFile::GetGroup(const char *name, size_t len, bool create_new) +IniGroup *IniLoadFile::GetGroup(const std::string &name, bool create_new) { - if (len == 0) len = strlen(name); - /* does it exist already? */ for (IniGroup *group = this->group; group != nullptr; group = group->next) { - if (!strncmp(group->name, name, len) && group->name[len] == 0) { - return group; - } + if (group->name == name) return group; } if (!create_new) return nullptr; /* otherwise make a new one */ - IniGroup *group = new IniGroup(this, name, name + len - 1); - group->comment = stredup("\n"); + IniGroup *group = new IniGroup(this, name); + group->comment = "\n"; return group; } @@ -182,7 +167,7 @@ void IniLoadFile::RemoveGroup(const char *name) /* does it exist already? */ for (group = this->group; group != nullptr; prev = group, group = group->next) { - if (strncmp(group->name, name, len) == 0) { + if (group->name.compare(0, len, name) == 0) { break; } } @@ -266,17 +251,17 @@ void IniLoadFile::LoadFromDisk(const char *filename, Subdirectory subdir, std::s e--; } s++; // skip [ - group = new IniGroup(this, s, e - 1); + group = new IniGroup(this, std::string(s, e - s)); if (comment_size != 0) { - group->comment = stredup(comment, comment + comment_size - 1); + group->comment.assign(comment, comment_size); comment_size = 0; } } else if (group != nullptr) { if (group->type == IGT_SEQUENCE) { /* A sequence group, use the line as item name without further interpretation. */ - IniItem *item = new IniItem(group, buffer, e - 1); + IniItem *item = new IniItem(group, std::string(buffer, e - buffer)); if (comment_size) { - item->comment = stredup(comment, comment + comment_size - 1); + item->comment.assign(comment, comment_size); comment_size = 0; } continue; @@ -292,9 +277,9 @@ void IniLoadFile::LoadFromDisk(const char *filename, Subdirectory subdir, std::s } /* it's an item in an existing group */ - IniItem *item = new IniItem(group, s, t - 1); + IniItem *item = new IniItem(group, std::string(s, t - s)); if (comment_size != 0) { - item->comment = stredup(comment, comment + comment_size - 1); + item->comment.assign(comment, comment_size); comment_size = 0; } @@ -310,8 +295,11 @@ void IniLoadFile::LoadFromDisk(const char *filename, Subdirectory subdir, std::s *e = '\0'; /* If the value was not quoted and empty, it must be nullptr */ - item->value = (!quoted && e == t) ? nullptr : stredup(t); - if (item->value != nullptr) str_validate(item->value, item->value + strlen(item->value)); + if (!quoted && e == t) { + item->value.reset(); + } else { + item->value = str_validate(std::string(t)); + } } else { /* it's an orphan item */ this->ReportFileError("ini: '", buffer, "' outside of group"); @@ -319,7 +307,7 @@ void IniLoadFile::LoadFromDisk(const char *filename, Subdirectory subdir, std::s } if (comment_size > 0) { - this->comment = stredup(comment, comment + comment_size - 1); + this->comment.assign(comment, comment_size); comment_size = 0; } diff --git a/src/ini_type.h b/src/ini_type.h index d2166a7e20..17331ccc58 100644 --- a/src/ini_type.h +++ b/src/ini_type.h @@ -11,6 +11,8 @@ #define INI_TYPE_H #include "fileio_type.h" +#include +#include "3rdparty/optional/ottd_optional.h" #include @@ -23,12 +25,12 @@ enum IniGroupType { /** A single "line" in an ini file. */ struct IniItem { - IniItem *next; ///< The next item in this group - char *name; ///< The name of this item - char *value; ///< The value of this item - char *comment; ///< The comment associated with this item + IniItem *next; ///< The next item in this group + std::string name; ///< The name of this item + opt::optional value; ///< The value of this item + std::string comment; ///< The comment associated with this item - IniItem(struct IniGroup *parent, const char *name, const char *last = nullptr); + IniItem(struct IniGroup *parent, const std::string &name); ~IniItem(); void SetValue(const char *value); @@ -40,13 +42,13 @@ struct IniGroup { IniGroupType type; ///< type of group IniItem *item; ///< the first item in the group IniItem **last_item; ///< the last item in the group - char *name; ///< name of group - char *comment; ///< comment for group + std::string name; ///< name of group + std::string comment; ///< comment for group - IniGroup(struct IniLoadFile *parent, const char *name, const char *last = nullptr); + IniGroup(struct IniLoadFile *parent, const std::string &name); ~IniGroup(); - IniItem *GetItem(const char *name, bool create); + IniItem *GetItem(const std::string &name, bool create); void Clear(); }; @@ -54,14 +56,14 @@ struct IniGroup { struct IniLoadFile { IniGroup *group; ///< the first group in the ini IniGroup **last_group; ///< the last group in the ini - char *comment; ///< last comment in file + std::string comment; ///< last comment in file const char * const *list_group_names; ///< nullptr terminated list with group names that are lists const char * const *seq_group_names; ///< nullptr terminated list with group names that are sequences. IniLoadFile(const char * const *list_group_names = nullptr, const char * const *seq_group_names = nullptr); virtual ~IniLoadFile(); - IniGroup *GetGroup(const char *name, size_t len = 0, bool create_new = true); + IniGroup *GetGroup(const std::string &name, bool create_new = true); void RemoveGroup(const char *name); void LoadFromDisk(const char *filename, Subdirectory subdir, std::string *save = nullptr); diff --git a/src/lang/dutch.txt b/src/lang/dutch.txt index 9a43208f22..0fced179f5 100644 --- a/src/lang/dutch.txt +++ b/src/lang/dutch.txt @@ -935,6 +935,7 @@ STR_GAME_OPTIONS_CURRENCY_MXN :Mexicaanse peso STR_GAME_OPTIONS_CURRENCY_NTD :Nieuwe Taiwanse dollar (NTD) STR_GAME_OPTIONS_CURRENCY_CNY :Chinese Renminbi (CNY) STR_GAME_OPTIONS_CURRENCY_HKD :Hong Kong Dollar (HKD) +STR_GAME_OPTIONS_CURRENCY_INR :Indiase rupee (INR) ############ end of currency region STR_GAME_OPTIONS_ROAD_VEHICLES_FRAME :{BLACK}Wegvoertuigen diff --git a/src/lang/indonesian.txt b/src/lang/indonesian.txt index bb47acc9f0..9e372f2ed9 100644 --- a/src/lang/indonesian.txt +++ b/src/lang/indonesian.txt @@ -3605,6 +3605,7 @@ STR_REPLACE_WAGONS :Gerbong STR_REPLACE_ALL_RAILTYPE :Semua kereta STR_REPLACE_HELP_RAILTYPE :{BLACK}Pilih jenis kereta yang anda inginkan untuk diganti +STR_REPLACE_HELP_ROADTYPE :{BLACK}Pilih jenis jalan yang anda inginkan untuk diganti STR_REPLACE_HELP_REPLACE_INFO_TAB :{BLACK}Menampilkan kendaraan terpilih di sisi kiri yang akan diganti, jika ada STR_REPLACE_RAIL_VEHICLES :Kereta STR_REPLACE_ELRAIL_VEHICLES :Kereta Listrik diff --git a/src/lang/latvian.txt b/src/lang/latvian.txt index 78259df150..41fdcd800b 100644 --- a/src/lang/latvian.txt +++ b/src/lang/latvian.txt @@ -244,6 +244,7 @@ STR_TOOLTIP_CLOSE_WINDOW :{BLACK}Aizvērt STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS :{BLACK}Loga virsraksts - vilkt to, lai pārvietotu logu STR_TOOLTIP_SHADE :{BLACK}Aizēnot logu - rādīt tikai virsrakstu STR_TOOLTIP_DEBUG :{BLACK}Rādīt NewGRF atkļūdošanas informāciju +STR_TOOLTIP_DEFSIZE :{BLACK}Mainīt loga izmēru uz tā noklusējuma izmēru. Ctrl+klikšķis, lai saglabātu esošo izmēru kā noklusējuma STR_TOOLTIP_STICKY :{BLACK}Atzīmēt šo logu kā neaizveramu ar "Aizvērt visus logus" taustiņu. Ctrl+klikšķis, lai saglabātu stāvokli kā noklusējumu STR_TOOLTIP_RESIZE :{BLACK}Klikšķināt un vilkt, lai mainītu šī loga lielumu STR_TOOLTIP_TOGGLE_LARGE_SMALL_WINDOW :{BLACK}Pārslēgties starp lielu/mazu loga izmēru @@ -361,6 +362,7 @@ STR_SCENEDIT_TOOLBAR_LANDSCAPE_GENERATION :{BLACK}Ainavas STR_SCENEDIT_TOOLBAR_TOWN_GENERATION :{BLACK}Pilsētu radīšana STR_SCENEDIT_TOOLBAR_INDUSTRY_GENERATION :{BLACK}Ražotņu radīšana STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION :{BLACK}Ceļu būvēšana +STR_SCENEDIT_TOOLBAR_TRAM_CONSTRUCTION :{BLACK}Tramvaju sliežu ceļu būvniecība STR_SCENEDIT_TOOLBAR_PLANT_TREES :{BLACK}Stādīt kokus. Shift pārslēdz būvēšanu/izmaksu tāmes rādīšanu STR_SCENEDIT_TOOLBAR_PLACE_SIGN :{BLACK}Novietot zīmi STR_SCENEDIT_TOOLBAR_PLACE_OBJECT :{BLACK}Novietot objektu. Shift pārslēdz būvēšanu/izmaksu tāmes rādīšanu @@ -651,6 +653,7 @@ STR_MUSIC_EFFECTS_VOLUME :{TINY_FONT}{BLA STR_MUSIC_TRACK_NONE :{TINY_FONT}{DKGREEN}-- STR_MUSIC_TRACK_DIGIT :{TINY_FONT}{DKGREEN}{ZEROFILL_NUM} STR_MUSIC_TITLE_NONE :{TINY_FONT}{DKGREEN}------ +STR_MUSIC_TITLE_NOMUSIC :{TINY_FONT}{DKGREEN}Mūzika nav pieejama STR_MUSIC_TITLE_NAME :{TINY_FONT}{DKGREEN}"{STRING}" STR_MUSIC_TRACK :{TINY_FONT}{BLACK}Celiņš STR_MUSIC_XTITLE :{TINY_FONT}{BLACK}Nosaukums @@ -884,10 +887,10 @@ STR_NEWS_EXCLUSIVE_RIGHTS_DESCRIPTION :{BIG_FONT}{BLAC # Extra view window STR_EXTRA_VIEW_PORT_TITLE :{WHITE}Skatvieta {COMMA} -STR_EXTRA_VIEW_MOVE_VIEW_TO_MAIN :{BLACK}Kopēt uz skatvietu +STR_EXTRA_VIEW_MOVE_VIEW_TO_MAIN :{BLACK}Mainīt skatvietu STR_EXTRA_VIEW_MOVE_VIEW_TO_MAIN_TT :{BLACK}Kopēt galvenā skata atrašanās vietu uz šo skatvietu -STR_EXTRA_VIEW_MOVE_MAIN_TO_VIEW :{BLACK}Kopēt no skatvietas -STR_EXTRA_VIEW_MOVE_MAIN_TO_VIEW_TT :{BLACK}Ielīmēt šīs skatvietas atrašanās vietu uz galveno skatu +STR_EXTRA_VIEW_MOVE_MAIN_TO_VIEW :{BLACK}Mainīt galveno skatu +STR_EXTRA_VIEW_MOVE_MAIN_TO_VIEW_TT :{BLACK}Kopēt šīs skatvietas atrašanās vietu uz galveno skatu # Game options window STR_GAME_OPTIONS_CAPTION :{WHITE}Spēles opcijas @@ -933,6 +936,7 @@ STR_GAME_OPTIONS_CURRENCY_RUB :Jaunais Krievij STR_GAME_OPTIONS_CURRENCY_MXN :Meksikas peso (MXN) STR_GAME_OPTIONS_CURRENCY_NTD :Jaunais Taivānas dolārs (NTD) STR_GAME_OPTIONS_CURRENCY_CNY :Ķīnas juaņa (CNY) +STR_GAME_OPTIONS_CURRENCY_HKD :Honkongas dolārs (HKD) STR_GAME_OPTIONS_CURRENCY_INR :Indijas rūpija (INR) ############ end of currency region @@ -997,6 +1001,7 @@ STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_2X_ZOOM :Divkāršs STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_4X_ZOOM :Četrkāršs STR_GAME_OPTIONS_FONT_ZOOM :{BLACK}Fonta izmērs +STR_GAME_OPTIONS_FONT_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Izvēlieties saskarnes fonta izmēru STR_GAME_OPTIONS_FONT_ZOOM_DROPDOWN_NORMAL :Normāls STR_GAME_OPTIONS_FONT_ZOOM_DROPDOWN_2X_ZOOM :Divkāršs izmērs @@ -1016,6 +1021,7 @@ STR_GAME_OPTIONS_BASE_MUSIC_TOOLTIP :{BLACK}Atlasīt STR_GAME_OPTIONS_BASE_MUSIC_STATUS :{RED}{NUM} bojāt{P s i u} fail{P s i u} STR_GAME_OPTIONS_BASE_MUSIC_DESCRIPTION_TOOLTIP :{BLACK}Papildinformācija par pamata mūzikas kopu +STR_ERROR_RESOLUTION_LIST_FAILED :{WHITE}Neizdevās saņemt sarakstu ar atbalstītajām izšķirtspējām STR_ERROR_FULLSCREEN_FAILED :{WHITE}Pilnekrāna spēles iestatīšana neizdevās # Custom currency window @@ -1133,6 +1139,7 @@ STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_INGAME :Spēles iestat STR_CONFIG_SETTING_TYPE_DROPDOWN_COMPANY_MENU :Uzņēmuma iestatījumi (tiek iekļauti saglabājumos, ietekmē tikai jaunās spēles) STR_CONFIG_SETTING_TYPE_DROPDOWN_COMPANY_INGAME :Uzņēmuma iestatījumi (tiek iekļauti saglabājumā, ietekmē tikai pašreizējo uzņēmumu) STR_CONFIG_SETTING_CATEGORY_HIDES :{BLACK}Rādīt visus meklēšanas rezultātus, iestatot{}{SILVER}Kategoriju {BLACK}uz {WHITE}{STRING} +STR_CONFIG_SETTING_TYPE_HIDES :{BLACK}Rādīt visus meklēšanas rezultātus, iestatot{}{SILVER}Veidu {BLACK}uz {WHITE}Visi iestatījumu veidi STR_CONFIG_SETTING_CATEGORY_AND_TYPE_HIDES :{BLACK}Rādīt visus meklēšanas rezultātus, iestatot{}{SILVER}Kategorija {BLACK}uz {WHITE}{STRING} {BLACK}un {SILVER}Tips {BLACK}uz {WHITE}Visi iestatījumu veidi STR_CONFIG_SETTINGS_NONE :{WHITE}-Nav- @@ -1157,17 +1164,21 @@ STR_CONFIG_SETTING_MAXIMUM_INITIAL_LOAN_HELPTEXT :Maksimālais ai STR_CONFIG_SETTING_INTEREST_RATE :Procentu likme: {STRING} STR_CONFIG_SETTING_INTEREST_RATE_HELPTEXT :Aizdevumu procentu likme; ja ieslēgts, ietekmē arī inflāciju STR_CONFIG_SETTING_RUNNING_COSTS :Kārtējās izmaksas: {STRING} +STR_CONFIG_SETTING_RUNNING_COSTS_HELPTEXT :Iestaties uzturēšanas un ekspluatācijas izmaksu līmeni transportlīdzekļiem un infrastruktūrai STR_CONFIG_SETTING_CONSTRUCTION_SPEED :Būvēšanas ātrums: {STRING} STR_CONFIG_SETTING_CONSTRUCTION_SPEED_HELPTEXT :MI (mākslīgā intelekta) būvniecības darbību daudzuma ierobežošana STR_CONFIG_SETTING_VEHICLE_BREAKDOWNS :Transportlīdzekļu bojāšanās: {STRING} +STR_CONFIG_SETTING_VEHICLE_BREAKDOWNS_HELPTEXT :Nosaka, cik bieži var salūzt nepietiekami apkalpoti transportlīdzekļi STR_CONFIG_SETTING_SUBSIDY_MULTIPLIER :Subsīdiju reizinātājs: {STRING} STR_CONFIG_SETTING_SUBSIDY_MULTIPLIER_HELPTEXT :Iestatīt, cik daudz maksāt par subsidētajiem savienojumiem STR_CONFIG_SETTING_CONSTRUCTION_COSTS :Būvēšanas izmaksas: {STRING} STR_CONFIG_SETTING_CONSTRUCTION_COSTS_HELPTEXT :Iestatīt būvēšanas un pirkumu izmaksas STR_CONFIG_SETTING_RECESSIONS :Lejupslīde: {STRING} +STR_CONFIG_SETTING_RECESSIONS_HELPTEXT :Ja ieslēgts, ik pa laikam var gadīties recesijas. To laikā visa ražošana būtiski samazinās (tā atgriežas sākotnējā līmenī pēc recesijas beigām). STR_CONFIG_SETTING_TRAIN_REVERSING :Neatļaut vilcienu apgriešanos stacijās: {STRING} STR_CONFIG_SETTING_TRAIN_REVERSING_HELPTEXT :Ja ieslēgts, stacijās vilcieni negriezīsies pretējā virzienā, pat ja braucot tādā veidā tie atrastu īsāku ceļu un nākamo pieturu; izņēmums ir gala stacijas STR_CONFIG_SETTING_DISASTERS :Katastrofas: {STRING} +STR_CONFIG_SETTING_DISASTERS_HELPTEXT :Pārslēgt katastrofas, kas laiku pa laikam var bloķēt vai iznīcināt transportlīdzekļus un infrastruktūru STR_CONFIG_SETTING_CITY_APPROVAL :Pilsētu domju attieksme pret platības pārstrukturēšanu: {STRING} STR_CONFIG_SETTING_CITY_APPROVAL_HELPTEXT :Izvēlieties, cik lielā mērā trokšņi un vides bojājumi ietekmē uzņēmuma reitingu un turpmākās būvniecības darbības viņu teritorijā @@ -1178,6 +1189,8 @@ STR_CONFIG_SETTING_AUTOSLOPE :Atļaut ainavas STR_CONFIG_SETTING_AUTOSLOPE_HELPTEXT :Atļauj ainavas veidošanu zem ekām un ceļiem bez to nojaukšanas STR_CONFIG_SETTING_CATCHMENT :Atļaut realistiskākas, palielinātas apkalpojamās platības: {STRING} STR_CONFIG_SETTING_CATCHMENT_HELPTEXT :Atšķirīga lieluma apkalpojamās platības dažādu veidu stacijām un lidostām +STR_CONFIG_SETTING_SERVE_NEUTRAL_INDUSTRIES :Uzņēmumu stacijas var apkalpot industrijas, kurām ir pievienotas neitrālas stacijas: {STRING} +STR_CONFIG_SETTING_SERVE_NEUTRAL_INDUSTRIES_HELPTEXT :Ja ieslēgts, industrijas ar pievienotām stacijām (piemēram, naftas ieguves platformas) var apkalpot arī netālu esošās uzņēmumumam piederošās stacijas. Ja izslēgts, šīs industrijas var apkalpot tikai to pašu stacijas. Tuvumā esošās uzņēmumu stacijas nevarēs tās apkalpot, un pievienotās stacijas neapkalpos preču veidus, kas nav atbilstošas attiecīgajai industrijai. STR_CONFIG_SETTING_EXTRADYNAMITE :Atļaut pilsētai piederošo ceļu, tiltu un tuneļu nojaukšanu: {STRING} STR_CONFIG_SETTING_EXTRADYNAMITE_HELPTEXT :Padara vieglāku pilsētai piederošas infrastruktūras un ēku nojaukšanu STR_CONFIG_SETTING_TRAIN_LENGTH :Maksimālais vilcienu garums: {STRING} @@ -1194,8 +1207,8 @@ STR_CONFIG_SETTING_TRAIN_SLOPE_STEEPNESS_HELPTEXT :Slīpu lauciņu STR_CONFIG_SETTING_PERCENTAGE :{COMMA}% STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS :Nogāžu stāvums autotransporta līdzekļiem: {STRING} STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS_HELPTEXT :Slīpu lauciņu nogāžu stāvums autotransporta līdzekļiem. Augstākas vērtības apgrūtina uzbraukšanu uzkalnā -STR_CONFIG_SETTING_FORBID_90_DEG :Aizliegt vilcieniem un kuģiem veikt 90 grādu pagriezienus: {STRING} -STR_CONFIG_SETTING_FORBID_90_DEG_HELPTEXT :90 grādu pagriezieni rodas, ja horizontālam sliežu ceļa posmam tieši seko vertikāls sliežu ceļa posms uz blakus esošā lauciņa. Tādējādi vilciens, šķērsojot lauciņu malas, veic 90 grādu pagriezienu, nevis parasto 45 grādu kā citām sliežu ceļu kombinācijām. Tas attiecas arī uz kuģu pagrieziena lenķiem +STR_CONFIG_SETTING_FORBID_90_DEG :Aizliegt vilcieniem veikt 90° pagriezienus: {STRING} +STR_CONFIG_SETTING_FORBID_90_DEG_HELPTEXT :90 grādu pagriezieni rodas, ja horizontālam sliežu ceļa posmam tieši seko vertikāls sliežu ceļa posms uz blakus esošā lauciņa. Tādējādi vilciens, šķērsojot lauciņu malas, veic 90 grādu pagriezienu, nevis parasto 45 grādu kā citām sliežu ceļu kombinācijām. Tas attiecas arī uz kuģu pagrieziena leņķiem. Tas arī attiecas uz kuģu pagriešanās rādiusu. STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS :Atļaut savienot stacijas, kas neatrodas tieši blakus: {STRING} STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS_HELPTEXT :Atļaut pievienot staciju daļas, tām nesaskaroties ar jau esošajām. Novietojot jaunās daļas, ir nepieciešams nospiest Ctrl+klikšķis STR_CONFIG_SETTING_INFLATION :Inflācija: {STRING} @@ -1240,7 +1253,7 @@ STR_CONFIG_SETTING_BRIBE_HELPTEXT :Lauj uzņēmumi STR_CONFIG_SETTING_ALLOW_EXCLUSIVE :Atļaut pirkt pārvadājumu izņēmuma tiesības: {STRING} STR_CONFIG_SETTING_ALLOW_EXCLUSIVE_HELPTEXT :Ja uzņēmums pērk pārvadājumu izņēmuma tiesības pilsētā, pretinieku stacijas (pasažieru un kravas) veselu gadu nesaņems nekādu kravu STR_CONFIG_SETTING_ALLOW_FUND_BUILDINGS :Atļaut ēku finansēšanu: {STRING} -STR_CONFIG_SETTING_ALLOW_FUND_BUILDINGS_HELPTEXT :Atļauj uzņēmumiem dot naudu pilsētām jaunu ēku finansēšanai +STR_CONFIG_SETTING_ALLOW_FUND_BUILDINGS_HELPTEXT :Atļauj uzņēmumiem dot naudu apdzīvotām vietām jaunu ēku finansēšanai STR_CONFIG_SETTING_ALLOW_FUND_ROAD :Atļaut finansēt vietējo ceļu atjaunošanu: {STRING} STR_CONFIG_SETTING_ALLOW_FUND_ROAD_HELPTEXT :Atļaut uzņēmumiem dot pilsētām naudu ceļu rekonstrukcijai, lai kaitētu ceļu pakalpojumiem pilsētās STR_CONFIG_SETTING_ALLOW_GIVE_MONEY :Atļaut pārsūtīt naudu citiem uzņēmumiem: {STRING} @@ -1251,8 +1264,8 @@ STR_CONFIG_SETTING_PLANE_SPEED :Lidmašīnu āt STR_CONFIG_SETTING_PLANE_SPEED_HELPTEXT :Iestatīt lidmašīnu nosacīto ātrumu salīdzinājumā ar citu veidu transportlīdzekļiem, lai samazinātu lidaparātu ienākumus STR_CONFIG_SETTING_PLANE_SPEED_VALUE :1 / {COMMA} STR_CONFIG_SETTING_PLANE_CRASHES :Lidmašīnu avāriju daudzums: {STRING} -STR_CONFIG_SETTING_PLANE_CRASHES_HELPTEXT :Iestatīt lidaparātu avāriju notikšanas iespējamību -STR_CONFIG_SETTING_PLANE_CRASHES_NONE :neviena +STR_CONFIG_SETTING_PLANE_CRASHES_HELPTEXT :Iestatīt nejaušu lidaparātu avāriju iespējamību.{}* Lielām lidmašīnām vienmēr ir risks avarēt, kad piezemējas mazās lidostās +STR_CONFIG_SETTING_PLANE_CRASHES_NONE :Nav* STR_CONFIG_SETTING_PLANE_CRASHES_REDUCED :samazināts STR_CONFIG_SETTING_PLANE_CRASHES_NORMAL :parasts STR_CONFIG_SETTING_STOP_ON_TOWN_ROAD :Atļaut caurbraucamas pieturvietas uz pilsētai piederošiem ceļiem: {STRING} @@ -1308,11 +1321,12 @@ STR_CONFIG_SETTING_LAND_GENERATOR :Zemes radītāj STR_CONFIG_SETTING_LAND_GENERATOR_HELPTEXT :Sākotnējais ģenerators ir atkarīgs no bāzes grafikas kopas, un veido fiksētas ainavas formas. TerraGenesis ir uz Perlina trokšņa balstīts ģenerators ar smalkākiem vadības iestatījumiem. STR_CONFIG_SETTING_LAND_GENERATOR_ORIGINAL :Sākotnējais STR_CONFIG_SETTING_LAND_GENERATOR_TERRA_GENESIS :TerraGenesis +STR_CONFIG_SETTING_TERRAIN_TYPE :Reljefa veids: {STRING} STR_CONFIG_SETTING_TERRAIN_TYPE_HELPTEXT :(Tikai TerraGenesis) Ainavas kalnainība STR_CONFIG_SETTING_INDUSTRY_DENSITY :Industriju blīvums: {STRING} STR_CONFIG_SETTING_INDUSTRY_DENSITY_HELPTEXT :Iestatiet, cik industrijas jāģenerē un kāds līmenis jāuztur spēles laikā -STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE :Maksimālais attālums no kartes malas naftas pārstrādes rūpnīcām: {STRING} -STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE_HELPTEXT :Naftas pārstrādes rūpnīcas ir būvējamas tikai kartes malu tuvumā, salu kartēm tas ir pie krasta +STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE :Naftas industriju maksimālais attālums no kartes malas: {STRING} +STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE_HELPTEXT :Limits, cik tālu no kartes malām drīkst taisīt naftas pārstrādes rūpnīcas un un naftas ieguves platformas. Uz salu kartēm tas nodrošina, ka šīs konstrukcijas tiek būvētas piekrastēs. Uz kartēm, kas ir lielākas par 256 lauciņiem šī vērtība tiek palielināta. STR_CONFIG_SETTING_SNOWLINE_HEIGHT :Sniega līnijas augstums: {STRING} STR_CONFIG_SETTING_SNOWLINE_HEIGHT_HELPTEXT :Noteikt, kādā augstumā sākas subarktiskā ainava. Sniegs arī ietekmē industriju rašanos un apdzīvoto vietu pieaugšanas prasības STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN :Apvidus nelīdzenums: {STRING} @@ -1331,6 +1345,7 @@ STR_CONFIG_SETTING_TREE_PLACER_NONE :Nav STR_CONFIG_SETTING_TREE_PLACER_ORIGINAL :Sākotnējais STR_CONFIG_SETTING_TREE_PLACER_IMPROVED :Uzlabotais STR_CONFIG_SETTING_ROAD_SIDE :Autotransporta līdzekļi: {STRING} +STR_CONFIG_SETTING_ROAD_SIDE_HELPTEXT :Izvēlieties braukšanas pusi STR_CONFIG_SETTING_HEIGHTMAP_ROTATION :Augstumu kartes pagriešana: {STRING} STR_CONFIG_SETTING_HEIGHTMAP_ROTATION_COUNTER_CLOCKWISE :Pret pulksteņa rādītāja virzienu STR_CONFIG_SETTING_HEIGHTMAP_ROTATION_CLOCKWISE :Pulksteņa rādītāja virzienā @@ -1353,8 +1368,10 @@ STR_CONFIG_SETTING_SCROLLMODE :Skatvietas riti STR_CONFIG_SETTING_SCROLLMODE_HELPTEXT :Uzvedība, kad ritina karti STR_CONFIG_SETTING_SCROLLMODE_DEFAULT :Pārvietot skatvietu ar labo peles pogu, peles pozīcija ir fiksēta STR_CONFIG_SETTING_SCROLLMODE_RMB_LOCKED :Pārvietot karti ar labo peles pogu, peles pozīcija ir fiksēta +STR_CONFIG_SETTING_SCROLLMODE_RMB :Pārvietot karti ar labo peles pogu STR_CONFIG_SETTING_SCROLLMODE_LMB :Pārvietot karti ar kreiso peles pogu STR_CONFIG_SETTING_SMOOTH_SCROLLING :Plūdena skatvietas ritināšana: {STRING} +STR_CONFIG_SETTING_SMOOTH_SCROLLING_HELPTEXT :Noteikt, kā galvenais skats ritina uz norādīto pozīciju, kad klikšķina uz mazās kartes vai kad dod komandu ritināt uz noteiktu kartes objektu. Ja ieslēgs, skatvieta ritinās gludi. Ja izslēgts, skats pārlec uz izvēlēto punktu. STR_CONFIG_SETTING_MEASURE_TOOLTIP :Rādīt mērījumu rīkjoslu, izmantojot dažādus būvniecības rīkus: {STRING} STR_CONFIG_SETTING_MEASURE_TOOLTIP_HELPTEXT :Rāda lauciņu attālumus un augstuma starpības, ar vilkšanu veicot būvniecības darbības STR_CONFIG_SETTING_LIVERIES :Rādīt uzņēmuma identitātes krāsas: {STRING} @@ -1384,6 +1401,7 @@ STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_COMMAND :Komanda+klikš STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_CONTROL :Ctrl+klikšķis STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_OFF :Izslēgta +STR_CONFIG_SETTING_RIGHT_MOUSE_WND_CLOSE :Aizvērt logu ar labo klikšķi: {STRING} STR_CONFIG_SETTING_RIGHT_MOUSE_WND_CLOSE_HELPTEXT :Labais klikšķis logā aizver logu. Izslēdz paskaidres parādīšanu ar labo klikšķi! STR_CONFIG_SETTING_AUTOSAVE :Automātiskā saglabāšana: {STRING} @@ -1477,6 +1495,7 @@ STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY_HELPTEXT :Cik daudz atmi STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY_VALUE :{COMMA} MiB STR_CONFIG_SETTING_SERVINT_ISPERCENT :Apkopju starplaiki procentos: {STRING} +STR_CONFIG_SETTING_SERVINT_ISPERCENT_HELPTEXT :Izvēlieties, vai transportlīdzekļu apkopi veikt pēc fiksēta laika kopš iepriekšējās apkopes vai, kad uzticamība nokrīt zem kāda noteiktas daļas no maksimālās uzticamības STR_CONFIG_SETTING_SERVINT_TRAINS :Vilcienu apkopju noklusējuma starplaiks: {STRING} STR_CONFIG_SETTING_SERVINT_TRAINS_HELPTEXT :Izvēlēties jaunajiem sliežu transportlīdzekļiem apkopju noklusējuma starplaiku, ja tiem tas nav noteikts STR_CONFIG_SETTING_SERVINT_VALUE :{COMMA}{NBSP}dien{P 0 a as u}/% @@ -1533,6 +1552,7 @@ STR_CONFIG_SETTING_COLOURED_NEWS_YEAR :Krāsaini avī STR_CONFIG_SETTING_COLOURED_NEWS_YEAR_HELPTEXT :Gads kad sāk drukāt krāsainas avīzes. Pirms šā gada tās ir melnbaltas STR_CONFIG_SETTING_STARTING_YEAR :Sākuma gads: {STRING} STR_CONFIG_SETTING_ENDING_YEAR :Vērtēšanas beigu gads: {STRING} +STR_CONFIG_SETTING_ENDING_YEAR_HELPTEXT :Spēles beigas gads (tiek izmantots rezultāta noteikšanai). Šī gada beigās uzņēmuma rezultāti tiek ierakstīti un uz ekrāna tiek parādīti labākie rezultāti, bet spēlētāji var turpināt spēlēt arī pēc šī datuma.{}Ja tas ir norādīts pirms spēles sākuma datuma, labākie rezultāti nekad netiek parādīti. STR_CONFIG_SETTING_ENDING_YEAR_VALUE :{NUM} STR_CONFIG_SETTING_ENDING_YEAR_ZERO :Nekad STR_CONFIG_SETTING_SMOOTH_ECONOMY :Atļaut vienmērīgas izmaiņas ekonomikā: {STRING} @@ -1621,12 +1641,12 @@ STR_CONFIG_SETTING_TOWN_GROWTH_SLOW :mazs STR_CONFIG_SETTING_TOWN_GROWTH_NORMAL :vidējs STR_CONFIG_SETTING_TOWN_GROWTH_FAST :liels STR_CONFIG_SETTING_TOWN_GROWTH_VERY_FAST :ļoti liels -STR_CONFIG_SETTING_LARGER_TOWNS :Pilsētu daļa kas kļūs par lielpilsētām: {STRING} -STR_CONFIG_SETTING_LARGER_TOWNS_HELPTEXT :Pilsētu daudzums kas kļūs par lielpilsētām, tādēļ tās sākumā ir lielākas un attīstās ātrāk +STR_CONFIG_SETTING_LARGER_TOWNS :Apdzīvotu vietu proporcija, kas kļūs par pilsētām: {STRING} +STR_CONFIG_SETTING_LARGER_TOWNS_HELPTEXT :Apdzīvotu vietu daudzums kas kļūs par pilsētām; tādēļ apdzīvota vieta, kas sākumā ir lielāka, augs straujāk STR_CONFIG_SETTING_LARGER_TOWNS_VALUE :1 pret {COMMA} STR_CONFIG_SETTING_LARGER_TOWNS_DISABLED :neviena -STR_CONFIG_SETTING_CITY_SIZE_MULTIPLIER :Lielpilsētu sākuma lieluma reizinātājs: {STRING} -STR_CONFIG_SETTING_CITY_SIZE_MULTIPLIER_HELPTEXT :Lielpilsētu vidējais lielums attiecībā pret parastām pilsētām spēles sākumā +STR_CONFIG_SETTING_CITY_SIZE_MULTIPLIER :Pilsētu sākuma lieluma reizinātājs: {STRING} +STR_CONFIG_SETTING_CITY_SIZE_MULTIPLIER_HELPTEXT :Pilsētu vidējais lielums attiecībā pret parastām apdzīvotām vietām spēles sākumā STR_CONFIG_SETTING_LINKGRAPH_INTERVAL :Atjaunināt sadales grafu ik pa {STRING}{NBSP}dien{P 0:2 ai ām ām} STR_CONFIG_SETTING_LINKGRAPH_INTERVAL_HELPTEXT :Laiks starp secīgām saišu grafa pārrēķināšanām. Katra pārrēķināšana izskaitļo plānos vienai grafa komponentei. Tas nozīmē, ka šim iestatījumam vērtība X nenozīmē, ka viss grafs tiks atjaunināts ir pēc X dienām. Tikai dažas komponentes tiks pārrēķinātas. Jo mazāka iestatītā vērtība, jo vairāk laika CPU pavadīs rēķinot. Jo lielāka iestatītā vērtība, jo ilgāk nevarēs sākties kravu izplatīšana jaunos maršrutos. @@ -1644,10 +1664,12 @@ STR_CONFIG_SETTING_DISTRIBUTION_ARMOURED_HELPTEXT :APSARGĀJAMĀ k STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT :Izplatīšanas modelis citām kravu klasēm: {STRING} STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT_HELPTEXT :"asimetriska" nozīmē, ka patvaļīgu kravas daudzumu var nosūtīt abos virzienos."manuāli" nozīmē, ka šīm kravām netiks veikta automātiska izplatīšana. STR_CONFIG_SETTING_LINKGRAPH_ACCURACY :Sadales precizitāte: {STRING} +STR_CONFIG_SETTING_LINKGRAPH_ACCURACY_HELPTEXT :Jo lielāku vērtību iestatīsiet, jo vairāk CPU laika aizies saišu grafa aprēķināšanai. Ja tas aizņem pārāk daudz laika, jūs varētu pamanīt spēles iebremzēšanos. Ja iestatīsiet pārāk mazu, izplatīšana būs neprecīza un jūs varētu pamanīt, ka krava tiek nosūtīta uz negaidītām vietām. STR_CONFIG_SETTING_DEMAND_DISTANCE :Attāluma ietekme uz pieprasījumu: {STRING} STR_CONFIG_SETTING_DEMAND_DISTANCE_HELPTEXT :Ja iestatīsiet šo vērtību lielāku kā 0, attālums starp kravas izcelsmes staciju A un iespējamo galastaciju B ietekmēs sūtāmās kravas apjomu. Jo tālāk no stacijas A ir stacija B, jo mazāk kravas tiks nosūtīts. Jo augstāka vērtība, jo mazāk kravas tiks nosūtīts uz tālo staciju un vairāk kravu uz tuvo staciju. STR_CONFIG_SETTING_DEMAND_SIZE :Atpakaļceļa kravas daudzums simetriskajā režīmā: {STRING} STR_CONFIG_SETTING_DEMAND_SIZE_HELPTEXT :Uzstādod šo mazāk par 100% liks simetriskajai sadalei izturēties vairāk kā asimetriskajai. Mazāk kravas ar varu tiks sūtīts atpakaļ ja noteikts daudzums tiks sūtīts uz piestātni. Ja jūs uzstādīsiet to uz 0% simetriskā sadale izturēsies tā pat kā asimetriskā. +STR_CONFIG_SETTING_SHORT_PATH_SATURATION :Īso ceļu piesātinājums pirms sākt izmantot augstas ietilpības ceļus: {STRING} STR_CONFIG_SETTING_SHORT_PATH_SATURATION_HELPTEXT :Nereti starp divām stacijām ir vairāki ceļi. Kravu sadale vispirms piesātinās īsāko maršrutu, pēc tam izmantos nākamo īsāko maršrutu līdz tas būs piesātināts, un tā tālāk. Piesātinājumu nosaka novērtējot ietilpību un plānoto izmantojumu. Kad visi ceļi ir piesātināti un vēl ir palicis pieprasījumus, tas pārslogos visus ceļus, dodot priekšroku ceļiem ar lielāko ietilpību. Algoritms visbiežāk nepareizi novērtēs ietilpību. Šis iestatījums jums atļaus norādīt, līdz cik procentiem īsākais ceļš ir jāpiesātina pirmajā piegājienā pirms izvēlēties garāku ceļu. Iestatiet to uz mazāk kā 100%, lai izvairītos no pārpildītām stacijām, ja kapacitāte ir pārvērtēta. STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY :Ātruma mērvienības: {STRING} @@ -1803,8 +1825,8 @@ STR_OSNAME_SUNOS :SunOS # Abandon game STR_ABANDON_GAME_CAPTION :{WHITE}Pamest spēli -STR_ABANDON_GAME_QUERY :{YELLOW}Vai jūs tiešām vēlaties pamest šo spēli? -STR_ABANDON_SCENARIO_QUERY :{YELLOW}Vai esat pārliecināts, ka vēlaties pamest šo scenāriju? +STR_ABANDON_GAME_QUERY :{YELLOW}Vai tiešām vēlaties pamest šo spēli? +STR_ABANDON_SCENARIO_QUERY :{YELLOW}Vai tiešām vēlaties pamest šo scenāriju? # Cheat window STR_CHEATS :{WHITE}Blēdības @@ -2132,7 +2154,7 @@ STR_NETWORK_CHAT_ALL :[Visiem] {STRIN STR_NETWORK_CHAT_OSKTITLE :{BLACK}Ievadīt tekstu tīkla tērzēšanai # Network messages -STR_NETWORK_ERROR_NOTAVAILABLE :{WHITE}Neviena tīkla iekārta nav atrasta vai kompilēta bez ENABLE_NETWORK +STR_NETWORK_ERROR_NOTAVAILABLE :{WHITE}Nav atrasta neviena tīkla ierīce STR_NETWORK_ERROR_NOSERVER :{WHITE}Nevar atrast nevienu tīkla spēli STR_NETWORK_ERROR_NOCONNECTION :{WHITE}Serveris neatbild uz pieprasījumu STR_NETWORK_ERROR_NEWGRF_MISMATCH :{WHITE}Nevar pieslēgties sakarā ar NewGRF neatbilstību @@ -2386,9 +2408,9 @@ STR_BUILD_SIGNAL_ELECTRIC_COMBO_TOOLTIP :{BLACK}Kombinē STR_BUILD_SIGNAL_ELECTRIC_PBS_TOOLTIP :{BLACK}Ceļa signāls (luksofors){}Ceļa signāls ļauj vairāk kā vienam vilcienam iebraukt signāla blokā vienlaicīgi, ja vien vilciens var rezervēt drošu apstāšanās punktu. Parastiem ceļa signāliem var pabraukt garām no aizmugures STR_BUILD_SIGNAL_ELECTRIC_PBS_OWAY_TOOLTIP :{BLACK}Vienvirziena ceļa signālierīce (elektriska){}Ceļa signāls ļauj iebraukt signāla blokā vairāk kā vienam vilcienam vienlaicīgi, ja vien vilciens var rezervēt drošu apstāšanās punktu. Vienvirziena ceļa signālierīcēm nevar pabraukt garām no aizmugures STR_BUILD_SIGNAL_CONVERT_TOOLTIP :{BLACK}Signālierīču pārveidotājs{}Kad ieslēgts, klikšķis uz jau esošas signālierīces pārveidos to uz norādīto signāla tipu un variantu. Ctrl+klikšķis pārslēgs pašreizējo variantu. Shift+klikšķis rāda pārveidošanas tāmes vērtību -STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_TOOLTIP :{BLACK}Vilkt signālu biežumu +STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_TOOLTIP :{BLACK}Vilkto signālu attālums STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_DECREASE_TOOLTIP :{BLACK}Samazināt signālierīču attālumu -STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_INCREASE_TOOLTIP :{BLACK}Palielināt signālierīču biežumu +STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_INCREASE_TOOLTIP :{BLACK}Palielināt signālierīču atstatumu # Bridge selection window STR_SELECT_RAIL_BRIDGE_CAPTION :{WHITE}Izvēlēties dzelzceļa tiltu @@ -2426,6 +2448,7 @@ STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_TUNNEL :{BLACK}Būvēt STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_TUNNEL :{BLACK}Būvēt tramvaju tuneli. Shift pārslēdz būvēšanu/izmaksu tāmes rādīšanu STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD :{BLACK}Pārslēgties starp ceļa būvēšanas/nojaukšanas režīmiem STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS :{BLACK}Pārslēgt būvēt/novākt tramvaju būvei +STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_ROAD :{BLACK}Pārveidot/uzlabot ceļa veidu. Shift pārslēdz būvēšanu/izmaksu novērtējumu rādīšanu STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_TRAM :{BLACK}Pārveidot/uzlabot tramvaju veidu. Shift pārslēdz būvēšanu/izmaksu novērtējumu rādīšanu STR_ROAD_NAME_ROAD :Ceļš @@ -2477,7 +2500,7 @@ STR_STATION_BUILD_AIRPORT_CLASS_LABEL :{BLACK}Lidostas STR_STATION_BUILD_AIRPORT_LAYOUT_NAME :{BLACK}{NUM}. izkārtojums STR_AIRPORT_SMALL :Maza -STR_AIRPORT_CITY :Lielpilsēta +STR_AIRPORT_CITY :Pilsēta STR_AIRPORT_METRO :Metropolitēns STR_AIRPORT_INTERNATIONAL :Starptautiskā lidosta STR_AIRPORT_COMMUTER :Ikdienas satiksme @@ -2553,8 +2576,8 @@ STR_FOUND_TOWN_INITIAL_SIZE_MEDIUM_BUTTON :{BLACK}Vidējs STR_FOUND_TOWN_INITIAL_SIZE_LARGE_BUTTON :{BLACK}Liels STR_FOUND_TOWN_SIZE_RANDOM :{BLACK}Nejaušs STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP :{BLACK}Izvēlēties pilsētas izmērus -STR_FOUND_TOWN_CITY :{BLACK}Lielpilsēta -STR_FOUND_TOWN_CITY_TOOLTIP :{BLACK}Lielpilsētas attīstās ātrāk kā pilsētas{}Atkarībā no iestatījumiem, dibināšanas brīdī tās ir lielākas +STR_FOUND_TOWN_CITY :{BLACK}Pilsēta +STR_FOUND_TOWN_CITY_TOOLTIP :{BLACK}Pilsētas aug straujāk kā parastas apdzīvotās vietas{}Atkarībā no iestatījumiem, dibināšanas brīdī pilsētas ir lielākas STR_FOUND_TOWN_ROAD_LAYOUT :{YELLOW}Pilsētas ceļu izskats: STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT :{BLACK}Atlasīt šajā pilsētā lietojamo ceļu izkārtojumu @@ -2616,6 +2639,7 @@ STR_LAND_AREA_INFORMATION_CARGO_ACCEPTED :{BLACK}Pieņem STR_LAND_AREA_INFORMATION_CARGO_EIGHTS :({COMMA}/8 {STRING}) STR_LANG_AREA_INFORMATION_RAIL_TYPE :{BLACK}Sliežu veids: {LTBLUE}{STRING} STR_LANG_AREA_INFORMATION_ROAD_TYPE :{BLACK}Ceļu tips: {LTBLUE}{STRING} +STR_LANG_AREA_INFORMATION_TRAM_TYPE :{BLACK}Tramvaja veids: {LTBLUE}{STRING} STR_LANG_AREA_INFORMATION_RAIL_SPEED_LIMIT :{BLACK}Sliežu ātruma ierobežojums: {LTBLUE}{VELOCITY} STR_LANG_AREA_INFORMATION_ROAD_SPEED_LIMIT :{BLACK}Ceļa ātruma ierobežojums: {LTBLUE}{VELOCITY} STR_LANG_AREA_INFORMATION_TRAM_SPEED_LIMIT :{BLACK}Tramvaja ātruma ierobežojums: {LTBLUE}{VELOCITY} @@ -2629,29 +2653,29 @@ STR_LAI_CLEAR_DESCRIPTION_FIELDS :Lauki STR_LAI_CLEAR_DESCRIPTION_SNOW_COVERED_LAND :Apsnigusi zeme STR_LAI_CLEAR_DESCRIPTION_DESERT :Tuksnesis -STR_LAI_RAIL_DESCRIPTION_TRACK :Dzelzceļš sliedes -STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_SIGNALS :Dzelzceļš ceļš ar bloķēšanas signālierīcēm -STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRESIGNALS :Dzelzceļš sliedes ar pirmssignālierīcēm -STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXITSIGNALS :Dzelzceļš sliedes ar izejas signālierīcēm -STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBOSIGNALS :Dzelzceļš sliedes ar kombinētajām signālierīcēm -STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBSSIGNALS :Dzelzceļš sliedes ar ceļa signālierīcēm -STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NOENTRYSIGNALS :Dzelzceļš sliedes ar vienvirziena ceļa signālierīcēm -STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS :Dzelzceļš sliedes ar bloka un pirmssignālierīcēm -STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS :Dzelzceļš sliedes ar bloka un izejas signālierīcēm -STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS :Dzelzceļš sliedes ar bloka un kombinētajām signālierīcēm -STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS :Dzelzceļš sliedes ar bloka un ceļa signālierīcēm -STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS :Dzelzceļš sliedes ar bloka un vienvirziena ceļa signālierīcēm -STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS :Dzelzceļš sliedes ar izejas un pirmssignālierīcēm -STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS :Dzelzceļš sliedes ar kombinētajām un pirmssignālierīcēm -STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS :Dzelzceļš sliedes ar ceļu un pirmssignālierīcēm -STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS :Dzelzceļš sliedes ar vienvirziena ceļu un pirmssignālierīcēm -STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS :Dzelzceļš sliedes ar izejas un kombinētajām signālierīcēm -STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS :Dzelzceļš sliedes ar izejas un ceļa signālierīcēm -STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS :Dzelzceļš sliedes ar izejas un vienvirziena ceļa signālierīcēm -STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS :Dzelzceļš sliedes ar kombinētajām un ceļa signālierīcēm -STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS :Dzelzceļš sliedes ar kombinētajām un vienvirziena ceļa signālierīcēm -STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS :Dzelzceļš sliedes ar ceļa un vienvirziena ceļa signālierīcēm -STR_LAI_RAIL_DESCRIPTION_TRAIN_DEPOT :Dzelzceļš vilcienu depo +STR_LAI_RAIL_DESCRIPTION_TRACK :Dzelzceļa sliedes +STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_SIGNALS :Dzelzceļa sliedes ar bloku signālierīcēm +STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRESIGNALS :Dzelzceļa sliedes ar pirmssignālierīcēm +STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXITSIGNALS :Dzelzceļa sliedes ar izejas signālierīcēm +STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBOSIGNALS :Dzelzceļa sliedes ar kombinētajām signālierīcēm +STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBSSIGNALS :Dzelzceļa sliedes ar ceļa signālierīcēm +STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NOENTRYSIGNALS :Dzelzceļa sliedes ar vienvirziena ceļa signālierīcēm +STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS :Dzelzceļa sliedes ar bloku un pirmssignālierīcēm +STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS :Dzelzceļa sliedes ar bloku un izejas signālierīcēm +STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS :Dzelzceļa sliedes ar bloku un kombinētajām signālierīcēm +STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS :Dzelzceļa sliedes ar bloku un ceļu signālierīcēm +STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS :Dzelzceļa sliedes ar bloka un vienvirziena ceļa signālierīcēm +STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS :Dzelzceļa sliedes ar izejas un pirmssignālierīcēm +STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS :Dzelzceļa sliedes ar kombinētajām un pirmssignālierīcēm +STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS :Dzelzceļa sliedes ar ceļu un pirmssignālierīcēm +STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS :Dzelzceļa sliedes ar vienvirziena un pirmssignālierīcēm +STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS :Dzelzceļa sliedes ar izejas un kombinētajām signālierīcēm +STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS :Dzelzceļa sliedes ar izejas un ceļa signālierīcēm +STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS :Dzelzceļa sliedes ar izejas un vienvirziena ceļa signālierīcēm +STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS :Dzelzceļa sliedes ar kombinētajām un ceļa signālierīcēm +STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS :Dzelzceļa sliedes ar kombinētajām un vienvirziena ceļa signālierīcēm +STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS :Dzelzceļa sliedes ar ceļu un vienvirziena ceļu signālierīcēm +STR_LAI_RAIL_DESCRIPTION_TRAIN_DEPOT :Dzelzceļa vilcienu depo STR_LAI_ROAD_DESCRIPTION_ROAD :Ceļš STR_LAI_ROAD_DESCRIPTION_ROAD_WITH_STREETLIGHTS :Ceļš ar ielu apgaismojumu @@ -2723,7 +2747,8 @@ STR_FRAMERATE_CAPTION_SMALL :{STRING}{WHITE} STR_FRAMERATE_RATE_GAMELOOP :{BLACK}Simulācijas ātrums: {STRING} STR_FRAMERATE_RATE_GAMELOOP_TOOLTIP :{BLACK}Spēles tikšķu skaits, ko simulēt vienā sekundē. STR_FRAMERATE_RATE_BLITTER :{BLACK}Grafikas kadru ātrums: {STRING} -STR_FRAMERATE_SPEED_FACTOR :{WHITE}pašreizējās spēles ātruma pakāpe: {DECIMAL}x +STR_FRAMERATE_RATE_BLITTER_TOOLTIP :{BLACK}Sekundē renderēto video kadru skaits. +STR_FRAMERATE_SPEED_FACTOR :{BLACK}Pašreizējās spēles ātruma pakāpe: {DECIMAL}× STR_FRAMERATE_SPEED_FACTOR_TOOLTIP :{BLACK}Cik ātri spēle šobrīd iet salīdzinot ar standarta ātrumu. STR_FRAMERATE_CURRENT :{WHITE}Pašreizējais STR_FRAMERATE_AVERAGE :{WHITE}Vidējais @@ -2749,6 +2774,7 @@ STR_FRAMERATE_GL_SHIPS :{BLACK} Kuģu STR_FRAMERATE_GL_AIRCRAFT :{BLACK} Lidaparātu tikšķi: STR_FRAMERATE_GL_LANDSCAPE :{BLACK} Pasaules tikšķi: STR_FRAMERATE_GL_LINKGRAPH :{BLACK} Saišu grafika aizture: +STR_FRAMERATE_DRAWING :{BLACK}Grafikas renderēšana: STR_FRAMERATE_DRAWING_VIEWPORTS :{BLACK} Pasaules skatvietas: STR_FRAMERATE_VIDEO :{BLACK}Video izvade: STR_FRAMERATE_SOUND :{BLACK}Skaņas miksēšana: @@ -2761,6 +2787,7 @@ STR_FRAMETIME_CAPTION_GAMELOOP :Spēles cikls STR_FRAMETIME_CAPTION_GL_ECONOMY : Kravu iekraušana un izkraušana STR_FRAMETIME_CAPTION_GL_TRAINS :Vilcienu tikšķi STR_FRAMETIME_CAPTION_GL_ROADVEHS :Autotransporta tikšķi +STR_FRAMETIME_CAPTION_GL_SHIPS :Kuģu tikšķi STR_FRAMETIME_CAPTION_GL_AIRCRAFT :Lidaparātu tikšķi STR_FRAMETIME_CAPTION_GL_LANDSCAPE :Pasaules tikšķi STR_FRAMETIME_CAPTION_GL_LINKGRAPH :Saišu grafa aizture @@ -2918,6 +2945,8 @@ STR_NEWGRF_SETTINGS_MD5SUM :{BLACK}MD5sum: STR_NEWGRF_SETTINGS_PALETTE :{BLACK}Palete: {SILVER}{STRING} STR_NEWGRF_SETTINGS_PALETTE_DEFAULT :Noklusējuma (D) STR_NEWGRF_SETTINGS_PALETTE_DEFAULT_32BPP :Noklusējuma (D) / 32 bpp +STR_NEWGRF_SETTINGS_PALETTE_LEGACY :Mantotais (W) +STR_NEWGRF_SETTINGS_PALETTE_LEGACY_32BPP :Mantotais (W) / 32 bpp STR_NEWGRF_SETTINGS_PARAMETER :{BLACK}Parametri: {SILVER}{STRING} STR_NEWGRF_SETTINGS_PARAMETER_NONE :Nav @@ -2965,9 +2994,11 @@ STR_SPRITE_ALIGNER_GOTO_TOOLTIP :{BLACK}Iet pie STR_SPRITE_ALIGNER_PREVIOUS_BUTTON :{BLACK}Iepriekšējais gariņš STR_SPRITE_ALIGNER_PREVIOUS_TOOLTIP :{BLACK}Iet pie iepriekšējā parastā gariņa, izlaižot visus pseido/pārkrāsotos/fonta gariņus STR_SPRITE_ALIGNER_SPRITE_TOOLTIP :{BLACK}Atlasītā gariņa attēlojums. To attēlojot, izkārtojums netiek ievērots -STR_SPRITE_ALIGNER_MOVE_TOOLTIP :{BLACK}Pārvietot gariņu, lai mainītu X un Y vērtības +STR_SPRITE_ALIGNER_MOVE_TOOLTIP :{BLACK}Pārvietot gariņu, lai mainītu X un Y vērtības. Ctrl+klikšķis, lai vienā piegājienā pārvietotu gariņu par astoņām vienībām STR_SPRITE_ALIGNER_RESET_BUTTON :{BLACK}Atiestatīt relatīvi +STR_SPRITE_ALIGNER_RESET_TOOLTIP :{BLACK}Pāriestatīt paršreizējo relatīvo nobīdi STR_SPRITE_ALIGNER_OFFSETS_ABS :{BLACK}X nobīde: {NUM}, Y nobīde: {NUM} (absolūta) +STR_SPRITE_ALIGNER_OFFSETS_REL :{BLACK}X nobīde: {NUM}, Y nobīde: {NUM} (relatīvi) STR_SPRITE_ALIGNER_PICKER_BUTTON :{BLACK}Paņemt gariņu STR_SPRITE_ALIGNER_PICKER_TOOLTIP :{BLACK}Paņemt gariņu no jebkuras vietas ekrānā @@ -3033,6 +3064,7 @@ STR_NEWGRF_BUGGY :{WHITE}NewGRF ' STR_NEWGRF_BUGGY_ARTICULATED_CARGO :{WHITE}'{1:ENGINE}' kravas pielāgošanas informācija pēc izbūves atšķiras no pārdošanas sarakstā norādītās. Tas var liegt automātiskai atjaunošanai/aizvietošanai pareizi pielāgot kravas STR_NEWGRF_BUGGY_ENDLESS_PRODUCTION_CALLBACK :{WHITE}'{1:STRING}' izraisīja bezgalīgu ražošanas izsaukumu ciklu STR_NEWGRF_BUGGY_UNKNOWN_CALLBACK_RESULT :{WHITE}Izsaukums {1:HEX} atgrieza nezināmu vai nederīgu rezultātu {2:HEX} +STR_NEWGRF_BUGGY_INVALID_CARGO_PRODUCTION_CALLBACK :{WHITE}“{1:STRING}” atgrieza nederīgu kravas veidu ražošanas atgriezeniskajā funkcijā punktā {2:HEX} # 'User removed essential NewGRFs'-placeholders for stuff without specs STR_NEWGRF_INVALID_CARGO : @@ -3073,7 +3105,7 @@ STR_TOWN_POPULATION :{BLACK}Pasaules # Town view window STR_TOWN_VIEW_TOWN_CAPTION :{WHITE}{TOWN} -STR_TOWN_VIEW_CITY_CAPTION :{WHITE}{TOWN} (lielpilsēta) +STR_TOWN_VIEW_CITY_CAPTION :{WHITE}{TOWN} (pilsēta) STR_TOWN_VIEW_POPULATION_HOUSES :{BLACK}Iedzīvotāji: {ORANGE}{COMMA}{BLACK} Mājas: {ORANGE}{COMMA} STR_TOWN_VIEW_CARGO_LAST_MONTH_MAX :{BLACK}{CARGO_LIST} iepriekšējā mēnesī: {ORANGE}{COMMA}{BLACK} maks.: {ORANGE}{COMMA} STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH :{BLACK}Krava nepieciešama pilsētas attīstībai: @@ -3101,6 +3133,7 @@ STR_TOWN_VIEW_RENAME_TOWN_BUTTON :Pārdēvēt pil # Town local authority window STR_LOCAL_AUTHORITY_CAPTION :{WHITE}{TOWN} pašvaldība STR_LOCAL_AUTHORITY_ZONE :{BLACK}Zona +STR_LOCAL_AUTHORITY_ZONE_TOOLTIP :{BLACK}Rādīt zonu pašvaldības robežās STR_LOCAL_AUTHORITY_COMPANY_RATINGS :{BLACK}Transporta uzņēmumu vērtējumi: STR_LOCAL_AUTHORITY_COMPANY_RATING :{YELLOW}{COMPANY} {COMPANY_NUM}: {ORANGE}{STRING} STR_LOCAL_AUTHORITY_ACTIONS_TITLE :{BLACK}Pieejamās darbības: @@ -3180,6 +3213,7 @@ STR_SUBSIDIES_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER :{BLACK}Klikšķ # Story book window STR_STORY_BOOK_CAPTION :{WHITE}{COMPANY} Stāstu grāmata STR_STORY_BOOK_SPECTATOR_CAPTION :{WHITE}Globālā stāstu grāmata +STR_STORY_BOOK_SPECTATOR :Globālā stāstu grāmata STR_STORY_BOOK_TITLE :{YELLOW}{STRING} STR_STORY_BOOK_GENERIC_PAGE_ITEM :{NUM} lapa STR_STORY_BOOK_SEL_PAGE_TOOLTIP :{BLACK}Pārlēkt uz specifisku lapu spiežot to zemāk esošajā sarakstā. @@ -3373,6 +3407,7 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL :{WHITE}{CURRENC STR_INDUSTRY_DIRECTORY_CAPTION :{WHITE}Ražotnes STR_INDUSTRY_DIRECTORY_NONE :{G=m}{ORANGE}- Neviens - STR_INDUSTRY_DIRECTORY_NONE.kas :{ORANGE}- Neviena - +STR_INDUSTRY_DIRECTORY_ITEM_INFO :{BLACK}{CARGO_LONG}{STRING}{YELLOW} (pārvadāti {COMMA}%){BLACK} STR_INDUSTRY_DIRECTORY_ITEM_NOPROD :{ORANGE}{INDUSTRY} STR_INDUSTRY_DIRECTORY_ITEM_PROD1 :{ORANGE}{INDUSTRY} {STRING} STR_INDUSTRY_DIRECTORY_ITEM_PROD2 :{ORANGE}{INDUSTRY} {STRING}, {STRING} @@ -3387,7 +3422,7 @@ STR_INDUSTRY_DIRECTORY_FILTER_NONE :Nav # Industry view STR_INDUSTRY_VIEW_CAPTION :{WHITE}{INDUSTRY} STR_INDUSTRY_VIEW_PRODUCTION_LAST_MONTH_TITLE :{BLACK}Iepriekšējā mēnesī saražots: -STR_INDUSTRY_VIEW_TRANSPORTED :{YELLOW}{CARGO_LONG}{STRING}{BLACK} (aizvests {COMMA}%) +STR_INDUSTRY_VIEW_TRANSPORTED :{YELLOW}{CARGO_LONG}{STRING}{BLACK} (pārvadāti {COMMA}%) STR_INDUSTRY_VIEW_LOCATION_TOOLTIP :{BLACK}Centrēt galveno skatu uz ražotni. Ctrl+klikšķis atvērs skatu uz ražotni jaunā skatlaukā STR_INDUSTRY_VIEW_PRODUCTION_LEVEL :{BLACK}Ražošanas līmenis: {YELLOW}{COMMA}% STR_INDUSTRY_VIEW_INDUSTRY_ANNOUNCED_CLOSURE :{YELLOW}Nozare ir paziņojusi par nenovēršamu slēgšanu! @@ -3396,6 +3431,7 @@ STR_INDUSTRY_VIEW_REQUIRES_N_CARGO :{BLACK}Pieprasa STR_INDUSTRY_VIEW_PRODUCES_N_CARGO :{BLACK}Ražo: {YELLOW}{STRING}{STRING} STR_INDUSTRY_VIEW_CARGO_LIST_EXTENSION :, {STRING}{STRING} +STR_INDUSTRY_VIEW_REQUIRES :{BLACK}Pieprasa: STR_INDUSTRY_VIEW_ACCEPT_CARGO :{YELLOW}{STRING}{BLACK}{3:STRING} STR_INDUSTRY_VIEW_ACCEPT_CARGO_AMOUNT :{YELLOW}{STRING}{BLACK}: {CARGO_SHORT} gaida{STRING} @@ -3466,6 +3502,7 @@ STR_GROUP_RENAME_CAPTION :{BLACK}Pārdēv STR_GROUP_PROFIT_THIS_YEAR :Ienākumi šajā gadā: STR_GROUP_PROFIT_LAST_YEAR :Peļņa pērn: +STR_GROUP_OCCUPANCY :Pašreizējais lietojums: STR_GROUP_OCCUPANCY_VALUE :{NUM}% # Build vehicle window @@ -3485,6 +3522,7 @@ STR_BUY_VEHICLE_AIRCRAFT_CAPTION :Jauns lidaparā ############ range for vehicle availability ends STR_PURCHASE_INFO_COST_WEIGHT :{BLACK}Cena: {GOLD}{CURRENCY_LONG}{BLACK} Svars: {GOLD}{WEIGHT_SHORT} +STR_PURCHASE_INFO_COST_REFIT_WEIGHT :{BLACK}Cena: {GOLD}{CURRENCY_LONG}{BLACK} (Pielāgošanas izmaksas: {GOLD}{CURRENCY_LONG}{BLACK}) Svars: {GOLD}{WEIGHT_SHORT} STR_PURCHASE_INFO_SPEED_POWER :{BLACK}Ātrums: {GOLD}{VELOCITY}{BLACK} Jauda: {GOLD}{POWER} STR_PURCHASE_INFO_SPEED :{BLACK}Ātrums: {GOLD}{VELOCITY} STR_PURCHASE_INFO_SPEED_OCEAN :{BLACK}Ātrums okeānā: {GOLD}{VELOCITY} @@ -3657,6 +3695,7 @@ STR_ENGINE_PREVIEW_SHIP :kuģis STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER :{BLACK}Cena: {CURRENCY_LONG} Svars: {WEIGHT_SHORT}{}Ātrums: {VELOCITY} Jauda: {POWER}{}Kārtējās izmaksas: {CURRENCY_LONG} gadā{}Ietilpība: {CARGO_LONG} STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER_MAX_TE :{BLACK}Cena: {CURRENCY_LONG} Svars: {WEIGHT_SHORT}{}Ātrums: {VELOCITY} Jauda: {POWER} Maks. spēks: {6:FORCE}{}Kārtējās izmaksas: {4:CURRENCY_LONG} gadā{}Ietilpība: {5:CARGO_LONG} STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAP_RUNCOST :{BLACK}Cena: {CURRENCY_LONG} Maks. ātrums: {VELOCITY}{}Ietilpība: {CARGO_LONG}{}Kārtējās izmaksas: {CURRENCY_LONG} gadā +STR_ENGINE_PREVIEW_COST_MAX_SPEED_TYPE_CAP_CAP_RUNCOST :{BLACK}Cena: {CURRENCY_LONG} Maks. ātrums: {VELOCITY}{}Lidaparāta veids: {STRING}{}Ietilpība: {CARGO_LONG}, {CARGO_LONG}{}Izmaksas: {CURRENCY_LONG} gadā STR_ENGINE_PREVIEW_COST_MAX_SPEED_TYPE_CAP_RUNCOST :{BLACK}Cena: {CURRENCY_LONG} Maks. ātrums: {VELOCITY}{}Lidaparāta veids: {STRING}{}Ietilpība: {CARGO_LONG}{}Izmaksas: {CURRENCY_LONG}/gadā STR_ENGINE_PREVIEW_COST_MAX_SPEED_TYPE_RANGE_CAP_CAP_RUNCOST :{BLACK}Cena: {CURRENCY_LONG} Maks. ātrums: {VELOCITY}{}Lidaparāta veids: {STRING} Attālums: {COMMA} lauciņi{}Ietilpība: {CARGO_LONG}, {CARGO_LONG}{}Izmaksas: {CURRENCY_LONG}/gadā STR_ENGINE_PREVIEW_COST_MAX_SPEED_TYPE_RANGE_CAP_RUNCOST :{BLACK}Cena: {CURRENCY_LONG} Maks. ātrums: {VELOCITY}{}Lidaparāta veids: {STRING} Attālums: {COMMA} lauciņi{}Ietilpība: {CARGO_LONG}{}Izmaksas: {CURRENCY_LONG}/gadā @@ -3669,7 +3708,9 @@ STR_REPLACE_VEHICLE_SHIP :Kuģis STR_REPLACE_VEHICLE_AIRCRAFT :Lidaparāts STR_REPLACE_VEHICLE_VEHICLES_IN_USE :{YELLOW}Lietošanā esošie transportlīdzekļi +STR_REPLACE_VEHICLE_VEHICLES_IN_USE_TOOLTIP :{BLACK}Kolonna ar jums piederošajiem transportlīdzekļiem STR_REPLACE_VEHICLE_AVAILABLE_VEHICLES :{YELLOW}Pieejamie transportlīdzekļi +STR_REPLACE_VEHICLE_AVAILABLE_VEHICLES_TOOLTIP :{BLACK}Kolonna ar transportlīdzekļiem, kurus var aizvietot STR_REPLACE_HELP_LEFT_ARRAY :{BLACK}Izvēlēties lokomotīves veidu, kuru vēlaties mainīt STR_REPLACE_HELP_RIGHT_ARRAY :{BLACK}Izvēlēties jaunu lokomotīves veidu, kuru vēlaties lietot kreisajā pusē atlasītās lokomotīves vietā @@ -3691,6 +3732,7 @@ STR_REPLACE_ALL_RAILTYPE :Visi dzelzceļa STR_REPLACE_ALL_ROADTYPE :Visi ceļu transportlīdzekļi STR_REPLACE_HELP_RAILTYPE :{BLACK}Izvēlēties sliežu veidu, kuram vēlaties nomainīt lokomotīves +STR_REPLACE_HELP_ROADTYPE :{BLACK}Izvēlēties ceļu veidu, kuram vēlaties nomainīt dzinējus STR_REPLACE_HELP_REPLACE_INFO_TAB :{BLACK}Parāda kura lokomotīve no kreisajā pusē atlasītajām tiek nomainīta, ja vien kāda ir STR_REPLACE_RAIL_VEHICLES :Sliežu transportlīdzekļi STR_REPLACE_ELRAIL_VEHICLES :Elektrificētā dzelzceļa transportlīdzekļi @@ -3784,6 +3826,8 @@ STR_VEHICLE_INFO_AGE :{COMMA} gad{P s STR_VEHICLE_INFO_AGE_RED :{RED}{COMMA} gad{P s i u} ({COMMA}) STR_VEHICLE_INFO_MAX_SPEED :{BLACK}Maks. ātrums: {LTBLUE}{VELOCITY} +STR_VEHICLE_INFO_MAX_SPEED_TYPE :{BLACK}Maks. ātrums: {LTBLUE}{VELOCITY} {BLACK}Lidaparāta veids: {LTBLUE}{STRING} +STR_VEHICLE_INFO_MAX_SPEED_TYPE_RANGE :{BLACK}Maks. ātrums: {LTBLUE}{VELOCITY} {BLACK}Lidaparāta veids: {LTBLUE}{STRING} {BLACK}Attālums: {LTBLUE}{COMMA} lauciņi STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED :{BLACK}Svars: {LTBLUE}{WEIGHT_SHORT} {BLACK}Jauda: {LTBLUE}{POWER}{BLACK} Maks. ātrums: {LTBLUE}{VELOCITY} STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE :{BLACK}Svars: {LTBLUE}{WEIGHT_SHORT} {BLACK}Jauda: {LTBLUE}{POWER}{BLACK} Maks. ātrums: {LTBLUE}{VELOCITY} {BLACK}Maks. spēks: {LTBLUE}{FORCE} @@ -4197,6 +4241,7 @@ STR_FEEDER :{YELLOW}Pārska STR_FEEDER_INCOME_TINY :{TINY_FONT}{YELLOW}Pārkraušana: {CURRENCY_LONG}{WHITE} / {GREEN}Ienākumi: {CURRENCY_LONG} STR_FEEDER_INCOME :{YELLOW}Pārkraušana: {CURRENCY_LONG}{WHITE} / {GREEN}Ienākumi: {CURRENCY_LONG} STR_FEEDER_COST_TINY :{TINY_FONT}{YELLOW}Pārkraušana: {CURRENCY_LONG}{WHITE} / {RED}Izmaksas: {CURRENCY_LONG} +STR_FEEDER_COST :{YELLOW}Pārkraušana: {CURRENCY_LONG}{WHITE} / {RED}Izmaksas: {CURRENCY_LONG} STR_MESSAGE_ESTIMATED_COST :{WHITE}Plānotās izmaksas: {CURRENCY_LONG} STR_MESSAGE_ESTIMATED_INCOME :{WHITE}Plānotie ienākumi: {CURRENCY_LONG} @@ -4448,6 +4493,7 @@ STR_ERROR_CAN_T_REMOVE_TRAMWAY_FROM :{WHITE}Šeit ne STR_ERROR_THERE_IS_NO_ROAD :{WHITE}... tur nav ceļa STR_ERROR_THERE_IS_NO_TRAMWAY :{WHITE}... tur nav tramvaju sliežu ceļa STR_ERROR_CAN_T_CONVERT_ROAD :{WHITE}Šeit nevar mainīt ceļa veidu... +STR_ERROR_CAN_T_CONVERT_TRAMWAY :{WHITE}Šeit nevar pārveidot tramvaja veidu... STR_ERROR_NO_SUITABLE_ROAD :{WHITE}Nav piemērota ceļa STR_ERROR_NO_SUITABLE_TRAMWAY :{WHITE}Nav piemērotu tramvaju STR_ERROR_INCOMPATIBLE_ROAD :{WHITE}... nesavietojams ceļš @@ -4504,6 +4550,7 @@ STR_ERROR_GROUP_CAN_T_CREATE :{WHITE}Nevar iz STR_ERROR_GROUP_CAN_T_DELETE :{WHITE}Nevar izdzēst šo grupu... STR_ERROR_GROUP_CAN_T_RENAME :{WHITE}Nevar pārdēvēt grupu... STR_ERROR_GROUP_CAN_T_SET_PARENT :nevar iestatīt vecāku grupu... +STR_ERROR_GROUP_CAN_T_SET_PARENT_RECURSION :{WHITE}... grupu hierarhijās cikli nav atļauti STR_ERROR_GROUP_CAN_T_REMOVE_ALL_VEHICLES :{WHITE}Nevar noņemt no šīs grupas visus transportlīdzekļus... STR_ERROR_GROUP_CAN_T_ADD_VEHICLE :{WHITE}Nevar pievienot transportlīdzekļus šai grupai... STR_ERROR_GROUP_CAN_T_ADD_SHARED_VEHICLE :{WHITE}Nevar pievienot koplietojamos transportlīdzekļus šai grupai... diff --git a/src/lang/russian.txt b/src/lang/russian.txt index 8c0dd077bc..3d3c94c551 100644 --- a/src/lang/russian.txt +++ b/src/lang/russian.txt @@ -1063,7 +1063,7 @@ STR_GAME_OPTIONS_CURRENCY_NLG :Нидерла STR_GAME_OPTIONS_CURRENCY_NOK :Норвежская крона (NOK) STR_GAME_OPTIONS_CURRENCY_PLN :Польский злотый (PLN) STR_GAME_OPTIONS_CURRENCY_RON :Румынский лей (RON) -STR_GAME_OPTIONS_CURRENCY_RUR :Российский рубль (RUR) +STR_GAME_OPTIONS_CURRENCY_RUR :Российский рубль (старый) (RUR) STR_GAME_OPTIONS_CURRENCY_SIT :Словенский толар (SIT) STR_GAME_OPTIONS_CURRENCY_SEK :Шведская крона (SEK) STR_GAME_OPTIONS_CURRENCY_TRY :Турецкая лира (TRY) @@ -1076,11 +1076,12 @@ STR_GAME_OPTIONS_CURRENCY_ZAR :Южноафр STR_GAME_OPTIONS_CURRENCY_CUSTOM :Своя... STR_GAME_OPTIONS_CURRENCY_GEL :Грузинский лари (GEL) STR_GAME_OPTIONS_CURRENCY_IRR :Иранский риал (IRR) -STR_GAME_OPTIONS_CURRENCY_RUB :Российский новый рубль (RUR) +STR_GAME_OPTIONS_CURRENCY_RUB :Российский рубль (RUR) STR_GAME_OPTIONS_CURRENCY_MXN :Мексиканский песо (MXN) STR_GAME_OPTIONS_CURRENCY_NTD :Новый тайваньский доллар (NTD) STR_GAME_OPTIONS_CURRENCY_CNY :Китайский юань (CNY) STR_GAME_OPTIONS_CURRENCY_HKD :Гонконгский доллар (HKD) +STR_GAME_OPTIONS_CURRENCY_INR :Индийская рупия (INR) ############ end of currency region STR_GAME_OPTIONS_ROAD_VEHICLES_FRAME :{BLACK}Движение автомобилей diff --git a/src/lang/spanish_MX.txt b/src/lang/spanish_MX.txt index 60b0ec2897..69b41a7c33 100644 --- a/src/lang/spanish_MX.txt +++ b/src/lang/spanish_MX.txt @@ -225,9 +225,9 @@ STR_UNITS_HEIGHT_METRIC :{COMMA}{NBSP}m STR_UNITS_HEIGHT_SI :{COMMA}{NBSP}m # Common window strings -STR_LIST_FILTER_TITLE :{BLACK}Filtrar palabras: -STR_LIST_FILTER_OSKTITLE :{BLACK}Indicar una palabra a filtrar -STR_LIST_FILTER_TOOLTIP :{BLACK}Indicar una palabra clave para filtrar la lista +STR_LIST_FILTER_TITLE :{BLACK}Filtrar texto: +STR_LIST_FILTER_OSKTITLE :{BLACK}Indicar texto a filtrar +STR_LIST_FILTER_TOOLTIP :{BLACK}Indicar un texto clave para filtrar la lista STR_TOOLTIP_GROUP_ORDER :{BLACK}Elegir orden de grupo STR_TOOLTIP_SORT_ORDER :{BLACK}Elegir orden descendiente o ascendiente @@ -1109,7 +1109,7 @@ STR_WARNING_NO_SUITABLE_AI :{WHITE}No se en # Settings tree window STR_CONFIG_SETTING_TREE_CAPTION :{WHITE}Configuración -STR_CONFIG_SETTING_FILTER_TITLE :{BLACK}Filtrar palabras: +STR_CONFIG_SETTING_FILTER_TITLE :{BLACK}Filtrar texto: STR_CONFIG_SETTING_EXPAND_ALL :{BLACK}Desplegar todo STR_CONFIG_SETTING_COLLAPSE_ALL :{BLACK}Plegar todo STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT :(sin explicación disponible) @@ -1163,7 +1163,7 @@ STR_CONFIG_SETTING_MAXIMUM_INITIAL_LOAN_HELPTEXT :Máxima cantida STR_CONFIG_SETTING_INTEREST_RATE :Porcentaje de interés: {STRING} STR_CONFIG_SETTING_INTEREST_RATE_HELPTEXT :Porcentaje de interés de los préstamos; controla también la inflación, en caso de estar activada STR_CONFIG_SETTING_RUNNING_COSTS :Costos de operación: {STRING} -STR_CONFIG_SETTING_RUNNING_COSTS_HELPTEXT :Nivel de los costos de mantenimiento y operación de vehículos e infraestructura +STR_CONFIG_SETTING_RUNNING_COSTS_HELPTEXT :Nivel de costos de mantenimiento y operación de vehículos e infraestructura STR_CONFIG_SETTING_CONSTRUCTION_SPEED :Velocidad de construcción: {STRING} STR_CONFIG_SETTING_CONSTRUCTION_SPEED_HELPTEXT :Restringir la velocidad de las acciones de construcción de jugadores no humanos STR_CONFIG_SETTING_VEHICLE_BREAKDOWNS :Averías de vehículos: {STRING} @@ -1173,9 +1173,9 @@ STR_CONFIG_SETTING_SUBSIDY_MULTIPLIER_HELPTEXT :Establecer cuá STR_CONFIG_SETTING_CONSTRUCTION_COSTS :Costos de construcción: {STRING} STR_CONFIG_SETTING_CONSTRUCTION_COSTS_HELPTEXT :Nivel de costos de construcción y adquisición STR_CONFIG_SETTING_RECESSIONS :Recesiones: {STRING} -STR_CONFIG_SETTING_RECESSIONS_HELPTEXT :Si se activa, habrá recesiones cada cierto año. Durante una recesión, toda la producción decaerá considerablemente (se restablecerá al final de la recesión) -STR_CONFIG_SETTING_TRAIN_REVERSING :Prohibir a los trenes que cambien de dirección en las estaciones: {STRING} -STR_CONFIG_SETTING_TRAIN_REVERSING_HELPTEXT :Si se activa, los trenes no podrán girar al lado opuesto en estaciones intermedias, ni siquiera si al girar hay una ruta más corta a su próximo destino +STR_CONFIG_SETTING_RECESSIONS_HELPTEXT :Al activarse, habrá recesiones cada cierto año en las que toda la producción decaerá considerablemente, restableciéndose al final de cada recesión +STR_CONFIG_SETTING_TRAIN_REVERSING :Prohibir a los trenes que den reversa en estaciones: {STRING} +STR_CONFIG_SETTING_TRAIN_REVERSING_HELPTEXT :Al activarse, los trenes no podrán dar reversa en estaciones intermedias, aun si detrás hay una ruta más corta a su próximo destino STR_CONFIG_SETTING_DISASTERS :Desastres: {STRING} STR_CONFIG_SETTING_DISASTERS_HELPTEXT :Desastres que ocasionalmente pueden bloquear o destruir vehículos o infraestructura STR_CONFIG_SETTING_CITY_APPROVAL :Actitud de los ayuntamientos ante restructuraciones hechas en sus zonas: {STRING} @@ -1189,7 +1189,7 @@ STR_CONFIG_SETTING_AUTOSLOPE_HELPTEXT :Modificar el te STR_CONFIG_SETTING_CATCHMENT :Permitir cambiar el tamaño del área de recolección a una forma más real: {STRING} STR_CONFIG_SETTING_CATCHMENT_HELPTEXT :Las áreas de recolección se adecúan a diferentes tamaños, según los tipos de estaciones y aeropuertos STR_CONFIG_SETTING_SERVE_NEUTRAL_INDUSTRIES :Las estaciones privadas pueden dar servicio a industrias con estaciones neutrales: {STRING} -STR_CONFIG_SETTING_SERVE_NEUTRAL_INDUSTRIES_HELPTEXT :Si se activa, las industrias con estaciones integradas (ej. plataformas petrolíferas) podrán aceptar cargamento de estaciones privadas construidas cerca. Si se desactiva, tales industrias solo recibirán cargamento en sus propias estaciones. No aceptarán cargamento de estaciones de compañías, y la estación integrada no brindará servicio a nada más que su industria +STR_CONFIG_SETTING_SERVE_NEUTRAL_INDUSTRIES_HELPTEXT :Al activarse, las industrias con estaciones integradas (ej. plataformas petrolíferas) podrán aceptar carga de estaciones aledañas. Al desactivarse, tales industrias solo recibirán carga en sus propias estaciones y no aceptarán de otras estaciones, ni la estación integrada brindará servicio a nada más que su industria STR_CONFIG_SETTING_EXTRADYNAMITE :Permitir quitar mayor cantidad de carreteras, puentes y túneles de los pueblos: {STRING} STR_CONFIG_SETTING_EXTRADYNAMITE_HELPTEXT :Hacer más fácil eliminar infraestructura y edificios que sean propiedad de los pueblos STR_CONFIG_SETTING_TRAIN_LENGTH :Longitud máxima de trenes: {STRING} @@ -1242,7 +1242,7 @@ STR_CONFIG_SETTING_STOP_LOCATION_NEAR_END :principio STR_CONFIG_SETTING_STOP_LOCATION_MIDDLE :centro STR_CONFIG_SETTING_STOP_LOCATION_FAR_END :fondo STR_CONFIG_SETTING_AUTOSCROLL :Recorrer vista cuando se mueva el cursor a los bordes: {STRING} -STR_CONFIG_SETTING_AUTOSCROLL_HELPTEXT :Si se activa esta opción, las vistas se recorrerán cuando el ratón esté cerca de los bordes de la ventana +STR_CONFIG_SETTING_AUTOSCROLL_HELPTEXT :Al activarse, las vistas se desplazarán cuando el ratón se acarque a los bordes de la ventana STR_CONFIG_SETTING_AUTOSCROLL_DISABLED :Desactivado STR_CONFIG_SETTING_AUTOSCROLL_MAIN_VIEWPORT_FULLSCREEN :Vista principal, solo en pantalla completa STR_CONFIG_SETTING_AUTOSCROLL_MAIN_VIEWPORT :Vista principal @@ -1273,7 +1273,7 @@ STR_CONFIG_SETTING_STOP_ON_COMPETITOR_ROAD :Permitir la con STR_CONFIG_SETTING_STOP_ON_COMPETITOR_ROAD_HELPTEXT :Construir paradas de autobuses intermedias en carreteras que sean propiedad de otras empresas STR_CONFIG_SETTING_DYNAMIC_ENGINES_EXISTING_VEHICLES :{WHITE}No se puede cambiar esta opción si ya existen vehículos STR_CONFIG_SETTING_INFRASTRUCTURE_MAINTENANCE :Mantenimiento de infraestructura: {STRING} -STR_CONFIG_SETTING_INFRASTRUCTURE_MAINTENANCE_HELPTEXT :Cuando se activa, la infraestructura tiene costo de mantenimiento, el cual aumenta en relación con el tamaño de la red de transporte. Esto afecta en mayor medida a las empresas grandes que a las pequeñas +STR_CONFIG_SETTING_INFRASTRUCTURE_MAINTENANCE_HELPTEXT :Al activarse, la infraestructura tiene costo de mantenimiento que aumenta según el tamaño de la red de transporte, de modo que las empresas grandes se afectan más que las pequeñas STR_CONFIG_SETTING_COMPANY_STARTING_COLOUR :Color inicial de la empresa: {STRING} STR_CONFIG_SETTING_COMPANY_STARTING_COLOUR_HELPTEXT :Elegir el color inicial de la empresa @@ -1284,7 +1284,7 @@ STR_CONFIG_SETTING_NEVER_EXPIRE_AIRPORTS_HELPTEXT :Los tipos de ae STR_CONFIG_SETTING_WARN_LOST_VEHICLE :Avisar si un vehículo se ha perdido: {STRING} STR_CONFIG_SETTING_WARN_LOST_VEHICLE_HELPTEXT :Mostrar mensajes indicando aquellos vehículos que no puedan encontrar una ruta a su destino STR_CONFIG_SETTING_ORDER_REVIEW :Analizar órdenes de vehículos: {STRING} -STR_CONFIG_SETTING_ORDER_REVIEW_HELPTEXT :Cuando se activa, las órdenes de los vehículos se analizan regularmente y los problemas que se encuentren se informan en una noticia +STR_CONFIG_SETTING_ORDER_REVIEW_HELPTEXT :Al activarse, se analizan regularmente las órdenes de los vehículos y los problemas obvios que se detecten se informan en una noticia STR_CONFIG_SETTING_ORDER_REVIEW_OFF :No STR_CONFIG_SETTING_ORDER_REVIEW_EXDEPOT :Sí, excepto los vehículos detenidos STR_CONFIG_SETTING_ORDER_REVIEW_ON :Todos los vehículos @@ -1294,8 +1294,8 @@ STR_CONFIG_SETTING_NEVER_EXPIRE_VEHICLES :Vehículos siem STR_CONFIG_SETTING_NEVER_EXPIRE_VEHICLES_HELPTEXT :Todos los modelos de vehículos estarán disponibles para siempre tras haber sido introducidos STR_CONFIG_SETTING_AUTORENEW_VEHICLE :Renovar automáticamente vehículos que se hagan viejos: {STRING} STR_CONFIG_SETTING_AUTORENEW_VEHICLE_HELPTEXT :Los vehículos próximos al final de su vida útil serán renovados automáticamente, siempre y cuando se cumplan las condiciones de renovación -STR_CONFIG_SETTING_AUTORENEW_MONTHS :Renovar automáticamente el vehículo a {STRING} de su edad máxima -STR_CONFIG_SETTING_AUTORENEW_MONTHS_HELPTEXT :Edad relativa en la que un vehículo es considerado para renovarse +STR_CONFIG_SETTING_AUTORENEW_MONTHS :Renovar automáticamente el vehículo cumpla {STRING} +STR_CONFIG_SETTING_AUTORENEW_MONTHS_HELPTEXT :Edad relativa en que un vehículo se considera para renovación STR_CONFIG_SETTING_AUTORENEW_MONTHS_VALUE_BEFORE :{COMMA} mes{P 0 "" es} antes STR_CONFIG_SETTING_AUTORENEW_MONTHS_VALUE_AFTER :{COMMA} mes{P 0 "" es} después STR_CONFIG_SETTING_AUTORENEW_MONEY :Costo mínimo requerido para renovación automática: {STRING} @@ -1370,7 +1370,7 @@ STR_CONFIG_SETTING_SCROLLMODE_RMB_LOCKED :Recorrer mapa c STR_CONFIG_SETTING_SCROLLMODE_RMB :Recorrer mapa con clic derecho STR_CONFIG_SETTING_SCROLLMODE_LMB :Recorrer mapa con clic izquierdo STR_CONFIG_SETTING_SMOOTH_SCROLLING :Desplazamiento de vista suavizado: {STRING} -STR_CONFIG_SETTING_SMOOTH_SCROLLING_HELPTEXT :Forma en la que la vista principal se mueve a una ubicación específica al hacer clic en el minimapa o tras una orden de moverse a un objeto determinado del mapa. Si se activa, la vista se mueve de forma suave. Si se desactiva, la vista se mueve instantáneamente al sitio indicado +STR_CONFIG_SETTING_SMOOTH_SCROLLING_HELPTEXT :Forma en que la vista principal cambia a una ubicación desde el minimapa o tras una orden de ver un objeto determinado del mapa. Al activarse, la vista se mueve suavemente, y al desactivarse, la vista se mueve instantáneamente al sitio indicado STR_CONFIG_SETTING_MEASURE_TOOLTIP :Mostrar información de medidas al usar las herramientas de construcción: {STRING} STR_CONFIG_SETTING_MEASURE_TOOLTIP_HELPTEXT :Mostrar distancias en número de casillas y las diferencias de altura cuando se realicen labores de construcción STR_CONFIG_SETTING_LIVERIES :Mostrar cromáticas por tipo de vehículo: {STRING} @@ -1413,7 +1413,7 @@ STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_SHORT :corto (31-12-20 STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_ISO :ISO (2008-12-31) STR_CONFIG_SETTING_PAUSE_ON_NEW_GAME :Poner el juego en pausa al comenzar una partida: {STRING} -STR_CONFIG_SETTING_PAUSE_ON_NEW_GAME_HELPTEXT :Si se activa, el juego se detendrá automáticamente al comenzar nuevas partidas para permitir revisar el mapa +STR_CONFIG_SETTING_PAUSE_ON_NEW_GAME_HELPTEXT :Al activarse, el juego se detendrá automáticamente al comenzar nuevas partidas para permitir revisar el mapa STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL :Al pausar el juego, permitir: {STRING} STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_HELPTEXT :Qué acciones se pueden realizar mientras el juego está en pausa. STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_NO_ACTIONS :Ninguna acción @@ -1460,7 +1460,7 @@ STR_CONFIG_SETTING_SOUND_AMBIENT :Ambiente: {STRI STR_CONFIG_SETTING_SOUND_AMBIENT_HELPTEXT :Reproducir sonidos ambientales de terreno, industrias y pueblos STR_CONFIG_SETTING_DISABLE_UNSUITABLE_BUILDING :Deshabilitar construcción de infraestructura cuando no haya vehículos apropiados disponibles: {STRING} -STR_CONFIG_SETTING_DISABLE_UNSUITABLE_BUILDING_HELPTEXT :Cuando se activa, solamente se puede construir infraestructura si hay vehículos apropiados disponibles, previniendo un gasto innecesario de tiempo y dinero +STR_CONFIG_SETTING_DISABLE_UNSUITABLE_BUILDING_HELPTEXT :Al activarse, hay infraestructura disponible solo si hay vehículos adecuados, evitando gastos de tiempo y dinero en infraestructura inservible STR_CONFIG_SETTING_MAX_TRAINS :Número máximo de trenes por empresa: {STRING} STR_CONFIG_SETTING_MAX_TRAINS_HELPTEXT :Número máximo de trenes que una empresa puede tener STR_CONFIG_SETTING_MAX_ROAD_VEHICLES :Número máximo de vehículos de carretera por empresa: {STRING} @@ -1510,7 +1510,7 @@ STR_CONFIG_SETTING_NOSERVICE_HELPTEXT :Al activarse, l STR_CONFIG_SETTING_WAGONSPEEDLIMITS :Activar límites de velocidad para vagones: {STRING} STR_CONFIG_SETTING_WAGONSPEEDLIMITS_HELPTEXT :Al activarse, se tienen en cuenta los límites de velocidad de los vagones para decidir la máxima velocidad de un tren STR_CONFIG_SETTING_DISABLE_ELRAILS :Desactivar ferrocarriles eléctricos: {STRING} -STR_CONFIG_SETTING_DISABLE_ELRAILS_HELPTEXT :Si se activa, no es necesario electrificar las vías férreas para hacer que los trenes eléctricos puedan recorrerlas +STR_CONFIG_SETTING_DISABLE_ELRAILS_HELPTEXT :Al activarse, no es necesario electrificar las vías para que los trenes eléctricos las usen STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OWN :Llegada del primer vehículo a una estación del jugador: {STRING} STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OWN_HELPTEXT :Mostrar noticia cuando el primer vehículo llegue a una estación del jugador @@ -1566,11 +1566,11 @@ STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY :Al arrastrar, c STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY_HELPTEXT :Distancia de separación entre señales hasta topar con algún obstáculo (otra señal, un desvío, etc.) al instalarlas mediante arrastre con el ratón STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY_VALUE :{COMMA} casilla{P 0 "" s} STR_CONFIG_SETTING_DRAG_SIGNALS_FIXED_DISTANCE :Al arrastrar, mantener distancia fija entre señales: {STRING} -STR_CONFIG_SETTING_DRAG_SIGNALS_FIXED_DISTANCE_HELPTEXT :Forma en que se instalan las señales cuando se usa Ctrl+Arrastrar. Si se desactiva, se instalan señales a la entrada de túneles y puentes para evitar tramos largas de vías férreas sin señales. Si se activa, se colocan señales cada cierto número de casillas, haciendo que el alineamiento de señales en vías paralelas sea más sencillo +STR_CONFIG_SETTING_DRAG_SIGNALS_FIXED_DISTANCE_HELPTEXT :Forma en que se instalan señales con Ctrl+Arrastrar. Al desactivarse, se colocan señales cerca de túneles y puentes para evitar tramos largos de vías sin señales. Al activarse, se colocan señales cada tanto de casillas, con lo que alinear señales en vías paralelas es más fácil STR_CONFIG_SETTING_SEMAPHORE_BUILD_BEFORE_DATE :Señales mecánicas por defecto antes de: {STRING} STR_CONFIG_SETTING_SEMAPHORE_BUILD_BEFORE_DATE_HELPTEXT :Año a partir del cual se usarán señales eléctricas. Antes de ese año se usarán señales mecánicas, las cuales funcionan igual pero tienen distinto aspecto STR_CONFIG_SETTING_ENABLE_SIGNAL_GUI :Activar interfaz de señales: {STRING} -STR_CONFIG_SETTING_ENABLE_SIGNAL_GUI_HELPTEXT :Mostrar una ventana para elegir los tipos de señales a instalar. Si no se activa, se instalan las señales y se selecciona un tipo determinado mediante Ctrl+Clic, sin que aparezca ninguna interfaz +STR_CONFIG_SETTING_ENABLE_SIGNAL_GUI_HELPTEXT :Mostrar una ventana para elegir qué tipo de señales instalar en lugar de solo ir rotando los tipos mediante Ctrl+Clic y sin ventana STR_CONFIG_SETTING_DEFAULT_SIGNAL_TYPE :Tipo de señal a instalar por defecto: {STRING} STR_CONFIG_SETTING_DEFAULT_SIGNAL_TYPE_HELPTEXT :Tipo de señal por defecto STR_CONFIG_SETTING_DEFAULT_SIGNAL_NORMAL :Señales de tramo @@ -2246,7 +2246,7 @@ STR_CONTENT_SEARCH_EXTERNAL :{BLACK}Buscar e STR_CONTENT_SEARCH_EXTERNAL_TOOLTIP :{BLACK}Buscar contenido no disponible en el servicio de contenido del juego en sitios web externos no asociados con OpenTTD STR_CONTENT_SEARCH_EXTERNAL_DISCLAIMER_CAPTION :{WHITE}¡Estás saliendo de OpenTTD! STR_CONTENT_SEARCH_EXTERNAL_DISCLAIMER :{WHITE}Los términos y condiciones para descargar contenido de sitios web externos varían.{}Será necesario referirse a tales sitios para saber cómo instalar el contenido en OpenTTD.{}¿Continuar? -STR_CONTENT_FILTER_TITLE :{BLACK}Etiqueta o palabras claves +STR_CONTENT_FILTER_TITLE :{BLACK}Etiqueta o nombre: STR_CONTENT_OPEN_URL :{BLACK}Visitar sitio web STR_CONTENT_OPEN_URL_TOOLTIP :{BLACK}Visitar el sitio web de este contenido STR_CONTENT_DOWNLOAD_CAPTION :{BLACK}Descargar @@ -2819,7 +2819,7 @@ STR_SAVELOAD_DETAIL_CAPTION :{BLACK}Detalles STR_SAVELOAD_DETAIL_NOT_AVAILABLE :{BLACK}No hay información disponible STR_SAVELOAD_DETAIL_COMPANY_INDEX :{SILVER}{COMMA}: {WHITE}{STRING} STR_SAVELOAD_DETAIL_GRFSTATUS :{SILVER}NewGRF: {WHITE}{STRING} -STR_SAVELOAD_FILTER_TITLE :{BLACK}Filtrar palabras: +STR_SAVELOAD_FILTER_TITLE :{BLACK}Filtrar texto: STR_SAVELOAD_OVERWRITE_TITLE :{WHITE}Sobrescribir archivo STR_SAVELOAD_OVERWRITE_WARNING :{YELLOW}¿Estás seguro de sobrescribir el archivo? @@ -2903,7 +2903,7 @@ STR_NEWGRF_SETTINGS_INFO_TITLE :{WHITE}Informac STR_NEWGRF_SETTINGS_ACTIVE_LIST :{WHITE}Archivos NewGRF activos STR_NEWGRF_SETTINGS_INACTIVE_LIST :{WHITE}Archivos NewGRF inactivos STR_NEWGRF_SETTINGS_SELECT_PRESET :{ORANGE}Seleccionar perfil: -STR_NEWGRF_FILTER_TITLE :{ORANGE}Filtrar palabras: +STR_NEWGRF_FILTER_TITLE :{ORANGE}Filtrar texto: STR_NEWGRF_SETTINGS_PRESET_LIST_TOOLTIP :{BLACK}Cargar perfil STR_NEWGRF_SETTINGS_PRESET_SAVE :{BLACK}Guardar STR_NEWGRF_SETTINGS_PRESET_SAVE_TOOLTIP :{BLACK}Guardar lista actual como nuevo perfil diff --git a/src/linkgraph/linkgraph.h b/src/linkgraph/linkgraph.h index ebffe20218..216b569a4e 100644 --- a/src/linkgraph/linkgraph.h +++ b/src/linkgraph/linkgraph.h @@ -18,6 +18,7 @@ #include "../cargotype.h" #include "../date_func.h" #include "linkgraph_type.h" +#include struct SaveLoad; class LinkGraph; @@ -189,20 +190,20 @@ public: * to return something that implements operator->, but isn't a pointer * from operator->. A fake pointer. */ - class FakePointer : public SmallPair { + class FakePointer : public std::pair { public: /** * Construct a fake pointer from a pair of NodeID and edge. * @param pair Pair to be "pointed" to (in fact shallow-copied). */ - FakePointer(const SmallPair &pair) : SmallPair(pair) {} + FakePointer(const std::pair &pair) : std::pair(pair) {} /** * Retrieve the pair by operator->. * @return Pair being "pointed" to. */ - SmallPair *operator->() { return this; } + std::pair *operator->() { return this; } }; public: @@ -267,9 +268,9 @@ public: * Dereference with operator*. * @return Pair of current target NodeID and edge object. */ - SmallPair operator*() const + std::pair operator*() const { - return SmallPair(this->current, Tedge_wrapper(this->base[this->current])); + return std::pair(this->current, Tedge_wrapper(this->base[this->current])); } /** diff --git a/src/linkgraph/linkgraphjob.h b/src/linkgraph/linkgraphjob.h index 98299ceb7e..4c0ac4bc89 100644 --- a/src/linkgraph/linkgraphjob.h +++ b/src/linkgraph/linkgraphjob.h @@ -173,9 +173,9 @@ public: * @return Pair of the edge currently pointed to and the ID of its * other end. */ - SmallPair operator*() const + std::pair operator*() const { - return SmallPair(this->current, Edge(this->base[this->current], this->base_anno[this->current])); + return std::pair(this->current, Edge(this->base[this->current], this->base_anno[this->current])); } /** diff --git a/src/music.cpp b/src/music.cpp index 29828b6822..e78263c873 100644 --- a/src/music.cpp +++ b/src/music.cpp @@ -135,10 +135,10 @@ bool MusicSet::FillSetDetails(IniFile *ini, const char *path, const char *full_f this->songinfo[i].filename = filename; // non-owned pointer IniItem *item = catindex->GetItem(_music_file_names[i], false); - if (item != nullptr && !StrEmpty(item->value)) { + if (item != nullptr && item->value.has_value() && !item->value->empty()) { /* Song has a CAT file index, assume it's MPS MIDI format */ this->songinfo[i].filetype = MTT_MPSMIDI; - this->songinfo[i].cat_index = atoi(item->value); + this->songinfo[i].cat_index = atoi(item->value->c_str()); char *songname = GetMusicCatEntryName(filename, this->songinfo[i].cat_index); if (songname == nullptr) { DEBUG(grf, 1, "Base music set song missing from CAT file: %s/%d", filename, this->songinfo[i].cat_index); @@ -161,12 +161,12 @@ bool MusicSet::FillSetDetails(IniFile *ini, const char *path, const char *full_f while (*trimmed_filename == PATHSEPCHAR) trimmed_filename++; item = names->GetItem(trimmed_filename, false); - if (item != nullptr && !StrEmpty(item->value)) break; + if (item != nullptr && item->value.has_value() && !item->value->empty()) break; } if (this->songinfo[i].filetype == MTT_STANDARDMIDI) { - if (item != nullptr && !StrEmpty(item->value)) { - strecpy(this->songinfo[i].songname, item->value, lastof(this->songinfo[i].songname)); + if (item != nullptr && item->value.has_value() && !item->value->empty()) { + strecpy(this->songinfo[i].songname, item->value->c_str(), lastof(this->songinfo[i].songname)); } else { DEBUG(grf, 0, "Base music set song name missing: %s", filename); return false; @@ -181,12 +181,12 @@ bool MusicSet::FillSetDetails(IniFile *ini, const char *path, const char *full_f this->songinfo[i].tracknr = tracknr++; } - item = timingtrim->GetItem(trimmed_filename, false); - if (item != nullptr && !StrEmpty(item->value)) { - const char *endpos = strchr(item->value, ':'); - if (endpos != nullptr) { - this->songinfo[i].override_start = atoi(item->value); - this->songinfo[i].override_end = atoi(endpos + 1); + item = trimmed_filename != nullptr ? timingtrim->GetItem(trimmed_filename, false) : nullptr; + if (item != nullptr && item->value.has_value() && !item->value->empty()) { + auto endpos = item->value->find(':'); + if (endpos != std::string::npos) { + this->songinfo[i].override_start = atoi(item->value->c_str()); + this->songinfo[i].override_end = atoi(item->value->c_str() + endpos + 1); } } } diff --git a/src/music/allegro_m.cpp b/src/music/allegro_m.cpp index 4f90bce061..6d06ce87ec 100644 --- a/src/music/allegro_m.cpp +++ b/src/music/allegro_m.cpp @@ -26,7 +26,7 @@ static MIDI *_midi = nullptr; */ extern int _allegro_instance_count; -const char *MusicDriver_Allegro::Start(const char * const *param) +const char *MusicDriver_Allegro::Start(const StringList ¶m) { if (_allegro_instance_count == 0 && install_allegro(SYSTEM_AUTODETECT, &errno, nullptr)) { DEBUG(driver, 0, "allegro: install_allegro failed '%s'", allegro_error); diff --git a/src/music/allegro_m.h b/src/music/allegro_m.h index 1965626ca2..b07a7073b6 100644 --- a/src/music/allegro_m.h +++ b/src/music/allegro_m.h @@ -15,7 +15,7 @@ /** Allegro's music player. */ class MusicDriver_Allegro : public MusicDriver { public: - const char *Start(const char * const *param) override; + const char *Start(const StringList ¶m) override; void Stop() override; diff --git a/src/music/bemidi.cpp b/src/music/bemidi.cpp index c3ea152dae..4175f526b0 100644 --- a/src/music/bemidi.cpp +++ b/src/music/bemidi.cpp @@ -24,7 +24,7 @@ static BMidiSynthFile midiSynthFile; /** Factory for BeOS' midi player. */ static FMusicDriver_BeMidi iFMusicDriver_BeMidi; -const char *MusicDriver_BeMidi::Start(const char * const *parm) +const char *MusicDriver_BeMidi::Start(const StringList &parm) { return nullptr; } diff --git a/src/music/bemidi.h b/src/music/bemidi.h index a524069db0..8e96acc8d7 100644 --- a/src/music/bemidi.h +++ b/src/music/bemidi.h @@ -15,7 +15,7 @@ /** The midi player for BeOS. */ class MusicDriver_BeMidi : public MusicDriver { public: - const char *Start(const char * const *param) override; + const char *Start(const StringList ¶m) override; void Stop() override; diff --git a/src/music/cocoa_m.cpp b/src/music/cocoa_m.cpp index 9fec5ba15b..a989cfe769 100644 --- a/src/music/cocoa_m.cpp +++ b/src/music/cocoa_m.cpp @@ -79,7 +79,7 @@ static void DoSetVolume() /** * Initialized the MIDI player, including QuickTime initialization. */ -const char *MusicDriver_Cocoa::Start(const char * const *parm) +const char *MusicDriver_Cocoa::Start(const StringList &parm) { if (NewMusicPlayer(&_player) != noErr) return "failed to create music player"; diff --git a/src/music/cocoa_m.h b/src/music/cocoa_m.h index aa477eddaf..046a60c386 100644 --- a/src/music/cocoa_m.h +++ b/src/music/cocoa_m.h @@ -14,7 +14,7 @@ class MusicDriver_Cocoa : public MusicDriver { public: - const char *Start(const char * const *param) override; + const char *Start(const StringList ¶m) override; void Stop() override; diff --git a/src/music/dmusic.cpp b/src/music/dmusic.cpp index 218e1b96fc..c4edcfe08f 100644 --- a/src/music/dmusic.cpp +++ b/src/music/dmusic.cpp @@ -1074,7 +1074,7 @@ static const char *LoadDefaultDLSFile(const char *user_dls) } -const char *MusicDriver_DMusic::Start(const char * const *parm) +const char *MusicDriver_DMusic::Start(const StringList &parm) { /* Initialize COM */ if (FAILED(CoInitializeEx(nullptr, COINITBASE_MULTITHREADED))) return "COM initialization failed"; diff --git a/src/music/dmusic.h b/src/music/dmusic.h index bfbb07f16d..616bf01208 100644 --- a/src/music/dmusic.h +++ b/src/music/dmusic.h @@ -17,7 +17,7 @@ class MusicDriver_DMusic : public MusicDriver { public: virtual ~MusicDriver_DMusic(); - const char *Start(const char * const *param) override; + const char *Start(const StringList ¶m) override; void Stop() override; diff --git a/src/music/extmidi.cpp b/src/music/extmidi.cpp index b7e7e63b90..f882452501 100644 --- a/src/music/extmidi.cpp +++ b/src/music/extmidi.cpp @@ -36,7 +36,7 @@ /** Factory for the midi player that uses external players. */ static FMusicDriver_ExtMidi iFMusicDriver_ExtMidi; -const char *MusicDriver_ExtMidi::Start(const char * const * parm) +const char *MusicDriver_ExtMidi::Start(const StringList &parm) { if (strcmp(VideoDriver::GetInstance()->GetName(), "allegro") == 0 || strcmp(SoundDriver::GetInstance()->GetName(), "allegro") == 0) { diff --git a/src/music/extmidi.h b/src/music/extmidi.h index 495e9a72cf..f43bbad179 100644 --- a/src/music/extmidi.h +++ b/src/music/extmidi.h @@ -22,7 +22,7 @@ private: void DoStop(); public: - const char *Start(const char * const *param) override; + const char *Start(const StringList ¶m) override; void Stop() override; diff --git a/src/music/fluidsynth.cpp b/src/music/fluidsynth.cpp index 64abe0e538..61686a441e 100644 --- a/src/music/fluidsynth.cpp +++ b/src/music/fluidsynth.cpp @@ -50,7 +50,7 @@ static void RenderMusicStream(int16 *buffer, size_t samples) fluid_synth_write_s16(_midi.synth, samples, buffer, 0, 2, buffer, 1, 2); } -const char *MusicDriver_FluidSynth::Start(const char * const *param) +const char *MusicDriver_FluidSynth::Start(const StringList ¶m) { std::lock_guard lock{ _midi.synth_mutex }; diff --git a/src/music/fluidsynth.h b/src/music/fluidsynth.h index 71d43fec4c..91543662d0 100644 --- a/src/music/fluidsynth.h +++ b/src/music/fluidsynth.h @@ -15,7 +15,7 @@ /** Music driver making use of FluidSynth. */ class MusicDriver_FluidSynth : public MusicDriver { public: - const char *Start(const char * const *param) override; + const char *Start(const StringList ¶m) override; void Stop() override; diff --git a/src/music/music_driver.hpp b/src/music/music_driver.hpp index 601cc6d475..3953685bf0 100644 --- a/src/music/music_driver.hpp +++ b/src/music/music_driver.hpp @@ -48,6 +48,6 @@ public: } }; -extern char *_ini_musicdriver; +extern std::string _ini_musicdriver; #endif /* MUSIC_MUSIC_DRIVER_HPP */ diff --git a/src/music/null_m.h b/src/music/null_m.h index 09f84e35ce..3a034110dc 100644 --- a/src/music/null_m.h +++ b/src/music/null_m.h @@ -15,7 +15,7 @@ /** The music player that does nothing. */ class MusicDriver_Null : public MusicDriver { public: - const char *Start(const char * const *param) override { return nullptr; } + const char *Start(const StringList ¶m) override { return nullptr; } void Stop() override { } diff --git a/src/music/os2_m.cpp b/src/music/os2_m.cpp index f66c2bd9e8..4736065678 100644 --- a/src/music/os2_m.cpp +++ b/src/music/os2_m.cpp @@ -80,7 +80,7 @@ bool MusicDriver_OS2::IsSongPlaying() return strcmp(buf, "playing") == 0 || strcmp(buf, "seeking") == 0; } -const char *MusicDriver_OS2::Start(const char * const *parm) +const char *MusicDriver_OS2::Start(const StringList &parm) { return 0; } diff --git a/src/music/os2_m.h b/src/music/os2_m.h index d0a4809b2c..a60f5bbfc7 100644 --- a/src/music/os2_m.h +++ b/src/music/os2_m.h @@ -15,7 +15,7 @@ /** OS/2's music player. */ class MusicDriver_OS2 : public MusicDriver { public: - const char *Start(const char * const *param) override; + const char *Start(const StringList ¶m) override; void Stop() override; diff --git a/src/music/win32_m.cpp b/src/music/win32_m.cpp index 992f3d92d7..33fb7a0cd0 100644 --- a/src/music/win32_m.cpp +++ b/src/music/win32_m.cpp @@ -366,7 +366,7 @@ void MusicDriver_Win32::SetVolume(byte vol) _midi.new_volume = vol; } -const char *MusicDriver_Win32::Start(const char * const *parm) +const char *MusicDriver_Win32::Start(const StringList &parm) { DEBUG(driver, 2, "Win32-MIDI: Start: initializing"); diff --git a/src/music/win32_m.h b/src/music/win32_m.h index 394c3d9909..5101d29321 100644 --- a/src/music/win32_m.h +++ b/src/music/win32_m.h @@ -15,7 +15,7 @@ /** The Windows music player. */ class MusicDriver_Win32 : public MusicDriver { public: - const char *Start(const char * const *param) override; + const char *Start(const StringList ¶m) override; void Stop() override; diff --git a/src/music_gui.cpp b/src/music_gui.cpp index d15025ea3d..dad5c2ba71 100644 --- a/src/music_gui.cpp +++ b/src/music_gui.cpp @@ -65,7 +65,7 @@ struct MusicSystem { void BuildPlaylists(); void ChangePlaylist(PlaylistChoices pl); - void ChangeMusicSet(const char *set_name); + void ChangeMusicSet(const std::string &set_name); void Shuffle(); void Unshuffle(); @@ -167,12 +167,10 @@ void MusicSystem::ChangePlaylist(PlaylistChoices pl) * Change to named music set, and reset playback. * @param set_name Name of music set to select */ -void MusicSystem::ChangeMusicSet(const char *set_name) +void MusicSystem::ChangeMusicSet(const std::string &set_name) { BaseMusic::SetSet(set_name); - - free(BaseMusic::ini_set); - BaseMusic::ini_set = stredup(set_name); + BaseMusic::ini_set = set_name; this->BuildPlaylists(); this->ChangePlaylist(this->selected_playlist); @@ -433,8 +431,7 @@ void MusicLoop() void ChangeMusicSet(int index) { if (BaseMusic::GetIndexOfUsedSet() == index) return; - const char *name = BaseMusic::GetSet(index)->name; - _music.ChangeMusicSet(name); + _music.ChangeMusicSet(BaseMusic::GetSet(index)->name); } /** @@ -464,7 +461,7 @@ struct MusicTrackSelectionWindow : public Window { SetDParam(0, STR_MUSIC_PLAYLIST_ALL + _settings_client.music.playlist); break; case WID_MTS_CAPTION: - SetDParamStr(0, BaseMusic::GetUsedSet()->name); + SetDParamStr(0, BaseMusic::GetUsedSet()->name.c_str()); break; } } diff --git a/src/network/network_gamelist.cpp b/src/network/network_gamelist.cpp index ff744e8757..dfe07bdbbb 100644 --- a/src/network/network_gamelist.cpp +++ b/src/network/network_gamelist.cpp @@ -175,21 +175,15 @@ void NetworkAfterNewGRFScan() /* Don't know the GRF, so mark game incompatible and the (possibly) * already resolved name for this GRF (another server has sent the * name of the GRF already. */ - c->name->Release(); c->name = FindUnknownGRFName(c->ident.grfid, c->ident.md5sum, true); - c->name->AddRef(); c->status = GCS_NOT_FOUND; /* If we miss a file, we're obviously incompatible. */ item->info.compatible = false; } else { c->filename = f->filename; - c->name->Release(); c->name = f->name; - c->name->AddRef(); - c->info->Release(); c->info = f->info; - c->info->AddRef(); c->status = GCS_UNKNOWN; } } diff --git a/src/network/network_udp.cpp b/src/network/network_udp.cpp index 400c147adb..895b63a7c7 100644 --- a/src/network/network_udp.cpp +++ b/src/network/network_udp.cpp @@ -511,9 +511,9 @@ void ClientNetworkUDPSocketHandler::Receive_SERVER_NEWGRFS(Packet *p, NetworkAdd /* Try to find the GRFTextWrapper for the name of this GRF ID and MD5sum tuple. * If it exists and not resolved yet, then name of the fake GRF is * overwritten with the name from the reply. */ - GRFTextWrapper *unknown_name = FindUnknownGRFName(c.grfid, c.md5sum, false); - if (unknown_name != nullptr && strcmp(GetGRFStringFromGRFText(unknown_name->text), UNKNOWN_GRF_NAME_PLACEHOLDER) == 0) { - AddGRFTextToList(&unknown_name->text, name); + GRFTextWrapper unknown_name = FindUnknownGRFName(c.grfid, c.md5sum, false); + if (unknown_name && strcmp(GetGRFStringFromGRFText(unknown_name), UNKNOWN_GRF_NAME_PLACEHOLDER) == 0) { + AddGRFTextToList(unknown_name, name); } } } @@ -526,21 +526,13 @@ void ClientNetworkUDPSocketHandler::HandleIncomingNetworkGameInfoGRFConfig(GRFCo /* Don't know the GRF, so mark game incompatible and the (possibly) * already resolved name for this GRF (another server has sent the * name of the GRF already */ - config->name->Release(); config->name = FindUnknownGRFName(config->ident.grfid, config->ident.md5sum, true); - config->name->AddRef(); config->status = GCS_NOT_FOUND; } else { config->filename = f->filename; - config->name->Release(); config->name = f->name; - config->name->AddRef(); - config->info->Release(); config->info = f->info; - config->info->AddRef(); - config->url->Release(); config->url = f->url; - config->url->AddRef(); } SetBit(config->flags, GCF_COPY); } diff --git a/src/newgrf.cpp b/src/newgrf.cpp index b263006a8b..e20c94e3e0 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -5355,7 +5355,7 @@ static void NewSpriteGroup(ByteReader *buf) group->num_input = buf->ReadByte(); if (group->num_input > lengthof(group->subtract_input)) { GRFError *error = DisableGrf(STR_NEWGRF_ERROR_INDPROD_CALLBACK); - error->data = stredup("too many inputs (max 16)"); + error->data = "too many inputs (max 16)"; return; } for (uint i = 0; i < group->num_input; i++) { @@ -5368,7 +5368,7 @@ static void NewSpriteGroup(ByteReader *buf) group->version = 0xFF; } else if (std::find(group->cargo_input, group->cargo_input + i, cargo) != group->cargo_input + i) { GRFError *error = DisableGrf(STR_NEWGRF_ERROR_INDPROD_CALLBACK); - error->data = stredup("duplicate input cargo"); + error->data = "duplicate input cargo"; return; } group->cargo_input[i] = cargo; @@ -5377,7 +5377,7 @@ static void NewSpriteGroup(ByteReader *buf) group->num_output = buf->ReadByte(); if (group->num_output > lengthof(group->add_output)) { GRFError *error = DisableGrf(STR_NEWGRF_ERROR_INDPROD_CALLBACK); - error->data = stredup("too many outputs (max 16)"); + error->data = "too many outputs (max 16)"; return; } for (uint i = 0; i < group->num_output; i++) { @@ -5388,7 +5388,7 @@ static void NewSpriteGroup(ByteReader *buf) group->version = 0xFF; } else if (std::find(group->cargo_output, group->cargo_output + i, cargo) != group->cargo_output + i) { GRFError *error = DisableGrf(STR_NEWGRF_ERROR_INDPROD_CALLBACK); - error->data = stredup("duplicate output cargo"); + error->data = "duplicate output cargo"; return; } group->cargo_output[i] = cargo; @@ -6636,7 +6636,7 @@ static void CfgApply(ByteReader *buf) static void DisableStaticNewGRFInfluencingNonStaticNewGRFs(GRFConfig *c) { GRFError *error = DisableGrf(STR_NEWGRF_ERROR_STATIC_GRF_CAUSES_DESYNC, c); - error->data = stredup(_cur.grfconfig->GetName()); + error->data = _cur.grfconfig->GetName(); } /* Action 0x07 @@ -6839,11 +6839,11 @@ static void ScanInfo(ByteReader *buf) /* GRF IDs starting with 0xFF are reserved for internal TTDPatch use */ if (GB(grfid, 0, 8) == 0xFF) SetBit(_cur.grfconfig->flags, GCF_SYSTEM); - AddGRFTextToList(&_cur.grfconfig->name->text, 0x7F, grfid, false, name); + AddGRFTextToList(_cur.grfconfig->name, 0x7F, grfid, false, name); if (buf->HasData()) { const char *info = buf->ReadString(); - AddGRFTextToList(&_cur.grfconfig->info->text, 0x7F, grfid, true, info); + AddGRFTextToList(_cur.grfconfig->info, 0x7F, grfid, true, info); } /* GLS_INFOSCAN only looks for the action 8, so we can skip the rest of the file */ @@ -7014,10 +7014,10 @@ static void GRFLoadError(ByteReader *buf) if (buf->HasData()) { const char *message = buf->ReadString(); - error->custom_message = TranslateTTDPatchCodes(_cur.grffile->grfid, lang, true, message, nullptr, SCC_RAW_STRING_POINTER); + error->custom_message = TranslateTTDPatchCodes(_cur.grffile->grfid, lang, true, message, SCC_RAW_STRING_POINTER); } else { grfmsg(7, "GRFLoadError: No custom message supplied."); - error->custom_message = stredup(""); + error->custom_message.clear(); } } else { error->message = msgstr[message_id]; @@ -7029,7 +7029,7 @@ static void GRFLoadError(ByteReader *buf) error->data = TranslateTTDPatchCodes(_cur.grffile->grfid, lang, true, data); } else { grfmsg(7, "GRFLoadError: No message data supplied."); - error->data = stredup(""); + error->data.clear(); } /* Only two parameter numbers can be used in the string. */ @@ -7575,9 +7575,8 @@ static void FeatureTownName(ByteReader *buf) const char *name = buf->ReadString(); - char *lang_name = TranslateTTDPatchCodes(grfid, lang, false, name); - grfmsg(6, "FeatureTownName: lang 0x%X -> '%s'", lang, lang_name); - free(lang_name); + std::string lang_name = TranslateTTDPatchCodes(grfid, lang, false, name); + grfmsg(6, "FeatureTownName: lang 0x%X -> '%s'", lang, lang_name.c_str()); townname->name[nb_gen] = AddGRFString(grfid, id, lang, new_scheme, false, name, STR_UNDEFINED); @@ -7619,7 +7618,7 @@ static void FeatureTownName(ByteReader *buf) townname->partlist[id][i].parts[j].data.id = ref_id; } else { const char *text = buf->ReadString(); - townname->partlist[id][i].parts[j].data.text = TranslateTTDPatchCodes(grfid, 0, false, text); + townname->partlist[id][i].parts[j].data.text = stredup(TranslateTTDPatchCodes(grfid, 0, false, text).c_str()); grfmsg(6, "FeatureTownName: part %d, text %d, '%s' (with probability %d)", i, j, townname->partlist[id][i].parts[j].data.text, prob); } townname->partlist[id][i].parts[j].prob = prob; @@ -7891,7 +7890,7 @@ static void TranslateGRFStrings(ByteReader *buf) char tmp[256]; GetString(tmp, STR_NEWGRF_ERROR_AFTER_TRANSLATED_FILE, lastof(tmp)); - error->data = stredup(tmp); + error->data = tmp; return; } @@ -7925,21 +7924,21 @@ static void TranslateGRFStrings(ByteReader *buf) /** Callback function for 'INFO'->'NAME' to add a translation to the newgrf name. */ static bool ChangeGRFName(byte langid, const char *str) { - AddGRFTextToList(&_cur.grfconfig->name->text, langid, _cur.grfconfig->ident.grfid, false, str); + AddGRFTextToList(_cur.grfconfig->name, langid, _cur.grfconfig->ident.grfid, false, str); return true; } /** Callback function for 'INFO'->'DESC' to add a translation to the newgrf description. */ static bool ChangeGRFDescription(byte langid, const char *str) { - AddGRFTextToList(&_cur.grfconfig->info->text, langid, _cur.grfconfig->ident.grfid, true, str); + AddGRFTextToList(_cur.grfconfig->info, langid, _cur.grfconfig->ident.grfid, true, str); return true; } /** Callback function for 'INFO'->'URL_' to set the newgrf url. */ static bool ChangeGRFURL(byte langid, const char *str) { - AddGRFTextToList(&_cur.grfconfig->url->text, langid, _cur.grfconfig->ident.grfid, false, str); + AddGRFTextToList(_cur.grfconfig->url, langid, _cur.grfconfig->ident.grfid, false, str); return true; } @@ -8041,14 +8040,14 @@ static GRFParameterInfo *_cur_parameter; ///< The parameter which info is curren /** Callback function for 'INFO'->'PARAM'->param_num->'NAME' to set the name of a parameter. */ static bool ChangeGRFParamName(byte langid, const char *str) { - AddGRFTextToList(&_cur_parameter->name, langid, _cur.grfconfig->ident.grfid, false, str); + AddGRFTextToList(_cur_parameter->name, langid, _cur.grfconfig->ident.grfid, false, str); return true; } /** Callback function for 'INFO'->'PARAM'->param_num->'DESC' to set the description of a parameter. */ static bool ChangeGRFParamDescription(byte langid, const char *str) { - AddGRFTextToList(&_cur_parameter->desc, langid, _cur.grfconfig->ident.grfid, true, str); + AddGRFTextToList(_cur_parameter->desc, langid, _cur.grfconfig->ident.grfid, true, str); return true; } @@ -8249,12 +8248,12 @@ static bool ChangeGRFParamValueNames(ByteReader *buf) byte langid = buf->ReadByte(); const char *name_string = buf->ReadString(); - SmallPair *val_name = _cur_parameter->value_names.Find(id); + std::pair *val_name = _cur_parameter->value_names.Find(id); if (val_name != _cur_parameter->value_names.End()) { - AddGRFTextToList(&val_name->second, langid, _cur.grfconfig->ident.grfid, false, name_string); + AddGRFTextToList(val_name->second, langid, _cur.grfconfig->ident.grfid, false, name_string); } else { - GRFText *list = nullptr; - AddGRFTextToList(&list, langid, _cur.grfconfig->ident.grfid, false, name_string); + GRFTextList list; + AddGRFTextToList(list, langid, _cur.grfconfig->ident.grfid, false, name_string); _cur_parameter->value_names.Insert(id, list); } diff --git a/src/newgrf_config.cpp b/src/newgrf_config.cpp index b3b25506a8..652a038859 100644 --- a/src/newgrf_config.cpp +++ b/src/newgrf_config.cpp @@ -21,6 +21,7 @@ #include "textfile_gui.h" #include "thread.h" #include "newgrf_config.h" +#include "newgrf_text.h" #include "fileio_func.h" #include "fios.h" @@ -35,17 +36,6 @@ #include "safeguards.h" -/** Create a new GRFTextWrapper. */ -GRFTextWrapper::GRFTextWrapper() : - text(nullptr) -{ -} - -/** Cleanup a GRFTextWrapper object. */ -GRFTextWrapper::~GRFTextWrapper() -{ - CleanUpGRFText(this->text); -} /** * Create a new GRFConfig. @@ -53,15 +43,9 @@ GRFTextWrapper::~GRFTextWrapper() * is copied so the original string isn't needed after the constructor. */ GRFConfig::GRFConfig(const char *filename) : - name(new GRFTextWrapper()), - info(new GRFTextWrapper()), - url(new GRFTextWrapper()), num_valid_params(lengthof(param)) { if (filename != nullptr) this->filename = stredup(filename); - this->name->AddRef(); - this->info->AddRef(); - this->url->AddRef(); } /** @@ -87,9 +71,6 @@ GRFConfig::GRFConfig(const GRFConfig &config) : MemCpyT(this->original_md5sum, config.original_md5sum, lengthof(this->original_md5sum)); MemCpyT(this->param, config.param, lengthof(this->param)); if (config.filename != nullptr) this->filename = stredup(config.filename); - this->name->AddRef(); - this->info->AddRef(); - this->url->AddRef(); if (config.error != nullptr) this->error = new GRFError(*config.error); for (uint i = 0; i < config.param_info.size(); i++) { if (config.param_info[i] == nullptr) { @@ -109,9 +90,6 @@ GRFConfig::~GRFConfig() delete this->error; } free(this->full_filename); - this->name->Release(); - this->info->Release(); - this->url->Release(); for (uint i = 0; i < this->param_info.size(); i++) delete this->param_info[i]; } @@ -134,7 +112,7 @@ void GRFConfig::CopyParams(const GRFConfig &src) */ const char *GRFConfig::GetName() const { - const char *name = GetGRFStringFromGRFText(this->name->text); + const char *name = GetGRFStringFromGRFText(this->name); return StrEmpty(name) ? this->filename : name; } @@ -144,7 +122,7 @@ const char *GRFConfig::GetName() const */ const char *GRFConfig::GetDescription() const { - return GetGRFStringFromGRFText(this->info->text); + return GetGRFStringFromGRFText(this->info); } /** @@ -153,7 +131,7 @@ const char *GRFConfig::GetDescription() const */ const char *GRFConfig::GetURL() const { - return GetGRFStringFromGRFText(this->url->text); + return GetGRFStringFromGRFText(this->url); } /** Set the default value for all parameters as specified by action14. */ @@ -212,7 +190,8 @@ bool _grf_bug_too_many_strings = false; */ GRFError::GRFError(StringID severity, StringID message) : message(message), - severity(severity) + severity(severity), + param_value() { } @@ -221,30 +200,21 @@ GRFError::GRFError(StringID severity, StringID message) : * @param error The GRFError object to make a copy of. */ GRFError::GRFError(const GRFError &error) : - ZeroedMemoryAllocator(), custom_message(error.custom_message), data(error.data), message(error.message), severity(error.severity) { - if (error.custom_message != nullptr) this->custom_message = stredup(error.custom_message); - if (error.data != nullptr) this->data = stredup(error.data); memcpy(this->param_value, error.param_value, sizeof(this->param_value)); } -GRFError::~GRFError() -{ - free(this->custom_message); - free(this->data); -} - /** * Create a new empty GRFParameterInfo object. * @param nr The newgrf parameter that is changed. */ GRFParameterInfo::GRFParameterInfo(uint nr) : - name(nullptr), - desc(nullptr), + name(), + desc(), type(PTYPE_UINT_ENUM), min_value(0), max_value(UINT32_MAX), @@ -252,6 +222,7 @@ GRFParameterInfo::GRFParameterInfo(uint nr) : param_nr(nr), first_bit(0), num_bit(32), + value_names(), complete_labels(false) {} @@ -261,8 +232,8 @@ GRFParameterInfo::GRFParameterInfo(uint nr) : * @param info The GRFParameterInfo object to make a copy of. */ GRFParameterInfo::GRFParameterInfo(GRFParameterInfo &info) : - name(DuplicateGRFText(info.name)), - desc(DuplicateGRFText(info.desc)), + name(info.name), + desc(info.desc), type(info.type), min_value(info.min_value), max_value(info.max_value), @@ -270,23 +241,9 @@ GRFParameterInfo::GRFParameterInfo(GRFParameterInfo &info) : param_nr(info.param_nr), first_bit(info.first_bit), num_bit(info.num_bit), + value_names(info.value_names), complete_labels(info.complete_labels) { - for (uint i = 0; i < info.value_names.size(); i++) { - SmallPair *data = info.value_names.data() + i; - this->value_names.Insert(data->first, DuplicateGRFText(data->second)); - } -} - -/** Cleanup all parameter info. */ -GRFParameterInfo::~GRFParameterInfo() -{ - CleanUpGRFText(this->name); - CleanUpGRFText(this->desc); - for (uint i = 0; i < this->value_names.size(); i++) { - SmallPair *data = this->value_names.data() + i; - CleanUpGRFText(data->second); - } } /** @@ -689,12 +646,8 @@ compatible_grf: free(c->filename); c->filename = stredup(f->filename); memcpy(c->ident.md5sum, f->ident.md5sum, sizeof(c->ident.md5sum)); - c->name->Release(); c->name = f->name; - c->name->AddRef(); - c->info->Release(); c->info = f->name; - c->info->AddRef(); c->error = nullptr; c->version = f->version; c->min_loadable_version = f->min_loadable_version; @@ -798,7 +751,7 @@ bool GRFFileScanner::AddFile(const char *filename, size_t basepath_length, const _modal_progress_paint_mutex.lock(); const char *name = nullptr; - if (c->name != nullptr) name = GetGRFStringFromGRFText(c->name->text); + if (c->name != nullptr) name = GetGRFStringFromGRFText(c->name); if (name == nullptr) name = c->filename; UpdateNewGRFScanStatus(this->num_scanned, name); @@ -932,8 +885,12 @@ const GRFConfig *FindGRFConfig(uint32 grfid, FindGRFConfigMode mode, const uint8 /** Structure for UnknownGRFs; this is a lightweight variant of GRFConfig */ struct UnknownGRF : public GRFIdentifier { - UnknownGRF *next; ///< The next unknown GRF. - GRFTextWrapper *name; ///< Name of the GRF. + GRFTextWrapper name; ///< Name of the GRF. + + UnknownGRF() = default; + UnknownGRF(const UnknownGRF &other) = default; + UnknownGRF(UnknownGRF &&other) = default; + UnknownGRF(uint32 grfid, const uint8 *_md5sum) : GRFIdentifier(grfid, _md5sum), name(new GRFTextList) {} }; /** @@ -953,30 +910,24 @@ struct UnknownGRF : public GRFIdentifier { * and MD5 checksum or nullptr when it does not exist and create is false. * This value must NEVER be freed by the caller. */ -GRFTextWrapper *FindUnknownGRFName(uint32 grfid, uint8 *md5sum, bool create) +GRFTextWrapper FindUnknownGRFName(uint32 grfid, uint8 *md5sum, bool create) { - UnknownGRF *grf; - static UnknownGRF *unknown_grfs = nullptr; + static std::vector unknown_grfs; - for (grf = unknown_grfs; grf != nullptr; grf = grf->next) { - if (grf->grfid == grfid) { - if (memcmp(md5sum, grf->md5sum, sizeof(grf->md5sum)) == 0) return grf->name; + for (const auto &grf : unknown_grfs) { + if (grf.grfid == grfid) { + if (memcmp(md5sum, grf.md5sum, sizeof(grf.md5sum)) == 0) return grf.name; } } if (!create) return nullptr; - grf = CallocT(1); - grf->grfid = grfid; - grf->next = unknown_grfs; - grf->name = new GRFTextWrapper(); - grf->name->AddRef(); + unknown_grfs.emplace_back(grfid, md5sum); + UnknownGRF &grf = unknown_grfs.back(); - AddGRFTextToList(&grf->name->text, UNKNOWN_GRF_NAME_PLACEHOLDER); - memcpy(grf->md5sum, md5sum, sizeof(grf->md5sum)); + AddGRFTextToList(grf.name, UNKNOWN_GRF_NAME_PLACEHOLDER); - unknown_grfs = grf; - return grf->name; + return grf.name; } /** diff --git a/src/newgrf_config.h b/src/newgrf_config.h index 276c97a559..c7390be489 100644 --- a/src/newgrf_config.h +++ b/src/newgrf_config.h @@ -16,6 +16,7 @@ #include "misc/countedptr.hpp" #include "fileio_type.h" #include "textfile_type.h" +#include "newgrf_text.h" /** GRF config bit flags */ enum GCF_Flags { @@ -83,6 +84,16 @@ struct GRFIdentifier { uint32 grfid; ///< GRF ID (defined by Action 0x08) uint8 md5sum[16]; ///< MD5 checksum of file to distinguish files with the same GRF ID (eg. newer version of GRF) + GRFIdentifier() = default; + GRFIdentifier(const GRFIdentifier &other) = default; + GRFIdentifier(GRFIdentifier &&other) = default; + GRFIdentifier(uint32 grfid, const uint8 *md5sum) : grfid(grfid) + { + MemCpyT(this->md5sum, md5sum, lengthof(this->md5sum)); + } + + GRFIdentifier& operator =(const GRFIdentifier &other) = default; + /** * Does the identification match the provided values? * @param grfid Expected grfid. @@ -98,16 +109,15 @@ struct GRFIdentifier { }; /** Information about why GRF had problems during initialisation */ -struct GRFError : ZeroedMemoryAllocator { +struct GRFError { GRFError(StringID severity, StringID message = 0); GRFError(const GRFError &error); - ~GRFError(); - char *custom_message; ///< Custom message (if present) - char *data; ///< Additional data for message and custom_message - StringID message; ///< Default message - StringID severity; ///< Info / Warning / Error / Fatal - uint64 param_value[4]; ///< Values of GRF parameters to show for message and custom_message + std::string custom_message; ///< Custom message (if present) + std::string data; ///< Additional data for message and custom_message + StringID message; ///< Default message + StringID severity; ///< Info / Warning / Error / Fatal + uint64 param_value[4]; ///< Values of GRF parameters to show for message and custom_message }; /** The possible types of a newgrf parameter. */ @@ -121,9 +131,8 @@ enum GRFParameterType { struct GRFParameterInfo { GRFParameterInfo(uint nr); GRFParameterInfo(GRFParameterInfo &info); - ~GRFParameterInfo(); - struct GRFText *name; ///< The name of this parameter - struct GRFText *desc; ///< The description of this parameter + GRFTextList name; ///< The name of this parameter + GRFTextList desc; ///< The description of this parameter GRFParameterType type; ///< The type of this parameter uint32 min_value; ///< The minimal value this parameter can have uint32 max_value; ///< The maximal value of this parameter @@ -131,7 +140,7 @@ struct GRFParameterInfo { byte param_nr; ///< GRF parameter to store content in byte first_bit; ///< First bit to use in the GRF parameter byte num_bit; ///< Number of bits to use for this parameter - SmallMap value_names; ///< Names for each value. + SmallMap value_names; ///< Names for each value. bool complete_labels; ///< True if all values have a label. uint32 GetValue(struct GRFConfig *config) const; @@ -139,14 +148,6 @@ struct GRFParameterInfo { void Finalize(); }; -/** Reference counted wrapper around a GRFText pointer. */ -struct GRFTextWrapper : public SimpleCountedObject { - struct GRFText *text; ///< The actual text - - GRFTextWrapper(); - ~GRFTextWrapper(); -}; - /** Information about GRF, used in the game and (part of it) in savegames */ struct GRFConfig : ZeroedMemoryAllocator { GRFConfig(const char *filename = nullptr); @@ -157,9 +158,9 @@ struct GRFConfig : ZeroedMemoryAllocator { uint8 original_md5sum[16]; ///< MD5 checksum of original file if only a 'compatible' file was loaded char *filename; ///< Filename - either with or without full path char *full_filename; ///< NOSAVE: Full filename - GRFTextWrapper *name; ///< NOSAVE: GRF name (Action 0x08) - GRFTextWrapper *info; ///< NOSAVE: GRF info (author, copyright, ...) (Action 0x08) - GRFTextWrapper *url; ///< NOSAVE: URL belonging to this GRF. + GRFTextWrapper name; ///< NOSAVE: GRF name (Action 0x08) + GRFTextWrapper info; ///< NOSAVE: GRF info (author, copyright, ...) (Action 0x08) + GRFTextWrapper url; ///< NOSAVE: URL belonging to this GRF. GRFError *error; ///< NOSAVE: Error/Warning during GRF loading (Action 0x0B) uint32 version; ///< NOSAVE: Version a NewGRF can set so only the newest NewGRF is shown @@ -237,7 +238,7 @@ void ShowNewGRFSettings(bool editable, bool show_params, bool exec_changes, GRFC /** For communication about GRFs over the network */ #define UNKNOWN_GRF_NAME_PLACEHOLDER "" -GRFTextWrapper *FindUnknownGRFName(uint32 grfid, uint8 *md5sum, bool create); +GRFTextWrapper FindUnknownGRFName(uint32 grfid, uint8 *md5sum, bool create); void UpdateNewGRFScanStatus(uint num, const char *name); bool UpdateNewGRFConfigPalette(int32 p1 = 0); diff --git a/src/newgrf_debug_gui.cpp b/src/newgrf_debug_gui.cpp index b29a726be4..d61f3b3f8f 100644 --- a/src/newgrf_debug_gui.cpp +++ b/src/newgrf_debug_gui.cpp @@ -842,7 +842,7 @@ GrfSpecFeature GetGrfSpecFeature(VehicleType type) /** Window used for aligning sprites. */ struct SpriteAlignerWindow : Window { - typedef SmallPair XyOffs; ///< Pair for x and y offsets of the sprite before alignment. First value contains the x offset, second value y offset. + typedef std::pair XyOffs; ///< Pair for x and y offsets of the sprite before alignment. First value contains the x offset, second value y offset. SpriteID current_sprite; ///< The currently shown sprite. Scrollbar *vscroll; diff --git a/src/newgrf_gui.cpp b/src/newgrf_gui.cpp index 09968dedac..df4ea58e25 100644 --- a/src/newgrf_gui.cpp +++ b/src/newgrf_gui.cpp @@ -50,10 +50,10 @@ void ShowNewGRFError() /* We only want to show fatal errors */ if (c->error == nullptr || c->error->severity != STR_NEWGRF_ERROR_MSG_FATAL) continue; - SetDParam (0, c->error->custom_message == nullptr ? c->error->message : STR_JUST_RAW_STRING); - SetDParamStr(1, c->error->custom_message); + SetDParam (0, c->error->message != STR_NULL ? c->error->message : STR_JUST_RAW_STRING); + SetDParamStr(1, c->error->custom_message.c_str()); SetDParamStr(2, c->filename); - SetDParamStr(3, c->error->data); + SetDParamStr(3, c->error->data.c_str()); for (uint i = 0; i < lengthof(c->error->param_value); i++) { SetDParam(4 + i, c->error->param_value[i]); } @@ -66,13 +66,13 @@ static void ShowNewGRFInfo(const GRFConfig *c, uint x, uint y, uint right, uint { if (c->error != nullptr) { char message[512]; - SetDParamStr(0, c->error->custom_message); // is skipped by built-in messages + SetDParamStr(0, c->error->custom_message.c_str()); // is skipped by built-in messages SetDParamStr(1, c->filename); - SetDParamStr(2, c->error->data); + SetDParamStr(2, c->error->data.c_str()); for (uint i = 0; i < lengthof(c->error->param_value); i++) { SetDParam(3 + i, c->error->param_value[i]); } - GetString(message, c->error->custom_message == nullptr ? c->error->message : STR_JUST_RAW_STRING, lastof(message)); + GetString(message, c->error->message != STR_NULL ? c->error->message : STR_JUST_RAW_STRING, lastof(message)); SetDParamStr(0, message); y = DrawStringMultiLine(x, right, y, bottom, c->error->severity); @@ -927,7 +927,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { list.emplace_back(new DropDownListStringItem(STR_NONE, -1, false)); for (uint i = 0; i < this->grf_presets.size(); i++) { - list.emplace_back(new DropDownListCharStringItem(this->grf_presets[i].c_str(), i, false)); + list.emplace_back(new DropDownListCharStringItem(this->grf_presets[i], i, false)); } this->DeleteChildWindows(WC_QUERY_STRING); // Remove the parameter query window diff --git a/src/newgrf_house.cpp b/src/newgrf_house.cpp index 077584a0be..722257c91d 100644 --- a/src/newgrf_house.cpp +++ b/src/newgrf_house.cpp @@ -749,8 +749,6 @@ bool NewHouseTileLoop(TileIndex tile) uint16 callback_res = GetHouseCallback(CBID_HOUSE_DESTRUCTION, 0, 0, GetHouseType(tile), t, tile); if (callback_res != CALLBACK_FAILED && Convert8bitBooleanCallback(hs->grf_prop.grffile, CBID_HOUSE_DESTRUCTION, callback_res)) { ClearTownHouse(t, tile); - extern void RemoveNearbyStations(Town *t); - RemoveNearbyStations(t); return false; } } diff --git a/src/newgrf_text.cpp b/src/newgrf_text.cpp index 09e70ea5e2..be68c47e44 100644 --- a/src/newgrf_text.cpp +++ b/src/newgrf_text.cpp @@ -32,6 +32,8 @@ #include "core/alloc_type.hpp" #include "core/smallmap_type.hpp" #include "language.h" +#include +#include #include "table/strings.h" #include "table/control_codes.h" @@ -64,89 +66,6 @@ enum GRFExtendedLanguages { GRFLX_UNSPECIFIED = 0x7F, }; -/** - * Element of the linked list. - * Each of those elements represent the string, - * but according to a different lang. - */ -struct GRFText { -public: - /** - * Allocate, and assign a new GRFText with the given text. - * As these strings can have string terminations in them, e.g. - * due to "choice lists" we (sometimes) cannot rely on detecting - * the length by means of strlen. Also, if the length of already - * known not scanning the whole string is more efficient. - * @param langid The language of the text. - * @param text The text to store in the new GRFText. - * @param len The length of the text. - */ - static GRFText *New(byte langid, const char *text, size_t len) - { - return new (len) GRFText(langid, text, len); - } - - /** - * Create a copy of this GRFText. - * @param orig the grftext to copy. - * @return an exact copy of the given text. - */ - static GRFText *Copy(GRFText *orig) - { - return GRFText::New(orig->langid, orig->text, orig->len); - } - - /** - * Helper allocation function to disallow something. - * Don't allow simple 'news'; they wouldn't have enough memory. - * @param size the amount of space not to allocate. - */ - void *operator new(size_t size) - { - NOT_REACHED(); - } - - /** - * Free the memory we allocated. - * @param p memory to free. - */ - void operator delete(void *p) - { - free(p); - } -private: - /** - * Actually construct the GRFText. - * @param langid_ The language of the text. - * @param text_ The text to store in this GRFText. - * @param len_ The length of the text to store. - */ - GRFText(byte langid_, const char *text_, size_t len_) : next(nullptr), len(len_), langid(langid_) - { - /* We need to use memcpy instead of strcpy due to - * the possibility of "choice lists" and therefore - * intermediate string terminators. */ - memcpy(this->text, text_, len); - } - - /** - * Allocate memory for this class. - * @param size the size of the instance - * @param extra the extra memory for the text - * @return the requested amount of memory for both the instance and the text - */ - void *operator new(size_t size, size_t extra) - { - return MallocT(size + extra); - } - -public: - GRFText *next; ///< The next GRFText in this chain. - size_t len; ///< The length of the stored string, used for copying. - byte langid; ///< The language associated with this GRFText. - char text[]; ///< The actual (translated) text. -}; - /** * Holder of the above structure. @@ -157,7 +76,7 @@ struct GRFTextEntry { uint32 grfid; uint16 stringid; StringID def_string; - GRFText *textholder; + GRFTextList textholder; }; @@ -196,58 +115,48 @@ int LanguageMap::GetReverseMapping(int openttd_id, bool gender) const } /** Helper structure for mapping choice lists. */ -struct UnmappedChoiceList : ZeroedMemoryAllocator { - /** Clean everything up. */ - ~UnmappedChoiceList() - { - for (SmallPair p : this->strings) { - free(p.second); - } - } - +struct UnmappedChoiceList { /** * Initialise the mapping. * @param type The type of mapping. - * @param old_d The old begin of the string, i.e. from where to start writing again. * @param offset The offset to get the plural/gender from. */ - UnmappedChoiceList(StringControlCode type, char *old_d, int offset) : - type(type), old_d(old_d), offset(offset) + UnmappedChoiceList(StringControlCode type, int offset) : + type(type), offset(offset) { } StringControlCode type; ///< The type of choice list. - char *old_d; ///< The old/original location of the "d" local variable. int offset; ///< The offset for the plural/gender form. /** Mapping of NewGRF supplied ID to the different strings in the choice list. */ - SmallMap strings; + std::map strings; /** - * Flush this choice list into the old d variable. - * @param lm The current language mapping. - * @return The new location of the output string. + * Flush this choice list into the destination string. + * @param lm The current language mapping. + * @param dest Target to write to. */ - char *Flush(const LanguageMap *lm) + void Flush(const LanguageMap *lm, std::ostringstream &dest) { - if (!this->strings.Contains(0)) { + if (this->strings.find(0) == this->strings.end()) { /* In case of a (broken) NewGRF without a default, * assume an empty string. */ grfmsg(1, "choice list misses default value"); - this->strings[0] = stredup(""); + this->strings[0] = std::stringstream(); } - char *d = old_d; + std::ostreambuf_iterator d(dest); + if (lm == nullptr) { /* In case there is no mapping, just ignore everything but the default. * A probable cause for this happening is when the language file has * been removed by the user and as such no mapping could be made. */ - size_t len = strlen(this->strings[0]); - memcpy(d, this->strings[0], len); - return d + len; + dest << this->strings[0].rdbuf(); + return; } - d += Utf8Encode(d, this->type); + Utf8Encode(d, this->type); if (this->type == SCC_SWITCH_CASE) { /* @@ -260,33 +169,31 @@ struct UnmappedChoiceList : ZeroedMemoryAllocator { int count = 0; for (uint8 i = 0; i < _current_language->num_cases; i++) { /* Count the ones we have a mapped string for. */ - if (this->strings.Contains(lm->GetReverseMapping(i, false))) count++; + if (this->strings.find(lm->GetReverseMapping(i, false)) != this->strings.end()) count++; } *d++ = count; for (uint8 i = 0; i < _current_language->num_cases; i++) { /* Resolve the string we're looking for. */ int idx = lm->GetReverseMapping(i, false); - if (!this->strings.Contains(idx)) continue; - char *str = this->strings[idx]; + if (this->strings.find(idx) == this->strings.end()) continue; + auto str = this->strings[idx].str(); /* "" */ *d++ = i + 1; - /* "" */ - size_t len = strlen(str) + 1; - *d++ = GB(len, 8, 8); - *d++ = GB(len, 0, 8); + /* "": Limit the length of the string to 0xFFFE to leave space for the '\0'. */ + size_t len = min(0xFFFE, str.size()); + *d++ = GB(len + 1, 8, 8); + *d++ = GB(len + 1, 0, 8); /* "" */ - memcpy(d, str, len); - d += len; + dest.write(str.c_str(), len); + *d++ = '\0'; } /* "" */ - size_t len = strlen(this->strings[0]) + 1; - memcpy(d, this->strings[0], len); - d += len; + dest << this->strings[0].rdbuf() << '\0'; } else { if (this->type == SCC_PLURAL_LIST) { *d++ = lm->plural_form; @@ -307,8 +214,8 @@ struct UnmappedChoiceList : ZeroedMemoryAllocator { /* "" */ for (int i = 0; i < count; i++) { int idx = (this->type == SCC_GENDER_LIST ? lm->GetReverseMapping(i, true) : i + 1); - const char *str = this->strings[this->strings.Contains(idx) ? idx : 0]; - size_t len = strlen(str) + 1; + const auto &str = this->strings[this->strings.find(idx) != this->strings.end() ? idx : 0].str(); + size_t len = str.size() + 1; if (len > 0xFF) grfmsg(1, "choice list string is too long"); *d++ = GB(len, 0, 8); } @@ -316,16 +223,14 @@ struct UnmappedChoiceList : ZeroedMemoryAllocator { /* "" */ for (int i = 0; i < count; i++) { int idx = (this->type == SCC_GENDER_LIST ? lm->GetReverseMapping(i, true) : i + 1); - const char *str = this->strings[this->strings.Contains(idx) ? idx : 0]; + const auto &str = this->strings[this->strings.find(idx) != this->strings.end() ? idx : 0].str(); /* Limit the length of the string we copy to 0xFE. The length is written above * as a byte and we need room for the final '\0'. */ - size_t len = min(0xFE, strlen(str)); - memcpy(d, str, len); - d += len; + size_t len = min(0xFE, str.size()); + dest.write(str.c_str(), len); *d++ = '\0'; } } - return d; } }; @@ -335,47 +240,55 @@ struct UnmappedChoiceList : ZeroedMemoryAllocator { * @param language_id The (NewGRF) language ID associated with this string. * @param allow_newlines Whether newlines are allowed in the string or not. * @param str The string to translate. - * @param[out] olen The length of the final string. * @param byte80 The control code to use as replacement for the 0x80-value. * @return The translated string. */ -char *TranslateTTDPatchCodes(uint32 grfid, uint8 language_id, bool allow_newlines, const char *str, int *olen, StringControlCode byte80) +std::string TranslateTTDPatchCodes(uint32 grfid, uint8 language_id, bool allow_newlines, const std::string &str, StringControlCode byte80) { - char *tmp = MallocT(strlen(str) * 10 + 1); // Allocate space to allow for expansion - char *d = tmp; + /* Empty input string? Nothing to do here. */ + if (str.empty()) return str; + + std::string::const_iterator src = str.cbegin(); + + /* Is this an unicode string? */ bool unicode = false; - WChar c; - size_t len = Utf8Decode(&c, str); + WChar marker; + size_t len = Utf8Decode(&marker, &*src); + + if (marker == NFO_UTF8_IDENTIFIER) { + unicode = true; + src += len; + } /* Helper variable for a possible (string) mapping. */ UnmappedChoiceList *mapping = nullptr; - if (c == NFO_UTF8_IDENTIFIER) { - unicode = true; - str += len; - } + std::ostringstream dest; + std::ostreambuf_iterator d(dest); + while (src != str.cend()) { + WChar c; - for (;;) { - if (unicode && Utf8EncodedCharLen(*str) != 0) { - c = Utf8Consume(&str); + if (unicode && Utf8EncodedCharLen(*src) != 0) { + c = Utf8Consume(src); /* 'Magic' range of control codes. */ if (GB(c, 8, 8) == 0xE0) { c = GB(c, 0, 8); } else if (c >= 0x20) { if (!IsValidChar(c, CS_ALPHANUMERAL)) c = '?'; - d += Utf8Encode(d, c); + Utf8Encode(d, c); continue; } } else { - c = (byte)*str++; + c = (byte)*src++; } + if (c == '\0') break; switch (c) { case 0x01: - if (str[0] == '\0') goto string_end; - d += Utf8Encode(d, ' '); - str++; + if (*src == '\0') goto string_end; + Utf8Encode(d, ' '); + src++; break; case 0x0A: break; case 0x0D: @@ -385,92 +298,96 @@ char *TranslateTTDPatchCodes(uint32 grfid, uint8 language_id, bool allow_newline grfmsg(1, "Detected newline in string that does not allow one"); } break; - case 0x0E: d += Utf8Encode(d, SCC_TINYFONT); break; - case 0x0F: d += Utf8Encode(d, SCC_BIGFONT); break; + case 0x0E: Utf8Encode(d, SCC_TINYFONT); break; + case 0x0F: Utf8Encode(d, SCC_BIGFONT); break; case 0x1F: - if (str[0] == '\0' || str[1] == '\0') goto string_end; - d += Utf8Encode(d, ' '); - str += 2; + if (src[0] == '\0' || src[1] == '\0') goto string_end; + Utf8Encode(d, ' '); + src += 2; break; case 0x7B: case 0x7C: case 0x7D: case 0x7E: - case 0x7F: d += Utf8Encode(d, SCC_NEWGRF_PRINT_DWORD_SIGNED + c - 0x7B); break; - case 0x80: d += Utf8Encode(d, byte80); break; - case 0x81: { - if (str[0] == '\0' || str[1] == '\0') goto string_end; + case 0x7F: Utf8Encode(d, SCC_NEWGRF_PRINT_DWORD_SIGNED + c - 0x7B); break; + case 0x80: Utf8Encode(d, byte80); break; + case 0x81: + { + if (src[0] == '\0' || src[1] == '\0') goto string_end; StringID string; - string = ((uint8)*str++); - string |= ((uint8)*str++) << 8; - d += Utf8Encode(d, SCC_NEWGRF_STRINL); - d += Utf8Encode(d, MapGRFStringID(grfid, string)); + string = ((uint8)* src++); + string |= ((uint8)* src++) << 8; + Utf8Encode(d, SCC_NEWGRF_STRINL); + Utf8Encode(d, MapGRFStringID(grfid, string)); break; } case 0x82: case 0x83: - case 0x84: d += Utf8Encode(d, SCC_NEWGRF_PRINT_WORD_DATE_LONG + c - 0x82); break; - case 0x85: d += Utf8Encode(d, SCC_NEWGRF_DISCARD_WORD); break; - case 0x86: d += Utf8Encode(d, SCC_NEWGRF_ROTATE_TOP_4_WORDS); break; - case 0x87: d += Utf8Encode(d, SCC_NEWGRF_PRINT_WORD_VOLUME_LONG); break; - case 0x88: d += Utf8Encode(d, SCC_BLUE); break; - case 0x89: d += Utf8Encode(d, SCC_SILVER); break; - case 0x8A: d += Utf8Encode(d, SCC_GOLD); break; - case 0x8B: d += Utf8Encode(d, SCC_RED); break; - case 0x8C: d += Utf8Encode(d, SCC_PURPLE); break; - case 0x8D: d += Utf8Encode(d, SCC_LTBROWN); break; - case 0x8E: d += Utf8Encode(d, SCC_ORANGE); break; - case 0x8F: d += Utf8Encode(d, SCC_GREEN); break; - case 0x90: d += Utf8Encode(d, SCC_YELLOW); break; - case 0x91: d += Utf8Encode(d, SCC_DKGREEN); break; - case 0x92: d += Utf8Encode(d, SCC_CREAM); break; - case 0x93: d += Utf8Encode(d, SCC_BROWN); break; - case 0x94: d += Utf8Encode(d, SCC_WHITE); break; - case 0x95: d += Utf8Encode(d, SCC_LTBLUE); break; - case 0x96: d += Utf8Encode(d, SCC_GRAY); break; - case 0x97: d += Utf8Encode(d, SCC_DKBLUE); break; - case 0x98: d += Utf8Encode(d, SCC_BLACK); break; - case 0x9A: { - int code = *str++; + case 0x84: Utf8Encode(d, SCC_NEWGRF_PRINT_WORD_DATE_LONG + c - 0x82); break; + case 0x85: Utf8Encode(d, SCC_NEWGRF_DISCARD_WORD); break; + case 0x86: Utf8Encode(d, SCC_NEWGRF_ROTATE_TOP_4_WORDS); break; + case 0x87: Utf8Encode(d, SCC_NEWGRF_PRINT_WORD_VOLUME_LONG); break; + case 0x88: Utf8Encode(d, SCC_BLUE); break; + case 0x89: Utf8Encode(d, SCC_SILVER); break; + case 0x8A: Utf8Encode(d, SCC_GOLD); break; + case 0x8B: Utf8Encode(d, SCC_RED); break; + case 0x8C: Utf8Encode(d, SCC_PURPLE); break; + case 0x8D: Utf8Encode(d, SCC_LTBROWN); break; + case 0x8E: Utf8Encode(d, SCC_ORANGE); break; + case 0x8F: Utf8Encode(d, SCC_GREEN); break; + case 0x90: Utf8Encode(d, SCC_YELLOW); break; + case 0x91: Utf8Encode(d, SCC_DKGREEN); break; + case 0x92: Utf8Encode(d, SCC_CREAM); break; + case 0x93: Utf8Encode(d, SCC_BROWN); break; + case 0x94: Utf8Encode(d, SCC_WHITE); break; + case 0x95: Utf8Encode(d, SCC_LTBLUE); break; + case 0x96: Utf8Encode(d, SCC_GRAY); break; + case 0x97: Utf8Encode(d, SCC_DKBLUE); break; + case 0x98: Utf8Encode(d, SCC_BLACK); break; + case 0x9A: + { + int code = *src++; switch (code) { case 0x00: goto string_end; - case 0x01: d += Utf8Encode(d, SCC_NEWGRF_PRINT_QWORD_CURRENCY); break; - /* 0x02: ignore next colour byte is not supported. It works on the final - * string and as such hooks into the string drawing routine. At that - * point many things already happened, such as splitting up of strings - * when drawn over multiple lines or right-to-left translations, which - * make the behaviour peculiar, e.g. only happening at specific width - * of windows. Or we need to add another pass over the string to just - * support this. As such it is not implemented in OpenTTD. */ - case 0x03: { - if (str[0] == '\0' || str[1] == '\0') goto string_end; - uint16 tmp = ((uint8)*str++); - tmp |= ((uint8)*str++) << 8; - d += Utf8Encode(d, SCC_NEWGRF_PUSH_WORD); - d += Utf8Encode(d, tmp); + case 0x01: Utf8Encode(d, SCC_NEWGRF_PRINT_QWORD_CURRENCY); break; + /* 0x02: ignore next colour byte is not supported. It works on the final + * string and as such hooks into the string drawing routine. At that + * point many things already happened, such as splitting up of strings + * when drawn over multiple lines or right-to-left translations, which + * make the behaviour peculiar, e.g. only happening at specific width + * of windows. Or we need to add another pass over the string to just + * support this. As such it is not implemented in OpenTTD. */ + case 0x03: + { + if (src[0] == '\0' || src[1] == '\0') goto string_end; + uint16 tmp = ((uint8)* src++); + tmp |= ((uint8)* src++) << 8; + Utf8Encode(d, SCC_NEWGRF_PUSH_WORD); + Utf8Encode(d, tmp); break; } case 0x04: - if (str[0] == '\0') goto string_end; - d += Utf8Encode(d, SCC_NEWGRF_UNPRINT); - d += Utf8Encode(d, *str++); + if (src[0] == '\0') goto string_end; + Utf8Encode(d, SCC_NEWGRF_UNPRINT); + Utf8Encode(d, *src++); break; - case 0x06: d += Utf8Encode(d, SCC_NEWGRF_PRINT_BYTE_HEX); break; - case 0x07: d += Utf8Encode(d, SCC_NEWGRF_PRINT_WORD_HEX); break; - case 0x08: d += Utf8Encode(d, SCC_NEWGRF_PRINT_DWORD_HEX); break; + case 0x06: Utf8Encode(d, SCC_NEWGRF_PRINT_BYTE_HEX); break; + case 0x07: Utf8Encode(d, SCC_NEWGRF_PRINT_WORD_HEX); break; + case 0x08: Utf8Encode(d, SCC_NEWGRF_PRINT_DWORD_HEX); break; /* 0x09, 0x0A are TTDPatch internal use only string codes. */ - case 0x0B: d += Utf8Encode(d, SCC_NEWGRF_PRINT_QWORD_HEX); break; - case 0x0C: d += Utf8Encode(d, SCC_NEWGRF_PRINT_WORD_STATION_NAME); break; - case 0x0D: d += Utf8Encode(d, SCC_NEWGRF_PRINT_WORD_WEIGHT_LONG); break; + case 0x0B: Utf8Encode(d, SCC_NEWGRF_PRINT_QWORD_HEX); break; + case 0x0C: Utf8Encode(d, SCC_NEWGRF_PRINT_WORD_STATION_NAME); break; + case 0x0D: Utf8Encode(d, SCC_NEWGRF_PRINT_WORD_WEIGHT_LONG); break; case 0x0E: - case 0x0F: { + case 0x0F: + { if (str[0] == '\0') goto string_end; const LanguageMap *lm = LanguageMap::GetLanguageMap(grfid, language_id); - int index = *str++; + int index = *src++; int mapped = lm != nullptr ? lm->GetMapping(index, code == 0x0E) : -1; if (mapped >= 0) { - d += Utf8Encode(d, code == 0x0E ? SCC_GENDER_INDEX : SCC_SET_CASE); - d += Utf8Encode(d, code == 0x0E ? mapped : mapped + 1); + Utf8Encode(d, code == 0x0E ? SCC_GENDER_INDEX : SCC_SET_CASE); + Utf8Encode(d, code == 0x0E ? mapped : mapped + 1); } break; } @@ -479,18 +396,16 @@ char *TranslateTTDPatchCodes(uint32 grfid, uint8 language_id, bool allow_newline case 0x11: if (str[0] == '\0') goto string_end; if (mapping == nullptr) { - if (code == 0x10) str++; // Skip the index + if (code == 0x10) src++; // Skip the index grfmsg(1, "choice list %s marker found when not expected", code == 0x10 ? "next" : "default"); break; } else { - /* Terminate the previous string. */ - *d = '\0'; - int index = (code == 0x10 ? *str++ : 0); - if (mapping->strings.Contains(index)) { + int index = (code == 0x10 ? *src++ : 0); + if (mapping->strings.find(index) != mapping->strings.end()) { grfmsg(1, "duplicate choice list string, ignoring"); d++; } else { - d = mapping->strings[index] = MallocT(strlen(str) * 10 + 1); + d = std::ostreambuf_iterator(mapping->strings[index]); } } break; @@ -499,26 +414,25 @@ char *TranslateTTDPatchCodes(uint32 grfid, uint8 language_id, bool allow_newline if (mapping == nullptr) { grfmsg(1, "choice list end marker found when not expected"); } else { - /* Terminate the previous string. */ - *d = '\0'; - /* Now we can start flushing everything and clean everything up. */ - d = mapping->Flush(LanguageMap::GetLanguageMap(grfid, language_id)); + mapping->Flush(LanguageMap::GetLanguageMap(grfid, language_id), dest); delete mapping; mapping = nullptr; + + d = std::ostreambuf_iterator(dest); } break; case 0x13: case 0x14: case 0x15: - if (str[0] == '\0') goto string_end; + if (src[0] == '\0') goto string_end; if (mapping != nullptr) { grfmsg(1, "choice lists can't be stacked, it's going to get messy now..."); - if (code != 0x14) str++; + if (code != 0x14) src++; } else { static const StringControlCode mp[] = { SCC_GENDER_LIST, SCC_SWITCH_CASE, SCC_PLURAL_LIST }; - mapping = new UnmappedChoiceList(mp[code - 0x13], d, code == 0x14 ? 0 : *str++); + mapping = new UnmappedChoiceList(mp[code - 0x13], code == 0x14 ? 0 : *src++); } break; @@ -531,11 +445,11 @@ char *TranslateTTDPatchCodes(uint32 grfid, uint8 language_id, bool allow_newline case 0x1C: case 0x1D: case 0x1E: - d += Utf8Encode(d, SCC_NEWGRF_PRINT_DWORD_DATE_LONG + code - 0x16); + Utf8Encode(d, SCC_NEWGRF_PRINT_DWORD_DATE_LONG + code - 0x16); break; - case 0x1F: d += Utf8Encode(d, SCC_PUSH_COLOUR); break; - case 0x20: d += Utf8Encode(d, SCC_POP_COLOUR); break; + case 0x1F: Utf8Encode(d, SCC_PUSH_COLOUR); break; + case 0x20: Utf8Encode(d, SCC_POP_COLOUR); break; default: grfmsg(1, "missing handler for extended format code"); @@ -544,25 +458,25 @@ char *TranslateTTDPatchCodes(uint32 grfid, uint8 language_id, bool allow_newline break; } - case 0x9E: d += Utf8Encode(d, 0x20AC); break; // Euro - case 0x9F: d += Utf8Encode(d, 0x0178); break; // Y with diaeresis - case 0xA0: d += Utf8Encode(d, SCC_UP_ARROW); break; - case 0xAA: d += Utf8Encode(d, SCC_DOWN_ARROW); break; - case 0xAC: d += Utf8Encode(d, SCC_CHECKMARK); break; - case 0xAD: d += Utf8Encode(d, SCC_CROSS); break; - case 0xAF: d += Utf8Encode(d, SCC_RIGHT_ARROW); break; - case 0xB4: d += Utf8Encode(d, SCC_TRAIN); break; - case 0xB5: d += Utf8Encode(d, SCC_LORRY); break; - case 0xB6: d += Utf8Encode(d, SCC_BUS); break; - case 0xB7: d += Utf8Encode(d, SCC_PLANE); break; - case 0xB8: d += Utf8Encode(d, SCC_SHIP); break; - case 0xB9: d += Utf8Encode(d, SCC_SUPERSCRIPT_M1); break; - case 0xBC: d += Utf8Encode(d, SCC_SMALL_UP_ARROW); break; - case 0xBD: d += Utf8Encode(d, SCC_SMALL_DOWN_ARROW); break; + case 0x9E: Utf8Encode(d, 0x20AC); break; // Euro + case 0x9F: Utf8Encode(d, 0x0178); break; // Y with diaeresis + case 0xA0: Utf8Encode(d, SCC_UP_ARROW); break; + case 0xAA: Utf8Encode(d, SCC_DOWN_ARROW); break; + case 0xAC: Utf8Encode(d, SCC_CHECKMARK); break; + case 0xAD: Utf8Encode(d, SCC_CROSS); break; + case 0xAF: Utf8Encode(d, SCC_RIGHT_ARROW); break; + case 0xB4: Utf8Encode(d, SCC_TRAIN); break; + case 0xB5: Utf8Encode(d, SCC_LORRY); break; + case 0xB6: Utf8Encode(d, SCC_BUS); break; + case 0xB7: Utf8Encode(d, SCC_PLANE); break; + case 0xB8: Utf8Encode(d, SCC_SHIP); break; + case 0xB9: Utf8Encode(d, SCC_SUPERSCRIPT_M1); break; + case 0xBC: Utf8Encode(d, SCC_SMALL_UP_ARROW); break; + case 0xBD: Utf8Encode(d, SCC_SMALL_DOWN_ARROW); break; default: /* Validate any unhandled character */ if (!IsValidChar(c, CS_ALPHANUMERAL)) c = '?'; - d += Utf8Encode(d, c); + Utf8Encode(d, c); break; } } @@ -573,33 +487,27 @@ string_end: delete mapping; } - *d = '\0'; - if (olen != nullptr) *olen = d - tmp + 1; - tmp = ReallocT(tmp, d - tmp + 1); - return tmp; + return dest.str(); } /** - * Add a GRFText to a GRFText list. + * Add a new text to a GRFText list. * @param list The list where the text should be added to. - * @param text_to_add The GRFText to add to the list. + * @param langid The The language of the new text. + * @param text_to_add The text to add to the list. */ -void AddGRFTextToList(GRFText **list, GRFText *text_to_add) +static void AddGRFTextToList(GRFTextList &list, byte langid, const std::string &text_to_add) { - GRFText **ptext, *text; - /* Loop through all languages and see if we can replace a string */ - for (ptext = list; (text = *ptext) != nullptr; ptext = &text->next) { - if (text->langid == text_to_add->langid) { - text_to_add->next = text->next; - *ptext = text_to_add; - delete text; + for (auto &text : list) { + if (text.langid == langid) { + text.text = text_to_add; return; } } /* If a string wasn't replaced, then we must append the new string */ - *ptext = text_to_add; + list.push_back(GRFText{ langid, text_to_add }); } /** @@ -611,14 +519,24 @@ void AddGRFTextToList(GRFText **list, GRFText *text_to_add) * @param text_to_add The text to add to the list. * @note All text-codes will be translated. */ -void AddGRFTextToList(struct GRFText **list, byte langid, uint32 grfid, bool allow_newlines, const char *text_to_add) +void AddGRFTextToList(GRFTextList &list, byte langid, uint32 grfid, bool allow_newlines, const char *text_to_add) { - int len; - char *translatedtext = TranslateTTDPatchCodes(grfid, langid, allow_newlines, text_to_add, &len); - GRFText *newtext = GRFText::New(langid, translatedtext, len); - free(translatedtext); + AddGRFTextToList(list, langid, TranslateTTDPatchCodes(grfid, langid, allow_newlines, text_to_add)); +} - AddGRFTextToList(list, newtext); +/** + * Add a string to a GRFText list. + * @param list The list where the text should be added to. + * @param langid The language of the new text. + * @param grfid The grfid where this string is defined. + * @param allow_newlines Whether newlines are allowed in this string. + * @param text_to_add The text to add to the list. + * @note All text-codes will be translated. + */ +void AddGRFTextToList(GRFTextWrapper &list, byte langid, uint32 grfid, bool allow_newlines, const char *text_to_add) +{ + if (!list) list.reset(new GRFTextList()); + AddGRFTextToList(*list, langid, grfid, allow_newlines, text_to_add); } /** @@ -627,25 +545,10 @@ void AddGRFTextToList(struct GRFText **list, byte langid, uint32 grfid, bool all * @param list The list where the text should be added to. * @param text_to_add The text to add to the list. */ -void AddGRFTextToList(struct GRFText **list, const char *text_to_add) +void AddGRFTextToList(GRFTextWrapper &list, const char *text_to_add) { - AddGRFTextToList(list, GRFText::New(0x7F, text_to_add, strlen(text_to_add) + 1)); -} - -/** - * Create a copy of this GRFText list. - * @param orig The GRFText list to copy. - * @return A duplicate of the given GRFText. - */ -GRFText *DuplicateGRFText(GRFText *orig) -{ - GRFText *newtext = nullptr; - GRFText **ptext = &newtext; - for (; orig != nullptr; orig = orig->next) { - *ptext = GRFText::Copy(orig); - ptext = &(*ptext)->next; - } - return newtext; + if (!list) list.reset(new GRFTextList()); + AddGRFTextToList(*list, GRFLX_UNSPECIFIED, std::string(text_to_add)); } /** @@ -653,9 +556,6 @@ GRFText *DuplicateGRFText(GRFText *orig) */ StringID AddGRFString(uint32 grfid, uint16 stringid, byte langid_to_add, bool new_scheme, bool allow_newlines, const char *text_to_add, StringID def_string) { - char *translatedtext; - uint id; - /* When working with the old language scheme (grf_version is less than 7) and * English or American is among the set bits, simply add it as English in * the new scheme, i.e. as langid = 1. @@ -674,6 +574,7 @@ StringID AddGRFString(uint32 grfid, uint16 stringid, byte langid_to_add, bool ne } } + uint id; for (id = 0; id < _num_grf_texts; id++) { if (_grf_text[id].grfid == grfid && _grf_text[id].stringid == stringid) { break; @@ -686,24 +587,19 @@ StringID AddGRFString(uint32 grfid, uint16 stringid, byte langid_to_add, bool ne return STR_EMPTY; } - int len; - translatedtext = TranslateTTDPatchCodes(grfid, langid_to_add, allow_newlines, text_to_add, &len); - - GRFText *newtext = GRFText::New(langid_to_add, translatedtext, len); - - free(translatedtext); + std::string newtext = TranslateTTDPatchCodes(grfid, langid_to_add, allow_newlines, text_to_add); /* If we didn't find our stringid and grfid in the list, allocate a new id */ if (id == _num_grf_texts) _num_grf_texts++; - if (_grf_text[id].textholder == nullptr) { + if (_grf_text[id].textholder.empty()) { _grf_text[id].grfid = grfid; _grf_text[id].stringid = stringid; _grf_text[id].def_string = def_string; } - AddGRFTextToList(&_grf_text[id].textholder, newtext); + AddGRFTextToList(_grf_text[id].textholder, langid_to_add, newtext); - grfmsg(3, "Added 0x%X: grfid %08X string 0x%X lang 0x%X string '%s' (%X)", id, grfid, stringid, newtext->langid, newtext->text, MakeStringID(TEXT_TAB_NEWGRF_START, id)); + grfmsg(3, "Added 0x%X: grfid %08X string 0x%X lang 0x%X string '%s' (%X)", id, grfid, stringid, langid_to_add, newtext.c_str(), MakeStringID(TEXT_TAB_NEWGRF_START, id)); return MakeStringID(TEXT_TAB_NEWGRF_START, id); } @@ -728,20 +624,20 @@ StringID GetGRFStringID(uint32 grfid, StringID stringid) * current language it is returned, otherwise the default translation * is returned. If there is neither a default nor a translation for the * current language nullptr is returned. - * @param text The GRFText to get the string from. + * @param text_list The GRFTextList to get the string from. */ -const char *GetGRFStringFromGRFText(const GRFText *text) +const char *GetGRFStringFromGRFText(const GRFTextList &text_list) { const char *default_text = nullptr; /* Search the list of lang-strings of this stringid for current lang */ - for (; text != nullptr; text = text->next) { - if (text->langid == _currentLangID) return text->text; + for (const auto &text : text_list) { + if (text.langid == _currentLangID) return text.text.c_str(); /* If the current string is English or American, set it as the * fallback language if the specific language isn't available. */ - if (text->langid == GRFLX_UNSPECIFIED || (default_text == nullptr && (text->langid == GRFLX_ENGLISH || text->langid == GRFLX_AMERICAN))) { - default_text = text->text; + if (text.langid == GRFLX_UNSPECIFIED || (default_text == nullptr && (text.langid == GRFLX_ENGLISH || text.langid == GRFLX_AMERICAN))) { + default_text = text.text.c_str(); } } @@ -751,6 +647,18 @@ const char *GetGRFStringFromGRFText(const GRFText *text) static std::array, 16> _grf_string_ptr_log; static unsigned int _grf_string_ptr_log_next = 0; +/** + * Get a C-string from a GRFText-list. If there is a translation for the + * current language it is returned, otherwise the default translation + * is returned. If there is neither a default nor a translation for the + * current language nullptr is returned. + * @param text The GRFTextList to get the string from. + */ +const char *GetGRFStringFromGRFText(const GRFTextWrapper &text) +{ + return text ? GetGRFStringFromGRFText(*text) : nullptr; +} + /** * Get a C-string from a stringid set by a newgrf. */ @@ -797,19 +705,6 @@ bool CheckGrfLangID(byte lang_id, byte grf_version) return (lang_id == _currentLangID || lang_id == GRFLX_UNSPECIFIED); } -/** - * Delete all items of a linked GRFText list. - * @param grftext the head of the list to delete - */ -void CleanUpGRFText(GRFText *grftext) -{ - while (grftext != nullptr) { - GRFText *grftext2 = grftext->next; - delete grftext; - grftext = grftext2; - } -} - /** * House cleaning. * Remove all strings and reset the text counter. @@ -819,10 +714,9 @@ void CleanUpStrings() uint id; for (id = 0; id < _num_grf_texts; id++) { - CleanUpGRFText(_grf_text[id].textholder); _grf_text[id].grfid = 0; _grf_text[id].stringid = 0; - _grf_text[id].textholder = nullptr; + _grf_text[id].textholder.clear(); } for (id = 0; id < _grf_string_ptr_log.size(); id++) { diff --git a/src/newgrf_text.h b/src/newgrf_text.h index 709f4dd244..2c7eb731db 100644 --- a/src/newgrf_text.h +++ b/src/newgrf_text.h @@ -14,26 +14,39 @@ #include "strings_type.h" #include "core/smallvec_type.hpp" #include "table/control_codes.h" +#include +#include +#include /** This character, the thorn ('þ'), indicates a unicode string to NFO. */ static const WChar NFO_UTF8_IDENTIFIER = 0x00DE; +/** A GRF text with associated language ID. */ +struct GRFText { + byte langid; ///< The language associated with this GRFText. + std::string text; ///< The actual (translated) text. +}; + +/** A GRF text with a list of translations. */ +typedef std::vector GRFTextList; +/** Reference counted wrapper around a GRFText pointer. */ +typedef std::shared_ptr GRFTextWrapper; + StringID AddGRFString(uint32 grfid, uint16 stringid, byte langid, bool new_scheme, bool allow_newlines, const char *text_to_add, StringID def_string); StringID GetGRFStringID(uint32 grfid, StringID stringid); -const char *GetGRFStringFromGRFText(const struct GRFText *text); +const char *GetGRFStringFromGRFText(const GRFTextList &text_list); +const char *GetGRFStringFromGRFText(const GRFTextWrapper &text); const char *GetGRFStringPtr(uint16 stringid); void CleanUpStrings(); void SetCurrentGrfLangID(byte language_id); -char *TranslateTTDPatchCodes(uint32 grfid, uint8 language_id, bool allow_newlines, const char *str, int *olen = nullptr, StringControlCode byte80 = SCC_NEWGRF_PRINT_WORD_STRING_ID); -struct GRFText *DuplicateGRFText(struct GRFText *orig); -void AddGRFTextToList(struct GRFText **list, struct GRFText *text_to_add); -void AddGRFTextToList(struct GRFText **list, byte langid, uint32 grfid, bool allow_newlines, const char *text_to_add); -void AddGRFTextToList(struct GRFText **list, const char *text_to_add); -void CleanUpGRFText(struct GRFText *grftext); +std::string TranslateTTDPatchCodes(uint32 grfid, uint8 language_id, bool allow_newlines, const std::string &str, StringControlCode byte80 = SCC_NEWGRF_PRINT_WORD_STRING_ID); +void AddGRFTextToList(GRFTextList &list, byte langid, uint32 grfid, bool allow_newlines, const char *text_to_add); +void AddGRFTextToList(GRFTextWrapper &list, byte langid, uint32 grfid, bool allow_newlines, const char *text_to_add); +void AddGRFTextToList(GRFTextWrapper &list, const char *text_to_add); bool CheckGrfLangID(byte lang_id, byte grf_version); -void StartTextRefStackUsage(const GRFFile *grffile, byte numEntries, const uint32 *values = nullptr); +void StartTextRefStackUsage(const struct GRFFile *grffile, byte numEntries, const uint32 *values = nullptr); void StopTextRefStackUsage(); void RewindTextRefStack(); bool UsingNewGRFTextStack(); diff --git a/src/openttd.cpp b/src/openttd.cpp index c912432ee8..4b30fb63d7 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -671,17 +671,17 @@ static const OptionData _options[] = { int openttd_main(int argc, char *argv[]) { SetSelfAsMainThread(); - char *musicdriver = nullptr; - char *sounddriver = nullptr; - char *videodriver = nullptr; - char *blitter = nullptr; - char *graphics_set = nullptr; - char *sounds_set = nullptr; - char *music_set = nullptr; + std::string musicdriver; + std::string sounddriver; + std::string videodriver; + std::string blitter; + std::string graphics_set; + std::string sounds_set; + std::string music_set; Dimension resolution = {0, 0}; /* AfterNewGRFScan sets save_config to true after scanning completed. */ bool save_config = false; - AfterNewGRFScan *scanner = new AfterNewGRFScan(&save_config); + std::unique_ptr scanner(new AfterNewGRFScan(&save_config)); bool dedicated = false; char *debuglog_conn = nullptr; @@ -701,22 +701,18 @@ int openttd_main(int argc, char *argv[]) int i; while ((i = mgo.GetOpt()) != -1) { switch (i) { - case 'I': free(graphics_set); graphics_set = stredup(mgo.opt); break; - case 'S': free(sounds_set); sounds_set = stredup(mgo.opt); break; - case 'M': free(music_set); music_set = stredup(mgo.opt); break; - case 'm': free(musicdriver); musicdriver = stredup(mgo.opt); break; - case 's': free(sounddriver); sounddriver = stredup(mgo.opt); break; - case 'v': free(videodriver); videodriver = stredup(mgo.opt); break; - case 'b': free(blitter); blitter = stredup(mgo.opt); break; + case 'I': graphics_set = mgo.opt; break; + case 'S': sounds_set = mgo.opt; break; + case 'M': music_set = mgo.opt; break; + case 'm': musicdriver = mgo.opt; break; + case 's': sounddriver = mgo.opt; break; + case 'v': videodriver = mgo.opt; break; + case 'b': blitter = mgo.opt; break; case 'D': - free(musicdriver); - free(sounddriver); - free(videodriver); - free(blitter); - musicdriver = stredup("null"); - sounddriver = stredup("null"); - videodriver = stredup("dedicated"); - blitter = stredup("null"); + musicdriver = "null"; + sounddriver = "null"; + videodriver = "dedicated"; + blitter = "null"; dedicated = true; SetDebugString("net=6"); if (mgo.opt != nullptr) { @@ -780,7 +776,7 @@ int openttd_main(int argc, char *argv[]) DeterminePaths(argv[0]); if (StrEmpty(mgo.opt)) { ret = 1; - goto exit_noshutdown; + return ret; } char title[80]; @@ -799,7 +795,7 @@ int openttd_main(int argc, char *argv[]) GetString(buf, _load_check_data.error, lastof(buf)); fprintf(stderr, "%s\n", buf); } - goto exit_noshutdown; + return ret; } if (i == 'q') { @@ -807,8 +803,7 @@ int openttd_main(int argc, char *argv[]) } else { WriteSavegameDebugData(title); } - - goto exit_noshutdown; + return ret; } case 'G': scanner->generation_seed = strtoul(mgo.opt, nullptr, 10); break; case 'c': free(_config_file); _config_file = stredup(mgo.opt); break; @@ -816,7 +811,7 @@ int openttd_main(int argc, char *argv[]) case 'J': _quit_after_days = Clamp(atoi(mgo.opt), 0, INT_MAX); break; case 'Z': { CrashLog::VersionInfoLog(); - goto exit_noshutdown; + return ret; } case 'h': i = -2; // Force printing of help. @@ -837,8 +832,7 @@ int openttd_main(int argc, char *argv[]) BaseSounds::FindSets(); BaseMusic::FindSets(); ShowHelp(); - - goto exit_noshutdown; + return ret; } DeterminePaths(argv[0]); @@ -881,24 +875,23 @@ int openttd_main(int argc, char *argv[]) InitWindowSystem(); BaseGraphics::FindSets(); - if (graphics_set == nullptr && BaseGraphics::ini_set != nullptr) graphics_set = stredup(BaseGraphics::ini_set); + if (graphics_set.empty() && !BaseGraphics::ini_set.empty()) graphics_set = BaseGraphics::ini_set; if (!BaseGraphics::SetSet(graphics_set)) { - if (!StrEmpty(graphics_set)) { - BaseGraphics::SetSet(nullptr); + if (!graphics_set.empty()) { + BaseGraphics::SetSet({}); ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_BASE_GRAPHICS_NOT_FOUND); - msg.SetDParamStr(0, graphics_set); + msg.SetDParamStr(0, graphics_set.c_str()); ScheduleErrorMessage(msg); } } - free(graphics_set); /* Initialize game palette */ GfxInitPalettes(); DEBUG(misc, 1, "Loading blitter..."); - if (blitter == nullptr && _ini_blitter != nullptr) blitter = stredup(_ini_blitter); - _blitter_autodetected = StrEmpty(blitter); + if (blitter.empty() && !_ini_blitter.empty()) blitter = _ini_blitter; + _blitter_autodetected = blitter.empty(); /* Activate the initial blitter. * This is only some initial guess, after NewGRFs have been loaded SwitchNewGRFBlitter may switch to a different one. * - Never guess anything, if the user specified a blitter. (_blitter_autodetected) @@ -909,16 +902,14 @@ int openttd_main(int argc, char *argv[]) (_support8bpp != S8BPP_NONE && (BaseGraphics::GetUsedSet() == nullptr || BaseGraphics::GetUsedSet()->blitter == BLT_8BPP)) || BlitterFactory::SelectBlitter("32bpp-anim") == nullptr) { if (BlitterFactory::SelectBlitter(blitter) == nullptr) { - StrEmpty(blitter) ? + blitter.empty() ? usererror("Failed to autoprobe blitter") : - usererror("Failed to select requested blitter '%s'; does it exist?", blitter); + usererror("Failed to select requested blitter '%s'; does it exist?", blitter.c_str()); } } - free(blitter); - if (videodriver == nullptr && _ini_videodriver != nullptr) videodriver = stredup(_ini_videodriver); + if (videodriver.empty() && !_ini_videodriver.empty()) videodriver = _ini_videodriver; DriverFactoryBase::SelectDriver(videodriver, Driver::DT_VIDEO); - free(videodriver); InitializeSpriteSorter(); @@ -942,8 +933,7 @@ int openttd_main(int argc, char *argv[]) if (!HandleBootstrap()) { ShutdownGame(); - - goto exit_bootstrap; + return ret; } VideoDriver::GetInstance()->ClaimMousePointer(); @@ -952,38 +942,34 @@ int openttd_main(int argc, char *argv[]) InitializeScreenshotFormats(); BaseSounds::FindSets(); - if (sounds_set == nullptr && BaseSounds::ini_set != nullptr) sounds_set = stredup(BaseSounds::ini_set); + if (sounds_set.empty() && !BaseSounds::ini_set.empty()) sounds_set = BaseSounds::ini_set; if (!BaseSounds::SetSet(sounds_set)) { - if (StrEmpty(sounds_set) || !BaseSounds::SetSet(nullptr)) { + if (sounds_set.empty() || !BaseSounds::SetSet({})) { usererror("Failed to find a sounds set. Please acquire a sounds set for OpenTTD. See section 1.4 of README.md."); } else { ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_BASE_SOUNDS_NOT_FOUND); - msg.SetDParamStr(0, sounds_set); + msg.SetDParamStr(0, sounds_set.c_str()); ScheduleErrorMessage(msg); } } - free(sounds_set); BaseMusic::FindSets(); - if (music_set == nullptr && BaseMusic::ini_set != nullptr) music_set = stredup(BaseMusic::ini_set); + if (music_set.empty() && !BaseMusic::ini_set.empty()) music_set = BaseMusic::ini_set; if (!BaseMusic::SetSet(music_set)) { - if (StrEmpty(music_set) || !BaseMusic::SetSet(nullptr)) { + if (music_set.empty() || !BaseMusic::SetSet({})) { usererror("Failed to find a music set. Please acquire a music set for OpenTTD. See section 1.4 of README.md."); } else { ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_BASE_MUSIC_NOT_FOUND); - msg.SetDParamStr(0, music_set); + msg.SetDParamStr(0, music_set.c_str()); ScheduleErrorMessage(msg); } } - free(music_set); - if (sounddriver == nullptr && _ini_sounddriver != nullptr) sounddriver = stredup(_ini_sounddriver); + if (sounddriver.empty() && !_ini_sounddriver.empty()) sounddriver = _ini_sounddriver; DriverFactoryBase::SelectDriver(sounddriver, Driver::DT_SOUND); - free(sounddriver); - if (musicdriver == nullptr && _ini_musicdriver != nullptr) musicdriver = stredup(_ini_musicdriver); + if (musicdriver.empty() && !_ini_musicdriver.empty()) musicdriver = _ini_musicdriver; DriverFactoryBase::SelectDriver(musicdriver, Driver::DT_MUSIC); - free(musicdriver); /* Take our initial lock on whatever we might want to do! */ try { @@ -1003,8 +989,7 @@ int openttd_main(int argc, char *argv[]) CheckForMissingGlyphs(); /* ScanNewGRFFiles now has control over the scanner. */ - ScanNewGRFFiles(scanner); - scanner = nullptr; + ScanNewGRFFiles(scanner.release()); VideoDriver::GetInstance()->MainLoop(); @@ -1023,38 +1008,6 @@ int openttd_main(int argc, char *argv[]) /* Reset windowing system, stop drivers, free used memory, ... */ ShutdownGame(); - goto exit_normal; - -exit_noshutdown: - /* These three are normally freed before bootstrap. */ - free(graphics_set); - free(videodriver); - free(blitter); - -exit_bootstrap: - /* These are normally freed before exit, but after bootstrap. */ - free(sounds_set); - free(music_set); - free(musicdriver); - free(sounddriver); - -exit_normal: - free(BaseGraphics::ini_set); - free(BaseSounds::ini_set); - free(BaseMusic::ini_set); - - free(_ini_musicdriver); - free(_ini_sounddriver); - free(_ini_videodriver); - free(_ini_blitter); - - delete scanner; - - extern FILE *_log_fd; - if (_log_fd != nullptr) { - fclose(_log_fd); - } - return ret; } @@ -1324,9 +1277,9 @@ void SwitchToMode(SwitchMode new_mode) case SM_MENU: // Switch to game intro menu LoadIntroGame(); - if (BaseSounds::ini_set == nullptr && BaseSounds::GetUsedSet()->fallback) { + if (BaseSounds::ini_set.empty() && BaseSounds::GetUsedSet()->fallback) { ShowErrorMessage(STR_WARNING_FALLBACK_SOUNDSET, INVALID_STRING_ID, WL_CRITICAL); - BaseSounds::ini_set = stredup(BaseSounds::GetUsedSet()->name); + BaseSounds::ini_set = BaseSounds::GetUsedSet()->name; } break; diff --git a/src/road_gui.cpp b/src/road_gui.cpp index 70195712c5..a47b810b8b 100644 --- a/src/road_gui.cpp +++ b/src/road_gui.cpp @@ -1360,7 +1360,7 @@ DropDownList GetScenRoadTypeDropDownList(RoadTramTypes rtts) DropDownListIconItem *item = new DropDownListIconItem(rti->gui_sprites.build_x_road, PAL_NONE, str, rt, !HasBit(avail_roadtypes, rt)); item->SetDimension(d); item->SetParam(0, rti->strings.menu_text); - item->SetParam(1, rti->max_speed); + item->SetParam(1, rti->max_speed / 2); list.emplace_back(item); } diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index 29353e8848..0496f65d51 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -722,20 +722,20 @@ bool AfterLoadGame() if (IsSavegameVersionBefore(SLV_84)) { for (Company *c : Company::Iterate()) { c->name = CopyFromOldName(c->name_1); - if (c->name != nullptr) c->name_1 = STR_SV_UNNAMED; + if (!c->name.empty()) c->name_1 = STR_SV_UNNAMED; c->president_name = CopyFromOldName(c->president_name_1); - if (c->president_name != nullptr) c->president_name_1 = SPECSTR_PRESIDENT_NAME; + if (!c->president_name.empty()) c->president_name_1 = SPECSTR_PRESIDENT_NAME; } for (Station *st : Station::Iterate()) { st->name = CopyFromOldName(st->string_id); /* generating new name would be too much work for little effect, use the station name fallback */ - if (st->name != nullptr) st->string_id = STR_SV_STNAME_FALLBACK; + if (!st->name.empty()) st->string_id = STR_SV_STNAME_FALLBACK; } for (Town *t : Town::Iterate()) { t->name = CopyFromOldName(t->townnametype); - if (t->name != nullptr) t->townnametype = SPECSTR_TOWNNAME_START + _settings_game.game_creation.town_name; + if (!t->name.empty()) t->townnametype = SPECSTR_TOWNNAME_START + _settings_game.game_creation.town_name; } } @@ -2780,11 +2780,11 @@ bool AfterLoadGame() * highest possible number to get them numbered in the * order they have in the pool. */ for (Waypoint *wp : Waypoint::Iterate()) { - if (wp->name != nullptr) wp->town_cn = UINT16_MAX; + if (!wp->name.empty()) wp->town_cn = UINT16_MAX; } for (Waypoint* wp : Waypoint::Iterate()) { - if (wp->name != nullptr) MakeDefaultName(wp); + if (!wp->name.empty()) MakeDefaultName(wp); } } diff --git a/src/saveload/company_sl.cpp b/src/saveload/company_sl.cpp index 0b84343b20..60c3fa6c66 100644 --- a/src/saveload/company_sl.cpp +++ b/src/saveload/company_sl.cpp @@ -240,11 +240,11 @@ void AfterLoadCompanyStats() static const SaveLoad _company_desc[] = { SLE_VAR(CompanyProperties, name_2, SLE_UINT32), SLE_VAR(CompanyProperties, name_1, SLE_STRINGID), - SLE_CONDSTR(CompanyProperties, name, SLE_STR | SLF_ALLOW_CONTROL, 0, SLV_84, SL_MAX_VERSION), + SLE_CONDSSTR(CompanyProperties, name, SLE_STR | SLF_ALLOW_CONTROL, SLV_84, SL_MAX_VERSION), SLE_VAR(CompanyProperties, president_name_1, SLE_STRINGID), SLE_VAR(CompanyProperties, president_name_2, SLE_UINT32), - SLE_CONDSTR(CompanyProperties, president_name, SLE_STR | SLF_ALLOW_CONTROL, 0, SLV_84, SL_MAX_VERSION), + SLE_CONDSSTR(CompanyProperties, president_name, SLE_STR | SLF_ALLOW_CONTROL, SLV_84, SL_MAX_VERSION), SLE_VAR(CompanyProperties, face, SLE_UINT32), @@ -530,7 +530,7 @@ static void Check_PLYR() } } - if (cprops->name == nullptr && !IsInsideMM(cprops->name_1, SPECSTR_COMPANY_NAME_START, SPECSTR_COMPANY_NAME_LAST + 1) && + if (cprops->name.empty() && !IsInsideMM(cprops->name_1, SPECSTR_COMPANY_NAME_START, SPECSTR_COMPANY_NAME_LAST + 1) && cprops->name_1 != STR_GAME_SAVELOAD_NOT_AVAILABLE && cprops->name_1 != STR_SV_UNNAMED && cprops->name_1 != SPECSTR_ANDCO_NAME && cprops->name_1 != SPECSTR_PRESIDENT_NAME && cprops->name_1 != SPECSTR_SILLY_NAME) { diff --git a/src/saveload/depot_sl.cpp b/src/saveload/depot_sl.cpp index e2560422b9..eedfcfd83c 100644 --- a/src/saveload/depot_sl.cpp +++ b/src/saveload/depot_sl.cpp @@ -23,7 +23,7 @@ static const SaveLoad _depot_desc[] = { SLEG_CONDVAR(_town_index, SLE_UINT16, SL_MIN_VERSION, SLV_141), SLE_CONDREF(Depot, town, REF_TOWN, SLV_141, SL_MAX_VERSION), SLE_CONDVAR(Depot, town_cn, SLE_UINT16, SLV_141, SL_MAX_VERSION), - SLE_CONDSTR(Depot, name, SLE_STR, 0, SLV_141, SL_MAX_VERSION), + SLE_CONDSSTR(Depot, name, SLE_STR, SLV_141, SL_MAX_VERSION), SLE_CONDVAR(Depot, build_date, SLE_INT32, SLV_142, SL_MAX_VERSION), SLE_CONDNULL_X(4, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SPRINGPP, 5)), SLE_END() diff --git a/src/saveload/engine_sl.cpp b/src/saveload/engine_sl.cpp index 44ba6498ef..863aabff07 100644 --- a/src/saveload/engine_sl.cpp +++ b/src/saveload/engine_sl.cpp @@ -39,7 +39,7 @@ static const SaveLoad _engine_desc[] = { SLE_CONDVAR(Engine, company_avail, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_104), SLE_CONDVAR(Engine, company_avail, SLE_UINT16, SLV_104, SL_MAX_VERSION), SLE_CONDVAR(Engine, company_hidden, SLE_UINT16, SLV_193, SL_MAX_VERSION), - SLE_CONDSTR(Engine, name, SLE_STR, 0, SLV_84, SL_MAX_VERSION), + SLE_CONDSSTR(Engine, name, SLE_STR, SLV_84, SL_MAX_VERSION), SLE_CONDNULL(16, SLV_2, SLV_144), // old reserved space @@ -137,7 +137,7 @@ void CopyTempEngineData() e->preview_wait = se->preview_wait; e->company_avail = se->company_avail; e->company_hidden = se->company_hidden; - if (se->name != nullptr) e->name = stredup(se->name); + e->name = se->name; } ResetTempEngineData(); diff --git a/src/saveload/game_sl.cpp b/src/saveload/game_sl.cpp index 28a6c6c11a..e134843850 100644 --- a/src/saveload/game_sl.cpp +++ b/src/saveload/game_sl.cpp @@ -113,23 +113,23 @@ static void Save_GSDT() extern GameStrings *_current_data; -static const char *_game_saveload_string; +static std::string _game_saveload_string; static uint _game_saveload_strings; static const SaveLoad _game_language_header[] = { - SLEG_STR(_game_saveload_string, SLE_STR), - SLEG_VAR(_game_saveload_strings, SLE_UINT32), - SLE_END() + SLEG_SSTR(_game_saveload_string, SLE_STR), + SLEG_VAR(_game_saveload_strings, SLE_UINT32), + SLE_END() }; static const SaveLoad _game_language_string[] = { - SLEG_STR(_game_saveload_string, SLE_STR | SLF_ALLOW_CONTROL), - SLE_END() + SLEG_SSTR(_game_saveload_string, SLE_STR | SLF_ALLOW_CONTROL), + SLE_END() }; static void SaveReal_GSTR(const LanguageStrings *ls) { - _game_saveload_string = ls->language; + _game_saveload_string = ls->language.c_str(); _game_saveload_strings = (uint)ls->lines.size(); SlObject(nullptr, _game_language_header); @@ -145,13 +145,13 @@ static void Load_GSTR() _current_data = new GameStrings(); while (SlIterateArray() != -1) { - _game_saveload_string = nullptr; + _game_saveload_string.clear(); SlObject(nullptr, _game_language_header); - std::unique_ptr ls(new LanguageStrings(_game_saveload_string != nullptr ? _game_saveload_string : "")); + LanguageStrings ls(_game_saveload_string); for (uint i = 0; i < _game_saveload_strings; i++) { SlObject(nullptr, _game_language_string); - ls->lines.emplace_back(_game_saveload_string != nullptr ? _game_saveload_string : ""); + ls.lines.emplace_back(_game_saveload_string); } _current_data->raw_strings.push_back(std::move(ls)); @@ -174,7 +174,7 @@ static void Save_GSTR() for (uint i = 0; i < _current_data->raw_strings.size(); i++) { SlSetArrayIndex(i); - SlAutolength((AutolengthProc *)SaveReal_GSTR, _current_data->raw_strings[i].get()); + SlAutolength((AutolengthProc *)SaveReal_GSTR, &_current_data->raw_strings[i]); } } diff --git a/src/saveload/group_sl.cpp b/src/saveload/group_sl.cpp index 33c63ee44f..cae313ff83 100644 --- a/src/saveload/group_sl.cpp +++ b/src/saveload/group_sl.cpp @@ -17,7 +17,7 @@ static const SaveLoad _group_desc[] = { SLE_CONDVAR(Group, name, SLE_NAME, SL_MIN_VERSION, SLV_84), - SLE_CONDSTR(Group, name, SLE_STR | SLF_ALLOW_CONTROL, 0, SLV_84, SL_MAX_VERSION), + SLE_CONDSSTR(Group, name, SLE_STR | SLF_ALLOW_CONTROL, SLV_84, SL_MAX_VERSION), SLE_CONDNULL(2, SL_MIN_VERSION, SLV_164), // num_vehicle SLE_VAR(Group, owner, SLE_UINT8), SLE_VAR(Group, vehicle_type, SLE_UINT8), diff --git a/src/saveload/plans_sl.cpp b/src/saveload/plans_sl.cpp index 608962cabc..2ab51812f0 100644 --- a/src/saveload/plans_sl.cpp +++ b/src/saveload/plans_sl.cpp @@ -19,8 +19,8 @@ static const SaveLoad _plan_desc[] = { SLE_VAR(Plan, visible, SLE_BOOL), SLE_VAR(Plan, visible_by_all, SLE_BOOL), SLE_VAR(Plan, creation_date, SLE_INT32), - SLE_CONDSTDSTR_X(Plan, name, 0, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ENH_VIEWPORT_PLANS, 3)), - SLE_CONDSTDSTR_X(Plan, name, 0, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_JOKERPP, SL_JOKER_1_20)), + SLE_CONDSSSTR_X(Plan, name, 0, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ENH_VIEWPORT_PLANS, 3)), + SLE_CONDSSSTR_X(Plan, name, 0, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_JOKERPP, SL_JOKER_1_20)), SLE_END() }; diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp index 2344bbb42e..9490c531e1 100644 --- a/src/saveload/saveload.cpp +++ b/src/saveload/saveload.cpp @@ -44,6 +44,7 @@ #include "../fios.h" #include "../error.h" #include +#include #include "../tbtr_template_vehicle.h" @@ -891,7 +892,7 @@ void WriteValue(void *ptr, VarType conv, int64 val) case SLE_VAR_U32: *(uint32*)ptr = val; break; case SLE_VAR_I64: *(int64 *)ptr = val; break; case SLE_VAR_U64: *(uint64*)ptr = val; break; - case SLE_VAR_NAME: *(char**)ptr = CopyFromOldName(val); break; + case SLE_VAR_NAME: *reinterpret_cast(ptr) = CopyFromOldName(val); break; case SLE_VAR_NULL: break; default: NOT_REACHED(); } @@ -1110,8 +1111,8 @@ static void SlString(void *ptr, size_t length, VarType conv) } /** - * Save/Load a std::string. - * @param ptr the std::string being manipulated + * Save/Load a \c std::string. + * @param ptr the string being manipulated * @param conv must be SLE_FILE_STRING */ static void SlStdString(std::string &str, VarType conv) @@ -1131,11 +1132,15 @@ static void SlStdString(std::string &str, VarType conv) StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK; if ((conv & SLF_ALLOW_CONTROL) != 0) { settings = settings | SVS_ALLOW_CONTROL_CODE; + if (IsSavegameVersionBefore(SLV_169)) { + char *buf = const_cast(str.c_str()); + str.resize(str_fix_scc_encoded(buf, buf + str.size()) - buf); + } } if ((conv & SLF_ALLOW_NEWLINE) != 0) { settings = settings | SVS_ALLOW_NEWLINE; } - str_validate(str, settings); + str_validate_inplace(str, settings); break; } case SLA_PTRS: break; @@ -1692,6 +1697,8 @@ static bool IsVariableSizeRight(const SaveLoad *sld) case SLE_VAR_I64: case SLE_VAR_U64: return sld->size == sizeof(int64); + case SLE_VAR_NAME: + return sld->size == sizeof(std::string); default: return sld->size == sizeof(void *); } @@ -1704,6 +1711,7 @@ static bool IsVariableSizeRight(const SaveLoad *sld) return sld->size == sizeof(void *) || sld->size == sld->length; case SL_STDSTR: + /* These should be all pointers to std::string. */ return sld->size == sizeof(std::string); default: diff --git a/src/saveload/saveload.h b/src/saveload/saveload.h index 268f22886b..785d822229 100644 --- a/src/saveload/saveload.h +++ b/src/saveload/saveload.h @@ -620,7 +620,7 @@ typedef SaveLoad SaveLoadGlobVarList; #define SLE_CONDSTR(base, variable, type, length, from, to) SLE_CONDSTR_X(base, variable, type, length, from, to, SlXvFeatureTest()) /** - * Storage of a std::string in some savegame versions. + * Storage of a \c std::string in some savegame versions. * @param base Name of the class or struct containing the string. * @param variable Name of the variable in the class or struct referenced by \a base. * @param type Storage of the data in memory and in the savegame. @@ -628,8 +628,8 @@ typedef SaveLoad SaveLoadGlobVarList; * @param to Last savegame version that has the string. * @param extver SlXvFeatureTest to test (along with from and to) which savegames have the field */ -#define SLE_CONDSTDSTR_X(base, variable, type, from, to, extver) SLE_GENERAL_X(SL_STDSTR, base, variable, type, 0, from, to, extver) -#define SLE_CONDSTDSTR(base, variable, type, from, to) SLE_CONDSTDSTR_X(base, variable, type, from, to, SlXvFeatureTest()) +#define SLE_CONDSSSTR_X(base, variable, type, from, to, extver) SLE_GENERAL_X(SL_STDSTR, base, variable, type, 0, from, to, extver) +#define SLE_CONDSSTR(base, variable, type, from, to) SLE_GENERAL(SL_STDSTR, base, variable, type, 0, from, to) /** * Storage of a list in some savegame versions. @@ -726,12 +726,12 @@ typedef SaveLoad SaveLoadGlobVarList; #define SLE_STR(base, variable, type, length) SLE_CONDSTR(base, variable, type, length, SL_MIN_VERSION, SL_MAX_VERSION) /** - * Storage of a std::string in every savegame version. + * Storage of a \c std::string in every savegame version. * @param base Name of the class or struct containing the string. * @param variable Name of the variable in the class or struct referenced by \a base. * @param type Storage of the data in memory and in the savegame. */ -#define SLE_STDSTR(base, variable, type) SLE_CONDSTDSTR(base, variable, type, SL_MIN_VERSION, SL_MAX_VERSION) +#define SLE_SSTR(base, variable, type) SLE_CONDSSTR(base, variable, type, SL_MIN_VERSION, SL_MAX_VERSION) /** * Storage of a list in every savegame version. @@ -841,6 +841,15 @@ typedef SaveLoad SaveLoadGlobVarList; #define SLEG_CONDSTR_X(variable, type, length, from, to, extver) SLEG_GENERAL_X(SL_STR, variable, type, length, from, to, extver) #define SLEG_CONDSTR(variable, type, length, from, to) SLEG_CONDSTR_X(variable, type, length, from, to, SlXvFeatureTest()) +/** + * Storage of a global \c std::string in some savegame versions. + * @param variable Name of the global variable. + * @param type Storage of the data in memory and in the savegame. + * @param from First savegame version that has the string. + * @param to Last savegame version that has the string. + */ +#define SLEG_CONDSSTR(variable, type, from, to) SLEG_GENERAL(SL_STDSTR, variable, type, 0, from, to) + /** * Storage of a global list in some savegame versions. * @param variable Name of the global variable. @@ -902,6 +911,13 @@ typedef SaveLoad SaveLoadGlobVarList; */ #define SLEG_STR(variable, type) SLEG_CONDSTR(variable, type, sizeof(variable), SL_MIN_VERSION, SL_MAX_VERSION) +/** + * Storage of a global \c std::string in every savegame version. + * @param variable Name of the global variable. + * @param type Storage of the data in memory and in the savegame. + */ +#define SLEG_SSTR(variable, type) SLEG_CONDSSTR(variable, type, SL_MIN_VERSION, SL_MAX_VERSION) + /** * Storage of a global list in every savegame version. * @param variable Name of the global variable. diff --git a/src/saveload/saveload_internal.h b/src/saveload/saveload_internal.h index ea50abf1de..aac89c9ac2 100644 --- a/src/saveload/saveload_internal.h +++ b/src/saveload/saveload_internal.h @@ -17,7 +17,7 @@ void InitializeOldNames(); StringID RemapOldStringID(StringID s); -char *CopyFromOldName(StringID id); +std::string CopyFromOldName(StringID id); void ResetOldNames(); void ResetOldWaypoints(); diff --git a/src/saveload/signs_sl.cpp b/src/saveload/signs_sl.cpp index 7d13bd1f0d..b8b68ca1d9 100644 --- a/src/saveload/signs_sl.cpp +++ b/src/saveload/signs_sl.cpp @@ -18,7 +18,7 @@ /** Description of a sign within the savegame. */ static const SaveLoad _sign_desc[] = { SLE_CONDVAR(Sign, name, SLE_NAME, SL_MIN_VERSION, SLV_84), - SLE_CONDSTR(Sign, name, SLE_STR | SLF_ALLOW_CONTROL, 0, SLV_84, SL_MAX_VERSION), + SLE_CONDSSTR(Sign, name, SLE_STR | SLF_ALLOW_CONTROL, SLV_84, SL_MAX_VERSION), SLE_CONDVAR(Sign, x, SLE_FILE_I16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_5), SLE_CONDVAR(Sign, y, SLE_FILE_I16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_5), SLE_CONDVAR(Sign, x, SLE_INT32, SLV_5, SL_MAX_VERSION), diff --git a/src/saveload/station_sl.cpp b/src/saveload/station_sl.cpp index 85f68a898b..8bcbe6c5a5 100644 --- a/src/saveload/station_sl.cpp +++ b/src/saveload/station_sl.cpp @@ -65,8 +65,7 @@ void MoveBuoysToWaypoints() TileIndex xy = st->xy; Town *town = st->town; StringID string_id = st->string_id; - char *name = st->name; - st->name = nullptr; + std::string name = st->name; Date build_date = st->build_date; /* TTDPatch could use "buoys with rail station" for rail waypoints */ bool train = st->train_station.tile != INVALID_TILE; @@ -179,7 +178,7 @@ static const SaveLoad _old_station_desc[] = { SLE_CONDNULL(1, SL_MIN_VERSION, SLV_4), ///< alpha_order SLE_VAR(Station, string_id, SLE_STRINGID), - SLE_CONDSTR(Station, name, SLE_STR | SLF_ALLOW_CONTROL, 0, SLV_84, SL_MAX_VERSION), + SLE_CONDSSTR(Station, name, SLE_STR | SLF_ALLOW_CONTROL, SLV_84, SL_MAX_VERSION), SLE_CONDVAR(Station, indtype, SLE_UINT8, SLV_103, SL_MAX_VERSION), SLE_CONDVAR(Station, had_vehicle_of_type, SLE_FILE_U16 | SLE_VAR_U8, SL_MIN_VERSION, SLV_122), SLE_CONDVAR(Station, had_vehicle_of_type, SLE_UINT8, SLV_122, SL_MAX_VERSION), @@ -400,7 +399,7 @@ static const SaveLoad _base_station_desc[] = { SLE_VAR(BaseStation, xy, SLE_UINT32), SLE_REF(BaseStation, town, REF_TOWN), SLE_VAR(BaseStation, string_id, SLE_STRINGID), - SLE_STR(BaseStation, name, SLE_STR | SLF_ALLOW_CONTROL, 0), + SLE_SSTR(BaseStation, name, SLE_STR | SLF_ALLOW_CONTROL), SLE_CONDVAR_X(Station, delete_ctr, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SPRINGPP, 0, 3)), SLE_CONDVAR_X(Station, delete_ctr, SLE_FILE_U16 | SLE_VAR_U8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SPRINGPP, 4)), SLE_VAR(BaseStation, owner, SLE_UINT8), diff --git a/src/saveload/strings_sl.cpp b/src/saveload/strings_sl.cpp index dce8fdedb7..dad7eb1abd 100644 --- a/src/saveload/strings_sl.cpp +++ b/src/saveload/strings_sl.cpp @@ -11,6 +11,7 @@ #include "../string_func.h" #include "../strings_func.h" #include "saveload_internal.h" +#include #include "table/strings.h" @@ -56,18 +57,17 @@ char *_old_name_array = nullptr; * @param id the StringID of the custom name to clone. * @return the clones custom name. */ -char *CopyFromOldName(StringID id) +std::string CopyFromOldName(StringID id) { /* Is this name an (old) custom name? */ - if (GetStringTab(id) != TEXT_TAB_OLD_CUSTOM) return nullptr; + if (GetStringTab(id) != TEXT_TAB_OLD_CUSTOM) return std::string(); if (IsSavegameVersionBefore(SLV_37)) { - /* Allow for expansion when converted to UTF-8. */ - char tmp[LEN_OLD_STRINGS * MAX_CHAR_LENGTH]; uint offs = _savegame_type == SGT_TTO ? LEN_OLD_STRINGS_TTO * GB(id, 0, 8) : LEN_OLD_STRINGS * GB(id, 0, 9); const char *strfrom = &_old_name_array[offs]; - char *strto = tmp; + std::ostringstream tmp; + std::ostreambuf_iterator strto(tmp); for (; *strfrom != '\0'; strfrom++) { WChar c = (byte)*strfrom; @@ -84,19 +84,13 @@ char *CopyFromOldName(StringID id) default: break; } - /* Check character will fit into our buffer. */ - if (strto + Utf8CharLen(c) > lastof(tmp)) break; - - strto += Utf8Encode(strto, c); + Utf8Encode(strto, c); } - /* Terminate the new string and copy it back to the name array */ - *strto = '\0'; - - return stredup(tmp); + return tmp.str(); } else { /* Name will already be in UTF-8. */ - return stredup(&_old_name_array[LEN_OLD_STRINGS * GB(id, 0, 9)]); + return std::string(&_old_name_array[LEN_OLD_STRINGS * GB(id, 0, 9)]); } } diff --git a/src/saveload/town_sl.cpp b/src/saveload/town_sl.cpp index 1649afe271..5222f47e7c 100644 --- a/src/saveload/town_sl.cpp +++ b/src/saveload/town_sl.cpp @@ -133,7 +133,7 @@ static const SaveLoad _town_desc[] = { SLE_CONDVAR(Town, townnamegrfid, SLE_UINT32, SLV_66, SL_MAX_VERSION), SLE_VAR(Town, townnametype, SLE_UINT16), SLE_VAR(Town, townnameparts, SLE_UINT32), - SLE_CONDSTR(Town, name, SLE_STR | SLF_ALLOW_CONTROL, 0, SLV_84, SL_MAX_VERSION), + SLE_CONDSSTR(Town, name, SLE_STR | SLF_ALLOW_CONTROL, SLV_84, SL_MAX_VERSION), SLE_VAR(Town, flags, SLE_UINT8), SLE_CONDVAR(Town, statues, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_104), @@ -188,7 +188,7 @@ static const SaveLoad _town_desc[] = { SLE_CONDARR(Town, goal, SLE_UINT32, NUM_TE, SLV_165, SL_MAX_VERSION), - SLE_CONDSTR(Town, text, SLE_STR | SLF_ALLOW_CONTROL, 0, SLV_168, SL_MAX_VERSION), + SLE_CONDSSTR(Town, text, SLE_STR | SLF_ALLOW_CONTROL, SLV_168, SL_MAX_VERSION), SLE_CONDVAR(Town, time_until_rebuild, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_54), SLE_CONDVAR(Town, grow_counter, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_54), diff --git a/src/saveload/tracerestrict_sl.cpp b/src/saveload/tracerestrict_sl.cpp index ca68080c35..89d795a39d 100644 --- a/src/saveload/tracerestrict_sl.cpp +++ b/src/saveload/tracerestrict_sl.cpp @@ -125,7 +125,7 @@ static const SaveLoad _trace_restrict_slot_stub_desc[] = { static const SaveLoad _trace_restrict_slot_desc[] = { SLE_VAR(TraceRestrictSlot, max_occupancy, SLE_UINT32), - SLE_STDSTR(TraceRestrictSlot, name, SLF_ALLOW_CONTROL), + SLE_SSTR(TraceRestrictSlot, name, SLF_ALLOW_CONTROL), SLE_VAR(TraceRestrictSlot, owner, SLE_UINT8), SLE_END() }; diff --git a/src/saveload/vehicle_sl.cpp b/src/saveload/vehicle_sl.cpp index 5f28fe68e6..8df267be59 100644 --- a/src/saveload/vehicle_sl.cpp +++ b/src/saveload/vehicle_sl.cpp @@ -622,7 +622,7 @@ const SaveLoad *GetVehicleDescription(VehicleType vt) SLE_REF(Vehicle, next, REF_VEHICLE_OLD), SLE_CONDVAR(Vehicle, name, SLE_NAME, SL_MIN_VERSION, SLV_84), - SLE_CONDSTR(Vehicle, name, SLE_STR | SLF_ALLOW_CONTROL, 0, SLV_84, SL_MAX_VERSION), + SLE_CONDSSTR(Vehicle, name, SLE_STR | SLF_ALLOW_CONTROL, SLV_84, SL_MAX_VERSION), SLE_CONDVAR(Vehicle, unitnumber, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_8), SLE_CONDVAR(Vehicle, unitnumber, SLE_UINT16, SLV_8, SL_MAX_VERSION), SLE_VAR(Vehicle, owner, SLE_UINT8), diff --git a/src/saveload/waypoint_sl.cpp b/src/saveload/waypoint_sl.cpp index 5336d247b4..4117a591ee 100644 --- a/src/saveload/waypoint_sl.cpp +++ b/src/saveload/waypoint_sl.cpp @@ -29,7 +29,7 @@ struct OldWaypoint { Town *town; uint16 town_cn; StringID string_id; - char *name; + std::string name; uint8 delete_ctr; Date build_date; uint8 localidx; @@ -172,7 +172,7 @@ static const SaveLoad _old_waypoint_desc[] = { SLE_CONDVAR(OldWaypoint, town_cn, SLE_FILE_U8 | SLE_VAR_U16, SLV_12, SLV_89), SLE_CONDVAR(OldWaypoint, town_cn, SLE_UINT16, SLV_89, SL_MAX_VERSION), SLE_CONDVAR(OldWaypoint, string_id, SLE_STRINGID, SL_MIN_VERSION, SLV_84), - SLE_CONDSTR(OldWaypoint, name, SLE_STR, 0, SLV_84, SL_MAX_VERSION), + SLE_CONDSSTR(OldWaypoint, name, SLE_STR, SLV_84, SL_MAX_VERSION), SLE_VAR(OldWaypoint, delete_ctr, SLE_UINT8), SLE_CONDVAR(OldWaypoint, build_date, SLE_FILE_U16 | SLE_VAR_I32, SLV_3, SLV_31), @@ -194,7 +194,6 @@ static void Load_WAYP() while ((index = SlIterateArray()) != -1) { /*C++17: OldWaypoint *wp = &*/ _old_waypoints.emplace_back(); OldWaypoint *wp = &_old_waypoints.back(); - memset(wp, 0, sizeof(*wp)); wp->index = index; SlObject(wp, _old_waypoint_desc); diff --git a/src/screenshot.cpp b/src/screenshot.cpp index 45a1aacb64..5ed0b73a7a 100644 --- a/src/screenshot.cpp +++ b/src/screenshot.cpp @@ -321,7 +321,7 @@ static bool MakePNGImage(const char *name, ScreenshotCallback *callb, void *user char buf[8192]; char *p = buf; - p += seprintf(p, lastof(buf), "Graphics set: %s (%u)\n", BaseGraphics::GetUsedSet()->name, BaseGraphics::GetUsedSet()->version); + p += seprintf(p, lastof(buf), "Graphics set: %s (%u)\n", BaseGraphics::GetUsedSet()->name.c_str(), BaseGraphics::GetUsedSet()->version); p = strecpy(p, "NewGRFs:\n", lastof(buf)); for (const GRFConfig *c = _game_mode == GM_MENU ? nullptr : _grfconfig; c != nullptr; c = c->next) { p += seprintf(p, lastof(buf), "%08X ", BSWAP32(c->ident.grfid)); diff --git a/src/settings.cpp b/src/settings.cpp index a416d4626f..40fba9466b 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -422,6 +422,7 @@ static const void *StringToVal(const SettingDescBase *desc, const char *orig_str return desc->def; } + case SDT_STDSTRING: case SDT_STRING: return orig_str; case SDT_INTLIST: return str; default: break; @@ -527,45 +528,42 @@ static void IniLoadSettings(IniFile *ini, const SettingDesc *sd, const char *grp { IniGroup *group; IniGroup *group_def = ini->GetGroup(grpname); - IniItem *item; - const void *p; - void *ptr; - const char *s; for (; sd->save.cmd != SL_END; sd++) { const SettingDescBase *sdb = &sd->desc; const SaveLoad *sld = &sd->save; if (!SlIsObjectCurrentlyValid(sld->version_from, sld->version_to, sld->ext_feature_test)) continue; + IniItem *item; if (sdb->flags & SGF_NO_NEWGAME) { item = nullptr; } else { /* For settings.xx.yy load the settings from [xx] yy = ? */ - s = strchr(sdb->name, '.'); - if (s != nullptr) { - group = ini->GetGroup(sdb->name, s - sdb->name); - s++; + std::string s{ sdb->name }; + auto sc = s.find('.'); + if (sc != std::string::npos) { + group = ini->GetGroup(s.substr(0, sc)); + s = s.substr(sc + 1); } else { - s = sdb->name; group = group_def; } item = group->GetItem(s, false); if (item == nullptr && group != group_def) { - /* For settings.xx.yy load the settings from [settingss] yy = ? in case the previous + /* For settings.xx.yy load the settings from [settings] yy = ? in case the previous * did not exist (e.g. loading old config files with a [settings] section */ item = group_def->GetItem(s, false); } if (item == nullptr) { /* For settings.xx.zz.yy load the settings from [zz] yy = ? in case the previous * did not exist (e.g. loading old config files with a [yapf] section */ - const char *sc = strchr(s, '.'); - if (sc != nullptr) item = ini->GetGroup(s, sc - s)->GetItem(sc + 1, false); + sc = s.find('.'); + if (sc != std::string::npos) item = ini->GetGroup(s.substr(0, sc))->GetItem(s.substr(sc + 1), false); } } - p = (item == nullptr) ? sdb->def : StringToVal(sdb, item->value); - ptr = GetVariableAddress(object, sld); + const void *p = (item == nullptr) ? sdb->def : StringToVal(sdb, item->value.has_value() ? item->value->c_str() : nullptr); + void *ptr = GetVariableAddress(object, sld); switch (sdb->cmd) { case SDT_BOOLX: // All four are various types of (integer) numbers @@ -594,6 +592,22 @@ static void IniLoadSettings(IniFile *ini, const SettingDesc *sd, const char *grp } break; + case SDT_STDSTRING: + switch (GetVarMemType(sld->conv)) { + case SLE_VAR_STR: + case SLE_VAR_STRQ: + if (p != nullptr) { + reinterpret_cast(ptr)->assign((const char *)p); + } else { + reinterpret_cast(ptr)->clear(); + } + break; + + default: NOT_REACHED(); + } + + break; + case SDT_INTLIST: { if (!LoadIntList((const char*)p, ptr, sld->length, GetVarMemType(sld->conv))) { ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_ARRAY); @@ -629,7 +643,6 @@ static void IniSaveSettings(IniFile *ini, const SettingDesc *sd, const char *grp IniGroup *group_def = nullptr, *group; IniItem *item; char buf[512]; - const char *s; void *ptr; for (; sd->save.cmd != SL_END; sd++) { @@ -643,22 +656,22 @@ static void IniSaveSettings(IniFile *ini, const SettingDesc *sd, const char *grp if (sdb->flags & SGF_NO_NEWGAME) continue; /* XXX - wtf is this?? (group override?) */ - s = strchr(sdb->name, '.'); - if (s != nullptr) { - group = ini->GetGroup(sdb->name, s - sdb->name); - s++; + std::string s{ sdb->name }; + auto sc = s.find('.'); + if (sc != std::string::npos) { + group = ini->GetGroup(s.substr(0, sc)); + s = s.substr(sc + 1); } else { if (group_def == nullptr) group_def = ini->GetGroup(grpname); - s = sdb->name; group = group_def; } item = group->GetItem(s, true); ptr = GetVariableAddress(object, sld); - if (item->value != nullptr) { + if (item->value.has_value()) { /* check if the value is the same as the old value */ - const void *p = StringToVal(sdb, item->value); + const void *p = StringToVal(sdb, item->value->c_str()); /* The main type of a variable/setting is in bytes 8-15 * The subtype (what kind of numbers do we have there) is in 0-7 */ @@ -732,6 +745,22 @@ static void IniSaveSettings(IniFile *ini, const SettingDesc *sd, const char *grp } break; + case SDT_STDSTRING: + switch (GetVarMemType(sld->conv)) { + case SLE_VAR_STR: strecpy(buf, reinterpret_cast(ptr)->c_str(), lastof(buf)); break; + + case SLE_VAR_STRQ: + if (reinterpret_cast(ptr)->empty()) { + buf[0] = '\0'; + } else { + seprintf(buf, lastof(buf), "\"%s\"", reinterpret_cast(ptr)->c_str()); + } + break; + + default: NOT_REACHED(); + } + break; + case SDT_INTLIST: MakeIntList(buf, lastof(buf), ptr, sld->length, sld->conv); break; @@ -740,8 +769,7 @@ static void IniSaveSettings(IniFile *ini, const SettingDesc *sd, const char *grp } /* The value is different, that means we have to write it to the ini */ - free(item->value); - item->value = stredup(buf); + item->value.emplace(buf); } } @@ -763,7 +791,7 @@ static void IniLoadSettingList(IniFile *ini, const char *grpname, StringList &li list.clear(); for (const IniItem *item = group->item; item != nullptr; item = item->next) { - if (item->name != nullptr) list.emplace_back(item->name); + if (!item->name.empty()) list.push_back(item->name); } } @@ -1610,14 +1638,14 @@ static void AILoadConfig(IniFile *ini, const char *grpname) for (item = group->item; c < MAX_COMPANIES && item != nullptr; c++, item = item->next) { AIConfig *config = AIConfig::GetConfig(c, AIConfig::SSS_FORCE_NEWGAME); - config->Change(item->name); + config->Change(item->name.c_str()); if (!config->HasScript()) { - if (strcmp(item->name, "none") != 0) { - DEBUG(script, 0, "The AI by the name '%s' was no longer found, and removed from the list.", item->name); + if (item->name != "none") { + DEBUG(script, 0, "The AI by the name '%s' was no longer found, and removed from the list.", item->name.c_str()); continue; } } - if (item->value != nullptr) config->StringToSettings(item->value); + if (item->value.has_value()) config->StringToSettings(item->value->c_str()); } } @@ -1637,14 +1665,14 @@ static void GameLoadConfig(IniFile *ini, const char *grpname) GameConfig *config = GameConfig::GetConfig(AIConfig::SSS_FORCE_NEWGAME); - config->Change(item->name); + config->Change(item->name.c_str()); if (!config->HasScript()) { - if (strcmp(item->name, "none") != 0) { - DEBUG(script, 0, "The GameScript by the name '%s' was no longer found, and removed from the list.", item->name); + if (item->name != "none") { + DEBUG(script, 0, "The GameScript by the name '%s' was no longer found, and removed from the list.", item->name.c_str()); return; } } - if (item->value != nullptr) config->StringToSettings(item->value); + if (item->value.has_value()) config->StringToSettings(item->value->c_str()); } /** @@ -1668,7 +1696,7 @@ static int DecodeHexNibble(char c) * @param dest_size Number of bytes in \a dest. * @return Whether reading was successful. */ -static bool DecodeHexText(char *pos, uint8 *dest, size_t dest_size) +static bool DecodeHexText(const char *pos, uint8 *dest, size_t dest_size) { while (dest_size > 0) { int hi = DecodeHexNibble(pos[0]); @@ -1700,7 +1728,7 @@ static GRFConfig *GRFLoadConfig(IniFile *ini, const char *grpname, bool is_stati GRFConfig *c = nullptr; uint8 grfid_buf[4], md5sum[16]; - char *filename = item->name; + const char *filename = item->name.c_str(); bool has_grfid = false; bool has_md5sum = false; @@ -1724,8 +1752,8 @@ static GRFConfig *GRFLoadConfig(IniFile *ini, const char *grpname, bool is_stati if (c == nullptr) c = new GRFConfig(filename); /* Parse parameters */ - if (!StrEmpty(item->value)) { - int count = ParseIntList(item->value, c->param, lengthof(c->param)); + if (item->value.has_value() && !item->value->empty()) { + int count = ParseIntList(item->value->c_str(), c->param, lengthof(c->param)); if (count < 0) { SetDParamStr(0, filename); ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_ARRAY, WL_CRITICAL); @@ -1748,7 +1776,7 @@ static GRFConfig *GRFLoadConfig(IniFile *ini, const char *grpname, bool is_stati SetDParam(1, STR_CONFIG_ERROR_INVALID_GRF_UNKNOWN); } - SetDParamStr(0, StrEmpty(filename) ? item->name : filename); + SetDParamStr(0, StrEmpty(filename) ? item->name.c_str() : filename); ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_GRF, WL_CRITICAL); delete c; continue; @@ -1959,8 +1987,8 @@ StringList GetGRFPresetList() std::unique_ptr ini(IniLoadConfig()); for (IniGroup *group = ini->group; group != nullptr; group = group->next) { - if (strncmp(group->name, "preset-", 7) == 0) { - list.emplace_back(group->name + 7); + if (group->name.compare(0, 7, "preset-") == 0) { + list.push_back(group->name.substr(7)); } } diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index a8976c3715..31695ef200 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -153,7 +153,7 @@ struct BaseSetTextfileWindow : public TextfileWindow { { if (widget == WID_TF_CAPTION) { SetDParam(0, content_type); - SetDParamStr(1, this->baseset->name); + SetDParamStr(1, this->baseset->name.c_str()); } } }; @@ -336,10 +336,10 @@ struct GameOptionsWindow : Window { case WID_GO_RESOLUTION_DROPDOWN: SetDParam(0, GetCurRes() == _resolutions.size() ? STR_GAME_OPTIONS_RESOLUTION_OTHER : SPECSTR_RESOLUTION_START + GetCurRes()); break; case WID_GO_GUI_ZOOM_DROPDOWN: SetDParam(0, _gui_zoom_dropdown[ZOOM_LVL_OUT_4X - _gui_zoom]); break; case WID_GO_FONT_ZOOM_DROPDOWN: SetDParam(0, _font_zoom_dropdown[ZOOM_LVL_OUT_4X - _font_zoom]); break; - case WID_GO_BASE_GRF_DROPDOWN: SetDParamStr(0, BaseGraphics::GetUsedSet()->name); break; + case WID_GO_BASE_GRF_DROPDOWN: SetDParamStr(0, BaseGraphics::GetUsedSet()->name.c_str()); break; case WID_GO_BASE_GRF_STATUS: SetDParam(0, BaseGraphics::GetUsedSet()->GetNumInvalid()); break; - case WID_GO_BASE_SFX_DROPDOWN: SetDParamStr(0, BaseSounds::GetUsedSet()->name); break; - case WID_GO_BASE_MUSIC_DROPDOWN: SetDParamStr(0, BaseMusic::GetUsedSet()->name); break; + case WID_GO_BASE_SFX_DROPDOWN: SetDParamStr(0, BaseSounds::GetUsedSet()->name.c_str()); break; + case WID_GO_BASE_MUSIC_DROPDOWN: SetDParamStr(0, BaseMusic::GetUsedSet()->name.c_str()); break; case WID_GO_BASE_MUSIC_STATUS: SetDParam(0, BaseMusic::GetUsedSet()->GetNumInvalid()); break; } } @@ -482,10 +482,9 @@ struct GameOptionsWindow : Window { void SetMediaSet(int index) { if (_game_mode == GM_MENU) { - const char *name = T::GetSet(index)->name; + auto name = T::GetSet(index)->name; - free(T::ini_set); - T::ini_set = stredup(name); + T::ini_set = name; T::SetSet(name); this->reload = true; diff --git a/src/settings_internal.h b/src/settings_internal.h index 4a89a424df..d28e633e26 100644 --- a/src/settings_internal.h +++ b/src/settings_internal.h @@ -27,8 +27,9 @@ enum SettingDescType : byte { SDT_MANYOFMANY = 3, ///< bitmasked number where MULTIPLE bits may be set SDT_INTLIST = 4, ///< list of integers separated by a comma ',' SDT_STRING = 5, ///< string with a pre-allocated buffer + SDT_STDSTRING = 6, ///< \c std::string SDT_END, - /* 10 more possible primitives */ + /* 9 more possible primitives */ }; diff --git a/src/settingsgen/settingsgen.cpp b/src/settingsgen/settingsgen.cpp index 9f272dabbe..764f370bde 100644 --- a/src/settingsgen/settingsgen.cpp +++ b/src/settingsgen/settingsgen.cpp @@ -214,11 +214,11 @@ static IniLoadFile *LoadIniFile(const char *filename) */ static void DumpGroup(IniLoadFile *ifile, const char * const group_name) { - IniGroup *grp = ifile->GetGroup(group_name, 0, false); + IniGroup *grp = ifile->GetGroup(group_name, false); if (grp != nullptr && grp->type == IGT_SEQUENCE) { for (IniItem *item = grp->item; item != nullptr; item = item->next) { - if (item->name) { - _stored_output.Add(item->name); + if (!item->name.empty()) { + _stored_output.Add(item->name.c_str()); _stored_output.Add("\n", 1); } } @@ -236,8 +236,8 @@ static const char *FindItemValue(const char *name, IniGroup *grp, IniGroup *defa { IniItem *item = grp->GetItem(name, false); if (item == nullptr && defaults != nullptr) item = defaults->GetItem(name, false); - if (item == nullptr || item->value == nullptr) return nullptr; - return item->value; + if (item == nullptr || !item->value.has_value()) return nullptr; + return item->value->c_str(); } /** @@ -249,19 +249,19 @@ static void DumpSections(IniLoadFile *ifile) static const int MAX_VAR_LENGTH = 64; static const char * const special_group_names[] = {PREAMBLE_GROUP_NAME, POSTAMBLE_GROUP_NAME, DEFAULTS_GROUP_NAME, TEMPLATES_GROUP_NAME, nullptr}; - IniGroup *default_grp = ifile->GetGroup(DEFAULTS_GROUP_NAME, 0, false); - IniGroup *templates_grp = ifile->GetGroup(TEMPLATES_GROUP_NAME, 0, false); + IniGroup *default_grp = ifile->GetGroup(DEFAULTS_GROUP_NAME, false); + IniGroup *templates_grp = ifile->GetGroup(TEMPLATES_GROUP_NAME, false); if (templates_grp == nullptr) return; /* Output every group, using its name as template name. */ for (IniGroup *grp = ifile->group; grp != nullptr; grp = grp->next) { const char * const *sgn; - for (sgn = special_group_names; *sgn != nullptr; sgn++) if (strcmp(grp->name, *sgn) == 0) break; + for (sgn = special_group_names; *sgn != nullptr; sgn++) if (grp->name == *sgn) break; if (*sgn != nullptr) continue; IniItem *template_item = templates_grp->GetItem(grp->name, false); // Find template value. - if (template_item == nullptr || template_item->value == nullptr) { - fprintf(stderr, "settingsgen: Warning: Cannot find template %s\n", grp->name); + if (template_item == nullptr || !template_item->value.has_value()) { + fprintf(stderr, "settingsgen: Warning: Cannot find template %s\n", grp->name.c_str()); continue; } @@ -281,7 +281,7 @@ static void DumpSections(IniLoadFile *ifile) } /* Output text of the template, except template variables of the form '$[_a-z0-9]+' which get replaced by their value. */ - const char *txt = template_item->value; + const char *txt = template_item->value->c_str(); while (*txt != '\0') { if (*txt != '$') { _stored_output.Add(txt, 1); diff --git a/src/signs.cpp b/src/signs.cpp index a1cb05c77c..576160f351 100644 --- a/src/signs.cpp +++ b/src/signs.cpp @@ -34,8 +34,6 @@ Sign::Sign(Owner owner) /** Destroy the sign */ Sign::~Sign() { - free(this->name); - if (CleaningPool()) return; DeleteRenameSignWindow(this->index); diff --git a/src/signs_base.h b/src/signs_base.h index 3f77995dbd..fe9a22554f 100644 --- a/src/signs_base.h +++ b/src/signs_base.h @@ -15,12 +15,13 @@ #include "core/pool_type.hpp" #include "company_type.h" #include "company_func.h" +#include typedef Pool SignPool; extern SignPool _sign_pool; struct Sign : SignPool::PoolItem<&_sign_pool> { - char *name; + std::string name; TrackedViewportSign sign; int32 x; int32 y; diff --git a/src/signs_cmd.cpp b/src/signs_cmd.cpp index 26725359f6..a70fcbe6a1 100644 --- a/src/signs_cmd.cpp +++ b/src/signs_cmd.cpp @@ -86,10 +86,8 @@ CommandCost CmdRenameSign(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 if (Utf8StringLength(text) >= MAX_LENGTH_SIGN_NAME_CHARS) return CMD_ERROR; if (flags & DC_EXEC) { - /* Delete the old name */ - free(si->name); /* Assign the new one */ - si->name = stredup(text); + si->name = text; if (_game_mode != GM_EDITOR) si->owner = _current_company; si->UpdateVirtCoord(); diff --git a/src/signs_gui.cpp b/src/signs_gui.cpp index ea3de70085..0bb1a0909b 100644 --- a/src/signs_gui.cpp +++ b/src/signs_gui.cpp @@ -75,11 +75,8 @@ struct SignList { * a lot of them. Therefore a worthwhile performance gain can be made by * directly comparing Sign::name instead of going through the string * system for each comparison. */ - const char *a_name = a->name; - const char *b_name = b->name; - - if (a_name == nullptr) a_name = SignList::default_name; - if (b_name == nullptr) b_name = SignList::default_name; + const char *a_name = a->name.empty() ? SignList::default_name : a->name.c_str(); + const char *b_name = b->name.empty() ? SignList::default_name : b->name.c_str(); int r = strnatcmp(a_name, b_name); // Sort by name (natural sorting). @@ -95,9 +92,7 @@ struct SignList { static bool CDECL SignNameFilter(const Sign * const *a, StringFilter &filter) { /* Same performance benefit as above for sorting. */ - const char *a_name = (*a)->name; - - if (a_name == nullptr) a_name = SignList::default_name; + const char *a_name = (*a)->name.empty() ? SignList::default_name : (*a)->name.c_str(); filter.ResetState(); filter.AddLine(a_name); @@ -439,7 +434,7 @@ struct SignWindow : Window, SignList { void UpdateSignEditWindow(const Sign *si) { /* Display an empty string when the sign hasn't been edited yet */ - if (si->name != nullptr) { + if (!si->name.empty()) { SetDParam(0, si->index); this->name_editbox.text.Assign(STR_SIGN_NAME); } else { diff --git a/src/sound/allegro_s.cpp b/src/sound/allegro_s.cpp index f7fa5df08b..09198100bf 100644 --- a/src/sound/allegro_s.cpp +++ b/src/sound/allegro_s.cpp @@ -50,7 +50,7 @@ void SoundDriver_Allegro::MainLoop() */ extern int _allegro_instance_count; -const char *SoundDriver_Allegro::Start(const char * const *parm) +const char *SoundDriver_Allegro::Start(const StringList &parm) { if (_allegro_instance_count == 0 && install_allegro(SYSTEM_AUTODETECT, &errno, nullptr)) { DEBUG(driver, 0, "allegro: install_allegro failed '%s'", allegro_error); diff --git a/src/sound/allegro_s.h b/src/sound/allegro_s.h index 307d10fca4..6d40c58760 100644 --- a/src/sound/allegro_s.h +++ b/src/sound/allegro_s.h @@ -15,7 +15,7 @@ /** Implementation of the allegro sound driver. */ class SoundDriver_Allegro : public SoundDriver { public: - const char *Start(const char * const *param); + const char *Start(const StringList ¶m); void Stop(); diff --git a/src/sound/cocoa_s.cpp b/src/sound/cocoa_s.cpp index cb1bc59e80..f5003a23c3 100644 --- a/src/sound/cocoa_s.cpp +++ b/src/sound/cocoa_s.cpp @@ -44,7 +44,7 @@ static OSStatus audioCallback(void *inRefCon, AudioUnitRenderActionFlags *inActi } -const char *SoundDriver_Cocoa::Start(const char * const *parm) +const char *SoundDriver_Cocoa::Start(const StringList &parm) { struct AURenderCallbackStruct callback; AudioStreamBasicDescription requestedDesc; diff --git a/src/sound/cocoa_s.h b/src/sound/cocoa_s.h index 43646504d7..dca5421915 100644 --- a/src/sound/cocoa_s.h +++ b/src/sound/cocoa_s.h @@ -14,7 +14,7 @@ class SoundDriver_Cocoa : public SoundDriver { public: - const char *Start(const char * const *param) override; + const char *Start(const StringList ¶m) override; void Stop() override; const char *GetName() const override { return "cocoa"; } diff --git a/src/sound/null_s.h b/src/sound/null_s.h index 5b883dde1e..c01eae32a6 100644 --- a/src/sound/null_s.h +++ b/src/sound/null_s.h @@ -15,7 +15,7 @@ /** Implementation of the null sound driver. */ class SoundDriver_Null : public SoundDriver { public: - const char *Start(const char * const *param) override { return nullptr; } + const char *Start(const StringList ¶m) override { return nullptr; } void Stop() override { } const char *GetName() const override { return "null"; } diff --git a/src/sound/sdl2_s.cpp b/src/sound/sdl2_s.cpp index 0b4e6c086d..9d1e47fabb 100644 --- a/src/sound/sdl2_s.cpp +++ b/src/sound/sdl2_s.cpp @@ -31,7 +31,7 @@ static void CDECL fill_sound_buffer(void *userdata, Uint8 *stream, int len) MxMixSamples(stream, len / 4); } -const char *SoundDriver_SDL::Start(const char * const *parm) +const char *SoundDriver_SDL::Start(const StringList &parm) { SDL_AudioSpec spec; SDL_AudioSpec spec_actual; diff --git a/src/sound/sdl_s.cpp b/src/sound/sdl_s.cpp index aac786dab5..737192a7ed 100644 --- a/src/sound/sdl_s.cpp +++ b/src/sound/sdl_s.cpp @@ -31,7 +31,7 @@ static void CDECL fill_sound_buffer(void *userdata, Uint8 *stream, int len) MxMixSamples(stream, len / 4); } -const char *SoundDriver_SDL::Start(const char * const *parm) +const char *SoundDriver_SDL::Start(const StringList &parm) { SDL_AudioSpec spec; diff --git a/src/sound/sdl_s.h b/src/sound/sdl_s.h index 4f746107c7..2b3be4d14c 100644 --- a/src/sound/sdl_s.h +++ b/src/sound/sdl_s.h @@ -15,7 +15,7 @@ /** Implementation of the SDL sound driver. */ class SoundDriver_SDL : public SoundDriver { public: - const char *Start(const char * const *param) override; + const char *Start(const StringList ¶m) override; void Stop() override; const char *GetName() const override { return "sdl"; } diff --git a/src/sound/sound_driver.hpp b/src/sound/sound_driver.hpp index f1a0519f83..6de66d74e9 100644 --- a/src/sound/sound_driver.hpp +++ b/src/sound/sound_driver.hpp @@ -26,6 +26,6 @@ public: } }; -extern char *_ini_sounddriver; +extern std::string _ini_sounddriver; #endif /* SOUND_SOUND_DRIVER_HPP */ diff --git a/src/sound/win32_s.cpp b/src/sound/win32_s.cpp index f45a619b53..4551778bd6 100644 --- a/src/sound/win32_s.cpp +++ b/src/sound/win32_s.cpp @@ -58,7 +58,7 @@ static DWORD WINAPI SoundThread(LPVOID arg) return 0; } -const char *SoundDriver_Win32::Start(const char * const *parm) +const char *SoundDriver_Win32::Start(const StringList &parm) { WAVEFORMATEX wfex; wfex.wFormatTag = WAVE_FORMAT_PCM; diff --git a/src/sound/win32_s.h b/src/sound/win32_s.h index be48a055c5..6f8f9791db 100644 --- a/src/sound/win32_s.h +++ b/src/sound/win32_s.h @@ -15,7 +15,7 @@ /** Implementation of the sound driver for Windows. */ class SoundDriver_Win32 : public SoundDriver { public: - const char *Start(const char * const *param) override; + const char *Start(const StringList ¶m) override; void Stop() override; const char *GetName() const override { return "win32"; } diff --git a/src/sound/xaudio2_s.cpp b/src/sound/xaudio2_s.cpp index 8b9afbd1b1..5aa0580407 100644 --- a/src/sound/xaudio2_s.cpp +++ b/src/sound/xaudio2_s.cpp @@ -126,7 +126,7 @@ static StreamingVoiceContext* _voice_context = nullptr; * @return An error message if unsuccessful, or nullptr otherwise. * */ -const char *SoundDriver_XAudio2::Start(const char * const *parm) +const char *SoundDriver_XAudio2::Start(const StringList &parm) { HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); diff --git a/src/sound/xaudio2_s.h b/src/sound/xaudio2_s.h index 70b4d80cc9..9fcd26fd0a 100644 --- a/src/sound/xaudio2_s.h +++ b/src/sound/xaudio2_s.h @@ -15,7 +15,7 @@ /** Implementation of the XAudio2 sound driver. */ class SoundDriver_XAudio2 : public SoundDriver { public: - const char *Start(const char * const *param) override; + const char *Start(const StringList ¶m) override; void Stop() override; const char *GetName() const override { return "xaudio2"; } diff --git a/src/station.cpp b/src/station.cpp index 14cb18519d..abf3ed18dd 100644 --- a/src/station.cpp +++ b/src/station.cpp @@ -53,7 +53,6 @@ void RebuildStationKdtree() BaseStation::~BaseStation() { - free(this->name); free(this->speclist); if (CleaningPool()) return; diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index ce1f76b41d..b2c9dc65f4 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -4139,7 +4139,7 @@ static uint UpdateStationWaiting(Station *st, CargoID type, uint amount, SourceT static bool IsUniqueStationName(const char *name) { for (const Station *st : Station::Iterate()) { - if (st->name != nullptr && strcmp(st->name, name) == 0) return false; + if (!st->name.empty() && st->name == name) return false; } return true; @@ -4171,8 +4171,11 @@ CommandCost CmdRenameStation(TileIndex tile, DoCommandFlag flags, uint32 p1, uin if (flags & DC_EXEC) { st->cached_name.clear(); - free(st->name); - st->name = reset ? nullptr : stredup(text); + if (reset) { + st->name.clear(); + } else { + st->name = text; + } st->UpdateVirtCoord(); InvalidateWindowData(WC_STATION_LIST, st->owner, 1); diff --git a/src/string.cpp b/src/string.cpp index 66ffc9e2cb..33b36f9390 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -18,6 +18,7 @@ #include #include /* required for tolower() */ +#include #ifdef _MSC_VER #include // required by vsnprintf implementation for MSVC @@ -192,8 +193,9 @@ std::string CDECL stdstr_fmt(const char *str, ...) * it's new, static value. * @param str the string to scan * @param last the last valid character of str + * @return Pointer to new null terminator. */ -void str_fix_scc_encoded(char *str, const char *last) +const char *str_fix_scc_encoded(char *str, const char *last) { while (str <= last && *str != '\0') { size_t len = Utf8EncodedCharLen(*str); @@ -209,14 +211,15 @@ void str_fix_scc_encoded(char *str, const char *last) str += Utf8Encode(str, c); } *str = '\0'; + return str; } -char *str_validate_intl(char *str, const char *last, StringValidationSettings settings) +template +static void str_validate(T &dst, const char *str, const char *last, StringValidationSettings settings) { /* Assume the ABSOLUTE WORST to be in str as it comes from the outside. */ - char *dst = str; while (str <= last && *str != '\0') { size_t len = Utf8EncodedCharLen(*str); /* If the character is unknown, i.e. encoded length is 0 @@ -240,7 +243,7 @@ char *str_validate_intl(char *str, const char *last, StringValidationSettings se do { *dst++ = *str++; } while (--len != 0); - } else if ((settings & SVS_ALLOW_NEWLINE) != 0 && c == '\n') { + } else if ((settings & SVS_ALLOW_NEWLINE) != 0 && c == '\n') { *dst++ = *str++; } else { if ((settings & SVS_ALLOW_NEWLINE) != 0 && c == '\r' && str[1] == '\n') { @@ -252,10 +255,42 @@ char *str_validate_intl(char *str, const char *last, StringValidationSettings se if ((settings & SVS_REPLACE_WITH_QUESTION_MARK) != 0) *dst++ = '?'; } } +} +/** + * Scans the string for valid characters and if it finds invalid ones, + * replaces them with a question mark '?' (if not ignored) + * @param str the string to validate + * @param last the last valid character of str + * @param settings the settings for the string validation. + * @return pointer to terminating 0. + */ +char *str_validate(char *str, const char *last, StringValidationSettings settings) +{ + char *dst = str; + str_validate(dst, str, last, settings); + *dst = '\0'; return dst; } +/** + * Scans the string for valid characters and if it finds invalid ones, + * replaces them with a question mark '?' (if not ignored) + * @param str the string to validate + * @param settings the settings for the string validation. + */ +std::string str_validate(const std::string &str, StringValidationSettings settings) +{ + auto buf = str.data(); + auto last = buf + str.size(); + + std::ostringstream dst; + std::ostreambuf_iterator dst_iter(dst); + str_validate(dst_iter, buf, last, settings); + + return dst.str(); +} + /** * Scans the string for valid characters and if it finds invalid ones, * replaces them with a question mark '?'. @@ -556,11 +591,13 @@ size_t Utf8Decode(WChar *c, const char *s) /** * Encode a unicode character and place it in the buffer. + * @tparam T Type of the buffer. * @param buf Buffer to place character. * @param c Unicode character to encode. * @return Number of characters in the encoded sequence. */ -size_t Utf8Encode(char *buf, WChar c) +template +inline size_t Utf8Encode(T buf, WChar c) { if (c < 0x80) { *buf = c; @@ -587,6 +624,16 @@ size_t Utf8Encode(char *buf, WChar c) return 1; } +size_t Utf8Encode(char *buf, WChar c) +{ + return Utf8Encode(buf, c); +} + +size_t Utf8Encode(std::ostreambuf_iterator &buf, WChar c) +{ + return Utf8Encode &>(buf, c); +} + /** * Properly terminate an UTF8 string to some maximum length * @param s string to check if it needs additional trimming diff --git a/src/string_func.h b/src/string_func.h index d7db5131c6..a3177871fa 100644 --- a/src/string_func.h +++ b/src/string_func.h @@ -25,6 +25,7 @@ #define STRING_FUNC_H #include +#include #include "core/bitmath_func.hpp" #include "string_type.h" @@ -41,23 +42,11 @@ char *str_vfmt(const char *str, va_list ap); std::string CDECL stdstr_fmt(const char *str, ...) WARN_FORMAT(1, 2); std::string stdstr_vfmt(const char *str, va_list va); -char *str_validate_intl(char *str, const char *last, StringValidationSettings settings); - -/** - * Scans the string for valid characters and if it finds invalid ones, - * replaces them with a question mark '?' (if not ignored) - * @param str the string to validate - * @param last the last valid character of str - * @param settings the settings for the string validation. - */ -static inline void str_validate(char *str, const char *last, StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK) -{ - *str_validate_intl(str, last, settings) = '\0'; -} - +char *str_validate(char *str, const char *last, StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK); +std::string str_validate(const std::string &str, StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK); void ValidateString(const char *str); -void str_fix_scc_encoded(char *str, const char *last); +const char *str_fix_scc_encoded(char *str, const char *last); void str_strip_colours(char *str); char *str_replace_wchar(char *str, const char *last, WChar find, WChar replace); bool strtolower(char *str); @@ -96,6 +85,7 @@ bool IsValidChar(WChar key, CharSetFilter afilter); size_t Utf8Decode(WChar *c, const char *s); size_t Utf8Encode(char *buf, WChar c); +size_t Utf8Encode(std::ostreambuf_iterator &buf, WChar c); size_t Utf8TrimString(char *s, size_t maxlen); @@ -106,6 +96,14 @@ static inline WChar Utf8Consume(const char **s) return c; } +template +static inline WChar Utf8Consume(Titr &s) +{ + WChar c; + s += Utf8Decode(&c, &*s); + return c; +} + /** * Return the length of a UTF-8 encoded character. * @param c Unicode character. diff --git a/src/string_func_extra.h b/src/string_func_extra.h index 82ed1bbc2d..71aeb5680b 100644 --- a/src/string_func_extra.h +++ b/src/string_func_extra.h @@ -11,11 +11,11 @@ #include "string_func.h" #include -static inline void str_validate(std::string &str, StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK) +static inline void str_validate_inplace(std::string &str, StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK) { if (str.empty()) return; char *buf = const_cast(str.c_str()); - str.resize(str_validate_intl(buf, buf + str.size(), settings) - buf); + str.resize(str_validate(buf, buf + str.size(), settings) - buf); } template diff --git a/src/string_type.h b/src/string_type.h index b00acaf8ad..cca9af6e4a 100644 --- a/src/string_type.h +++ b/src/string_type.h @@ -33,7 +33,7 @@ enum CharSetFilter { }; /** Type for wide characters, i.e. non-UTF8 encoded unicode characters. */ -typedef uint32 WChar; +typedef char32_t WChar; /* The following are directional formatting codes used to get the LTR and RTL strings right: * http://www.unicode.org/unicode/reports/tr9/#Directional_Formatting_Codes */ diff --git a/src/strings.cpp b/src/strings.cpp index 1ff3edeb43..1636097486 100644 --- a/src/strings.cpp +++ b/src/strings.cpp @@ -1547,8 +1547,8 @@ static char *FormatString(char *buff, const char *str_arg, StringParameters *arg const Company *c = Company::GetIfValid(args->GetInt32()); if (c == nullptr) break; - if (c->name != nullptr) { - int64 args_array[] = {(int64)(size_t)c->name}; + if (!c->name.empty()) { + int64 args_array[] = {(int64)(size_t)c->name.c_str()}; StringParameters tmp_params(args_array); buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last); } else { @@ -1582,8 +1582,8 @@ static char *FormatString(char *buff, const char *str_arg, StringParameters *arg } const Depot *d = Depot::Get(args->GetInt32()); - if (d->name != nullptr) { - int64 args_array[] = {(int64)(size_t)d->name}; + if (!d->name.empty()) { + int64 args_array[] = {(int64)(size_t)d->name.c_str()}; StringParameters tmp_params(args_array); buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last); } else { @@ -1598,8 +1598,8 @@ static char *FormatString(char *buff, const char *str_arg, StringParameters *arg const Engine *e = Engine::GetIfValid(args->GetInt32(SCC_ENGINE_NAME)); if (e == nullptr) break; - if (e->name != nullptr && e->IsEnabled()) { - int64 args_array[] = {(int64)(size_t)e->name}; + if (!e->name.empty() && e->IsEnabled()) { + int64 args_array[] = {(int64)(size_t)e->name.c_str()}; StringParameters tmp_params(args_array); buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last); } else { @@ -1613,8 +1613,8 @@ static char *FormatString(char *buff, const char *str_arg, StringParameters *arg const Group *g = Group::GetIfValid(args->GetInt32()); if (g == nullptr) break; - if (g->name != nullptr) { - int64 args_array[] = {(int64)(size_t)g->name}; + if (!g->name.empty()) { + int64 args_array[] = {(int64)(size_t)g->name.c_str()}; StringParameters tmp_params(args_array); buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last); } else { @@ -1650,8 +1650,8 @@ static char *FormatString(char *buff, const char *str_arg, StringParameters *arg const Company *c = Company::GetIfValid(args->GetInt32(SCC_PRESIDENT_NAME)); if (c == nullptr) break; - if (c->president_name != nullptr) { - int64 args_array[] = {(int64)(size_t)c->president_name}; + if (!c->president_name.empty()) { + int64 args_array[] = {(int64)(size_t)c->president_name.c_str()}; StringParameters tmp_params(args_array); buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last); } else { @@ -1675,8 +1675,8 @@ static char *FormatString(char *buff, const char *str_arg, StringParameters *arg break; } - if (st->name != nullptr) { - int64 args_array[] = {(int64)(size_t)st->name}; + if (!st->name.empty()) { + int64 args_array[] = {(int64)(size_t)st->name.c_str()}; StringParameters tmp_params(args_array); buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last); } else { @@ -1705,8 +1705,8 @@ static char *FormatString(char *buff, const char *str_arg, StringParameters *arg const Town *t = Town::GetIfValid(args->GetInt32(SCC_TOWN_NAME)); if (t == nullptr) break; - if (t->name != nullptr) { - int64 args_array[] = {(int64)(size_t)t->name}; + if (!t->name.empty()) { + int64 args_array[] = {(int64)(size_t)t->name.c_str()}; StringParameters tmp_params(args_array); buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last); } else { @@ -1719,8 +1719,8 @@ static char *FormatString(char *buff, const char *str_arg, StringParameters *arg Waypoint *wp = Waypoint::GetIfValid(args->GetInt32(SCC_WAYPOINT_NAME)); if (wp == nullptr) break; - if (wp->name != nullptr) { - int64 args_array[] = {(int64)(size_t)wp->name}; + if (!wp->name.empty()) { + int64 args_array[] = {(int64)(size_t)wp->name.c_str()}; StringParameters tmp_params(args_array); buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last); } else { @@ -1737,8 +1737,8 @@ static char *FormatString(char *buff, const char *str_arg, StringParameters *arg const Vehicle *v = Vehicle::GetIfValid(args->GetInt32(SCC_VEHICLE_NAME)); if (v == nullptr) break; - if (v->name != nullptr) { - int64 args_array[] = {(int64)(size_t)v->name}; + if (!v->name.empty()) { + int64 args_array[] = {(int64)(size_t)v->name.c_str()}; StringParameters tmp_params(args_array); buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last); } else { @@ -1763,8 +1763,8 @@ static char *FormatString(char *buff, const char *str_arg, StringParameters *arg const Sign *si = Sign::GetIfValid(args->GetInt32()); if (si == nullptr) break; - if (si->name != nullptr) { - int64 args_array[] = {(int64)(size_t)si->name}; + if (!si->name.empty()) { + int64 args_array[] = {(int64)(size_t)si->name.c_str()}; StringParameters tmp_params(args_array); buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last); } else { diff --git a/src/table/misc_settings.ini b/src/table/misc_settings.ini index 91cdf11c1a..1878d01aba 100644 --- a/src/table/misc_settings.ini +++ b/src/table/misc_settings.ini @@ -17,6 +17,7 @@ SDTG_LIST = SDTG_LIST($name, $type, $length, $flags, $guiflags, $var, $def, SDTG_MMANY = SDTG_MMANY($name, $type, $flags, $guiflags, $var, $def, $full, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver, nullptr), SDTG_OMANY = SDTG_OMANY($name, $type, $flags, $guiflags, $var, $def, $max, $full, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver, nullptr), SDTG_STR = SDTG_STR($name, $type, $flags, $guiflags, $var, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver, nullptr), +SDTG_SSTR = SDTG_SSTR($name, $type, $flags, $guiflags, $var, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver, nullptr), SDTG_BOOL = SDTG_BOOL($name, $flags, $guiflags, $var, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver, nullptr), SDTG_VAR = SDTG_VAR($name, $type, $flags, $guiflags, $var, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver, nullptr, $orderproc), SDTG_END = SDTG_END() @@ -60,49 +61,49 @@ max = 2 full = _support8bppmodes cat = SC_BASIC -[SDTG_STR] +[SDTG_SSTR] name = ""graphicsset"" type = SLE_STRQ var = BaseGraphics::ini_set def = nullptr cat = SC_BASIC -[SDTG_STR] +[SDTG_SSTR] name = ""soundsset"" type = SLE_STRQ var = BaseSounds::ini_set def = nullptr cat = SC_BASIC -[SDTG_STR] +[SDTG_SSTR] name = ""musicset"" type = SLE_STRQ var = BaseMusic::ini_set def = nullptr cat = SC_BASIC -[SDTG_STR] +[SDTG_SSTR] name = ""videodriver"" type = SLE_STRQ var = _ini_videodriver def = nullptr cat = SC_EXPERT -[SDTG_STR] +[SDTG_SSTR] name = ""musicdriver"" type = SLE_STRQ var = _ini_musicdriver def = nullptr cat = SC_EXPERT -[SDTG_STR] +[SDTG_SSTR] name = ""sounddriver"" type = SLE_STRQ var = _ini_sounddriver def = nullptr cat = SC_EXPERT -[SDTG_STR] +[SDTG_SSTR] name = ""blitter"" type = SLE_STRQ var = _ini_blitter diff --git a/src/table/settings.h.preamble b/src/table/settings.h.preamble index 7041a27b92..934f257968 100644 --- a/src/table/settings.h.preamble +++ b/src/table/settings.h.preamble @@ -77,6 +77,9 @@ static size_t ConvertLandscape(const char *value); #define SDTG_LIST(name, type, length, flags, guiflags, var, def, str, strhelp, strval, proc, from, to, cat, extver, patxname)\ SDTG_GENERAL(name, SDT_INTLIST, SL_ARR, type, flags, guiflags, var, length, def, 0, 0, 0, nullptr, str, strhelp, strval, proc, from, to, cat, extver, patxname) +#define SDTG_SSTR(name, type, flags, guiflags, var, def, str, strhelp, strval, proc, from, to, cat, extver, patxname)\ + SDTG_GENERAL(name, SDT_STDSTRING, SL_STDSTR, type, flags, guiflags, var, sizeof(var), def, 0, 0, 0, nullptr, str, strhelp, strval, proc, from, to, cat, extver, patxname) + #define SDTG_STR(name, type, flags, guiflags, var, def, str, strhelp, strval, proc, from, to, cat, extver, patxname)\ SDTG_GENERAL(name, SDT_STRING, SL_STR, type, flags, guiflags, var, sizeof(var), def, 0, 0, 0, nullptr, str, strhelp, strval, proc, from, to, cat, extver, patxname) diff --git a/src/textbuf_type.h b/src/textbuf_type.h index a238aa74b5..b4f234f737 100644 --- a/src/textbuf_type.h +++ b/src/textbuf_type.h @@ -53,7 +53,7 @@ struct Textbuf { void DeleteAll(); bool InsertClipboard(); - bool InsertChar(uint32 key); + bool InsertChar(WChar key); bool InsertString(const char *str, bool marked, const char *caret = nullptr, const char *insert_location = nullptr, const char *replacement_end = nullptr); bool DeleteChar(uint16 keycode); diff --git a/src/town.h b/src/town.h index 06a44ea0c7..dc3c27c863 100644 --- a/src/town.h +++ b/src/town.h @@ -63,7 +63,7 @@ struct Town : TownPool::PoolItem<&_town_pool> { uint32 townnamegrfid; uint16 townnametype; uint32 townnameparts; - char *name; ///< Custom town name. If nullptr, the town was not renamed and uses the generated name. + std::string name; ///< Custom town name. If empty, the town was not renamed and uses the generated name. mutable std::string cached_name; ///< NOSAVE: Cache of the resolved name of the town, if not using a custom town name byte flags; ///< See #TownFlags. @@ -84,7 +84,7 @@ struct Town : TownPool::PoolItem<&_town_pool> { TransportedCargoStat received[NUM_TE]; ///< Cargo statistics about received cargotypes. uint32 goal[NUM_TE]; ///< Amount of cargo required for the town to grow. - char *text; ///< General text with additional information. + std::string text; ///< General text with additional information. inline byte GetPercentTransported(CargoID cid) const { return this->supplied[cid].old_act * 256 / (this->supplied[cid].old_max + 1); } @@ -162,7 +162,7 @@ struct Town : TownPool::PoolItem<&_town_pool> { inline const char *GetCachedName() const { - if (this->name != nullptr) return this->name; + if (!this->name.empty()) return this->name.c_str(); if (this->cached_name.empty()) this->FillCachedName(); return this->cached_name.c_str(); } @@ -279,7 +279,7 @@ template void MakeDefaultName(T *obj) { /* We only want to set names if it hasn't been set before, or when we're calling from afterload. */ - assert(obj->name == nullptr || obj->town_cn == UINT16_MAX); + assert(obj->name.empty() || obj->town_cn == UINT16_MAX); obj->town = ClosestTownFromTile(obj->xy, UINT_MAX); diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp index a57a83dd90..3945031ce5 100644 --- a/src/town_cmd.cpp +++ b/src/town_cmd.cpp @@ -107,9 +107,6 @@ static bool TestTownOwnsBridge(TileIndex tile, const Town *t) Town::~Town() { - free(this->name); - free(this->text); - if (CleaningPool()) return; /* Delete town authority window @@ -563,13 +560,22 @@ uint32 GetWorldPopulation() /** * Remove stations from nearby station list if a town is no longer in the catchment area of each. + * To improve performance only checks stations that cover the provided house area (doesn't need to contain an actual house). * @param t Town to work on + * @param tile Location of house area (north part) + * @param flags BuildingFlags containing the size of house area */ -void RemoveNearbyStations(Town *t) +static void RemoveNearbyStations(Town *t, TileIndex tile, BuildingFlags flags) { for (StationList::iterator it = t->stations_near.begin(); it != t->stations_near.end(); /* incremented inside loop */) { const Station *st = *it; - if (!st->CatchmentCoversTown(t->index)) { + + bool covers_area = st->TileIsInCatchment(tile); + if (flags & BUILDING_2_TILES_Y) covers_area |= st->TileIsInCatchment(tile + TileDiffXY(0, 1)); + if (flags & BUILDING_2_TILES_X) covers_area |= st->TileIsInCatchment(tile + TileDiffXY(1, 0)); + if (flags & BUILDING_HAS_4_TILES) covers_area |= st->TileIsInCatchment(tile + TileDiffXY(1, 1)); + + if (covers_area && !st->CatchmentCoversTown(t->index)) { it = t->stations_near.erase(it); } else { ++it; @@ -781,11 +787,7 @@ static void TileLoop_Town(TileIndex tile) ClearTownHouse(t, tile); /* Rebuild with another house? */ - bool built = (GB(r, 24, 8) >= 12 && BuildTownHouse(t, tile)); - if (!built || ((hs->building_flags & BUILDING_HAS_1_TILE & ~HouseSpec::Get(GetHouseType(tile))->building_flags) != 0)) { - /* House wasn't replaced, or replacement was smaller/different shape, so remove it */ - if (!_generating_world) RemoveNearbyStations(t); - } + if (GB(r, 24, 8) >= 12) BuildTownHouse(t, tile); } cur_company.Restore(); @@ -814,7 +816,6 @@ static CommandCost ClearTile_Town(TileIndex tile, DoCommandFlag flags) ChangeTownRating(t, -rating, RATING_HOUSE_MINIMUM, flags); if (flags & DC_EXEC) { ClearTownHouse(t, tile); - RemoveNearbyStations(t); } return cost; @@ -2063,7 +2064,7 @@ static CommandCost TownCanBePlacedHere(TileIndex tile) static bool IsUniqueTownName(const char *name) { for (const Town *t : Town::Iterate()) { - if (t->name != nullptr && strcmp(t->name, name) == 0) return false; + if (!t->name.empty() && t->name == name) return false; } return true; @@ -2954,16 +2955,17 @@ void ClearTownHouse(Town *t, TileIndex tile) } /* Do the actual clearing of tiles */ - uint eflags = hs->building_flags; DoClearTownHouseHelper(tile, t, house); - if (eflags & BUILDING_2_TILES_Y) DoClearTownHouseHelper(tile + TileDiffXY(0, 1), t, ++house); - if (eflags & BUILDING_2_TILES_X) DoClearTownHouseHelper(tile + TileDiffXY(1, 0), t, ++house); - if (eflags & BUILDING_HAS_4_TILES) DoClearTownHouseHelper(tile + TileDiffXY(1, 1), t, ++house); + if (hs->building_flags & BUILDING_2_TILES_Y) DoClearTownHouseHelper(tile + TileDiffXY(0, 1), t, ++house); + if (hs->building_flags & BUILDING_2_TILES_X) DoClearTownHouseHelper(tile + TileDiffXY(1, 0), t, ++house); + if (hs->building_flags & BUILDING_HAS_4_TILES) DoClearTownHouseHelper(tile + TileDiffXY(1, 1), t, ++house); + + RemoveNearbyStations(t, tile, hs->building_flags); UpdateTownRadius(t); /* Update cargo acceptance. */ - UpdateTownCargoesHouse(t, tile, eflags & BUILDING_2_TILES_X, eflags & BUILDING_2_TILES_Y); + UpdateTownCargoesHouse(t, tile, hs->building_flags & BUILDING_2_TILES_X, hs->building_flags & BUILDING_2_TILES_Y); } /** @@ -2989,8 +2991,11 @@ CommandCost CmdRenameTown(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 if (flags & DC_EXEC) { t->cached_name.clear(); - free(t->name); - t->name = reset ? nullptr : stredup(text); + if (reset) { + t->name.clear(); + } else { + t->name = text; + } t->UpdateVirtCoord(); InvalidateWindowData(WC_TOWN_DIRECTORY, 0, TDIWD_FORCE_RESORT); @@ -3066,8 +3071,8 @@ CommandCost CmdTownSetText(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 if (t == nullptr) return CMD_ERROR; if (flags & DC_EXEC) { - free(t->text); - t->text = StrEmpty(text) ? nullptr : stredup(text); + t->text.clear(); + if (!StrEmpty(text)) t->text = text; InvalidateWindowData(WC_TOWN_VIEW, p1); } diff --git a/src/town_gui.cpp b/src/town_gui.cpp index 782accfa59..6c7529333f 100644 --- a/src/town_gui.cpp +++ b/src/town_gui.cpp @@ -439,8 +439,8 @@ public: DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += FONT_HEIGHT_NORMAL, STR_TOWN_VIEW_NOISE_IN_TOWN); } - if (this->town->text != nullptr) { - SetDParamStr(0, this->town->text); + if (!this->town->text.empty()) { + SetDParamStr(0, this->town->text.c_str()); DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y += FONT_HEIGHT_NORMAL, UINT16_MAX, STR_JUST_RAW_STRING, TC_BLACK); } } @@ -521,8 +521,8 @@ public: if (_settings_game.economy.station_noise_level) aimed_height += FONT_HEIGHT_NORMAL; - if (this->town->text != nullptr) { - SetDParamStr(0, this->town->text); + if (!this->town->text.empty()) { + SetDParamStr(0, this->town->text.c_str()); aimed_height += GetStringHeight(STR_JUST_RAW_STRING, width - WD_FRAMERECT_LEFT - WD_FRAMERECT_RIGHT); } diff --git a/src/townname.cpp b/src/townname.cpp index 5cc414794a..77dfb448b2 100644 --- a/src/townname.cpp +++ b/src/townname.cpp @@ -97,7 +97,7 @@ bool VerifyTownName(uint32 r, const TownNameParams *par, TownNames *town_names) for (const Town *t : Town::Iterate()) { /* We can't just compare the numbers since * several numbers may map to a single name. */ - const char *buf = t->name; + const char *buf = t->name.empty() ? nullptr : t->name.c_str(); if (buf == nullptr) { GetTownName(buf2, t, lastof(buf2)); buf = buf2; diff --git a/src/tree_cmd.cpp b/src/tree_cmd.cpp index 9c5e6f1376..a691603452 100644 --- a/src/tree_cmd.cpp +++ b/src/tree_cmd.cpp @@ -729,6 +729,13 @@ static void TileLoopTreesAlps(TileIndex tile) MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP); } +static bool CanPlantExtraTrees(TileIndex tile) +{ + return ((_settings_game.game_creation.landscape == LT_TROPIC && GetTropicZone(tile) == TROPICZONE_RAINFOREST) ? + _settings_game.construction.extra_tree_placement != ETP_NONE : + _settings_game.construction.extra_tree_placement == ETP_ALL); +} + static void TileLoop_Trees(TileIndex tile) { if (GetTreeGround(tile) == TREE_GROUND_SHORE) { @@ -788,12 +795,7 @@ static void TileLoop_Trees(TileIndex tile) FALLTHROUGH; case 2: { // add a neighbouring tree - /* Don't plant extra trees if that's not allowed. */ - if ((_settings_game.game_creation.landscape == LT_TROPIC && GetTropicZone(tile) == TROPICZONE_RAINFOREST) ? - _settings_game.construction.extra_tree_placement == ETP_NONE : - _settings_game.construction.extra_tree_placement != ETP_ALL) { - break; - } + if (!CanPlantExtraTrees(tile)) break; TreeType treetype = GetTreeType(tile); @@ -821,6 +823,9 @@ static void TileLoop_Trees(TileIndex tile) /* more than one tree, delete it */ AddTreeCount(tile, -1); SetTreeGrowth(tile, 3); + } else if (!CanPlantExtraTrees(tile)) { + /* if trees can't spread just plant a new one to prevent deforestation */ + SetTreeGrowth(tile, 0); } else { /* just one tree, change type into MP_CLEAR */ switch (GetTreeGround(tile)) { diff --git a/src/vehicle_cmd.cpp b/src/vehicle_cmd.cpp index 914621b234..885bac8654 100644 --- a/src/vehicle_cmd.cpp +++ b/src/vehicle_cmd.cpp @@ -33,6 +33,8 @@ #include "core/random_func.hpp" #include "tbtr_template_vehicle.h" #include "tbtr_template_vehicle_func.h" +#include +#include #include "table/strings.h" @@ -785,7 +787,7 @@ CommandCost CmdDepotMassAutoReplace(TileIndex tile, DoCommandFlag flags, uint32 static bool IsUniqueVehicleName(const char *name) { for (const Vehicle *v : Vehicle::Iterate()) { - if (v->name != nullptr && strcmp(v->name, name) == 0) return false; + if (!v->name.empty() && v->name == name) return false; } return true; @@ -798,42 +800,48 @@ static bool IsUniqueVehicleName(const char *name) */ static void CloneVehicleName(const Vehicle *src, Vehicle *dst) { - char buf[256]; + std::string buf; /* Find the position of the first digit in the last group of digits. */ size_t number_position; - for (number_position = strlen(src->name); number_position > 0; number_position--) { + for (number_position = src->name.length(); number_position > 0; number_position--) { /* The design of UTF-8 lets this work simply without having to check * for UTF-8 sequences. */ if (src->name[number_position - 1] < '0' || src->name[number_position - 1] > '9') break; } /* Format buffer and determine starting number. */ - int num; + long num; byte padding = 0; - if (number_position == strlen(src->name)) { + if (number_position == src->name.length()) { /* No digit at the end, so start at number 2. */ - strecpy(buf, src->name, lastof(buf)); - strecat(buf, " ", lastof(buf)); - number_position = strlen(buf); + buf = src->name; + buf += " "; + number_position = buf.length(); num = 2; } else { /* Found digits, parse them and start at the next number. */ - strecpy(buf, src->name, lastof(buf)); - buf[number_position] = '\0'; - char *endptr; - num = strtol(&src->name[number_position], &endptr, 10) + 1; - padding = endptr - &src->name[number_position]; + buf = src->name.substr(0, number_position); + + auto num_str = src->name.substr(number_position); + padding = (byte)num_str.length(); + + std::istringstream iss(num_str); + iss >> num; + num++; } /* Check if this name is already taken. */ for (int max_iterations = 1000; max_iterations > 0; max_iterations--, num++) { + std::ostringstream oss; + /* Attach the number to the temporary name. */ - seprintf(&buf[number_position], lastof(buf), "%0*d", padding, num); + oss << buf << std::setw(padding) << std::setfill('0') << std::internal << num; /* Check the name is unique. */ - if (IsUniqueVehicleName(buf)) { - dst->name = stredup(buf); + auto new_name = oss.str(); + if (IsUniqueVehicleName(new_name.c_str())) { + dst->name = new_name; break; } } @@ -1484,7 +1492,7 @@ CommandCost CmdCloneVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint DoCommand(0, w_front->index | (p2 & 1 ? CO_SHARE : CO_COPY) << 30, v_front->index, flags, CMD_CLONE_ORDER); /* Now clone the vehicle's name, if it has one. */ - if (v_front->name != nullptr) CloneVehicleName(v_front, w_front); + if (!v_front->name.empty()) CloneVehicleName(v_front, w_front); } /* Since we can't estimate the cost of cloning a vehicle accurately we must @@ -1611,8 +1619,11 @@ CommandCost CmdRenameVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uin } if (flags & DC_EXEC) { - free(v->name); - v->name = reset ? nullptr : stredup(text); + if (reset) { + v->name.clear(); + } else { + v->name = text; + } InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 1); InvalidateWindowClassesData(WC_DEPARTURES_BOARD, 0); MarkWholeScreenDirty(); diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index 2d24088aed..1021eddaa4 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -1784,7 +1784,7 @@ void BaseVehicleListWindow::DrawVehicleListItems(VehicleID selected_vehicle, int GfxFillRect((text_right - 1) - (FONT_HEIGHT_SMALL - 2), y + 1, text_right - 1, (y + 1) + (FONT_HEIGHT_SMALL - 2), ccolour, FILLRECT_OPAQUE); } - if (v->name != nullptr) { + if (!v->name.empty()) { /* The vehicle got a name so we will print it */ SetDParam(0, v->index); DrawString(text_left, text_right, y, STR_TINY_BLACK_VEHICLE); diff --git a/src/video/allegro_v.cpp b/src/video/allegro_v.cpp index a12061f1e8..ec43fd8a84 100644 --- a/src/video/allegro_v.cpp +++ b/src/video/allegro_v.cpp @@ -410,7 +410,7 @@ static void PollEvent() */ int _allegro_instance_count = 0; -const char *VideoDriver_Allegro::Start(const char * const *parm) +const char *VideoDriver_Allegro::Start(const StringList &parm) { if (_allegro_instance_count == 0 && install_allegro(SYSTEM_AUTODETECT, &errno, nullptr)) { DEBUG(driver, 0, "allegro: install_allegro failed '%s'", allegro_error); diff --git a/src/video/allegro_v.h b/src/video/allegro_v.h index fb7b84ee2c..641e3d6c2f 100644 --- a/src/video/allegro_v.h +++ b/src/video/allegro_v.h @@ -15,7 +15,7 @@ /** The allegro video driver. */ class VideoDriver_Allegro : public VideoDriver { public: - const char *Start(const char * const *param) override; + const char *Start(const StringList ¶m) override; void Stop() override; diff --git a/src/video/cocoa/cocoa_v.h b/src/video/cocoa/cocoa_v.h index 7286c685b8..3da6848d09 100644 --- a/src/video/cocoa/cocoa_v.h +++ b/src/video/cocoa/cocoa_v.h @@ -14,7 +14,7 @@ class VideoDriver_Cocoa : public VideoDriver { public: - const char *Start(const char * const *param) override; + const char *Start(const StringList ¶m) override; /** Stop the video driver */ void Stop() override; diff --git a/src/video/cocoa/cocoa_v.mm b/src/video/cocoa/cocoa_v.mm index 607d83a364..36e3fe3a5f 100644 --- a/src/video/cocoa/cocoa_v.mm +++ b/src/video/cocoa/cocoa_v.mm @@ -396,7 +396,7 @@ void VideoDriver_Cocoa::Stop() /** * Initialize a cocoa video subdriver. */ -const char *VideoDriver_Cocoa::Start(const char * const *parm) +const char *VideoDriver_Cocoa::Start(const StringList &parm) { if (!MacOSVersionIsAtLeast(10, 6, 0)) return "The Cocoa video driver requires Mac OS X 10.6 or later."; @@ -520,7 +520,7 @@ void CocoaDialog(const char *title, const char *message, const char *buttonLabel bool wasstarted = _cocoa_video_started; if (VideoDriver::GetInstance() == nullptr) { setupApplication(); // Setup application before showing dialog - } else if (!_cocoa_video_started && VideoDriver::GetInstance()->Start(nullptr) != nullptr) { + } else if (!_cocoa_video_started && VideoDriver::GetInstance()->Start(StringList()) != NULL) { fprintf(stderr, "%s: %s\n", title, message); return; } diff --git a/src/video/dedicated_v.cpp b/src/video/dedicated_v.cpp index 7d97b8c113..ed336e88dd 100644 --- a/src/video/dedicated_v.cpp +++ b/src/video/dedicated_v.cpp @@ -133,7 +133,7 @@ extern bool SafeLoad(const char *filename, SaveLoadOperation fop, DetailedFileTy static FVideoDriver_Dedicated iFVideoDriver_Dedicated; -const char *VideoDriver_Dedicated::Start(const char * const *parm) +const char *VideoDriver_Dedicated::Start(const StringList &parm) { int bpp = BlitterFactory::GetCurrentBlitter()->GetScreenDepth(); _dedicated_video_mem = (bpp == 0) ? nullptr : MallocT(_cur_resolution.width * _cur_resolution.height * (bpp / 8)); diff --git a/src/video/dedicated_v.h b/src/video/dedicated_v.h index 27401aae91..54e2dd402b 100644 --- a/src/video/dedicated_v.h +++ b/src/video/dedicated_v.h @@ -15,7 +15,7 @@ /** The dedicated server video driver. */ class VideoDriver_Dedicated : public VideoDriver { public: - const char *Start(const char * const *param) override; + const char *Start(const StringList ¶m) override; void Stop() override; diff --git a/src/video/null_v.cpp b/src/video/null_v.cpp index 9d62a135dd..d6aa2e4f77 100644 --- a/src/video/null_v.cpp +++ b/src/video/null_v.cpp @@ -19,7 +19,7 @@ static FVideoDriver_Null iFVideoDriver_Null; extern bool _exit_game; -const char *VideoDriver_Null::Start(const char * const *parm) +const char *VideoDriver_Null::Start(const StringList &parm) { #ifdef _MSC_VER /* Disable the MSVC assertion message box. */ diff --git a/src/video/null_v.h b/src/video/null_v.h index 426ee76342..1676dc202d 100644 --- a/src/video/null_v.h +++ b/src/video/null_v.h @@ -19,7 +19,7 @@ private: bool until_exit; public: - const char *Start(const char * const *param) override; + const char *Start(const StringList ¶m) override; void Stop() override; diff --git a/src/video/sdl2_v.cpp b/src/video/sdl2_v.cpp index 95e9b056b6..4a4c8086ea 100644 --- a/src/video/sdl2_v.cpp +++ b/src/video/sdl2_v.cpp @@ -942,7 +942,7 @@ int VideoDriver_SDL::PollEvent() return -1; } -const char *VideoDriver_SDL::Start(const char * const *parm) +const char *VideoDriver_SDL::Start(const StringList &parm) { #if defined(WITH_FCITX) FcitxInit(); @@ -972,7 +972,7 @@ const char *VideoDriver_SDL::Start(const char * const *parm) MarkWholeScreenDirty(); - _draw_threaded = GetDriverParam(parm, "no_threads") == nullptr && GetDriverParam(parm, "no_thread") == nullptr; + _draw_threaded = !GetDriverParamBool(parm, "no_threads") && !GetDriverParamBool(parm, "no_thread"); SDL_StopTextInput(); this->edit_box_focused = false; diff --git a/src/video/sdl2_v.h b/src/video/sdl2_v.h index ae456a39d1..80d4018a77 100644 --- a/src/video/sdl2_v.h +++ b/src/video/sdl2_v.h @@ -15,7 +15,7 @@ /** The SDL video driver. */ class VideoDriver_SDL : public VideoDriver { public: - const char *Start(const char * const *param) override; + const char *Start(const StringList ¶m) override; void Stop() override; diff --git a/src/video/sdl_v.cpp b/src/video/sdl_v.cpp index 9735235a46..682b3f8268 100644 --- a/src/video/sdl_v.cpp +++ b/src/video/sdl_v.cpp @@ -600,7 +600,7 @@ int VideoDriver_SDL::PollEvent() return -1; } -const char *VideoDriver_SDL::Start(const char * const *parm) +const char *VideoDriver_SDL::Start(const StringList &parm) { char buf[30]; _use_hwpalette = GetDriverParamInt(parm, "hw_palette", 2); @@ -627,7 +627,7 @@ const char *VideoDriver_SDL::Start(const char * const *parm) MarkWholeScreenDirty(); SetupKeyboard(); - _draw_threaded = GetDriverParam(parm, "no_threads") == nullptr && GetDriverParam(parm, "no_thread") == nullptr; + _draw_threaded = !GetDriverParamBool(parm, "no_threads") && !GetDriverParamBool(parm, "no_thread"); return nullptr; } diff --git a/src/video/sdl_v.h b/src/video/sdl_v.h index 39c77e5d33..ffebd041e0 100644 --- a/src/video/sdl_v.h +++ b/src/video/sdl_v.h @@ -15,7 +15,7 @@ /** The SDL video driver. */ class VideoDriver_SDL : public VideoDriver { public: - const char *Start(const char * const *param) override; + const char *Start(const StringList ¶m) override; void Stop() override; diff --git a/src/video/video_driver.hpp b/src/video/video_driver.hpp index 8d2844e2ae..23421387c2 100644 --- a/src/video/video_driver.hpp +++ b/src/video/video_driver.hpp @@ -104,7 +104,7 @@ public: } }; -extern char *_ini_videodriver; +extern std::string _ini_videodriver; extern std::vector _resolutions; extern Dimension _cur_resolution; extern bool _rightclick_emulate; diff --git a/src/video/win32_v.cpp b/src/video/win32_v.cpp index fbbf7fbfc8..0d6da96387 100644 --- a/src/video/win32_v.cpp +++ b/src/video/win32_v.cpp @@ -1115,7 +1115,7 @@ static void FindResolutions() static FVideoDriver_Win32 iFVideoDriver_Win32; -const char *VideoDriver_Win32::Start(const char * const *parm) +const char *VideoDriver_Win32::Start(const StringList &parm) { memset(&_wnd, 0, sizeof(_wnd)); @@ -1136,7 +1136,7 @@ const char *VideoDriver_Win32::Start(const char * const *parm) MarkWholeScreenDirty(); - _draw_threaded = GetDriverParam(parm, "no_threads") == nullptr && GetDriverParam(parm, "no_thread") == nullptr && std::thread::hardware_concurrency() > 1; + _draw_threaded = !GetDriverParamBool(parm, "no_threads") && !GetDriverParamBool(parm, "no_thread") && std::thread::hardware_concurrency() > 1; return nullptr; } diff --git a/src/video/win32_v.h b/src/video/win32_v.h index a0b5c7e161..5c1b20322f 100644 --- a/src/video/win32_v.h +++ b/src/video/win32_v.h @@ -15,7 +15,7 @@ /** The video driver for windows. */ class VideoDriver_Win32 : public VideoDriver { public: - const char *Start(const char * const *param) override; + const char *Start(const StringList ¶m) override; void Stop() override; diff --git a/src/waypoint_cmd.cpp b/src/waypoint_cmd.cpp index f1e1e8ec84..9f2bd65eb6 100644 --- a/src/waypoint_cmd.cpp +++ b/src/waypoint_cmd.cpp @@ -402,7 +402,7 @@ CommandCost RemoveBuoy(TileIndex tile, DoCommandFlag flags) static bool IsUniqueWaypointName(const char *name) { for (const Waypoint *wp : Waypoint::Iterate()) { - if (wp->name != nullptr && strcmp(wp->name, name) == 0) return false; + if (!wp->name.empty() && wp->name == name) return false; } return true; @@ -435,8 +435,11 @@ CommandCost CmdRenameWaypoint(TileIndex tile, DoCommandFlag flags, uint32 p1, ui } if (flags & DC_EXEC) { - free(wp->name); - wp->name = reset ? nullptr : stredup(text); + if (reset) { + wp->name.clear(); + } else { + wp->name = text; + } wp->UpdateVirtCoord(); } diff --git a/src/widgets/dropdown.cpp b/src/widgets/dropdown.cpp index 3d6e4a0d5e..1f26a398db 100644 --- a/src/widgets/dropdown.cpp +++ b/src/widgets/dropdown.cpp @@ -65,7 +65,7 @@ StringID DropDownListParamStringItem::String() const StringID DropDownListCharStringItem::String() const { - SetDParamStr(0, this->raw_string); + SetDParamStr(0, this->raw_string.c_str()); return this->string; } diff --git a/src/widgets/dropdown_type.h b/src/widgets/dropdown_type.h index 0e4a883240..540c3c9cb7 100644 --- a/src/widgets/dropdown_type.h +++ b/src/widgets/dropdown_type.h @@ -75,9 +75,9 @@ public: */ class DropDownListCharStringItem : public DropDownListStringItem { public: - const char *raw_string; + std::string raw_string; - DropDownListCharStringItem(const char *raw_string, int result, bool masked) : DropDownListStringItem(STR_JUST_RAW_STRING, result, masked), raw_string(raw_string) {} + DropDownListCharStringItem(const std::string &raw_string, int result, bool masked) : DropDownListStringItem(STR_JUST_RAW_STRING, result, masked), raw_string(raw_string) {} StringID String() const override; };