From 5886603a5a280fc77e688d17583e1d30c26c29ff Mon Sep 17 00:00:00 2001
From: Claude <noreply@anthropic.com>
Date: Tue, 26 May 2026 17:04:21 +0000
Subject: [PATCH] log: extract platform fatal-exit body to a sibling TU

First slice of the NETTOOL retirement.  log.cc had three NETTOOL
gates: the include block for env_t / display / messagebox / simwin;
the pakset() vfprintf body; and the platform-specific fatal-exit
tail (puts+exit for nettool, modal news + dr_fatal_notify for
simutrans).  All three collapse here: the in-source #ifndef NETTOOL
goes away, the display tail moves to log_fatal_display.cc (linked
into simutrans only), and nettool gets a tiny stub plus the two
env_t defaults it needs (verbose_debug, pakset_debug) from a new
nettool_compat.cc.

The -DNETTOOL=1 flag stays defined for now; the rest of the
codebase still uses it.  Subsequent slices retire it from network/
and the final cleanup drops the flag.
---
 Makefile                                 |  1 +
 Simutrans-Main.vcxitems                  |  1 +
 cmake/SimutransSourceList.cmake          |  1 +
 src/nettool/CMakeLists.txt               |  1 +
 src/nettool/Makefile                     |  1 +
 src/nettool/Nettool.vcxproj              |  1 +
 src/nettool/nettool_compat.cc            | 29 ++++++++++++
 src/simutrans/utils/log.cc               | 60 ++----------------------
 src/simutrans/utils/log.h                |  4 ++
 src/simutrans/utils/log_fatal_display.cc | 59 +++++++++++++++++++++++
 10 files changed, 103 insertions(+), 55 deletions(-)
 create mode 100644 src/nettool/nettool_compat.cc
 create mode 100644 src/simutrans/utils/log_fatal_display.cc

diff --git a/Makefile b/Makefile
index 3f5ea360b3..3d114bfa80 100644
--- a/Makefile
+++ b/Makefile
@@ -603,6 +603,7 @@ SOURCES += src/simutrans/utils/cbuffer.cc
 SOURCES += src/simutrans/utils/checklist.cc
 SOURCES += src/simutrans/utils/csv.cc
 SOURCES += src/simutrans/utils/log.cc
+SOURCES += src/simutrans/utils/log_fatal_display.cc
 SOURCES += src/simutrans/utils/searchfolder.cc
 SOURCES += src/simutrans/utils/sha1.cc
 SOURCES += src/simutrans/utils/sha1_hash.cc
diff --git a/Simutrans-Main.vcxitems b/Simutrans-Main.vcxitems
index 394b18fd3d..78c85514e2 100644
--- a/Simutrans-Main.vcxitems
+++ b/Simutrans-Main.vcxitems
@@ -324,6 +324,7 @@
     <ClCompile Include="$(MSBuildThisFileDirectory)src\simutrans\utils\checklist.cc" />
     <ClCompile Include="$(MSBuildThisFileDirectory)src\simutrans\utils\csv.cc" />
     <ClCompile Include="$(MSBuildThisFileDirectory)src\simutrans\utils\log.cc" />
+    <ClCompile Include="$(MSBuildThisFileDirectory)src\simutrans\utils\log_fatal_display.cc" />
     <ClCompile Include="$(MSBuildThisFileDirectory)src\simutrans\utils\searchfolder.cc" />
     <ClCompile Include="$(MSBuildThisFileDirectory)src\simutrans\utils\sha1.cc" />
     <ClCompile Include="$(MSBuildThisFileDirectory)src\simutrans\utils\sha1_hash.cc" />
