#include "term/term-color-types.h"
#include "time.h"
#include "util/angband-files.h"
+#include "util/string-processor.h"
#include "world/world.h"
+#include <vector>
#include <chrono>
/*!
/*!
* @brief 各データファイルを読み取るためのパスを取得する.
* @param libpath 各PCのインストール環境における"lib/" を表す絶対パス
+ * @param varpath Is the base path for directories that have files which
+ * are not read-only: ANGBAND_DIR_APEX, ANGBAND_DIR_BONE, ANGBAND_DIR_DATA,
+ * and ANGBAND_DIR_SAVE. If the PRIVATE_USER_PATH preprocessor macro has
+ * not been set, it is also used as the base path for ANGBAND_DIR_USER.
*/
-void init_file_paths(const std::filesystem::path &libpath)
+void init_file_paths(const std::filesystem::path &libpath, const std::filesystem::path &varpath)
{
ANGBAND_DIR = std::filesystem::path(libpath);
- ANGBAND_DIR_APEX = std::filesystem::path(libpath).append("apex");
- ANGBAND_DIR_BONE = std::filesystem::path(libpath).append("bone");
- ANGBAND_DIR_DATA = std::filesystem::path(libpath).append("data");
+ ANGBAND_DIR_APEX = std::filesystem::path(varpath).append("apex");
+ ANGBAND_DIR_BONE = std::filesystem::path(varpath).append("bone");
+ ANGBAND_DIR_DATA = std::filesystem::path(varpath).append("data");
ANGBAND_DIR_EDIT = std::filesystem::path(libpath).append("edit");
ANGBAND_DIR_SCRIPT = std::filesystem::path(libpath).append("script");
ANGBAND_DIR_FILE = std::filesystem::path(libpath).append("file");
ANGBAND_DIR_HELP = std::filesystem::path(libpath).append("help");
ANGBAND_DIR_INFO = std::filesystem::path(libpath).append("info");
ANGBAND_DIR_PREF = std::filesystem::path(libpath).append("pref");
- ANGBAND_DIR_SAVE = std::filesystem::path(libpath).append("save");
+ ANGBAND_DIR_SAVE = std::filesystem::path(varpath).append("save");
ANGBAND_DIR_DEBUG_SAVE = std::filesystem::path(ANGBAND_DIR_SAVE).append("log");
#ifdef PRIVATE_USER_PATH
- ANGBAND_DIR_USER = std::filesystem::path(PRIVATE_USER_PATH).append(VARIANT_NAME);
+ ANGBAND_DIR_USER = path_parse(PRIVATE_USER_PATH).append(VARIANT_NAME);
#else
- ANGBAND_DIR_USER = std::filesystem::path(libpath).append("user");
+ ANGBAND_DIR_USER = std::filesystem::path(varpath).append("user");
#endif
ANGBAND_DIR_XTRA = std::filesystem::path(libpath).append("xtra");
remove_old_debug_savefiles();
}
+/*
+ * Helper function for create_needed_dirs(). Copied over from PosChengband.
+ */
+static bool dir_exists(const std::filesystem::path path)
+{
+ struct stat buf;
+ if (stat(path.native().data(), &buf) != 0)
+ return false;
+#ifdef WIN32
+ else if (buf.st_mode & S_IFDIR)
+#else
+ else if (S_ISDIR(buf.st_mode))
+#endif
+ return true;
+ else
+ return false;
+}
+
+
+/*
+ * Helper function for create_needed_dirs(). Copied over from PosChengband
+ * but use the global definition for the path separator rather than a local
+ * one in PosChengband's code and check for paths that end with the path
+ * separator.
+ */
+static bool dir_create(const std::filesystem::path path)
+{
+#ifdef WIN32
+ /* If the directory already exists then we're done */
+ if (dir_exists(path)) return true;
+ return false;
+#else
+ std::vector<std::filesystem::path> missing;
+ std::filesystem::path next_path = path;
+
+ while (1) {
+ if (dir_exists(next_path)) {
+ break;
+ }
+ missing.push_back(next_path);
+ if (!next_path.has_relative_path()) {
+ break;
+ }
+ next_path = next_path.parent_path();
+ }
+ for (; !missing.empty(); missing.pop_back()) {
+ if (mkdir(missing.back().native().data(), 0755) != 0) {
+ return false;
+ }
+ }
+ return true;
+#endif
+}
+
+
+/*
+ * Create any missing directories. We create only those dirs which may be
+ * empty (user/, save/, apex/, bone/, data/). Only user/ is created when
+ * the PRIVATE_USER_PATH preprocessor maccro has been set. The others are
+ * assumed to contain required files and therefore must exist at startup
+ * (edit/, pref/, file/, xtra/).
+ *
+ * ToDo: Only create the directories when actually writing files.
+ * Copied over from PosChengband to support main-cocoa.m. Dropped
+ * creation of help/ (and removed it and info/ in the comment)
+ * since init_file_paths() puts those in libpath which may not be writable
+ * by the user running the application. Added bone/ since
+ * init_file_paths() puts that in varpath.
+ */
+void create_needed_dirs(void)
+{
+ if (!dir_create(ANGBAND_DIR_USER)) quit_fmt("Cannot create '%s'", ANGBAND_DIR_USER.native().data());
+#ifndef PRIVATE_USER_PATH
+ if (!dir_create(ANGBAND_DIR_SAVE)) quit_fmt("Cannot create '%s'", ANGBAND_DIR_SAVE.native().data());
+ if (!dir_create(ANGBAND_DIR_DEBUG_SAVE)) quit_fmt("Cannot create '%s'", ANGBAND_DIR_DEBUG_SAVE.native().data());
+ if (!dir_create(ANGBAND_DIR_APEX)) quit_fmt("Cannot create '%s'", ANGBAND_DIR_APEX.native().data());
+ if (!dir_create(ANGBAND_DIR_BONE)) quit_fmt("Cannot create '%s'", ANGBAND_DIR_BONE.native().data());
+ if (!dir_create(ANGBAND_DIR_DATA)) quit_fmt("Cannot create '%s'", ANGBAND_DIR_DATA.native().data());
+#endif /* ndef PRIVATE_USER_PATH */
+}
+
/*!
* @brief 画面左下にシステムメッセージを表示する / Take notes on line 23
* @param str 初期化中のコンテンツ文字列