From e0b953b80404b37cc5b85a2b88ce0c548ebbc2c8 Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Fri, 25 Dec 2020 20:04:48 +0100 Subject: [PATCH 01/64] Fix: [Emscripten] compile with exceptions enabled, as our AIs depend on it Also parts of the saveload code does, and some other places. This does slow down builds, but for most computers this will not be measurable. At least, the ones I had access to I could not find a difference in FPS, mainly as that is heavily limited by the Hz of the screens of the computer. Either way, it is better to have a full functional game than a fast one in my opinion --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index ca2284ffc1..bbde268c4b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -242,6 +242,8 @@ if(EMSCRIPTEN) # Allow heap-growth, and start with a bigger memory size. target_link_libraries(WASM::WASM INTERFACE "-s ALLOW_MEMORY_GROWTH=1") target_link_libraries(WASM::WASM INTERFACE "-s INITIAL_MEMORY=33554432") + target_link_libraries(WASM::WASM INTERFACE "-s DISABLE_EXCEPTION_CATCHING=0") + add_definitions(-s DISABLE_EXCEPTION_CATCHING=0) # Export functions to Javascript. target_link_libraries(WASM::WASM INTERFACE "-s EXPORTED_FUNCTIONS='[\"_main\", \"_em_openttd_add_server\"]' -s EXTRA_EXPORTED_RUNTIME_METHODS='[\"cwrap\"]'") From 6aef1164a4c34d17b60acfb99e61117f35749c98 Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Fri, 25 Dec 2020 20:06:37 +0100 Subject: [PATCH 02/64] Fix: [Emscripten] using TIC/TOC on this platform is silly Stop throwing a warning about this, as it is not likely we will ever implement it. --- src/cpu.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/cpu.cpp b/src/cpu.cpp index 87aa841324..bafa0f7352 100644 --- a/src/cpu.cpp +++ b/src/cpu.cpp @@ -66,6 +66,12 @@ uint64 ottd_rdtsc() # define RDTSC_AVAILABLE #endif +#if defined(__EMSCRIPTEN__) && !defined(RDTSC_AVAILABLE) +/* On emscripten doing TIC/TOC would be ill-advised */ +uint64 ottd_rdtsc() {return 0;} +# define RDTSC_AVAILABLE +#endif + /* In all other cases we have no support for rdtsc. No major issue, * you just won't be able to profile your code with TIC()/TOC() */ #if !defined(RDTSC_AVAILABLE) From f2d78b11ddc50cea53a8c84e3584319ba5dd0e7b Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Sat, 26 Dec 2020 13:48:57 +0100 Subject: [PATCH 03/64] Fix: [Actions] cmakeBuildType is only used with CMakeListsTxtBasic (#8435) We use CMakeListsTxtAdvanced, and as such, we have to do this our self via "-DCMAKE_BUILD_TYPE=RelWithDebInfo". Otherwise we are producing Debug builds instead of Release builds. Oops. --- .github/workflows/release.yml | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 965fe1bf61..275a994d99 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -479,8 +479,7 @@ jobs: useVcpkgToolchainFile: false buildDirectory: '${{ github.workspace }}/build-host' buildWithCMakeArgs: '--target tools' - cmakeBuildType: RelWithDebInfo - cmakeAppendedArgs: ' -GNinja -DOPTION_TOOLS_ONLY=ON' + cmakeAppendedArgs: ' -GNinja -DOPTION_TOOLS_ONLY=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo' - name: Install MSVC problem matcher uses: ammaraskar/msvc-problem-matcher@master @@ -492,8 +491,7 @@ jobs: cmakeListsOrSettingsJson: CMakeListsTxtAdvanced useVcpkgToolchainFile: true buildDirectory: '${{ github.workspace }}/build' - cmakeBuildType: RelWithDebInfo - cmakeAppendedArgs: ' -GNinja -DOPTION_USE_NSIS=ON -DHOST_BINARY_DIR=${{ github.workspace }}/build-host' + cmakeAppendedArgs: ' -GNinja -DOPTION_USE_NSIS=ON -DHOST_BINARY_DIR=${{ github.workspace }}/build-host -DCMAKE_BUILD_TYPE=RelWithDebInfo' - name: Build (without installer) if: needs.source.outputs.is_tag != 'true' || matrix.arch == 'arm64' @@ -502,8 +500,7 @@ jobs: cmakeListsOrSettingsJson: CMakeListsTxtAdvanced useVcpkgToolchainFile: true buildDirectory: '${{ github.workspace }}/build' - cmakeBuildType: RelWithDebInfo - cmakeAppendedArgs: ' -GNinja -DHOST_BINARY_DIR=${{ github.workspace }}/build-host' + cmakeAppendedArgs: ' -GNinja -DHOST_BINARY_DIR=${{ github.workspace }}/build-host -DCMAKE_BUILD_TYPE=RelWithDebInfo' - name: Create bundles shell: bash From 8fa2a67f6b486d4169cdf0a3782782f8e71e04ad Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Sat, 26 Dec 2020 13:54:00 +0100 Subject: [PATCH 04/64] Fix f66baa44: for-loop is no longer increasing "i" During conversion it was overlooked that the for-loop used to do this. Oops. --- src/ai/ai_gui.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ai/ai_gui.cpp b/src/ai/ai_gui.cpp index 23d1e81b70..f1ee03fc17 100644 --- a/src/ai/ai_gui.cpp +++ b/src/ai/ai_gui.cpp @@ -92,6 +92,8 @@ struct AIListWindow : public Window { this->selected = i; break; } + + i++; } } } From 2c8c6d423c32bef374d12664c062ed1daf60a981 Mon Sep 17 00:00:00 2001 From: translators Date: Sat, 26 Dec 2020 18:16:26 +0000 Subject: [PATCH 05/64] Update: Translations from eints korean: 18 changes by telk5093 --- src/lang/korean.txt | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/lang/korean.txt b/src/lang/korean.txt index 33382de3f6..0a8612ca07 100644 --- a/src/lang/korean.txt +++ b/src/lang/korean.txt @@ -1243,7 +1243,7 @@ STR_CONFIG_SETTING_SIGNALSIDE_HELPTEXT :선로의 어 STR_CONFIG_SETTING_SIGNALSIDE_LEFT :왼쪽에 STR_CONFIG_SETTING_SIGNALSIDE_DRIVING_SIDE :진행 방향에 STR_CONFIG_SETTING_SIGNALSIDE_RIGHT :오른쪽에 -STR_CONFIG_SETTING_SHOWFINANCES :연말에 자동으로 재정 창을 띄움: {STRING} +STR_CONFIG_SETTING_SHOWFINANCES :연말에 자동으로 재정 창을 띄우기: {STRING} STR_CONFIG_SETTING_SHOWFINANCES_HELPTEXT :이 설정을 켜면. 회사의 재정 상태를 확인하기 쉽도록 매년 말에 재정 창이 자동으로 뜹니다. STR_CONFIG_SETTING_NONSTOP_BY_DEFAULT :새로 지정하는 경로는 기본적으로 '직행'으로 처리: {STRING} STR_CONFIG_SETTING_NONSTOP_BY_DEFAULT_HELPTEXT :일반적으로 차량은 경로 상에 있는 모든 역에 정차하게 되어있습니다. 이 설정을 켜면, 차량이 마지막 목적지까지 정차없이 모든 역을 통과할 것입니다. 이 설정은 새로 경로를 지정하는 차량에만 적용되는 점을 알아두십시오. 하지만 각 차량의 경로는 두 가지 방법 중에 원하는 대로 다시 설정할 수 있습니다. @@ -1292,7 +1292,7 @@ STR_CONFIG_SETTING_COMPANY_STARTING_COLOUR_HELPTEXT :새 회사에 STR_CONFIG_SETTING_NEVER_EXPIRE_AIRPORTS :옛날 공항을 사라지지 않고 계속 만들 수 있게 함: {STRING} STR_CONFIG_SETTING_NEVER_EXPIRE_AIRPORTS_HELPTEXT :이 설정을 켜면, 소형 공항을 포함한 모든 공항 종류를 도입 이후에 계속 사용할 수 있게 됩니다. -STR_CONFIG_SETTING_WARN_LOST_VEHICLE :차량이 길을 잃으면 경고: {STRING} +STR_CONFIG_SETTING_WARN_LOST_VEHICLE :차량이 길을 잃으면 경고하기: {STRING} STR_CONFIG_SETTING_WARN_LOST_VEHICLE_HELPTEXT :다음 목적지로 가기 위한 경로를 찾을 수 없는 차량이 있으면 뉴스 메시지로 알려줍니다. STR_CONFIG_SETTING_ORDER_REVIEW :차량의 경로를 검사: {STRING} STR_CONFIG_SETTING_ORDER_REVIEW_HELPTEXT :이 설정을 켜면, 차량의 경로를 주기적으로 검사하여 문제가 발견되면 뉴스 메시지로 알려줍니다. @@ -1316,7 +1316,7 @@ STR_CONFIG_SETTING_ERRMSG_DURATION_HELPTEXT :오류 메시 STR_CONFIG_SETTING_ERRMSG_DURATION_VALUE :{COMMA}초 동안 STR_CONFIG_SETTING_HOVER_DELAY :도움말 보이기: {STRING} STR_CONFIG_SETTING_HOVER_DELAY_HELPTEXT :마우스를 올려놓았을 때 도움말이 뜨는데 걸리는 시간을 설정합니다. 마우스 오른쪽 클릭으로 바로 뜨도록 할 수도 있습니다. -STR_CONFIG_SETTING_HOVER_DELAY_VALUE :마우스를 {COMMA}밀리초 동안 올려놓기 (1밀리초 = 1/1000초) +STR_CONFIG_SETTING_HOVER_DELAY_VALUE :마우스를 {COMMA}밀리초 동안 올려놓기 STR_CONFIG_SETTING_HOVER_DELAY_DISABLED :마우스 오른쪽 클릭 STR_CONFIG_SETTING_POPULATION_IN_LABEL :도시 이름 옆에 도시의 인구 수를 표시함: {STRING} STR_CONFIG_SETTING_POPULATION_IN_LABEL_HELPTEXT :도시 이름 옆에 도시의 인구 수를 표시합니다. @@ -1367,7 +1367,7 @@ STR_CONFIG_SETTING_STATION_SPREAD :역의 최대 STR_CONFIG_SETTING_STATION_SPREAD_HELPTEXT :역의 최대 크기를 설정합니다. 값이 높으면 게임이 느려질 수도 있습니다. STR_CONFIG_SETTING_SERVICEATHELIPAD :헬리콥터를 발착장에서 자동으로 점검: {STRING} STR_CONFIG_SETTING_SERVICEATHELIPAD_HELPTEXT :공항에 격납고가 없어도 헬리콥터가 공항에 착륙할 때마다 점검을 하도록 합니다. -STR_CONFIG_SETTING_LINK_TERRAFORM_TOOLBAR :철도/도로/항만/공항 건설창을 띄울 때 지형 편집창도 같이 띄움: {STRING} +STR_CONFIG_SETTING_LINK_TERRAFORM_TOOLBAR :철도/도로/항만/공항 건설창을 띄울 때 지형 편집창도 같이 띄우기: {STRING} STR_CONFIG_SETTING_LINK_TERRAFORM_TOOLBAR_HELPTEXT :수송 시설과 관련된 건설 창을 열 때 지형 편집 창을 같이 엽니다. STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR :소형지도 창에 표시될 땅의 색상: {STRING} STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_HELPTEXT :소형지도 창에 사용할 지형의 색상을 선택합니다. @@ -1417,7 +1417,7 @@ STR_CONFIG_SETTING_RIGHT_MOUSE_WND_CLOSE_HELPTEXT :창 내부를 STR_CONFIG_SETTING_AUTOSAVE :자동 저장: {STRING} STR_CONFIG_SETTING_AUTOSAVE_HELPTEXT :게임을 자동으로 저장할 간격을 선택하십시오. -STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES :저장 파일의 이름으로 {STRING} 날짜 형식을 사용합니다. +STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES :저장 파일 이름으로 {STRING} 날짜 형식을 사용 STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_HELPTEXT :게임 저장 파일 이름에 사용할 날짜 형식을 선택합니다. STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_LONG :긴 (2012년 1월 1일) STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_SHORT :짧은 (2012.01.01) @@ -1501,7 +1501,7 @@ STR_CONFIG_SETTING_AI_IN_MULTIPLAYER_HELPTEXT :멀티 플레 STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES :게임 스크립트가 중지되기 직전에 계산할 수 있는 최대 횟수: {STRING} STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES_HELPTEXT :게임 스크립트가 한 단계에서 계산할 수 있는 최대 계산 횟수를 설정합니다. STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY :스크립트당 최대 메모리 사용량: {STRING} -STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY_HELPTEXT :강제로 종료되기 전에 단일 스크립트가 사용할 수 있는 메모리의 양입니다. 크기가 큰 맵에서는 값을 크게 설정해야할 수도 있습니다. +STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY_HELPTEXT :스크립트 하나가 강제 종료되기 전까지 사용할 수 있는 메모리의 양입니다. 크기가 큰 맵에서는 값을 크게 설정해야할 수도 있습니다. STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY_VALUE :{COMMA} MiB STR_CONFIG_SETTING_SERVINT_ISPERCENT :신뢰도에 따른 정비 설정: {STRING} @@ -1572,7 +1572,7 @@ STR_CONFIG_SETTING_ECONOMY_TYPE_SMOOTH :부드러움 STR_CONFIG_SETTING_ECONOMY_TYPE_FROZEN :멈춤 STR_CONFIG_SETTING_ALLOW_SHARES :다른 회사의 지분을 사는 것을 허용: {STRING} STR_CONFIG_SETTING_ALLOW_SHARES_HELPTEXT :이 설정을 켜면, 회사의 지분을 거래할 수 있게 됩니다. 회사의 지분을 거래하려면 해당 회사가 어느 정도 오래되어야 합니다. -STR_CONFIG_SETTING_MIN_YEARS_FOR_SHARES :지분 거래를 허용할 최소 회사 나이: {STRING} +STR_CONFIG_SETTING_MIN_YEARS_FOR_SHARES :지분 거래를 허용할 최소 회사 나이: {STRING}년 STR_CONFIG_SETTING_MIN_YEARS_FOR_SHARES_HELPTEXT :지분을 사고 팔기 위해 필요한 회사의 최소 나이를 설정합니다. STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE :환승시 벌어들이는 중간 수익의 비율: {STRING} STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE_HELPTEXT :더 많은 수익을 내기 위해, 수송 관계상 중간 구간에게 주어진 수익의 비율을 설정합니다. @@ -1583,7 +1583,7 @@ STR_CONFIG_SETTING_DRAG_SIGNALS_FIXED_DISTANCE :드래그할 STR_CONFIG_SETTING_DRAG_SIGNALS_FIXED_DISTANCE_HELPTEXT :신호기를 CTRL+드래그 하여 설치할 때의 행동을 선택합니다. 이 설정을 끄면, 신호기가 없는 긴 폐색을 만들지 않기 위해 터널이나 다리 주변에 먼저 신호기가 설치될 것입니다. 이 설정을 켜면, 신호기는 터널/다리와 상관없이 매 n개의 칸마다 설치될 것입니다. STR_CONFIG_SETTING_SEMAPHORE_BUILD_BEFORE_DATE :전자식 신호기의 사용: {STRING}년 이후에 STR_CONFIG_SETTING_SEMAPHORE_BUILD_BEFORE_DATE_HELPTEXT :전자식 신호기를 사용할 수 있는 연도를 설정합니다. 이 이전에는 구식 신호기만 사용 가능합니다. (두 신호기는 기능적으로는 동일하고 모습만 다릅니다.) -STR_CONFIG_SETTING_ENABLE_SIGNAL_GUI :신호기 설치시 신호기 선택 창을 띄움: {STRING} +STR_CONFIG_SETTING_ENABLE_SIGNAL_GUI :신호기 설치시 신호기 선택 창을 띄우기: {STRING} STR_CONFIG_SETTING_ENABLE_SIGNAL_GUI_HELPTEXT :설치할 신호기 종류를 고를 수 있는 신호기 선택 창을 표시합니다. 이 설정을 끄면, 신호기 선택 창 없이 CTRL+클릭 만으로 신호기의 종류를 바꿔야 합니다. STR_CONFIG_SETTING_DEFAULT_SIGNAL_TYPE :기본적으로 만들 신호기 종류: {STRING} STR_CONFIG_SETTING_DEFAULT_SIGNAL_TYPE_HELPTEXT :기본으로 설치할 신호기의 종류를 선택합니다. @@ -1619,8 +1619,12 @@ STR_CONFIG_SETTING_TOWN_CARGOGENMODE_HELPTEXT :도시의 전 STR_CONFIG_SETTING_TOWN_CARGOGENMODE_ORIGINAL :제곱 (기본) STR_CONFIG_SETTING_TOWN_CARGOGENMODE_BITCOUNT :선형 -STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT :게임 진행 중에 나무가 자동적으로 번식: {STRING} -STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_HELPTEXT :게임 중에 나무가 자동적으로 번식하는지 여부를 조절합니다. 이 설정을 조정하면, 아열대 기후의 벌목소처럼 나무의 성장에 의존하는 산업시설에 영향을 끼칠 수 있습니다. +STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT :나무의 성장과 확장: {STRING} +STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_HELPTEXT :게임 플레이 중 나무의 성장과 확장 여부를 조절합니다. 이 설정을 조정하면, 아열대 기후의 벌목소처럼 나무의 성장에 의존하는 산업시설에 영향을 끼칠 수 있습니다. +STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_NO_SPREAD :성장은 하되 확장은 안 함 {RED}(제재소가 멈출 수 있음) +STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_SPREAD_RAINFOREST :성장은 하되 열대 우림에서만 확장함 +STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_SPREAD_ALL :어디서나 성장하고 확장함 +STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_NO_GROWTH_NO_SPREAD :성장과 확장 모두 안 함 {RED}(제재소가 멈출 수 있음) STR_CONFIG_SETTING_TOOLBAR_POS :주메뉴의 위치: {STRING} STR_CONFIG_SETTING_TOOLBAR_POS_HELPTEXT :주 메뉴가 화면 상단의 어느 위치에 표시될지를 선택합니다. @@ -1984,6 +1988,10 @@ STR_NETWORK_SERVER_LIST_JOIN_GAME :{BLACK}게임 STR_NETWORK_SERVER_LIST_REFRESH :{BLACK}새로고침 STR_NETWORK_SERVER_LIST_REFRESH_TOOLTIP :{BLACK}서버 정보를 새로 고칩니다. +STR_NETWORK_SERVER_LIST_SEARCH_SERVER_INTERNET :{BLACK}인터넷 검색 +STR_NETWORK_SERVER_LIST_SEARCH_SERVER_INTERNET_TOOLTIP :{BLACK}인터넷에서 공개 서버를 검색합니다 +STR_NETWORK_SERVER_LIST_SEARCH_SERVER_LAN :{BLACK}LAN 검색 +STR_NETWORK_SERVER_LIST_SEARCH_SERVER_LAN_TOOLTIP :{BLACK}로컬 영역 네트워크에서 서버를 검색합니다 STR_NETWORK_SERVER_LIST_ADD_SERVER :{BLACK}서버 추가 STR_NETWORK_SERVER_LIST_ADD_SERVER_TOOLTIP :{BLACK}서버를 목록에 수동으로 추가합니다. STR_NETWORK_SERVER_LIST_START_SERVER :{BLACK}서버 열기 From 4d0f19406b8ab841f920fc1206796be90d7643ea Mon Sep 17 00:00:00 2001 From: Niels Martin Hansen Date: Sun, 28 Jun 2020 13:43:17 +0200 Subject: [PATCH 06/64] Fix: Wrong tree sprite in tree toolbar --- src/tree_gui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tree_gui.cpp b/src/tree_gui.cpp index 5a1da825b1..72d40af3e8 100644 --- a/src/tree_gui.cpp +++ b/src/tree_gui.cpp @@ -29,7 +29,7 @@ void PlaceTreesRandomly(); /** Tree Sprites with their palettes */ const PalSpriteID tree_sprites[] = { - { 1621, PAL_NONE }, { 1587, PAL_NONE }, { 1656, PAL_NONE }, { 1579, PAL_NONE }, + { 1621, PAL_NONE }, { 1635, PAL_NONE }, { 1656, PAL_NONE }, { 1579, PAL_NONE }, { 1607, PAL_NONE }, { 1593, PAL_NONE }, { 1614, PAL_NONE }, { 1586, PAL_NONE }, { 1663, PAL_NONE }, { 1677, PAL_NONE }, { 1691, PAL_NONE }, { 1705, PAL_NONE }, { 1711, PAL_NONE }, { 1746, PAL_NONE }, { 1753, PAL_NONE }, { 1732, PAL_NONE }, From e0ee2d530aaa7bcf0bf80012f27024337d0ac4e7 Mon Sep 17 00:00:00 2001 From: Niels Martin Hansen Date: Mon, 22 Jun 2020 18:48:51 +0200 Subject: [PATCH 07/64] Change: Switch tree GUI to use dynamically generated buttons This makes it look a bit better in climates with fewer tree types. --- src/tree_gui.cpp | 249 ++++++++++++++++++++------------------ src/widgets/tree_widget.h | 14 +-- 2 files changed, 134 insertions(+), 129 deletions(-) diff --git a/src/tree_gui.cpp b/src/tree_gui.cpp index 72d40af3e8..58edf563b2 100644 --- a/src/tree_gui.cpp +++ b/src/tree_gui.cpp @@ -15,6 +15,8 @@ #include "company_base.h" #include "command_func.h" #include "sound_func.h" +#include "strings_func.h" +#include "zoom_func.h" #include "tree_map.h" #include "widgets/tree_widget.h" @@ -41,91 +43,111 @@ const PalSpriteID tree_sprites[] = { { 1978, PAL_NONE }, { 1985, PALETTE_TO_RED, }, { 1992, PALETTE_TO_PALE_GREEN }, { 1999, PALETTE_TO_YELLOW }, { 2006, PALETTE_TO_RED } }; +/** + * Calculate the maximum size of all tree sprites + * @return Dimension of the largest tree sprite + */ +static Dimension GetMaxTreeSpriteSize() +{ + const uint16 base = _tree_base_by_landscape[_settings_game.game_creation.landscape]; + const uint16 count = _tree_count_by_landscape[_settings_game.game_creation.landscape]; + + Dimension size, this_size; + Point offset; + /* Avoid to use it uninitialized */ + size.width = 32; // default width - WD_FRAMERECT_LEFT + size.height = 39; // default height - BUTTON_BOTTOM_OFFSET + offset.x = 0; + offset.y = 0; + + for (int i = base; i < base + count; i++) { + if (i >= (int)lengthof(tree_sprites)) return size; + this_size = GetSpriteSize(tree_sprites[i].sprite, &offset); + size.width = max(size.width, 2 * max(this_size.width, -offset.x)); + size.height = max(size.height, max(this_size.height, -offset.y)); + } + + return size; +} + /** * The build trees window. */ class BuildTreesWindow : public Window { - uint16 base; ///< Base tree number used for drawing the window. - uint16 count; ///< Number of different trees available. - TreeType tree_to_plant; ///< Tree number to plant, \c TREE_INVALID for a random tree. + /** Visual Y offset of tree root from the bottom of the tree type buttons */ + static const int BUTTON_BOTTOM_OFFSET = 7; -public: - BuildTreesWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) - { - this->InitNested(window_number); - ResetObjectToPlace(); - } + int tree_to_plant; ///< Tree number to plant, \c TREE_INVALID for a random tree. /** - * Calculate the maximum size of all tree sprites - * @return Dimension of the largest tree sprite + * Update the GUI and enable/disable planting to reflect selected options. */ - Dimension GetMaxTreeSpriteSize() + void UpdateMode() { - Dimension size, this_size; - Point offset; - /* Avoid to use it uninitialized */ - size.width = 32; // default width - 2 - size.height = 39; // default height - 7 - offset.x = 0; - offset.y = 0; - - for (int i = this->base; i < this->base + this->count; i++) { - if (i >= (int)lengthof(tree_sprites)) return size; - this_size = GetSpriteSize(tree_sprites[i].sprite, &offset); - size.width = max(size.width, 2 * max(this_size.width, -offset.x)); - size.height = max(size.height, max(this_size.height, -offset.y)); + this->RaiseButtons(); + + const int current_tree = this->tree_to_plant; + + if (this->tree_to_plant >= 0) { + /* Activate placement */ + if (_settings_client.sound.confirm) SndPlayFx(SND_15_BEEP); + SetObjectToPlace(SPR_CURSOR_TREE, PAL_NONE, HT_RECT, this->window_class, this->window_number); + this->tree_to_plant = current_tree; // SetObjectToPlace may call ResetObjectToPlace which may reset tree_to_plant to -1 + } else { + /* Deactivate placement */ + ResetObjectToPlace(); + } + + if (this->tree_to_plant == TREE_INVALID) { + this->LowerWidget(WID_BT_TYPE_RANDOM); + } else if (this->tree_to_plant >= 0) { + this->LowerWidget(WID_BT_TYPE_BUTTON_FIRST + this->tree_to_plant); } - return size; + this->SetDirty(); + } + +public: + BuildTreesWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc), tree_to_plant(-1) + { + this->InitNested(window_number); + ResetObjectToPlace(); + + /* Show scenario editor tools in editor */ + auto *se_tools = this->GetWidget(WID_BT_SE_PANE); + if (_game_mode != GM_EDITOR) { + se_tools->SetDisplayedPlane(SZSP_HORIZONTAL); + this->ReInit(); + } } void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { - if (widget >= WID_BT_TYPE_11 && widget <= WID_BT_TYPE_34) { + if (widget >= WID_BT_TYPE_BUTTON_FIRST) { + /* Ensure tree type buttons are sized after the largest tree type */ Dimension d = GetMaxTreeSpriteSize(); - /* Allow some pixels extra width and height */ size->width = d.width + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; - size->height = d.height + WD_FRAMERECT_RIGHT + WD_FRAMERECT_BOTTOM + 7; // we need some more space - return; - } - - if (widget != WID_BT_MANY_RANDOM) return; - - if (_game_mode != GM_EDITOR) { - size->width = 0; - size->height = 0; + size->height = d.height + WD_FRAMERECT_RIGHT + WD_FRAMERECT_BOTTOM + ScaleGUITrad(BUTTON_BOTTOM_OFFSET); // we need some more space } } void DrawWidget(const Rect &r, int widget) const override { - if (widget < WID_BT_TYPE_11 || widget > WID_BT_TYPE_34 || widget - WID_BT_TYPE_11 >= this->count) return; - - int i = this->base + widget - WID_BT_TYPE_11; - /* Trees "grow" in the centre on the bottom line of the buttons */ - DrawSprite(tree_sprites[i].sprite, tree_sprites[i].pal, (r.left + r.right) / 2 + WD_FRAMERECT_LEFT, r.bottom - 7); + if (widget >= WID_BT_TYPE_BUTTON_FIRST) { + const int index = widget - WID_BT_TYPE_BUTTON_FIRST; + /* Trees "grow" in the centre on the bottom line of the buttons */ + DrawSprite(tree_sprites[index].sprite, tree_sprites[index].pal, (r.left + r.right) / 2 + WD_FRAMERECT_LEFT, r.bottom - ScaleGUITrad(BUTTON_BOTTOM_OFFSET)); + } } void OnClick(Point pt, int widget, int click_count) override { switch (widget) { - case WID_BT_TYPE_11: case WID_BT_TYPE_12: case WID_BT_TYPE_13: case WID_BT_TYPE_14: - case WID_BT_TYPE_21: case WID_BT_TYPE_22: case WID_BT_TYPE_23: case WID_BT_TYPE_24: - case WID_BT_TYPE_31: case WID_BT_TYPE_32: case WID_BT_TYPE_33: case WID_BT_TYPE_34: - if (widget - WID_BT_TYPE_11 >= this->count) break; - - if (HandlePlacePushButton(this, widget, SPR_CURSOR_TREE, HT_RECT)) { - this->tree_to_plant = (TreeType)(this->base + widget - WID_BT_TYPE_11); - } - break; - case WID_BT_TYPE_RANDOM: // tree of random type. - if (HandlePlacePushButton(this, WID_BT_TYPE_RANDOM, SPR_CURSOR_TREE, HT_RECT)) { - this->tree_to_plant = TREE_INVALID; - } + this->tree_to_plant = this->tree_to_plant == TREE_INVALID ? -1 : TREE_INVALID; + this->UpdateMode(); break; case WID_BT_MANY_RANDOM: // place trees randomly over the landscape @@ -133,6 +155,14 @@ public: PlaceTreesRandomly(); MarkWholeScreenDirty(); break; + + default: + if (widget >= WID_BT_TYPE_BUTTON_FIRST) { + const int index = widget - WID_BT_TYPE_BUTTON_FIRST; + this->tree_to_plant = this->tree_to_plant == index ? -1 : index; + this->UpdateMode(); + } + break; } } @@ -149,26 +179,53 @@ public: void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) override { if (pt.x != -1 && select_proc == DDSP_PLANT_TREES) { - DoCommandP(end_tile, this->tree_to_plant, start_tile, - CMD_PLANT_TREE | CMD_MSG(STR_ERROR_CAN_T_PLANT_TREE_HERE)); + DoCommandP(end_tile, this->tree_to_plant, start_tile, CMD_PLANT_TREE | CMD_MSG(STR_ERROR_CAN_T_PLANT_TREE_HERE)); } } - /** - * Initialize the window data - */ - void OnInit() override - { - this->base = _tree_base_by_landscape[_settings_game.game_creation.landscape]; - this->count = _tree_count_by_landscape[_settings_game.game_creation.landscape]; - } - void OnPlaceObjectAbort() override { - this->RaiseButtons(); + this->tree_to_plant = -1; + this->UpdateMode(); } }; +/** + * Make widgets for the current available tree types. + * This does not use a NWID_MATRIX or WWT_MATRIX control as those are more difficult to + * get producing the correct result than dynamically building the widgets is. + * @see NWidgetFunctionType + */ +static NWidgetBase *MakeTreeTypeButtons(int *biggest_index) +{ + const byte type_base = _tree_base_by_landscape[_settings_game.game_creation.landscape]; + const byte type_count = _tree_count_by_landscape[_settings_game.game_creation.landscape]; + + /* Toyland has 9 tree types, which look better in 3x3 than 4x3 */ + const int num_columns = type_count == 9 ? 3 : 4; + const int num_rows = CeilDiv(type_count, num_columns); + byte cur_type = type_base; + + NWidgetVertical *vstack = new NWidgetVertical(NC_EQUALSIZE); + vstack->SetPIP(0, 1, 0); + + for (int row = 0; row < num_rows; row++) { + NWidgetHorizontal *hstack = new NWidgetHorizontal(NC_EQUALSIZE); + hstack->SetPIP(0, 1, 0); + vstack->Add(hstack); + for (int col = 0; col < num_columns; col++) { + if (cur_type > type_base + type_count) break; + NWidgetBackground *button = new NWidgetBackground(WWT_PANEL, COLOUR_GREY, WID_BT_TYPE_BUTTON_FIRST + cur_type); + button->SetDataTip(0x0, STR_PLANT_TREE_TOOLTIP); + hstack->Add(button); + *biggest_index = WID_BT_TYPE_BUTTON_FIRST + cur_type; + cur_type++; + } + } + + return vstack; +} + static const NWidgetPart _nested_build_trees_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), @@ -177,58 +234,16 @@ static const NWidgetPart _nested_build_trees_widgets[] = { NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), EndContainer(), NWidget(WWT_PANEL, COLOUR_DARK_GREEN), - NWidget(NWID_SPACER), SetMinimalSize(0, 2), - NWidget(NWID_HORIZONTAL), - NWidget(NWID_SPACER), SetMinimalSize(2, 0), - NWidget(NWID_VERTICAL), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BT_TYPE_11), SetMinimalSize(34, 46), SetDataTip(0x0, STR_PLANT_TREE_TOOLTIP), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(1, 0), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BT_TYPE_12), SetMinimalSize(34, 46), SetDataTip(0x0, STR_PLANT_TREE_TOOLTIP), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(1, 0), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BT_TYPE_13), SetMinimalSize(34, 46), SetDataTip(0x0, STR_PLANT_TREE_TOOLTIP), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(1, 0), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BT_TYPE_14), SetMinimalSize(34, 46), SetDataTip(0x0, STR_PLANT_TREE_TOOLTIP), - EndContainer(), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 1), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BT_TYPE_21), SetMinimalSize(34, 46), SetDataTip(0x0, STR_PLANT_TREE_TOOLTIP), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(1, 0), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BT_TYPE_22), SetMinimalSize(34, 46), SetDataTip(0x0, STR_PLANT_TREE_TOOLTIP), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(1, 0), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BT_TYPE_23), SetMinimalSize(34, 46), SetDataTip(0x0, STR_PLANT_TREE_TOOLTIP), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(1, 0), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BT_TYPE_24), SetMinimalSize(34, 46), SetDataTip(0x0, STR_PLANT_TREE_TOOLTIP), - EndContainer(), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 1), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BT_TYPE_31), SetMinimalSize(34, 46), SetDataTip(0x0, STR_PLANT_TREE_TOOLTIP), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(1, 0), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BT_TYPE_32), SetMinimalSize(34, 46), SetDataTip(0x0, STR_PLANT_TREE_TOOLTIP), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(1, 0), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BT_TYPE_33), SetMinimalSize(34, 46), SetDataTip(0x0, STR_PLANT_TREE_TOOLTIP), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(1, 0), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BT_TYPE_34), SetMinimalSize(34, 46), SetDataTip(0x0, STR_PLANT_TREE_TOOLTIP), - EndContainer(), + NWidget(NWID_VERTICAL), SetPadding(2), + NWidgetFunction(MakeTreeTypeButtons), + NWidget(NWID_SPACER), SetMinimalSize(0, 1), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BT_TYPE_RANDOM), SetDataTip(STR_TREES_RANDOM_TYPE, STR_TREES_RANDOM_TYPE_TOOLTIP), + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BT_SE_PANE), + NWidget(NWID_VERTICAL), + NWidget(NWID_SPACER), SetMinimalSize(0, 1), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BT_MANY_RANDOM), SetDataTip(STR_TREES_RANDOM_TREES_BUTTON, STR_TREES_RANDOM_TREES_TOOLTIP), EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 1), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BT_TYPE_RANDOM), SetMinimalSize(139, 12), SetDataTip(STR_TREES_RANDOM_TYPE, STR_TREES_RANDOM_TYPE_TOOLTIP), - NWidget(NWID_SPACER), SetMinimalSize(0, 1), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BT_MANY_RANDOM), SetMinimalSize(139, 12), SetDataTip(STR_TREES_RANDOM_TREES_BUTTON, STR_TREES_RANDOM_TREES_TOOLTIP), - NWidget(NWID_SPACER), SetMinimalSize(0, 2), EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(2, 0), EndContainer(), EndContainer(), }; diff --git a/src/widgets/tree_widget.h b/src/widgets/tree_widget.h index 7da9fa4a84..7474667a80 100644 --- a/src/widgets/tree_widget.h +++ b/src/widgets/tree_widget.h @@ -12,20 +12,10 @@ /** Widgets of the #BuildTreesWindow class. */ enum BuildTreesWidgets { - WID_BT_TYPE_11, ///< Tree 1st column 1st row. - WID_BT_TYPE_12, ///< Tree 1st column 2nd row. - WID_BT_TYPE_13, ///< Tree 1st column 3rd row. - WID_BT_TYPE_14, ///< Tree 1st column 4th row. - WID_BT_TYPE_21, ///< Tree 2st column 1st row. - WID_BT_TYPE_22, ///< Tree 2st column 2nd row. - WID_BT_TYPE_23, ///< Tree 2st column 3rd row. - WID_BT_TYPE_24, ///< Tree 2st column 4th row. - WID_BT_TYPE_31, ///< Tree 3st column 1st row. - WID_BT_TYPE_32, ///< Tree 3st column 2nd row. - WID_BT_TYPE_33, ///< Tree 3st column 3rd row. - WID_BT_TYPE_34, ///< Tree 3st column 4th row. WID_BT_TYPE_RANDOM, ///< Button to build random type of tree. + WID_BT_SE_PANE, ///< Selection pane to show/hide scenario editor tools. WID_BT_MANY_RANDOM, ///< Button to build many random trees. + WID_BT_TYPE_BUTTON_FIRST, ///< First tree type selection button. (This must be last in the enum.) }; #endif /* WIDGETS_TREE_WIDGET_H */ From 2d9fa81bd08425d64ab40ff377d9711aae39b6d5 Mon Sep 17 00:00:00 2001 From: Niels Martin Hansen Date: Fri, 26 Jun 2020 21:30:18 +0200 Subject: [PATCH 08/64] Feature: Plant clumps of trees in editor by dragging on the landscape --- src/lang/english.txt | 8 ++++- src/tilehighlight_func.h | 1 + src/tree_cmd.cpp | 47 ++++++++++++++++++++++++- src/tree_gui.cpp | 74 ++++++++++++++++++++++++++++++++++++--- src/viewport.cpp | 27 ++++++++++++-- src/widgets/tree_widget.h | 3 ++ src/window_gui.h | 3 +- 7 files changed, 153 insertions(+), 10 deletions(-) diff --git a/src/lang/english.txt b/src/lang/english.txt index a735eace9d..63f36588a6 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -2542,13 +2542,19 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Size: {G STR_OBJECT_CLASS_LTHS :Lighthouses STR_OBJECT_CLASS_TRNS :Transmitters -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Trees STR_PLANT_TREE_TOOLTIP :{BLACK}Select tree type to plant. If the tile already has a tree, this will add more trees of mixed types independent of the selected type STR_TREES_RANDOM_TYPE :{BLACK}Trees of random type STR_TREES_RANDOM_TYPE_TOOLTIP :{BLACK}Place trees of random type. Shift toggles building/showing cost estimate STR_TREES_RANDOM_TREES_BUTTON :{BLACK}Random Trees STR_TREES_RANDOM_TREES_TOOLTIP :{BLACK}Plant trees randomly throughout the landscape +STR_TREES_MODE_NORMAL_BUTTON :{BLACK}Normal +STR_TREES_MODE_NORMAL_TOOLTIP :{BLACK}Plant single trees by dragging over the landscape. +STR_TREES_MODE_FOREST_SM_BUTTON :{BLACK}Grove +STR_TREES_MODE_FOREST_SM_TOOLTIP :{BLACK}Plant small forests by dragging over the landscape. +STR_TREES_MODE_FOREST_LG_BUTTON :{BLACK}Forest +STR_TREES_MODE_FOREST_LG_TOOLTIP :{BLACK}Plant large forests by dragging over the landscape. # Land generation window (SE) STR_TERRAFORM_TOOLBAR_LAND_GENERATION_CAPTION :{WHITE}Land Generation diff --git a/src/tilehighlight_func.h b/src/tilehighlight_func.h index a6e8a38155..c980931d7d 100644 --- a/src/tilehighlight_func.h +++ b/src/tilehighlight_func.h @@ -22,6 +22,7 @@ void SetObjectToPlace(CursorID icon, PaletteID pal, HighLightStyle mode, WindowC void ResetObjectToPlace(); void VpSelectTilesWithMethod(int x, int y, ViewportPlaceMethod method); +void VpStartDragging(ViewportDragDropSelectionProcess process); void VpStartPlaceSizing(TileIndex tile, ViewportPlaceMethod method, ViewportDragDropSelectionProcess process); void VpSetPresizeRange(TileIndex from, TileIndex to); void VpSetPlaceSizingLimit(int limit); diff --git a/src/tree_cmd.cpp b/src/tree_cmd.cpp index c40df4394c..60eb781f58 100644 --- a/src/tree_cmd.cpp +++ b/src/tree_cmd.cpp @@ -290,6 +290,51 @@ void PlaceTreesRandomly() } } +/** + * Place some trees in a radius around a tile. + * The trees are placed in an quasi-normal distribution around the indicated tile, meaning that while + * the radius does define a square, the distribution inside the square will be roughly circular. + * @note This function the interactive RNG and must only be used in editor and map generation. + * @param tile Tile to place trees around. + * @param treetype Type of trees to place. Must be a valid tree type for the climate. + * @param radius Maximum distance (on each axis) from tile to place trees. + * @param count Maximum number of trees to place. + * @return Number of trees actually placed. + */ +uint PlaceTreeGroupAroundTile(TileIndex tile, TreeType treetype, uint radius, uint count) +{ + assert(treetype < TREE_TOYLAND + TREE_COUNT_TOYLAND); + const bool allow_desert = treetype == TREE_CACTUS; + uint planted = 0; + + for (; count > 0; count--) { + /* Simple quasi-normal distribution with range [-radius; radius) */ + auto mkcoord = [&]() -> int32 { + const uint32 rand = InteractiveRandom(); + const int32 dist = GB(rand, 0, 8) + GB(rand, 8, 8) + GB(rand, 16, 8) + GB(rand, 24, 8); + const int32 scu = dist * radius / 512; + return scu - radius; + }; + const int32 xofs = mkcoord(); + const int32 yofs = mkcoord(); + const TileIndex tile_to_plant = TileAddWrap(tile, xofs, yofs); + if (tile_to_plant != INVALID_TILE) { + if (IsTileType(tile_to_plant, MP_TREES) && GetTreeCount(tile_to_plant) < 4) { + AddTreeCount(tile_to_plant, 1); + SetTreeGrowth(tile_to_plant, 0); + MarkTileDirtyByTile(tile_to_plant, 0); + planted++; + } else if (CanPlantTreesOnTile(tile_to_plant, allow_desert)) { + PlantTreesOnTile(tile_to_plant, treetype, 0, 3); + MarkTileDirtyByTile(tile_to_plant, 0); + planted++; + } + } + } + + return planted; +} + /** * Place new trees. * @@ -349,7 +394,7 @@ CommandCost CmdPlantTree(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 switch (GetTileType(tile)) { case MP_TREES: /* no more space for trees? */ - if (_game_mode != GM_EDITOR && GetTreeCount(tile) == 4) { + if (GetTreeCount(tile) == 4) { msg = STR_ERROR_TREE_ALREADY_HERE; continue; } diff --git a/src/tree_gui.cpp b/src/tree_gui.cpp index 58edf563b2..ee94c35afa 100644 --- a/src/tree_gui.cpp +++ b/src/tree_gui.cpp @@ -14,6 +14,7 @@ #include "company_func.h" #include "company_base.h" #include "command_func.h" +#include "core/random_func.hpp" #include "sound_func.h" #include "strings_func.h" #include "zoom_func.h" @@ -28,6 +29,7 @@ #include "safeguards.h" void PlaceTreesRandomly(); +uint PlaceTreeGroupAroundTile(TileIndex tile, TreeType treetype, uint radius, uint count); /** Tree Sprites with their palettes */ const PalSpriteID tree_sprites[] = { @@ -79,7 +81,14 @@ class BuildTreesWindow : public Window /** Visual Y offset of tree root from the bottom of the tree type buttons */ static const int BUTTON_BOTTOM_OFFSET = 7; + enum PlantingMode { + PM_NORMAL, + PM_FOREST_SM, + PM_FOREST_LG, + }; + int tree_to_plant; ///< Tree number to plant, \c TREE_INVALID for a random tree. + PlantingMode mode; ///< Current mode for planting /** * Update the GUI and enable/disable planting to reflect selected options. @@ -106,15 +115,35 @@ class BuildTreesWindow : public Window this->LowerWidget(WID_BT_TYPE_BUTTON_FIRST + this->tree_to_plant); } + switch (this->mode) { + case PM_NORMAL: this->LowerWidget(WID_BT_MODE_NORMAL); break; + case PM_FOREST_SM: this->LowerWidget(WID_BT_MODE_FOREST_SM); break; + case PM_FOREST_LG: this->LowerWidget(WID_BT_MODE_FOREST_LG); break; + default: NOT_REACHED(); + } + this->SetDirty(); } + void DoPlantForest(TileIndex tile) + { + TreeType treetype = (TreeType)this->tree_to_plant; + if (this->tree_to_plant == TREE_INVALID) { + treetype = (TreeType)(InteractiveRandomRange(_tree_count_by_landscape[_settings_game.game_creation.landscape]) + _tree_base_by_landscape[_settings_game.game_creation.landscape]); + } + const uint radius = this->mode == PM_FOREST_LG ? 12 : 5; + const uint count = this->mode == PM_FOREST_LG ? 12 : 5; + PlaceTreeGroupAroundTile(tile, treetype, radius, count); + } + public: - BuildTreesWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc), tree_to_plant(-1) + BuildTreesWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc), tree_to_plant(-1), mode(PM_NORMAL) { this->InitNested(window_number); ResetObjectToPlace(); + this->LowerWidget(WID_BT_MODE_NORMAL); + /* Show scenario editor tools in editor */ auto *se_tools = this->GetWidget(WID_BT_SE_PANE); if (_game_mode != GM_EDITOR) { @@ -156,6 +185,23 @@ public: MarkWholeScreenDirty(); break; + case WID_BT_MODE_NORMAL: + this->mode = PM_NORMAL; + this->UpdateMode(); + break; + + case WID_BT_MODE_FOREST_SM: + assert(_game_mode == GM_EDITOR); + this->mode = PM_FOREST_SM; + this->UpdateMode(); + break; + + case WID_BT_MODE_FOREST_LG: + assert(_game_mode == GM_EDITOR); + this->mode = PM_FOREST_LG; + this->UpdateMode(); + break; + default: if (widget >= WID_BT_TYPE_BUTTON_FIRST) { const int index = widget - WID_BT_TYPE_BUTTON_FIRST; @@ -168,17 +214,31 @@ public: void OnPlaceObject(Point pt, TileIndex tile) override { - VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_PLANT_TREES); + if (_game_mode != GM_EDITOR && this->mode == PM_NORMAL) { + VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_PLANT_TREES); + } else { + VpStartDragging(DDSP_PLANT_TREES); + } } void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) override { - VpSelectTilesWithMethod(pt.x, pt.y, select_method); + if (_game_mode != GM_EDITOR && this->mode == PM_NORMAL) { + VpSelectTilesWithMethod(pt.x, pt.y, select_method); + } else { + TileIndex tile = TileVirtXY(pt.x, pt.y); + + if (this->mode == PM_NORMAL) { + DoCommandP(tile, this->tree_to_plant, tile, CMD_PLANT_TREE); + } else { + this->DoPlantForest(tile); + } + } } void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) override { - if (pt.x != -1 && select_proc == DDSP_PLANT_TREES) { + if (_game_mode != GM_EDITOR && this->mode == PM_NORMAL && pt.x != -1 && select_proc == DDSP_PLANT_TREES) { DoCommandP(end_tile, this->tree_to_plant, start_tile, CMD_PLANT_TREE | CMD_MSG(STR_ERROR_CAN_T_PLANT_TREE_HERE)); } } @@ -240,6 +300,12 @@ static const NWidgetPart _nested_build_trees_widgets[] = { NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BT_TYPE_RANDOM), SetDataTip(STR_TREES_RANDOM_TYPE, STR_TREES_RANDOM_TYPE_TOOLTIP), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BT_SE_PANE), NWidget(NWID_VERTICAL), + NWidget(NWID_SPACER), SetMinimalSize(0, 1), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BT_MODE_NORMAL), SetFill(1, 0), SetDataTip(STR_TREES_MODE_NORMAL_BUTTON, STR_TREES_MODE_NORMAL_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BT_MODE_FOREST_SM), SetFill(1, 0), SetDataTip(STR_TREES_MODE_FOREST_SM_BUTTON, STR_TREES_MODE_FOREST_SM_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BT_MODE_FOREST_LG), SetFill(1, 0), SetDataTip(STR_TREES_MODE_FOREST_LG_BUTTON, STR_TREES_MODE_FOREST_LG_TOOLTIP), + EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 1), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BT_MANY_RANDOM), SetDataTip(STR_TREES_RANDOM_TREES_BUTTON, STR_TREES_RANDOM_TREES_TOOLTIP), EndContainer(), diff --git a/src/viewport.cpp b/src/viewport.cpp index e9e8d34dac..7c5fd93b3e 100644 --- a/src/viewport.cpp +++ b/src/viewport.cpp @@ -2674,6 +2674,18 @@ void VpStartPlaceSizing(TileIndex tile, ViewportPlaceMethod method, ViewportDrag _special_mouse_mode = WSM_SIZING; } +/** Drag over the map while holding the left mouse down. */ +void VpStartDragging(ViewportDragDropSelectionProcess process) +{ + _thd.select_method = VPM_X_AND_Y; + _thd.select_proc = process; + _thd.selstart.x = 0; + _thd.selstart.y = 0; + _thd.next_drawstyle = HT_RECT; + + _special_mouse_mode = WSM_DRAGGING; +} + void VpSetPlaceSizingLimit(int limit) { _thd.sizelimit = limit; @@ -3283,7 +3295,7 @@ calc_heightdiff_single_direction:; */ EventState VpHandlePlaceSizingDrag() { - if (_special_mouse_mode != WSM_SIZING) return ES_NOT_HANDLED; + if (_special_mouse_mode != WSM_SIZING && _special_mouse_mode != WSM_DRAGGING) return ES_NOT_HANDLED; /* stop drag mode if the window has been closed */ Window *w = _thd.GetCallbackWnd(); @@ -3294,13 +3306,22 @@ EventState VpHandlePlaceSizingDrag() /* while dragging execute the drag procedure of the corresponding window (mostly VpSelectTilesWithMethod() ) */ if (_left_button_down) { + if (_special_mouse_mode == WSM_DRAGGING) { + /* Only register a drag event when the mouse moved. */ + if (_thd.new_pos.x == _thd.selstart.x && _thd.new_pos.y == _thd.selstart.y) return ES_HANDLED; + _thd.selstart.x = _thd.new_pos.x; + _thd.selstart.y = _thd.new_pos.y; + } + w->OnPlaceDrag(_thd.select_method, _thd.select_proc, GetTileBelowCursor()); return ES_HANDLED; } - /* mouse button released.. - * keep the selected tool, but reset it to the original mode. */ + /* Mouse button released. */ _special_mouse_mode = WSM_NONE; + if (_special_mouse_mode == WSM_DRAGGING) return ES_HANDLED; + + /* Keep the selected tool, but reset it to the original mode. */ HighLightStyle others = _thd.place_mode & ~(HT_DRAG_MASK | HT_DIR_MASK); if ((_thd.next_drawstyle & HT_DRAG_MASK) == HT_RECT) { _thd.place_mode = HT_RECT | others; diff --git a/src/widgets/tree_widget.h b/src/widgets/tree_widget.h index 7474667a80..2cfc38ad40 100644 --- a/src/widgets/tree_widget.h +++ b/src/widgets/tree_widget.h @@ -14,6 +14,9 @@ enum BuildTreesWidgets { WID_BT_TYPE_RANDOM, ///< Button to build random type of tree. WID_BT_SE_PANE, ///< Selection pane to show/hide scenario editor tools. + WID_BT_MODE_NORMAL, ///< Select normal/rectangle planting mode. + WID_BT_MODE_FOREST_SM, ///< Select small forest planting mode. + WID_BT_MODE_FOREST_LG, ///< Select large forest planting mode. WID_BT_MANY_RANDOM, ///< Button to build many random trees. WID_BT_TYPE_BUTTON_FIRST, ///< First tree type selection button. (This must be last in the enum.) }; diff --git a/src/window_gui.h b/src/window_gui.h index b389db5a6e..b03f5bbcad 100644 --- a/src/window_gui.h +++ b/src/window_gui.h @@ -903,9 +903,10 @@ extern bool _mouse_hovering; /** Mouse modes. */ enum SpecialMouseMode { WSM_NONE, ///< No special mouse mode. - WSM_DRAGDROP, ///< Dragging an object. + WSM_DRAGDROP, ///< Drag&drop an object. WSM_SIZING, ///< Sizing mode. WSM_PRESIZE, ///< Presizing mode (docks, tunnels). + WSM_DRAGGING, ///< Dragging mode (trees). }; extern SpecialMouseMode _special_mouse_mode; From 5a5d613ee38ea90f235ec7d8c0388bbb52707155 Mon Sep 17 00:00:00 2001 From: Michael Lutz Date: Fri, 25 Dec 2020 21:55:13 +0100 Subject: [PATCH 09/64] Change: Disable changing the inflation setting in network games. --- src/table/settings.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/src/table/settings.ini b/src/table/settings.ini index 320786751a..b75dd0ff28 100644 --- a/src/table/settings.ini +++ b/src/table/settings.ini @@ -1283,6 +1283,7 @@ proc = DeleteSelectStationWindow [SDT_BOOL] base = GameSettings var = economy.inflation +guiflags = SGF_NO_NETWORK def = true str = STR_CONFIG_SETTING_INFLATION strhelp = STR_CONFIG_SETTING_INFLATION_HELPTEXT From 1478fa93b344fc25000725dd143109e4def24f0b Mon Sep 17 00:00:00 2001 From: Michael Lutz Date: Fri, 25 Dec 2020 12:36:13 +0100 Subject: [PATCH 10/64] Add: [NewGRF] Patch flag to test if inflation is on or off. --- src/newgrf.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/newgrf.cpp b/src/newgrf.cpp index aa48022265..097e68ae22 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -8389,7 +8389,8 @@ static void InitializeGRFSpecial() | (1 << 0x1E) // variablerunningcosts | (1 << 0x1F); // any switch is on - _ttdpatch_flags[4] = (1 << 0x00); // larger persistent storage + _ttdpatch_flags[4] = (1 << 0x00) // larger persistent storage + | ((_settings_game.economy.inflation ? 1 : 0) << 0x01); // inflation is on } /** Reset and clear all NewGRF stations */ From d8605ad18da2a00fceb72b38325374b341ac6f16 Mon Sep 17 00:00:00 2001 From: glx22 Date: Sun, 27 Dec 2020 00:13:56 +0100 Subject: [PATCH 11/64] Codechange: Replace FOR_VEHICLE_ORDERS with range-based for loops --- src/autoreplace_cmd.cpp | 3 +- src/industry_cmd.cpp | 3 +- src/order_backup.cpp | 3 +- src/order_base.h | 2 -- src/order_cmd.cpp | 32 ++++++----------- src/order_gui.cpp | 3 +- src/saveload/afterload.cpp | 3 +- src/script/api/script_vehiclelist.cpp | 8 ++--- src/station_cmd.cpp | 3 +- src/vehicle_base.h | 49 +++++++++++++++++++++++++++ src/vehiclelist.cpp | 8 ++--- 11 files changed, 69 insertions(+), 48 deletions(-) diff --git a/src/autoreplace_cmd.cpp b/src/autoreplace_cmd.cpp index 4b444ae196..e3639742ff 100644 --- a/src/autoreplace_cmd.cpp +++ b/src/autoreplace_cmd.cpp @@ -179,9 +179,8 @@ static bool VerifyAutoreplaceRefitForOrders(const Vehicle *v, EngineID engine_ty CargoTypes union_refit_mask_a = GetUnionOfArticulatedRefitMasks(v->engine_type, false); CargoTypes union_refit_mask_b = GetUnionOfArticulatedRefitMasks(engine_type, false); - const Order *o; const Vehicle *u = (v->type == VEH_TRAIN) ? v->First() : v; - FOR_VEHICLE_ORDERS(u, o) { + for (const Order *o : u->Orders()) { if (!o->IsRefit() || o->IsAutoRefit()) continue; CargoID cargo_type = o->GetRefitCargo(); diff --git a/src/industry_cmd.cpp b/src/industry_cmd.cpp index 92741e3f69..816146212f 100644 --- a/src/industry_cmd.cpp +++ b/src/industry_cmd.cpp @@ -2609,8 +2609,7 @@ static int WhoCanServiceIndustry(Industry *ind) * We cannot check the first of shared orders only, since the first vehicle in such a chain * may have a different cargo type. */ - const Order *o; - FOR_VEHICLE_ORDERS(v, o) { + for (const Order *o : v->Orders()) { if (o->IsType(OT_GOTO_STATION) && !(o->GetUnloadType() & OUFB_TRANSFER)) { /* Vehicle visits a station to load or unload */ Station *st = Station::Get(o->GetDestination()); diff --git a/src/order_backup.cpp b/src/order_backup.cpp index d537d8ce5c..000df56540 100644 --- a/src/order_backup.cpp +++ b/src/order_backup.cpp @@ -56,8 +56,7 @@ OrderBackup::OrderBackup(const Vehicle *v, uint32 user) Order **tail = &this->orders; /* Count the number of orders */ - const Order *order; - FOR_VEHICLE_ORDERS(v, order) { + for (const Order *order : v->Orders()) { Order *copy = new Order(); copy->AssignOrder(*order); *tail = copy; diff --git a/src/order_base.h b/src/order_base.h index ba4959c0f3..923e67d423 100644 --- a/src/order_base.h +++ b/src/order_base.h @@ -392,6 +392,4 @@ public: void DebugCheckSanity() const; }; -#define FOR_VEHICLE_ORDERS(v, order) for (order = (v->orders.list == nullptr) ? nullptr : v->orders.list->GetFirstOrder(); order != nullptr; order = order->next) - #endif /* ORDER_BASE_H */ diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp index 1e9e8f2f3b..c9fa919890 100644 --- a/src/order_cmd.cpp +++ b/src/order_cmd.cpp @@ -969,8 +969,7 @@ void InsertOrder(Vehicle *v, Order *new_o, VehicleOrderID sel_ord) /* As we insert an order, the order to skip to will be 'wrong'. */ VehicleOrderID cur_order_id = 0; - Order *order; - FOR_VEHICLE_ORDERS(v, order) { + for (Order *order : v->Orders()) { if (order->IsType(OT_CONDITIONAL)) { VehicleOrderID order_id = order->GetConditionSkipToOrder(); if (order_id >= sel_ord) { @@ -1090,8 +1089,7 @@ void DeleteOrder(Vehicle *v, VehicleOrderID sel_ord) /* As we delete an order, the order to skip to will be 'wrong'. */ VehicleOrderID cur_order_id = 0; - Order *order = nullptr; - FOR_VEHICLE_ORDERS(v, order) { + for (Order *order : v->Orders()) { if (order->IsType(OT_CONDITIONAL)) { VehicleOrderID order_id = order->GetConditionSkipToOrder(); if (order_id >= sel_ord) { @@ -1225,8 +1223,7 @@ CommandCost CmdMoveOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 } /* As we move an order, the order to skip to will be 'wrong'. */ - Order *order; - FOR_VEHICLE_ORDERS(v, order) { + for (Order *order : v->Orders()) { if (order->IsType(OT_CONDITIONAL)) { VehicleOrderID order_id = order->GetConditionSkipToOrder(); if (order_id == moving_order) { @@ -1560,9 +1557,7 @@ CommandCost CmdCloneOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 /* Is the vehicle already in the shared list? */ if (src->FirstShared() == dst->FirstShared()) return CMD_ERROR; - const Order *order; - - FOR_VEHICLE_ORDERS(src, order) { + for (const Order *order : src->Orders()) { if (!OrderGoesToStation(dst, order)) continue; /* Allow copying unreachable destinations if they were already unreachable for the source. @@ -1613,8 +1608,7 @@ CommandCost CmdCloneOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 /* Trucks can't copy all the orders from busses (and visa versa), * and neither can helicopters and aircraft. */ - const Order *order; - FOR_VEHICLE_ORDERS(src, order) { + for (const Order *order : src->Orders()) { if (OrderGoesToStation(dst, order) && !CanVehicleUseStation(dst, Station::Get(order->GetDestination()))) { return_cmd_error(STR_ERROR_CAN_T_COPY_SHARE_ORDER); @@ -1632,7 +1626,6 @@ CommandCost CmdCloneOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 } if (flags & DC_EXEC) { - const Order *order; Order *first = nullptr; Order **order_dst; @@ -1642,7 +1635,7 @@ CommandCost CmdCloneOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 DeleteVehicleOrders(dst, true, dst->GetNumOrders() != src->GetNumOrders()); order_dst = &first; - FOR_VEHICLE_ORDERS(src, order) { + for (const Order *order : src->Orders()) { *order_dst = new Order(); (*order_dst)->AssignOrder(*order); order_dst = &(*order_dst)->next; @@ -1749,13 +1742,12 @@ void CheckOrders(const Vehicle *v) /* Only check every 20 days, so that we don't flood the message log */ if (v->owner == _local_company && v->day_counter % 20 == 0) { - const Order *order; StringID message = INVALID_STRING_ID; /* Check the order list */ int n_st = 0; - FOR_VEHICLE_ORDERS(v, order) { + for (const Order *order : v->Orders()) { /* Dummy order? */ if (order->IsType(OT_DUMMY)) { message = STR_NEWS_VEHICLE_HAS_VOID_ORDER; @@ -1829,7 +1821,7 @@ void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination, bool /* Clear the order from the order-list */ int id = -1; - FOR_VEHICLE_ORDERS(v, order) { + for (Order *order : v->Orders()) { id++; restart: @@ -1879,9 +1871,7 @@ restart: */ bool Vehicle::HasDepotOrder() const { - const Order *order; - - FOR_VEHICLE_ORDERS(this, order) { + for (const Order *order : this->Orders()) { if (order->IsType(OT_GOTO_DEPOT)) return true; } @@ -1940,9 +1930,7 @@ uint16 GetServiceIntervalClamped(uint interval, bool ispercent) */ static bool CheckForValidOrders(const Vehicle *v) { - const Order *order; - - FOR_VEHICLE_ORDERS(v, order) { + for (const Order *order : v->Orders()) { switch (order->GetType()) { case OT_GOTO_STATION: case OT_GOTO_DEPOT: diff --git a/src/order_gui.cpp b/src/order_gui.cpp index 4edf994f78..5529a8331e 100644 --- a/src/order_gui.cpp +++ b/src/order_gui.cpp @@ -793,8 +793,7 @@ public: if (_settings_client.gui.quick_goto && v->owner == _local_company) { /* If there are less than 2 station, make Go To active. */ int station_orders = 0; - const Order *order; - FOR_VEHICLE_ORDERS(v, order) { + for(const Order *order : v->Orders()) { if (order->IsType(OT_GOTO_STATION)) station_orders++; } diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index c617348d73..4eab99c883 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -1733,8 +1733,7 @@ bool AfterLoadGame() v->current_order.ConvertFromOldSavegame(); if (v->type == VEH_ROAD && v->IsPrimaryVehicle() && v->FirstShared() == v) { - Order* order; - FOR_VEHICLE_ORDERS(v, order) order->SetNonStopType(ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS); + for (Order *order : v->Orders()) order->SetNonStopType(ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS); } } } else if (IsSavegameVersionBefore(SLV_94)) { diff --git a/src/script/api/script_vehiclelist.cpp b/src/script/api/script_vehiclelist.cpp index 58c03ff9a9..3a4d2d135b 100644 --- a/src/script/api/script_vehiclelist.cpp +++ b/src/script/api/script_vehiclelist.cpp @@ -31,9 +31,7 @@ ScriptVehicleList_Station::ScriptVehicleList_Station(StationID station_id) for (const Vehicle *v : Vehicle::Iterate()) { if ((v->owner == ScriptObject::GetCompany() || ScriptObject::GetCompany() == OWNER_DEITY) && v->IsPrimaryVehicle()) { - const Order *order; - - FOR_VEHICLE_ORDERS(v, order) { + for (const Order *order : v->Orders()) { if ((order->IsType(OT_GOTO_STATION) || order->IsType(OT_GOTO_WAYPOINT)) && order->GetDestination() == station_id) { this->AddItem(v->index); break; @@ -81,9 +79,7 @@ ScriptVehicleList_Depot::ScriptVehicleList_Depot(TileIndex tile) for (const Vehicle *v : Vehicle::Iterate()) { if ((v->owner == ScriptObject::GetCompany() || ScriptObject::GetCompany() == OWNER_DEITY) && v->IsPrimaryVehicle() && v->type == type) { - const Order *order; - - FOR_VEHICLE_ORDERS(v, order) { + for (const Order *order : v->Orders()) { if (order->IsType(OT_GOTO_DEPOT) && order->GetDestination() == dest) { this->AddItem(v->index); break; diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index cd56dcb698..64a7adca8e 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -2486,8 +2486,7 @@ bool HasStationInUse(StationID station, bool include_company, CompanyID company) { for (const Vehicle *v : Vehicle::Iterate()) { if ((v->owner == company) == include_company) { - const Order *order; - FOR_VEHICLE_ORDERS(v, order) { + for (const Order *order : v->Orders()) { if ((order->IsType(OT_GOTO_STATION) || order->IsType(OT_GOTO_WAYPOINT)) && order->GetDestination() == station) { return true; } diff --git a/src/vehicle_base.h b/src/vehicle_base.h index bc72c6bbfd..019c94a29a 100644 --- a/src/vehicle_base.h +++ b/src/vehicle_base.h @@ -969,6 +969,55 @@ public: return v; } + + /** + * Iterator to iterate orders + * Supports deletion of current order + */ + struct OrderIterator { + typedef Order value_type; + typedef Order* pointer; + typedef Order& reference; + typedef size_t difference_type; + typedef std::forward_iterator_tag iterator_category; + + explicit OrderIterator(OrderList *list) : list(list), prev(nullptr) + { + this->order = (this->list == nullptr) ? nullptr : this->list->GetFirstOrder(); + } + + bool operator==(const OrderIterator &other) const { return this->order == other.order; } + bool operator!=(const OrderIterator &other) const { return !(*this == other); } + Order * operator*() const { return this->order; } + OrderIterator & operator++() + { + this->prev = (this->prev == nullptr) ? this->list->GetFirstOrder() : this->prev->next; + this->order = (this->prev == nullptr) ? nullptr : this->prev->next; + return *this; + } + + private: + OrderList *list; + Order *order; + Order *prev; + }; + + /** + * Iterable ensemble of orders + */ + struct IterateWrapper { + OrderList *list; + IterateWrapper(OrderList *list = nullptr) : list(list) {} + OrderIterator begin() { return OrderIterator(this->list); } + OrderIterator end() { return OrderIterator(nullptr); } + bool empty() { return this->begin() == this->end(); } + }; + + /** + * Returns an iterable ensemble of orders of a vehicle + * @return an iterable ensemble of orders of a vehicle + */ + IterateWrapper Orders() const { return IterateWrapper(this->orders.list); } }; /** diff --git a/src/vehiclelist.cpp b/src/vehiclelist.cpp index de37e3abae..79df540cf4 100644 --- a/src/vehiclelist.cpp +++ b/src/vehiclelist.cpp @@ -118,9 +118,7 @@ bool GenerateVehicleSortList(VehicleList *list, const VehicleListIdentifier &vli case VL_STATION_LIST: for (const Vehicle *v : Vehicle::Iterate()) { if (v->type == vli.vtype && v->IsPrimaryVehicle()) { - const Order *order; - - FOR_VEHICLE_ORDERS(v, order) { + for (const Order *order : v->Orders()) { if ((order->IsType(OT_GOTO_STATION) || order->IsType(OT_GOTO_WAYPOINT) || order->IsType(OT_IMPLICIT)) && order->GetDestination() == vli.index) { list->push_back(v); @@ -165,9 +163,7 @@ bool GenerateVehicleSortList(VehicleList *list, const VehicleListIdentifier &vli case VL_DEPOT_LIST: for (const Vehicle *v : Vehicle::Iterate()) { if (v->type == vli.vtype && v->IsPrimaryVehicle()) { - const Order *order; - - FOR_VEHICLE_ORDERS(v, order) { + for (const Order *order : v->Orders()) { if (order->IsType(OT_GOTO_DEPOT) && !(order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) && order->GetDestination() == vli.index) { list->push_back(v); break; From 52f3abba6ef2e5a69b58cf71fdcdaa75d603b062 Mon Sep 17 00:00:00 2001 From: Charles Pigott Date: Sun, 27 Dec 2020 09:56:43 +0000 Subject: [PATCH 12/64] Cleanup: Remove unnecessary assert_tcompile macro --- src/cargopacket.cpp | 4 ++-- src/cmd_helper.h | 6 +++--- src/stdafx.h | 7 +------ 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/cargopacket.cpp b/src/cargopacket.cpp index f5f7c0c033..08b72ec462 100644 --- a/src/cargopacket.cpp +++ b/src/cargopacket.cpp @@ -556,8 +556,8 @@ void VehicleCargoList::InvalidateCache() template uint VehicleCargoList::Reassign(uint max_move, TileOrStationID) { - assert_tcompile(Tfrom != MTA_TRANSFER && Tto != MTA_TRANSFER); - assert_tcompile(Tfrom - Tto == 1 || Tto - Tfrom == 1); + assert_compile(Tfrom != MTA_TRANSFER && Tto != MTA_TRANSFER); + assert_compile(Tfrom - Tto == 1 || Tto - Tfrom == 1); max_move = min(this->action_counts[Tfrom], max_move); this->action_counts[Tfrom] -= max_move; this->action_counts[Tto] += max_move; diff --git a/src/cmd_helper.h b/src/cmd_helper.h index ee5d445c28..a505c1fd8b 100644 --- a/src/cmd_helper.h +++ b/src/cmd_helper.h @@ -24,9 +24,9 @@ template static inline T Extract(U v) { /* Check if there are enough bits in v */ - assert_tcompile(N == EnumPropsT::num_bits); - assert_tcompile(S + N <= sizeof(U) * 8); - assert_tcompile(EnumPropsT::end <= (1 << N)); + assert_compile(N == EnumPropsT::num_bits); + assert_compile(S + N <= sizeof(U) * 8); + assert_compile(EnumPropsT::end <= (1 << N)); U masked = GB(v, S, N); return IsInsideMM(masked, EnumPropsT::begin, EnumPropsT::end) ? (T)masked : EnumPropsT::invalid; } diff --git a/src/stdafx.h b/src/stdafx.h index c421c55aa2..5b9281a28c 100644 --- a/src/stdafx.h +++ b/src/stdafx.h @@ -348,19 +348,14 @@ typedef unsigned char byte; # define PERSONAL_DIR "" #endif -/* Compile time assertions. Prefer c++0x static_assert(). - * Older compilers cannot evaluate some expressions at compile time, - * typically when templates are involved, try assert_tcompile() in those cases. */ +/* Compile time assertions. Prefer c++0x static_assert(). */ #if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1600) # define assert_compile(expr) static_assert(expr, #expr ) -# define assert_tcompile(expr) assert_compile(expr) #elif defined(__OS2__) /* Disabled for OS/2 */ # define assert_compile(expr) -# define assert_tcompile(expr) assert_compile(expr) #else # define assert_compile(expr) typedef int __ct_assert__[1 - 2 * !(expr)] -# define assert_tcompile(expr) assert(expr) #endif /* Check if the types have the bitsizes like we are using them */ From eb74179c6d66921d2946e4a93e41a5de0af4a4ac Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Mon, 5 Sep 2016 01:15:09 +0100 Subject: [PATCH 13/64] Codechange: Unconditionally use static_assert We're well past having to support non-C++11 compliant compilers now. --- src/stdafx.h | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/stdafx.h b/src/stdafx.h index 5b9281a28c..9b9f4c6a94 100644 --- a/src/stdafx.h +++ b/src/stdafx.h @@ -348,15 +348,7 @@ typedef unsigned char byte; # define PERSONAL_DIR "" #endif -/* Compile time assertions. Prefer c++0x static_assert(). */ -#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1600) -# define assert_compile(expr) static_assert(expr, #expr ) -#elif defined(__OS2__) - /* Disabled for OS/2 */ -# define assert_compile(expr) -#else -# define assert_compile(expr) typedef int __ct_assert__[1 - 2 * !(expr)] -#endif +#define assert_compile(expr) static_assert(expr, #expr) /* Check if the types have the bitsizes like we are using them */ assert_compile(sizeof(uint64) == 8); From 5cf28be742581d335ecb0c270e8039ee8ed9ccf0 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Mon, 5 Sep 2016 01:18:09 +0100 Subject: [PATCH 14/64] Codechange: Add support for verbose asserts --- src/openttd.cpp | 2 +- src/stdafx.h | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/openttd.cpp b/src/openttd.cpp index e4fcf40e94..33f65314d1 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -129,7 +129,7 @@ void CDECL usererror(const char *s, ...) void CDECL error(const char *s, ...) { va_list va; - char buf[512]; + char buf[2048]; va_start(va, s); vseprintf(buf, lastof(buf), s, va); diff --git a/src/stdafx.h b/src/stdafx.h index 9b9f4c6a94..00dd1322ac 100644 --- a/src/stdafx.h +++ b/src/stdafx.h @@ -430,6 +430,9 @@ void NORETURN CDECL error(const char *str, ...) WARN_FORMAT(1, 2); /* Asserts are enabled if NDEBUG isn't defined or WITH_ASSERT is defined. */ #if !defined(NDEBUG) || defined(WITH_ASSERT) # define OTTD_ASSERT +# define assert_msg(expression, msg, ...) if (!(expression)) error("Assertion failed at line %i of %s: %s\n\t" msg, __LINE__, __FILE__, #expression, __VA_ARGS__); +#else +# define assert_msg(expression, msg, ...) #endif #if defined(OPENBSD) From fc52d3df5010994083c858fef01fa2926de951ad Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Thu, 10 Mar 2016 00:13:58 +0000 Subject: [PATCH 15/64] Codechange: Use likely/__builtin_expect for assertion macros --- src/stdafx.h | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/stdafx.h b/src/stdafx.h index 00dd1322ac..332f1a3eea 100644 --- a/src/stdafx.h +++ b/src/stdafx.h @@ -417,6 +417,14 @@ assert_compile(SIZE_MAX >= UINT32_MAX); # define CloseConnection OTTD_CloseConnection #endif /* __APPLE__ */ +#ifdef __GNUC__ +# define likely(x) __builtin_expect(!!(x), 1) +# define unlikely(x) __builtin_expect(!!(x), 0) +#else +# define likely(x) (x) +# define unlikely(x) (x) +#endif + void NORETURN CDECL usererror(const char *str, ...) WARN_FORMAT(1, 2); void NORETURN CDECL error(const char *str, ...) WARN_FORMAT(1, 2); #define NOT_REACHED() error("NOT_REACHED triggered at line %i of %s", __LINE__, __FILE__) @@ -424,13 +432,13 @@ void NORETURN CDECL error(const char *str, ...) WARN_FORMAT(1, 2); /* For non-debug builds with assertions enabled use the special assertion handler. */ #if defined(NDEBUG) && defined(WITH_ASSERT) # undef assert -# define assert(expression) if (!(expression)) error("Assertion failed at line %i of %s: %s", __LINE__, __FILE__, #expression); +# define assert(expression) if (unlikely(!(expression))) error("Assertion failed at line %i of %s: %s", __LINE__, __FILE__, #expression); #endif /* Asserts are enabled if NDEBUG isn't defined or WITH_ASSERT is defined. */ #if !defined(NDEBUG) || defined(WITH_ASSERT) # define OTTD_ASSERT -# define assert_msg(expression, msg, ...) if (!(expression)) error("Assertion failed at line %i of %s: %s\n\t" msg, __LINE__, __FILE__, #expression, __VA_ARGS__); +# define assert_msg(expression, msg, ...) if (unlikely(!(expression))) error("Assertion failed at line %i of %s: %s\n\t" msg, __LINE__, __FILE__, #expression, __VA_ARGS__); #else # define assert_msg(expression, msg, ...) #endif From 0e017f62330c09bc8c5a69f3e8424645726de560 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Thu, 8 Sep 2016 18:38:53 +0100 Subject: [PATCH 16/64] Codechange: Enable FINAL, (un)likely, __attribute__ when building with clang --- src/stdafx.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/stdafx.h b/src/stdafx.h index 332f1a3eea..c99d7a2771 100644 --- a/src/stdafx.h +++ b/src/stdafx.h @@ -111,7 +111,7 @@ #endif /* Stuff for GCC */ -#if defined(__GNUC__) +#if defined(__GNUC__) || defined(__clang__) # define NORETURN __attribute__ ((noreturn)) # define CDECL # define __int64 long long @@ -134,7 +134,7 @@ # else # define FALLTHROUGH # endif -#endif /* __GNUC__ */ +#endif /* __GNUC__ || __clang__ */ #if defined(__WATCOMC__) # define NORETURN @@ -417,13 +417,13 @@ assert_compile(SIZE_MAX >= UINT32_MAX); # define CloseConnection OTTD_CloseConnection #endif /* __APPLE__ */ -#ifdef __GNUC__ +#if defined(__GNUC__) || defined(__clang__) # define likely(x) __builtin_expect(!!(x), 1) # define unlikely(x) __builtin_expect(!!(x), 0) #else # define likely(x) (x) # define unlikely(x) (x) -#endif +#endif /* __GNUC__ || __clang__ */ void NORETURN CDECL usererror(const char *str, ...) WARN_FORMAT(1, 2); void NORETURN CDECL error(const char *str, ...) WARN_FORMAT(1, 2); From 46ff7d918b09878b6fe6bf504112425ad2ba49c2 Mon Sep 17 00:00:00 2001 From: cirdan Date: Sat, 8 Dec 2012 19:01:56 +0100 Subject: [PATCH 17/64] Cleanup: Remove save-only autolength flag from economy chunk handlers CH_AUTO_LENGTH is only used when saving chunks; it makes no sense to set it for chunks without a save handler. --- src/saveload/economy_sl.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/saveload/economy_sl.cpp b/src/saveload/economy_sl.cpp index 637d2529c6..a7d1819468 100644 --- a/src/saveload/economy_sl.cpp +++ b/src/saveload/economy_sl.cpp @@ -98,7 +98,7 @@ static void Ptrs_CAPY() extern const ChunkHandler _economy_chunk_handlers[] = { { 'CAPY', Save_CAPY, Load_CAPY, Ptrs_CAPY, nullptr, CH_ARRAY}, - { 'PRIC', nullptr, Load_PRIC, nullptr, nullptr, CH_RIFF | CH_AUTO_LENGTH}, - { 'CAPR', nullptr, Load_CAPR, nullptr, nullptr, CH_RIFF | CH_AUTO_LENGTH}, + { 'PRIC', nullptr, Load_PRIC, nullptr, nullptr, CH_RIFF }, + { 'CAPR', nullptr, Load_CAPR, nullptr, nullptr, CH_RIFF }, { 'ECMY', Save_ECMY, Load_ECMY, nullptr, nullptr, CH_RIFF | CH_LAST}, }; From 395a5d9991b500c681ff384f8d3b4e153e687abb Mon Sep 17 00:00:00 2001 From: cirdan Date: Sat, 8 Dec 2012 19:21:55 +0100 Subject: [PATCH 18/64] Cleanup: Remove unused ChunkType flag CH_AUTO_LENGTH CH_AUTO_LENGTH is no longer used anywhere, so remove all code that depends on it. --- src/saveload/saveload.cpp | 32 -------------------------------- src/saveload/saveload.h | 1 - 2 files changed, 33 deletions(-) diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp index 4f3b7e9914..3471a8295e 100644 --- a/src/saveload/saveload.cpp +++ b/src/saveload/saveload.cpp @@ -1753,32 +1753,6 @@ static void SlLoadCheckChunk(const ChunkHandler *ch) } } -/** - * Stub Chunk handlers to only calculate length and do nothing else. - * The intended chunk handler that should be called. - */ -static ChunkSaveLoadProc *_stub_save_proc; - -/** - * Stub Chunk handlers to only calculate length and do nothing else. - * Actually call the intended chunk handler. - * @param arg ignored parameter. - */ -static inline void SlStubSaveProc2(void *arg) -{ - _stub_save_proc(); -} - -/** - * Stub Chunk handlers to only calculate length and do nothing else. - * Call SlAutoLenth with our stub save proc that will eventually - * call the intended chunk handler. - */ -static void SlStubSaveProc() -{ - SlAutolength(SlStubSaveProc2, nullptr); -} - /** * Save a chunk of data (eg. vehicles, stations, etc.). Each chunk is * prefixed by an ID identifying it, followed by data, and terminator where appropriate @@ -1794,12 +1768,6 @@ static void SlSaveChunk(const ChunkHandler *ch) SlWriteUint32(ch->id); DEBUG(sl, 2, "Saving chunk %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id); - if (ch->flags & CH_AUTO_LENGTH) { - /* Need to calculate the length. Solve that by calling SlAutoLength in the save_proc. */ - _stub_save_proc = proc; - proc = SlStubSaveProc; - } - _sl.block_mode = ch->flags & CH_TYPE_MASK; switch (ch->flags & CH_TYPE_MASK) { case CH_RIFF: diff --git a/src/saveload/saveload.h b/src/saveload/saveload.h index 58a2919326..a153b36301 100644 --- a/src/saveload/saveload.h +++ b/src/saveload/saveload.h @@ -409,7 +409,6 @@ enum ChunkType { CH_SPARSE_ARRAY = 2, CH_TYPE_MASK = 3, CH_LAST = 8, ///< Last chunk in this array. - CH_AUTO_LENGTH = 16, }; /** From 860c270c73048b4930ac8cbebcd60be746eb9782 Mon Sep 17 00:00:00 2001 From: Charles Pigott Date: Sun, 27 Dec 2020 10:44:22 +0000 Subject: [PATCH 19/64] Codechange: Replace assert_compile macro with static_assert --- src/blitter/32bpp_sse2.hpp | 2 +- src/cargomonitor.h | 4 ++-- src/cargopacket.cpp | 4 ++-- src/cheat_gui.cpp | 2 +- src/cmd_helper.h | 6 +++--- src/command.cpp | 2 +- src/company_gui.cpp | 2 +- src/company_manager_face.h | 2 +- src/console_cmds.cpp | 2 +- src/core/math_func.hpp | 2 +- src/core/pool_type.hpp | 2 +- src/economy.cpp | 2 +- src/effectvehicle.cpp | 6 +++--- src/engine.cpp | 2 +- src/fileio.cpp | 2 +- src/gamelog.cpp | 4 ++-- src/genworld_gui.cpp | 6 +++--- src/gfx.cpp | 2 +- src/gfx_type.h | 2 +- src/gfxinit.cpp | 2 +- src/goal.cpp | 2 +- src/graph_gui.cpp | 4 ++-- src/ground_vehicle.cpp | 4 ++-- src/house.h | 2 +- src/industry_gui.cpp | 6 +++--- src/landscape.cpp | 2 +- src/language.h | 2 +- src/linkgraph/linkgraph_gui.cpp | 2 +- src/map_type.h | 2 +- src/misc/fixedsizearray.hpp | 2 +- src/misc_gui.cpp | 2 +- src/music.cpp | 2 +- src/network/core/os_abstraction.h | 4 ++-- src/network/core/tcp_admin.cpp | 8 ++++---- src/network/network.cpp | 10 +++++----- src/network/network_admin.cpp | 4 ++-- src/network/network_chat_gui.cpp | 2 +- src/network/network_client.cpp | 4 ++-- src/network/network_server.cpp | 10 +++++----- src/newgrf.cpp | 4 ++-- src/newgrf_airporttiles.cpp | 2 +- src/newgrf_engine.cpp | 2 +- src/newgrf_station.cpp | 6 +++--- src/newgrf_storage.h | 2 +- src/news_gui.cpp | 2 +- src/openttd.cpp | 2 +- src/order_cmd.cpp | 4 ++-- src/rail_cmd.cpp | 2 +- src/road_cmd.cpp | 2 +- src/roadveh_cmd.cpp | 2 +- src/saveload/afterload.cpp | 2 +- src/saveload/gamelog_sl.cpp | 2 +- src/saveload/oldloader.cpp | 2 +- src/saveload/oldloader.h | 2 +- src/saveload/saveload.cpp | 2 +- src/screenshot.cpp | 8 ++++---- src/settings_gui.cpp | 2 +- src/signal.cpp | 2 +- src/sound.cpp | 2 +- src/spritecache.cpp | 4 ++-- src/stdafx.h | 12 +++++------- src/strings_func.h | 2 +- src/table/airport_defaults.h | 2 +- src/table/airporttiles.h | 2 +- src/table/newgrf_debug_data.h | 2 +- src/table/pricebase.h | 2 +- src/table/sprites.h | 10 +++++----- src/table/station_land.h | 2 +- src/table/town_land.h | 4 ++-- src/table/train_cmd.h | 6 +++--- src/textfile_gui.cpp | 2 +- src/town_cmd.cpp | 2 +- src/vehicle.cpp | 8 ++++---- src/vehicle_gui.cpp | 16 ++++++++-------- src/vehiclelist.cpp | 2 +- src/video/dedicated_v.cpp | 2 +- src/viewport_sprite_sorter_sse4.cpp | 2 +- 77 files changed, 133 insertions(+), 135 deletions(-) diff --git a/src/blitter/32bpp_sse2.hpp b/src/blitter/32bpp_sse2.hpp index 4103eed487..12105516f8 100644 --- a/src/blitter/32bpp_sse2.hpp +++ b/src/blitter/32bpp_sse2.hpp @@ -31,7 +31,7 @@ public: uint8 m; uint8 v; }; - assert_compile(sizeof(MapValue) == 2); + static_assert(sizeof(MapValue) == 2); /** Helper for creating specialised functions for specific optimisations. */ enum ReadMode { diff --git a/src/cargomonitor.h b/src/cargomonitor.h index 9a6a0c44d8..31053c46cb 100644 --- a/src/cargomonitor.h +++ b/src/cargomonitor.h @@ -48,8 +48,8 @@ enum CargoCompanyBits { CCB_COMPANY_LENGTH = 4, ///< Number of bits of the company field. }; -assert_compile(NUM_CARGO <= (1 << CCB_CARGO_TYPE_LENGTH)); -assert_compile(MAX_COMPANIES <= (1 << CCB_COMPANY_LENGTH)); +static_assert(NUM_CARGO <= (1 << CCB_CARGO_TYPE_LENGTH)); +static_assert(MAX_COMPANIES <= (1 << CCB_COMPANY_LENGTH)); /** diff --git a/src/cargopacket.cpp b/src/cargopacket.cpp index 08b72ec462..eafab6880e 100644 --- a/src/cargopacket.cpp +++ b/src/cargopacket.cpp @@ -556,8 +556,8 @@ void VehicleCargoList::InvalidateCache() template uint VehicleCargoList::Reassign(uint max_move, TileOrStationID) { - assert_compile(Tfrom != MTA_TRANSFER && Tto != MTA_TRANSFER); - assert_compile(Tfrom - Tto == 1 || Tto - Tfrom == 1); + static_assert(Tfrom != MTA_TRANSFER && Tto != MTA_TRANSFER); + static_assert(Tfrom - Tto == 1 || Tto - Tfrom == 1); max_move = min(this->action_counts[Tfrom], max_move); this->action_counts[Tfrom] -= max_move; this->action_counts[Tto] += max_move; diff --git a/src/cheat_gui.cpp b/src/cheat_gui.cpp index 7290414c00..344e15e636 100644 --- a/src/cheat_gui.cpp +++ b/src/cheat_gui.cpp @@ -192,7 +192,7 @@ static const CheatEntry _cheats_ui[] = { {SLE_INT32, STR_CHEAT_CHANGE_DATE, &_cur_year, &_cheats.change_date.been_used, &ClickChangeDateCheat }, }; -assert_compile(CHT_NUM_CHEATS == lengthof(_cheats_ui)); +static_assert(CHT_NUM_CHEATS == lengthof(_cheats_ui)); /** Widget definitions of the cheat GUI. */ static const NWidgetPart _nested_cheat_widgets[] = { diff --git a/src/cmd_helper.h b/src/cmd_helper.h index a505c1fd8b..ceb4d4bd9b 100644 --- a/src/cmd_helper.h +++ b/src/cmd_helper.h @@ -24,9 +24,9 @@ template static inline T Extract(U v) { /* Check if there are enough bits in v */ - assert_compile(N == EnumPropsT::num_bits); - assert_compile(S + N <= sizeof(U) * 8); - assert_compile(EnumPropsT::end <= (1 << N)); + static_assert(N == EnumPropsT::num_bits); + static_assert(S + N <= sizeof(U) * 8); + static_assert(EnumPropsT::end <= (1 << N)); U masked = GB(v, S, N); return IsInsideMM(masked, EnumPropsT::begin, EnumPropsT::end) ? (T)masked : EnumPropsT::invalid; } diff --git a/src/command.cpp b/src/command.cpp index 9fbc6cae6a..de5f8397d5 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -430,7 +430,7 @@ bool IsCommandAllowedWhilePaused(uint32 cmd) CMDPL_NO_ACTIONS, ///< CMDT_SERVER_SETTING CMDPL_NO_ACTIONS, ///< CMDT_CHEAT }; - assert_compile(lengthof(command_type_lookup) == CMDT_END); + static_assert(lengthof(command_type_lookup) == CMDT_END); assert(IsValidCommand(cmd)); return _game_mode == GM_EDITOR || command_type_lookup[_command_proc_table[cmd & CMD_ID_MASK].type] <= _settings_game.construction.command_pause_level; diff --git a/src/company_gui.cpp b/src/company_gui.cpp index 14567b1de7..e0bafda877 100644 --- a/src/company_gui.cpp +++ b/src/company_gui.cpp @@ -2438,7 +2438,7 @@ struct CompanyWindow : Window if (amounts[0] + amounts[1] + amounts[2] + amounts[3] == 0) { DrawString(r.left, r.right, y, STR_COMPANY_VIEW_VEHICLES_NONE); } else { - assert_compile(lengthof(amounts) == lengthof(_company_view_vehicle_count_strings)); + static_assert(lengthof(amounts) == lengthof(_company_view_vehicle_count_strings)); for (uint i = 0; i < lengthof(amounts); i++) { if (amounts[i] != 0) { diff --git a/src/company_manager_face.h b/src/company_manager_face.h index 2f16656d56..fe6365a121 100644 --- a/src/company_manager_face.h +++ b/src/company_manager_face.h @@ -83,7 +83,7 @@ static const CompanyManagerFaceBitsInfo _cmf_info[] = { /* CMFV_GLASSES */ { 31, 1, { 2, 2, 2, 2 }, { 0x347, 0x347, 0x3AE, 0x3AE } } ///< Depends on CMFV_HAS_GLASSES }; /** Make sure the table's size is right. */ -assert_compile(lengthof(_cmf_info) == CMFV_END); +static_assert(lengthof(_cmf_info) == CMFV_END); /** * Gets the company manager's face bits for the given company manager's face variable diff --git a/src/console_cmds.cpp b/src/console_cmds.cpp index e87232b365..d2066df2b7 100644 --- a/src/console_cmds.cpp +++ b/src/console_cmds.cpp @@ -1760,7 +1760,7 @@ struct ConsoleContentCallback : public ContentCallback { static void OutputContentState(const ContentInfo *const ci) { static const char * const types[] = { "Base graphics", "NewGRF", "AI", "AI library", "Scenario", "Heightmap", "Base sound", "Base music", "Game script", "GS library" }; - assert_compile(lengthof(types) == CONTENT_TYPE_END - CONTENT_TYPE_BEGIN); + static_assert(lengthof(types) == CONTENT_TYPE_END - CONTENT_TYPE_BEGIN); static const char * const states[] = { "Not selected", "Selected", "Dep Selected", "Installed", "Unknown" }; static const TextColour state_to_colour[] = { CC_COMMAND, CC_INFO, CC_INFO, CC_WHITE, CC_ERROR }; diff --git a/src/core/math_func.hpp b/src/core/math_func.hpp index d36dc55f9c..55061066a5 100644 --- a/src/core/math_func.hpp +++ b/src/core/math_func.hpp @@ -112,7 +112,7 @@ static inline T Align(const T x, uint n) template static inline T *AlignPtr(T *x, uint n) { - assert_compile(sizeof(size_t) == sizeof(void *)); + static_assert(sizeof(size_t) == sizeof(void *)); return reinterpret_cast(Align((size_t)x, n)); } diff --git a/src/core/pool_type.hpp b/src/core/pool_type.hpp index 9e6fc8fecd..e847dfbb72 100644 --- a/src/core/pool_type.hpp +++ b/src/core/pool_type.hpp @@ -80,7 +80,7 @@ private: template struct Pool : PoolBase { /* Ensure Tmax_size is within the bounds of Tindex. */ - assert_compile((uint64)(Tmax_size - 1) >> 8 * sizeof(Tindex) == 0); + static_assert((uint64)(Tmax_size - 1) >> 8 * sizeof(Tindex) == 0); static const size_t MAX_SIZE = Tmax_size; ///< Make template parameter accessible from outside diff --git a/src/economy.cpp b/src/economy.cpp index 3af220d96a..c73012096a 100644 --- a/src/economy.cpp +++ b/src/economy.cpp @@ -1258,7 +1258,7 @@ void PrepareUnload(Vehicle *front_v) assert(front_v->cargo_payment == nullptr); /* One CargoPayment per vehicle and the vehicle limit equals the * limit in number of CargoPayments. Can't go wrong. */ - assert_compile(CargoPaymentPool::MAX_SIZE == VehiclePool::MAX_SIZE); + static_assert(CargoPaymentPool::MAX_SIZE == VehiclePool::MAX_SIZE); assert(CargoPayment::CanAllocateItem()); front_v->cargo_payment = new CargoPayment(front_v); diff --git a/src/effectvehicle.cpp b/src/effectvehicle.cpp index f11a92e5d6..82054acc66 100644 --- a/src/effectvehicle.cpp +++ b/src/effectvehicle.cpp @@ -546,7 +546,7 @@ static EffectInitProc * const _effect_init_procs[] = { SmokeInit, // EV_BREAKDOWN_SMOKE_AIRCRAFT SmokeInit, // EV_COPPER_MINE_SMOKE }; -assert_compile(lengthof(_effect_init_procs) == EV_END); +static_assert(lengthof(_effect_init_procs) == EV_END); /** Functions for controlling effect vehicles at each tick. */ static EffectTickProc * const _effect_tick_procs[] = { @@ -563,7 +563,7 @@ static EffectTickProc * const _effect_tick_procs[] = { SmokeTick, // EV_BREAKDOWN_SMOKE_AIRCRAFT SmokeTick, // EV_COPPER_MINE_SMOKE }; -assert_compile(lengthof(_effect_tick_procs) == EV_END); +static_assert(lengthof(_effect_tick_procs) == EV_END); /** Transparency options affecting the effects. */ static const TransparencyOption _effect_transparency_options[] = { @@ -580,7 +580,7 @@ static const TransparencyOption _effect_transparency_options[] = { TO_INVALID, // EV_BREAKDOWN_SMOKE_AIRCRAFT TO_INDUSTRIES, // EV_COPPER_MINE_SMOKE }; -assert_compile(lengthof(_effect_transparency_options) == EV_END); +static_assert(lengthof(_effect_transparency_options) == EV_END); /** diff --git a/src/engine.cpp b/src/engine.cpp index 311a936ed4..68e44c8ae2 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -62,7 +62,7 @@ const uint8 _engine_offsets[4] = { lengthof(_orig_rail_vehicle_info) + lengthof(_orig_road_vehicle_info) + lengthof(_orig_ship_vehicle_info), }; -assert_compile(lengthof(_orig_rail_vehicle_info) + lengthof(_orig_road_vehicle_info) + lengthof(_orig_ship_vehicle_info) + lengthof(_orig_aircraft_vehicle_info) == lengthof(_orig_engine_info)); +static_assert(lengthof(_orig_rail_vehicle_info) + lengthof(_orig_road_vehicle_info) + lengthof(_orig_ship_vehicle_info) + lengthof(_orig_aircraft_vehicle_info) == lengthof(_orig_engine_info)); const uint EngineOverrideManager::NUM_DEFAULT_ENGINES = _engine_counts[VEH_TRAIN] + _engine_counts[VEH_ROAD] + _engine_counts[VEH_SHIP] + _engine_counts[VEH_AIRCRAFT]; diff --git a/src/fileio.cpp b/src/fileio.cpp index e294a82929..e409d9d2a4 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -238,7 +238,7 @@ static const char * const _subdirs[] = { "game" PATHSEP "library" PATHSEP, "screenshot" PATHSEP, }; -assert_compile(lengthof(_subdirs) == NUM_SUBDIRS); +static_assert(lengthof(_subdirs) == NUM_SUBDIRS); const char *_searchpaths[NUM_SEARCHPATHS]; TarList _tar_list[NUM_SUBDIRS]; diff --git a/src/gamelog.cpp b/src/gamelog.cpp index 156dfe6287..d1a9ab038f 100644 --- a/src/gamelog.cpp +++ b/src/gamelog.cpp @@ -45,7 +45,7 @@ static const char * GetGamelogRevisionString() { /* Allocate a buffer larger than necessary (git revision hash is 40 bytes) to avoid truncation later */ static char gamelog_revision[48] = { 0 }; - assert_compile(lengthof(gamelog_revision) > GAMELOG_REVISION_LENGTH); + static_assert(lengthof(gamelog_revision) > GAMELOG_REVISION_LENGTH); if (IsReleasedVersion()) { return _openttd_revision; @@ -167,7 +167,7 @@ static const char * const la_text[] = { "emergency savegame", }; -assert_compile(lengthof(la_text) == GLAT_END); +static_assert(lengthof(la_text) == GLAT_END); /** * Information about the presence of a Grf at a certain point during gamelog history diff --git a/src/genworld_gui.cpp b/src/genworld_gui.cpp index 154097e722..4f1524f8ab 100644 --- a/src/genworld_gui.cpp +++ b/src/genworld_gui.cpp @@ -304,7 +304,7 @@ static const StringID _num_towns[] = {STR_NUM_VERY_LOW, STR_NUM_LOW, STR_NUM_N static const StringID _num_inds[] = {STR_FUNDING_ONLY, STR_MINIMAL, STR_NUM_VERY_LOW, STR_NUM_LOW, STR_NUM_NORMAL, STR_NUM_HIGH, INVALID_STRING_ID}; static const StringID _variety[] = {STR_VARIETY_NONE, STR_VARIETY_VERY_LOW, STR_VARIETY_LOW, STR_VARIETY_MEDIUM, STR_VARIETY_HIGH, STR_VARIETY_VERY_HIGH, INVALID_STRING_ID}; -assert_compile(lengthof(_num_inds) == ID_END + 1); +static_assert(lengthof(_num_inds) == ID_END + 1); struct GenerateLandscapeWindow : public Window { uint widget_id; @@ -1166,7 +1166,7 @@ static const StringID _generation_class_table[] = { STR_GENERATION_PREPARING_SCRIPT, STR_GENERATION_PREPARING_GAME }; -assert_compile(lengthof(_generation_class_table) == GWP_CLASS_COUNT); +static_assert(lengthof(_generation_class_table) == GWP_CLASS_COUNT); static void AbortGeneratingWorldCallback(Window *w, bool confirmed) @@ -1268,7 +1268,7 @@ void ShowGenerateWorldProgress() static void _SetGeneratingWorldProgress(GenWorldProgress cls, uint progress, uint total) { static const int percent_table[] = {0, 5, 14, 17, 20, 40, 60, 65, 80, 85, 95, 99, 100 }; - assert_compile(lengthof(percent_table) == GWP_CLASS_COUNT + 1); + static_assert(lengthof(percent_table) == GWP_CLASS_COUNT + 1); assert(cls < GWP_CLASS_COUNT); /* Do not run this function if we aren't in a thread */ diff --git a/src/gfx.cpp b/src/gfx.cpp index 8027dad265..c0a2efc315 100644 --- a/src/gfx.cpp +++ b/src/gfx.cpp @@ -1681,7 +1681,7 @@ void UpdateCursorSize() /* Ignore setting any cursor before the sprites are loaded. */ if (GetMaxSpriteID() == 0) return; - assert_compile(lengthof(_cursor.sprite_seq) == lengthof(_cursor.sprite_pos)); + static_assert(lengthof(_cursor.sprite_seq) == lengthof(_cursor.sprite_pos)); assert(_cursor.sprite_count <= lengthof(_cursor.sprite_seq)); for (uint i = 0; i < _cursor.sprite_count; ++i) { const Sprite *p = GetSprite(GB(_cursor.sprite_seq[i].sprite, 0, SPRITE_WIDTH), ST_NORMAL); diff --git a/src/gfx_type.h b/src/gfx_type.h index ab802c45e4..3b9f04d9e8 100644 --- a/src/gfx_type.h +++ b/src/gfx_type.h @@ -199,7 +199,7 @@ union Colour { } }; -assert_compile(sizeof(Colour) == sizeof(uint32)); +static_assert(sizeof(Colour) == sizeof(uint32)); /** Available font sizes */ diff --git a/src/gfxinit.cpp b/src/gfxinit.cpp index 95c9540959..f4d1a7b03f 100644 --- a/src/gfxinit.cpp +++ b/src/gfxinit.cpp @@ -150,7 +150,7 @@ void CheckExternalFiles() 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.c_str()); - assert_compile(SoundsSet::NUM_FILES == 1); + static_assert(SoundsSet::NUM_FILES == 1); /* No need to loop each file, as long as there is only a single * sound file. */ add_pos += seprintf(add_pos, last, "\t%s is %s (%s)\n", sounds_set->files->filename, SoundsSet::CheckMD5(sounds_set->files, BASESET_DIR) == MD5File::CR_MISMATCH ? "corrupt" : "missing", sounds_set->files->missing_warning); diff --git a/src/goal.cpp b/src/goal.cpp index 02ec85255f..954d2f7bf7 100644 --- a/src/goal.cpp +++ b/src/goal.cpp @@ -248,7 +248,7 @@ CommandCost CmdGoalQuestion(TileIndex tile, DoCommandFlag flags, uint32 p1, uint CompanyID company = (CompanyID)GB(p1, 16, 8); ClientID client = (ClientID)GB(p1, 16, 16); - assert_compile(GOAL_QUESTION_BUTTON_COUNT < 29); + static_assert(GOAL_QUESTION_BUTTON_COUNT < 29); uint32 button_mask = GB(p2, 0, GOAL_QUESTION_BUTTON_COUNT); byte type = GB(p2, 29, 2); bool is_client = HasBit(p2, 31); diff --git a/src/graph_gui.cpp b/src/graph_gui.cpp index d454d8a9b5..3d6d2a3a36 100644 --- a/src/graph_gui.cpp +++ b/src/graph_gui.cpp @@ -289,7 +289,7 @@ protected: /* the colours and cost array of GraphDrawer must accommodate * both values for cargo and companies. So if any are higher, quit */ - assert_compile(GRAPH_MAX_DATASETS >= (int)NUM_CARGO && GRAPH_MAX_DATASETS >= (int)MAX_COMPANIES); + static_assert(GRAPH_MAX_DATASETS >= (int)NUM_CARGO && GRAPH_MAX_DATASETS >= (int)MAX_COMPANIES); assert(this->num_vert_lines > 0); byte grid_colour = _colour_gradient[COLOUR_GREY][4]; @@ -1527,7 +1527,7 @@ static NWidgetBase *MakePerformanceDetailPanels(int *biggest_index) STR_PERFORMANCE_DETAIL_TOTAL_TOOLTIP, }; - assert_compile(lengthof(performance_tips) == SCORE_END - SCORE_BEGIN); + static_assert(lengthof(performance_tips) == SCORE_END - SCORE_BEGIN); NWidgetVertical *vert = new NWidgetVertical(NC_EQUALSIZE); for (int widnum = WID_PRD_SCORE_FIRST; widnum <= WID_PRD_SCORE_LAST; widnum++) { diff --git a/src/ground_vehicle.cpp b/src/ground_vehicle.cpp index 74095fc576..0f1915c964 100644 --- a/src/ground_vehicle.cpp +++ b/src/ground_vehicle.cpp @@ -191,8 +191,8 @@ bool GroundVehicle::IsChainInDepot() const { const T *v = this->First(); /* Is the front engine stationary in the depot? */ - assert_compile((int)TRANSPORT_RAIL == (int)VEH_TRAIN); - assert_compile((int)TRANSPORT_ROAD == (int)VEH_ROAD); + static_assert((int)TRANSPORT_RAIL == (int)VEH_TRAIN); + static_assert((int)TRANSPORT_ROAD == (int)VEH_ROAD); if (!IsDepotTypeTile(v->tile, (TransportType)Type) || v->cur_speed != 0) return false; /* Check whether the rest is also already trying to enter the depot. */ diff --git a/src/house.h b/src/house.h index 7d3b8dc5e8..f381fc1e0b 100644 --- a/src/house.h +++ b/src/house.h @@ -64,7 +64,7 @@ enum HouseZonesBits { HZB_TOWN_CENTRE, HZB_END, }; -assert_compile(HZB_END == 5); +static_assert(HZB_END == 5); DECLARE_POSTFIX_INCREMENT(HouseZonesBits) diff --git a/src/industry_gui.cpp b/src/industry_gui.cpp index caa18c8e3e..ed770ed043 100644 --- a/src/industry_gui.cpp +++ b/src/industry_gui.cpp @@ -145,7 +145,7 @@ enum CargoSuffixInOut { template static inline void GetAllCargoSuffixes(CargoSuffixInOut use_input, CargoSuffixType cst, const Industry *ind, IndustryType ind_type, const IndustrySpec *indspec, const TC &cargoes, TS &suffixes) { - assert_compile(lengthof(cargoes) <= lengthof(suffixes)); + static_assert(lengthof(cargoes) <= lengthof(suffixes)); if (indspec->behaviour & INDUSTRYBEH_CARGOTYPES_UNLIMITED) { /* Reworked behaviour with new many-in-many-out scheme */ @@ -2201,8 +2201,8 @@ private: } }; -assert_compile(MAX_CARGOES >= cpp_lengthof(IndustrySpec, produced_cargo)); -assert_compile(MAX_CARGOES >= cpp_lengthof(IndustrySpec, accepts_cargo)); +static_assert(MAX_CARGOES >= cpp_lengthof(IndustrySpec, produced_cargo)); +static_assert(MAX_CARGOES >= cpp_lengthof(IndustrySpec, accepts_cargo)); int CargoesField::small_height; ///< Height of the header row. int CargoesField::normal_height; ///< Height of the non-header rows. diff --git a/src/landscape.cpp b/src/landscape.cpp index 33afd5163c..6dddbfd70f 100644 --- a/src/landscape.cpp +++ b/src/landscape.cpp @@ -811,7 +811,7 @@ void RunTileLoop() static const uint32 feedbacks[] = { 0xD8F, 0x1296, 0x2496, 0x4357, 0x8679, 0x1030E, 0x206CD, 0x403FE, 0x807B8, 0x1004B2, 0x2006A8, 0x4004B2, 0x800B87 }; - assert_compile(lengthof(feedbacks) == 2 * MAX_MAP_SIZE_BITS - 2 * MIN_MAP_SIZE_BITS + 1); + static_assert(lengthof(feedbacks) == 2 * MAX_MAP_SIZE_BITS - 2 * MIN_MAP_SIZE_BITS + 1); const uint32 feedback = feedbacks[MapLogX() + MapLogY() - 2 * MIN_MAP_SIZE_BITS]; /* We update every tile every 256 ticks, so divide the map size by 2^8 = 256 */ diff --git a/src/language.h b/src/language.h index aec5d9c85f..269b22c246 100644 --- a/src/language.h +++ b/src/language.h @@ -86,7 +86,7 @@ struct LanguagePackHeader { } }; /** Make sure the size is right. */ -assert_compile(sizeof(LanguagePackHeader) % 4 == 0); +static_assert(sizeof(LanguagePackHeader) % 4 == 0); /** Metadata about a single language. */ struct LanguageMetadata : public LanguagePackHeader { diff --git a/src/linkgraph/linkgraph_gui.cpp b/src/linkgraph/linkgraph_gui.cpp index b5fbc50ff7..fa4002e2b8 100644 --- a/src/linkgraph/linkgraph_gui.cpp +++ b/src/linkgraph/linkgraph_gui.cpp @@ -454,7 +454,7 @@ static const NWidgetPart _nested_linkgraph_legend_widgets[] = { EndContainer() }; -assert_compile(WID_LGL_SATURATION_LAST - WID_LGL_SATURATION_FIRST == +static_assert(WID_LGL_SATURATION_LAST - WID_LGL_SATURATION_FIRST == lengthof(LinkGraphOverlay::LINK_COLOURS) - 1); static WindowDesc _linkgraph_legend_desc( diff --git a/src/map_type.h b/src/map_type.h index 453186d88e..f34f137c64 100644 --- a/src/map_type.h +++ b/src/map_type.h @@ -24,7 +24,7 @@ struct Tile { byte m5; ///< General purpose }; -assert_compile(sizeof(Tile) == 8); +static_assert(sizeof(Tile) == 8); /** * Data that is stored per tile. Also used Tile for this. diff --git a/src/misc/fixedsizearray.hpp b/src/misc/fixedsizearray.hpp index db6c7808b3..a36a810f27 100644 --- a/src/misc/fixedsizearray.hpp +++ b/src/misc/fixedsizearray.hpp @@ -67,7 +67,7 @@ public: FixedSizeArray() { /* Ensure the size won't overflow. */ - assert_compile(C < (SIZE_MAX - HeaderSize) / Tsize); + static_assert(C < (SIZE_MAX - HeaderSize) / Tsize); /* allocate block for header + items (don't construct items) */ data = (T*)((MallocT(HeaderSize + C * Tsize)) + HeaderSize); diff --git a/src/misc_gui.cpp b/src/misc_gui.cpp index f7345416c1..17a460bf55 100644 --- a/src/misc_gui.cpp +++ b/src/misc_gui.cpp @@ -681,7 +681,7 @@ struct TooltipsWindow : public Window { this->parent = parent; this->string_id = str; - assert_compile(sizeof(this->params[0]) == sizeof(params[0])); + static_assert(sizeof(this->params[0]) == sizeof(params[0])); assert(paramcount <= lengthof(this->params)); if (paramcount > 0) memcpy(this->params, params, sizeof(this->params[0]) * paramcount); this->paramcount = paramcount; diff --git a/src/music.cpp b/src/music.cpp index 131651e55c..66ac2b511b 100644 --- a/src/music.cpp +++ b/src/music.cpp @@ -83,7 +83,7 @@ static const char * const _music_file_names[] = { "ezy_0", "ezy_1", "ezy_2", "ezy_3", "ezy_4", "ezy_5", "ezy_6", "ezy_7", "ezy_8", "ezy_9", }; /** Make sure we aren't messing things up. */ -assert_compile(lengthof(_music_file_names) == NUM_SONGS_AVAILABLE); +static_assert(lengthof(_music_file_names) == NUM_SONGS_AVAILABLE); template /* static */ const char * const *BaseSet::file_names = _music_file_names; diff --git a/src/network/core/os_abstraction.h b/src/network/core/os_abstraction.h index 8aa072aefb..836cfeae8f 100644 --- a/src/network/core/os_abstraction.h +++ b/src/network/core/os_abstraction.h @@ -210,7 +210,7 @@ static inline bool SetNoDelay(SOCKET d) } /* Make sure these structures have the size we expect them to be */ -assert_compile(sizeof(in_addr) == 4); ///< IPv4 addresses should be 4 bytes. -assert_compile(sizeof(in6_addr) == 16); ///< IPv6 addresses should be 16 bytes. +static_assert(sizeof(in_addr) == 4); ///< IPv4 addresses should be 4 bytes. +static_assert(sizeof(in6_addr) == 16); ///< IPv6 addresses should be 16 bytes. #endif /* NETWORK_CORE_OS_ABSTRACTION_H */ diff --git a/src/network/core/tcp_admin.cpp b/src/network/core/tcp_admin.cpp index 98227e0199..c72583f553 100644 --- a/src/network/core/tcp_admin.cpp +++ b/src/network/core/tcp_admin.cpp @@ -18,10 +18,10 @@ #include "../../safeguards.h" /* Make sure that these enums match. */ -assert_compile((int)CRR_MANUAL == (int)ADMIN_CRR_MANUAL); -assert_compile((int)CRR_AUTOCLEAN == (int)ADMIN_CRR_AUTOCLEAN); -assert_compile((int)CRR_BANKRUPT == (int)ADMIN_CRR_BANKRUPT); -assert_compile((int)CRR_END == (int)ADMIN_CRR_END); +static_assert((int)CRR_MANUAL == (int)ADMIN_CRR_MANUAL); +static_assert((int)CRR_AUTOCLEAN == (int)ADMIN_CRR_AUTOCLEAN); +static_assert((int)CRR_BANKRUPT == (int)ADMIN_CRR_BANKRUPT); +static_assert((int)CRR_END == (int)ADMIN_CRR_END); /** * Create the admin handler for the given socket. diff --git a/src/network/network.cpp b/src/network/network.cpp index da341f253f..907f158420 100644 --- a/src/network/network.cpp +++ b/src/network/network.cpp @@ -43,7 +43,7 @@ bool _ddc_fastforward = true; #endif /* DEBUG_DUMP_COMMANDS */ /** Make sure both pools have the same size. */ -assert_compile(NetworkClientInfoPool::MAX_SIZE == NetworkClientSocketPool::MAX_SIZE); +static_assert(NetworkClientInfoPool::MAX_SIZE == NetworkClientSocketPool::MAX_SIZE); /** The pool with client information. */ NetworkClientInfoPool _networkclientinfo_pool("NetworkClientInfo"); @@ -80,8 +80,8 @@ uint8 _network_advertise_retries; ///< The number of advertisement retries w CompanyMask _network_company_passworded; ///< Bitmask of the password status of all companies. /* Check whether NETWORK_NUM_LANDSCAPES is still in sync with NUM_LANDSCAPE */ -assert_compile((int)NETWORK_NUM_LANDSCAPES == (int)NUM_LANDSCAPE); -assert_compile((int)NETWORK_COMPANY_NAME_LENGTH == MAX_LENGTH_COMPANY_NAME_CHARS * MAX_CHAR_LENGTH); +static_assert((int)NETWORK_NUM_LANDSCAPES == (int)NUM_LANDSCAPE); +static_assert((int)NETWORK_COMPANY_NAME_LENGTH == MAX_LENGTH_COMPANY_NAME_CHARS * MAX_CHAR_LENGTH); extern NetworkUDPSocketHandler *_udp_client_socket; ///< udp client socket extern NetworkUDPSocketHandler *_udp_server_socket; ///< udp server socket @@ -322,7 +322,7 @@ StringID GetNetworkErrorMsg(NetworkErrorCode err) STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP, STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN, }; - assert_compile(lengthof(network_error_strings) == NETWORK_ERROR_END); + static_assert(lengthof(network_error_strings) == NETWORK_ERROR_END); if (err >= (ptrdiff_t)lengthof(network_error_strings)) err = NETWORK_ERROR_GENERAL; @@ -920,7 +920,7 @@ void NetworkGameLoop() if (*p == ' ') p++; cp = CallocT(1); int company; - assert_compile(sizeof(cp->text) == 128); + static_assert(sizeof(cp->text) == 128); int ret = sscanf(p, "%x; %x; %x; %x; %x; %x; %x; \"%127[^\"]\"", &next_date, &next_date_fract, &company, &cp->tile, &cp->p1, &cp->p2, &cp->cmd, cp->text); /* There are 8 pieces of data to read, however the last is a * string that might or might not exist. Ignore it if that diff --git a/src/network/network_admin.cpp b/src/network/network_admin.cpp index f304740a6a..007722ec69 100644 --- a/src/network/network_admin.cpp +++ b/src/network/network_admin.cpp @@ -54,7 +54,7 @@ static const AdminUpdateFrequency _admin_update_type_frequencies[] = { ADMIN_FREQUENCY_AUTOMATIC, ///< ADMIN_UPDATE_GAMESCRIPT }; /** Sanity check. */ -assert_compile(lengthof(_admin_update_type_frequencies) == ADMIN_UPDATE_END); +static_assert(lengthof(_admin_update_type_frequencies) == ADMIN_UPDATE_END); /** * Create a new socket for the server side of the admin network. @@ -86,7 +86,7 @@ ServerNetworkAdminSocketHandler::~ServerNetworkAdminSocketHandler() bool accept = !StrEmpty(_settings_client.network.admin_password) && _network_admins_connected < MAX_ADMINS; /* We can't go over the MAX_ADMINS limit here. However, if we accept * the connection, there has to be space in the pool. */ - assert_compile(NetworkAdminSocketPool::MAX_SIZE == MAX_ADMINS); + static_assert(NetworkAdminSocketPool::MAX_SIZE == MAX_ADMINS); assert(!accept || ServerNetworkAdminSocketHandler::CanAllocateItem()); return accept; } diff --git a/src/network/network_chat_gui.cpp b/src/network/network_chat_gui.cpp index 07348c0484..e0f3bf57c3 100644 --- a/src/network/network_chat_gui.cpp +++ b/src/network/network_chat_gui.cpp @@ -31,7 +31,7 @@ /** The draw buffer must be able to contain the chat message, client name and the "[All]" message, * some spaces and possible translations of [All] to other languages. */ -assert_compile((int)DRAW_STRING_BUFFER >= (int)NETWORK_CHAT_LENGTH + NETWORK_NAME_LENGTH + 40); +static_assert((int)DRAW_STRING_BUFFER >= (int)NETWORK_CHAT_LENGTH + NETWORK_NAME_LENGTH + 40); /** Spacing between chat lines. */ static const uint NETWORK_CHAT_LINE_SPACING = 3; diff --git a/src/network/network_client.cpp b/src/network/network_client.cpp index dc593eacd7..eb5c4cbb35 100644 --- a/src/network/network_client.cpp +++ b/src/network/network_client.cpp @@ -324,7 +324,7 @@ const char *_network_join_server_password = nullptr; const char *_network_join_company_password = nullptr; /** Make sure the server ID length is the same as a md5 hash. */ -assert_compile(NETWORK_SERVER_ID_LENGTH == 16 * 2 + 1); +static_assert(NETWORK_SERVER_ID_LENGTH == 16 * 2 + 1); /*********** * Sending functions @@ -682,7 +682,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_ERROR(Packet *p STR_NETWORK_ERROR_TIMEOUT_MAP, // NETWORK_ERROR_TIMEOUT_MAP STR_NETWORK_ERROR_TIMEOUT_JOIN, // NETWORK_ERROR_TIMEOUT_JOIN }; - assert_compile(lengthof(network_error_strings) == NETWORK_ERROR_END); + static_assert(lengthof(network_error_strings) == NETWORK_ERROR_END); NetworkErrorCode error = (NetworkErrorCode)p->Recv_uint8(); diff --git a/src/network/network_server.cpp b/src/network/network_server.cpp index c82c51cfd4..1454991a8c 100644 --- a/src/network/network_server.cpp +++ b/src/network/network_server.cpp @@ -41,9 +41,9 @@ DECLARE_POSTFIX_INCREMENT(ClientID) static ClientID _network_client_id = CLIENT_ID_FIRST; /** Make very sure the preconditions given in network_type.h are actually followed */ -assert_compile(MAX_CLIENT_SLOTS > MAX_CLIENTS); +static_assert(MAX_CLIENT_SLOTS > MAX_CLIENTS); /** Yes... */ -assert_compile(NetworkClientSocketPool::MAX_SIZE == MAX_CLIENT_SLOTS); +static_assert(NetworkClientSocketPool::MAX_SIZE == MAX_CLIENT_SLOTS); /** The pool with clients. */ NetworkClientSocketPool _networkclientsocket_pool("NetworkClientSocket"); @@ -223,7 +223,7 @@ ServerNetworkGameSocketHandler::ServerNetworkGameSocketHandler(SOCKET s) : Netwo /* The Socket and Info pools need to be the same in size. After all, * each Socket will be associated with at most one Info object. As * such if the Socket was allocated the Info object can as well. */ - assert_compile(NetworkClientSocketPool::MAX_SIZE == NetworkClientInfoPool::MAX_SIZE); + static_assert(NetworkClientSocketPool::MAX_SIZE == NetworkClientInfoPool::MAX_SIZE); } /** @@ -311,7 +311,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::CloseConnection(NetworkRecvSta /* We can't go over the MAX_CLIENTS limit here. However, the * pool must have place for all clients and ourself. */ - assert_compile(NetworkClientSocketPool::MAX_SIZE == MAX_CLIENTS + 1); + static_assert(NetworkClientSocketPool::MAX_SIZE == MAX_CLIENTS + 1); assert(!accept || ServerNetworkGameSocketHandler::CanAllocateItem()); return accept; } @@ -1962,7 +1962,7 @@ void NetworkServerShowStatusToConsole() "ready", "active" }; - assert_compile(lengthof(stat_str) == NetworkClientSocket::STATUS_END); + static_assert(lengthof(stat_str) == NetworkClientSocket::STATUS_END); for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) { NetworkClientInfo *ci = cs->GetInfo(); diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 097e68ae22..2663a34705 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -503,7 +503,7 @@ static StringID TTDPStringIDToOTTDStringIDMapping(StringID str) assert(!IsInsideMM(str, 0xD000, 0xD7FF)); #define TEXTID_TO_STRINGID(begin, end, stringid, stringend) \ - assert_compile(stringend - stringid == end - begin); \ + static_assert(stringend - stringid == end - begin); \ if (str >= begin && str <= end) return str + (stringid - begin) /* We have some changes in our cargo strings, resulting in some missing. */ @@ -8728,7 +8728,7 @@ GRFFile::GRFFile(const GRFConfig *config) /* Copy the initial parameter list * 'Uninitialised' parameters are zeroed as that is their default value when dynamically creating them. */ - assert_compile(lengthof(this->param) == lengthof(config->param) && lengthof(this->param) == 0x80); + static_assert(lengthof(this->param) == lengthof(config->param) && lengthof(this->param) == 0x80); assert(config->num_params <= lengthof(config->param)); this->param_end = config->num_params; diff --git a/src/newgrf_airporttiles.cpp b/src/newgrf_airporttiles.cpp index 3059174a86..a437fb596a 100644 --- a/src/newgrf_airporttiles.cpp +++ b/src/newgrf_airporttiles.cpp @@ -37,7 +37,7 @@ AirportTileOverrideManager _airporttile_mngr(NEW_AIRPORTTILE_OFFSET, NUM_AIRPORT { /* should be assert(gfx < lengthof(tiles)), but that gives compiler warnings * since it's always true if the following holds: */ - assert_compile(MAX_UVALUE(StationGfx) + 1 == lengthof(tiles)); + static_assert(MAX_UVALUE(StationGfx) + 1 == lengthof(tiles)); return &AirportTileSpec::tiles[gfx]; } diff --git a/src/newgrf_engine.cpp b/src/newgrf_engine.cpp index db2f5ac43c..efc9873af4 100644 --- a/src/newgrf_engine.cpp +++ b/src/newgrf_engine.cpp @@ -1313,7 +1313,7 @@ void FillNewGRFVehicleCache(const Vehicle *v) { 0x43, NCVV_COMPANY_INFORMATION }, { 0x4D, NCVV_POSITION_IN_VEHICLE }, }; - assert_compile(NCVV_END == lengthof(cache_entries)); + static_assert(NCVV_END == lengthof(cache_entries)); /* Resolve all the variables, so their caches are set. */ for (size_t i = 0; i < lengthof(cache_entries); i++) { diff --git a/src/newgrf_station.cpp b/src/newgrf_station.cpp index 19f32bd754..d607f8bd05 100644 --- a/src/newgrf_station.cpp +++ b/src/newgrf_station.cpp @@ -431,9 +431,9 @@ uint32 Station::GetNewGRFVariable(const ResolverObject &object, byte variable, b case 0x64: return ge->HasVehicleEverTriedLoading() ? ge->last_speed | (ge->last_age << 8) : 0xFF00; case 0x65: return GB(ge->status, GoodsEntry::GES_ACCEPTANCE, 1) << 3; case 0x69: { - assert_compile((int)GoodsEntry::GES_EVER_ACCEPTED + 1 == (int)GoodsEntry::GES_LAST_MONTH); - assert_compile((int)GoodsEntry::GES_EVER_ACCEPTED + 2 == (int)GoodsEntry::GES_CURRENT_MONTH); - assert_compile((int)GoodsEntry::GES_EVER_ACCEPTED + 3 == (int)GoodsEntry::GES_ACCEPTED_BIGTICK); + static_assert((int)GoodsEntry::GES_EVER_ACCEPTED + 1 == (int)GoodsEntry::GES_LAST_MONTH); + static_assert((int)GoodsEntry::GES_EVER_ACCEPTED + 2 == (int)GoodsEntry::GES_CURRENT_MONTH); + static_assert((int)GoodsEntry::GES_EVER_ACCEPTED + 3 == (int)GoodsEntry::GES_ACCEPTED_BIGTICK); return GB(ge->status, GoodsEntry::GES_EVER_ACCEPTED, 4); } } diff --git a/src/newgrf_storage.h b/src/newgrf_storage.h index 61206a587b..ff322c9445 100644 --- a/src/newgrf_storage.h +++ b/src/newgrf_storage.h @@ -228,6 +228,6 @@ struct PersistentStorage : PersistentStorageArray, PersistentStorage } }; -assert_compile(cpp_lengthof(OldPersistentStorage, storage) <= cpp_lengthof(PersistentStorage, storage)); +static_assert(cpp_lengthof(OldPersistentStorage, storage) <= cpp_lengthof(PersistentStorage, storage)); #endif /* NEWGRF_STORAGE_H */ diff --git a/src/news_gui.cpp b/src/news_gui.cpp index a3f73d7296..e98f76da9d 100644 --- a/src/news_gui.cpp +++ b/src/news_gui.cpp @@ -244,7 +244,7 @@ static NewsTypeData _news_type_data[] = { NewsTypeData("news_display.general", 60, SND_BEGIN ), ///< NT_GENERAL }; -assert_compile(lengthof(_news_type_data) == NT_END); +static_assert(lengthof(_news_type_data) == NT_END); /** * Return the news display option. diff --git a/src/openttd.cpp b/src/openttd.cpp index 33f65314d1..89cc15c35a 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -424,7 +424,7 @@ struct AfterNewGRFScan : NewGRFScanCallback { { /* Visual C++ 2015 fails compiling this line (AfterNewGRFScan::generation_seed undefined symbol) * if it's placed outside a member function, directly in the struct body. */ - assert_compile(sizeof(generation_seed) == sizeof(_settings_game.game_creation.generation_seed)); + static_assert(sizeof(generation_seed) == sizeof(_settings_game.game_creation.generation_seed)); } virtual void OnNewGRFsScanned() diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp index c9fa919890..b8ba7ab901 100644 --- a/src/order_cmd.cpp +++ b/src/order_cmd.cpp @@ -34,8 +34,8 @@ /* DestinationID must be at least as large as every these below, because it can * be any of them */ -assert_compile(sizeof(DestinationID) >= sizeof(DepotID)); -assert_compile(sizeof(DestinationID) >= sizeof(StationID)); +static_assert(sizeof(DestinationID) >= sizeof(DepotID)); +static_assert(sizeof(DestinationID) >= sizeof(StationID)); OrderPool _order_pool("Order"); INSTANTIATE_POOL_METHODS(Order) diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp index 162fe97799..a714415326 100644 --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -62,7 +62,7 @@ enum SignalOffsets { */ void ResetRailTypes() { - assert_compile(lengthof(_original_railtypes) <= lengthof(_railtypes)); + static_assert(lengthof(_original_railtypes) <= lengthof(_railtypes)); uint i = 0; for (; i < lengthof(_original_railtypes); i++) _railtypes[i] = _original_railtypes[i]; diff --git a/src/road_cmd.cpp b/src/road_cmd.cpp index b8aee88d60..bac6f8e1f4 100644 --- a/src/road_cmd.cpp +++ b/src/road_cmd.cpp @@ -61,7 +61,7 @@ RoadTypes _roadtypes_type; */ void ResetRoadTypes() { - assert_compile(lengthof(_original_roadtypes) <= lengthof(_roadtypes)); + static_assert(lengthof(_original_roadtypes) <= lengthof(_roadtypes)); uint i = 0; for (; i < lengthof(_original_roadtypes); i++) _roadtypes[i] = _original_roadtypes[i]; diff --git a/src/roadveh_cmd.cpp b/src/roadveh_cmd.cpp index 261af7042b..0e490fbc21 100644 --- a/src/roadveh_cmd.cpp +++ b/src/roadveh_cmd.cpp @@ -60,7 +60,7 @@ static const uint16 _roadveh_full_adder[] = { 0, 16, 16, 0, 8, 8, 8, 8, 0, 0, 0, 8, 8, 8, 8 }; -assert_compile(lengthof(_roadveh_images) == lengthof(_roadveh_full_adder)); +static_assert(lengthof(_roadveh_images) == lengthof(_roadveh_full_adder)); template <> bool IsValidImageIndex(uint8 image_index) diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index 4eab99c883..329152ab27 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -2182,7 +2182,7 @@ bool AfterLoadGame() for (iter = st->loading_vehicles.begin(); iter != st->loading_vehicles.end(); ++iter) { /* There are always as many CargoPayments as Vehicles. We need to make the * assert() in Pool::GetNew() happy by calling CanAllocateItem(). */ - assert_compile(CargoPaymentPool::MAX_SIZE == VehiclePool::MAX_SIZE); + static_assert(CargoPaymentPool::MAX_SIZE == VehiclePool::MAX_SIZE); assert(CargoPayment::CanAllocateItem()); Vehicle *v = *iter; if (v->cargo_payment == nullptr) v->cargo_payment = new CargoPayment(v); diff --git a/src/saveload/gamelog_sl.cpp b/src/saveload/gamelog_sl.cpp index 576bfa5bc7..6bff1b154c 100644 --- a/src/saveload/gamelog_sl.cpp +++ b/src/saveload/gamelog_sl.cpp @@ -100,7 +100,7 @@ static const SaveLoad * const _glog_desc[] = { _glog_emergency_desc, }; -assert_compile(lengthof(_glog_desc) == GLCT_END); +static_assert(lengthof(_glog_desc) == GLCT_END); static void Load_GLOG_common(LoggedAction *&gamelog_action, uint &gamelog_actions) { diff --git a/src/saveload/oldloader.cpp b/src/saveload/oldloader.cpp index 5dac33777d..0c2c7f80bc 100644 --- a/src/saveload/oldloader.cpp +++ b/src/saveload/oldloader.cpp @@ -243,7 +243,7 @@ static inline bool CheckOldSavegameType(FILE *f, char *temp, const char *last, u static SavegameType DetermineOldSavegameType(FILE *f, char *title, const char *last) { - assert_compile(TTD_HEADER_SIZE >= TTO_HEADER_SIZE); + static_assert(TTD_HEADER_SIZE >= TTO_HEADER_SIZE); char temp[TTD_HEADER_SIZE] = "Unknown"; SavegameType type = SGT_TTO; diff --git a/src/saveload/oldloader.h b/src/saveload/oldloader.h index fcc7be4be0..1600a9ac22 100644 --- a/src/saveload/oldloader.h +++ b/src/saveload/oldloader.h @@ -93,7 +93,7 @@ struct OldChunks { }; /* If it fails, check lines above.. */ -assert_compile(sizeof(TileIndex) == 4); +static_assert(sizeof(TileIndex) == 4); extern uint _bump_assert_value; byte ReadByte(LoadgameState *ls); diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp index 3471a8295e..bfbf1957b8 100644 --- a/src/saveload/saveload.cpp +++ b/src/saveload/saveload.cpp @@ -1142,7 +1142,7 @@ static size_t ReferenceToInt(const void *obj, SLRefType rt) */ static void *IntToReference(size_t index, SLRefType rt) { - assert_compile(sizeof(size_t) <= sizeof(void *)); + static_assert(sizeof(size_t) <= sizeof(void *)); assert(_sl.action == SLA_PTRS); diff --git a/src/screenshot.cpp b/src/screenshot.cpp index b7abab8fc7..b832e2224b 100644 --- a/src/screenshot.cpp +++ b/src/screenshot.cpp @@ -81,7 +81,7 @@ PACK(struct BitmapFileHeader { uint32 reserved; uint32 off_bits; }); -assert_compile(sizeof(BitmapFileHeader) == 14); +static_assert(sizeof(BitmapFileHeader) == 14); /** BMP Info Header (stored in little endian) */ struct BitmapInfoHeader { @@ -90,13 +90,13 @@ struct BitmapInfoHeader { uint16 planes, bitcount; uint32 compression, sizeimage, xpels, ypels, clrused, clrimp; }; -assert_compile(sizeof(BitmapInfoHeader) == 40); +static_assert(sizeof(BitmapInfoHeader) == 40); /** Format of palette data in BMP header */ struct RgbQuad { byte blue, green, red, reserved; }; -assert_compile(sizeof(RgbQuad) == 4); +static_assert(sizeof(RgbQuad) == 4); /** * Generic .BMP writer @@ -419,7 +419,7 @@ struct PcxHeader { uint16 height; byte filler[54]; }; -assert_compile(sizeof(PcxHeader) == 128); +static_assert(sizeof(PcxHeader) == 128); /** * Generic .PCX file image writer. diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index c7dd0cb140..77be428c9d 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -1783,7 +1783,7 @@ static const StringID _game_settings_restrict_dropdown[] = { STR_CONFIG_SETTING_RESTRICT_CHANGED_AGAINST_DEFAULT, // RM_CHANGED_AGAINST_DEFAULT STR_CONFIG_SETTING_RESTRICT_CHANGED_AGAINST_NEW, // RM_CHANGED_AGAINST_NEW }; -assert_compile(lengthof(_game_settings_restrict_dropdown) == RM_END); +static_assert(lengthof(_game_settings_restrict_dropdown) == RM_END); /** Warnings about hidden search results. */ enum WarnHiddenResult { diff --git a/src/signal.cpp b/src/signal.cpp index 9b17e51dcb..d6795e3b5c 100644 --- a/src/signal.cpp +++ b/src/signal.cpp @@ -25,7 +25,7 @@ static const uint SIG_TBD_SIZE = 256; ///< number of intersections - open nod static const uint SIG_GLOB_SIZE = 128; ///< number of open blocks (block can be opened more times until detected) static const uint SIG_GLOB_UPDATE = 64; ///< how many items need to be in _globset to force update -assert_compile(SIG_GLOB_UPDATE <= SIG_GLOB_SIZE); +static_assert(SIG_GLOB_UPDATE <= SIG_GLOB_SIZE); /** incidating trackbits with given enterdir */ static const TrackBits _enterdir_to_trackbits[DIAGDIR_END] = { diff --git a/src/sound.cpp b/src/sound.cpp index 0d15473095..73c0b22e37 100644 --- a/src/sound.cpp +++ b/src/sound.cpp @@ -188,7 +188,7 @@ static void StartSound(SoundID sound_id, float pan, uint volume) static const byte _vol_factor_by_zoom[] = {255, 255, 255, 190, 134, 87}; -assert_compile(lengthof(_vol_factor_by_zoom) == ZOOM_LVL_COUNT); +static_assert(lengthof(_vol_factor_by_zoom) == ZOOM_LVL_COUNT); static const byte _sound_base_vol[] = { 128, 90, 128, 128, 128, 128, 128, 128, diff --git a/src/spritecache.cpp b/src/spritecache.cpp index da0ca80484..3eceb38de5 100644 --- a/src/spritecache.cpp +++ b/src/spritecache.cpp @@ -618,9 +618,9 @@ void DupSprite(SpriteID old_spr, SpriteID new_spr) static const size_t S_FREE_MASK = sizeof(size_t) - 1; /* to make sure nobody adds things to MemBlock without checking S_FREE_MASK first */ -assert_compile(sizeof(MemBlock) == sizeof(size_t)); +static_assert(sizeof(MemBlock) == sizeof(size_t)); /* make sure it's a power of two */ -assert_compile((sizeof(size_t) & (sizeof(size_t) - 1)) == 0); +static_assert((sizeof(size_t) & (sizeof(size_t) - 1)) == 0); static inline MemBlock *NextBlock(MemBlock *block) { diff --git a/src/stdafx.h b/src/stdafx.h index c99d7a2771..dca0e6c6f3 100644 --- a/src/stdafx.h +++ b/src/stdafx.h @@ -348,14 +348,12 @@ typedef unsigned char byte; # define PERSONAL_DIR "" #endif -#define assert_compile(expr) static_assert(expr, #expr) - /* Check if the types have the bitsizes like we are using them */ -assert_compile(sizeof(uint64) == 8); -assert_compile(sizeof(uint32) == 4); -assert_compile(sizeof(uint16) == 2); -assert_compile(sizeof(uint8) == 1); -assert_compile(SIZE_MAX >= UINT32_MAX); +static_assert(sizeof(uint64) == 8); +static_assert(sizeof(uint32) == 4); +static_assert(sizeof(uint16) == 2); +static_assert(sizeof(uint8) == 1); +static_assert(SIZE_MAX >= UINT32_MAX); #ifndef M_PI_2 #define M_PI_2 1.57079632679489661923 diff --git a/src/strings_func.h b/src/strings_func.h index 6ef36dafc6..2019b8b369 100644 --- a/src/strings_func.h +++ b/src/strings_func.h @@ -84,7 +84,7 @@ public: offset(0), num_param(Tnum_param) { - assert_compile(sizeof(data[0]) == sizeof(uint64)); + static_assert(sizeof(data[0]) == sizeof(uint64)); } /** diff --git a/src/table/airport_defaults.h b/src/table/airport_defaults.h index ec30874f71..dce71843a5 100644 --- a/src/table/airport_defaults.h +++ b/src/table/airport_defaults.h @@ -406,7 +406,7 @@ extern const AirportSpec _origin_airport_specs[] = { AS_GENERIC(&_airportfta_oilrig, nullptr, _default_airports_rotation, 0, nullptr, 0, 1, 1, 0, 4, 0, 0, 0, ATP_TTDP_OILRIG, APC_HELIPORT, STR_NULL, 0, false), }; -assert_compile(NEW_AIRPORT_OFFSET == lengthof(_origin_airport_specs)); +static_assert(NEW_AIRPORT_OFFSET == lengthof(_origin_airport_specs)); const AirportSpec AirportSpec::dummy = AS_GENERIC(&_airportfta_dummy, nullptr, _default_airports_rotation, 0, nullptr, 0, 0, 0, 0, 0, MIN_YEAR, MIN_YEAR, 0, ATP_TTDP_LARGE, APC_BEGIN, STR_NULL, 0, false); diff --git a/src/table/airporttiles.h b/src/table/airporttiles.h index d4fb3d968e..0393cf7a5f 100644 --- a/src/table/airporttiles.h +++ b/src/table/airporttiles.h @@ -104,7 +104,7 @@ static const AirportTileSpec _origin_airporttile_specs[] = { AT(3, 1), // APT_GRASS_FENCE_NE_FLAG_2 }; -assert_compile(NEW_AIRPORTTILE_OFFSET == lengthof(_origin_airporttile_specs)); +static_assert(NEW_AIRPORTTILE_OFFSET == lengthof(_origin_airporttile_specs)); #undef AT_NOANIM #undef AT diff --git a/src/table/newgrf_debug_data.h b/src/table/newgrf_debug_data.h index d14415051c..4e5abaff5b 100644 --- a/src/table/newgrf_debug_data.h +++ b/src/table/newgrf_debug_data.h @@ -620,4 +620,4 @@ static const NIFeature * const _nifeatures[] = { &_nif_tramtype, // GSF_TRAMTYPES &_nif_town, // GSF_FAKE_TOWNS }; -assert_compile(lengthof(_nifeatures) == GSF_FAKE_END); +static_assert(lengthof(_nifeatures) == GSF_FAKE_END); diff --git a/src/table/pricebase.h b/src/table/pricebase.h index 5051254a38..27af6a370e 100644 --- a/src/table/pricebase.h +++ b/src/table/pricebase.h @@ -80,4 +80,4 @@ extern const PriceBaseSpec _price_base_specs[] = { { 100, PCAT_RUNNING, GSF_END, PR_STATION_VALUE }, ///< PR_INFRASTRUCTURE_STATION { 5000, PCAT_RUNNING, GSF_END, PR_BUILD_STATION_AIRPORT}, ///< PR_INFRASTRUCTURE_AIRPORT }; -assert_compile(lengthof(_price_base_specs) == PR_END); +static_assert(lengthof(_price_base_specs) == PR_END); diff --git a/src/table/sprites.h b/src/table/sprites.h index 64f628e5d1..7d9f980ef1 100644 --- a/src/table/sprites.h +++ b/src/table/sprites.h @@ -1545,11 +1545,11 @@ enum SpriteMasks { PALETTE_MASK = MAX_PALETTES - 1, ///< The mask for the auxiliary sprite (the one that takes care of recolouring) }; -assert_compile( (1 << TRANSPARENT_BIT & SPRITE_MASK) == 0 ); -assert_compile( (1 << RECOLOUR_BIT & SPRITE_MASK) == 0 ); -assert_compile( TRANSPARENT_BIT != RECOLOUR_BIT ); -assert_compile( (1 << TRANSPARENT_BIT & PALETTE_MASK) == 0); -assert_compile( (1 << RECOLOUR_BIT & PALETTE_MASK) == 0 ); +static_assert( (1 << TRANSPARENT_BIT & SPRITE_MASK) == 0 ); +static_assert( (1 << RECOLOUR_BIT & SPRITE_MASK) == 0 ); +static_assert( TRANSPARENT_BIT != RECOLOUR_BIT ); +static_assert( (1 << TRANSPARENT_BIT & PALETTE_MASK) == 0); +static_assert( (1 << RECOLOUR_BIT & PALETTE_MASK) == 0 ); static const PaletteID PAL_NONE = 0; diff --git a/src/table/station_land.h b/src/table/station_land.h index 6b4b2267ac..8429914f32 100644 --- a/src/table/station_land.h +++ b/src/table/station_land.h @@ -988,7 +988,7 @@ static const DrawTileSprites _station_display_datas_waypoint[] = { /* Default waypoint is also drawn as fallback for NewGRF waypoints. * As these are drawn/build like stations, they may use the same number of layouts. */ -assert_compile(lengthof(_station_display_datas_rail) == lengthof(_station_display_datas_waypoint)); +static_assert(lengthof(_station_display_datas_rail) == lengthof(_station_display_datas_waypoint)); static const DrawTileSprites * const _station_display_datas[] = { _station_display_datas_rail, diff --git a/src/table/town_land.h b/src/table/town_land.h index 80a181baa3..92292f6203 100644 --- a/src/table/town_land.h +++ b/src/table/town_land.h @@ -1788,7 +1788,7 @@ static const DrawBuildingsTileStruct _town_draw_tile_data[] = { }; #undef M /** Make sure we have the right number of elements: 4 variants * 4 build stages for each house */ -assert_compile(lengthof(_town_draw_tile_data) == (NEW_HOUSE_OFFSET) * 4 * 4); +static_assert(lengthof(_town_draw_tile_data) == (NEW_HOUSE_OFFSET) * 4 * 4); /** * Describes the data that defines each house in the game @@ -2276,4 +2276,4 @@ static const HouseSpec _original_house_specs[] = { #undef MS /** Make sure we have the right number of elements: one entry for each house */ -assert_compile(lengthof(_original_house_specs) == NEW_HOUSE_OFFSET); +static_assert(lengthof(_original_house_specs) == NEW_HOUSE_OFFSET); diff --git a/src/table/train_cmd.h b/src/table/train_cmd.h index cc53582f8d..f9419990b9 100644 --- a/src/table/train_cmd.h +++ b/src/table/train_cmd.h @@ -63,6 +63,6 @@ static const byte _wagon_full_adder[] = { 32, 32 }; -assert_compile(lengthof(_engine_sprite_base) == lengthof(_engine_sprite_and)); -assert_compile(lengthof(_engine_sprite_base) == lengthof(_engine_sprite_add)); -assert_compile(lengthof(_engine_sprite_base) == lengthof(_wagon_full_adder)); +static_assert(lengthof(_engine_sprite_base) == lengthof(_engine_sprite_and)); +static_assert(lengthof(_engine_sprite_base) == lengthof(_engine_sprite_add)); +static_assert(lengthof(_engine_sprite_base) == lengthof(_wagon_full_adder)); diff --git a/src/textfile_gui.cpp b/src/textfile_gui.cpp index 3519c27508..7b728e9b2c 100644 --- a/src/textfile_gui.cpp +++ b/src/textfile_gui.cpp @@ -390,7 +390,7 @@ const char *GetTextfile(TextfileType type, Subdirectory dir, const char *filenam "changelog", "license", }; - assert_compile(lengthof(prefixes) == TFT_END); + static_assert(lengthof(prefixes) == TFT_END); const char *prefix = prefixes[type]; diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp index ff63b613f5..8928ffdbf9 100644 --- a/src/town_cmd.cpp +++ b/src/town_cmd.cpp @@ -1877,7 +1877,7 @@ CommandCost CmdFoundTown(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 static const byte price_mult[][TSZ_RANDOM + 1] = {{ 15, 25, 40, 25 }, { 20, 35, 55, 35 }}; /* multidimensional arrays have to have defined length of non-first dimension */ - assert_compile(lengthof(price_mult[0]) == 4); + static_assert(lengthof(price_mult[0]) == 4); CommandCost cost(EXPENSES_OTHER, _price[PR_BUILD_TOWN]); byte mult = price_mult[city][size]; diff --git a/src/vehicle.cpp b/src/vehicle.cpp index 3ed7cb1b00..e014944a9f 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -1935,7 +1935,7 @@ static PaletteID GetEngineColourMap(EngineID engine_type, CompanyID company, Eng uint16 callback = GetVehicleCallback(CBID_VEHICLE_COLOUR_MAPPING, 0, 0, engine_type, v); /* Failure means "use the default two-colour" */ if (callback != CALLBACK_FAILED) { - assert_compile(PAL_NONE == 0); // Returning 0x4000 (resp. 0xC000) coincidences with default value (PAL_NONE) + static_assert(PAL_NONE == 0); // Returning 0x4000 (resp. 0xC000) coincidences with default value (PAL_NONE) map = GB(callback, 0, 14); /* If bit 14 is set, then the company colours are applied to the * map else it's returned as-is. */ @@ -2552,9 +2552,9 @@ void Vehicle::ShowVisualEffect() const } else { effect_model = (VisualEffectSpawnModel)GB(v->vcache.cached_vis_effect, VE_TYPE_START, VE_TYPE_COUNT); assert(effect_model != (VisualEffectSpawnModel)VE_TYPE_DEFAULT); // should have been resolved by UpdateVisualEffect - assert_compile((uint)VESM_STEAM == (uint)VE_TYPE_STEAM); - assert_compile((uint)VESM_DIESEL == (uint)VE_TYPE_DIESEL); - assert_compile((uint)VESM_ELECTRIC == (uint)VE_TYPE_ELECTRIC); + static_assert((uint)VESM_STEAM == (uint)VE_TYPE_STEAM); + static_assert((uint)VESM_DIESEL == (uint)VE_TYPE_DIESEL); + static_assert((uint)VESM_ELECTRIC == (uint)VE_TYPE_ELECTRIC); } /* Show no smoke when: diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index 2cc9f9d749..50a011c8ed 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -2009,10 +2009,10 @@ void ShowVehicleListWindow(CompanyID company, VehicleType vehicle_type, TileInde /* Unified vehicle GUI - Vehicle Details Window */ -assert_compile(WID_VD_DETAILS_CARGO_CARRIED == WID_VD_DETAILS_CARGO_CARRIED + TDW_TAB_CARGO ); -assert_compile(WID_VD_DETAILS_TRAIN_VEHICLES == WID_VD_DETAILS_CARGO_CARRIED + TDW_TAB_INFO ); -assert_compile(WID_VD_DETAILS_CAPACITY_OF_EACH == WID_VD_DETAILS_CARGO_CARRIED + TDW_TAB_CAPACITY); -assert_compile(WID_VD_DETAILS_TOTAL_CARGO == WID_VD_DETAILS_CARGO_CARRIED + TDW_TAB_TOTALS ); +static_assert(WID_VD_DETAILS_CARGO_CARRIED == WID_VD_DETAILS_CARGO_CARRIED + TDW_TAB_CARGO ); +static_assert(WID_VD_DETAILS_TRAIN_VEHICLES == WID_VD_DETAILS_CARGO_CARRIED + TDW_TAB_INFO ); +static_assert(WID_VD_DETAILS_CAPACITY_OF_EACH == WID_VD_DETAILS_CARGO_CARRIED + TDW_TAB_CAPACITY); +static_assert(WID_VD_DETAILS_TOTAL_CARGO == WID_VD_DETAILS_CARGO_CARRIED + TDW_TAB_TOTALS ); /** Vehicle details widgets (other than train). */ static const NWidgetPart _nested_nontrain_vehicle_details_widgets[] = { @@ -2554,10 +2554,10 @@ static WindowDesc _train_view_desc( /* Just to make sure, nobody has changed the vehicle type constants, as we are using them for array indexing in a number of places here. */ -assert_compile(VEH_TRAIN == 0); -assert_compile(VEH_ROAD == 1); -assert_compile(VEH_SHIP == 2); -assert_compile(VEH_AIRCRAFT == 3); +static_assert(VEH_TRAIN == 0); +static_assert(VEH_ROAD == 1); +static_assert(VEH_SHIP == 2); +static_assert(VEH_AIRCRAFT == 3); /** Zoom levels for vehicle views indexed by vehicle type. */ static const ZoomLevel _vehicle_view_zoom_levels[] = { diff --git a/src/vehiclelist.cpp b/src/vehiclelist.cpp index 79df540cf4..a574d9b817 100644 --- a/src/vehiclelist.cpp +++ b/src/vehiclelist.cpp @@ -25,7 +25,7 @@ uint32 VehicleListIdentifier::Pack() const assert(this->vtype < (1 << 2)); assert(this->index < (1 << 20)); assert(this->type < VLT_END); - assert_compile(VLT_END <= (1 << 3)); + static_assert(VLT_END <= (1 << 3)); return c << 28 | this->type << 23 | this->vtype << 26 | this->index; } diff --git a/src/video/dedicated_v.cpp b/src/video/dedicated_v.cpp index 0089d163df..b3acb82a4c 100644 --- a/src/video/dedicated_v.cpp +++ b/src/video/dedicated_v.cpp @@ -227,7 +227,7 @@ static void DedicatedHandleKeyInput() if (fgets(input_line, lengthof(input_line), stdin) == nullptr) return; #else /* Handle console input, and signal console thread, it can accept input again */ - assert_compile(lengthof(_win_console_thread_buffer) <= lengthof(input_line)); + static_assert(lengthof(_win_console_thread_buffer) <= lengthof(input_line)); strecpy(input_line, _win_console_thread_buffer, lastof(input_line)); SetEvent(_hWaitForInputHandling); #endif diff --git a/src/viewport_sprite_sorter_sse4.cpp b/src/viewport_sprite_sorter_sse4.cpp index 876821fdda..aac8333180 100644 --- a/src/viewport_sprite_sorter_sse4.cpp +++ b/src/viewport_sprite_sorter_sse4.cpp @@ -20,7 +20,7 @@ #include "safeguards.h" #ifdef _SQ64 - assert_compile((sizeof(ParentSpriteToDraw) % 16) == 0); + static_assert((sizeof(ParentSpriteToDraw) % 16) == 0); # define LOAD_128 _mm_load_si128 #else # define LOAD_128 _mm_loadu_si128 From dd138fc460dcbab37452e90ff070a31516994aa2 Mon Sep 17 00:00:00 2001 From: Michael Lutz Date: Sun, 6 Dec 2020 21:11:42 +0100 Subject: [PATCH 20/64] Codechange: Stringify config file paths. --- src/base_media_func.h | 13 ++++---- src/crashlog.cpp | 4 +-- src/fileio.cpp | 53 +++++++++++++++------------------ src/fileio_func.h | 3 +- src/fios_gui.cpp | 2 +- src/highscore.cpp | 6 ++-- src/hotkeys.cpp | 2 +- src/ini.cpp | 8 ++--- src/ini_load.cpp | 4 +-- src/ini_type.h | 4 +-- src/openttd.cpp | 7 ++--- src/os/windows/crashlog_win.cpp | 2 +- src/os/windows/win32.cpp | 6 ++-- src/screenshot.cpp | 2 +- src/settings.cpp | 2 +- src/window.cpp | 2 +- 16 files changed, 56 insertions(+), 64 deletions(-) diff --git a/src/base_media_func.h b/src/base_media_func.h index c5e2a6da23..703165db5e 100644 --- a/src/base_media_func.h +++ b/src/base_media_func.h @@ -157,17 +157,17 @@ bool BaseMedia::AddFile(const char *filename, size_t basepath_length, Tbase_set *set = new Tbase_set(); IniFile *ini = new IniFile(); - char *path = stredup(filename + basepath_length); + std::string path{ filename + basepath_length }; ini->LoadFromDisk(path, BASESET_DIR); - char *psep = strrchr(path, PATHSEPCHAR); - if (psep != nullptr) { - psep[1] = '\0'; + auto psep = path.rfind(PATHSEPCHAR); + if (psep != std::string::npos) { + path.erase(psep + 1); } else { - *path = '\0'; + path.clear(); } - if (set->FillSetDetails(ini, path, filename)) { + if (set->FillSetDetails(ini, path.c_str(), filename)) { Tbase_set *duplicate = nullptr; for (Tbase_set *c = BaseMedia::available_sets; c != nullptr; c = c->next) { if (c->name == set->name || c->shortname == set->shortname) { @@ -214,7 +214,6 @@ bool BaseMedia::AddFile(const char *filename, size_t basepath_length, } else { delete set; } - free(path); delete ini; return ret; diff --git a/src/crashlog.cpp b/src/crashlog.cpp index 29e650b937..c447019fef 100644 --- a/src/crashlog.cpp +++ b/src/crashlog.cpp @@ -368,7 +368,7 @@ char *CrashLog::FillCrashLog(char *buffer, const char *last) const */ bool CrashLog::WriteCrashLog(const char *buffer, char *filename, const char *filename_last) const { - seprintf(filename, filename_last, "%scrash.log", _personal_dir); + seprintf(filename, filename_last, "%scrash.log", _personal_dir.c_str()); FILE *file = FioFOpenFile(filename, "w", NO_DIRECTORY); if (file == nullptr) return false; @@ -403,7 +403,7 @@ bool CrashLog::WriteSavegame(char *filename, const char *filename_last) const try { GamelogEmergency(); - seprintf(filename, filename_last, "%scrash.sav", _personal_dir); + seprintf(filename, filename_last, "%scrash.sav", _personal_dir.c_str()); /* Don't do a threaded saveload. */ return SaveOrLoad(filename, SLO_SAVE, DFT_GAME_FILE, NO_DIRECTORY, false) == SL_OK; diff --git a/src/fileio.cpp b/src/fileio.cpp index e409d9d2a4..135a6bee21 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -53,8 +53,8 @@ static Fio _fio; ///< #Fio instance. /** Whether the working directory should be scanned. */ static bool _do_scan_working_directory = true; -extern char *_config_file; -extern char *_highscore_file; +extern std::string _config_file; +extern std::string _highscore_file; /** * Get position in the current file. @@ -336,7 +336,7 @@ char *FioGetDirectory(char *buf, const char *last, Subdirectory subdir) } /* Could not find the directory, fall back to a base path */ - strecpy(buf, _personal_dir, last); + strecpy(buf, _personal_dir.c_str(), last); return buf; } @@ -1064,7 +1064,7 @@ void DetermineBasePaths(const char *exe) char cwd[MAX_PATH]; if (getcwd(cwd, MAX_PATH) == nullptr) *cwd = '\0'; - if (_config_file == nullptr) { + if (_config_file.empty()) { /* Get the path to working directory of OpenTTD. */ if (getcwd(tmp, MAX_PATH) == nullptr) *tmp = '\0'; AppendPathSeparator(tmp, lastof(tmp)); @@ -1073,7 +1073,7 @@ void DetermineBasePaths(const char *exe) _do_scan_working_directory = DoScanWorkingDirectory(); } else { /* Use the folder of the config file as working directory. */ - char *config_dir = stredup(_config_file); + char *config_dir = stredup(_config_file.c_str()); char *end = strrchr(config_dir, PATHSEPCHAR); if (end == nullptr) { free(config_dir); @@ -1120,7 +1120,7 @@ extern void cocoaSetApplicationBundleDir(); } #endif /* defined(_WIN32) */ -const char *_personal_dir; +std::string _personal_dir; /** * Acquire the base paths (personal dir and game data dir), @@ -1149,16 +1149,15 @@ void DeterminePaths(const char *exe) DEBUG(misc, 4, "%s added as search path", _searchpaths[sp]); } - const char *config_dir; - if (_config_file != nullptr) { + std::string config_dir; + if (!_config_file.empty()) { config_dir = _searchpaths[SP_WORKING_DIR]; } else { char personal_dir[MAX_PATH]; if (FioFindFullPath(personal_dir, lastof(personal_dir), BASE_DIR, "openttd.cfg") != nullptr) { char *end = strrchr(personal_dir, PATHSEPCHAR); if (end != nullptr) end[1] = '\0'; - config_dir = stredup(personal_dir); - _config_file = str_fmt("%sopenttd.cfg", config_dir); + config_dir = personal_dir; } else { #if defined(WITH_XDG_BASEDIR) && defined(WITH_PERSONAL_DIR) /* No previous configuration file found. Use the configuration folder from XDG. */ @@ -1168,26 +1167,25 @@ void DeterminePaths(const char *exe) SP_PERSONAL_DIR, SP_BINARY_DIR, SP_WORKING_DIR, SP_SHARED_DIR, SP_INSTALLATION_DIR }; - config_dir = nullptr; + config_dir.clear(); for (uint i = 0; i < lengthof(new_openttd_cfg_order); i++) { if (IsValidSearchPath(new_openttd_cfg_order[i])) { - config_dir = stredup(_searchpaths[new_openttd_cfg_order[i]]); + config_dir = _searchpaths[new_openttd_cfg_order[i]]; break; } } - assert(config_dir != nullptr); #endif - _config_file = str_fmt("%sopenttd.cfg", config_dir); } + _config_file = config_dir + "openttd.cfg"; } - DEBUG(misc, 3, "%s found as config directory", config_dir); + DEBUG(misc, 3, "%s found as config directory", config_dir.c_str()); - _highscore_file = str_fmt("%shs.dat", config_dir); - extern char *_hotkeys_file; - _hotkeys_file = str_fmt("%shotkeys.cfg", config_dir); - extern char *_windows_file; - _windows_file = str_fmt("%swindows.cfg", config_dir); + _highscore_file = config_dir + "hs.dat"; + extern std::string _hotkeys_file; + _hotkeys_file = config_dir + "hotkeys.cfg"; + extern std::string _windows_file; + _windows_file = config_dir + "windows.cfg"; #if defined(WITH_XDG_BASEDIR) && defined(WITH_PERSONAL_DIR) if (config_dir == config_home) { @@ -1201,25 +1199,23 @@ void DeterminePaths(const char *exe) } /* Make the necessary folders */ - FioCreateDirectory(config_dir); + FioCreateDirectory(config_dir.c_str()); #if defined(WITH_PERSONAL_DIR) - FioCreateDirectory(_personal_dir); + FioCreateDirectory(_personal_dir.c_str()); #endif - DEBUG(misc, 3, "%s found as personal directory", _personal_dir); + DEBUG(misc, 3, "%s found as personal directory", _personal_dir.c_str()); static const Subdirectory default_subdirs[] = { SAVE_DIR, AUTOSAVE_DIR, SCENARIO_DIR, HEIGHTMAP_DIR, BASESET_DIR, NEWGRF_DIR, AI_DIR, AI_LIBRARY_DIR, GAME_DIR, GAME_LIBRARY_DIR, SCREENSHOT_DIR }; for (uint i = 0; i < lengthof(default_subdirs); i++) { - char *dir = str_fmt("%s%s", _personal_dir, _subdirs[default_subdirs[i]]); - FioCreateDirectory(dir); - free(dir); + FioCreateDirectory((_personal_dir + _subdirs[default_subdirs[i]]).c_str()); } /* If we have network we make a directory for the autodownloading of content */ - _searchpaths[SP_AUTODOWNLOAD_DIR] = str_fmt("%s%s", _personal_dir, "content_download" PATHSEP); + _searchpaths[SP_AUTODOWNLOAD_DIR] = str_fmt("%s%s", _personal_dir.c_str(), "content_download" PATHSEP); FioCreateDirectory(_searchpaths[SP_AUTODOWNLOAD_DIR]); /* Create the directory for each of the types of content */ @@ -1231,8 +1227,7 @@ void DeterminePaths(const char *exe) } extern std::string _log_file; - _log_file = _personal_dir; - _log_file += "openttd.log"; + _log_file = _personal_dir + "openttd.log"; } /** diff --git a/src/fileio_func.h b/src/fileio_func.h index d951318801..b883a00e80 100644 --- a/src/fileio_func.h +++ b/src/fileio_func.h @@ -12,6 +12,7 @@ #include "core/enum_type.hpp" #include "fileio_type.h" +#include void FioSeekTo(size_t pos, int mode); void FioSeekToFile(uint8 slot, size_t pos); @@ -64,7 +65,7 @@ void *ReadFileToMem(const char *filename, size_t *lenp, size_t maxsize); bool FileExists(const char *filename); bool ExtractTar(const char *tar_filename, Subdirectory subdir); -extern const char *_personal_dir; ///< custom directory for personal settings, saves, newgrf, etc. +extern std::string _personal_dir; ///< custom directory for personal settings, saves, newgrf, etc. /** Helper for scanning for files with a given name */ class FileScanner { diff --git a/src/fios_gui.cpp b/src/fios_gui.cpp index 47f7e1e2dd..059bbf0ce9 100644 --- a/src/fios_gui.cpp +++ b/src/fios_gui.cpp @@ -382,7 +382,7 @@ public: break; default: - strecpy(o_dir.name, _personal_dir, lastof(o_dir.name)); + strecpy(o_dir.name, _personal_dir.c_str(), lastof(o_dir.name)); } switch (this->fop) { diff --git a/src/highscore.cpp b/src/highscore.cpp index d8fe348fe0..187df028bd 100644 --- a/src/highscore.cpp +++ b/src/highscore.cpp @@ -20,7 +20,7 @@ #include "safeguards.h" HighScore _highscore_table[SP_HIGHSCORE_END][5]; ///< various difficulty-settings; top 5 -char *_highscore_file; ///< The file to store the highscore data in. +std::string _highscore_file; ///< The file to store the highscore data in. static const StringID _endgame_perf_titles[] = { STR_HIGHSCORE_PERFORMANCE_TITLE_BUSINESSMAN, @@ -123,7 +123,7 @@ int8 SaveHighScoreValueNetwork() /** Save HighScore table to file */ void SaveToHighScore() { - FILE *fp = fopen(_highscore_file, "wb"); + FILE *fp = fopen(_highscore_file.c_str(), "wb"); if (fp != nullptr) { uint i; @@ -151,7 +151,7 @@ void SaveToHighScore() /** Initialize the highscore table to 0 and if any file exists, load in values */ void LoadFromHighScore() { - FILE *fp = fopen(_highscore_file, "rb"); + FILE *fp = fopen(_highscore_file.c_str(), "rb"); memset(_highscore_table, 0, sizeof(_highscore_table)); diff --git a/src/hotkeys.cpp b/src/hotkeys.cpp index 6db3a406b3..0a10290c18 100644 --- a/src/hotkeys.cpp +++ b/src/hotkeys.cpp @@ -16,7 +16,7 @@ #include "safeguards.h" -char *_hotkeys_file; +std::string _hotkeys_file; /** * List of all HotkeyLists. diff --git a/src/ini.cpp b/src/ini.cpp index fc9b1e8fd2..036ced6688 100644 --- a/src/ini.cpp +++ b/src/ini.cpp @@ -43,7 +43,7 @@ IniFile::IniFile(const char * const *list_group_names) : IniLoadFile(list_group_ * @param filename the file to save to. * @return true if saving succeeded. */ -bool IniFile::SaveToDisk(const char *filename) +bool IniFile::SaveToDisk(const std::string &filename) { /* * First write the configuration to a (temporary) file and then rename @@ -96,7 +96,7 @@ bool IniFile::SaveToDisk(const char *filename) # undef strncpy /* Allocate space for one more \0 character. */ TCHAR tfilename[MAX_PATH + 1], tfile_new[MAX_PATH + 1]; - _tcsncpy(tfilename, OTTD2FS(filename), MAX_PATH); + _tcsncpy(tfilename, OTTD2FS(filename.c_str()), MAX_PATH); _tcsncpy(tfile_new, OTTD2FS(file_new.c_str()), MAX_PATH); /* SHFileOperation wants a double '\0' terminated string. */ tfilename[MAX_PATH - 1] = '\0'; @@ -113,8 +113,8 @@ bool IniFile::SaveToDisk(const char *filename) shfopt.pTo = tfilename; SHFileOperation(&shfopt); #else - if (rename(file_new.c_str(), filename) < 0) { - DEBUG(misc, 0, "Renaming %s to %s failed; configuration not saved", file_new.c_str(), filename); + if (rename(file_new.c_str(), filename.c_str()) < 0) { + DEBUG(misc, 0, "Renaming %s to %s failed; configuration not saved", file_new.c_str(), filename.c_str()); } #endif diff --git a/src/ini_load.cpp b/src/ini_load.cpp index 93b6bdf72d..e7c2b95fe6 100644 --- a/src/ini_load.cpp +++ b/src/ini_load.cpp @@ -192,7 +192,7 @@ void IniLoadFile::RemoveGroup(const char *name) * @param subdir the sub directory to load the file from. * @pre nothing has been loaded yet. */ -void IniLoadFile::LoadFromDisk(const char *filename, Subdirectory subdir) +void IniLoadFile::LoadFromDisk(const std::string &filename, Subdirectory subdir) { assert(this->last_group == &this->group); @@ -204,7 +204,7 @@ void IniLoadFile::LoadFromDisk(const char *filename, Subdirectory subdir) uint comment_alloc = 0; size_t end; - FILE *in = this->OpenFile(filename, subdir, &end); + FILE *in = this->OpenFile(filename.c_str(), subdir, &end); if (in == nullptr) return; end += ftell(in); diff --git a/src/ini_type.h b/src/ini_type.h index b5f8398d97..1637174500 100644 --- a/src/ini_type.h +++ b/src/ini_type.h @@ -64,7 +64,7 @@ struct IniLoadFile { IniGroup *GetGroup(const std::string &name, bool create_new = true); void RemoveGroup(const char *name); - void LoadFromDisk(const char *filename, Subdirectory subdir); + void LoadFromDisk(const std::string &filename, Subdirectory subdir); /** * Open the INI file. @@ -88,7 +88,7 @@ struct IniLoadFile { struct IniFile : IniLoadFile { IniFile(const char * const *list_group_names = nullptr); - bool SaveToDisk(const char *filename); + bool SaveToDisk(const std::string &filename); virtual FILE *OpenFile(const char *filename, Subdirectory subdir, size_t *size); virtual void ReportFileError(const char * const pre, const char * const buffer, const char * const post); diff --git a/src/openttd.cpp b/src/openttd.cpp index 89cc15c35a..2409e8e4e3 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -88,7 +88,7 @@ bool HandleBootstrap(); extern Company *DoStartupNewCompany(bool is_ai, CompanyID company = INVALID_COMPANY); extern void ShowOSErrorBox(const char *buf, bool system); -extern char *_config_file; +extern std::string _config_file; bool _save_config = false; @@ -316,8 +316,6 @@ static void ShutdownGame() /* Uninitialize variables that are allocated dynamically */ GamelogReset(); - free(_config_file); - LinkGraphSchedule::Clear(); PoolBase::Clean(PT_ALL); @@ -566,7 +564,6 @@ int openttd_main(int argc, char *argv[]) _game_mode = GM_MENU; _switch_mode = SM_MENU; - _config_file = nullptr; GetOptData mgo(argc - 1, argv + 1, _options); int ret = 0; @@ -672,7 +669,7 @@ int openttd_main(int argc, char *argv[]) return ret; } case 'G': scanner->generation_seed = strtoul(mgo.opt, nullptr, 10); break; - case 'c': free(_config_file); _config_file = stredup(mgo.opt); break; + case 'c': _config_file = mgo.opt; break; case 'x': scanner->save_config = false; break; case 'h': i = -2; // Force printing of help. diff --git a/src/os/windows/crashlog_win.cpp b/src/os/windows/crashlog_win.cpp index 7a1a524aa5..c96c4cf7c2 100644 --- a/src/os/windows/crashlog_win.cpp +++ b/src/os/windows/crashlog_win.cpp @@ -499,7 +499,7 @@ char *CrashLogWindows::AppendDecodedStacktrace(char *buffer, const char *last) c CONST PMINIDUMP_CALLBACK_INFORMATION); MiniDumpWriteDump_t funcMiniDumpWriteDump = (MiniDumpWriteDump_t)GetProcAddress(dbghelp, "MiniDumpWriteDump"); if (funcMiniDumpWriteDump != nullptr) { - seprintf(filename, filename_last, "%scrash.dmp", _personal_dir); + seprintf(filename, filename_last, "%scrash.dmp", _personal_dir.c_str()); HANDLE file = CreateFile(OTTD2FS(filename), GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, 0, 0); HANDLE proc = GetCurrentProcess(); DWORD procid = GetCurrentProcessId(); diff --git a/src/os/windows/win32.cpp b/src/os/windows/win32.cpp index 468234391c..c4e400279a 100644 --- a/src/os/windows/win32.cpp +++ b/src/os/windows/win32.cpp @@ -451,7 +451,7 @@ char *getcwd(char *buf, size_t size) return buf; } -extern char *_config_file; +extern std::string _config_file; void DetermineBasePaths(const char *exe) { @@ -482,7 +482,7 @@ void DetermineBasePaths(const char *exe) _searchpaths[SP_SHARED_DIR] = nullptr; #endif - if (_config_file == nullptr) { + if (_config_file.empty()) { /* Get the path to working directory of OpenTTD. */ getcwd(tmp, lengthof(tmp)); AppendPathSeparator(tmp, lastof(tmp)); @@ -490,7 +490,7 @@ void DetermineBasePaths(const char *exe) } else { /* Use the folder of the config file as working directory. */ TCHAR config_dir[MAX_PATH]; - _tcsncpy(path, convert_to_fs(_config_file, path, lengthof(path)), lengthof(path)); + _tcsncpy(path, convert_to_fs(_config_file.c_str(), path, lengthof(path)), lengthof(path)); if (!GetFullPathName(path, lengthof(config_dir), config_dir, nullptr)) { DEBUG(misc, 0, "GetFullPathName failed (%lu)\n", GetLastError()); _searchpaths[SP_WORKING_DIR] = nullptr; diff --git a/src/screenshot.cpp b/src/screenshot.cpp index b832e2224b..1274a4c50f 100644 --- a/src/screenshot.cpp +++ b/src/screenshot.cpp @@ -681,7 +681,7 @@ static const char *MakeScreenshotName(const char *default_fn, const char *ext, b size_t len = strlen(_screenshot_name); seprintf(&_screenshot_name[len], lastof(_screenshot_name), ".%s", ext); - const char *screenshot_dir = crashlog ? _personal_dir : FiosGetScreenshotDir(); + const char *screenshot_dir = crashlog ? _personal_dir.c_str() : FiosGetScreenshotDir(); for (uint serial = 1;; serial++) { if (seprintf(_full_screenshot_name, lastof(_full_screenshot_name), "%s%s", screenshot_dir, _screenshot_name) >= (int)lengthof(_full_screenshot_name)) { diff --git a/src/settings.cpp b/src/settings.cpp index 02cd520049..b5a07fbb25 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -80,7 +80,7 @@ ClientSettings _settings_client; GameSettings _settings_game; ///< Game settings of a running game or the scenario editor. GameSettings _settings_newgame; ///< Game settings for new games (updated from the intro screen). VehicleDefaultSettings _old_vds; ///< Used for loading default vehicles settings from old savegames -char *_config_file; ///< Configuration file of OpenTTD +std::string _config_file; ///< Configuration file of OpenTTD typedef std::list ErrorList; static ErrorList _settings_error_list; ///< Errors while loading minimal settings. diff --git a/src/window.cpp b/src/window.cpp index 6fd4d0d0b6..feabbfdd26 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -86,7 +86,7 @@ SpecialMouseMode _special_mouse_mode; ///< Mode of the mouse. static std::vector *_window_descs = nullptr; /** Config file to store WindowDesc */ -char *_windows_file; +std::string _windows_file; /** Window description constructor. */ WindowDesc::WindowDesc(WindowPosition def_pos, const char *ini_key, int16 def_width_trad, int16 def_height_trad, From 0c6e8a8123c9f74db757272f73adcbd8621e012d Mon Sep 17 00:00:00 2001 From: Michael Lutz Date: Sun, 6 Dec 2020 21:11:43 +0100 Subject: [PATCH 21/64] Codechange: Store file search paths as std::string. --- src/fileio.cpp | 93 ++++++++++++++++++++++---------------- src/fileio_func.h | 13 +----- src/fileio_type.h | 2 +- src/os/windows/win32.cpp | 31 +++++++------ src/string.cpp | 11 +++++ src/string_func.h | 1 + src/video/cocoa/cocoa_v.mm | 7 ++- 7 files changed, 89 insertions(+), 69 deletions(-) diff --git a/src/fileio.cpp b/src/fileio.cpp index 135a6bee21..aed0106fb1 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -25,6 +25,7 @@ #endif #include #include +#include #include #ifdef WITH_XDG_BASEDIR @@ -240,13 +241,29 @@ static const char * const _subdirs[] = { }; static_assert(lengthof(_subdirs) == NUM_SUBDIRS); -const char *_searchpaths[NUM_SEARCHPATHS]; +/** + * The search paths OpenTTD could search through. + * At least one of the slots has to be filled with a path. + * An empty string tells that there is no such path for the + * current operating system. + */ +std::array _searchpaths; TarList _tar_list[NUM_SUBDIRS]; TarFileList _tar_filelist[NUM_SUBDIRS]; typedef std::map TarLinkList; static TarLinkList _tar_linklist[NUM_SUBDIRS]; ///< List of directory links +/** + * Checks whether the given search path is a valid search path + * @param sp the search path to check + * @return true if the search path is valid + */ +bool IsValidSearchPath(Searchpath sp) +{ + return sp < _searchpaths.size() && !_searchpaths[sp].empty(); +} + /** * Check whether the given file exists * @param filename the file to try for existence. @@ -285,7 +302,7 @@ char *FioGetFullPath(char *buf, const char *last, Searchpath sp, Subdirectory su assert(subdir < NUM_SUBDIRS); assert(sp < NUM_SEARCHPATHS); - seprintf(buf, last, "%s%s%s", _searchpaths[sp], _subdirs[subdir], filename); + seprintf(buf, last, "%s%s%s", _searchpaths[sp].c_str(), _subdirs[subdir], filename); return buf; } @@ -309,7 +326,7 @@ char *FioFindFullPath(char *buf, const char *last, Subdirectory subdir, const ch /* Be, as opening files, aware that sometimes the filename * might be in uppercase when it is in lowercase on the * disk. Of course Windows doesn't care about casing. */ - if (strtolower(buf + strlen(_searchpaths[sp]) - 1) && FileExists(buf)) return buf; + if (strtolower(buf + _searchpaths[sp].size() - 1) && FileExists(buf)) return buf; #endif } @@ -321,7 +338,7 @@ char *FioAppendDirectory(char *buf, const char *last, Searchpath sp, Subdirector assert(subdir < NUM_SUBDIRS); assert(sp < NUM_SEARCHPATHS); - seprintf(buf, last, "%s%s", _searchpaths[sp], _subdirs[subdir]); + seprintf(buf, last, "%s%s", _searchpaths[sp].c_str(), _subdirs[subdir]); return buf; } @@ -352,22 +369,22 @@ static FILE *FioFOpenFileSp(const char *filename, const char *mode, Searchpath s MultiByteToWideChar(CP_ACP, 0, mode, -1, Lmode, lengthof(Lmode)); #endif FILE *f = nullptr; - char buf[MAX_PATH]; + std::string buf; if (subdir == NO_DIRECTORY) { - strecpy(buf, filename, lastof(buf)); + buf = filename; } else { - seprintf(buf, lastof(buf), "%s%s%s", _searchpaths[sp], _subdirs[subdir], filename); + buf = _searchpaths[sp] + _subdirs[subdir] + filename; } #if defined(_WIN32) - if (mode[0] == 'r' && GetFileAttributes(OTTD2FS(buf)) == INVALID_FILE_ATTRIBUTES) return nullptr; + if (mode[0] == 'r' && GetFileAttributes(OTTD2FS(buf.c_str())) == INVALID_FILE_ATTRIBUTES) return nullptr; #endif - f = fopen(buf, mode); + f = fopen(buf.c_str(), mode); #if !defined(_WIN32) - if (f == nullptr && strtolower(buf + ((subdir == NO_DIRECTORY) ? 0 : strlen(_searchpaths[sp]) - 1))) { - f = fopen(buf, mode); + if (f == nullptr && strtolower(buf, subdir == NO_DIRECTORY ? 0 : _searchpaths[sp].size() - 1) ) { + f = fopen(buf.c_str(), mode); } #endif if (f != nullptr && filesize != nullptr) { @@ -988,18 +1005,18 @@ static bool ChangeWorkingDirectoryToExecutable(const char *exe) bool DoScanWorkingDirectory() { /* No working directory, so nothing to do. */ - if (_searchpaths[SP_WORKING_DIR] == nullptr) return false; + if (_searchpaths[SP_WORKING_DIR].empty()) return false; /* Working directory is root, so do nothing. */ - if (strcmp(_searchpaths[SP_WORKING_DIR], PATHSEP) == 0) return false; + if (_searchpaths[SP_WORKING_DIR] == PATHSEP) return false; /* No personal/home directory, so the working directory won't be that. */ - if (_searchpaths[SP_PERSONAL_DIR] == nullptr) return true; + if (_searchpaths[SP_PERSONAL_DIR].empty()) return true; char tmp[MAX_PATH]; - seprintf(tmp, lastof(tmp), "%s%s", _searchpaths[SP_WORKING_DIR], PERSONAL_DIR); + seprintf(tmp, lastof(tmp), "%s%s", _searchpaths[SP_WORKING_DIR].c_str(), PERSONAL_DIR); AppendPathSeparator(tmp, lastof(tmp)); - return strcmp(tmp, _searchpaths[SP_PERSONAL_DIR]) != 0; + return _searchpaths[SP_PERSONAL_DIR] != tmp; } /** @@ -1016,10 +1033,10 @@ void DetermineBasePaths(const char *exe) free(xdg_data_home); AppendPathSeparator(tmp, lastof(tmp)); - _searchpaths[SP_PERSONAL_DIR_XDG] = stredup(tmp); + _searchpaths[SP_PERSONAL_DIR_XDG] = tmp; #endif #if defined(OS2) || !defined(WITH_PERSONAL_DIR) - _searchpaths[SP_PERSONAL_DIR] = nullptr; + _searchpaths[SP_PERSONAL_DIR].clear(); #else #ifdef __HAIKU__ BPath path; @@ -1046,19 +1063,19 @@ void DetermineBasePaths(const char *exe) seprintf(tmp, lastof(tmp), "%s" PATHSEP "%s", homedir, PERSONAL_DIR); AppendPathSeparator(tmp, lastof(tmp)); - _searchpaths[SP_PERSONAL_DIR] = stredup(tmp); + _searchpaths[SP_PERSONAL_DIR] = tmp; free(homedir); } else { - _searchpaths[SP_PERSONAL_DIR] = nullptr; + _searchpaths[SP_PERSONAL_DIR].clear(); } #endif #if defined(WITH_SHARED_DIR) seprintf(tmp, lastof(tmp), "%s", SHARED_DIR); AppendPathSeparator(tmp, lastof(tmp)); - _searchpaths[SP_SHARED_DIR] = stredup(tmp); + _searchpaths[SP_SHARED_DIR] = tmp; #else - _searchpaths[SP_SHARED_DIR] = nullptr; + _searchpaths[SP_SHARED_DIR].clear(); #endif char cwd[MAX_PATH]; @@ -1068,23 +1085,19 @@ void DetermineBasePaths(const char *exe) /* Get the path to working directory of OpenTTD. */ if (getcwd(tmp, MAX_PATH) == nullptr) *tmp = '\0'; AppendPathSeparator(tmp, lastof(tmp)); - _searchpaths[SP_WORKING_DIR] = stredup(tmp); + _searchpaths[SP_WORKING_DIR] = tmp; _do_scan_working_directory = DoScanWorkingDirectory(); } else { /* Use the folder of the config file as working directory. */ - char *config_dir = stredup(_config_file.c_str()); - char *end = strrchr(config_dir, PATHSEPCHAR); - if (end == nullptr) { - free(config_dir); - + size_t end = _config_file.find_last_of(PATHSEPCHAR); + if (end == std::string::npos) { /* _config_file is not in a folder, so use current directory. */ if (getcwd(tmp, MAX_PATH) == nullptr) *tmp = '\0'; AppendPathSeparator(tmp, lastof(tmp)); - _searchpaths[SP_WORKING_DIR] = stredup(tmp); + _searchpaths[SP_WORKING_DIR] = tmp; } else { - end[1] = '\0'; - _searchpaths[SP_WORKING_DIR] = config_dir; + _searchpaths[SP_WORKING_DIR] = _config_file.substr(0, end + 1); } } @@ -1092,9 +1105,9 @@ void DetermineBasePaths(const char *exe) if (ChangeWorkingDirectoryToExecutable(exe)) { if (getcwd(tmp, MAX_PATH) == nullptr) *tmp = '\0'; AppendPathSeparator(tmp, lastof(tmp)); - _searchpaths[SP_BINARY_DIR] = stredup(tmp); + _searchpaths[SP_BINARY_DIR] = tmp; } else { - _searchpaths[SP_BINARY_DIR] = nullptr; + _searchpaths[SP_BINARY_DIR].clear(); } if (cwd[0] != '\0') { @@ -1105,17 +1118,17 @@ void DetermineBasePaths(const char *exe) } #if !defined(GLOBAL_DATA_DIR) - _searchpaths[SP_INSTALLATION_DIR] = nullptr; + _searchpaths[SP_INSTALLATION_DIR].clear(); #else seprintf(tmp, lastof(tmp), "%s", GLOBAL_DATA_DIR); AppendPathSeparator(tmp, lastof(tmp)); - _searchpaths[SP_INSTALLATION_DIR] = stredup(tmp); + _searchpaths[SP_INSTALLATION_DIR] = tmp; #endif #ifdef WITH_COCOA extern void cocoaSetApplicationBundleDir(); cocoaSetApplicationBundleDir(); #else - _searchpaths[SP_APPLICATION_BUNDLE_DIR] = nullptr; + _searchpaths[SP_APPLICATION_BUNDLE_DIR].clear(); #endif } #endif /* defined(_WIN32) */ @@ -1146,7 +1159,7 @@ void DeterminePaths(const char *exe) Searchpath sp; FOR_ALL_SEARCHPATHS(sp) { if (sp == SP_WORKING_DIR && !_do_scan_working_directory) continue; - DEBUG(misc, 4, "%s added as search path", _searchpaths[sp]); + DEBUG(misc, 4, "%s added as search path", _searchpaths[sp].c_str()); } std::string config_dir; @@ -1215,13 +1228,13 @@ void DeterminePaths(const char *exe) } /* If we have network we make a directory for the autodownloading of content */ - _searchpaths[SP_AUTODOWNLOAD_DIR] = str_fmt("%s%s", _personal_dir.c_str(), "content_download" PATHSEP); - FioCreateDirectory(_searchpaths[SP_AUTODOWNLOAD_DIR]); + _searchpaths[SP_AUTODOWNLOAD_DIR] = _personal_dir + "content_download" PATHSEP; + FioCreateDirectory(_searchpaths[SP_AUTODOWNLOAD_DIR].c_str()); /* Create the directory for each of the types of content */ const Subdirectory dirs[] = { SCENARIO_DIR, HEIGHTMAP_DIR, BASESET_DIR, NEWGRF_DIR, AI_DIR, AI_LIBRARY_DIR, GAME_DIR, GAME_LIBRARY_DIR }; for (uint i = 0; i < lengthof(dirs); i++) { - char *tmp = str_fmt("%s%s", _searchpaths[SP_AUTODOWNLOAD_DIR], _subdirs[dirs[i]]); + char *tmp = str_fmt("%s%s", _searchpaths[SP_AUTODOWNLOAD_DIR].c_str(), _subdirs[dirs[i]]); FioCreateDirectory(tmp); free(tmp); } diff --git a/src/fileio_func.h b/src/fileio_func.h index b883a00e80..a4bdeb0076 100644 --- a/src/fileio_func.h +++ b/src/fileio_func.h @@ -26,23 +26,12 @@ void FioOpenFile(int slot, const char *filename, Subdirectory subdir); void FioReadBlock(void *ptr, size_t size); void FioSkipBytes(int n); -/** - * The search paths OpenTTD could search through. - * At least one of the slots has to be filled with a path. - * nullptr paths tell that there is no such path for the - * current operating system. - */ -extern const char *_searchpaths[NUM_SEARCHPATHS]; - /** * Checks whether the given search path is a valid search path * @param sp the search path to check * @return true if the search path is valid */ -static inline bool IsValidSearchPath(Searchpath sp) -{ - return sp < NUM_SEARCHPATHS && _searchpaths[sp] != nullptr; -} +bool IsValidSearchPath(Searchpath sp); /** Iterator for all the search paths */ #define FOR_ALL_SEARCHPATHS(sp) for (sp = SP_FIRST_DIR; sp < NUM_SEARCHPATHS; sp++) if (IsValidSearchPath(sp)) diff --git a/src/fileio_type.h b/src/fileio_type.h index 15f886d050..62147f9e6e 100644 --- a/src/fileio_type.h +++ b/src/fileio_type.h @@ -128,7 +128,7 @@ enum Subdirectory { /** * Types of searchpaths OpenTTD might use */ -enum Searchpath { +enum Searchpath : unsigned { SP_FIRST_DIR, SP_WORKING_DIR = SP_FIRST_DIR, ///< Search in the working directory #if defined(WITH_XDG_BASEDIR) && defined(WITH_PERSONAL_DIR) diff --git a/src/os/windows/win32.cpp b/src/os/windows/win32.cpp index c4e400279a..7553740e76 100644 --- a/src/os/windows/win32.cpp +++ b/src/os/windows/win32.cpp @@ -29,6 +29,7 @@ #include #include "../../language.h" #include "../../thread.h" +#include #include "../../safeguards.h" @@ -455,6 +456,8 @@ extern std::string _config_file; void DetermineBasePaths(const char *exe) { + extern std::array _searchpaths; + char tmp[MAX_PATH]; TCHAR path[MAX_PATH]; #ifdef WITH_PERSONAL_DIR @@ -463,9 +466,9 @@ void DetermineBasePaths(const char *exe) AppendPathSeparator(tmp, lastof(tmp)); strecat(tmp, PERSONAL_DIR, lastof(tmp)); AppendPathSeparator(tmp, lastof(tmp)); - _searchpaths[SP_PERSONAL_DIR] = stredup(tmp); + _searchpaths[SP_PERSONAL_DIR] = tmp; } else { - _searchpaths[SP_PERSONAL_DIR] = nullptr; + _searchpaths[SP_PERSONAL_DIR].clear(); } if (SUCCEEDED(OTTDSHGetFolderPath(nullptr, CSIDL_COMMON_DOCUMENTS, nullptr, SHGFP_TYPE_CURRENT, path))) { @@ -473,54 +476,54 @@ void DetermineBasePaths(const char *exe) AppendPathSeparator(tmp, lastof(tmp)); strecat(tmp, PERSONAL_DIR, lastof(tmp)); AppendPathSeparator(tmp, lastof(tmp)); - _searchpaths[SP_SHARED_DIR] = stredup(tmp); + _searchpaths[SP_SHARED_DIR] = tmp; } else { - _searchpaths[SP_SHARED_DIR] = nullptr; + _searchpaths[SP_SHARED_DIR].clear(); } #else - _searchpaths[SP_PERSONAL_DIR] = nullptr; - _searchpaths[SP_SHARED_DIR] = nullptr; + _searchpaths[SP_PERSONAL_DIR].clear(); + _searchpaths[SP_SHARED_DIR].clear(); #endif if (_config_file.empty()) { /* Get the path to working directory of OpenTTD. */ getcwd(tmp, lengthof(tmp)); AppendPathSeparator(tmp, lastof(tmp)); - _searchpaths[SP_WORKING_DIR] = stredup(tmp); + _searchpaths[SP_WORKING_DIR] = tmp; } else { /* Use the folder of the config file as working directory. */ TCHAR config_dir[MAX_PATH]; _tcsncpy(path, convert_to_fs(_config_file.c_str(), path, lengthof(path)), lengthof(path)); if (!GetFullPathName(path, lengthof(config_dir), config_dir, nullptr)) { DEBUG(misc, 0, "GetFullPathName failed (%lu)\n", GetLastError()); - _searchpaths[SP_WORKING_DIR] = nullptr; + _searchpaths[SP_WORKING_DIR].clear(); } else { strecpy(tmp, convert_from_fs(config_dir, tmp, lengthof(tmp)), lastof(tmp)); char *s = strrchr(tmp, PATHSEPCHAR); *(s + 1) = '\0'; - _searchpaths[SP_WORKING_DIR] = stredup(tmp); + _searchpaths[SP_WORKING_DIR] = tmp; } } if (!GetModuleFileName(nullptr, path, lengthof(path))) { DEBUG(misc, 0, "GetModuleFileName failed (%lu)\n", GetLastError()); - _searchpaths[SP_BINARY_DIR] = nullptr; + _searchpaths[SP_BINARY_DIR].clear(); } else { TCHAR exec_dir[MAX_PATH]; _tcsncpy(path, convert_to_fs(exe, path, lengthof(path)), lengthof(path)); if (!GetFullPathName(path, lengthof(exec_dir), exec_dir, nullptr)) { DEBUG(misc, 0, "GetFullPathName failed (%lu)\n", GetLastError()); - _searchpaths[SP_BINARY_DIR] = nullptr; + _searchpaths[SP_BINARY_DIR].clear(); } else { strecpy(tmp, convert_from_fs(exec_dir, tmp, lengthof(tmp)), lastof(tmp)); char *s = strrchr(tmp, PATHSEPCHAR); *(s + 1) = '\0'; - _searchpaths[SP_BINARY_DIR] = stredup(tmp); + _searchpaths[SP_BINARY_DIR] = tmp; } } - _searchpaths[SP_INSTALLATION_DIR] = nullptr; - _searchpaths[SP_APPLICATION_BUNDLE_DIR] = nullptr; + _searchpaths[SP_INSTALLATION_DIR].clear(); + _searchpaths[SP_APPLICATION_BUNDLE_DIR].clear(); } diff --git a/src/string.cpp b/src/string.cpp index d0de261e53..14bc926c1a 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -362,6 +362,17 @@ bool strtolower(char *str) return changed; } +bool strtolower(std::string &str, std::string::size_type offs) +{ + bool changed = false; + for (auto ch = str.begin() + offs; ch != str.end(); ++ch) { + auto new_ch = static_cast(tolower(static_cast(*ch))); + changed |= new_ch != *ch; + *ch = new_ch; + } + return changed; +} + /** * Only allow certain keys. You can define the filter to be used. This makes * sure no invalid keys can get into an editbox, like BELL. diff --git a/src/string_func.h b/src/string_func.h index 6c226c6104..13e14f2d39 100644 --- a/src/string_func.h +++ b/src/string_func.h @@ -46,6 +46,7 @@ void ValidateString(const char *str); void str_fix_scc_encoded(char *str, const char *last); void str_strip_colours(char *str); bool strtolower(char *str); +bool strtolower(std::string &str, std::string::size_type offs = 0); bool StrValid(const char *str, const char *last); diff --git a/src/video/cocoa/cocoa_v.mm b/src/video/cocoa/cocoa_v.mm index 10f30027bc..f02599799c 100644 --- a/src/video/cocoa/cocoa_v.mm +++ b/src/video/cocoa/cocoa_v.mm @@ -34,6 +34,7 @@ #include "../../window_func.h" #include "../../window_gui.h" +#include #import /* for MAXPATHLEN */ /** @@ -545,13 +546,15 @@ void CocoaDialog(const char *title, const char *message, const char *buttonLabel */ void cocoaSetApplicationBundleDir() { + extern std::array _searchpaths; + char tmp[MAXPATHLEN]; CFAutoRelease url(CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle())); if (CFURLGetFileSystemRepresentation(url.get(), true, (unsigned char*)tmp, MAXPATHLEN)) { AppendPathSeparator(tmp, lastof(tmp)); - _searchpaths[SP_APPLICATION_BUNDLE_DIR] = stredup(tmp); + _searchpaths[SP_APPLICATION_BUNDLE_DIR] = tmp; } else { - _searchpaths[SP_APPLICATION_BUNDLE_DIR] = NULL; + _searchpaths[SP_APPLICATION_BUNDLE_DIR].clear(); } } From f3326d34e78bd28fba6d8cfd3bc455a506b429fe Mon Sep 17 00:00:00 2001 From: Michael Lutz Date: Sun, 6 Dec 2020 21:11:44 +0100 Subject: [PATCH 22/64] Codechange: Use std::string in FIO search path handling. --- src/fileio.cpp | 138 ++++++++++++++------------------ src/fileio_func.h | 9 +-- src/fios.cpp | 109 +++++++++++-------------- src/fios_gui.cpp | 10 ++- src/music/midifile.cpp | 33 ++++---- src/network/network_content.cpp | 27 ++++--- src/os/windows/win32.cpp | 40 ++++----- src/script/script_instance.cpp | 11 ++- src/strings.cpp | 5 +- src/video/cocoa/cocoa_v.mm | 2 +- src/video/sdl2_v.cpp | 6 +- src/video/sdl_v.cpp | 6 +- 12 files changed, 180 insertions(+), 216 deletions(-) diff --git a/src/fileio.cpp b/src/fileio.cpp index aed0106fb1..afdbdd256c 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -297,65 +297,52 @@ void FioFCloseFile(FILE *f) fclose(f); } -char *FioGetFullPath(char *buf, const char *last, Searchpath sp, Subdirectory subdir, const char *filename) -{ - assert(subdir < NUM_SUBDIRS); - assert(sp < NUM_SEARCHPATHS); - - seprintf(buf, last, "%s%s%s", _searchpaths[sp].c_str(), _subdirs[subdir], filename); - return buf; -} - /** * Find a path to the filename in one of the search directories. - * @param[out] buf Destination buffer for the path. - * @param last End of the destination buffer. * @param subdir Subdirectory to try. * @param filename Filename to look for. - * @return \a buf containing the path if the path was found, else \c nullptr. + * @return String containing the path if the path was found, else an empty string. */ -char *FioFindFullPath(char *buf, const char *last, Subdirectory subdir, const char *filename) +std::string FioFindFullPath(Subdirectory subdir, const char *filename) { Searchpath sp; assert(subdir < NUM_SUBDIRS); FOR_ALL_SEARCHPATHS(sp) { - FioGetFullPath(buf, last, sp, subdir, filename); - if (FileExists(buf)) return buf; + std::string buf = FioGetDirectory(sp, subdir); + buf += filename; + if (FileExists(buf.c_str())) return buf; #if !defined(_WIN32) /* Be, as opening files, aware that sometimes the filename * might be in uppercase when it is in lowercase on the * disk. Of course Windows doesn't care about casing. */ - if (strtolower(buf + _searchpaths[sp].size() - 1) && FileExists(buf)) return buf; + if (strtolower(buf, _searchpaths[sp].size() - 1) && FileExists(buf.c_str())) return buf; #endif } - return nullptr; + return {}; } -char *FioAppendDirectory(char *buf, const char *last, Searchpath sp, Subdirectory subdir) +std::string FioGetDirectory(Searchpath sp, Subdirectory subdir) { assert(subdir < NUM_SUBDIRS); assert(sp < NUM_SEARCHPATHS); - seprintf(buf, last, "%s%s", _searchpaths[sp].c_str(), _subdirs[subdir]); - return buf; + return _searchpaths[sp] + _subdirs[subdir]; } -char *FioGetDirectory(char *buf, const char *last, Subdirectory subdir) +std::string FioFindDirectory(Subdirectory subdir) { Searchpath sp; /* Find and return the first valid directory */ FOR_ALL_SEARCHPATHS(sp) { - char *ret = FioAppendDirectory(buf, last, sp, subdir); - if (FileExists(buf)) return ret; + std::string ret = FioGetDirectory(sp, subdir); + if (FileExists(ret.c_str())) return ret; } /* Could not find the directory, fall back to a base path */ - strecpy(buf, _personal_dir.c_str(), last); - - return buf; + return _personal_dir; } static FILE *FioFOpenFileSp(const char *filename, const char *mode, Searchpath sp, Subdirectory subdir, size_t *filesize) @@ -545,21 +532,13 @@ void FioCreateDirectory(const char *name) * Appends, if necessary, the path separator character to the end of the string. * It does not add the path separator to zero-sized strings. * @param buf string to append the separator to - * @param last the last element of \a buf. * @return true iff the operation succeeded */ -bool AppendPathSeparator(char *buf, const char *last) +void AppendPathSeparator(std::string &buf) { - size_t s = strlen(buf); + if (buf.empty()) return; - /* Length of string + path separator + '\0' */ - if (s != 0 && buf[s - 1] != PATHSEPCHAR) { - if (&buf[s] >= last) return false; - - seprintf(buf + s, last, "%c", PATHSEPCHAR); - } - - return true; + if (buf.back() != PATHSEPCHAR) buf.push_back(PATHSEPCHAR); } static void TarAddLink(const std::string &srcParam, const std::string &destParam, Subdirectory subdir) @@ -1013,9 +992,9 @@ bool DoScanWorkingDirectory() /* No personal/home directory, so the working directory won't be that. */ if (_searchpaths[SP_PERSONAL_DIR].empty()) return true; - char tmp[MAX_PATH]; - seprintf(tmp, lastof(tmp), "%s%s", _searchpaths[SP_WORKING_DIR].c_str(), PERSONAL_DIR); - AppendPathSeparator(tmp, lastof(tmp)); + std::string tmp = _searchpaths[SP_WORKING_DIR] + PERSONAL_DIR; + AppendPathSeparator(tmp); + return _searchpaths[SP_PERSONAL_DIR] != tmp; } @@ -1025,14 +1004,15 @@ bool DoScanWorkingDirectory() */ void DetermineBasePaths(const char *exe) { - char tmp[MAX_PATH]; + std::string tmp; #if defined(WITH_XDG_BASEDIR) && defined(WITH_PERSONAL_DIR) const char *xdg_data_home = xdgDataHome(nullptr); - seprintf(tmp, lastof(tmp), "%s" PATHSEP "%s", xdg_data_home, - PERSONAL_DIR[0] == '.' ? &PERSONAL_DIR[1] : PERSONAL_DIR); + tmp = xdg_data_home; + tmp += PATHSEP; + tmp += PERSONAL_DIR[0] == '.' ? &PERSONAL_DIR[1] : PERSONAL_DIR; free(xdg_data_home); - AppendPathSeparator(tmp, lastof(tmp)); + AppendPathSeparator(tmp); _searchpaths[SP_PERSONAL_DIR_XDG] = tmp; #endif #if defined(OS2) || !defined(WITH_PERSONAL_DIR) @@ -1060,8 +1040,10 @@ void DetermineBasePaths(const char *exe) if (homedir != nullptr) { ValidateString(homedir); - seprintf(tmp, lastof(tmp), "%s" PATHSEP "%s", homedir, PERSONAL_DIR); - AppendPathSeparator(tmp, lastof(tmp)); + tmp = homedir; + tmp += PATHSEP; + tmp += PERSONAL_DIR; + AppendPathSeparator(tmp); _searchpaths[SP_PERSONAL_DIR] = tmp; free(homedir); @@ -1071,8 +1053,8 @@ void DetermineBasePaths(const char *exe) #endif #if defined(WITH_SHARED_DIR) - seprintf(tmp, lastof(tmp), "%s", SHARED_DIR); - AppendPathSeparator(tmp, lastof(tmp)); + tmp = SHARED_DIR; + AppendPathSeparator(tmp); _searchpaths[SP_SHARED_DIR] = tmp; #else _searchpaths[SP_SHARED_DIR].clear(); @@ -1083,8 +1065,8 @@ void DetermineBasePaths(const char *exe) if (_config_file.empty()) { /* Get the path to working directory of OpenTTD. */ - if (getcwd(tmp, MAX_PATH) == nullptr) *tmp = '\0'; - AppendPathSeparator(tmp, lastof(tmp)); + tmp = cwd; + AppendPathSeparator(tmp); _searchpaths[SP_WORKING_DIR] = tmp; _do_scan_working_directory = DoScanWorkingDirectory(); @@ -1093,8 +1075,8 @@ void DetermineBasePaths(const char *exe) size_t end = _config_file.find_last_of(PATHSEPCHAR); if (end == std::string::npos) { /* _config_file is not in a folder, so use current directory. */ - if (getcwd(tmp, MAX_PATH) == nullptr) *tmp = '\0'; - AppendPathSeparator(tmp, lastof(tmp)); + tmp = cwd; + AppendPathSeparator(tmp); _searchpaths[SP_WORKING_DIR] = tmp; } else { _searchpaths[SP_WORKING_DIR] = _config_file.substr(0, end + 1); @@ -1103,8 +1085,13 @@ void DetermineBasePaths(const char *exe) /* Change the working directory to that one of the executable */ if (ChangeWorkingDirectoryToExecutable(exe)) { - if (getcwd(tmp, MAX_PATH) == nullptr) *tmp = '\0'; - AppendPathSeparator(tmp, lastof(tmp)); + char buf[MAX_PATH]; + if (getcwd(buf, lengthof(buf)) == nullptr) { + tmp.clear(); + } else { + tmp = buf; + } + AppendPathSeparator(tmp); _searchpaths[SP_BINARY_DIR] = tmp; } else { _searchpaths[SP_BINARY_DIR].clear(); @@ -1120,8 +1107,8 @@ void DetermineBasePaths(const char *exe) #if !defined(GLOBAL_DATA_DIR) _searchpaths[SP_INSTALLATION_DIR].clear(); #else - seprintf(tmp, lastof(tmp), "%s", GLOBAL_DATA_DIR); - AppendPathSeparator(tmp, lastof(tmp)); + tmp = GLOBAL_DATA_DIR; + AppendPathSeparator(tmp); _searchpaths[SP_INSTALLATION_DIR] = tmp; #endif #ifdef WITH_COCOA @@ -1146,14 +1133,13 @@ void DeterminePaths(const char *exe) DetermineBasePaths(exe); #if defined(WITH_XDG_BASEDIR) && defined(WITH_PERSONAL_DIR) - char config_home[MAX_PATH]; - const char *xdg_config_home = xdgConfigHome(nullptr); - seprintf(config_home, lastof(config_home), "%s" PATHSEP "%s", xdg_config_home, - PERSONAL_DIR[0] == '.' ? &PERSONAL_DIR[1] : PERSONAL_DIR); + std::string config_home(xdg_config_home); + config_home += PATHSEP; + config_home += PERSONAL_DIR[0] == '.' ? &PERSONAL_DIR[1] : PERSONAL_DIR; free(xdg_config_home); - AppendPathSeparator(config_home, lastof(config_home)); + AppendPathSeparator(config_home); #endif Searchpath sp; @@ -1166,10 +1152,10 @@ void DeterminePaths(const char *exe) if (!_config_file.empty()) { config_dir = _searchpaths[SP_WORKING_DIR]; } else { - char personal_dir[MAX_PATH]; - if (FioFindFullPath(personal_dir, lastof(personal_dir), BASE_DIR, "openttd.cfg") != nullptr) { - char *end = strrchr(personal_dir, PATHSEPCHAR); - if (end != nullptr) end[1] = '\0'; + std::string personal_dir = FioFindFullPath(BASE_DIR, "openttd.cfg"); + if (!personal_dir.empty()) { + auto end = personal_dir.find_last_of(PATHSEPCHAR); + if (end != std::string::npos) personal_dir.erase(end + 1); config_dir = personal_dir; } else { #if defined(WITH_XDG_BASEDIR) && defined(WITH_PERSONAL_DIR) @@ -1330,21 +1316,21 @@ static uint ScanPath(FileScanner *fs, const char *extension, const char *path, s while ((dirent = readdir(dir)) != nullptr) { const char *d_name = FS2OTTD(dirent->d_name); - char filename[MAX_PATH]; if (!FiosIsValidFile(path, dirent, &sb)) continue; - seprintf(filename, lastof(filename), "%s%s", path, d_name); + std::string filename(path); + filename += d_name; if (S_ISDIR(sb.st_mode)) { /* Directory */ if (!recursive) continue; if (strcmp(d_name, ".") == 0 || strcmp(d_name, "..") == 0) continue; - if (!AppendPathSeparator(filename, lastof(filename))) continue; - num += ScanPath(fs, extension, filename, basepath_length, recursive); + AppendPathSeparator(filename); + num += ScanPath(fs, extension, filename.c_str(), basepath_length, recursive); } else if (S_ISREG(sb.st_mode)) { /* File */ - if (MatchesExtension(extension, filename) && fs->AddFile(filename, basepath_length, nullptr)) num++; + if (MatchesExtension(extension, filename.c_str()) && fs->AddFile(filename.c_str(), basepath_length, nullptr)) num++; } } @@ -1383,7 +1369,6 @@ uint FileScanner::Scan(const char *extension, Subdirectory sd, bool tars, bool r this->subdir = sd; Searchpath sp; - char path[MAX_PATH]; TarFileList::iterator tar; uint num = 0; @@ -1391,8 +1376,8 @@ uint FileScanner::Scan(const char *extension, Subdirectory sd, bool tars, bool r /* Don't search in the working directory */ if (sp == SP_WORKING_DIR && !_do_scan_working_directory) continue; - FioAppendDirectory(path, lastof(path), sp, sd); - num += ScanPath(this, extension, path, strlen(path), recursive); + std::string path = FioGetDirectory(sp, sd); + num += ScanPath(this, extension, path.c_str(), path.size(), recursive); } if (tars && sd != NO_DIRECTORY) { @@ -1425,8 +1410,7 @@ uint FileScanner::Scan(const char *extension, Subdirectory sd, bool tars, bool r */ uint FileScanner::Scan(const char *extension, const char *directory, bool recursive) { - char path[MAX_PATH]; - strecpy(path, directory, lastof(path)); - if (!AppendPathSeparator(path, lastof(path))) return 0; - return ScanPath(this, extension, path, strlen(path), recursive); + std::string path(directory); + AppendPathSeparator(path); + return ScanPath(this, extension, path.c_str(), path.size(), recursive); } diff --git a/src/fileio_func.h b/src/fileio_func.h index a4bdeb0076..83e90be176 100644 --- a/src/fileio_func.h +++ b/src/fileio_func.h @@ -39,16 +39,15 @@ bool IsValidSearchPath(Searchpath sp); void FioFCloseFile(FILE *f); FILE *FioFOpenFile(const char *filename, const char *mode, Subdirectory subdir, size_t *filesize = nullptr); bool FioCheckFileExists(const char *filename, Subdirectory subdir); -char *FioGetFullPath(char *buf, const char *last, Searchpath sp, Subdirectory subdir, const char *filename); -char *FioFindFullPath(char *buf, const char *last, Subdirectory subdir, const char *filename); -char *FioAppendDirectory(char *buf, const char *last, Searchpath sp, Subdirectory subdir); -char *FioGetDirectory(char *buf, const char *last, Subdirectory subdir); +std::string FioFindFullPath(Subdirectory subdir, const char *filename); +std::string FioGetDirectory(Searchpath sp, Subdirectory subdir); +std::string FioFindDirectory(Subdirectory subdir); void FioCreateDirectory(const char *name); const char *FiosGetScreenshotDir(); void SanitizeFilename(char *filename); -bool AppendPathSeparator(char *buf, const char *last); +void AppendPathSeparator(std::string &buf); void DeterminePaths(const char *exe); void *ReadFileToMem(const char *filename, size_t *lenp, size_t maxsize); bool FileExists(const char *filename); diff --git a/src/fios.cpp b/src/fios.cpp index 61f08d93a9..4e2378a34b 100644 --- a/src/fios.cpp +++ b/src/fios.cpp @@ -19,6 +19,8 @@ #include "string_func.h" #include "tar_type.h" #include +#include +#include #ifndef _WIN32 # include @@ -29,8 +31,7 @@ #include "safeguards.h" /* Variables to display file lists */ -static char *_fios_path; -static const char *_fios_path_last; +static std::string *_fios_path = nullptr; SortingBits _savegame_sort_order = SORT_BY_DATE | SORT_DESCENDING; /* OS-specific functions are taken from their respective files (win32/unix/os2 .c) */ @@ -138,7 +139,7 @@ const FiosItem *FileList::FindItem(const char *file) */ StringID FiosGetDescText(const char **path, uint64 *total_free) { - *path = _fios_path; + *path = _fios_path->c_str(); return FiosGetDiskFreeSpace(*path, total_free) ? STR_SAVELOAD_BYTES_FREE : STR_ERROR_UNABLE_TO_READ_DRIVE; } @@ -152,7 +153,8 @@ const char *FiosBrowseTo(const FiosItem *item) switch (item->type) { case FIOS_TYPE_DRIVE: #if defined(_WIN32) || defined(__OS2__) - seprintf(_fios_path, _fios_path_last, "%c:" PATHSEP, item->title[0]); + assert(_fios_path != nullptr); + *_fios_path = std::string{ item->title[0] } + ":" PATHSEP; #endif break; @@ -160,25 +162,28 @@ const char *FiosBrowseTo(const FiosItem *item) break; case FIOS_TYPE_PARENT: { - /* Check for possible nullptr ptr */ - char *s = strrchr(_fios_path, PATHSEPCHAR); - if (s != nullptr && s != _fios_path) { - s[0] = '\0'; // Remove last path separator character, so we can go up one level. + assert(_fios_path != nullptr); + auto s = _fios_path->find_last_of(PATHSEPCHAR); + if (s != std::string::npos && s != 0) { + _fios_path->erase(s); // Remove last path separator character, so we can go up one level. } - s = strrchr(_fios_path, PATHSEPCHAR); - if (s != nullptr) { - s[1] = '\0'; // go up a directory + + s = _fios_path->find_last_of(PATHSEPCHAR); + if (s != std::string::npos) { + _fios_path->erase(s + 1); // go up a directory } break; } case FIOS_TYPE_DIR: - strecat(_fios_path, item->name, _fios_path_last); - strecat(_fios_path, PATHSEP, _fios_path_last); + assert(_fios_path != nullptr); + *_fios_path += item->name; + *_fios_path += PATHSEP; break; case FIOS_TYPE_DIRECT: - seprintf(_fios_path, _fios_path_last, "%s", item->name); + assert(_fios_path != nullptr); + *_fios_path = item->name; break; case FIOS_TYPE_FILE: @@ -227,7 +232,7 @@ void FiosMakeSavegameName(char *buf, const char *name, const char *last) { const char *extension = (_game_mode == GM_EDITOR) ? ".scn" : ".sav"; - FiosMakeFilename(buf, _fios_path, name, extension, last); + FiosMakeFilename(buf, _fios_path->c_str(), name, extension, last); } /** @@ -242,7 +247,7 @@ void FiosMakeHeightmapName(char *buf, const char *name, const char *last) ext[0] = '.'; strecpy(ext + 1, GetCurrentScreenshotExtension(), lastof(ext)); - FiosMakeFilename(buf, _fios_path, name, ext, last); + FiosMakeFilename(buf, _fios_path->c_str(), name, ext, last); } /** @@ -365,8 +370,10 @@ static void FiosGetFileList(SaveLoadOperation fop, fios_getlist_callback_proc *c file_list.Clear(); + assert(_fios_path != nullptr); + /* A parent directory link exists if we are not in the root directory */ - if (!FiosIsRoot(_fios_path)) { + if (!FiosIsRoot(_fios_path->c_str())) { fios = file_list.Append(); fios->type = FIOS_TYPE_PARENT; fios->mtime = 0; @@ -375,12 +382,12 @@ static void FiosGetFileList(SaveLoadOperation fop, fios_getlist_callback_proc *c } /* Show subdirectories */ - if ((dir = ttd_opendir(_fios_path)) != nullptr) { + if ((dir = ttd_opendir(_fios_path->c_str())) != nullptr) { while ((dirent = readdir(dir)) != nullptr) { strecpy(d_name, FS2OTTD(dirent->d_name), lastof(d_name)); /* found file must be directory, but not '.' or '..' */ - if (FiosIsValidFile(_fios_path, dirent, &sb) && S_ISDIR(sb.st_mode) && + if (FiosIsValidFile(_fios_path->c_str(), dirent, &sb) && S_ISDIR(sb.st_mode) && (!FiosIsHiddenFile(dirent) || strncasecmp(d_name, PERSONAL_DIR, strlen(d_name)) == 0) && strcmp(d_name, ".") != 0 && strcmp(d_name, "..") != 0) { fios = file_list.Append(); @@ -408,7 +415,7 @@ static void FiosGetFileList(SaveLoadOperation fop, fios_getlist_callback_proc *c /* Show files */ FiosFileScanner scanner(fop, callback_proc, file_list); if (subdir == NO_DIRECTORY) { - scanner.Scan(nullptr, _fios_path, false); + scanner.Scan(nullptr, _fios_path->c_str(), false); } else { scanner.Scan(nullptr, subdir, true, true); } @@ -491,17 +498,11 @@ FiosType FiosGetSavegameListCallback(SaveLoadOperation fop, const char *file, co */ void FiosGetSavegameList(SaveLoadOperation fop, FileList &file_list) { - static char *fios_save_path = nullptr; - static char *fios_save_path_last = nullptr; + static std::optional fios_save_path; - if (fios_save_path == nullptr) { - fios_save_path = MallocT(MAX_PATH); - fios_save_path_last = fios_save_path + MAX_PATH - 1; - FioGetDirectory(fios_save_path, fios_save_path_last, SAVE_DIR); - } + if (!fios_save_path) fios_save_path = FioFindDirectory(SAVE_DIR); - _fios_path = fios_save_path; - _fios_path_last = fios_save_path_last; + _fios_path = &(*fios_save_path); FiosGetFileList(fop, &FiosGetSavegameListCallback, NO_DIRECTORY, file_list); } @@ -546,23 +547,15 @@ static FiosType FiosGetScenarioListCallback(SaveLoadOperation fop, const char *f */ void FiosGetScenarioList(SaveLoadOperation fop, FileList &file_list) { - static char *fios_scn_path = nullptr; - static char *fios_scn_path_last = nullptr; + static std::optional fios_scn_path; /* Copy the default path on first run or on 'New Game' */ - if (fios_scn_path == nullptr) { - fios_scn_path = MallocT(MAX_PATH); - fios_scn_path_last = fios_scn_path + MAX_PATH - 1; - FioGetDirectory(fios_scn_path, fios_scn_path_last, SCENARIO_DIR); - } + if (!fios_scn_path) fios_scn_path = FioFindDirectory(SCENARIO_DIR); - _fios_path = fios_scn_path; - _fios_path_last = fios_scn_path_last; + _fios_path = &(*fios_scn_path); - char base_path[MAX_PATH]; - FioGetDirectory(base_path, lastof(base_path), SCENARIO_DIR); - - Subdirectory subdir = (fop == SLO_LOAD && strcmp(base_path, _fios_path) == 0) ? SCENARIO_DIR : NO_DIRECTORY; + std::string base_path = FioFindDirectory(SCENARIO_DIR); + Subdirectory subdir = (fop == SLO_LOAD && base_path == *_fios_path) ? SCENARIO_DIR : NO_DIRECTORY; FiosGetFileList(fop, &FiosGetScenarioListCallback, subdir, file_list); } @@ -593,10 +586,9 @@ static FiosType FiosGetHeightmapListCallback(SaveLoadOperation fop, const char * bool match = false; Searchpath sp; FOR_ALL_SEARCHPATHS(sp) { - char buf[MAX_PATH]; - FioAppendDirectory(buf, lastof(buf), sp, HEIGHTMAP_DIR); + std::string buf = FioGetDirectory(sp, HEIGHTMAP_DIR); - if (strncmp(buf, it->second.tar_filename, strlen(buf)) == 0) { + if (buf.compare(0, buf.size(), it->second.tar_filename, 0, buf.size()) == 0) { match = true; break; } @@ -617,22 +609,14 @@ static FiosType FiosGetHeightmapListCallback(SaveLoadOperation fop, const char * */ void FiosGetHeightmapList(SaveLoadOperation fop, FileList &file_list) { - static char *fios_hmap_path = nullptr; - static char *fios_hmap_path_last = nullptr; - - if (fios_hmap_path == nullptr) { - fios_hmap_path = MallocT(MAX_PATH); - fios_hmap_path_last = fios_hmap_path + MAX_PATH - 1; - FioGetDirectory(fios_hmap_path, fios_hmap_path_last, HEIGHTMAP_DIR); - } + static std::optional fios_hmap_path; - _fios_path = fios_hmap_path; - _fios_path_last = fios_hmap_path_last; + if (!fios_hmap_path) fios_hmap_path = FioFindDirectory(HEIGHTMAP_DIR); - char base_path[MAX_PATH]; - FioGetDirectory(base_path, lastof(base_path), HEIGHTMAP_DIR); + _fios_path = &(*fios_hmap_path); - Subdirectory subdir = strcmp(base_path, _fios_path) == 0 ? HEIGHTMAP_DIR : NO_DIRECTORY; + std::string base_path = FioFindDirectory(HEIGHTMAP_DIR); + Subdirectory subdir = base_path == *_fios_path ? HEIGHTMAP_DIR : NO_DIRECTORY; FiosGetFileList(fop, &FiosGetHeightmapListCallback, subdir, file_list); } @@ -642,14 +626,11 @@ void FiosGetHeightmapList(SaveLoadOperation fop, FileList &file_list) */ const char *FiosGetScreenshotDir() { - static char *fios_screenshot_path = nullptr; + static std::optional fios_screenshot_path; - if (fios_screenshot_path == nullptr) { - fios_screenshot_path = MallocT(MAX_PATH); - FioGetDirectory(fios_screenshot_path, fios_screenshot_path + MAX_PATH - 1, SCREENSHOT_DIR); - } + if (!fios_screenshot_path) fios_screenshot_path = FioFindDirectory(SCREENSHOT_DIR); - return fios_screenshot_path; + return fios_screenshot_path->c_str(); } /** Basic data to distinguish a scenario. Used in the server list window */ diff --git a/src/fios_gui.cpp b/src/fios_gui.cpp index 059bbf0ce9..53bb606f37 100644 --- a/src/fios_gui.cpp +++ b/src/fios_gui.cpp @@ -368,22 +368,24 @@ public: /* Select the initial directory. */ o_dir.type = FIOS_TYPE_DIRECT; + std::string dir; switch (this->abstract_filetype) { case FT_SAVEGAME: - FioGetDirectory(o_dir.name, lastof(o_dir.name), SAVE_DIR); + dir = FioFindDirectory(SAVE_DIR); break; case FT_SCENARIO: - FioGetDirectory(o_dir.name, lastof(o_dir.name), SCENARIO_DIR); + dir = FioFindDirectory(SCENARIO_DIR); break; case FT_HEIGHTMAP: - FioGetDirectory(o_dir.name, lastof(o_dir.name), HEIGHTMAP_DIR); + dir = FioFindDirectory(HEIGHTMAP_DIR); break; default: - strecpy(o_dir.name, _personal_dir.c_str(), lastof(o_dir.name)); + dir = _personal_dir; } + strecpy(o_dir.name, dir.c_str(), lastof(o_dir.name)); switch (this->fop) { case SLO_SAVE: diff --git a/src/music/midifile.cpp b/src/music/midifile.cpp index 67cc7b192c..b15a27911c 100644 --- a/src/music/midifile.cpp +++ b/src/music/midifile.cpp @@ -1048,14 +1048,12 @@ bool MidiFile::WriteSMF(const char *filename) std::string MidiFile::GetSMFFile(const MusicSongInfo &song) { if (song.filetype == MTT_STANDARDMIDI) { - char filename[MAX_PATH]; - if (FioFindFullPath(filename, lastof(filename), Subdirectory::BASESET_DIR, song.filename)) { - return std::string(filename); - } else if (FioFindFullPath(filename, lastof(filename), Subdirectory::OLD_GM_DIR, song.filename)) { - return std::string(filename); - } else { - return std::string(); - } + std::string filename = FioFindFullPath(Subdirectory::BASESET_DIR, song.filename); + if (!filename.empty()) return filename; + filename = FioFindFullPath(Subdirectory::OLD_GM_DIR, song.filename); + if (!filename.empty()) return filename; + + return std::string(); } if (song.filetype != MTT_MPSMIDI) return std::string(); @@ -1077,17 +1075,16 @@ std::string MidiFile::GetSMFFile(const MusicSongInfo &song) *wp++ = '\0'; } - char tempdirname[MAX_PATH]; - FioGetFullPath(tempdirname, lastof(tempdirname), Searchpath::SP_AUTODOWNLOAD_DIR, Subdirectory::BASESET_DIR, basename); - if (!AppendPathSeparator(tempdirname, lastof(tempdirname))) return std::string(); - FioCreateDirectory(tempdirname); + std::string tempdirname = FioGetDirectory(Searchpath::SP_AUTODOWNLOAD_DIR, Subdirectory::BASESET_DIR); + tempdirname += basename; + AppendPathSeparator(tempdirname); + FioCreateDirectory(tempdirname.c_str()); - char output_filename[MAX_PATH]; - seprintf(output_filename, lastof(output_filename), "%s%d.mid", tempdirname, song.cat_index); + std::string output_filename = tempdirname + std::to_string(song.cat_index) + ".mid"; - if (FileExists(output_filename)) { + if (FileExists(output_filename.c_str())) { /* If the file already exists, assume it's the correct decoded data */ - return std::string(output_filename); + return output_filename; } byte *data; @@ -1102,8 +1099,8 @@ std::string MidiFile::GetSMFFile(const MusicSongInfo &song) } free(data); - if (midifile.WriteSMF(output_filename)) { - return std::string(output_filename); + if (midifile.WriteSMF(output_filename.c_str())) { + return output_filename; } else { return std::string(); } diff --git a/src/network/network_content.cpp b/src/network/network_content.cpp index c4d26355c0..dc14a59fcb 100644 --- a/src/network/network_content.cpp +++ b/src/network/network_content.cpp @@ -385,14 +385,14 @@ void ClientNetworkContentSocketHandler::DownloadSelectedContentFallback(const Co * @return a statically allocated buffer with the filename or * nullptr when no filename could be made. */ -static char *GetFullFilename(const ContentInfo *ci, bool compressed) +static std::string GetFullFilename(const ContentInfo *ci, bool compressed) { Subdirectory dir = GetContentInfoSubDir(ci->type); - if (dir == NO_DIRECTORY) return nullptr; + if (dir == NO_DIRECTORY) return {}; - static char buf[MAX_PATH]; - FioGetFullPath(buf, lastof(buf), SP_AUTODOWNLOAD_DIR, dir, ci->filename); - strecat(buf, compressed ? ".tar.gz" : ".tar", lastof(buf)); + std::string buf = FioGetDirectory(SP_AUTODOWNLOAD_DIR, dir); + buf += ci->filename; + buf += compressed ? ".tar.gz" : ".tar"; return buf; } @@ -408,13 +408,13 @@ static bool GunzipFile(const ContentInfo *ci) bool ret = true; /* Need to open the file with fopen() to support non-ASCII on Windows. */ - FILE *ftmp = fopen(GetFullFilename(ci, true), "rb"); + FILE *ftmp = fopen(GetFullFilename(ci, true).c_str(), "rb"); if (ftmp == nullptr) return false; /* Duplicate the handle, and close the FILE*, to avoid double-closing the handle later. */ gzFile fin = gzdopen(dup(fileno(ftmp)), "rb"); fclose(ftmp); - FILE *fout = fopen(GetFullFilename(ci, false), "wb"); + FILE *fout = fopen(GetFullFilename(ci, false).c_str(), "wb"); if (fin == nullptr || fout == nullptr) { ret = false; @@ -509,8 +509,8 @@ bool ClientNetworkContentSocketHandler::BeforeDownload() if (this->curInfo->filesize != 0) { /* The filesize is > 0, so we are going to download it */ - const char *filename = GetFullFilename(this->curInfo, true); - if (filename == nullptr || (this->curFile = fopen(filename, "wb")) == nullptr) { + std::string filename = GetFullFilename(this->curInfo, true); + if (filename.empty() || (this->curFile = fopen(filename.c_str(), "wb")) == nullptr) { /* Unless that fails of course... */ DeleteWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD); ShowErrorMessage(STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD, STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_FILE_NOT_WRITABLE, WL_ERROR); @@ -532,18 +532,19 @@ void ClientNetworkContentSocketHandler::AfterDownload() this->curFile = nullptr; if (GunzipFile(this->curInfo)) { - unlink(GetFullFilename(this->curInfo, true)); + unlink(GetFullFilename(this->curInfo, true).c_str()); Subdirectory sd = GetContentInfoSubDir(this->curInfo->type); if (sd == NO_DIRECTORY) NOT_REACHED(); TarScanner ts; - ts.AddFile(sd, GetFullFilename(this->curInfo, false)); + std::string fname = GetFullFilename(this->curInfo, false); + ts.AddFile(sd, fname.c_str()); if (this->curInfo->type == CONTENT_TYPE_BASE_MUSIC) { /* Music can't be in a tar. So extract the tar! */ - ExtractTar(GetFullFilename(this->curInfo, false), BASESET_DIR); - unlink(GetFullFilename(this->curInfo, false)); + ExtractTar(fname.c_str(), BASESET_DIR); + unlink(fname.c_str()); } #ifdef __EMSCRIPTEN__ diff --git a/src/os/windows/win32.cpp b/src/os/windows/win32.cpp index 7553740e76..bbb7e359a9 100644 --- a/src/os/windows/win32.cpp +++ b/src/os/windows/win32.cpp @@ -458,24 +458,23 @@ void DetermineBasePaths(const char *exe) { extern std::array _searchpaths; - char tmp[MAX_PATH]; TCHAR path[MAX_PATH]; #ifdef WITH_PERSONAL_DIR if (SUCCEEDED(OTTDSHGetFolderPath(nullptr, CSIDL_PERSONAL, nullptr, SHGFP_TYPE_CURRENT, path))) { - strecpy(tmp, FS2OTTD(path), lastof(tmp)); - AppendPathSeparator(tmp, lastof(tmp)); - strecat(tmp, PERSONAL_DIR, lastof(tmp)); - AppendPathSeparator(tmp, lastof(tmp)); + std::string tmp(FS2OTTD(path)); + AppendPathSeparator(tmp); + tmp += PERSONAL_DIR; + AppendPathSeparator(tmp); _searchpaths[SP_PERSONAL_DIR] = tmp; } else { _searchpaths[SP_PERSONAL_DIR].clear(); } if (SUCCEEDED(OTTDSHGetFolderPath(nullptr, CSIDL_COMMON_DOCUMENTS, nullptr, SHGFP_TYPE_CURRENT, path))) { - strecpy(tmp, FS2OTTD(path), lastof(tmp)); - AppendPathSeparator(tmp, lastof(tmp)); - strecat(tmp, PERSONAL_DIR, lastof(tmp)); - AppendPathSeparator(tmp, lastof(tmp)); + std::string tmp(FS2OTTD(path)); + AppendPathSeparator(tmp); + tmp += PERSONAL_DIR; + AppendPathSeparator(tmp); _searchpaths[SP_SHARED_DIR] = tmp; } else { _searchpaths[SP_SHARED_DIR].clear(); @@ -486,10 +485,11 @@ void DetermineBasePaths(const char *exe) #endif if (_config_file.empty()) { - /* Get the path to working directory of OpenTTD. */ - getcwd(tmp, lengthof(tmp)); - AppendPathSeparator(tmp, lastof(tmp)); - _searchpaths[SP_WORKING_DIR] = tmp; + char cwd[MAX_PATH]; + getcwd(cwd, lengthof(cwd)); + std::string cwd_s(cwd); + AppendPathSeparator(cwd_s); + _searchpaths[SP_WORKING_DIR] = cwd_s; } else { /* Use the folder of the config file as working directory. */ TCHAR config_dir[MAX_PATH]; @@ -498,9 +498,10 @@ void DetermineBasePaths(const char *exe) DEBUG(misc, 0, "GetFullPathName failed (%lu)\n", GetLastError()); _searchpaths[SP_WORKING_DIR].clear(); } else { - strecpy(tmp, convert_from_fs(config_dir, tmp, lengthof(tmp)), lastof(tmp)); - char *s = strrchr(tmp, PATHSEPCHAR); - *(s + 1) = '\0'; + std::string tmp(FS2OTTD(config_dir)); + auto pos = tmp.find_last_of(PATHSEPCHAR); + if (pos != std::string::npos) tmp.erase(pos + 1); + _searchpaths[SP_WORKING_DIR] = tmp; } } @@ -515,9 +516,10 @@ void DetermineBasePaths(const char *exe) DEBUG(misc, 0, "GetFullPathName failed (%lu)\n", GetLastError()); _searchpaths[SP_BINARY_DIR].clear(); } else { - strecpy(tmp, convert_from_fs(exec_dir, tmp, lengthof(tmp)), lastof(tmp)); - char *s = strrchr(tmp, PATHSEPCHAR); - *(s + 1) = '\0'; + std::string tmp(FS2OTTD(exec_dir)); + auto pos = tmp.find_last_of(PATHSEPCHAR); + if (pos != std::string::npos) tmp.erase(pos + 1); + _searchpaths[SP_BINARY_DIR] = tmp; } } diff --git a/src/script/script_instance.cpp b/src/script/script_instance.cpp index 81283cb772..836bb82468 100644 --- a/src/script/script_instance.cpp +++ b/src/script/script_instance.cpp @@ -116,17 +116,16 @@ bool ScriptInstance::LoadCompatibilityScripts(const char *api_version, Subdirect { char script_name[32]; seprintf(script_name, lastof(script_name), "compat_%s.nut", api_version); - char buf[MAX_PATH]; Searchpath sp; FOR_ALL_SEARCHPATHS(sp) { - FioAppendDirectory(buf, lastof(buf), sp, dir); - strecat(buf, script_name, lastof(buf)); - if (!FileExists(buf)) continue; + std::string buf = FioGetDirectory(sp, dir); + buf += script_name; + if (!FileExists(buf.c_str())) continue; - if (this->engine->LoadScript(buf)) return true; + if (this->engine->LoadScript(buf.c_str())) return true; ScriptLog::Error("Failed to load API compatibility script"); - DEBUG(script, 0, "Error compiling / running API compatibility script: %s", buf); + DEBUG(script, 0, "Error compiling / running API compatibility script: %s", buf.c_str()); return false; } diff --git a/src/strings.cpp b/src/strings.cpp index ae0ab2c906..9f61ea5fd1 100644 --- a/src/strings.cpp +++ b/src/strings.cpp @@ -1959,9 +1959,8 @@ void InitializeLanguagePacks() Searchpath sp; FOR_ALL_SEARCHPATHS(sp) { - char path[MAX_PATH]; - FioAppendDirectory(path, lastof(path), sp, LANG_DIR); - GetLanguageList(path); + std::string path = FioGetDirectory(sp, LANG_DIR); + GetLanguageList(path.c_str()); } if (_languages.size() == 0) usererror("No available language packs (invalid versions?)"); diff --git a/src/video/cocoa/cocoa_v.mm b/src/video/cocoa/cocoa_v.mm index f02599799c..e4a0a0c6f6 100644 --- a/src/video/cocoa/cocoa_v.mm +++ b/src/video/cocoa/cocoa_v.mm @@ -551,8 +551,8 @@ void cocoaSetApplicationBundleDir() char tmp[MAXPATHLEN]; CFAutoRelease url(CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle())); if (CFURLGetFileSystemRepresentation(url.get(), true, (unsigned char*)tmp, MAXPATHLEN)) { - AppendPathSeparator(tmp, lastof(tmp)); _searchpaths[SP_APPLICATION_BUNDLE_DIR] = tmp; + AppendPathSeparator(_searchpaths[SP_APPLICATION_BUNDLE_DIR]); } else { _searchpaths[SP_APPLICATION_BUNDLE_DIR].clear(); } diff --git a/src/video/sdl2_v.cpp b/src/video/sdl2_v.cpp index 852f7298d9..ea2a88bb92 100644 --- a/src/video/sdl2_v.cpp +++ b/src/video/sdl2_v.cpp @@ -285,10 +285,10 @@ bool VideoDriver_SDL::CreateMainSurface(uint w, uint h, bool resize) return false; } - char icon_path[MAX_PATH]; - if (FioFindFullPath(icon_path, lastof(icon_path), BASESET_DIR, "openttd.32.bmp") != nullptr) { + std::string icon_path = FioFindFullPath(BASESET_DIR, "openttd.32.bmp"); + if (!icon_path.empty()) { /* Give the application an icon */ - SDL_Surface *icon = SDL_LoadBMP(icon_path); + SDL_Surface *icon = SDL_LoadBMP(icon_path.c_str()); if (icon != nullptr) { /* Get the colourkey, which will be magenta */ uint32 rgbmap = SDL_MapRGB(icon->format, 255, 0, 255); diff --git a/src/video/sdl_v.cpp b/src/video/sdl_v.cpp index 98777a87d5..4f5167335a 100644 --- a/src/video/sdl_v.cpp +++ b/src/video/sdl_v.cpp @@ -266,10 +266,10 @@ bool VideoDriver_SDL::CreateMainSurface(uint w, uint h) if (bpp == 0) usererror("Can't use a blitter that blits 0 bpp for normal visuals"); - char icon_path[MAX_PATH]; - if (FioFindFullPath(icon_path, lastof(icon_path), BASESET_DIR, "openttd.32.bmp") != nullptr) { + std::string icon_path = FioFindFullPath(BASESET_DIR, "openttd.32.bmp"); + if (!icon_path.empty()) { /* Give the application an icon */ - icon = SDL_LoadBMP(icon_path); + icon = SDL_LoadBMP(icon_path.c_str()); if (icon != nullptr) { /* Get the colourkey, which will be magenta */ uint32 rgbmap = SDL_MapRGB(icon->format, 255, 0, 255); From 65f65ad2ad8f029b99ef60e931b6d86952777610 Mon Sep 17 00:00:00 2001 From: Michael Lutz Date: Sun, 6 Dec 2020 21:11:45 +0100 Subject: [PATCH 23/64] Codechange: Convert some more FIO functions to take std::string. --- src/fileio.cpp | 44 ++++++++++++++++------------------ src/fileio_func.h | 6 ++--- src/fios.cpp | 37 +++++++++++++--------------- src/fios.h | 4 ++-- src/fios_gui.cpp | 4 ++-- src/genworld_gui.cpp | 2 +- src/landscape.cpp | 2 +- src/music/midifile.cpp | 4 ++-- src/network/network_client.cpp | 4 ++-- src/openttd.cpp | 14 +++++------ src/saveload/saveload.cpp | 2 +- src/saveload/saveload.h | 3 ++- src/script/script_instance.cpp | 2 +- src/video/dedicated_v.cpp | 2 +- 14 files changed, 62 insertions(+), 68 deletions(-) diff --git a/src/fileio.cpp b/src/fileio.cpp index afdbdd256c..09e884e4fa 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -270,9 +270,9 @@ bool IsValidSearchPath(Searchpath sp) * @param subdir the subdirectory to look in * @return true if and only if the file can be opened */ -bool FioCheckFileExists(const char *filename, Subdirectory subdir) +bool FioCheckFileExists(const std::string &filename, Subdirectory subdir) { - FILE *f = FioFOpenFile(filename, "rb", subdir); + FILE *f = FioFOpenFile(filename.c_str(), "rb", subdir); if (f == nullptr) return false; FioFCloseFile(f); @@ -284,9 +284,9 @@ bool FioCheckFileExists(const char *filename, Subdirectory subdir) * @param filename the file to test. * @return true if and only if the file exists. */ -bool FileExists(const char *filename) +bool FileExists(const std::string &filename) { - return access(OTTD2FS(filename), 0) == 0; + return access(OTTD2FS(filename.c_str()), 0) == 0; } /** @@ -311,12 +311,12 @@ std::string FioFindFullPath(Subdirectory subdir, const char *filename) FOR_ALL_SEARCHPATHS(sp) { std::string buf = FioGetDirectory(sp, subdir); buf += filename; - if (FileExists(buf.c_str())) return buf; + if (FileExists(buf)) return buf; #if !defined(_WIN32) /* Be, as opening files, aware that sometimes the filename * might be in uppercase when it is in lowercase on the * disk. Of course Windows doesn't care about casing. */ - if (strtolower(buf, _searchpaths[sp].size() - 1) && FileExists(buf.c_str())) return buf; + if (strtolower(buf, _searchpaths[sp].size() - 1) && FileExists(buf)) return buf; #endif } @@ -338,7 +338,7 @@ std::string FioFindDirectory(Subdirectory subdir) /* Find and return the first valid directory */ FOR_ALL_SEARCHPATHS(sp) { std::string ret = FioGetDirectory(sp, subdir); - if (FileExists(ret.c_str())) return ret; + if (FileExists(ret)) return ret; } /* Could not find the directory, fall back to a base path */ @@ -502,14 +502,12 @@ FILE *FioFOpenFile(const char *filename, const char *mode, Subdirectory subdir, * If the parent directory does not exist, it will try to create that as well. * @param name the new name of the directory */ -void FioCreateDirectory(const char *name) +void FioCreateDirectory(const std::string &name) { - char dirname[MAX_PATH]; - strecpy(dirname, name, lastof(dirname)); - char *p = strrchr(dirname, PATHSEPCHAR); - if (p != nullptr) { - *p = '\0'; - DIR *dir = ttd_opendir(dirname); + auto p = name.find_last_of(PATHSEPCHAR); + if (p != std::string::npos) { + std::string dirname = name.substr(0, p); + DIR *dir = ttd_opendir(dirname.c_str()); if (dir == nullptr) { FioCreateDirectory(dirname); // Try creating the parent directory, if we couldn't open it } else { @@ -520,11 +518,11 @@ void FioCreateDirectory(const char *name) /* Ignore directory creation errors; they'll surface later on, and most * of the time they are 'directory already exists' errors anyhow. */ #if defined(_WIN32) - CreateDirectory(OTTD2FS(name), nullptr); + CreateDirectory(OTTD2FS(name.c_str()), nullptr); #elif defined(OS2) && !defined(__INNOTEK_LIBC__) - mkdir(OTTD2FS(name)); + mkdir(OTTD2FS(name.c_str())); #else - mkdir(OTTD2FS(name), 0755); + mkdir(OTTD2FS(name.c_str()), 0755); #endif } @@ -1198,9 +1196,9 @@ void DeterminePaths(const char *exe) } /* Make the necessary folders */ - FioCreateDirectory(config_dir.c_str()); + FioCreateDirectory(config_dir); #if defined(WITH_PERSONAL_DIR) - FioCreateDirectory(_personal_dir.c_str()); + FioCreateDirectory(_personal_dir); #endif DEBUG(misc, 3, "%s found as personal directory", _personal_dir.c_str()); @@ -1210,19 +1208,17 @@ void DeterminePaths(const char *exe) }; for (uint i = 0; i < lengthof(default_subdirs); i++) { - FioCreateDirectory((_personal_dir + _subdirs[default_subdirs[i]]).c_str()); + FioCreateDirectory(_personal_dir + _subdirs[default_subdirs[i]]); } /* If we have network we make a directory for the autodownloading of content */ _searchpaths[SP_AUTODOWNLOAD_DIR] = _personal_dir + "content_download" PATHSEP; - FioCreateDirectory(_searchpaths[SP_AUTODOWNLOAD_DIR].c_str()); + FioCreateDirectory(_searchpaths[SP_AUTODOWNLOAD_DIR]); /* Create the directory for each of the types of content */ const Subdirectory dirs[] = { SCENARIO_DIR, HEIGHTMAP_DIR, BASESET_DIR, NEWGRF_DIR, AI_DIR, AI_LIBRARY_DIR, GAME_DIR, GAME_LIBRARY_DIR }; for (uint i = 0; i < lengthof(dirs); i++) { - char *tmp = str_fmt("%s%s", _searchpaths[SP_AUTODOWNLOAD_DIR].c_str(), _subdirs[dirs[i]]); - FioCreateDirectory(tmp); - free(tmp); + FioCreateDirectory(FioGetDirectory(SP_AUTODOWNLOAD_DIR, dirs[i])); } extern std::string _log_file; diff --git a/src/fileio_func.h b/src/fileio_func.h index 83e90be176..5007a04e63 100644 --- a/src/fileio_func.h +++ b/src/fileio_func.h @@ -38,11 +38,11 @@ bool IsValidSearchPath(Searchpath sp); void FioFCloseFile(FILE *f); FILE *FioFOpenFile(const char *filename, const char *mode, Subdirectory subdir, size_t *filesize = nullptr); -bool FioCheckFileExists(const char *filename, Subdirectory subdir); +bool FioCheckFileExists(const std::string &filename, Subdirectory subdir); std::string FioFindFullPath(Subdirectory subdir, const char *filename); std::string FioGetDirectory(Searchpath sp, Subdirectory subdir); std::string FioFindDirectory(Subdirectory subdir); -void FioCreateDirectory(const char *name); +void FioCreateDirectory(const std::string &name); const char *FiosGetScreenshotDir(); @@ -50,7 +50,7 @@ void SanitizeFilename(char *filename); void AppendPathSeparator(std::string &buf); void DeterminePaths(const char *exe); void *ReadFileToMem(const char *filename, size_t *lenp, size_t maxsize); -bool FileExists(const char *filename); +bool FileExists(const std::string &filename); bool ExtractTar(const char *tar_filename, Subdirectory subdir); extern std::string _personal_dir; ///< custom directory for personal settings, saves, newgrf, etc. diff --git a/src/fios.cpp b/src/fios.cpp index 4e2378a34b..e7341b1f51 100644 --- a/src/fios.cpp +++ b/src/fios.cpp @@ -200,26 +200,26 @@ const char *FiosBrowseTo(const FiosItem *item) /** * Construct a filename from its components in destination buffer \a buf. - * @param buf Destination buffer. * @param path Directory path, may be \c nullptr. * @param name Filename. * @param ext Filename extension (use \c "" for no extension). - * @param last Last element of buffer \a buf. + * @return The completed filename. */ -static void FiosMakeFilename(char *buf, const char *path, const char *name, const char *ext, const char *last) +static std::string FiosMakeFilename(const std::string *path, const char *name, const char *ext) { + std::string buf; + if (path != nullptr) { - const char *buf_start = buf; - buf = strecpy(buf, path, last); + buf = *path; /* Remove trailing path separator, if present */ - if (buf > buf_start && buf[-1] == PATHSEPCHAR) buf--; + if (!buf.empty() && buf.back() == PATHSEPCHAR) buf.pop_back(); } /* Don't append the extension if it is already there */ const char *period = strrchr(name, '.'); if (period != nullptr && strcasecmp(period, ext) == 0) ext = ""; - seprintf(buf, last, PATHSEP "%s%s", name, ext); + return buf + name + ext; } /** @@ -227,27 +227,26 @@ static void FiosMakeFilename(char *buf, const char *path, const char *name, cons * @param buf Destination buffer for saving the filename. * @param name Name of the file. * @param last Last element of buffer \a buf. + * @return The completed filename. */ -void FiosMakeSavegameName(char *buf, const char *name, const char *last) +std::string FiosMakeSavegameName(const char *name) { const char *extension = (_game_mode == GM_EDITOR) ? ".scn" : ".sav"; - FiosMakeFilename(buf, _fios_path->c_str(), name, extension, last); + return FiosMakeFilename(_fios_path, name, extension); } /** * Construct a filename for a height map. - * @param buf Destination buffer. * @param name Filename. - * @param last Last element of buffer \a buf. + * @return The completed filename. */ -void FiosMakeHeightmapName(char *buf, const char *name, const char *last) +std::string FiosMakeHeightmapName(const char *name) { - char ext[5]; - ext[0] = '.'; - strecpy(ext + 1, GetCurrentScreenshotExtension(), lastof(ext)); + std::string ext("."); + ext += GetCurrentScreenshotExtension(); - FiosMakeFilename(buf, _fios_path->c_str(), name, ext, last); + return FiosMakeFilename(_fios_path, name, ext.c_str()); } /** @@ -257,10 +256,8 @@ void FiosMakeHeightmapName(char *buf, const char *name, const char *last) */ bool FiosDelete(const char *name) { - char filename[512]; - - FiosMakeSavegameName(filename, name, lastof(filename)); - return unlink(filename) == 0; + std::string filename = FiosMakeSavegameName(name); + return unlink(filename.c_str()) == 0; } typedef FiosType fios_getlist_callback_proc(SaveLoadOperation fop, const char *filename, const char *ext, char *title, const char *last); diff --git a/src/fios.h b/src/fios.h index 259e493b24..e211396c1f 100644 --- a/src/fios.h +++ b/src/fios.h @@ -220,8 +220,8 @@ const char *FiosBrowseTo(const FiosItem *item); StringID FiosGetDescText(const char **path, uint64 *total_free); bool FiosDelete(const char *name); -void FiosMakeHeightmapName(char *buf, const char *name, const char *last); -void FiosMakeSavegameName(char *buf, const char *name, const char *last); +std::string FiosMakeHeightmapName(const char *name); +std::string FiosMakeSavegameName(const char *name); FiosType FiosGetSavegameListCallback(SaveLoadOperation fop, const char *file, const char *ext, char *title, const char *last); diff --git a/src/fios_gui.cpp b/src/fios_gui.cpp index 53bb606f37..a86bb7a222 100644 --- a/src/fios_gui.cpp +++ b/src/fios_gui.cpp @@ -771,14 +771,14 @@ public: } } else if (this->IsWidgetLowered(WID_SL_SAVE_GAME)) { // Save button clicked if (this->abstract_filetype == FT_SAVEGAME || this->abstract_filetype == FT_SCENARIO) { - FiosMakeSavegameName(_file_to_saveload.name, this->filename_editbox.text.buf, lastof(_file_to_saveload.name)); + _file_to_saveload.name = FiosMakeSavegameName(this->filename_editbox.text.buf); if (FioCheckFileExists(_file_to_saveload.name, Subdirectory::SAVE_DIR)) { ShowQuery(STR_SAVELOAD_OVERWRITE_TITLE, STR_SAVELOAD_OVERWRITE_WARNING, this, SaveLoadWindow::SaveGameConfirmationCallback); } else { _switch_mode = SM_SAVE_GAME; } } else { - FiosMakeHeightmapName(_file_to_saveload.name, this->filename_editbox.text.buf, lastof(_file_to_saveload.name)); + _file_to_saveload.name = FiosMakeHeightmapName(this->filename_editbox.text.buf); if (FioCheckFileExists(_file_to_saveload.name, Subdirectory::SAVE_DIR)) { ShowQuery(STR_SAVELOAD_OVERWRITE_TITLE, STR_SAVELOAD_OVERWRITE_WARNING, this, SaveLoadWindow::SaveHeightmapConfirmationCallback); } else { diff --git a/src/genworld_gui.cpp b/src/genworld_gui.cpp index 4f1524f8ab..37f3962ec6 100644 --- a/src/genworld_gui.cpp +++ b/src/genworld_gui.cpp @@ -831,7 +831,7 @@ static void _ShowGenerateLandscape(GenerateLandscapeWindowMode mode) if (mode == GLWM_HEIGHTMAP) { /* If the function returns negative, it means there was a problem loading the heightmap */ - if (!GetHeightmapDimensions(_file_to_saveload.detail_ftype, _file_to_saveload.name, &x, &y)) return; + if (!GetHeightmapDimensions(_file_to_saveload.detail_ftype, _file_to_saveload.name.c_str(), &x, &y)) return; } WindowDesc *desc = (mode == GLWM_HEIGHTMAP) ? &_heightmap_load_desc : &_generate_landscape_desc; diff --git a/src/landscape.cpp b/src/landscape.cpp index 6dddbfd70f..9f4116a232 100644 --- a/src/landscape.cpp +++ b/src/landscape.cpp @@ -1305,7 +1305,7 @@ void GenerateLandscape(byte mode) if (mode == GWM_HEIGHTMAP) { SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_HEIGHTMAP); - LoadHeightmap(_file_to_saveload.detail_ftype, _file_to_saveload.name); + LoadHeightmap(_file_to_saveload.detail_ftype, _file_to_saveload.name.c_str()); IncreaseGeneratingWorldProgress(GWP_LANDSCAPE); } else if (_settings_game.game_creation.land_generator == LG_TERRAGENESIS) { SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_TERRAGENESIS); diff --git a/src/music/midifile.cpp b/src/music/midifile.cpp index b15a27911c..59cc2a631f 100644 --- a/src/music/midifile.cpp +++ b/src/music/midifile.cpp @@ -1078,11 +1078,11 @@ std::string MidiFile::GetSMFFile(const MusicSongInfo &song) std::string tempdirname = FioGetDirectory(Searchpath::SP_AUTODOWNLOAD_DIR, Subdirectory::BASESET_DIR); tempdirname += basename; AppendPathSeparator(tempdirname); - FioCreateDirectory(tempdirname.c_str()); + FioCreateDirectory(tempdirname); std::string output_filename = tempdirname + std::to_string(song.cat_index) + ".mid"; - if (FileExists(output_filename.c_str())) { + if (FileExists(output_filename)) { /* If the file already exists, assume it's the correct decoded data */ return output_filename; } diff --git a/src/network/network_client.cpp b/src/network/network_client.cpp index eb5c4cbb35..a66786dade 100644 --- a/src/network/network_client.cpp +++ b/src/network/network_client.cpp @@ -541,7 +541,7 @@ bool ClientNetworkGameSocketHandler::IsConnected() * DEF_CLIENT_RECEIVE_COMMAND has parameter: Packet *p ************/ -extern bool SafeLoad(const char *filename, SaveLoadOperation fop, DetailedFileType dft, GameMode newgm, Subdirectory subdir, struct LoadFilter *lf = nullptr); +extern bool SafeLoad(const std::string &filename, SaveLoadOperation fop, DetailedFileType dft, GameMode newgm, Subdirectory subdir, struct LoadFilter *lf = nullptr); NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_FULL(Packet *p) { @@ -867,7 +867,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MAP_DONE(Packet /* The map is done downloading, load it */ ClearErrorMessages(); - bool load_success = SafeLoad(nullptr, SLO_LOAD, DFT_GAME_FILE, GM_NORMAL, NO_DIRECTORY, lf); + bool load_success = SafeLoad({}, SLO_LOAD, DFT_GAME_FILE, GM_NORMAL, NO_DIRECTORY, lf); /* Long savegame loads shouldn't affect the lag calculation! */ this->last_packet = _realtime_tick; diff --git a/src/openttd.cpp b/src/openttd.cpp index 2409e8e4e3..3e1b36cd87 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -626,9 +626,9 @@ int openttd_main(int argc, char *argv[]) _file_to_saveload.SetMode(SLO_LOAD, is_scenario ? FT_SCENARIO : FT_SAVEGAME, DFT_GAME_FILE); /* if the file doesn't exist or it is not a valid savegame, let the saveload code show an error */ - const char *t = strrchr(_file_to_saveload.name, '.'); - if (t != nullptr) { - FiosType ft = FiosGetSavegameListCallback(SLO_LOAD, _file_to_saveload.name, t, nullptr, nullptr); + auto t = _file_to_saveload.name.find_last_of('.'); + if (t != std::string::npos) { + FiosType ft = FiosGetSavegameListCallback(SLO_LOAD, _file_to_saveload.name.c_str(), _file_to_saveload.name.substr(t).c_str(), nullptr, nullptr); if (ft != FIOS_TYPE_INVALID) _file_to_saveload.SetMode(ft); } @@ -960,7 +960,7 @@ static void MakeNewEditorWorld() * @param subdir default directory to look for filename, set to 0 if not needed * @param lf Load filter to use, if nullptr: use filename + subdir. */ -bool SafeLoad(const char *filename, SaveLoadOperation fop, DetailedFileType dft, GameMode newgm, Subdirectory subdir, struct LoadFilter *lf = nullptr) +bool SafeLoad(const std::string &filename, SaveLoadOperation fop, DetailedFileType dft, GameMode newgm, Subdirectory subdir, struct LoadFilter *lf = nullptr) { assert(fop == SLO_LOAD); assert(dft == DFT_GAME_FILE || (lf == nullptr && dft == DFT_OLD_GAME_FILE)); @@ -968,7 +968,7 @@ bool SafeLoad(const char *filename, SaveLoadOperation fop, DetailedFileType dft, _game_mode = newgm; - switch (lf == nullptr ? SaveOrLoad(filename, fop, dft, subdir) : LoadWithFilter(lf)) { + switch (lf == nullptr ? SaveOrLoad(filename.c_str(), fop, dft, subdir) : LoadWithFilter(lf)) { case SL_OK: return true; case SL_REINIT: @@ -1127,7 +1127,7 @@ void SwitchToMode(SwitchMode new_mode) case SM_SAVE_GAME: // Save game. /* Make network saved games on pause compatible to singleplayer */ - if (SaveOrLoad(_file_to_saveload.name, SLO_SAVE, DFT_GAME_FILE, NO_DIRECTORY) != SL_OK) { + if (SaveOrLoad(_file_to_saveload.name.c_str(), SLO_SAVE, DFT_GAME_FILE, NO_DIRECTORY) != SL_OK) { SetDParamStr(0, GetSaveLoadErrorString()); ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR); } else { @@ -1136,7 +1136,7 @@ void SwitchToMode(SwitchMode new_mode) break; case SM_SAVE_HEIGHTMAP: // Save heightmap. - MakeHeightmapScreenshot(_file_to_saveload.name); + MakeHeightmapScreenshot(_file_to_saveload.name.c_str()); DeleteWindowById(WC_SAVELOAD, 0); break; diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp index bfbf1957b8..2bb960da60 100644 --- a/src/saveload/saveload.cpp +++ b/src/saveload/saveload.cpp @@ -2930,7 +2930,7 @@ void FileToSaveLoad::SetMode(SaveLoadOperation fop, AbstractFileType aft, Detail */ void FileToSaveLoad::SetName(const char *name) { - strecpy(this->name, name, lastof(this->name)); + this->name = name; } /** diff --git a/src/saveload/saveload.h b/src/saveload/saveload.h index a153b36301..5406462f6e 100644 --- a/src/saveload/saveload.h +++ b/src/saveload/saveload.h @@ -12,6 +12,7 @@ #include "../fileio_type.h" #include "../strings_type.h" +#include /** SaveLoad versions * Previous savegame versions, the trunk revision where they were @@ -337,7 +338,7 @@ struct FileToSaveLoad { SaveLoadOperation file_op; ///< File operation to perform. DetailedFileType detail_ftype; ///< Concrete file type (PNG, BMP, old save, etc). AbstractFileType abstract_ftype; ///< Abstract type of file (scenario, heightmap, etc). - char name[MAX_PATH]; ///< Name of the file. + std::string name; ///< Name of the file. char title[255]; ///< Internal name of the game. void SetMode(FiosType ft); diff --git a/src/script/script_instance.cpp b/src/script/script_instance.cpp index 836bb82468..8227060d35 100644 --- a/src/script/script_instance.cpp +++ b/src/script/script_instance.cpp @@ -120,7 +120,7 @@ bool ScriptInstance::LoadCompatibilityScripts(const char *api_version, Subdirect FOR_ALL_SEARCHPATHS(sp) { std::string buf = FioGetDirectory(sp, dir); buf += script_name; - if (!FileExists(buf.c_str())) continue; + if (!FileExists(buf)) continue; if (this->engine->LoadScript(buf.c_str())) return true; diff --git a/src/video/dedicated_v.cpp b/src/video/dedicated_v.cpp index b3acb82a4c..7efd417ce9 100644 --- a/src/video/dedicated_v.cpp +++ b/src/video/dedicated_v.cpp @@ -128,7 +128,7 @@ static void *_dedicated_video_mem; /* Whether a fork has been done. */ bool _dedicated_forks; -extern bool SafeLoad(const char *filename, SaveLoadOperation fop, DetailedFileType dft, GameMode newgm, Subdirectory subdir, struct LoadFilter *lf = nullptr); +extern bool SafeLoad(const std::string &filename, SaveLoadOperation fop, DetailedFileType dft, GameMode newgm, Subdirectory subdir, struct LoadFilter *lf = nullptr); static FVideoDriver_Dedicated iFVideoDriver_Dedicated; From 5cbb2da79434ec002831bd72b2c81f9dcd469601 Mon Sep 17 00:00:00 2001 From: Michael Lutz Date: Sun, 6 Dec 2020 21:11:47 +0100 Subject: [PATCH 24/64] Codechange: Even more std::string usage in file IO. --- src/fileio.cpp | 83 ++++++++++++++------------------- src/fileio_func.h | 4 +- src/game/game_text.cpp | 2 +- src/network/network_content.cpp | 2 +- src/newgrf_profiling.cpp | 2 +- src/openttd.cpp | 4 +- src/saveload/oldloader.cpp | 4 +- src/saveload/saveload.cpp | 8 ++-- src/saveload/saveload.h | 2 +- 9 files changed, 48 insertions(+), 63 deletions(-) diff --git a/src/fileio.cpp b/src/fileio.cpp index 09e884e4fa..5b8005929b 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -272,7 +272,7 @@ bool IsValidSearchPath(Searchpath sp) */ bool FioCheckFileExists(const std::string &filename, Subdirectory subdir) { - FILE *f = FioFOpenFile(filename.c_str(), "rb", subdir); + FILE *f = FioFOpenFile(filename, "rb", subdir); if (f == nullptr) return false; FioFCloseFile(f); @@ -345,7 +345,7 @@ std::string FioFindDirectory(Subdirectory subdir) return _personal_dir; } -static FILE *FioFOpenFileSp(const char *filename, const char *mode, Searchpath sp, Subdirectory subdir, size_t *filesize) +static FILE *FioFOpenFileSp(const std::string &filename, const char *mode, Searchpath sp, Subdirectory subdir, size_t *filesize) { #if defined(_WIN32) && defined(UNICODE) /* fopen is implemented as a define with ellipses for @@ -390,17 +390,17 @@ static FILE *FioFOpenFileSp(const char *filename, const char *mode, Searchpath s * @return File handle of the opened file, or \c nullptr if the file is not available. * @note The file is read from within the tar file, and may not return \c EOF after reading the whole file. */ -FILE *FioFOpenFileTar(TarFileListEntry *entry, size_t *filesize) +FILE *FioFOpenFileTar(const TarFileListEntry &entry, size_t *filesize) { - FILE *f = fopen(entry->tar_filename, "rb"); + FILE *f = fopen(entry.tar_filename, "rb"); if (f == nullptr) return f; - if (fseek(f, entry->position, SEEK_SET) < 0) { + if (fseek(f, entry.position, SEEK_SET) < 0) { fclose(f); return nullptr; } - if (filesize != nullptr) *filesize = entry->size; + if (filesize != nullptr) *filesize = entry.size; return f; } @@ -410,7 +410,7 @@ FILE *FioFOpenFileTar(TarFileListEntry *entry, size_t *filesize) * @param subdir Subdirectory to open. * @return File handle of the opened file, or \c nullptr if the file is not available. */ -FILE *FioFOpenFile(const char *filename, const char *mode, Subdirectory subdir, size_t *filesize) +FILE *FioFOpenFile(const std::string &filename, const char *mode, Subdirectory subdir, size_t *filesize) { FILE *f = nullptr; Searchpath sp; @@ -424,11 +424,8 @@ FILE *FioFOpenFile(const char *filename, const char *mode, Subdirectory subdir, /* We can only use .tar in case of data-dir, and read-mode */ if (f == nullptr && mode[0] == 'r' && subdir != NO_DIRECTORY) { - static const uint MAX_RESOLVED_LENGTH = 2 * (100 + 100 + 155) + 1; // Enough space to hold two filenames plus link. See 'TarHeader'. - char resolved_name[MAX_RESOLVED_LENGTH]; - /* Filenames in tars are always forced to be lowercase */ - strecpy(resolved_name, filename, lastof(resolved_name)); + std::string resolved_name = filename; strtolower(resolved_name); /* Resolve ".." */ @@ -443,36 +440,31 @@ FILE *FioFOpenFile(const char *filename, const char *mode, Subdirectory subdir, tokens.push_back(token); } } - resolved_name[0] = '\0'; + + resolved_name.clear(); bool first = true; for (const std::string &token : tokens) { if (!first) { - strecat(resolved_name, PATHSEP, lastof(resolved_name)); + resolved_name += PATHSEP; } - strecat(resolved_name, token.c_str(), lastof(resolved_name)); + resolved_name += token; first = false; } - size_t resolved_len = strlen(resolved_name); - /* Resolve ONE directory link */ for (TarLinkList::iterator link = _tar_linklist[subdir].begin(); link != _tar_linklist[subdir].end(); link++) { const std::string &src = link->first; size_t len = src.length(); - if (resolved_len >= len && resolved_name[len - 1] == PATHSEPCHAR && strncmp(src.c_str(), resolved_name, len) == 0) { + if (resolved_name.length() >= len && resolved_name[len - 1] == PATHSEPCHAR && src.compare(0, len, resolved_name, 0, len) == 0) { /* Apply link */ - char resolved_name2[MAX_RESOLVED_LENGTH]; - const std::string &dest = link->second; - strecpy(resolved_name2, &(resolved_name[len]), lastof(resolved_name2)); - strecpy(resolved_name, dest.c_str(), lastof(resolved_name)); - strecpy(&(resolved_name[dest.length()]), resolved_name2, lastof(resolved_name)); + resolved_name.replace(0, len, link->second); break; // Only resolve one level } } TarFileList::iterator it = _tar_filelist[subdir].find(resolved_name); if (it != _tar_filelist[subdir].end()) { - f = FioFOpenFileTar(&((*it).second), filesize); + f = FioFOpenFileTar(it->second, filesize); } } @@ -859,7 +851,7 @@ bool TarScanner::AddFile(const char *filename, size_t basepath_length, const cha * @param subdir The sub directory the tar is in. * @return false on failure. */ -bool ExtractTar(const char *tar_filename, Subdirectory subdir) +bool ExtractTar(const std::string &tar_filename, Subdirectory subdir) { TarList::iterator it = _tar_list[subdir].find(tar_filename); /* We don't know the file. */ @@ -869,41 +861,38 @@ bool ExtractTar(const char *tar_filename, Subdirectory subdir) /* The file doesn't have a sub directory! */ if (dirname == nullptr) { - DEBUG(misc, 1, "Extracting %s failed; archive rejected, the contents must be in a sub directory", tar_filename); + DEBUG(misc, 1, "Extracting %s failed; archive rejected, the contents must be in a sub directory", tar_filename.c_str()); return false; } - char filename[MAX_PATH]; - strecpy(filename, tar_filename, lastof(filename)); - char *p = strrchr(filename, PATHSEPCHAR); + std::string filename = tar_filename; + auto p = filename.find_last_of(PATHSEPCHAR); /* The file's path does not have a separator? */ - if (p == nullptr) return false; + if (p == std::string::npos) return false; - p++; - strecpy(p, dirname, lastof(filename)); - DEBUG(misc, 8, "Extracting %s to directory %s", tar_filename, filename); + filename.replace(p + 1, std::string::npos, dirname); + DEBUG(misc, 8, "Extracting %s to directory %s", tar_filename.c_str(), filename.c_str()); FioCreateDirectory(filename); for (TarFileList::iterator it2 = _tar_filelist[subdir].begin(); it2 != _tar_filelist[subdir].end(); it2++) { - if (strcmp((*it2).second.tar_filename, tar_filename) != 0) continue; + if (tar_filename != it2->second.tar_filename) continue; - strecpy(p, (*it2).first.c_str(), lastof(filename)); + filename.replace(p + 1, std::string::npos, it2->first); - DEBUG(misc, 9, " extracting %s", filename); + DEBUG(misc, 9, " extracting %s", filename.c_str()); /* First open the file in the .tar. */ size_t to_copy = 0; - FILE *in = FioFOpenFileTar(&(*it2).second, &to_copy); - if (in == nullptr) { - DEBUG(misc, 6, "Extracting %s failed; could not open %s", filename, tar_filename); + std::unique_ptr in(FioFOpenFileTar(it2->second, &to_copy)); + if (!in) { + DEBUG(misc, 6, "Extracting %s failed; could not open %s", filename.c_str(), tar_filename.c_str()); return false; } /* Now open the 'output' file. */ - FILE *out = fopen(filename, "wb"); - if (out == nullptr) { - DEBUG(misc, 6, "Extracting %s failed; could not open %s", filename, filename); - fclose(in); + std::unique_ptr out(fopen(filename.c_str(), "wb")); + if (!out) { + DEBUG(misc, 6, "Extracting %s failed; could not open %s", filename.c_str(), filename.c_str()); return false; } @@ -911,16 +900,12 @@ bool ExtractTar(const char *tar_filename, Subdirectory subdir) char buffer[4096]; size_t read; for (; to_copy != 0; to_copy -= read) { - read = fread(buffer, 1, min(to_copy, lengthof(buffer)), in); - if (read <= 0 || fwrite(buffer, 1, read, out) != read) break; + read = fread(buffer, 1, min(to_copy, lengthof(buffer)), in.get()); + if (read <= 0 || fwrite(buffer, 1, read, out.get()) != read) break; } - /* Close everything up. */ - fclose(in); - fclose(out); - if (to_copy != 0) { - DEBUG(misc, 6, "Extracting %s failed; still %i bytes to copy", filename, (int)to_copy); + DEBUG(misc, 6, "Extracting %s failed; still %i bytes to copy", filename.c_str(), (int)to_copy); return false; } } diff --git a/src/fileio_func.h b/src/fileio_func.h index 5007a04e63..a2da910636 100644 --- a/src/fileio_func.h +++ b/src/fileio_func.h @@ -37,7 +37,7 @@ bool IsValidSearchPath(Searchpath sp); #define FOR_ALL_SEARCHPATHS(sp) for (sp = SP_FIRST_DIR; sp < NUM_SEARCHPATHS; sp++) if (IsValidSearchPath(sp)) void FioFCloseFile(FILE *f); -FILE *FioFOpenFile(const char *filename, const char *mode, Subdirectory subdir, size_t *filesize = nullptr); +FILE *FioFOpenFile(const std::string &filename, const char *mode, Subdirectory subdir, size_t *filesize = nullptr); bool FioCheckFileExists(const std::string &filename, Subdirectory subdir); std::string FioFindFullPath(Subdirectory subdir, const char *filename); std::string FioGetDirectory(Searchpath sp, Subdirectory subdir); @@ -51,7 +51,7 @@ void AppendPathSeparator(std::string &buf); void DeterminePaths(const char *exe); void *ReadFileToMem(const char *filename, size_t *lenp, size_t maxsize); bool FileExists(const std::string &filename); -bool ExtractTar(const char *tar_filename, Subdirectory subdir); +bool ExtractTar(const std::string &tar_filename, Subdirectory subdir); extern std::string _personal_dir; ///< custom directory for personal settings, saves, newgrf, etc. diff --git a/src/game/game_text.cpp b/src/game/game_text.cpp index 39732f7898..f704dbc2eb 100644 --- a/src/game/game_text.cpp +++ b/src/game/game_text.cpp @@ -66,7 +66,7 @@ void NORETURN CDECL strgen_fatal(const char *s, ...) LanguageStrings ReadRawLanguageStrings(const std::string &file) { size_t to_read; - FILE *fh = FioFOpenFile(file.c_str(), "rb", GAME_DIR, &to_read); + FILE *fh = FioFOpenFile(file, "rb", GAME_DIR, &to_read); if (fh == nullptr) return LanguageStrings(); FileCloser fhClose(fh); diff --git a/src/network/network_content.cpp b/src/network/network_content.cpp index dc14a59fcb..7f610d9d36 100644 --- a/src/network/network_content.cpp +++ b/src/network/network_content.cpp @@ -543,7 +543,7 @@ void ClientNetworkContentSocketHandler::AfterDownload() if (this->curInfo->type == CONTENT_TYPE_BASE_MUSIC) { /* Music can't be in a tar. So extract the tar! */ - ExtractTar(fname.c_str(), BASESET_DIR); + ExtractTar(fname, BASESET_DIR); unlink(fname.c_str()); } diff --git a/src/newgrf_profiling.cpp b/src/newgrf_profiling.cpp index 17f32384d7..b7848fa671 100644 --- a/src/newgrf_profiling.cpp +++ b/src/newgrf_profiling.cpp @@ -102,7 +102,7 @@ uint32 NewGRFProfiler::Finish() std::string filename = this->GetOutputFilename(); IConsolePrintF(CC_DEBUG, "Finished profile of NewGRF [%08X], writing %u events to %s", BSWAP32(this->grffile->grfid), (uint)this->calls.size(), filename.c_str()); - FILE *f = FioFOpenFile(filename.c_str(), "wt", Subdirectory::NO_DIRECTORY); + FILE *f = FioFOpenFile(filename, "wt", Subdirectory::NO_DIRECTORY); FileCloser fcloser(f); uint32 total_microseconds = 0; diff --git a/src/openttd.cpp b/src/openttd.cpp index 3e1b36cd87..aa98da7260 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -968,7 +968,7 @@ bool SafeLoad(const std::string &filename, SaveLoadOperation fop, DetailedFileTy _game_mode = newgm; - switch (lf == nullptr ? SaveOrLoad(filename.c_str(), fop, dft, subdir) : LoadWithFilter(lf)) { + switch (lf == nullptr ? SaveOrLoad(filename, fop, dft, subdir) : LoadWithFilter(lf)) { case SL_OK: return true; case SL_REINIT: @@ -1127,7 +1127,7 @@ void SwitchToMode(SwitchMode new_mode) case SM_SAVE_GAME: // Save game. /* Make network saved games on pause compatible to singleplayer */ - if (SaveOrLoad(_file_to_saveload.name.c_str(), SLO_SAVE, DFT_GAME_FILE, NO_DIRECTORY) != SL_OK) { + if (SaveOrLoad(_file_to_saveload.name, SLO_SAVE, DFT_GAME_FILE, NO_DIRECTORY) != SL_OK) { SetDParamStr(0, GetSaveLoadErrorString()); ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR); } else { diff --git a/src/saveload/oldloader.cpp b/src/saveload/oldloader.cpp index 0c2c7f80bc..09f15e183f 100644 --- a/src/saveload/oldloader.cpp +++ b/src/saveload/oldloader.cpp @@ -271,7 +271,7 @@ static SavegameType DetermineOldSavegameType(FILE *f, char *title, const char *l typedef bool LoadOldMainProc(LoadgameState *ls); -bool LoadOldSaveGame(const char *file) +bool LoadOldSaveGame(const std::string &file) { LoadgameState ls; @@ -283,7 +283,7 @@ bool LoadOldSaveGame(const char *file) ls.file = FioFOpenFile(file, "rb", NO_DIRECTORY); if (ls.file == nullptr) { - DEBUG(oldloader, 0, "Cannot open file '%s'", file); + DEBUG(oldloader, 0, "Cannot open file '%s'", file.c_str()); return false; } diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp index 2bb960da60..91f9c5a080 100644 --- a/src/saveload/saveload.cpp +++ b/src/saveload/saveload.cpp @@ -2413,7 +2413,7 @@ static const SaveLoadFormat *GetSavegameFormat(char *s, byte *compression_level) /* actual loader/saver function */ void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settings); extern bool AfterLoadGame(); -extern bool LoadOldSaveGame(const char *file); +extern bool LoadOldSaveGame(const std::string &file); /** * Clear temporary data that is passed between various saveload phases. @@ -2769,7 +2769,7 @@ SaveOrLoadResult LoadWithFilter(LoadFilter *reader) * @param threaded True when threaded saving is allowed * @return Return the result of the action. #SL_OK, #SL_ERROR, or #SL_REINIT ("unload" the game) */ -SaveOrLoadResult SaveOrLoad(const char *filename, SaveLoadOperation fop, DetailedFileType dft, Subdirectory sb, bool threaded) +SaveOrLoadResult SaveOrLoad(const std::string &filename, SaveLoadOperation fop, DetailedFileType dft, Subdirectory sb, bool threaded) { /* An instance of saving is already active, so don't go saving again */ if (_sl.saveinprogress && fop == SLO_SAVE && dft == DFT_GAME_FILE && threaded) { @@ -2833,7 +2833,7 @@ SaveOrLoadResult SaveOrLoad(const char *filename, SaveLoadOperation fop, Detaile } if (fop == SLO_SAVE) { // SAVE game - DEBUG(desync, 1, "save: %08x; %02x; %s", _date, _date_fract, filename); + DEBUG(desync, 1, "save: %08x; %02x; %s", _date, _date_fract, filename.c_str()); if (_network_server || !_settings_client.gui.threaded_saves) threaded = false; return DoSave(new FileWriter(fh), threaded); @@ -2841,7 +2841,7 @@ SaveOrLoadResult SaveOrLoad(const char *filename, SaveLoadOperation fop, Detaile /* LOAD game */ assert(fop == SLO_LOAD || fop == SLO_CHECK); - DEBUG(desync, 1, "load: %s", filename); + DEBUG(desync, 1, "load: %s", filename.c_str()); return DoLoad(new FileReader(fh), fop == SLO_CHECK); } catch (...) { /* This code may be executed both for old and new save games. */ diff --git a/src/saveload/saveload.h b/src/saveload/saveload.h index 5406462f6e..f5ec936a2d 100644 --- a/src/saveload/saveload.h +++ b/src/saveload/saveload.h @@ -362,7 +362,7 @@ extern FileToSaveLoad _file_to_saveload; void GenerateDefaultSaveName(char *buf, const char *last); void SetSaveLoadError(StringID str); const char *GetSaveLoadErrorString(); -SaveOrLoadResult SaveOrLoad(const char *filename, SaveLoadOperation fop, DetailedFileType dft, Subdirectory sb, bool threaded = true); +SaveOrLoadResult SaveOrLoad(const std::string &filename, SaveLoadOperation fop, DetailedFileType dft, Subdirectory sb, bool threaded = true); void WaitTillSaved(); void ProcessAsyncSaveFinish(); void DoExitSave(); From 024a3f62593fd783285c5ff09b8c85ee1fc34e2d Mon Sep 17 00:00:00 2001 From: Michael Lutz Date: Sun, 6 Dec 2020 21:11:48 +0100 Subject: [PATCH 25/64] Codechange: Use automatic memory management for language pack reading. --- src/fileio.cpp | 29 +++++----- src/fileio_func.h | 2 +- src/language.h | 2 +- src/string.cpp | 2 +- src/strings.cpp | 102 ++++++++++++++++-------------------- src/table/misc_settings.ini | 6 +-- 6 files changed, 66 insertions(+), 77 deletions(-) diff --git a/src/fileio.cpp b/src/fileio.cpp index 5b8005929b..5431df814d 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -1236,28 +1236,27 @@ void SanitizeFilename(char *filename) * @return Pointer to new memory containing the loaded data, or \c nullptr if loading failed. * @note If \a maxsize less than the length of the file, loading fails. */ -void *ReadFileToMem(const char *filename, size_t *lenp, size_t maxsize) +std::unique_ptr ReadFileToMem(const std::string &filename, size_t &lenp, size_t maxsize) { - FILE *in = fopen(filename, "rb"); + FILE *in = fopen(filename.c_str(), "rb"); if (in == nullptr) return nullptr; + FileCloser fc(in); + fseek(in, 0, SEEK_END); size_t len = ftell(in); fseek(in, 0, SEEK_SET); - if (len > maxsize) { - fclose(in); - return nullptr; - } - byte *mem = MallocT(len + 1); - mem[len] = 0; - if (fread(mem, len, 1, in) != 1) { - fclose(in); - free(mem); - return nullptr; - } - fclose(in); + if (len > maxsize) return nullptr; + + /* std::unique_ptr assumes new/delete unless a custom deleter is supplied. + * As we don't want to have to carry that deleter all over the place, use + * new directly to allocate the memory instead of malloc. */ + std::unique_ptr mem(static_cast(::operator new(len + 1))); + + mem.get()[len] = 0; + if (fread(mem.get(), len, 1, in) != 1) return nullptr; - *lenp = len; + lenp = len; return mem; } diff --git a/src/fileio_func.h b/src/fileio_func.h index a2da910636..72d461863d 100644 --- a/src/fileio_func.h +++ b/src/fileio_func.h @@ -49,7 +49,7 @@ const char *FiosGetScreenshotDir(); void SanitizeFilename(char *filename); void AppendPathSeparator(std::string &buf); void DeterminePaths(const char *exe); -void *ReadFileToMem(const char *filename, size_t *lenp, size_t maxsize); +std::unique_ptr ReadFileToMem(const std::string &filename, size_t &lenp, size_t maxsize); bool FileExists(const std::string &filename); bool ExtractTar(const std::string &tar_filename, Subdirectory subdir); diff --git a/src/language.h b/src/language.h index 269b22c246..faac595613 100644 --- a/src/language.h +++ b/src/language.h @@ -103,7 +103,7 @@ extern LanguageList _languages; extern const LanguageMetadata *_current_language; #ifdef WITH_ICU_I18N -extern icu::Collator *_current_collator; +extern std::unique_ptr _current_collator; #endif /* WITH_ICU_I18N */ bool ReadLanguagePack(const LanguageMetadata *lang); diff --git a/src/string.cpp b/src/string.cpp index 14bc926c1a..91c1aa147d 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -630,7 +630,7 @@ int strnatcmp(const char *s1, const char *s2, bool ignore_garbage_at_front) } #ifdef WITH_ICU_I18N - if (_current_collator != nullptr) { + if (_current_collator) { UErrorCode status = U_ZERO_ERROR; int result = _current_collator->compareUTF8(s1, s2, status); if (U_SUCCESS(status)) return result; diff --git a/src/strings.cpp b/src/strings.cpp index 9f61ea5fd1..adb874ba14 100644 --- a/src/strings.cpp +++ b/src/strings.cpp @@ -41,14 +41,14 @@ #include "safeguards.h" -char _config_language_file[MAX_PATH]; ///< The file (name) stored in the configuration. +std::string _config_language_file; ///< The file (name) stored in the configuration. LanguageList _languages; ///< The actual list of language meta data. const LanguageMetadata *_current_language = nullptr; ///< The currently loaded language. TextDirection _current_text_dir; ///< Text direction of the currently selected language. #ifdef WITH_ICU_I18N -icu::Collator *_current_collator = nullptr; ///< Collator for the language currently in use. +std::unique_ptr _current_collator; ///< Collator for the language currently in use. #endif /* WITH_ICU_I18N */ static uint64 _global_string_params_data[20]; ///< Global array of string parameters. To access, use #SetDParam. @@ -185,10 +185,17 @@ struct LanguagePack : public LanguagePackHeader { char data[]; // list of strings }; -static char **_langpack_offs; -static LanguagePack *_langpack; -static uint _langtab_num[TEXT_TAB_END]; ///< Offset into langpack offs -static uint _langtab_start[TEXT_TAB_END]; ///< Offset into langpack offs +struct LoadedLanguagePack { + std::unique_ptr langpack; + + std::vector offsets; + + std::array langtab_num; ///< Offset into langpack offs + std::array langtab_start; ///< Offset into langpack offs +}; + +static LoadedLanguagePack _langpack; + static bool _scan_for_gender_data = false; ///< Are we scanning for the gender of the current string? (instead of formatting it) @@ -199,7 +206,7 @@ const char *GetStringPtr(StringID string) /* 0xD0xx and 0xD4xx IDs have been converted earlier. */ case TEXT_TAB_OLD_NEWGRF: NOT_REACHED(); case TEXT_TAB_NEWGRF_START: return GetGRFStringPtr(GetStringIndex(string)); - default: return _langpack_offs[_langtab_start[GetStringTab(string)] + GetStringIndex(string)]; + default: return _langpack.offsets[_langpack.langtab_start[GetStringTab(string)] + GetStringIndex(string)]; } } @@ -253,7 +260,7 @@ char *GetStringWithArgs(char *buffr, StringID string, StringParameters *args, co break; } - if (index >= _langtab_num[tab]) { + if (index >= _langpack.langtab_num[tab]) { if (game_script) { return GetStringWithArgs(buffr, STR_UNDEFINED, args, last); } @@ -318,7 +325,7 @@ static char *FormatNumber(char *buff, int64 number, const char *last, const char for (int i = 0; i < max_digits; i++) { if (i == max_digits - fractional_digits) { const char *decimal_separator = _settings_game.locale.digit_decimal_separator; - if (decimal_separator == nullptr) decimal_separator = _langpack->digit_decimal_separator; + if (decimal_separator == nullptr) decimal_separator = _langpack.langpack->digit_decimal_separator; buff += seprintf(buff, last, "%s", decimal_separator); } @@ -343,7 +350,7 @@ static char *FormatNumber(char *buff, int64 number, const char *last, const char static char *FormatCommaNumber(char *buff, int64 number, const char *last, int fractional_digits = 0) { const char *separator = _settings_game.locale.digit_group_separator; - if (separator == nullptr) separator = _langpack->digit_group_separator; + if (separator == nullptr) separator = _langpack.langpack->digit_group_separator; return FormatNumber(buff, number, last, separator, 1, fractional_digits); } @@ -382,7 +389,7 @@ static char *FormatBytes(char *buff, int64 number, const char *last) } const char *decimal_separator = _settings_game.locale.digit_decimal_separator; - if (decimal_separator == nullptr) decimal_separator = _langpack->digit_decimal_separator; + if (decimal_separator == nullptr) decimal_separator = _langpack.langpack->digit_decimal_separator; if (number < 1024) { id = 0; @@ -477,7 +484,7 @@ static char *FormatGenericCurrency(char *buff, const CurrencySpec *spec, Money n const char *separator = _settings_game.locale.digit_group_separator_currency; if (separator == nullptr && !StrEmpty(_currency->separator)) separator = _currency->separator; - if (separator == nullptr) separator = _langpack->digit_group_separator_currency; + if (separator == nullptr) separator = _langpack.langpack->digit_group_separator_currency; buff = FormatNumber(buff, number, last, separator); buff = strecpy(buff, multiplier, last); @@ -1721,16 +1728,15 @@ bool LanguagePackHeader::IsValid() const bool ReadLanguagePack(const LanguageMetadata *lang) { /* Current language pack */ - size_t len; - LanguagePack *lang_pack = (LanguagePack *)ReadFileToMem(lang->file, &len, 1U << 20); - if (lang_pack == nullptr) return false; + size_t len = 0; + std::unique_ptr lang_pack(reinterpret_cast(ReadFileToMem(lang->file, len, 1U << 20).release())); + if (!lang_pack) return false; /* End of read data (+ terminating zero added in ReadFileToMem()) */ - const char *end = (char *)lang_pack + len + 1; + const char *end = (char *)lang_pack.get() + len + 1; /* We need at least one byte of lang_pack->data */ if (end <= lang_pack->data || !lang_pack->IsValid()) { - free(lang_pack); return false; } @@ -1740,55 +1746,46 @@ bool ReadLanguagePack(const LanguageMetadata *lang) } #endif /* TTD_ENDIAN == TTD_BIG_ENDIAN */ + std::array tab_start, tab_num; + uint count = 0; for (uint i = 0; i < TEXT_TAB_END; i++) { uint16 num = lang_pack->offsets[i]; - if (num > TAB_SIZE) { - free(lang_pack); - return false; - } + if (num > TAB_SIZE) return false; - _langtab_start[i] = count; - _langtab_num[i] = num; + tab_start[i] = count; + tab_num[i] = num; count += num; } /* Allocate offsets */ - char **langpack_offs = MallocT(count); + std::vector offs(count); /* Fill offsets */ char *s = lang_pack->data; len = (byte)*s++; for (uint i = 0; i < count; i++) { - if (s + len >= end) { - free(lang_pack); - free(langpack_offs); - return false; - } + if (s + len >= end) return false; + if (len >= 0xC0) { len = ((len & 0x3F) << 8) + (byte)*s++; - if (s + len >= end) { - free(lang_pack); - free(langpack_offs); - return false; - } + if (s + len >= end) return false; } - langpack_offs[i] = s; + offs[i] = s; s += len; len = (byte)*s; *s++ = '\0'; // zero terminate the string } - free(_langpack); - _langpack = lang_pack; - - free(_langpack_offs); - _langpack_offs = langpack_offs; + _langpack.langpack = std::move(lang_pack); + _langpack.offsets = std::move(offs); + _langpack.langtab_num = tab_num; + _langpack.langtab_start = tab_start; _current_language = lang; _current_text_dir = (TextDirection)_current_language->text_dir; const char *c_file = strrchr(_current_language->file, PATHSEPCHAR) + 1; - strecpy(_config_language_file, c_file, lastof(_config_language_file)); + _config_language_file = c_file; SetCurrentGrfLangID(_current_language->newgrflangid); #ifdef _WIN32 @@ -1802,21 +1799,14 @@ bool ReadLanguagePack(const LanguageMetadata *lang) #endif #ifdef WITH_ICU_I18N - /* Delete previous collator. */ - if (_current_collator != nullptr) { - delete _current_collator; - _current_collator = nullptr; - } - /* Create a collator instance for our current locale. */ UErrorCode status = U_ZERO_ERROR; - _current_collator = icu::Collator::createInstance(icu::Locale(_current_language->isocode), status); + _current_collator.reset(icu::Collator::createInstance(icu::Locale(_current_language->isocode), status)); /* Sort number substrings by their numerical value. */ - if (_current_collator != nullptr) _current_collator->setAttribute(UCOL_NUMERIC_COLLATION, UCOL_ON, status); + if (_current_collator) _current_collator->setAttribute(UCOL_NUMERIC_COLLATION, UCOL_ON, status); /* Avoid using the collator if it is not correctly set. */ if (U_FAILURE(status)) { - delete _current_collator; - _current_collator = nullptr; + _current_collator.reset(); } #endif /* WITH_ICU_I18N */ @@ -1978,7 +1968,7 @@ void InitializeLanguagePacks() * configuration file, local environment and last, if nothing found, * English. */ const char *lang_file = strrchr(lng.file, PATHSEPCHAR) + 1; - if (strcmp(lang_file, _config_language_file) == 0) { + if (_config_language_file == lang_file) { chosen_language = &lng; break; } @@ -2003,7 +1993,7 @@ void InitializeLanguagePacks() */ const char *GetCurrentLanguageIsoCode() { - return _langpack->isocode; + return _langpack.langpack->isocode; } /** @@ -2057,10 +2047,10 @@ class LanguagePackGlyphSearcher : public MissingGlyphSearcher { { if (this->i >= TEXT_TAB_END) return nullptr; - const char *ret = _langpack_offs[_langtab_start[this->i] + this->j]; + const char *ret = _langpack.offsets[_langpack.langtab_start[this->i] + this->j]; this->j++; - while (this->i < TEXT_TAB_END && this->j >= _langtab_num[this->i]) { + while (this->i < TEXT_TAB_END && this->j >= _langpack.langtab_num[this->i]) { this->i++; this->j = 0; } @@ -2116,7 +2106,7 @@ void CheckForMissingGlyphs(bool base_font, MissingGlyphSearcher *searcher) _freetype.mono.os_handle = nullptr; _freetype.medium.os_handle = nullptr; - bad_font = !SetFallbackFont(&_freetype, _langpack->isocode, _langpack->winlangid, searcher); + bad_font = !SetFallbackFont(&_freetype, _langpack.langpack->isocode, _langpack.langpack->winlangid, searcher); free(_freetype.mono.os_handle); free(_freetype.medium.os_handle); diff --git a/src/table/misc_settings.ini b/src/table/misc_settings.ini index 60799a4369..edad848165 100644 --- a/src/table/misc_settings.ini +++ b/src/table/misc_settings.ini @@ -5,7 +5,7 @@ ; [pre-amble] -extern char _config_language_file[MAX_PATH]; +extern std::string _config_language_file; static const char *_support8bppmodes = "no|system|hardware"; @@ -107,9 +107,9 @@ type = SLE_STRQ var = _ini_blitter def = nullptr -[SDTG_STR] +[SDTG_SSTR] name = ""language"" -type = SLE_STRB +type = SLE_STR var = _config_language_file def = nullptr cat = SC_BASIC From 358056ec428d1938b8c9219a60c6fb400115f152 Mon Sep 17 00:00:00 2001 From: Michael Lutz Date: Sun, 6 Dec 2020 21:11:49 +0100 Subject: [PATCH 26/64] Codechange: Keep filenames of loaded Fio files in std::strings. --- src/fileio.cpp | 32 +++++++++++++++----------------- src/fileio_func.h | 2 +- src/ini.cpp | 2 +- src/ini_load.cpp | 2 +- src/ini_type.h | 4 ++-- src/settingsgen/settingsgen.cpp | 4 ++-- 6 files changed, 22 insertions(+), 24 deletions(-) diff --git a/src/fileio.cpp b/src/fileio.cpp index 5431df814d..7df22921e6 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -40,13 +40,13 @@ /** Structure for keeping several open files with just one data buffer. */ struct Fio { byte *buffer, *buffer_end; ///< position pointer in local buffer and last valid byte of buffer + byte buffer_start[FIO_BUFFER_SIZE]; ///< local buffer when read from file size_t pos; ///< current (system) position in file FILE *cur_fh; ///< current file handle - const char *filename; ///< current filename - FILE *handles[MAX_FILE_SLOTS]; ///< array of file handles we can have open - byte buffer_start[FIO_BUFFER_SIZE]; ///< local buffer when read from file - const char *filenames[MAX_FILE_SLOTS]; ///< array of filenames we (should) have open - char *shortnames[MAX_FILE_SLOTS]; ///< array of short names for spriteloader's use + std::string filename; ///< current filename + std::array handles; ///< array of file handles we can have open + std::array filenames; ///< array of filenames we (should) have open + std::array shortnames;///< array of short names for spriteloader's use }; static Fio _fio; ///< #Fio instance. @@ -73,7 +73,7 @@ size_t FioGetPos() */ const char *FioGetFilename(uint8 slot) { - return _fio.shortnames[slot]; + return _fio.shortnames[slot].c_str(); } /** @@ -87,7 +87,7 @@ void FioSeekTo(size_t pos, int mode) _fio.buffer = _fio.buffer_end = _fio.buffer_start + FIO_BUFFER_SIZE; _fio.pos = pos; if (fseek(_fio.cur_fh, _fio.pos, SEEK_SET) < 0) { - DEBUG(misc, 0, "Seeking in %s failed", _fio.filename); + DEBUG(misc, 0, "Seeking in %s failed", _fio.filename.c_str()); } } @@ -178,8 +178,7 @@ static inline void FioCloseFile(int slot) if (_fio.handles[slot] != nullptr) { fclose(_fio.handles[slot]); - free(_fio.shortnames[slot]); - _fio.shortnames[slot] = nullptr; + _fio.shortnames[slot].clear(); _fio.handles[slot] = nullptr; } @@ -199,27 +198,26 @@ void FioCloseAll() * @param filename Name of the file at the disk. * @param subdir The sub directory to search this file in. */ -void FioOpenFile(int slot, const char *filename, Subdirectory subdir) +void FioOpenFile(int slot, const std::string &filename, Subdirectory subdir) { FILE *f; f = FioFOpenFile(filename, "rb", subdir); - if (f == nullptr) usererror("Cannot open file '%s'", filename); + if (f == nullptr) usererror("Cannot open file '%s'", filename.c_str()); long pos = ftell(f); - if (pos < 0) usererror("Cannot read file '%s'", filename); + if (pos < 0) usererror("Cannot read file '%s'", filename.c_str()); FioCloseFile(slot); // if file was opened before, close it _fio.handles[slot] = f; _fio.filenames[slot] = filename; /* Store the filename without path and extension */ - const char *t = strrchr(filename, PATHSEPCHAR); - _fio.shortnames[slot] = stredup(t == nullptr ? filename : t); - char *t2 = strrchr(_fio.shortnames[slot], '.'); - if (t2 != nullptr) *t2 = '\0'; + auto t = filename.rfind(PATHSEPCHAR); + std::string sn = filename.substr(t != std::string::npos ? t + 1 : 0); + _fio.shortnames[slot] = sn.substr(0, sn.rfind('.')); strtolower(_fio.shortnames[slot]); - FioSeekToFile(slot, (uint32)pos); + FioSeekToFile(slot, (size_t)pos); } static const char * const _subdirs[] = { diff --git a/src/fileio_func.h b/src/fileio_func.h index 72d461863d..014050b4b9 100644 --- a/src/fileio_func.h +++ b/src/fileio_func.h @@ -22,7 +22,7 @@ byte FioReadByte(); uint16 FioReadWord(); uint32 FioReadDword(); void FioCloseAll(); -void FioOpenFile(int slot, const char *filename, Subdirectory subdir); +void FioOpenFile(int slot, const std::string &filename, Subdirectory subdir); void FioReadBlock(void *ptr, size_t size); void FioSkipBytes(int n); diff --git a/src/ini.cpp b/src/ini.cpp index 036ced6688..e70cc268aa 100644 --- a/src/ini.cpp +++ b/src/ini.cpp @@ -125,7 +125,7 @@ bool IniFile::SaveToDisk(const std::string &filename) return true; } -/* virtual */ FILE *IniFile::OpenFile(const char *filename, Subdirectory subdir, size_t *size) +/* virtual */ FILE *IniFile::OpenFile(const std::string &filename, Subdirectory subdir, size_t *size) { /* Open the text file in binary mode to prevent end-of-line translations * done by ftell() and friends, as defined by K&R. */ diff --git a/src/ini_load.cpp b/src/ini_load.cpp index e7c2b95fe6..022e2bf180 100644 --- a/src/ini_load.cpp +++ b/src/ini_load.cpp @@ -204,7 +204,7 @@ void IniLoadFile::LoadFromDisk(const std::string &filename, Subdirectory subdir) uint comment_alloc = 0; size_t end; - FILE *in = this->OpenFile(filename.c_str(), subdir, &end); + FILE *in = this->OpenFile(filename, subdir, &end); if (in == nullptr) return; end += ftell(in); diff --git a/src/ini_type.h b/src/ini_type.h index 1637174500..160ba7619c 100644 --- a/src/ini_type.h +++ b/src/ini_type.h @@ -73,7 +73,7 @@ struct IniLoadFile { * @param[out] size Size of the opened file. * @return File handle of the opened file, or \c nullptr. */ - virtual FILE *OpenFile(const char *filename, Subdirectory subdir, size_t *size) = 0; + virtual FILE *OpenFile(const std::string &filename, Subdirectory subdir, size_t *size) = 0; /** * Report an error about the file contents. @@ -90,7 +90,7 @@ struct IniFile : IniLoadFile { bool SaveToDisk(const std::string &filename); - virtual FILE *OpenFile(const char *filename, Subdirectory subdir, size_t *size); + virtual FILE *OpenFile(const std::string &filename, Subdirectory subdir, size_t *size); virtual void ReportFileError(const char * const pre, const char * const buffer, const char * const post); }; diff --git a/src/settingsgen/settingsgen.cpp b/src/settingsgen/settingsgen.cpp index b2a3c76f64..513b4c7544 100644 --- a/src/settingsgen/settingsgen.cpp +++ b/src/settingsgen/settingsgen.cpp @@ -165,11 +165,11 @@ struct SettingsIniFile : IniLoadFile { { } - virtual FILE *OpenFile(const char *filename, Subdirectory subdir, size_t *size) + virtual FILE *OpenFile(const std::string &filename, Subdirectory subdir, size_t *size) { /* Open the text file in binary mode to prevent end-of-line translations * done by ftell() and friends, as defined by K&R. */ - FILE *in = fopen(filename, "rb"); + FILE *in = fopen(filename.c_str(), "rb"); if (in == nullptr) return nullptr; fseek(in, 0L, SEEK_END); From b408fe77f792650ef569f9852165759f960fd52f Mon Sep 17 00:00:00 2001 From: Michael Lutz Date: Sun, 6 Dec 2020 21:11:50 +0100 Subject: [PATCH 27/64] Codechange: Use std::string in file scanners. --- src/ai/ai_scanner.cpp | 3 +-- src/base_media_base.h | 2 +- src/base_media_func.h | 10 +++---- src/fileio.cpp | 38 +++++++++++++-------------- src/fileio_func.h | 6 ++--- src/fios.cpp | 49 ++++++++++++++++------------------- src/fios.h | 2 +- src/game/game_text.cpp | 8 +++--- src/newgrf_config.cpp | 6 ++--- src/openttd.cpp | 2 +- src/saveload/oldloader.cpp | 2 +- src/script/script_info.cpp | 7 ++--- src/script/script_info.hpp | 10 +++---- src/script/script_scanner.cpp | 48 ++++++++++------------------------ src/script/script_scanner.hpp | 12 ++++----- src/tar_type.h | 18 +++---------- 16 files changed, 91 insertions(+), 132 deletions(-) diff --git a/src/ai/ai_scanner.cpp b/src/ai/ai_scanner.cpp index 1431a2820b..9b3613712d 100644 --- a/src/ai/ai_scanner.cpp +++ b/src/ai/ai_scanner.cpp @@ -32,8 +32,7 @@ void AIScannerInfo::Initialize() ScriptAllocatorScope alloc_scope(this->engine); /* Create the dummy AI */ - free(this->main_script); - this->main_script = stredup("%_dummy"); + this->main_script = "%_dummy"; extern void Script_CreateDummyInfo(HSQUIRRELVM vm, const char *type, const char *dir); Script_CreateDummyInfo(this->engine->GetVM(), "AI", "ai"); } diff --git a/src/base_media_base.h b/src/base_media_base.h index 881fdc3f38..790bb9d38c 100644 --- a/src/base_media_base.h +++ b/src/base_media_base.h @@ -167,7 +167,7 @@ protected: static Tbase_set *duplicate_sets; ///< All sets that aren't available, but needed for not downloading base sets when a newer version than the one on BaNaNaS is loaded. static const Tbase_set *used_set; ///< The currently used set - bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename) override; + bool AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename) override; /** * Get the extension that is used to identify this set. diff --git a/src/base_media_func.h b/src/base_media_func.h index 703165db5e..8491f0e510 100644 --- a/src/base_media_func.h +++ b/src/base_media_func.h @@ -150,14 +150,14 @@ bool BaseSet::FillSetDetails(IniFile *ini, const } template -bool BaseMedia::AddFile(const char *filename, size_t basepath_length, const char *tar_filename) +bool BaseMedia::AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename) { bool ret = false; - DEBUG(grf, 1, "Checking %s for base " SET_TYPE " set", filename); + DEBUG(grf, 1, "Checking %s for base " SET_TYPE " set", filename.c_str()); Tbase_set *set = new Tbase_set(); IniFile *ini = new IniFile(); - std::string path{ filename + basepath_length }; + std::string path{ filename, basepath_length }; ini->LoadFromDisk(path, BASESET_DIR); auto psep = path.rfind(PATHSEPCHAR); @@ -167,7 +167,7 @@ bool BaseMedia::AddFile(const char *filename, size_t basepath_length, path.clear(); } - if (set->FillSetDetails(ini, path.c_str(), filename)) { + if (set->FillSetDetails(ini, path.c_str(), filename.c_str())) { Tbase_set *duplicate = nullptr; for (Tbase_set *c = BaseMedia::available_sets; c != nullptr; c = c->next) { if (c->name == set->name || c->shortname == set->shortname) { @@ -377,7 +377,7 @@ template #define INSTANTIATE_BASE_MEDIA_METHODS(repl_type, set_type) \ 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::AddFile(const std::string &filename, size_t pathlength, const std::string &tar_filename); \ template bool repl_type::HasSet(const struct ContentInfo *ci, bool md5sum); \ template bool repl_type::SetSet(const std::string &name); \ template char *repl_type::GetSetsList(char *p, const char *last); \ diff --git a/src/fileio.cpp b/src/fileio.cpp index 7df22921e6..cba18873a4 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -246,7 +246,7 @@ static_assert(lengthof(_subdirs) == NUM_SUBDIRS); * current operating system. */ std::array _searchpaths; -TarList _tar_list[NUM_SUBDIRS]; +std::array _tar_list; TarFileList _tar_filelist[NUM_SUBDIRS]; typedef std::map TarLinkList; @@ -390,7 +390,7 @@ static FILE *FioFOpenFileSp(const std::string &filename, const char *mode, Searc */ FILE *FioFOpenFileTar(const TarFileListEntry &entry, size_t *filesize) { - FILE *f = fopen(entry.tar_filename, "rb"); + FILE *f = fopen(entry.tar_filename.c_str(), "rb"); if (f == nullptr) return f; if (fseek(f, entry.position, SEEK_SET) < 0) { @@ -613,16 +613,16 @@ uint TarScanner::DoScan(Subdirectory sd) * @param filename The name of the file to add. * @return True if the additions went correctly. */ -bool TarScanner::AddFile(Subdirectory sd, const char *filename) +bool TarScanner::AddFile(Subdirectory sd, const std::string &filename) { this->subdir = sd; return this->AddFile(filename, 0); } -bool TarScanner::AddFile(const char *filename, size_t basepath_length, const char *tar_filename) +bool TarScanner::AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename) { /* No tar within tar. */ - assert(tar_filename == nullptr); + assert(tar_filename.empty()); /* The TAR-header, repeated for every file */ struct TarHeader { @@ -650,16 +650,14 @@ bool TarScanner::AddFile(const char *filename, size_t basepath_length, const cha TarList::iterator it = _tar_list[this->subdir].find(filename); if (it != _tar_list[this->subdir].end()) return false; - FILE *f = fopen(filename, "rb"); + FILE *f = fopen(filename.c_str(), "rb"); /* Although the file has been found there can be * a number of reasons we cannot open the file. * Most common case is when we simply have not * been given read access. */ if (f == nullptr) return false; - const char *dupped_filename = stredup(filename); - _tar_list[this->subdir][filename].filename = dupped_filename; - _tar_list[this->subdir][filename].dirname = nullptr; + _tar_list[this->subdir][filename] = std::string{}; TarLinkList links; ///< Temporary list to collect links @@ -684,7 +682,7 @@ bool TarScanner::AddFile(const char *filename, size_t basepath_length, const cha /* If we have only zeros in the block, it can be an end-of-file indicator */ if (memcmp(&th, &empty[0], 512) == 0) continue; - DEBUG(misc, 0, "The file '%s' isn't a valid tar-file", filename); + DEBUG(misc, 0, "The file '%s' isn't a valid tar-file", filename.c_str()); fclose(f); return false; } @@ -714,7 +712,7 @@ bool TarScanner::AddFile(const char *filename, size_t basepath_length, const cha /* Store this entry in the list */ TarFileListEntry entry; - entry.tar_filename = dupped_filename; + entry.tar_filename = filename; entry.size = skip; entry.position = pos; @@ -782,7 +780,7 @@ bool TarScanner::AddFile(const char *filename, size_t basepath_length, const cha } if (destpos >= lastof(dest)) { - DEBUG(misc, 0, "The length of a link in tar-file '%s' is too large (malformed?)", filename); + DEBUG(misc, 0, "The length of a link in tar-file '%s' is too large (malformed?)", filename.c_str()); fclose(f); return false; } @@ -803,7 +801,7 @@ bool TarScanner::AddFile(const char *filename, size_t basepath_length, const cha /* Store the first directory name we detect */ DEBUG(misc, 6, "Found dir in tar: %s", name); - if (_tar_list[this->subdir][filename].dirname == nullptr) _tar_list[this->subdir][filename].dirname = stredup(name); + if (_tar_list[this->subdir][filename].empty()) _tar_list[this->subdir][filename] = name; break; default: @@ -814,14 +812,14 @@ bool TarScanner::AddFile(const char *filename, size_t basepath_length, const cha /* Skip to the next block.. */ skip = Align(skip, 512); if (fseek(f, skip, SEEK_CUR) < 0) { - DEBUG(misc, 0, "The file '%s' can't be read as a valid tar-file", filename); + DEBUG(misc, 0, "The file '%s' can't be read as a valid tar-file", filename.c_str()); fclose(f); return false; } pos += skip; } - DEBUG(misc, 1, "Found tar '%s' with " PRINTF_SIZE " new files", filename, num); + DEBUG(misc, 1, "Found tar '%s' with " PRINTF_SIZE " new files", filename.c_str(), num); fclose(f); /* Resolve file links and store directory links. @@ -855,10 +853,10 @@ bool ExtractTar(const std::string &tar_filename, Subdirectory subdir) /* We don't know the file. */ if (it == _tar_list[subdir].end()) return false; - const char *dirname = (*it).second.dirname; + const auto &dirname = (*it).second; /* The file doesn't have a sub directory! */ - if (dirname == nullptr) { + if (dirname.empty()) { DEBUG(misc, 1, "Extracting %s failed; archive rejected, the contents must be in a sub directory", tar_filename.c_str()); return false; } @@ -1308,7 +1306,7 @@ static uint ScanPath(FileScanner *fs, const char *extension, const char *path, s num += ScanPath(fs, extension, filename.c_str(), basepath_length, recursive); } else if (S_ISREG(sb.st_mode)) { /* File */ - if (MatchesExtension(extension, filename.c_str()) && fs->AddFile(filename.c_str(), basepath_length, nullptr)) num++; + if (MatchesExtension(extension, filename.c_str()) && fs->AddFile(filename, basepath_length, {})) num++; } } @@ -1326,9 +1324,9 @@ static uint ScanPath(FileScanner *fs, const char *extension, const char *path, s static uint ScanTar(FileScanner *fs, const char *extension, TarFileList::iterator tar) { uint num = 0; - const char *filename = (*tar).first.c_str(); + const auto &filename = (*tar).first; - if (MatchesExtension(extension, filename) && fs->AddFile(filename, 0, (*tar).second.tar_filename)) num++; + if (MatchesExtension(extension, filename.c_str()) && fs->AddFile(filename, 0, (*tar).second.tar_filename)) num++; return num; } diff --git a/src/fileio_func.h b/src/fileio_func.h index 014050b4b9..0195739061 100644 --- a/src/fileio_func.h +++ b/src/fileio_func.h @@ -74,7 +74,7 @@ public: * @param tar_filename the name of the tar file the file is read from. * @return true if the file is added. */ - virtual bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename) = 0; + virtual bool AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename) = 0; }; /** Helper for scanning for files with tar as extension */ @@ -92,9 +92,9 @@ public: ALL = BASESET | NEWGRF | AI | SCENARIO | GAME, ///< Scan for everything. }; - bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename = nullptr) override; + bool AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename = nullptr) override; - bool AddFile(Subdirectory sd, const char *filename); + bool AddFile(Subdirectory sd, const std::string &filename); /** Do the scan for Tars. */ static uint DoScan(TarScanner::Mode mode); diff --git a/src/fios.cpp b/src/fios.cpp index e7341b1f51..698a0b5592 100644 --- a/src/fios.cpp +++ b/src/fios.cpp @@ -42,7 +42,7 @@ extern void FiosGetDrives(FileList &file_list); extern bool FiosGetDiskFreeSpace(const char *path, uint64 *tot); /* get the name of an oldstyle savegame */ -extern void GetOldSaveGameName(const char *file, char *title, const char *last); +extern void GetOldSaveGameName(const std::string &file, char *title, const char *last); /** * Compare two FiosItem's. Used with sort when sorting the file list. @@ -260,7 +260,7 @@ bool FiosDelete(const char *name) return unlink(filename.c_str()) == 0; } -typedef FiosType fios_getlist_callback_proc(SaveLoadOperation fop, const char *filename, const char *ext, char *title, const char *last); +typedef FiosType fios_getlist_callback_proc(SaveLoadOperation fop, const std::string &filename, const char *ext, char *title, const char *last); /** * Scanner to scan for a particular type of FIOS file. @@ -280,7 +280,7 @@ public: fop(fop), callback_proc(callback_proc), file_list(file_list) {} - bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename) override; + bool AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename) override; }; /** @@ -289,25 +289,26 @@ public: * @param basepath_length amount of characters to chop of before to get a relative filename * @return true if the file is added. */ -bool FiosFileScanner::AddFile(const char *filename, size_t basepath_length, const char *tar_filename) +bool FiosFileScanner::AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename) { - const char *ext = strrchr(filename, '.'); - if (ext == nullptr) return false; + auto sep = filename.rfind('.'); + if (sep == std::string::npos) return false; + std::string ext = filename.substr(sep); char fios_title[64]; fios_title[0] = '\0'; // reset the title; - FiosType type = this->callback_proc(this->fop, filename, ext, fios_title, lastof(fios_title)); + FiosType type = this->callback_proc(this->fop, filename, ext.c_str(), fios_title, lastof(fios_title)); if (type == FIOS_TYPE_INVALID) return false; for (const FiosItem *fios = file_list.Begin(); fios != file_list.End(); fios++) { - if (strcmp(fios->name, filename) == 0) return false; + if (filename == fios->name) return false; } FiosItem *fios = file_list.Append(); #ifdef _WIN32 // Retrieve the file modified date using GetFileTime rather than stat to work around an obscure MSVC bug that affects Windows XP - HANDLE fh = CreateFile(OTTD2FS(filename), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr); + HANDLE fh = CreateFile(OTTD2FS(filename.c_str()), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr); if (fh != INVALID_HANDLE_VALUE) { FILETIME ft; @@ -326,7 +327,7 @@ bool FiosFileScanner::AddFile(const char *filename, size_t basepath_length, cons CloseHandle(fh); #else struct stat sb; - if (stat(filename, &sb) == 0) { + if (stat(filename.c_str(), &sb) == 0) { fios->mtime = sb.st_mtime; #endif } else { @@ -334,13 +335,13 @@ bool FiosFileScanner::AddFile(const char *filename, size_t basepath_length, cons } fios->type = type; - strecpy(fios->name, filename, lastof(fios->name)); + strecpy(fios->name, filename.c_str(), lastof(fios->name)); /* If the file doesn't have a title, use its filename */ const char *t = fios_title; if (StrEmpty(fios_title)) { - t = strrchr(filename, PATHSEPCHAR); - t = (t == nullptr) ? filename : (t + 1); + auto ps = filename.rfind(PATHSEPCHAR); + t = filename.c_str() + (ps == std::string::npos ? 0 : ps + 1); } strecpy(fios->title, t, lastof(fios->title)); str_validate(fios->title, lastof(fios->title)); @@ -433,11 +434,10 @@ static void FiosGetFileList(SaveLoadOperation fop, fios_getlist_callback_proc *c * @param last the last element in the title buffer * @param subdir the sub directory to search in */ -static void GetFileTitle(const char *file, char *title, const char *last, Subdirectory subdir) +static void GetFileTitle(const std::string &file, char *title, const char *last, Subdirectory subdir) { - char buf[MAX_PATH]; - strecpy(buf, file, lastof(buf)); - strecat(buf, ".title", lastof(buf)); + std::string buf = file; + buf += ".title"; FILE *f = FioFOpenFile(buf, "r", subdir); if (f == nullptr) return; @@ -460,7 +460,7 @@ static void GetFileTitle(const char *file, char *title, const char *last, Subdir * @see FiosGetFileList * @see FiosGetSavegameList */ -FiosType FiosGetSavegameListCallback(SaveLoadOperation fop, const char *file, const char *ext, char *title, const char *last) +FiosType FiosGetSavegameListCallback(SaveLoadOperation fop, const std::string &file, const char *ext, char *title, const char *last) { /* Show savegame files * .SAV OpenTTD saved game @@ -515,7 +515,7 @@ void FiosGetSavegameList(SaveLoadOperation fop, FileList &file_list) * @see FiosGetFileList * @see FiosGetScenarioList */ -static FiosType FiosGetScenarioListCallback(SaveLoadOperation fop, const char *file, const char *ext, char *title, const char *last) +static FiosType FiosGetScenarioListCallback(SaveLoadOperation fop, const std::string &file, const char *ext, char *title, const char *last) { /* Show scenario files * .SCN OpenTTD style scenario file @@ -556,7 +556,7 @@ void FiosGetScenarioList(SaveLoadOperation fop, FileList &file_list) FiosGetFileList(fop, &FiosGetScenarioListCallback, subdir, file_list); } -static FiosType FiosGetHeightmapListCallback(SaveLoadOperation fop, const char *file, const char *ext, char *title, const char *last) +static FiosType FiosGetHeightmapListCallback(SaveLoadOperation fop, const std::string &file, const char *ext, char *title, const char *last) { /* Show heightmap files * .PNG PNG Based heightmap files @@ -669,7 +669,7 @@ public: this->scanned = true; } - bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename) override + bool AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename) override { FILE *f = FioFOpenFile(filename, "r", SCENARIO_DIR); if (f == nullptr) return false; @@ -678,19 +678,16 @@ public: int fret = fscanf(f, "%u", &id.scenid); FioFCloseFile(f); if (fret != 1) return false; - strecpy(id.filename, filename, lastof(id.filename)); + strecpy(id.filename, filename.c_str(), lastof(id.filename)); Md5 checksum; uint8 buffer[1024]; - char basename[MAX_PATH]; ///< \a filename without the extension. size_t len, size; /* open the scenario file, but first get the name. * This is safe as we check on extension which * must always exist. */ - strecpy(basename, filename, lastof(basename)); - *strrchr(basename, '.') = '\0'; - f = FioFOpenFile(basename, "rb", SCENARIO_DIR, &size); + f = FioFOpenFile(filename.substr(0, filename.rfind('.')), "rb", SCENARIO_DIR, &size); if (f == nullptr) return false; /* calculate md5sum */ diff --git a/src/fios.h b/src/fios.h index e211396c1f..8d8faac07b 100644 --- a/src/fios.h +++ b/src/fios.h @@ -223,6 +223,6 @@ bool FiosDelete(const char *name); std::string FiosMakeHeightmapName(const char *name); std::string FiosMakeSavegameName(const char *name); -FiosType FiosGetSavegameListCallback(SaveLoadOperation fop, const char *file, const char *ext, char *title, const char *last); +FiosType FiosGetSavegameListCallback(SaveLoadOperation fop, const std::string &file, const char *ext, char *title, const char *last); #endif /* FIOS_H */ diff --git a/src/game/game_text.cpp b/src/game/game_text.cpp index f704dbc2eb..24f41c93ac 100644 --- a/src/game/game_text.cpp +++ b/src/game/game_text.cpp @@ -206,7 +206,7 @@ public: this->FileScanner::Scan(".txt", directory, false); } - bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename) override + bool AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename) override { if (exclude == filename) return true; @@ -244,9 +244,9 @@ GameStrings *LoadTranslations() LanguageScanner scanner(gs, filename); std::string ldir = basename + "lang" PATHSEP; - const char *tar_filename = info->GetTarFile(); + const std::string tar_filename = info->GetTarFile(); TarList::iterator iter; - if (tar_filename != nullptr && (iter = _tar_list[GAME_DIR].find(tar_filename)) != _tar_list[GAME_DIR].end()) { + if (!tar_filename.empty() && (iter = _tar_list[GAME_DIR].find(tar_filename)) != _tar_list[GAME_DIR].end()) { /* The main script is in a tar file, so find all files that * are in the same tar and add them to the langfile scanner. */ TarFileList::iterator tar; @@ -258,7 +258,7 @@ GameStrings *LoadTranslations() 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); + scanner.AddFile(tar->first, 0, tar_filename); } } else { /* Scan filesystem */ diff --git a/src/newgrf_config.cpp b/src/newgrf_config.cpp index 75c1977f2c..5ba54f26cf 100644 --- a/src/newgrf_config.cpp +++ b/src/newgrf_config.cpp @@ -586,7 +586,7 @@ public: { } - bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename) override; + bool AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename) override; /** Do the scan for GRFs. */ static uint DoScan() @@ -600,9 +600,9 @@ public: } }; -bool GRFFileScanner::AddFile(const char *filename, size_t basepath_length, const char *tar_filename) +bool GRFFileScanner::AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename) { - GRFConfig *c = new GRFConfig(filename + basepath_length); + GRFConfig *c = new GRFConfig(filename.c_str() + basepath_length); bool added = true; if (FillGRFDetails(c, false)) { diff --git a/src/openttd.cpp b/src/openttd.cpp index aa98da7260..6315b8fa15 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -628,7 +628,7 @@ int openttd_main(int argc, char *argv[]) /* if the file doesn't exist or it is not a valid savegame, let the saveload code show an error */ auto t = _file_to_saveload.name.find_last_of('.'); if (t != std::string::npos) { - FiosType ft = FiosGetSavegameListCallback(SLO_LOAD, _file_to_saveload.name.c_str(), _file_to_saveload.name.substr(t).c_str(), nullptr, nullptr); + FiosType ft = FiosGetSavegameListCallback(SLO_LOAD, _file_to_saveload.name, _file_to_saveload.name.substr(t).c_str(), nullptr, nullptr); if (ft != FIOS_TYPE_INVALID) _file_to_saveload.SetMode(ft); } diff --git a/src/saveload/oldloader.cpp b/src/saveload/oldloader.cpp index 09f15e183f..42970c9a2f 100644 --- a/src/saveload/oldloader.cpp +++ b/src/saveload/oldloader.cpp @@ -317,7 +317,7 @@ bool LoadOldSaveGame(const std::string &file) return true; } -void GetOldSaveGameName(const char *file, char *title, const char *last) +void GetOldSaveGameName(const std::string &file, char *title, const char *last) { FILE *f = FioFOpenFile(file, "rb", NO_DIRECTORY); diff --git a/src/script/script_info.cpp b/src/script/script_info.cpp index 4eebd548d3..d02bbe324e 100644 --- a/src/script/script_info.cpp +++ b/src/script/script_info.cpp @@ -39,8 +39,6 @@ ScriptInfo::~ScriptInfo() free(this->date); free(this->instance_name); free(this->url); - free(this->main_script); - free(this->tar_file); free(this->SQ_instance); } @@ -81,9 +79,8 @@ bool ScriptInfo::CheckMethod(const char *name) const } /* Get location information of the scanner */ - info->main_script = stredup(info->scanner->GetMainScript()); - const char *tar_name = info->scanner->GetTarFile(); - if (tar_name != nullptr) info->tar_file = stredup(tar_name); + info->main_script = info->scanner->GetMainScript(); + info->tar_file = info->scanner->GetTarFile(); /* Cache the data the info file gives us. */ if (!info->engine->CallStringMethodStrdup(*info->SQ_instance, "GetAuthor", &info->author, MAX_GET_OPS)) return SQ_ERROR; diff --git a/src/script/script_info.hpp b/src/script/script_info.hpp index 5f90e9b23f..c2e952b821 100644 --- a/src/script/script_info.hpp +++ b/src/script/script_info.hpp @@ -32,8 +32,6 @@ public: ScriptInfo() : engine(nullptr), SQ_instance(nullptr), - main_script(nullptr), - tar_file(nullptr), author(nullptr), name(nullptr), short_name(nullptr), @@ -89,12 +87,12 @@ public: /** * Get the filename of the main.nut script. */ - const char *GetMainScript() const { return this->main_script; } + const char *GetMainScript() const { return this->main_script.c_str(); } /** * Get the filename of the tar the script is in. */ - const char *GetTarFile() const { return this->tar_file; } + std::string GetTarFile() const { return this->tar_file; } /** * Check if a given method exists. @@ -152,8 +150,8 @@ protected: ScriptConfigItemList config_list; ///< List of settings from this Script. private: - char *main_script; ///< The full path of the script. - char *tar_file; ///< If, which tar file the script was in. + std::string main_script; ///< The full path of the script. + std::string tar_file; ///< If, which tar file the script was in. const char *author; ///< Author of the script. const char *name; ///< Full name of the script. const char *short_name; ///< Short name (4 chars) which uniquely identifies the script. diff --git a/src/script/script_scanner.cpp b/src/script/script_scanner.cpp index dc3feb58c7..6fa88bfee5 100644 --- a/src/script/script_scanner.cpp +++ b/src/script/script_scanner.cpp @@ -23,47 +23,29 @@ #include "../safeguards.h" -bool ScriptScanner::AddFile(const char *filename, size_t basepath_length, const char *tar_filename) +bool ScriptScanner::AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename) { - free(this->main_script); - this->main_script = stredup(filename); - if (this->main_script == nullptr) return false; - - free(this->tar_file); - if (tar_filename != nullptr) { - this->tar_file = stredup(tar_filename); - if (this->tar_file == nullptr) return false; - } else { - this->tar_file = nullptr; - } - - const char *end = this->main_script + strlen(this->main_script) + 1; - char *p = strrchr(this->main_script, PATHSEPCHAR); - if (p == nullptr) { - p = this->main_script; - } else { - /* Skip over the path separator character. We don't need that. */ - p++; - } + this->main_script = filename; + this->tar_file = tar_filename; - strecpy(p, "main.nut", end); + auto p = this->main_script.rfind(PATHSEPCHAR); + this->main_script.erase(p != std::string::npos ? p + 1 : 0); + this->main_script += "main.nut"; if (!FioCheckFileExists(filename, this->subdir) || !FioCheckFileExists(this->main_script, this->subdir)) return false; this->ResetEngine(); try { - this->engine->LoadScript(filename); + this->engine->LoadScript(filename.c_str()); } catch (Script_FatalError &e) { - DEBUG(script, 0, "Fatal error '%s' when trying to load the script '%s'.", e.GetErrorMessage(), filename); + DEBUG(script, 0, "Fatal error '%s' when trying to load the script '%s'.", e.GetErrorMessage(), filename.c_str()); return false; } return true; } ScriptScanner::ScriptScanner() : - engine(nullptr), - main_script(nullptr), - tar_file(nullptr) + engine(nullptr) { } @@ -87,8 +69,6 @@ ScriptScanner::~ScriptScanner() { this->Reset(); - free(this->main_script); - free(this->tar_file); delete this->engine; } @@ -194,7 +174,7 @@ struct ScriptFileChecksumCreator : FileScanner { } /* Add the file and calculate the md5 sum. */ - virtual bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename) + virtual bool AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename) { Md5 checksum; uint8 buffer[1024]; @@ -202,7 +182,7 @@ struct ScriptFileChecksumCreator : FileScanner { byte tmp_md5sum[16]; /* Open the file ... */ - FILE *f = FioFOpenFile(filename, "rb", this->dir, &size); + FILE *f = FioFOpenFile(filename.c_str(), "rb", this->dir, &size); if (f == nullptr) return false; /* ... calculate md5sum... */ @@ -239,9 +219,9 @@ static bool IsSameScript(const ContentInfo *ci, bool md5sum, ScriptInfo *info, S if (!md5sum) return true; ScriptFileChecksumCreator checksum(dir); - const char *tar_filename = info->GetTarFile(); + auto tar_filename = info->GetTarFile(); TarList::iterator iter; - if (tar_filename != nullptr && (iter = _tar_list[dir].find(tar_filename)) != _tar_list[dir].end()) { + if (!tar_filename.empty() && (iter = _tar_list[dir].find(tar_filename)) != _tar_list[dir].end()) { /* The main script is in a tar file, so find all files that * are in the same tar and add them to the MD5 checksumming. */ TarFileList::iterator tar; @@ -253,7 +233,7 @@ static bool IsSameScript(const ContentInfo *ci, bool md5sum, ScriptInfo *info, S const char *ext = strrchr(tar->first.c_str(), '.'); if (ext == nullptr || strcasecmp(ext, ".nut") != 0) continue; - checksum.AddFile(tar->first.c_str(), 0, tar_filename); + checksum.AddFile(tar->first, 0, tar_filename); } } else { char path[MAX_PATH]; diff --git a/src/script/script_scanner.hpp b/src/script/script_scanner.hpp index eb65a197e4..ca9068ca10 100644 --- a/src/script/script_scanner.hpp +++ b/src/script/script_scanner.hpp @@ -32,12 +32,12 @@ public: /** * Get the current main script the ScanDir is currently tracking. */ - const char *GetMainScript() { return this->main_script; } + std::string GetMainScript() { return this->main_script; } /** * Get the current tar file the ScanDir is currently tracking. */ - const char *GetTarFile() { return this->tar_file; } + std::string GetTarFile() { return this->tar_file; } /** * Get the list of all registered scripts. @@ -75,7 +75,7 @@ public: */ const char *FindMainScript(const ContentInfo *ci, bool md5sum); - bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename) override; + bool AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename) override; /** * Rescan the script dir. @@ -83,9 +83,9 @@ public: void RescanDir(); protected: - class Squirrel *engine; ///< The engine we're scanning with. - char *main_script; ///< The full path of the script. - char *tar_file; ///< If, which tar file the script was in. + class Squirrel *engine; ///< The engine we're scanning with. + std::string main_script; ///< The full path of the script. + std::string tar_file; ///< If, which tar file the script was in. ScriptInfoList info_list; ///< The list of all script. ScriptInfoList info_single_list; ///< The list of all unique script. The best script (highest version) is shown. diff --git a/src/tar_type.h b/src/tar_type.h index e428bc2496..c4e72df851 100644 --- a/src/tar_type.h +++ b/src/tar_type.h @@ -12,30 +12,20 @@ #include #include +#include #include "fileio_type.h" -/** The define of a TarList. */ -struct TarListEntry { - const char *filename; - const char *dirname; - - /* MSVC goes copying around this struct after initialisation, so it tries - * to free filename, which isn't set at that moment... but because it - * initializes the variable with garbage, it's going to segfault. */ - TarListEntry() : filename(nullptr), dirname(nullptr) {} - ~TarListEntry() { free(this->filename); free(this->dirname); } -}; struct TarFileListEntry { - const char *tar_filename; + std::string tar_filename; size_t size; size_t position; }; -typedef std::map TarList; +typedef std::map TarList; ///< Map of tar file to tar directory. typedef std::map TarFileList; -extern TarList _tar_list[NUM_SUBDIRS]; +extern std::array _tar_list; extern TarFileList _tar_filelist[NUM_SUBDIRS]; #define FOR_ALL_TARS(tar, sd) for (tar = _tar_filelist[sd].begin(); tar != _tar_filelist[sd].end(); tar++) From dc5b8020ccd41053f440371ccaa290ca7a2632b9 Mon Sep 17 00:00:00 2001 From: SamuXarick <43006711+SamuXarick@users.noreply.github.com> Date: Sun, 27 Dec 2020 14:05:47 +0000 Subject: [PATCH 28/64] Fix #6452: Reset only editable and visible settings from GUI (#7890) Also enables the Reset button while in-game for AI configs. --- src/ai/ai_gui.cpp | 8 ++------ src/script/script_config.cpp | 20 ++++++++++++++++++++ src/script/script_config.hpp | 5 +++++ 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/ai/ai_gui.cpp b/src/ai/ai_gui.cpp index f1ee03fc17..9e16ec3ec1 100644 --- a/src/ai/ai_gui.cpp +++ b/src/ai/ai_gui.cpp @@ -315,8 +315,6 @@ struct AISettingsWindow : public Window { this->vscroll = this->GetScrollbar(WID_AIS_SCROLLBAR); this->FinishInitNested(slot); // Initializes 'this->line_height' as side effect. - this->SetWidgetDisabledState(WID_AIS_RESET, _game_mode != GM_MENU && Company::IsValidID(this->slot)); - this->RebuildVisibleSettings(); } @@ -524,10 +522,8 @@ struct AISettingsWindow : public Window { break; case WID_AIS_RESET: - if (_game_mode == GM_MENU || !Company::IsValidID(this->slot)) { - this->ai_config->ResetSettings(); - this->SetDirty(); - } + this->ai_config->ResetEditableSettings(_game_mode == GM_MENU || ((this->slot != OWNER_DEITY) && !Company::IsValidID(this->slot))); + this->SetDirty(); break; } } diff --git a/src/script/script_config.cpp b/src/script/script_config.cpp index 8de141e662..9bb953c4c1 100644 --- a/src/script/script_config.cpp +++ b/src/script/script_config.cpp @@ -127,6 +127,26 @@ void ScriptConfig::ResetSettings() this->settings.clear(); } +void ScriptConfig::ResetEditableSettings(bool yet_to_start) +{ + if (this->info == nullptr) return ResetSettings(); + + for (SettingValueList::iterator it = this->settings.begin(); it != this->settings.end();) { + const ScriptConfigItem *config_item = this->info->GetConfigItem(it->first); + assert(config_item != nullptr); + + bool editable = yet_to_start || (config_item->flags & SCRIPTCONFIG_INGAME) != 0; + bool visible = _settings_client.gui.ai_developer_tools || (config_item->flags & SCRIPTCONFIG_DEVELOPER) == 0; + + if (editable && visible) { + free(it->first); + it = this->settings.erase(it); + } else { + it++; + } + } +} + void ScriptConfig::AddRandomDeviation() { for (const auto &item : *this->GetConfigList()) { diff --git a/src/script/script_config.hpp b/src/script/script_config.hpp index 31004caba7..be231fcdc2 100644 --- a/src/script/script_config.hpp +++ b/src/script/script_config.hpp @@ -134,6 +134,11 @@ public: */ void ResetSettings(); + /** + * Reset only editable and visible settings to their default value. + */ + void ResetEditableSettings(bool yet_to_start); + /** * Randomize all settings the Script requested to be randomized. */ From 4f8e7b2a2b97475fa45a3117c63c91116a884703 Mon Sep 17 00:00:00 2001 From: Michael Lutz Date: Sun, 27 Dec 2020 15:07:06 +0100 Subject: [PATCH 29/64] Fix 65f65ad2: Missing path separator that fell over a cliff. --- src/fios.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fios.cpp b/src/fios.cpp index 698a0b5592..4586f86b33 100644 --- a/src/fios.cpp +++ b/src/fios.cpp @@ -219,7 +219,7 @@ static std::string FiosMakeFilename(const std::string *path, const char *name, c const char *period = strrchr(name, '.'); if (period != nullptr && strcasecmp(period, ext) == 0) ext = ""; - return buf + name + ext; + return buf + PATHSEP + name + ext; } /** From 1bb0e6ed8cfba61818343a36111af3902f7d7199 Mon Sep 17 00:00:00 2001 From: translators Date: Sun, 27 Dec 2020 18:18:16 +0000 Subject: [PATCH 30/64] Update: Translations from eints russian: 19 changes by lexuslatvia finnish: 1 change by hpiirai latvian: 19 changes by lexuslatvia --- src/lang/afrikaans.txt | 2 +- src/lang/arabic_egypt.txt | 2 +- src/lang/basque.txt | 2 +- src/lang/belarusian.txt | 2 +- src/lang/brazilian_portuguese.txt | 2 +- src/lang/bulgarian.txt | 2 +- src/lang/catalan.txt | 2 +- src/lang/croatian.txt | 2 +- src/lang/czech.txt | 2 +- src/lang/danish.txt | 2 +- src/lang/dutch.txt | 2 +- src/lang/english_AU.txt | 2 +- src/lang/english_US.txt | 2 +- src/lang/esperanto.txt | 2 +- src/lang/estonian.txt | 2 +- src/lang/faroese.txt | 2 +- src/lang/finnish.txt | 4 ++-- src/lang/french.txt | 2 +- src/lang/gaelic.txt | 2 +- src/lang/galician.txt | 2 +- src/lang/german.txt | 2 +- src/lang/greek.txt | 2 +- src/lang/hebrew.txt | 2 +- src/lang/hungarian.txt | 2 +- src/lang/icelandic.txt | 2 +- src/lang/indonesian.txt | 2 +- src/lang/irish.txt | 2 +- src/lang/italian.txt | 2 +- src/lang/japanese.txt | 2 +- src/lang/korean.txt | 2 +- src/lang/latin.txt | 2 +- src/lang/latvian.txt | 21 ++++++++++++++++++++- src/lang/lithuanian.txt | 2 +- src/lang/luxembourgish.txt | 2 +- src/lang/malay.txt | 2 +- src/lang/norwegian_bokmal.txt | 2 +- src/lang/norwegian_nynorsk.txt | 2 +- src/lang/polish.txt | 2 +- src/lang/portuguese.txt | 2 +- src/lang/romanian.txt | 2 +- src/lang/russian.txt | 21 ++++++++++++++++++++- src/lang/serbian.txt | 2 +- src/lang/simplified_chinese.txt | 2 +- src/lang/slovak.txt | 2 +- src/lang/slovenian.txt | 2 +- src/lang/spanish.txt | 2 +- src/lang/spanish_MX.txt | 2 +- src/lang/swedish.txt | 2 +- src/lang/tamil.txt | 2 +- src/lang/thai.txt | 2 +- src/lang/traditional_chinese.txt | 2 +- src/lang/turkish.txt | 2 +- src/lang/ukrainian.txt | 2 +- src/lang/unfinished/chuvash.txt | 2 +- src/lang/unfinished/frisian.txt | 2 +- src/lang/unfinished/ido.txt | 2 +- src/lang/unfinished/macedonian.txt | 2 +- src/lang/unfinished/maltese.txt | 2 +- src/lang/unfinished/marathi.txt | 2 +- src/lang/unfinished/persian.txt | 2 +- src/lang/unfinished/urdu.txt | 2 +- src/lang/vietnamese.txt | 2 +- src/lang/welsh.txt | 2 +- 63 files changed, 102 insertions(+), 64 deletions(-) diff --git a/src/lang/afrikaans.txt b/src/lang/afrikaans.txt index 27c04099c3..a9c4fa4ce9 100644 --- a/src/lang/afrikaans.txt +++ b/src/lang/afrikaans.txt @@ -2507,7 +2507,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Grootte: STR_OBJECT_CLASS_LTHS :Vuurtorings STR_OBJECT_CLASS_TRNS :Stuurders -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Boome STR_PLANT_TREE_TOOLTIP :{BLACK}Kies tipe boom om te plant. Indien die teel reeds 'n boom op het sal enige tipe bome by geplant word, ongeag van die gekose tipe STR_TREES_RANDOM_TYPE :{BLACK}Bome van lukraake tipe diff --git a/src/lang/arabic_egypt.txt b/src/lang/arabic_egypt.txt index 7f342e7b3c..994889e0c2 100644 --- a/src/lang/arabic_egypt.txt +++ b/src/lang/arabic_egypt.txt @@ -2103,7 +2103,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}حجم: STR_OBJECT_CLASS_LTHS :مناراة ضوئية STR_OBJECT_CLASS_TRNS :النواقل -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}اشجار STR_PLANT_TREE_TOOLTIP :{BLACK} اختر نوع الشجر لزراعتة, اذا المربع يحتوي على اشجار فهذا الامر يضيف المزيد STR_TREES_RANDOM_TYPE :{BLACK}شجر عشوائي diff --git a/src/lang/basque.txt b/src/lang/basque.txt index 9e63803637..b797613a96 100644 --- a/src/lang/basque.txt +++ b/src/lang/basque.txt @@ -2365,7 +2365,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Tamainua STR_OBJECT_CLASS_LTHS :Itsasargiak STR_OBJECT_CLASS_TRNS :Igorgailuak -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Zuhaitzak STR_PLANT_TREE_TOOLTIP :{BLACK} Aukeratu landatuko diren zuhaitz motak. Laukiak zuhaitza badauka mota ezberdinetako zuhaitz gehio geituko ditu STR_TREES_RANDOM_TYPE :{BLACK}Ausazko zuhaitz motak diff --git a/src/lang/belarusian.txt b/src/lang/belarusian.txt index c297aefdf3..6f5bda851a 100644 --- a/src/lang/belarusian.txt +++ b/src/lang/belarusian.txt @@ -2833,7 +2833,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Паме STR_OBJECT_CLASS_LTHS :Маякi STR_OBJECT_CLASS_TRNS :Перадатчыкi -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Дрэвы STR_PLANT_TREE_TOOLTIP :{BLACK}Выберыце тып дрэваў для пасадкі. Калі на ўчастку ўжо ёсьць дрэвы, будуць дададзены некалькі дрэваў рознага тыпу, незалежна ад выбранага. STR_TREES_RANDOM_TYPE :{BLACK}Дрэвы розных відаў diff --git a/src/lang/brazilian_portuguese.txt b/src/lang/brazilian_portuguese.txt index 97a5f59fab..d75203968f 100644 --- a/src/lang/brazilian_portuguese.txt +++ b/src/lang/brazilian_portuguese.txt @@ -2517,7 +2517,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Tamanho: STR_OBJECT_CLASS_LTHS :Faróis STR_OBJECT_CLASS_TRNS :Transmissores -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Árvores STR_PLANT_TREE_TOOLTIP :{BLACK}Selecionar um tipo de árvore para plantar. Se o local já tiver uma árvore, isso irá adicionar mais árvores do tipo misto indepentendemente do tipo selecionado STR_TREES_RANDOM_TYPE :{BLACK}Árvores de tipo aleatório diff --git a/src/lang/bulgarian.txt b/src/lang/bulgarian.txt index 99183c8498..752df0fb91 100644 --- a/src/lang/bulgarian.txt +++ b/src/lang/bulgarian.txt @@ -2419,7 +2419,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Разм STR_OBJECT_CLASS_LTHS :Фарове STR_OBJECT_CLASS_TRNS :Предаватели -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Дървета STR_PLANT_TREE_TOOLTIP :{BLACK}Избор на вид дърво за засаждане. Ако на полето вече съществува дърво, ще бъдат добавени повече дървета от различни видове, независимо от избора на вид STR_TREES_RANDOM_TYPE :{BLACK}Дървета от произволен тип diff --git a/src/lang/catalan.txt b/src/lang/catalan.txt index 872ed5974b..31d30d0c81 100644 --- a/src/lang/catalan.txt +++ b/src/lang/catalan.txt @@ -2525,7 +2525,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Mida: {G STR_OBJECT_CLASS_LTHS :Fars STR_OBJECT_CLASS_TRNS :Transmissors -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Arbres STR_PLANT_TREE_TOOLTIP :{BLACK}Selecciona el tipus d'arbre a plantar. Si la casella ja conté un arbre, s'afegiran més arbres d'altres espècies independentment de quin estigui seleccionat STR_TREES_RANDOM_TYPE :{BLACK}Arbres de tipus aleatori diff --git a/src/lang/croatian.txt b/src/lang/croatian.txt index 66b02221e2..40c5fd0aed 100644 --- a/src/lang/croatian.txt +++ b/src/lang/croatian.txt @@ -2612,7 +2612,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Veličin STR_OBJECT_CLASS_LTHS :Svjetionici STR_OBJECT_CLASS_TRNS :Odašiljači -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Drveće STR_PLANT_TREE_TOOLTIP :{BLACK}Odaberi vrstu drveta za sadnju. Ako polje već ima drvo, ovo će dodati još drveća raznih vrsta neovisno o odabranoj vrsti STR_TREES_RANDOM_TYPE :{BLACK}Raznovrsno drveće diff --git a/src/lang/czech.txt b/src/lang/czech.txt index 41b3020ade..0e753b1801 100644 --- a/src/lang/czech.txt +++ b/src/lang/czech.txt @@ -2603,7 +2603,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Velikost STR_OBJECT_CLASS_LTHS :Majáky STR_OBJECT_CLASS_TRNS :Vysílače -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Stromy STR_PLANT_TREE_TOOLTIP :{BLACK}Zvol druh stromu na vysazení. Pokud se na políčku už nějaký strom nachází, přidá se k němu několik různých druhů bez ohledu na výběr druhu STR_TREES_RANDOM_TYPE :{BLACK}Různé stromy diff --git a/src/lang/danish.txt b/src/lang/danish.txt index 892782abcd..f6507f02bb 100644 --- a/src/lang/danish.txt +++ b/src/lang/danish.txt @@ -2516,7 +2516,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Størrel STR_OBJECT_CLASS_LTHS :Fyrtårn STR_OBJECT_CLASS_TRNS :Sendere -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Træer STR_PLANT_TREE_TOOLTIP :{BLACK}Vælg typen af træer der skal plantes. Hvis feltet allerede har et træ, vil dette tilføje flere træer i blandede typer, uafhængigt af den valgte type STR_TREES_RANDOM_TYPE :{BLACK}Træer af tilfældig type diff --git a/src/lang/dutch.txt b/src/lang/dutch.txt index 1ff98d11da..d911f68383 100644 --- a/src/lang/dutch.txt +++ b/src/lang/dutch.txt @@ -2516,7 +2516,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Grootte: STR_OBJECT_CLASS_LTHS :Vuurtorens STR_OBJECT_CLASS_TRNS :Zendmasten -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Bomen STR_PLANT_TREE_TOOLTIP :{BLACK}Kies een soort boom om te planten. Als de tegel al bomen bevat, komen er meer bomen van verschillende typen bij, onafhankelijk van het geselecteerde type. STR_TREES_RANDOM_TYPE :{BLACK}Willekeurige soorten bomen diff --git a/src/lang/english_AU.txt b/src/lang/english_AU.txt index 44efedb7f7..e1fab3f29e 100644 --- a/src/lang/english_AU.txt +++ b/src/lang/english_AU.txt @@ -2428,7 +2428,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Size: {G STR_OBJECT_CLASS_LTHS :Lighthouses STR_OBJECT_CLASS_TRNS :Transmitters -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Trees STR_PLANT_TREE_TOOLTIP :{BLACK}Select tree type to plant. If the tile already has a tree, this will add more trees of mixed types independent of the selected type STR_TREES_RANDOM_TYPE :{BLACK}Trees of random type diff --git a/src/lang/english_US.txt b/src/lang/english_US.txt index 38d01204f4..013088aace 100644 --- a/src/lang/english_US.txt +++ b/src/lang/english_US.txt @@ -2512,7 +2512,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Size: {G STR_OBJECT_CLASS_LTHS :Lighthouses STR_OBJECT_CLASS_TRNS :Transmitters -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Trees STR_PLANT_TREE_TOOLTIP :{BLACK}Select tree type to plant. If the tile already has a tree, this will add more trees of mixed types independent of the selected type STR_TREES_RANDOM_TYPE :{BLACK}Trees of random type diff --git a/src/lang/esperanto.txt b/src/lang/esperanto.txt index 0adcf0b115..c68684eca6 100644 --- a/src/lang/esperanto.txt +++ b/src/lang/esperanto.txt @@ -2061,7 +2061,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Grandeco STR_OBJECT_CLASS_LTHS :Lumturoj STR_OBJECT_CLASS_TRNS :Transigantoj -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Arboj STR_PLANT_TREE_TOOLTIP :{BLACK}Elektu arbo-tipon por planti. Kiam la regiono jam havas arbojn, aliaj arb-tipoj plantiĝos STR_TREES_RANDOM_TYPE :{BLACK}Arboj de hazardaj tipoj diff --git a/src/lang/estonian.txt b/src/lang/estonian.txt index 74b827f3f4..aa7277c7ba 100644 --- a/src/lang/estonian.txt +++ b/src/lang/estonian.txt @@ -2526,7 +2526,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Suurus: STR_OBJECT_CLASS_LTHS :Majakad STR_OBJECT_CLASS_TRNS :Saatejaamad -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Puud STR_PLANT_TREE_TOOLTIP :{BLACK}Vali istutatava puu liik. Kui ruudus juba on puu, siis lisatakse rohkem eri liikide puid, olenemata valikust STR_TREES_RANDOM_TYPE :{BLACK}Suvalised puutüübid diff --git a/src/lang/faroese.txt b/src/lang/faroese.txt index 0b2c1fa2b8..f439165102 100644 --- a/src/lang/faroese.txt +++ b/src/lang/faroese.txt @@ -2207,7 +2207,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Stødd: STR_OBJECT_CLASS_LTHS :Vitar STR_OBJECT_CLASS_TRNS :Sendarir -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Trø STR_TREES_RANDOM_TYPE :{BLACK}Tilvildarlig træ sløg STR_TREES_RANDOM_TREES_BUTTON :{BLACK}Tilvildarlig trø diff --git a/src/lang/finnish.txt b/src/lang/finnish.txt index 6a81b13454..64db506292 100644 --- a/src/lang/finnish.txt +++ b/src/lang/finnish.txt @@ -2542,7 +2542,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Koko: {G STR_OBJECT_CLASS_LTHS :Majakat STR_OBJECT_CLASS_TRNS :Lähettimet -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Puita STR_PLANT_TREE_TOOLTIP :{BLACK}Valitse istutettava puutyyppi. Jos ruudussa on jo puu, tämä lisää uusia puita riippumatta valitun puun tyypistä STR_TREES_RANDOM_TYPE :{BLACK}Sattumanvaraisia puita @@ -3255,7 +3255,7 @@ STR_STATION_VIEW_RATINGS_TOOLTIP :{BLACK}Näytä STR_STATION_VIEW_SUPPLY_RATINGS_TITLE :{BLACK}Kuukausittainen tarjonta ja paikallinen arvio: STR_STATION_VIEW_CARGO_SUPPLY_RATING :{WHITE}{STRING}: {YELLOW}{COMMA} / {STRING} ({COMMA}{NBSP}%) -STR_STATION_VIEW_GROUP :{BLACK}Järjestä +STR_STATION_VIEW_GROUP :{BLACK}Ryhmittele STR_STATION_VIEW_WAITING_STATION :Asema: Odottaa STR_STATION_VIEW_WAITING_AMOUNT :Määrä: Odottaa STR_STATION_VIEW_PLANNED_STATION :Asema: Suunniteltu diff --git a/src/lang/french.txt b/src/lang/french.txt index 6b08754c75..b239fda099 100644 --- a/src/lang/french.txt +++ b/src/lang/french.txt @@ -2525,7 +2525,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Taille{N STR_OBJECT_CLASS_LTHS :Phares STR_OBJECT_CLASS_TRNS :Transmetteurs -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Arbres STR_PLANT_TREE_TOOLTIP :{BLACK}Choix du type d'arbre. S'il y a déjà un arbre dans la case, plusieurs arbres de types différents y seront ajoutés, indépendamment du type sélectionné. STR_TREES_RANDOM_TYPE :{BLACK}Au hasard diff --git a/src/lang/gaelic.txt b/src/lang/gaelic.txt index 3db73e8bb0..8c80c59532 100644 --- a/src/lang/gaelic.txt +++ b/src/lang/gaelic.txt @@ -2686,7 +2686,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Meud: {G STR_OBJECT_CLASS_LTHS :Taighean-solais STR_OBJECT_CLASS_TRNS :Tùir chraobh-sgaoilidh -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Craobhan STR_PLANT_TREE_TOOLTIP :{BLACK}Tagh seòrsa na craoibhe airson cur. Ma tha craobh air an leac mu thràth, cuiridh seo barrachd chraobhan aig a bheil caochladh dhe sheòrsachan a tha neo-eisimeileach on t-seòrsa a thagh thu STR_TREES_RANDOM_TYPE :{BLACK}Craobhan dhe sheòrsa air thuaiream diff --git a/src/lang/galician.txt b/src/lang/galician.txt index 82c7be26a3..9f56b15eb0 100644 --- a/src/lang/galician.txt +++ b/src/lang/galician.txt @@ -2507,7 +2507,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Tamaño: STR_OBJECT_CLASS_LTHS :Faros STR_OBJECT_CLASS_TRNS :Transmisores -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Árbores STR_PLANT_TREE_TOOLTIP :{BLACK}Selecciona-lo tipo de árbore a plantar. Se xa hai unha árbore no cadro, isto engadirá máis árbores de varios tipos independentemente do tipo seleccionado STR_TREES_RANDOM_TYPE :{BLACK}Árbores de tipo aleatorio diff --git a/src/lang/german.txt b/src/lang/german.txt index d5fa23a4b7..e5c2d24c5c 100644 --- a/src/lang/german.txt +++ b/src/lang/german.txt @@ -2498,7 +2498,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Größe: STR_OBJECT_CLASS_LTHS :Leuchttürme STR_OBJECT_CLASS_TRNS :Sendemasten -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Bäume STR_PLANT_TREE_TOOLTIP :{BLACK}Wähle die zu pflanzende Baumart. Wenn auf dem Feld schon ein Baum steht, wird eine zufällige Baumart gepflanzt STR_TREES_RANDOM_TYPE :{BLACK}Zufällige Baumart diff --git a/src/lang/greek.txt b/src/lang/greek.txt index e60bdf374e..9ac448efc1 100644 --- a/src/lang/greek.txt +++ b/src/lang/greek.txt @@ -2596,7 +2596,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Μέγε STR_OBJECT_CLASS_LTHS :Φάροι STR_OBJECT_CLASS_TRNS :Αναμεταδότες -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Δέντρα STR_PLANT_TREE_TOOLTIP :{BLACK}Επιλέξτε τύπο δέντρου για φύτευση. Αν το τετραγωνίδιο έχει ήδη ένα δέντρο, αυτό θα προσθέσει περισσότερα δέντρα μεικτών τύπων ανεξάρτητα από τον επιλεγμένο τύπο STR_TREES_RANDOM_TYPE :{BLACK}Δέντρα τυχαίου τύπου diff --git a/src/lang/hebrew.txt b/src/lang/hebrew.txt index 2d59515113..4bffa240bc 100644 --- a/src/lang/hebrew.txt +++ b/src/lang/hebrew.txt @@ -2479,7 +2479,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}גודל STR_OBJECT_CLASS_LTHS :מגדלורים STR_OBJECT_CLASS_TRNS :אנטנות -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}עצים STR_PLANT_TREE_TOOLTIP :{BLACK}בחר סוג עץ לנטיעה. במידה ויש עץ במשבצת, יתווספו עצים נוספים מסוגים שונים ללא קשר לסוג הנבחר STR_TREES_RANDOM_TYPE :{BLACK}עצים מסוג אקראי diff --git a/src/lang/hungarian.txt b/src/lang/hungarian.txt index 1d543d19b6..c82cf92de3 100644 --- a/src/lang/hungarian.txt +++ b/src/lang/hungarian.txt @@ -2580,7 +2580,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Méret: STR_OBJECT_CLASS_LTHS :Világítótornyok STR_OBJECT_CLASS_TRNS :Adótornyok -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Fák STR_PLANT_TREE_TOOLTIP :{BLACK}Ültetendő fa kiválasztása. Ha már van fa a mezőn, akkor újabb fák ültetése a kiválasztott fatípustól függetlenül STR_TREES_RANDOM_TYPE :{BLACK}Véletlenszerű fafélék diff --git a/src/lang/icelandic.txt b/src/lang/icelandic.txt index 283221e8fb..2e7afccf83 100644 --- a/src/lang/icelandic.txt +++ b/src/lang/icelandic.txt @@ -2305,7 +2305,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Stærð: STR_OBJECT_CLASS_LTHS :Vitar STR_OBJECT_CLASS_TRNS :Sendar -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Tré STR_PLANT_TREE_TOOLTIP :{BLACK}Veldu trjátegund sem á að gróðursetja. Ef það er fyrir tré á reitnum, verðu fleiri trjám mismunandi trjám plantað óhað hvaða tegund hefur verið valin STR_TREES_RANDOM_TYPE :{BLACK}Tré af handahófskenndri gerð diff --git a/src/lang/indonesian.txt b/src/lang/indonesian.txt index dbf51e6df2..48ef414720 100644 --- a/src/lang/indonesian.txt +++ b/src/lang/indonesian.txt @@ -2516,7 +2516,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Ukuran: STR_OBJECT_CLASS_LTHS :Mercusuar STR_OBJECT_CLASS_TRNS :Pemancar -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Pepohonan STR_PLANT_TREE_TOOLTIP :{BLACK}Pilih jenis pohon untuk ditanam. Jika pohon sudah tertanam, ini akan menambah jenis pohon secara acak dari tipe yang sama. STR_TREES_RANDOM_TYPE :{BLACK}Tanam pohon secara acak diff --git a/src/lang/irish.txt b/src/lang/irish.txt index 63fbce5b6e..4af615635c 100644 --- a/src/lang/irish.txt +++ b/src/lang/irish.txt @@ -2453,7 +2453,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Méid: { STR_OBJECT_CLASS_LTHS :Tithe solais STR_OBJECT_CLASS_TRNS :Tarchuradóirí -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Crainnte STR_PLANT_TREE_TOOLTIP :{BLACK}Roghnaigh an cineál crainn le cur STR_TREES_RANDOM_TYPE :{BLACK}Crainnte randamacha diff --git a/src/lang/italian.txt b/src/lang/italian.txt index f25f4dc493..0f22a045ad 100644 --- a/src/lang/italian.txt +++ b/src/lang/italian.txt @@ -2546,7 +2546,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Dimensio STR_OBJECT_CLASS_LTHS :Fari STR_OBJECT_CLASS_TRNS :Trasmettitori -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Alberi STR_PLANT_TREE_TOOLTIP :{BLACK}Seleziona il tipo di albero da piantare. Se nel riquadro sono già presenti alberi, ne aggiunge altri di vari tipi, indipendentemente dal tipo selezionato STR_TREES_RANDOM_TYPE :{BLACK}Alberi casuali diff --git a/src/lang/japanese.txt b/src/lang/japanese.txt index d94701aa88..af48a6e6e2 100644 --- a/src/lang/japanese.txt +++ b/src/lang/japanese.txt @@ -2453,7 +2453,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}サイ STR_OBJECT_CLASS_LTHS :灯台 STR_OBJECT_CLASS_TRNS :電波塔 -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}植林 STR_PLANT_TREE_TOOLTIP :{BLACK}植林する樹類を選択します。既に木がある場合は追加で植林されます STR_TREES_RANDOM_TYPE :{BLACK}ランダムな樹類 diff --git a/src/lang/korean.txt b/src/lang/korean.txt index 0a8612ca07..238d344a34 100644 --- a/src/lang/korean.txt +++ b/src/lang/korean.txt @@ -2543,7 +2543,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}크기: STR_OBJECT_CLASS_LTHS :등대 STR_OBJECT_CLASS_TRNS :송신기 -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}나무 STR_PLANT_TREE_TOOLTIP :{BLACK}심고싶은 나무의 종류를 선택합니다. 이미 나무가 심어져있는 경우에는 선택한 나무의 크기를 키웁니다 STR_TREES_RANDOM_TYPE :{BLACK}여러 종류의 나무 같이 심기 diff --git a/src/lang/latin.txt b/src/lang/latin.txt index 98ebc4fc04..cec72a7fd1 100644 --- a/src/lang/latin.txt +++ b/src/lang/latin.txt @@ -2688,7 +2688,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Magnitud STR_OBJECT_CLASS_LTHS :Phari STR_OBJECT_CLASS_TRNS :Emissoria -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Arbores STR_PLANT_TREE_TOOLTIP :{BLACK}Eligere arborem serendam. Si tegula iam arborem habet, plures arbores fortuitas addentur (forsitan non idem typus arboris) STR_TREES_RANDOM_TYPE :{BLACK}Arbor fortuita diff --git a/src/lang/latvian.txt b/src/lang/latvian.txt index 175367f5a2..dac079fae8 100644 --- a/src/lang/latvian.txt +++ b/src/lang/latvian.txt @@ -317,8 +317,15 @@ STR_SORT_BY_CARGO_CAPACITY :kravnesības STR_SORT_BY_RANGE :apgabala STR_SORT_BY_POPULATION :iedzīvotāju skaita STR_SORT_BY_RATING :vērtējuma +STR_SORT_BY_NUM_VEHICLES :Autotransporta līdzekļu skaits +STR_SORT_BY_TOTAL_PROFIT_LAST_YEAR :Kopējā peļņa pagājušajā gadā +STR_SORT_BY_TOTAL_PROFIT_THIS_YEAR :Kopējā peļņa šogad +STR_SORT_BY_AVERAGE_PROFIT_LAST_YEAR :Vidējā peļņa iepriekšējā gadā +STR_SORT_BY_AVERAGE_PROFIT_THIS_YEAR :Vidējā peļņa šajā gadā # Group by options for vehicle list +STR_GROUP_BY_NONE :Nav +STR_GROUP_BY_SHARED_ORDERS :Koplietojamie rīkojumi # Tooltips for the main toolbar STR_TOOLBAR_TOOLTIP_PAUSE_GAME :{BLACK}Pauzēt spēli @@ -775,6 +782,7 @@ STR_SMALLMAP_TOOLTIP_ENABLE_ALL_CARGOS :{BLACK}Rādīt STR_STATUSBAR_TOOLTIP_SHOW_LAST_NEWS :{BLACK}Rādīt pēdējo ziņojumu vai avīzes rakstu STR_STATUSBAR_COMPANY_NAME :{SILVER}- - {COMPANY} - - STR_STATUSBAR_PAUSED :{YELLOW}* * PAUZE * * +STR_STATUSBAR_PAUSED_LINK_GRAPH :{ORANGE} * * PAUZE (gaida saites diagrammas atjaunināšanu) * * STR_STATUSBAR_AUTOSAVE :{RED}AUTOMĀTISKĀ SAGLABĀŠANA STR_STATUSBAR_SAVING_GAME :{RED}* * SPĒLE TIEK SAGLABĀTA * * @@ -1614,6 +1622,10 @@ STR_CONFIG_SETTING_TOWN_CARGOGENMODE_BITCOUNT :Lineārs STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT :Koku izvietojums spēlē: {STRING} STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_HELPTEXT :Vadīt nejaušu koku parādīšanos spēles laikā. Tas var ietekmēt no kokaudzēšanas atkarīgas ražotnes, piemēram kokzāģētavas +STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_NO_SPREAD :Augt, bet neizplatās {RED} (salauž kokzāģētavas) +STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_SPREAD_RAINFOREST :Aug, bet izplatās tikai lietus mežos +STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_SPREAD_ALL :Aug un izplatās visur +STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_NO_GROWTH_NO_SPREAD :Augt, bet neizplatās {RED} (salauž kokzāģētavas) STR_CONFIG_SETTING_TOOLBAR_POS :Galvenās rīkjoslas novietojums: {STRING} STR_CONFIG_SETTING_TOOLBAR_POS_HELPTEXT :Galvenās rīkjoslas horizontālais novietojums ekrāna augšējā daļā @@ -1979,6 +1991,10 @@ STR_NETWORK_SERVER_LIST_JOIN_GAME :{BLACK}Pievieno STR_NETWORK_SERVER_LIST_REFRESH :{BLACK}Atsvaidzināt serveri STR_NETWORK_SERVER_LIST_REFRESH_TOOLTIP :{BLACK}Atsvaidzināt servera informāciju +STR_NETWORK_SERVER_LIST_SEARCH_SERVER_INTERNET :Meklēt internetā +STR_NETWORK_SERVER_LIST_SEARCH_SERVER_INTERNET_TOOLTIP :{BLACK}Meklēt publiskos serverus internetā +STR_NETWORK_SERVER_LIST_SEARCH_SERVER_LAN :{BLACK}Meklēt LAN +STR_NETWORK_SERVER_LIST_SEARCH_SERVER_LAN_TOOLTIP :{BLACK}Meklēt serverus lokālajā tīklā STR_NETWORK_SERVER_LIST_ADD_SERVER :{BLACK}Pievienot serveri STR_NETWORK_SERVER_LIST_ADD_SERVER_TOOLTIP :{BLACK}Pievienot serveri sarakstam, kurš vienmēr tiks pārbaudīts vai tajā nav palaistas spēles STR_NETWORK_SERVER_LIST_START_SERVER :{BLACK}Palaist serveri @@ -2207,11 +2223,13 @@ STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_1 :Spēle joprojā STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_2 :Spēle joprojām pauzēta ({STRING}, {STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_3 :Spēle joprojām pauzēta ({STRING}, {STRING}, {STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_4 :Spēle vēl aizvien ir pauzēta ({STRING}, {STRING}, {STRING}, {STRING}) +STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_5 :Spēle joprojām pauzēta ({STRING}, {STRING}, {STRING}, {STRING}, {STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_UNPAUSED :Spēle atsākta ({STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_REASON_NOT_ENOUGH_PLAYERS :spēlētāju skaits STR_NETWORK_SERVER_MESSAGE_GAME_REASON_CONNECTING_CLIENTS :savieno spēlētājus STR_NETWORK_SERVER_MESSAGE_GAME_REASON_MANUAL :manuālā STR_NETWORK_SERVER_MESSAGE_GAME_REASON_GAME_SCRIPT :spēles skripts +STR_NETWORK_SERVER_MESSAGE_GAME_REASON_LINK_GRAPH :gaida uz saišu grafika atjaunošanu ############ End of leave-in-this-order STR_NETWORK_MESSAGE_CLIENT_LEAVING :aizeju STR_NETWORK_MESSAGE_CLIENT_JOINED :*** {STRING} ir pievienojies spēlei @@ -2528,7 +2546,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Izmērs: STR_OBJECT_CLASS_LTHS :Bākas STR_OBJECT_CLASS_TRNS :Raidītāji -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Koki STR_PLANT_TREE_TOOLTIP :{BLACK}Izvēlēties koka veidu stādīšanai. Ja lauciņš jau ir koks, tas pievienos vairāk jauktu veidu kokus neatkarīgi no izvēlētā veida STR_TREES_RANDOM_TYPE :{BLACK}Nejauši izvēlēta veida koki @@ -4251,6 +4269,7 @@ STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME :Spēle ir sagla STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE :Failu nevar nolasīt STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE :Failā nevar ierakstīt STR_GAME_SAVELOAD_ERROR_DATA_INTEGRITY_CHECK_FAILED :Datu integritātes pārbaude neizdevās +STR_GAME_SAVELOAD_ERROR_PATCHPACK :Saglabāšana notiek ar modificētu versiju STR_GAME_SAVELOAD_NOT_AVAILABLE :