OSDN Git Service

[Refactor] #40392 Translated player_personality_type; for example SEIKAKU_KIREMONO...
[hengband/hengband.git] / src / io / files-util.c
1 /*!
2  * @brief ファイル入出力管理 / Purpose: code dealing with files (and death)
3  * @date 2014/01/28
4  * @author
5  * <pre>
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
11  * </pre>
12  */
13
14 #include "system/angband.h"
15 #include "io/uid-checker.h"
16 #include "io/files-util.h"
17 #include "system/system-variables.h" // 暫定。後で消す.
18 #include "io/character-dump.h"
19
20 concptr ANGBAND_DIR; //!< Path name: The main "lib" directory This variable is not actually used anywhere in the code
21 concptr ANGBAND_DIR_APEX; //!< High score files (binary) These files may be portable between platforms
22 concptr ANGBAND_DIR_BONE; //!< Bone files for player ghosts (ascii) These files are portable between platforms
23 concptr ANGBAND_DIR_DATA; //!< Binary image files for the "*_info" arrays (binary) These files are not portable between platforms
24 concptr ANGBAND_DIR_EDIT; //!< Textual template files for the "*_info" arrays (ascii) These files are portable between platforms
25 concptr ANGBAND_DIR_SCRIPT; //!< Script files These files are portable between platforms.
26 concptr ANGBAND_DIR_FILE; //!< Various extra files (ascii) These files may be portable between platforms
27 concptr ANGBAND_DIR_HELP; //!< Help files (normal) for the online help (ascii) These files are portable between platforms
28 concptr ANGBAND_DIR_INFO; //!< Help files (spoilers) for the online help (ascii) These files are portable between platforms
29 concptr ANGBAND_DIR_PREF; //!< Default user "preference" files (ascii) These files are rarely portable between platforms
30 concptr ANGBAND_DIR_SAVE; //!< Savefiles for current characters (binary)
31 concptr ANGBAND_DIR_USER; //!< User "preference" files (ascii) These files are rarely portable between platforms
32 concptr ANGBAND_DIR_XTRA; //!< Various extra files (binary) These files are rarely portable between platforms
33
34 /*
35  * Buffer to hold the current savefile name
36  * 'savefile' holds full path name. 'savefile_base' holds only base name.
37  */
38 char savefile[1024];
39 char savefile_base[40];
40
41 /*!
42  * todo サブルーチンとは言い難い。autopick.c から直接呼ばれている
43  * @brief process_pref_fileのサブルーチンとして条件分岐処理の解釈と結果を返す
44  * Helper function for "process_pref_file()"
45  * @param creature_ptr プレーヤーへの参照ポインタ
46  * @param sp テキスト文字列の参照ポインタ
47  * @param fp 再帰中のポインタ参照
48  * @return
49  * @details
50  * <pre>
51  * Input:
52  *   v: output buffer array
53  *   f: final character
54  * Output:
55  *   result
56  * </pre>
57  */
58 concptr process_pref_file_expr(player_type *creature_ptr, char **sp, char *fp)
59 {
60         char *s;
61         s = (*sp);
62         while (iswspace(*s)) s++;
63
64         char *b;
65         b = s;
66
67         concptr v = "?o?o?";
68
69         char b1 = '[';
70         char b2 = ']';
71         char f = ' ';
72         static char tmp[16];
73         if (*s == b1)
74         {
75                 concptr p;
76                 concptr t;
77
78                 /* Skip b1 */
79                 s++;
80
81                 /* First */
82                 t = process_pref_file_expr(creature_ptr, &s, &f);
83
84                 if (!*t)
85                 {
86                 }
87                 else if (streq(t, "IOR"))
88                 {
89                         v = "0";
90                         while (*s && (f != b2))
91                         {
92                                 t = process_pref_file_expr(creature_ptr, &s, &f);
93                                 if (*t && !streq(t, "0")) v = "1";
94                         }
95                 }
96                 else if (streq(t, "AND"))
97                 {
98                         v = "1";
99                         while (*s && (f != b2))
100                         {
101                                 t = process_pref_file_expr(creature_ptr, &s, &f);
102                                 if (*t && streq(t, "0")) v = "0";
103                         }
104                 }
105                 else if (streq(t, "NOT"))
106                 {
107                         v = "1";
108                         while (*s && (f != b2))
109                         {
110                                 t = process_pref_file_expr(creature_ptr, &s, &f);
111                                 if (*t && streq(t, "1")) v = "0";
112                         }
113                 }
114                 else if (streq(t, "EQU"))
115                 {
116                         v = "0";
117                         if (*s && (f != b2))
118                         {
119                                 t = process_pref_file_expr(creature_ptr, &s, &f);
120                         }
121                         while (*s && (f != b2))
122                         {
123                                 p = process_pref_file_expr(creature_ptr, &s, &f);
124                                 if (streq(t, p)) v = "1";
125                         }
126                 }
127                 else if (streq(t, "LEQ"))
128                 {
129                         v = "1";
130                         if (*s && (f != b2))
131                         {
132                                 t = process_pref_file_expr(creature_ptr, &s, &f);
133                         }
134                         while (*s && (f != b2))
135                         {
136                                 p = t;
137                                 t = process_pref_file_expr(creature_ptr, &s, &f);
138                                 if (*t && atoi(p) > atoi(t)) v = "0";
139                         }
140                 }
141                 else if (streq(t, "GEQ"))
142                 {
143                         v = "1";
144                         if (*s && (f != b2))
145                         {
146                                 t = process_pref_file_expr(creature_ptr, &s, &f);
147                         }
148                         while (*s && (f != b2))
149                         {
150                                 p = t;
151                                 t = process_pref_file_expr(creature_ptr, &s, &f);
152                                 if (*t && atoi(p) < atoi(t)) v = "0";
153                         }
154                 }
155                 else
156                 {
157                         while (*s && (f != b2))
158                         {
159                                 t = process_pref_file_expr(creature_ptr, &s, &f);
160                         }
161                 }
162
163                 if (f != b2) v = "?x?x?";
164
165                 if ((f = *s) != '\0') *s++ = '\0';
166
167                 *fp = f;
168                 *sp = s;
169                 return v;
170         }
171
172         /* Accept all printables except spaces and brackets */
173 #ifdef JP
174         while (iskanji(*s) || (isprint(*s) && !my_strchr(" []", *s)))
175         {
176                 if (iskanji(*s)) s++;
177                 s++;
178         }
179 #else
180         while (isprint(*s) && !my_strchr(" []", *s)) ++s;
181 #endif
182
183         if ((f = *s) != '\0') *s++ = '\0';
184
185         if (*b != '$')
186         {
187                 v = b;
188                 *fp = f;
189                 *sp = s;
190                 return v;
191         }
192
193         if (streq(b + 1, "SYS"))
194         {
195                 v = ANGBAND_SYS;
196         }
197         else if (streq(b + 1, "KEYBOARD"))
198         {
199                 v = ANGBAND_KEYBOARD;
200         }
201         else if (streq(b + 1, "GRAF"))
202         {
203                 v = ANGBAND_GRAF;
204         }
205         else if (streq(b + 1, "MONOCHROME"))
206         {
207                 if (arg_monochrome)
208                         v = "ON";
209                 else
210                         v = "OFF";
211         }
212         else if (streq(b + 1, "RACE"))
213         {
214 #ifdef JP
215                 v = rp_ptr->E_title;
216 #else
217                 v = rp_ptr->title;
218 #endif
219         }
220         else if (streq(b + 1, "CLASS"))
221         {
222 #ifdef JP
223                 v = cp_ptr->E_title;
224 #else
225                 v = cp_ptr->title;
226 #endif
227         }
228         else if (streq(b + 1, "PLAYER"))
229         {
230                 static char tmp_player_name[32];
231                 char *pn, *tpn;
232                 for (pn = creature_ptr->name, tpn = tmp_player_name; *pn; pn++, tpn++)
233                 {
234 #ifdef JP
235                         if (iskanji(*pn))
236                         {
237                                 *(tpn++) = *(pn++);
238                                 *tpn = *pn;
239                                 continue;
240                         }
241 #endif
242                         *tpn = my_strchr(" []", *pn) ? '_' : *pn;
243                 }
244
245                 *tpn = '\0';
246                 v = tmp_player_name;
247         }
248         else if (streq(b + 1, "REALM1"))
249         {
250 #ifdef JP
251                 v = E_realm_names[creature_ptr->realm1];
252 #else
253                 v = realm_names[creature_ptr->realm1];
254 #endif
255         }
256         else if (streq(b + 1, "REALM2"))
257         {
258 #ifdef JP
259                 v = E_realm_names[creature_ptr->realm2];
260 #else
261                 v = realm_names[creature_ptr->realm2];
262 #endif
263         }
264         else if (streq(b + 1, "LEVEL"))
265         {
266                 sprintf(tmp, "%02d", creature_ptr->lev);
267                 v = tmp;
268         }
269         else if (streq(b + 1, "AUTOREGISTER"))
270         {
271                 if (creature_ptr->autopick_autoregister)
272                         v = "1";
273                 else
274                         v = "0";
275         }
276         else if (streq(b + 1, "MONEY"))
277         {
278                 sprintf(tmp, "%09ld", (long int)creature_ptr->au);
279                 v = tmp;
280         }
281
282         *fp = f;
283         *sp = s;
284         return v;
285 }
286
287
288 /*!
289  * @brief プレイヤーステータスをファイルダンプ出力する
290  * Hack -- Dump a character description file
291  * @param creature_ptr プレーヤーへの参照ポインタ
292  * @param name 出力ファイル名
293  * @return エラーコード
294  * @details
295  * Allow the "full" flag to dump additional info,
296  * and trigger its usage from various places in the code.
297  */
298 errr file_character(player_type *creature_ptr, concptr name, update_playtime_pf update_playtime, display_player_pf display_player, map_name_pf map_name)
299 {
300         char buf[1024];
301         path_build(buf, sizeof(buf), ANGBAND_DIR_USER, name);
302
303         FILE_TYPE(FILE_TYPE_TEXT);
304
305         int     fd = fd_open(buf, O_RDONLY);
306         if (fd >= 0)
307         {
308                 char out_val[160];
309                 (void)fd_close(fd);
310                 (void)sprintf(out_val, _("現存するファイル %s に上書きしますか? ", "Replace existing file %s? "), buf);
311                 if (get_check_strict(out_val, CHECK_NO_HISTORY)) fd = -1;
312         }
313
314         FILE *fff = NULL;
315         if (fd < 0) fff = my_fopen(buf, "w");
316
317         if (!fff)
318         {
319                 prt(_("キャラクタ情報のファイルへの書き出しに失敗しました!", "Character dump failed!"), 0, 0);
320                 (void)inkey();
321                 return -1;
322         }
323
324         make_character_dump(creature_ptr, fff, update_playtime, display_player, map_name);
325         my_fclose(fff);
326         msg_print(_("キャラクタ情報のファイルへの書き出しに成功しました。", "Character dump successful."));
327         msg_print(NULL);
328         return 0;
329 }
330
331
332 /*!
333  * @brief ファイルからランダムに行を一つ取得する /
334  * Get a random line from a file
335  * @param file_name ファイル名
336  * @param entry 特定条件時のN:タグヘッダID
337  * @param output 出力先の文字列参照ポインタ
338  * @return エラーコード
339  * @details
340  * <pre>
341  * Based on the monster speech patch by Matt Graham,
342  * </pre>
343  */
344 errr get_rnd_line(concptr file_name, int entry, char *output)
345 {
346         char buf[1024];
347         path_build(buf, sizeof(buf), ANGBAND_DIR_FILE, file_name);
348         FILE *fp;
349         fp = my_fopen(buf, "r");
350         if (!fp) return -1;
351
352         int test;
353         int line_num = 0;
354         while (TRUE)
355         {
356                 if (my_fgets(fp, buf, sizeof(buf)) != 0)
357                 {
358                         my_fclose(fp);
359                         return -1;
360                 }
361
362                 line_num++;
363                 if ((buf[0] != 'N') || (buf[1] != ':')) continue;
364
365                 if (buf[2] == '*')
366                 {
367                         break;
368                 }
369                 else if (buf[2] == 'M')
370                 {
371                         if (r_info[entry].flags1 & RF1_MALE) break;
372                 }
373                 else if (buf[2] == 'F')
374                 {
375                         if (r_info[entry].flags1 & RF1_FEMALE) break;
376                 }
377                 else if (sscanf(&(buf[2]), "%d", &test) != EOF)
378                 {
379                         if (test == entry) break;
380                 }
381                 else
382                 {
383                         msg_format("Error in line %d of %s!", line_num, file_name);
384                         my_fclose(fp);
385                         return -1;
386                 }
387         }
388
389         int counter;
390         for (counter = 0; ; counter++)
391         {
392                 while (TRUE)
393                 {
394                         test = my_fgets(fp, buf, sizeof(buf));
395                         if (!test)
396                         {
397                                 /* Ignore lines starting with 'N:' */
398                                 if ((buf[0] == 'N') && (buf[1] == ':')) continue;
399
400                                 if (buf[0] != '#') break;
401                         }
402                         else break;
403                 }
404
405                 if (!buf[0]) break;
406
407                 if (one_in_(counter + 1)) strcpy(output, buf);
408         }
409
410         my_fclose(fp);
411         return counter ? 0 : -1;
412 }
413
414
415 #ifdef JP
416 /*!
417  * @brief ファイルからランダムに行を一つ取得する(日本語文字列のみ) /
418  * @param file_name ファイル名
419  * @param entry 特定条件時のN:タグヘッダID
420  * @param output 出力先の文字列参照ポインタ
421  * @param count 試行回数
422  * @return エラーコード
423  * @details
424  */
425 errr get_rnd_line_jonly(concptr file_name, int entry, char *output, int count)
426 {
427         errr result = 1;
428         for (int i = 0; i < count; i++)
429         {
430                 result = get_rnd_line(file_name, entry, output);
431                 if (result) break;
432                 bool kanji = FALSE;
433                 for (int j = 0; output[j]; j++) kanji |= iskanji(output[j]);
434                 if (kanji) break;
435         }
436
437         return result;
438 }
439 #endif
440
441
442 /*!
443  * @brief ファイル位置をシーク /
444  * @param creature_ptr プレーヤーへの参照ポインタ
445  * @param fd ファイルディスクリプタ
446  * @param where ファイルバイト位置
447  * @param flag FALSEならば現ファイルを超えた位置へシーク時エラー、TRUEなら足りない間を0で埋め尽くす
448  * @return エラーコード
449  * @details
450  */
451 static errr counts_seek(player_type *creature_ptr, int fd, u32b where, bool flag)
452 {
453         char temp1[128], temp2[128];
454 #ifdef SAVEFILE_USE_UID
455         (void)sprintf(temp1, "%d.%s.%d%d%d", creature_ptr->player_uid, savefile_base, creature_ptr->pclass, creature_ptr->pseikaku, creature_ptr->age);
456 #else
457         (void)sprintf(temp1, "%s.%d%d%d", savefile_base, creature_ptr->pclass, creature_ptr->pseikaku, creature_ptr->age);
458 #endif
459         for (int i = 0; temp1[i]; i++)
460                 temp1[i] ^= (i + 1) * 63;
461
462         int seekpoint = 0;
463         u32b zero_header[3] = { 0L, 0L, 0L };
464         while (TRUE)
465         {
466                 if (fd_seek(fd, seekpoint + 3 * sizeof(u32b)))
467                         return 1;
468                 if (fd_read(fd, (char*)(temp2), sizeof(temp2)))
469                 {
470                         if (!flag)
471                                 return 1;
472                         /* add new name */
473                         fd_seek(fd, seekpoint);
474                         fd_write(fd, (char*)zero_header, 3 * sizeof(u32b));
475                         fd_write(fd, (char*)(temp1), sizeof(temp1));
476                         break;
477                 }
478
479                 if (strcmp(temp1, temp2) == 0)
480                         break;
481
482                 seekpoint += 128 + 3 * sizeof(u32b);
483         }
484
485         return fd_seek(fd, seekpoint + where * sizeof(u32b));
486 }
487
488
489 /*!
490  * @brief ファイル位置を読み込む
491  * @param creature_ptr プレーヤーへの参照ポインタ
492  * @param where ファイルバイト位置
493  * @return エラーコード
494  * @details
495  */
496 u32b counts_read(player_type *creature_ptr, int where)
497 {
498         char buf[1024];
499         path_build(buf, sizeof(buf), ANGBAND_DIR_DATA, _("z_info_j.raw", "z_info.raw"));
500         int fd = fd_open(buf, O_RDONLY);
501
502         u32b count = 0;
503         if (counts_seek(creature_ptr, fd, where, FALSE) ||
504                 fd_read(fd, (char*)(&count), sizeof(u32b)))
505                 count = 0;
506
507         (void)fd_close(fd);
508
509         return count;
510 }
511
512
513 /*!
514  * @brief ファイル位置に書き込む /
515  * @param creature_ptr プレーヤーへの参照ポインタ
516  * @param where ファイルバイト位置
517  * @param count 書き込む値
518  * @return エラーコード
519  * @details
520  */
521 errr counts_write(player_type *creature_ptr, int where, u32b count)
522 {
523         char buf[1024];
524         path_build(buf, sizeof(buf), ANGBAND_DIR_DATA, _("z_info_j.raw", "z_info.raw"));
525
526         safe_setuid_grab();
527         int fd = fd_open(buf, O_RDWR);
528         safe_setuid_drop();
529         if (fd < 0)
530         {
531                 FILE_TYPE(FILE_TYPE_DATA);
532                 safe_setuid_grab();
533                 fd = fd_make(buf, 0644);
534                 safe_setuid_drop();
535         }
536
537         safe_setuid_grab();
538         errr err = fd_lock(fd, F_WRLCK);
539         safe_setuid_drop();
540         if (err) return 1;
541
542         counts_seek(creature_ptr, fd, where, TRUE);
543         fd_write(fd, (char*)(&count), sizeof(u32b));
544         safe_setuid_grab();
545         err = fd_lock(fd, F_UNLCK);
546         safe_setuid_drop();
547
548         if (err) return 1;
549
550         (void)fd_close(fd);
551         return 0;
552 }
553
554
555 /*!
556  * @brief 墓のアスキーアートテンプレを読み込む
557  * @param buf テンプレへのバッファ
558  * @param buf_size バッファの長さ
559  * @return なし
560  */
561 void read_dead_file(char *buf, size_t buf_size)
562 {
563         path_build(buf, buf_size, ANGBAND_DIR_FILE, _("dead_j.txt", "dead.txt"));
564
565         FILE *fp;
566         fp = my_fopen(buf, "r");
567         if (!fp) return;
568
569         int i = 0;
570         while (my_fgets(fp, buf, buf_size) == 0)
571         {
572                 put_str(buf, i++, 0);
573         }
574
575         my_fclose(fp);
576 }