2 * @brief ファイル入出力管理 / Purpose: code dealing with files (and death)
6 * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke
7 * This software may be copied and distributed for educational, research,
8 * and not for profit purposes provided that this copyright and statement
9 * are included in all such copies. Other copyrights may also apply.
10 * 2014 Deskull rearranged comment for Doxygen.\n
14 #include "io/files-util.h"
15 #include "core/asking-player.h"
16 #include "io-dump/character-dump.h"
17 #include "io/input-key-acceptor.h"
18 #include "io/uid-checker.h"
19 #include "monster-race/monster-race.h"
20 #include "monster-race/race-flags1.h"
21 #include "system/angband-exceptions.h"
22 #include "system/monster-race-info.h"
23 #include "system/player-type-definition.h"
24 #include "term/screen-processor.h"
25 #include "term/z-form.h"
26 #include "util/angband-files.h"
27 #include "view/display-messages.h"
29 #ifdef SAVEFILE_USE_UID
30 #include "main-unix/unix-user-ids.h"
33 std::filesystem::path ANGBAND_DIR; //!< Path name: The main "lib" directory This variable is not actually used anywhere in the code
34 std::filesystem::path ANGBAND_DIR_APEX; //!< High score files (binary) These files may be portable between platforms
35 std::filesystem::path ANGBAND_DIR_BONE; //!< Bone files for player ghosts (ascii) These files are portable between platforms
36 std::filesystem::path ANGBAND_DIR_DATA; //!< Binary image files for the "*_info" arrays (binary) These files are not portable between platforms
37 std::filesystem::path ANGBAND_DIR_EDIT; //!< Textual template files for the "*_info" arrays (ascii) These files are portable between platforms
38 std::filesystem::path ANGBAND_DIR_SCRIPT; //!< Script files These files are portable between platforms.
39 std::filesystem::path ANGBAND_DIR_FILE; //!< Various extra files (ascii) These files may be portable between platforms
40 std::filesystem::path ANGBAND_DIR_HELP; //!< Help files (normal) for the online help (ascii) These files are portable between platforms
41 std::filesystem::path ANGBAND_DIR_INFO; //!< Help files (spoilers) for the online help (ascii) These files are portable between platforms
42 std::filesystem::path ANGBAND_DIR_PREF; //!< Default user "preference" files (ascii) These files are rarely portable between platforms
43 std::filesystem::path ANGBAND_DIR_SAVE; //!< Savefiles for current characters (binary)
44 std::filesystem::path ANGBAND_DIR_DEBUG_SAVE; //*< Savefiles for debug data
45 std::filesystem::path ANGBAND_DIR_USER; //!< User "preference" files (ascii) These files are rarely portable between platforms
46 std::filesystem::path ANGBAND_DIR_XTRA; //!< Various extra files (binary) These files are rarely portable between platforms
48 std::filesystem::path savefile;
49 std::string savefile_base;
50 std::filesystem::path debug_savefile;
53 * @brief プレイヤーステータスをファイルダンプ出力する
54 * Hack -- Dump a character description file
55 * @param player_ptr プレイヤーへの参照ポインタ
59 * Allow the "full" flag to dump additional info,
60 * and trigger its usage from various places in the code.
62 void file_character(PlayerType *player_ptr, std::string_view filename)
64 const auto &path = path_build(ANGBAND_DIR_USER, filename);
65 auto fd = fd_open(path, O_RDONLY);
67 const auto &path_str = path.string();
69 ss << _("現存するファイル ", "Replace existing file ") << path_str << _(" に上書きしますか? ", "? ");
71 if (input_check_strict(player_ptr, ss.str(), UserCheck::NO_HISTORY)) {
80 fff = angband_fopen(path, FileOpenMode::WRITE);
84 THROW_EXCEPTION(std::runtime_error, _("キャラクタ情報のファイルへの書き出しに失敗しました!", "Character dump failed!"));
88 make_character_dump(player_ptr, fff);
92 msg_print(_("キャラクタ情報のファイルへの書き出しに成功しました。", "Character dump successful."));
97 * @brief ファイルからランダムに行を一つ取得する
98 * @param file_name ファイル名
99 * @param entry 特定条件時のN:タグヘッダID
100 * @return ファイルから取得した行 (但しファイルがなかったり異常値ならばnullopt)
102 std::optional<std::string> get_random_line(concptr file_name, int entry)
104 const auto &path = path_build(ANGBAND_DIR_FILE, file_name);
105 auto *fp = angband_fopen(path, FileOpenMode::READ);
114 if (angband_fgets(fp, buf, sizeof(buf)) != 0) {
120 if ((buf[0] != 'N') || (buf[1] != ':')) {
129 if (monraces_info[i2enum<MonsterRaceId>(entry)].flags1 & RF1_MALE) {
132 } else if (buf[2] == 'F') {
133 if (monraces_info[i2enum<MonsterRaceId>(entry)].flags1 & RF1_FEMALE) {
136 } else if (sscanf(&(buf[2]), "%d", &test) != EOF) {
141 msg_format("Error in line %d of %s!", line_num, file_name);
148 std::optional<std::string> line{};
152 if (angband_fgets(fp, buf, sizeof(buf))) {
156 if ((buf[0] == 'N') && (buf[1] == ':')) {
169 if (one_in_(counter + 1)) {
182 * @brief ファイルからランダムに行を一つ取得する(日本語文字列のみ)
183 * @param file_name ファイル名
184 * @param entry 特定条件時のN:タグヘッダID
186 * @return ファイルから取得した行 (但しファイルがなかったり異常値ならばnullopt)
189 std::optional<std::string> get_random_line_ja_only(concptr file_name, int entry, int count)
191 std::optional<std::string> line;
192 for (auto i = 0; i < count; i++) {
193 line = get_random_line(file_name, entry);
194 if (!line.has_value()) {
198 auto is_kanji = false;
199 for (const auto c : line.value()) {
200 is_kanji |= iskanji(c);
213 * @brief ファイル位置をシーク /
214 * @param player_ptr プレイヤーへの参照ポインタ
215 * @param fd ファイルディスクリプタ
216 * @param where ファイルバイト位置
217 * @param flag FALSEならば現ファイルを超えた位置へシーク時エラー、TRUEなら足りない間を0で埋め尽くす
221 static errr counts_seek(PlayerType *player_ptr, int fd, uint32_t where, bool flag)
223 char temp1[128]{}, temp2[128]{};
224 auto short_pclass = enum2i(player_ptr->pclass);
225 #ifdef SAVEFILE_USE_UID
226 const auto user_id = UnixUserIds::get_instance().get_user_id();
227 strnfmt(temp1, sizeof(temp1), "%d.%s.%d%d%d", user_id, savefile_base.data(), short_pclass, player_ptr->ppersonality, player_ptr->age);
229 strnfmt(temp1, sizeof(temp1), "%s.%d%d%d", savefile_base.data(), short_pclass, player_ptr->ppersonality, player_ptr->age);
231 for (int i = 0; temp1[i]; i++) {
232 temp1[i] ^= (i + 1) * 63;
236 uint32_t zero_header[3] = { 0L, 0L, 0L };
238 if (fd_seek(fd, seekpoint + 3 * sizeof(uint32_t))) {
241 if (fd_read(fd, (char *)(temp2), sizeof(temp2))) {
246 fd_seek(fd, seekpoint);
247 fd_write(fd, (char *)zero_header, 3 * sizeof(uint32_t));
248 fd_write(fd, (char *)(temp1), sizeof(temp1));
252 if (strcmp(temp1, temp2) == 0) {
256 seekpoint += 128 + 3 * sizeof(uint32_t);
259 return fd_seek(fd, seekpoint + where * sizeof(uint32_t));
264 * @param player_ptr プレイヤーへの参照ポインタ
265 * @param where ファイルバイト位置
269 uint32_t counts_read(PlayerType *player_ptr, int where)
271 const auto &path = path_build(ANGBAND_DIR_DATA, _("z_info_j.raw", "z_info.raw"));
272 auto fd = fd_open(path, O_RDONLY);
274 if (counts_seek(player_ptr, fd, where, false) || fd_read(fd, (char *)(&count), sizeof(uint32_t))) {
283 * @brief ファイル位置に書き込む /
284 * @param player_ptr プレイヤーへの参照ポインタ
285 * @param where ファイルバイト位置
290 errr counts_write(PlayerType *player_ptr, int where, uint32_t count)
292 const auto &path = path_build(ANGBAND_DIR_DATA, _("z_info_j.raw", "z_info.raw"));
294 auto fd = fd_open(path, O_RDWR);
303 auto err = fd_lock(fd, F_WRLCK);
309 counts_seek(player_ptr, fd, where, true);
310 fd_write(fd, (char *)(&count), sizeof(uint32_t));
312 err = fd_lock(fd, F_UNLCK);
324 * @brief 墓のアスキーアートテンプレを読み込んで画面に表示する
326 void read_dead_file()
328 const auto &path = path_build(ANGBAND_DIR_FILE, _("dead_j.txt", "dead.txt"));
329 auto *fp = angband_fopen(path, FileOpenMode::READ);
336 while (angband_fgets(fp, buf, sizeof(buf)) == 0) {
337 put_str(buf, i++, 0);