# HG changeset patch
# User Markus Mützel <markus.muetzel@gmx.de>
# Date 1589295451 -7200
#      Tue May 12 16:57:31 2020 +0200
# Node ID 8cec0ef773b532435d4a131385f00191b44fb43b
# Parent  332e644726f9e78a256a9d826b9413c8e0368cd7
Move default history file location to inside XDG_CONFIG_HOME or APPDATA (bug #57463).

* oct-env.[cc,h] (get_user_config_directory, do_get_user_config_directory):
New functions.

* oct-hist.cc (history_system::default_file): Store history ata platform
dependent location by default.
(Fhistory_file): Document new default location for history file.

* NEWS: Announce change.

diff -r 332e644726f9 -r 8cec0ef773b5 NEWS
--- a/NEWS	Tue May 12 10:42:09 2020 +0200
+++ b/NEWS	Tue May 12 16:57:31 2020 +0200
@@ -35,6 +35,11 @@
     * `symlink`
     * `unlink`
 
+- By default, the history file is now located at $DATA/octave/history, where
+$DATA is a platform dependent location for (roaming) user data files (e.g.
+${XDG_DATA_HOME} or, if that is not set, ~/.local/share on Unix-like operating
+systems or %APPDATA% on Windows).
+
 ### Graphics backend
 
 - Support for Qt4 for graphics and the GUI has been removed.
diff -r 332e644726f9 -r 8cec0ef773b5 libinterp/corefcn/oct-hist.cc
--- a/libinterp/corefcn/oct-hist.cc	Tue May 12 10:42:09 2020 +0200
+++ b/libinterp/corefcn/oct-hist.cc	Tue May 12 16:57:31 2020 +0200
@@ -46,6 +46,7 @@
 
 #include "cmd-hist.h"
 #include "file-ops.h"
+#include "file-stat.h"
 #include "lo-mappers.h"
 #include "oct-env.h"
 #include "oct-time.h"
@@ -544,8 +545,24 @@
       file = env_file;
 
     if (file.empty ())
-      file = sys::file_ops::concat (sys::env::get_home_directory (),
-                                    ".octave_hist");
+      {
+        // Default to $DATA/octave/history, where $DATA is the platform-
+        // dependent location for (roaming) user data files.
+
+        std::string user_data_dir = sys::env::get_user_data_directory ();
+
+        std::string hist_dir = user_data_dir + sys::file_ops::dir_sep_str ()
+                               + "octave";
+
+        // Try to create the folder if it does not exist
+        sys::file_stat fs (hist_dir);
+        if (! fs.is_dir () && (sys::mkdir (hist_dir, 0777) < 0))
+          warning ("%s: Could not create directory \"%s\" for history",
+                   "history_system::default_file", hist_dir.c_str ());
+
+        file = sys::env::make_absolute ("history", hist_dir);
+      }
+
 
     return file;
   }
@@ -818,8 +835,11 @@
 All future commands issued during the current Octave session will be written to
 this new file (if the current setting of @code{history_save} allows for this).
 
-The default value is @file{~/.octave_hist}, but may be overridden by the
-environment variable @w{@env{OCTAVE_HISTFILE}}.
+The default value is @file{@w{@env{$DATA}}/octave/history}, where
+@w{@env{$DATA}} is the platform-specific location for (roaming) user data files
+(e.g. @w{@env{$XDG_DATA_HOME}} or, if that is not set, @file{~/.local/share} on
+Unix-like operating systems or @w{@env{%APPDATA%}} on Windows).  The default
+value may be overridden by the environment variable @w{@env{OCTAVE_HISTFILE}}.
 
 Programming Notes:
 
diff -r 332e644726f9 -r 8cec0ef773b5 liboctave/system/oct-env.cc
--- a/liboctave/system/oct-env.cc	Tue May 12 10:42:09 2020 +0200
+++ b/liboctave/system/oct-env.cc	Tue May 12 16:57:31 2020 +0200
@@ -165,6 +165,13 @@
     }
 
     std::string
+    env::get_user_data_directory ()
+    {
+      return (instance_ok ())
+        ? instance->do_get_user_data_directory () : "";
+    }
+
+    std::string
     env::get_program_name (void)
     {
       return (instance_ok ())
@@ -248,9 +255,9 @@
       if (SHGetFolderPathW (nullptr, CSIDL_APPDATA | CSIDL_FLAG_DONT_VERIFY,
                             nullptr, SHGFP_TYPE_CURRENT, path) == S_OK)
         {
-          char *local_app_data = u8_from_wchar (path);
-          cfg_dir = local_app_data;
-          free (local_app_data);
+          char *app_data = u8_from_wchar (path);
+          cfg_dir = app_data;
+          free (app_data);
         }
 #else
       cfg_dir = do_getenv ("XDG_CONFIG_HOME");
@@ -263,6 +270,32 @@
       return cfg_dir;
     }
 
+  std::string
+  env::do_get_user_data_directory (void) const
+  {
+      std::string hist_dir;
+
+#if defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) && defined (OCTAVE_USE_WINDOWS_API)
+      wchar_t path[MAX_PATH+1];
+      if (SHGetFolderPathW (nullptr, CSIDL_APPDATA | CSIDL_FLAG_DONT_VERIFY,
+                            nullptr, SHGFP_TYPE_CURRENT, path) == S_OK)
+        {
+          char *app_data = u8_from_wchar (path);
+          hist_dir = app_data;
+          free (app_data);
+        }
+#else
+      hist_dir = do_getenv ("XDG_DATA_HOME");
+
+      if (hist_dir.empty ())
+        hist_dir = do_get_home_directory () + sys::file_ops::dir_sep_str ()
+             + ".local" + sys::file_ops::dir_sep_str () + "share";
+#endif
+
+      return hist_dir;
+  }
+
+
     // 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 -r 332e644726f9 -r 8cec0ef773b5 liboctave/system/oct-env.h
--- a/liboctave/system/oct-env.h	Tue May 12 10:42:09 2020 +0200
+++ b/liboctave/system/oct-env.h	Tue May 12 16:57:31 2020 +0200
@@ -70,6 +70,8 @@
 
       static std::string get_user_config_directory (void);
 
+      static std::string get_user_data_directory (void);
+
       static std::string get_program_name (void);
 
       static std::string get_program_invocation_name (void);
@@ -111,6 +113,8 @@
 
       std::string do_get_user_config_directory (void) const;
 
+      std::string do_get_user_data_directory (void) const;
+
       std::string do_get_user_name (void) const;
 
       std::string do_get_host_name (void) const;