diff --git a/cmake/SimutransSourceList.cmake b/cmake/SimutransSourceList.cmake
index ba78610c08..68960b3d5a 100644
--- a/cmake/SimutransSourceList.cmake
+++ b/cmake/SimutransSourceList.cmake
@@ -309,6 +309,7 @@ target_sources(simutrans PRIVATE
 		src/simutrans/utils/checklist.cc
 		src/simutrans/utils/csv.cc
 		src/simutrans/utils/log.cc
+		src/simutrans/utils/log_fatal_display.cc
 		src/simutrans/utils/searchfolder.cc
 		src/simutrans/utils/sha1.cc
 		src/simutrans/utils/sha1_hash.cc
diff --git a/src/nettool/CMakeLists.txt b/src/nettool/CMakeLists.txt
index 79a49e3176..6143f2dbbd 100644
--- a/src/nettool/CMakeLists.txt
+++ b/src/nettool/CMakeLists.txt
@@ -5,6 +5,7 @@
 
 add_executable(nettool
 	nettool.cc
+	nettool_compat.cc
 )
 
 target_compile_options(nettool PRIVATE ${SIMUTRANS_COMMON_COMPILE_OPTIONS})
diff --git a/src/nettool/Makefile b/src/nettool/Makefile
index 4ea444b242..57baa2bb3b 100644
--- a/src/nettool/Makefile
+++ b/src/nettool/Makefile
@@ -73,6 +73,7 @@ CXXFLAGS += -DREVISION -Wall -Wextra -Wcast-qual -Wpointer-arith -Wcast-align $(
 # VARIANT_SOURCES contains those which need different .o files for nettool and simutrans.
 # At the moment they're all treated identically, of course.
 SOLO_SOURCES += nettool.cc
+SOLO_SOURCES += nettool_compat.cc
 SHARED_SOURCES += ../simutrans/dataobj/freelist.cc
 SHARED_SOURCES += ../simutrans/network/memory_rw.cc
 SHARED_SOURCES += ../simutrans/network/network_address.cc
diff --git a/src/nettool/Nettool.vcxproj b/src/nettool/Nettool.vcxproj
index 68df6d8462..3f07d64792 100644
--- a/src/nettool/Nettool.vcxproj
+++ b/src/nettool/Nettool.vcxproj
@@ -80,6 +80,7 @@
   </ItemDefinitionGroup>
   <ItemGroup>
     <ClCompile Include="nettool.cc" />
+    <ClCompile Include="nettool_compat.cc" />
     <ClCompile Include="..\simdebug.cc" />
     <ClCompile Include="..\simmem.cc" />
     <ClCompile Include="..\dataobj\freelist.cc" />
diff --git a/src/nettool/nettool_compat.cc b/src/nettool/nettool_compat.cc
new file mode 100644
index 0000000000..143925fa5e
--- /dev/null
+++ b/src/nettool/nettool_compat.cc
@@ -0,0 +1,29 @@
+/*
+ * This file is part of the Simutrans project under the Artistic License.
+ * (see LICENSE.txt)
+ *
+ * nettool-side definitions of symbols the shared utils/ TUs reach
+ * into.  Game-side counterparts live in log_fatal_display.cc and
+ * (for env_t) the in-game `karte_t` initialisation; nettool gets
+ * minimal defaults here.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "../simutrans/dataobj/environment.h"
+#include "../simutrans/utils/log.h"
+
+
+log_t::level_t env_t::verbose_debug = log_t::LEVEL_FATAL;
+bool env_t::pakset_debug = false;
+
+
+FILE *dr_fopen(const char *filename, const char *mode) { return fopen(filename, mode); }
+
+
+void log_t_platform_fatal_exit(char *buffer)
+{
+	puts(buffer);
+	exit(1);
+}
diff --git a/src/simutrans/utils/log.cc b/src/simutrans/utils/log.cc
index abe852112d..7effaaf54d 100644
--- a/src/simutrans/utils/log.cc
+++ b/src/simutrans/utils/log.cc
@@ -18,21 +18,11 @@
 
 
 #ifdef MAKEOBJ
-//debuglevel is global variable
+// debuglevel is a global variable; no env_t.
 #  define dr_fopen fopen
 #else
-#  ifdef NETTOOL
-#    define debuglevel (0)
-#    define dr_fopen fopen
-#  else
-#    define debuglevel (env_t::verbose_debug)
-
-// for display
-#    include "../gui/messagebox.h"
-#    include "../display/simgraph.h"
-#    include "../gui/simwin.h"
-#    include "../dataobj/environment.h"
-#  endif
+#  define debuglevel (env_t::verbose_debug)
+#  include "../dataobj/environment.h"
 #endif
 
 #ifdef __ANDROID__
@@ -47,7 +37,7 @@
 void log_t::pakset(const char* who, const char* format, ...)
 {
 // never spam the Android buffer
-#if !defined(__ANDROID__) && !defined (MAKEOBJ) && !defined(NETTOOL)
+#if !defined(__ANDROID__) && !defined (MAKEOBJ)
 	if (env_t::pakset_debug) {
 		va_list argptr;
 		va_start(argptr, format);
@@ -347,48 +337,8 @@ void log_t::custom_fatal(char *buffer)
 
 #if defined MAKEOBJ
 	exit(EXIT_FAILURE);
-#elif defined NETTOOL
-	// no display available
-	puts( buffer );
-	exit(1);
 #else
-
-	env_t::verbose_debug = log_t::LEVEL_FATAL; // no more window concerning messages
-
-	if (gfx->is_display_init()) {
-		// show notification
-		destroy_all_win( true );
-
-		strcat( buffer, "PRESS ANY KEY\n" );
-		fatal_news* sel = new fatal_news(buffer);
-
-		const scr_size screen = gfx->get_screen_size();
-		scr_coord xy( screen.w/2 - sel->get_windowsize().w/2, screen.h/2 - sel->get_windowsize().h/2 );
-		event_t ev;
-
-		create_win( xy, sel, w_info, magic_none );
-
-		while(win_is_top(sel)) {
-			// do not move, do not close it!
-			dr_sleep(50);
-			dr_prepare_flush();
-			sel->draw( xy, sel->get_windowsize() );
-			dr_flush();
-			display_poll_event(&ev);
-			// main window resized
-			check_pos_win(&ev,true);
-
-			if (IS_KEYDOWN(&ev)) {
-				break;
-			}
-		}
-	}
-	else {
-		// use OS means, if there
-		dr_fatal_notify(buffer);
-	}
-
-	abort();
+	log_t_platform_fatal_exit(buffer);
 #endif
 }
 
diff --git a/src/simutrans/utils/log.h b/src/simutrans/utils/log.h
index 321d0056cd..7f006e916e 100644
--- a/src/simutrans/utils/log.h
+++ b/src/simutrans/utils/log.h
@@ -125,4 +125,8 @@ class log_t
 extern log_t::level_t debuglevel;
 #endif
 
+// Per-binary fatal sink invoked at the end of log_t::custom_fatal.
+// Must not return.
+void NORETURN log_t_platform_fatal_exit(char *buffer);
+
 #endif
diff --git a/src/simutrans/utils/log_fatal_display.cc b/src/simutrans/utils/log_fatal_display.cc
new file mode 100644
index 0000000000..dd7197add7
--- /dev/null
+++ b/src/simutrans/utils/log_fatal_display.cc
@@ -0,0 +1,59 @@
+/*
+ * This file is part of the Simutrans project under the Artistic License.
+ * (see LICENSE.txt)
+ *
+ * Game-side fatal-exit sink: pops a modal window if the display is up,
+ * else falls back to dr_fatal_notify, then abort()s.  Linked into
+ * simutrans only; nettool links its own puts+exit stub from
+ * nettool_compat.cc.
+ */
+
+#include <string.h>
+
+#include "log.h"
+#include "../dataobj/environment.h"
+#include "../display/simgraph.h"
+#include "../gui/messagebox.h"
+#include "../gui/simwin.h"
+#include "../sys/simsys.h"
+
+
+void log_t_platform_fatal_exit(char *buffer)
+{
+	env_t::verbose_debug = log_t::LEVEL_FATAL; // no more window concerning messages
+
+	if (gfx->is_display_init()) {
+		// show notification
+		destroy_all_win( true );
+
+		strcat( buffer, "PRESS ANY KEY\n" );
+		fatal_news* sel = new fatal_news(buffer);
+
+		const scr_size screen = gfx->get_screen_size();
+		scr_coord xy( screen.w/2 - sel->get_windowsize().w/2, screen.h/2 - sel->get_windowsize().h/2 );
+		event_t ev;
+
+		create_win( xy, sel, w_info, magic_none );
+
+		while(win_is_top(sel)) {
+			// do not move, do not close it!
+			dr_sleep(50);
+			dr_prepare_flush();
+			sel->draw( xy, sel->get_windowsize() );
+			dr_flush();
+			display_poll_event(&ev);
+			// main window resized
+			check_pos_win(&ev,true);
+
+			if (IS_KEYDOWN(&ev)) {
+				break;
+			}
+		}
+	}
+	else {
+		// use OS means, if there
+		dr_fatal_notify(buffer);
+	}
+
+	abort();
+}
