# HG changeset patch
# User Mike Miller <mtmiller@octave.org>
# Date 1551912878 28800
#      Wed Mar 06 14:54:38 2019 -0800
# Node ID 7c88b9053616c3e1d8e68a55be81ee07c094c5f3
# Parent  156bd21bf6bdd059e21c516afc0d655ab94633c8
[WIP] read startup files from XDG_CONFIG_HOME or LOCALAPPDATA (bug #36477)

diff --git a/libinterp/corefcn/interpreter.cc b/libinterp/corefcn/interpreter.cc
--- a/libinterp/corefcn/interpreter.cc
+++ b/libinterp/corefcn/interpreter.cc
@@ -30,6 +30,7 @@ along with Octave; see the file COPYING.
 #include "cmd-edit.h"
 #include "cmd-hist.h"
 #include "file-stat.h"
+#include "file-ops.h"
 #include "fpucw-wrappers.h"
 #include "lo-blas-proto.h"
 #include "lo-error.h"
@@ -792,6 +793,29 @@ namespace octave
         // anywhere in the load path when exiting Octave.
         add_atexit_function ("__finish__");
 
+        // Try to execute commands from $CONFIG/octave/octaverc, where
+        // $CONFIG is the platform-dependent location for user local
+        // configuration files.
+
+        std::string user_config_dir = sys::env::get_user_config_directory ();
+
+        std::string cfg_dir = user_config_dir + sys::file_ops::dir_sep_str ()
+                            + "octave";
+
+        std::string cfg_rc = sys::env::make_absolute ("octaverc", cfg_dir);
+
+        if (! cfg_rc.empty ())
+          {
+            // FIXME: delete this debug
+            std::cerr << "debug: load new startup file: " << cfg_rc << std::endl;
+
+            int status = safe_source_file (cfg_rc, context, verbose,
+                                           require_file);
+
+            if (status)
+              exit_status = status;
+          }
+
         // Try to execute commands from $HOME/$OCTAVE_INITFILE and
         // $OCTAVE_INITFILE.  If $OCTAVE_INITFILE is not set,
         // .octaverc is assumed.
diff --git a/liboctave/system/oct-env.cc b/liboctave/system/oct-env.cc
--- a/liboctave/system/oct-env.cc
+++ b/liboctave/system/oct-env.cc
@@ -55,8 +55,14 @@ Free Software Foundation, Inc.
 #include "oct-syscalls.h"
 #include "set-program-name-wrapper.h"
 #include "singleton-cleanup.h"
+#include "uniconv-wrappers.h"
 #include "unistd-wrappers.h"
 
+#if defined (OCTAVE_USE_WINDOWS_API)
+#  include <windows.h>
+#  include <shlobj.h>
+#endif
+
 namespace octave
 {
   namespace sys
@@ -148,6 +154,13 @@ namespace octave
     }
 
     std::string
+    env::get_user_config_directory ()
+    {
+      return (instance_ok ())
+        ? instance->do_get_user_config_directory () : "";
+    }
+
+    std::string
     env::get_program_name (void)
     {
       return (instance_ok ())
@@ -221,6 +234,32 @@ namespace octave
       return tempd;
     }
 
+    std::string
+    env::do_get_user_config_directory (void) const
+    {
+      std::string cfgd;
+
+#if defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) && defined (OCTAVE_USE_WINDOWS_API)
+      PWSTR path = nullptr;
+      if (SHGetKnownFolderPath (FOLDERID_LocalAppData, KF_FLAG_DONT_VERIFY,
+                                nullptr, &path) == S_OK)
+        {
+          char *local_app_data = u8_from_wchar (path);
+          cfgd = local_app_data;
+          free (local_app_data);
+          CoTaskMemFree (path);
+        }
+#else
+      cfgd = do_getenv ("XDG_CONFIG_HOME");
+
+      if (cfgd.empty ())
+        cfgd = do_get_home_directory () + sys::file_ops::dir_sep_str ()
+             + ".config";
+#endif
+
+      return cfgd;
+    }
+
     // FIXME: this leaves no way to distinguish between a
     // variable that is not set and one that is set to the empty string.
     // Is this a problem?
diff --git a/liboctave/system/oct-env.h b/liboctave/system/oct-env.h
--- a/liboctave/system/oct-env.h
+++ b/liboctave/system/oct-env.h
@@ -65,6 +65,8 @@ namespace octave
 
       static std::string get_temp_directory (void);
 
+      static std::string get_user_config_directory (void);
+
       static std::string get_program_name (void);
 
       static std::string get_program_invocation_name (void);
@@ -104,6 +106,8 @@ namespace octave
 
       std::string do_get_temp_directory (void) const;
 
+      std::string do_get_user_config_directory (void) const;
+
       std::string do_get_user_name (void) const;
 
       std::string do_get_host_name (void) const;
