From 24c672a56f43ecac981633c9d4d0511388e50320 Mon Sep 17 00:00:00 2001
From: Marko Lindqvist <cazfi74@gmail.com>
Date: Wed, 21 Oct 2026 19:25:00 +0300
Subject: [PATCH 88/88] fc_stat(): Support nullptr 'buf'

See RM #2340

Signed-off-by: Marko Lindqvist <cazfi74@gmail.com>
---
 client/options.c   |  5 ++---
 server/stdinhand.c |  5 ++---
 utility/registry.c |  4 +---
 utility/shared.c   |  4 +---
 utility/support.c  | 17 +++++++++++++++--
 5 files changed, 21 insertions(+), 14 deletions(-)

diff --git a/client/options.c b/client/options.c
index 3a82b1261b..6e394ba18e 100644
--- a/client/options.c
+++ b/client/options.c
@@ -5702,7 +5702,6 @@ static const char *get_last_option_file_name(bool *allow_digital_boolean)
     fc_strlcpy(name_buffer, OPTION_FILE_NAME, sizeof(name_buffer));
 #else
     int major, minor;
-    struct stat buf;
 
     name = freeciv_storage_dir();
     if (name == NULL) {
@@ -5719,7 +5718,7 @@ static const char *get_last_option_file_name(bool *allow_digital_boolean)
               : minor >= 0); minor--) {
         fc_snprintf(name_buffer, sizeof(name_buffer),
                     "%s" DIR_SEPARATOR NEW_OPTION_FILE_NAME, name, major, minor);
-        if (0 == fc_stat(name_buffer, &buf)) {
+        if (0 == fc_stat(name_buffer, nullptr)) {
           if (MAJOR_NEW_OPTION_FILE_NAME != major
               || MINOR_NEW_OPTION_FILE_NAME != minor) {
             log_normal(_("Didn't find '%s' option file, "
@@ -5751,7 +5750,7 @@ static const char *get_last_option_file_name(bool *allow_digital_boolean)
          minor--) {
       fc_snprintf(name_buffer, sizeof(name_buffer),
                   "%s" DIR_SEPARATOR MID_OPTION_FILE_NAME, name, major, minor);
-      if (0 == fc_stat(name_buffer, &buf)) {
+      if (0 == fc_stat(name_buffer, nullptr)) {
         log_normal(_("Didn't find '%s' option file, "
                      "loading from '%s' instead."),
                    get_current_option_file_name() + strlen(name) + 1,
diff --git a/server/stdinhand.c b/server/stdinhand.c
index 916a5d82b6..273151d3ed 100644
--- a/server/stdinhand.c
+++ b/server/stdinhand.c
@@ -5017,7 +5017,6 @@ static const char *lua_accessor(int i)
 static bool lua_command(struct connection *caller, char *arg, bool check,
                         int read_recursion)
 {
-  struct stat statbuf;
   const char extension[] = ".lua", *real_filename = nullptr;
   char luafile[4096], tilde_filename[4096];
   char *tokens[1], *luaarg = nullptr;
@@ -5150,7 +5149,7 @@ static bool lua_command(struct connection *caller, char *arg, bool check,
               _("Loading Freeciv script file '%s'."), real_filename);
 
     if (is_reg_file_for_access(real_filename, FALSE)
-        && !fc_stat(real_filename, &statbuf)) {
+        && !fc_stat(real_filename, nullptr)) {
       ret = script_server_do_file(caller, real_filename);
     } else {
       cmd_reply(CMD_LUA, caller, C_FAIL,
@@ -5163,7 +5162,7 @@ static bool lua_command(struct connection *caller, char *arg, bool check,
               _("Loading Freeciv script file '%s'."), real_filename);
 
     if (is_reg_file_for_access(real_filename, FALSE)
-        && !fc_stat(real_filename, &statbuf)) {
+        && !fc_stat(real_filename, nullptr)) {
       ret = script_server_unsafe_do_file(caller, real_filename);
     } else {
       cmd_reply(CMD_LUA, caller, C_FAIL,
diff --git a/utility/registry.c b/utility/registry.c
index 9012784e97..b1bd6fb723 100644
--- a/utility/registry.c
+++ b/utility/registry.c
@@ -52,9 +52,7 @@ struct section_file *secfile_load(const char *filename,
                                   bool allow_duplicates)
 {
 #ifdef FREECIV_HAVE_XML_REGISTRY
-  struct stat buf;
-
-  if (fc_stat(filename, &buf) == 0) {
+  if (fc_stat(filename, nullptr) == 0) {
     xmlDoc *sec_doc;
 
     sec_doc = xmlReadFile(filename, nullptr, XML_PARSE_NOERROR);
diff --git a/utility/shared.c b/utility/shared.c
index dad285573b..b6b30b45ab 100644
--- a/utility/shared.c
+++ b/utility/shared.c
@@ -1132,10 +1132,8 @@ const char *fileinfoname(const struct strvec *dirs, const char *filename)
 #endif /* DIR_SEPARATOR_IS_DEFAULT */
 
   strvec_iterate(dirs, dirname) {
-    struct stat buf;    /* See if we can open the file or directory */
-
     astr_set(&realfile, "%s" DIR_SEPARATOR "%s", dirname, fnbuf);
-    if (fc_stat(astr_str(&realfile), &buf) == 0) {
+    if (fc_stat(astr_str(&realfile), nullptr) == 0) {
       return astr_str(&realfile);
     }
   } strvec_iterate_end;
diff --git a/utility/support.c b/utility/support.c
index 779ed93c5a..8469f7ce39 100644
--- a/utility/support.c
+++ b/utility/support.c
@@ -535,19 +535,32 @@ int fc_remove(const char *filename)
 /************************************************************************//**
   Wrapper function for stat() with filename conversion to local
   encoding on Windows.
+
+  @param   filename Name of the file to check
+  @param   buf      Stat struct to fill. Can be nullptr
+  @return  0 on success, -1 on failure
 ****************************************************************************/
 int fc_stat(const char *filename, struct stat *buf)
 {
+  struct stat dummy;
+  struct stat *ptr;
+
+  if (buf != nullptr) {
+    ptr = buf;
+  } else {
+    ptr = &dummy;
+  }
+
 #ifdef FREECIV_MSWINDOWS
   int result;
   char *filename_in_local_encoding =
     internal_to_local_string_malloc(filename);
 
-  result = stat(filename_in_local_encoding, buf);
+  result = stat(filename_in_local_encoding, ptr);
   free(filename_in_local_encoding);
   return result;
 #else  /* FREECIV_MSWINDOWS */
-  return stat(filename, buf);
+  return stat(filename, ptr);
 #endif /* FREECIV_MSWINDOWS */
 }
 
-- 
2.53.0

