OSDN Git Service

[Refactor] #39962 Separated tokenizer.c/h from files.c
[hengband/hengband.git] / src / files.c
1 /*!
2  * @file files.c
3  * @brief ファイル入出力管理 / Purpose: code dealing with files (and death)
4  * @date 2014/01/28
5  * @author
6  * <pre>
7  * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke
8  * This software may be copied and distributed for educational, research,
9  * and not for profit purposes provided that this copyright and statement
10  * are included in all such copies.  Other copyrights may also apply.
11  * 2014 Deskull rearranged comment for Doxygen.\n
12  * </pre>
13  */
14
15 #include "angband.h"
16 #include "term.h"
17 #include "signal-handlers.h"
18 #include "uid-checker.h"
19 #include "files.h"
20 #include "core.h" // リファクタリングして後で消す
21
22 #include "birth.h"
23 #include "character-dump.h"
24 #include "cmd-dump.h"
25 #include "world.h"
26 #include "player-move.h"
27 #include "player-personality.h"
28 #include "player-effects.h"
29 #include "monster-status.h"
30 #include "view-mainwindow.h"
31 #include "objectkind.h"
32 #include "autopick.h"
33 #include "save.h"
34 #include "io/gf-descriptions.h"
35 #include "io/tokenizer.h"
36
37 #define PREF_TYPE_NORMAL   0
38 #define PREF_TYPE_AUTOPICK 1
39 #define PREF_TYPE_HISTPREF 2
40
41 concptr ANGBAND_DIR; //!< Path name: The main "lib" directory This variable is not actually used anywhere in the code
42 concptr ANGBAND_DIR_APEX; //!< High score files (binary) These files may be portable between platforms
43 concptr ANGBAND_DIR_BONE; //!< Bone files for player ghosts (ascii) These files are portable between platforms
44 concptr ANGBAND_DIR_DATA; //!< Binary image files for the "*_info" arrays (binary) These files are not portable between platforms
45 concptr ANGBAND_DIR_EDIT; //!< Textual template files for the "*_info" arrays (ascii) These files are portable between platforms
46 concptr ANGBAND_DIR_SCRIPT; //!< Script files These files are portable between platforms.
47 concptr ANGBAND_DIR_FILE; //!< Various extra files (ascii) These files may be portable between platforms
48 concptr ANGBAND_DIR_HELP; //!< Help files (normal) for the online help (ascii) These files are portable between platforms
49 concptr ANGBAND_DIR_INFO; //!< Help files (spoilers) for the online help (ascii) These files are portable between platforms
50 concptr ANGBAND_DIR_PREF; //!< Default user "preference" files (ascii) These files are rarely portable between platforms
51 concptr ANGBAND_DIR_SAVE; //!< Savefiles for current characters (binary)
52 concptr ANGBAND_DIR_USER; //!< User "preference" files (ascii) These files are rarely portable between platforms
53 concptr ANGBAND_DIR_XTRA; //!< Various extra files (binary) These files are rarely portable between platforms
54
55 /*
56  * Buffer to hold the current savefile name
57  * 'savefile' holds full path name. 'savefile_base' holds only base name.
58  */
59 char savefile[1024];
60 char savefile_base[40];
61
62 /*!
63  * @brief 設定ファイルの各行から各種テキスト情報を取得する /
64  * Parse a sub-file of the "extra info" (format shown below)
65  * @param creature_ptr プレーヤーへの参照ポインタ
66  * @param buf データテキストの参照ポインタ
67  * @return エラーコード
68  * @details
69  * <pre>
70  * Each "action" line has an "action symbol" in the first column,
71  * followed by a colon, followed by some command specific info,
72  * usually in the form of "tokens" separated by colons or slashes.
73  * Blank lines, lines starting with white space, and lines starting
74  * with pound signs ("#") are ignored (as comments).
75  * Note the use of "tokenize()" to allow the use of both colons and
76  * slashes as delimeters, while still allowing final tokens which
77  * may contain any characters including "delimiters".
78  * Note the use of "strtol()" to allow all "integers" to be encoded
79  * in decimal, hexidecimal, or octal form.
80  * Note that "monster zero" is used for the "player" attr/char, "object
81  * zero" will be used for the "stack" attr/char, and "feature zero" is
82  * used for the "nothing" attr/char.
83  * Parse another file recursively, see below for details
84  *   %:\<filename\>
85  * Specify the attr/char values for "monsters" by race index
86  *   R:\<num\>:\<a\>:\<c\>
87  * Specify the attr/char values for "objects" by kind index
88  *   K:\<num\>:\<a\>:\<c\>
89  * Specify the attr/char values for "features" by feature index
90  *   F:\<num\>:\<a\>:\<c\>
91  * Specify the attr/char values for unaware "objects" by kind tval
92  *   U:\<tv\>:\<a\>:\<c\>
93  * Specify the attr/char values for inventory "objects" by kind tval
94  *   E:\<tv\>:\<a\>:\<c\>
95  * Define a macro action, given an encoded macro action
96  *   A:\<str\>
97  * Create a normal macro, given an encoded macro trigger
98  *   P:\<str\>
99  * Create a command macro, given an encoded macro trigger
100  *   C:\<str\>
101  * Create a keyset mapping
102  *   S:\<key\>:\<key\>:\<dir\>
103  * Turn an option off, given its name
104  *   X:\<str\>
105  * Turn an option on, given its name
106  *   Y:\<str\>
107  * Specify visual information, given an index, and some data
108  *   V:\<num\>:\<kv\>:\<rv\>:\<gv\>:\<bv\>
109  * Specify the set of colors to use when drawing a zapped spell
110  *   Z:\<type\>:\<str\>
111  * Specify a macro trigger template and macro trigger names.
112  *   T:\<template\>:\<modifier chr\>:\<modifier name1\>:\<modifier name2\>:...
113  *   T:\<trigger\>:\<keycode\>:\<shift-keycode\>
114  * </pre>
115  */
116 errr process_pref_file_command(player_type *creature_ptr, char *buf)
117 {
118         if (buf[1] != ':') return 1;
119
120         char *zz[16];
121         switch (buf[0])
122         {
123         case 'H':
124         {
125                 /* Process "H:<history>" */
126                 add_history_from_pref_line(buf + 2);
127                 return 0;
128         }
129         case 'R':
130         {
131                 /* Process "R:<num>:<a>/<c>" -- attr/char for monster races */
132                 if (tokenize(buf + 2, 3, zz, TOKENIZE_CHECKQUOTE) != 3) return 1;
133
134                 monster_race *r_ptr;
135                 int i = (huge)strtol(zz[0], NULL, 0);
136                 TERM_COLOR n1 = (TERM_COLOR)strtol(zz[1], NULL, 0);
137                 SYMBOL_CODE n2 = (SYMBOL_CODE)strtol(zz[2], NULL, 0);
138                 if (i >= max_r_idx) return 1;
139                 r_ptr = &r_info[i];
140                 if (n1 || (!(n2 & 0x80) && n2)) r_ptr->x_attr = n1; /* Allow TERM_DARK text */
141                 if (n2) r_ptr->x_char = n2;
142                 return 0;
143         }
144         case 'K':
145         {
146                 /* Process "K:<num>:<a>/<c>"  -- attr/char for object kinds */
147                 if (tokenize(buf + 2, 3, zz, TOKENIZE_CHECKQUOTE) != 3) return 1;
148                 
149                 object_kind *k_ptr;
150                 int i = (huge)strtol(zz[0], NULL, 0);
151                 TERM_COLOR n1 = (TERM_COLOR)strtol(zz[1], NULL, 0);
152                 SYMBOL_CODE n2 = (SYMBOL_CODE)strtol(zz[2], NULL, 0);
153                 if (i >= max_k_idx) return 1;
154                 k_ptr = &k_info[i];
155                 if (n1 || (!(n2 & 0x80) && n2)) k_ptr->x_attr = n1; /* Allow TERM_DARK text */
156                 if (n2) k_ptr->x_char = n2;
157                 return 0;
158         }
159         case 'F':
160         {
161                 /* Process "F:<num>:<a>/<c>" -- attr/char for terrain features */
162                 /* "F:<num>:<a>/<c>" */
163                 /* "F:<num>:<a>/<c>:LIT" */
164                 /* "F:<num>:<a>/<c>:<la>/<lc>:<da>/<dc>" */
165                 feature_type *f_ptr;
166                 int num = tokenize(buf + 2, F_LIT_MAX * 2 + 1, zz, TOKENIZE_CHECKQUOTE);
167
168                 if ((num != 3) && (num != 4) && (num != F_LIT_MAX * 2 + 1)) return 1;
169                 else if ((num == 4) && !streq(zz[3], "LIT")) return 1;
170
171                 int i = (huge)strtol(zz[0], NULL, 0);
172                 if (i >= max_f_idx) return 1;
173                 f_ptr = &f_info[i];
174
175                 TERM_COLOR n1 = (TERM_COLOR)strtol(zz[1], NULL, 0);
176                 SYMBOL_CODE n2 = (SYMBOL_CODE)strtol(zz[2], NULL, 0);
177                 if (n1 || (!(n2 & 0x80) && n2)) f_ptr->x_attr[F_LIT_STANDARD] = n1; /* Allow TERM_DARK text */
178                 if (n2) f_ptr->x_char[F_LIT_STANDARD] = n2;
179
180                 switch (num)
181                 {
182                 case 3:
183                 {
184                         /* No lighting support */
185                         n1 = f_ptr->x_attr[F_LIT_STANDARD];
186                         n2 = f_ptr->x_char[F_LIT_STANDARD];
187                         for (int j = F_LIT_NS_BEGIN; j < F_LIT_MAX; j++)
188                         {
189                                 f_ptr->x_attr[j] = n1;
190                                 f_ptr->x_char[j] = n2;
191                         }
192
193                         return 0;
194                 }
195                 case 4:
196                 {
197                         /* Use default lighting */
198                         apply_default_feat_lighting(f_ptr->x_attr, f_ptr->x_char);
199                         return 0;
200                 }
201                 case F_LIT_MAX * 2 + 1:
202                 {
203                         /* Use desired lighting */
204                         for (int j = F_LIT_NS_BEGIN; j < F_LIT_MAX; j++)
205                         {
206                                 n1 = (TERM_COLOR)strtol(zz[j * 2 + 1], NULL, 0);
207                                 n2 = (SYMBOL_CODE)strtol(zz[j * 2 + 2], NULL, 0);
208                                 if (n1 || (!(n2 & 0x80) && n2)) f_ptr->x_attr[j] = n1; /* Allow TERM_DARK text */
209                                 if (n2) f_ptr->x_char[j] = n2;
210                         }
211
212                         return 0;
213                 }
214                 default:
215                         return 0;
216                 }
217         }
218         case 'S':
219         {
220                 /* Process "S:<num>:<a>/<c>" -- attr/char for special things */
221                 if (tokenize(buf + 2, 3, zz, TOKENIZE_CHECKQUOTE) != 3) return 1;
222
223                 int j = (byte)strtol(zz[0], NULL, 0);
224                 TERM_COLOR n1 = (TERM_COLOR)strtol(zz[1], NULL, 0);
225                 SYMBOL_CODE n2 = (SYMBOL_CODE)strtol(zz[2], NULL, 0);
226                 misc_to_attr[j] = n1;
227                 misc_to_char[j] = n2;
228                 return 0;
229         }
230         case 'U':
231         {
232                 /* Process "U:<tv>:<a>/<c>" -- attr/char for unaware items */
233                 if (tokenize(buf + 2, 3, zz, TOKENIZE_CHECKQUOTE) != 3) return 1;
234
235                 int j = (huge)strtol(zz[0], NULL, 0);
236                 TERM_COLOR n1 = (TERM_COLOR)strtol(zz[1], NULL, 0);
237                 SYMBOL_CODE n2 = (SYMBOL_CODE)strtol(zz[2], NULL, 0);
238                 for (int i = 1; i < max_k_idx; i++)
239                 {
240                         object_kind *k_ptr = &k_info[i];
241                         if (k_ptr->tval == j)
242                         {
243                                 if (n1) k_ptr->d_attr = n1;
244                                 if (n2) k_ptr->d_char = n2;
245                         }
246                 }
247
248                 return 0;
249         }
250         case 'E':
251         {
252                 /* Process "E:<tv>:<a>" -- attribute for inventory objects */
253                 if (tokenize(buf + 2, 2, zz, TOKENIZE_CHECKQUOTE) != 2) return 1;
254
255                 int j = (byte)strtol(zz[0], NULL, 0) % 128;
256                 TERM_COLOR n1 = (TERM_COLOR)strtol(zz[1], NULL, 0);
257                 if (n1) tval_to_attr[j] = n1;
258                 return 0;
259         }
260         case 'A':
261         {
262                 /* Process "A:<str>" -- save an "action" for later */
263                 text_to_ascii(macro__buf, buf + 2);
264                 return 0;
265         }
266         case 'P':
267         {
268                 /* Process "P:<str>" -- normal macro */
269                 char tmp[1024];
270                 text_to_ascii(tmp, buf + 2);
271                 macro_add(tmp, macro__buf);
272                 return 0;
273         }
274         case 'C':
275         {
276                 /* Process "C:<str>" -- create keymap */
277                 if (tokenize(buf + 2, 2, zz, TOKENIZE_CHECKQUOTE) != 2) return 1;
278
279                 int mode = strtol(zz[0], NULL, 0);
280                 if ((mode < 0) || (mode >= KEYMAP_MODES)) return 1;
281
282                 char tmp[1024];
283                 text_to_ascii(tmp, zz[1]);
284                 if (!tmp[0] || tmp[1]) return 1;
285
286                 int i = (byte)(tmp[0]);
287                 string_free(keymap_act[mode][i]);
288                 keymap_act[mode][i] = string_make(macro__buf);
289                 return 0;
290         }
291         case 'V':
292         {
293                 /* Process "V:<num>:<kv>:<rv>:<gv>:<bv>" -- visual info */
294                 if (tokenize(buf + 2, 5, zz, TOKENIZE_CHECKQUOTE) != 5) return 1;
295
296                 int i = (byte)strtol(zz[0], NULL, 0);
297                 angband_color_table[i][0] = (byte)strtol(zz[1], NULL, 0);
298                 angband_color_table[i][1] = (byte)strtol(zz[2], NULL, 0);
299                 angband_color_table[i][2] = (byte)strtol(zz[3], NULL, 0);
300                 angband_color_table[i][3] = (byte)strtol(zz[4], NULL, 0);
301                 return 0;
302         }
303         case 'X':
304         case 'Y':
305         {
306                 /* Process "X:<str>" -- turn option off */
307                 /* Process "Y:<str>" -- turn option on */
308                 for (int i = 0; option_info[i].o_desc; i++)
309                 {
310                         bool is_option = option_info[i].o_var != NULL;
311                         is_option &= option_info[i].o_text != NULL;
312                         is_option &= streq(option_info[i].o_text, buf + 2);
313                         if (!is_option) continue;
314
315                         int os = option_info[i].o_set;
316                         int ob = option_info[i].o_bit;
317
318                         if ((creature_ptr->playing || current_world_ptr->character_xtra) &&
319                                 (OPT_PAGE_BIRTH == option_info[i].o_page) && !current_world_ptr->wizard)
320                         {
321                                 msg_format(_("初期オプションは変更できません! '%s'", "Birth options can not changed! '%s'"), buf);
322                                 msg_print(NULL);
323                                 return 0;
324                         }
325
326                         if (buf[0] == 'X')
327                         {
328                                 option_flag[os] &= ~(1L << ob);
329                                 (*option_info[i].o_var) = FALSE;
330                                 return 0;
331                         }
332
333                         option_flag[os] |= (1L << ob);
334                         (*option_info[i].o_var) = TRUE;
335                         return 0;
336                 }
337
338                 msg_format(_("オプションの名前が正しくありません: %s", "Ignored invalid option: %s"), buf);
339                 msg_print(NULL);
340                 return 0;
341         }
342         case 'Z':
343         {
344                 /* Process "Z:<type>:<str>" -- set spell color */
345                 char *t = my_strchr(buf + 2, ':');
346                 if (!t) return 1;
347
348                 *(t++) = '\0';
349                 for (int i = 0; i < MAX_NAMED_NUM; i++)
350                 {
351                         if (!streq(gf_desc[i].name, buf + 2)) continue;
352
353                         gf_color[gf_desc[i].num] = (TERM_COLOR)quark_add(t);
354                         return 0;
355                 }
356
357                 return 1;
358         }
359         case 'T':
360         {
361                 /* Initialize macro trigger names and a template */
362                 /* Process "T:<trigger>:<keycode>:<shift-keycode>" */
363                 /* Process "T:<template>:<modifier chr>:<modifier name>:..." */
364                 int tok = tokenize(buf + 2, 2 + MAX_MACRO_MOD, zz, 0);
365
366                 /* Process "T:<template>:<modifier chr>:<modifier name>:..." */
367                 if (tok >= 4)
368                 {
369                         if (macro_template != NULL)
370                         {
371                                 int macro_modifier_length = strlen(macro_modifier_chr);
372                                 string_free(macro_template);
373                                 macro_template = NULL;
374                                 string_free(macro_modifier_chr);
375                                 for (int i = 0; i < macro_modifier_length; i++)
376                                 {
377                                         string_free(macro_modifier_name[i]);
378                                 }
379
380                                 for (int i = 0; i < max_macrotrigger; i++)
381                                 {
382                                         string_free(macro_trigger_name[i]);
383                                         string_free(macro_trigger_keycode[0][i]);
384                                         string_free(macro_trigger_keycode[1][i]);
385                                 }
386
387                                 max_macrotrigger = 0;
388                         }
389
390                         if (*zz[0] == '\0') return 0;
391
392                         int zz_length = strlen(zz[1]);
393                         zz_length = MIN(MAX_MACRO_MOD, zz_length);
394                         if (2 + zz_length != tok) return 1;
395
396                         macro_template = string_make(zz[0]);
397                         macro_modifier_chr = string_make(zz[1]);
398                         for (int i = 0; i < zz_length; i++)
399                         {
400                                 macro_modifier_name[i] = string_make(zz[2 + i]);
401                         }
402
403                         return 0;
404                 }
405
406                 /* Process "T:<trigger>:<keycode>:<shift-keycode>" */
407                 if (tok < 2) return 0;
408
409                 char buf_aux[1024];
410                 char *t, *s;
411                 if (max_macrotrigger >= MAX_MACRO_TRIG)
412                 {
413                         msg_print(_("マクロトリガーの設定が多すぎます!", "Too many macro triggers!"));
414                         return 1;
415                 }
416
417                 int m = max_macrotrigger;
418                 max_macrotrigger++;
419                 t = buf_aux;
420                 s = zz[0];
421                 while (*s)
422                 {
423                         if ('\\' == *s) s++;
424                         *t++ = *s++;
425                 }
426
427                 *t = '\0';
428                 macro_trigger_name[m] = string_make(buf_aux);
429                 macro_trigger_keycode[0][m] = string_make(zz[1]);
430                 if (tok == 3)
431                 {
432                         macro_trigger_keycode[1][m] = string_make(zz[2]);
433                         return 0;
434                 }
435
436                 macro_trigger_keycode[1][m] = string_make(zz[1]);
437                 return 0;
438         }
439         }
440
441         return 1;
442 }
443
444
445 /*!
446  * @brief process_pref_fileのサブルーチンとして条件分岐処理の解釈と結果を返す /
447  * Helper function for "process_pref_file()"
448  * @param creature_ptr プレーヤーへの参照ポインタ
449  * @param sp テキスト文字列の参照ポインタ
450  * @param fp 再帰中のポインタ参照
451  * @return
452  * @details
453  * <pre>
454  * Input:
455  *   v: output buffer array
456  *   f: final character
457  * Output:
458  *   result
459  * </pre>
460  */
461 concptr process_pref_file_expr(player_type *creature_ptr, char **sp, char *fp)
462 {
463         char *s;
464         s = (*sp);
465         while (iswspace(*s)) s++;
466
467         char *b;
468         b = s;
469
470         concptr v = "?o?o?";
471
472         char b1 = '[';
473         char b2 = ']';
474         char f = ' ';
475         static char tmp[16];
476         if (*s == b1)
477         {
478                 concptr p;
479                 concptr t;
480
481                 /* Skip b1 */
482                 s++;
483
484                 /* First */
485                 t = process_pref_file_expr(creature_ptr, &s, &f);
486
487                 if (!*t)
488                 {
489                 }
490                 else if (streq(t, "IOR"))
491                 {
492                         v = "0";
493                         while (*s && (f != b2))
494                         {
495                                 t = process_pref_file_expr(creature_ptr, &s, &f);
496                                 if (*t && !streq(t, "0")) v = "1";
497                         }
498                 }
499                 else if (streq(t, "AND"))
500                 {
501                         v = "1";
502                         while (*s && (f != b2))
503                         {
504                                 t = process_pref_file_expr(creature_ptr, &s, &f);
505                                 if (*t && streq(t, "0")) v = "0";
506                         }
507                 }
508                 else if (streq(t, "NOT"))
509                 {
510                         v = "1";
511                         while (*s && (f != b2))
512                         {
513                                 t = process_pref_file_expr(creature_ptr, &s, &f);
514                                 if (*t && streq(t, "1")) v = "0";
515                         }
516                 }
517                 else if (streq(t, "EQU"))
518                 {
519                         v = "0";
520                         if (*s && (f != b2))
521                         {
522                                 t = process_pref_file_expr(creature_ptr, &s, &f);
523                         }
524                         while (*s && (f != b2))
525                         {
526                                 p = process_pref_file_expr(creature_ptr, &s, &f);
527                                 if (streq(t, p)) v = "1";
528                         }
529                 }
530                 else if (streq(t, "LEQ"))
531                 {
532                         v = "1";
533                         if (*s && (f != b2))
534                         {
535                                 t = process_pref_file_expr(creature_ptr, &s, &f);
536                         }
537                         while (*s && (f != b2))
538                         {
539                                 p = t;
540                                 t = process_pref_file_expr(creature_ptr, &s, &f);
541                                 if (*t && atoi(p) > atoi(t)) v = "0";
542                         }
543                 }
544                 else if (streq(t, "GEQ"))
545                 {
546                         v = "1";
547                         if (*s && (f != b2))
548                         {
549                                 t = process_pref_file_expr(creature_ptr, &s, &f);
550                         }
551                         while (*s && (f != b2))
552                         {
553                                 p = t;
554                                 t = process_pref_file_expr(creature_ptr, &s, &f);
555                                 if (*t && atoi(p) < atoi(t)) v = "0";
556                         }
557                 }
558                 else
559                 {
560                         while (*s && (f != b2))
561                         {
562                                 t = process_pref_file_expr(creature_ptr, &s, &f);
563                         }
564                 }
565
566                 if (f != b2) v = "?x?x?";
567
568                 if ((f = *s) != '\0') *s++ = '\0';
569
570                 *fp = f;
571                 *sp = s;
572                 return v;
573         }
574
575         /* Accept all printables except spaces and brackets */
576 #ifdef JP
577         while (iskanji(*s) || (isprint(*s) && !my_strchr(" []", *s)))
578         {
579                 if (iskanji(*s)) s++;
580                 s++;
581         }
582 #else
583         while (isprint(*s) && !my_strchr(" []", *s)) ++s;
584 #endif
585
586         if ((f = *s) != '\0') *s++ = '\0';
587
588         if (*b != '$')
589         {
590                 v = b;
591                 *fp = f;
592                 *sp = s;
593                 return v;
594         }
595
596         if (streq(b + 1, "SYS"))
597         {
598                 v = ANGBAND_SYS;
599         }
600         else if (streq(b + 1, "KEYBOARD"))
601         {
602                 v = ANGBAND_KEYBOARD;
603         }
604         else if (streq(b + 1, "GRAF"))
605         {
606                 v = ANGBAND_GRAF;
607         }
608         else if (streq(b + 1, "MONOCHROME"))
609         {
610                 if (arg_monochrome)
611                         v = "ON";
612                 else
613                         v = "OFF";
614         }
615         else if (streq(b + 1, "RACE"))
616         {
617 #ifdef JP
618                 v = rp_ptr->E_title;
619 #else
620                 v = rp_ptr->title;
621 #endif
622         }
623         else if (streq(b + 1, "CLASS"))
624         {
625 #ifdef JP
626                 v = cp_ptr->E_title;
627 #else
628                 v = cp_ptr->title;
629 #endif
630         }
631         else if (streq(b + 1, "PLAYER"))
632         {
633                 static char tmp_player_name[32];
634                 char *pn, *tpn;
635                 for (pn = creature_ptr->name, tpn = tmp_player_name; *pn; pn++, tpn++)
636                 {
637 #ifdef JP
638                         if (iskanji(*pn))
639                         {
640                                 *(tpn++) = *(pn++);
641                                 *tpn = *pn;
642                                 continue;
643                         }
644 #endif
645                         *tpn = my_strchr(" []", *pn) ? '_' : *pn;
646                 }
647
648                 *tpn = '\0';
649                 v = tmp_player_name;
650         }
651         else if (streq(b + 1, "REALM1"))
652         {
653 #ifdef JP
654                 v = E_realm_names[creature_ptr->realm1];
655 #else
656                 v = realm_names[creature_ptr->realm1];
657 #endif
658         }
659         else if (streq(b + 1, "REALM2"))
660         {
661 #ifdef JP
662                 v = E_realm_names[creature_ptr->realm2];
663 #else
664                 v = realm_names[creature_ptr->realm2];
665 #endif
666         }
667         else if (streq(b + 1, "LEVEL"))
668         {
669                 sprintf(tmp, "%02d", creature_ptr->lev);
670                 v = tmp;
671         }
672         else if (streq(b + 1, "AUTOREGISTER"))
673         {
674                 if (creature_ptr->autopick_autoregister)
675                         v = "1";
676                 else
677                         v = "0";
678         }
679         else if (streq(b + 1, "MONEY"))
680         {
681                 sprintf(tmp, "%09ld", (long int)creature_ptr->au);
682                 v = tmp;
683         }
684
685         *fp = f;
686         *sp = s;
687         return v;
688 }
689
690
691 /*!
692  * @brief process_pref_fileのサブルーチン /
693  * Open the "user pref file" and parse it.
694  * @param creature_ptr プレーヤーへの参照ポインタ
695  * @param name 読み込むファイル名
696  * @param preftype prefファイルのタイプ
697  * @return エラーコード
698  * @details
699  * <pre>
700  * Input:
701  *   v: output buffer array
702  *   f: final character
703  * Output:
704  *   result
705  * </pre>
706  */
707 static errr process_pref_file_aux(player_type *creature_ptr, concptr name, int preftype)
708 {
709         FILE *fp;
710         fp = my_fopen(name, "r");
711         if (!fp) return -1;
712
713         char buf[1024];
714         char old[1024];
715         int line = -1;
716         errr err = 0;
717         bool bypass = FALSE;
718         while (my_fgets(fp, buf, sizeof(buf)) == 0)
719         {
720                 line++;
721                 if (!buf[0]) continue;
722
723 #ifdef JP
724                 if (!iskanji(buf[0]))
725 #endif
726                         if (iswspace(buf[0])) continue;
727
728                 if (buf[0] == '#') continue;
729                 strcpy(old, buf);
730
731                 /* Process "?:<expr>" */
732                 if ((buf[0] == '?') && (buf[1] == ':'))
733                 {
734                         char f;
735                         char *s;
736                         s = buf + 2;
737                         concptr v = process_pref_file_expr(creature_ptr, &s, &f);
738                         bypass = streq(v, "0");
739                         continue;
740                 }
741
742                 if (bypass) continue;
743
744                 /* Process "%:<file>" */
745                 if (buf[0] == '%')
746                 {
747                         static int depth_count = 0;
748                         if (depth_count > 20) continue;
749
750                         depth_count++;
751                         switch (preftype)
752                         {
753                         case PREF_TYPE_AUTOPICK:
754                                 (void)process_autopick_file(creature_ptr, buf + 2);
755                                 break;
756                         case PREF_TYPE_HISTPREF:
757                                 (void)process_histpref_file(creature_ptr, buf + 2);
758                                 break;
759                         default:
760                                 (void)process_pref_file(creature_ptr, buf + 2);
761                                 break;
762                         }
763
764                         depth_count--;
765                         continue;
766                 }
767
768                 err = process_pref_file_command(creature_ptr, buf);
769                 if (err != 0)
770                 {
771                         if (preftype != PREF_TYPE_AUTOPICK)
772                                 break;
773                         err = process_autopick_file_command(buf);
774                 }
775         }
776
777         if (err != 0)
778         {
779                 /* Print error message */
780                 /* ToDo: Add better error messages */
781                 msg_format(_("ファイル'%s'の%d行でエラー番号%dのエラー。", "Error %d in line %d of file '%s'."),
782                         _(name, err), line, _(err, name));
783                 msg_format(_("('%s'を解析中)", "Parsing '%s'"), old);
784                 msg_print(NULL);
785         }
786
787         my_fclose(fp);
788         return (err);
789 }
790
791
792 /*!
793  * @brief pref設定ファイルを読み込み設定を反映させる /
794  * Process the "user pref file" with the given name
795  * @param creature_ptr プレーヤーへの参照ポインタ
796  * @param name 読み込むファイル名
797  * @return エラーコード
798  * @details
799  * <pre>
800  * See the functions above for a list of legal "commands".
801  * We also accept the special "?" and "%" directives, which
802  * allow conditional evaluation and filename inclusion.
803  * </pre>
804  */
805 errr process_pref_file(player_type *creature_ptr, concptr name)
806 {
807         char buf[1024];
808         path_build(buf, sizeof(buf), ANGBAND_DIR_PREF, name);
809
810         errr err1 = process_pref_file_aux(creature_ptr, buf, PREF_TYPE_NORMAL);
811         if (err1 > 0) return err1;
812
813         path_build(buf, sizeof(buf), ANGBAND_DIR_USER, name);
814         errr err2 = process_pref_file_aux(creature_ptr, buf, PREF_TYPE_NORMAL);
815         if (err2 < 0 && !err1)
816                 return -2;
817
818         return err2;
819 }
820
821
822 /*!
823  * @brief プレイヤーステータスをファイルダンプ出力する
824  * Hack -- Dump a character description file
825  * @param creature_ptr プレーヤーへの参照ポインタ
826  * @param name 出力ファイル名
827  * @return エラーコード
828  * @details
829  * Allow the "full" flag to dump additional info,
830  * and trigger its usage from various places in the code.
831  */
832 errr file_character(player_type *creature_ptr, concptr name, display_player_pf display_player, map_name_pf map_name)
833 {
834         char buf[1024];
835         path_build(buf, sizeof(buf), ANGBAND_DIR_USER, name);
836
837         FILE_TYPE(FILE_TYPE_TEXT);
838
839         int     fd = fd_open(buf, O_RDONLY);
840         if (fd >= 0)
841         {
842                 char out_val[160];
843                 (void)fd_close(fd);
844                 (void)sprintf(out_val, _("現存するファイル %s に上書きしますか? ", "Replace existing file %s? "), buf);
845                 if (get_check_strict(out_val, CHECK_NO_HISTORY)) fd = -1;
846         }
847
848         FILE *fff = NULL;
849         if (fd < 0) fff = my_fopen(buf, "w");
850
851         if (!fff)
852         {
853                 prt(_("キャラクタ情報のファイルへの書き出しに失敗しました!", "Character dump failed!"), 0, 0);
854                 (void)inkey();
855                 return -1;
856         }
857
858         make_character_dump(creature_ptr, fff, update_playtime, display_player, map_name);
859         my_fclose(fff);
860         msg_print(_("キャラクタ情報のファイルへの書き出しに成功しました。", "Character dump successful."));
861         msg_print(NULL);
862         return 0;
863 }
864
865
866 /*!
867  * @brief ファイル内容の一行をコンソールに出力する
868  * Display single line of on-line help file
869  * @param str 出力する文字列
870  * @param cy コンソールの行
871  * @param shower 確認中
872  * @return なし
873  * @details
874  * <pre>
875  * You can insert some special color tag to change text color.
876  * Such as...
877  * WHITETEXT [[[[y|SOME TEXT WHICH IS DISPLAYED IN YELLOW| WHITETEXT
878  * A colored segment is between "[[[[y|" and the last "|".
879  * You can use any single character in place of the "|".
880  * </pre>
881  */
882 static void show_file_aux_line(concptr str, int cy, concptr shower)
883 {
884         char lcstr[1024];
885         if (shower)
886         {
887                 strcpy(lcstr, str);
888                 str_tolower(lcstr);
889         }
890
891         int cx = 0;
892         Term_gotoxy(cx, cy);
893
894         static const char tag_str[] = "[[[[";
895         byte color = TERM_WHITE;
896         char in_tag = '\0';
897         for (int i = 0; str[i];)
898         {
899                 int len = strlen(&str[i]);
900                 int showercol = len + 1;
901                 int bracketcol = len + 1;
902                 int endcol = len;
903                 concptr ptr;
904                 if (shower)
905                 {
906                         ptr = my_strstr(&lcstr[i], shower);
907                         if (ptr) showercol = ptr - &lcstr[i];
908                 }
909
910                 ptr = in_tag ? my_strchr(&str[i], in_tag) : my_strstr(&str[i], tag_str);
911                 if (ptr) bracketcol = ptr - &str[i];
912                 if (bracketcol < endcol) endcol = bracketcol;
913                 if (showercol < endcol) endcol = showercol;
914
915                 Term_addstr(endcol, color, &str[i]);
916                 cx += endcol;
917                 i += endcol;
918
919                 if (endcol == showercol)
920                 {
921                         int showerlen = strlen(shower);
922                         Term_addstr(showerlen, TERM_YELLOW, &str[i]);
923                         cx += showerlen;
924                         i += showerlen;
925                         continue;
926                 }
927
928                 if (endcol != bracketcol) continue;
929
930                 if (in_tag)
931                 {
932                         i++;
933                         in_tag = '\0';
934                         color = TERM_WHITE;
935                         continue;
936                 }
937
938                 i += sizeof(tag_str) - 1;
939                 color = color_char_to_attr(str[i]);
940                 if (color == 255 || str[i + 1] == '\0')
941                 {
942                         color = TERM_WHITE;
943                         Term_addstr(-1, TERM_WHITE, tag_str);
944                         cx += sizeof(tag_str) - 1;
945                         continue;
946                 }
947
948                 i++;
949                 in_tag = str[i];
950                 i++;
951         }
952
953         Term_erase(cx, cy, 255);
954 }
955
956
957 /*!
958  * @brief ファイル内容をコンソールに出力する
959  * Recursive file perusal.
960  * @param creature_ptr プレーヤーへの参照ポインタ
961  * @param show_version TRUEならばコンソール上にゲームのバージョンを表示する
962  * @param name ファイル名の文字列
963  * @param what 内容キャプションの文字列
964  * @param line 表示の現在行
965  * @param mode オプション
966  * @return なし
967  * @details
968  * <pre>
969  * Process various special text in the input file, including
970  * the "menu" structures used by the "help file" system.
971  * Return FALSE on 'q' to exit from a deep, otherwise TRUE.
972  * </pre>
973  */
974 bool show_file(player_type *creature_ptr, bool show_version, concptr name, concptr what, int line, BIT_FLAGS mode)
975 {
976         int wid, hgt;
977         Term_get_size(&wid, &hgt);
978
979         char finder_str[81];
980         strcpy(finder_str, "");
981
982         char shower_str[81];
983         strcpy(shower_str, "");
984
985         char caption[128];
986         strcpy(caption, "");
987
988         char hook[68][32];
989         for (int i = 0; i < 68; i++)
990         {
991                 hook[i][0] = '\0';
992         }
993
994         char filename[1024];
995         strcpy(filename, name);
996         int n = strlen(filename);
997
998         concptr tag = NULL;
999         for (int i = 0; i < n; i++)
1000         {
1001                 if (filename[i] == '#')
1002                 {
1003                         filename[i] = '\0';
1004                         tag = filename + i + 1;
1005                         break;
1006                 }
1007         }
1008
1009         name = filename;
1010         FILE *fff = NULL;
1011         char path[1024];
1012         if (what)
1013         {
1014                 strcpy(caption, what);
1015                 strcpy(path, name);
1016                 fff = my_fopen(path, "r");
1017         }
1018
1019         if (!fff)
1020         {
1021                 sprintf(caption, _("ヘルプ・ファイル'%s'", "Help file '%s'"), name);
1022                 path_build(path, sizeof(path), ANGBAND_DIR_HELP, name);
1023                 fff = my_fopen(path, "r");
1024         }
1025
1026         if (!fff)
1027         {
1028                 sprintf(caption, _("スポイラー・ファイル'%s'", "Info file '%s'"), name);
1029                 path_build(path, sizeof(path), ANGBAND_DIR_INFO, name);
1030                 fff = my_fopen(path, "r");
1031         }
1032
1033         if (!fff)
1034         {
1035                 path_build(path, sizeof(path), ANGBAND_DIR, name);
1036
1037                 for (int i = 0; path[i]; i++)
1038                         if ('\\' == path[i])
1039                                 path[i] = PATH_SEP[0];
1040
1041                 sprintf(caption, _("スポイラー・ファイル'%s'", "Info file '%s'"), name);
1042                 fff = my_fopen(path, "r");
1043         }
1044
1045         if (!fff)
1046         {
1047                 msg_format(_("'%s'をオープンできません。", "Cannot open '%s'."), name);
1048                 msg_print(NULL);
1049
1050                 return TRUE;
1051         }
1052
1053         int skey;
1054         int next = 0;
1055         int size = 0;
1056         int back = 0;
1057         bool menu = FALSE;
1058         char buf[1024];
1059         bool reverse = (line < 0);
1060         while (TRUE)
1061         {
1062                 char *str = buf;
1063                 if (my_fgets(fff, buf, sizeof(buf))) break;
1064                 if (!prefix(str, "***** "))
1065                 {
1066                         next++;
1067                         continue;
1068                 }
1069
1070                 if ((str[6] == '[') && isalpha(str[7]))
1071                 {
1072                         int k = str[7] - 'A';
1073                         menu = TRUE;
1074                         if ((str[8] == ']') && (str[9] == ' '))
1075                         {
1076                                 strncpy(hook[k], str + 10, 31);
1077                                 hook[k][31] = '\0';
1078                         }
1079
1080                         continue;
1081                 }
1082
1083                 if (str[6] != '<') continue;
1084
1085                 size_t len = strlen(str);
1086                 if (str[len - 1] == '>')
1087                 {
1088                         str[len - 1] = '\0';
1089                         if (tag && streq(str + 7, tag)) line = next;
1090                 }
1091         }
1092
1093         size = next;
1094         int rows = hgt - 4;
1095         if (line == -1)
1096                 line = ((size - 1) / rows)*rows;
1097
1098         Term_clear();
1099
1100         concptr find = NULL;
1101         while (TRUE)
1102         {
1103                 if (line >= size - rows)
1104                         line = size - rows;
1105                 if (line < 0) line = 0;
1106
1107                 if (next > line)
1108                 {
1109                         my_fclose(fff);
1110                         fff = my_fopen(path, "r");
1111                         if (!fff) return FALSE;
1112
1113                         next = 0;
1114                 }
1115
1116                 while (next < line)
1117                 {
1118                         if (my_fgets(fff, buf, sizeof(buf))) break;
1119                         if (prefix(buf, "***** ")) continue;
1120                         next++;
1121                 }
1122
1123                 int row_count = 0;
1124                 concptr shower = NULL;
1125                 for (int i = 0; i < rows; i++)
1126                 {
1127                         concptr str = buf;
1128                         if (!i) line = next;
1129                         if (my_fgets(fff, buf, sizeof(buf))) break;
1130                         if (prefix(buf, "***** ")) continue;
1131                         next++;
1132                         if (find && !i)
1133                         {
1134                                 char lc_buf[1024];
1135                                 strcpy(lc_buf, str);
1136                                 str_tolower(lc_buf);
1137                                 if (!my_strstr(lc_buf, find)) continue;
1138                         }
1139
1140                         find = NULL;
1141                         show_file_aux_line(str, i + 2, shower);
1142                         row_count++;
1143                 }
1144
1145                 while (row_count < rows)
1146                 {
1147                         Term_erase(0, row_count + 2, 255);
1148                         row_count++;
1149                 }
1150
1151                 if (find)
1152                 {
1153                         bell();
1154                         line = back;
1155                         find = NULL;
1156                         continue;
1157                 }
1158
1159                 if (show_version)
1160                 {
1161                         prt(format(_("[変愚蛮怒 %d.%d.%d, %s, %d/%d]", "[Hengband %d.%d.%d, %s, Line %d/%d]"),
1162                                 FAKE_VER_MAJOR - 10, FAKE_VER_MINOR, FAKE_VER_PATCH,
1163                                 caption, line, size), 0, 0);
1164                 }
1165                 else
1166                 {
1167                         prt(format(_("[%s, %d/%d]", "[%s, Line %d/%d]"),
1168                                 caption, line, size), 0, 0);
1169                 }
1170
1171                 if (size <= rows)
1172                 {
1173                         prt(_("[キー:(?)ヘルプ (ESC)終了]", "[Press ESC to exit.]"), hgt - 1, 0);
1174                 }
1175                 else
1176                 {
1177 #ifdef JP
1178                         if (reverse)
1179                                 prt("[キー:(RET/スペース)↑ (-)↓ (?)ヘルプ (ESC)終了]", hgt - 1, 0);
1180                         else
1181                                 prt("[キー:(RET/スペース)↓ (-)↑ (?)ヘルプ (ESC)終了]", hgt - 1, 0);
1182 #else
1183                         prt("[Press Return, Space, -, =, /, |, or ESC to exit.]", hgt - 1, 0);
1184 #endif
1185                 }
1186
1187                 skey = inkey_special(TRUE);
1188                 switch (skey)
1189                 {
1190                 case '?':
1191                         if (strcmp(name, _("jhelpinfo.txt", "helpinfo.txt")) != 0)
1192                                 show_file(creature_ptr, TRUE, _("jhelpinfo.txt", "helpinfo.txt"), NULL, 0, mode);
1193                         break;
1194                 case '=':
1195                         prt(_("強調: ", "Show: "), hgt - 1, 0);
1196
1197                         char back_str[81];
1198                         strcpy(back_str, shower_str);
1199                         if (askfor(shower_str, 80))
1200                         {
1201                                 if (shower_str[0])
1202                                 {
1203                                         str_tolower(shower_str);
1204                                         shower = shower_str;
1205                                 }
1206                                 else shower = NULL;
1207                         }
1208                         else strcpy(shower_str, back_str);
1209                         break;
1210
1211                 case '/':
1212                 case KTRL('s'):
1213                         prt(_("検索: ", "Find: "), hgt - 1, 0);
1214                         strcpy(back_str, finder_str);
1215                         if (askfor(finder_str, 80))
1216                         {
1217                                 if (finder_str[0])
1218                                 {
1219                                         find = finder_str;
1220                                         back = line;
1221                                         line = line + 1;
1222                                         str_tolower(finder_str);
1223                                         shower = finder_str;
1224                                 }
1225                                 else shower = NULL;
1226                         }
1227                         else strcpy(finder_str, back_str);
1228                         break;
1229
1230                 case '#':
1231                 {
1232                         char tmp[81];
1233                         prt(_("行: ", "Goto Line: "), hgt - 1, 0);
1234                         strcpy(tmp, "0");
1235
1236                         if (askfor(tmp, 80)) line = atoi(tmp);
1237                         break;
1238                 }
1239
1240                 case SKEY_TOP:
1241                         line = 0;
1242                         break;
1243
1244                 case SKEY_BOTTOM:
1245                         line = ((size - 1) / rows) * rows;
1246                         break;
1247
1248                 case '%':
1249                 {
1250                         char tmp[81];
1251                         prt(_("ファイル・ネーム: ", "Goto File: "), hgt - 1, 0);
1252                         strcpy(tmp, _("jhelp.hlp", "help.hlp"));
1253
1254                         if (askfor(tmp, 80))
1255                         {
1256                                 if (!show_file(creature_ptr, TRUE, tmp, NULL, 0, mode)) skey = 'q';
1257                         }
1258
1259                         break;
1260                 }
1261
1262                 case '-':
1263                         line = line + (reverse ? rows : -rows);
1264                         if (line < 0) line = 0;
1265                         break;
1266
1267                 case SKEY_PGUP:
1268                         line = line - rows;
1269                         if (line < 0) line = 0;
1270                         break;
1271
1272                 case '\n':
1273                 case '\r':
1274                         line = line + (reverse ? -1 : 1);
1275                         if (line < 0) line = 0;
1276                         break;
1277
1278                 case '8':
1279                 case SKEY_UP:
1280                         line--;
1281                         if (line < 0) line = 0;
1282                         break;
1283
1284                 case '2':
1285                 case SKEY_DOWN:
1286                         line++;
1287                         break;
1288
1289                 case ' ':
1290                         line = line + (reverse ? -rows : rows);
1291                         if (line < 0) line = 0;
1292                         break;
1293
1294                 case SKEY_PGDOWN:
1295                         line = line + rows;
1296                         break;
1297                 }
1298
1299                 if (menu)
1300                 {
1301                         int key = -1;
1302                         if (!(skey & SKEY_MASK) && isalpha(skey))
1303                                 key = skey - 'A';
1304
1305                         if ((key > -1) && hook[key][0])
1306                         {
1307                                 /* Recurse on that file */
1308                                 if (!show_file(creature_ptr, TRUE, hook[key], NULL, 0, mode))
1309                                         skey = 'q';
1310                         }
1311                 }
1312
1313                 if (skey == '|')
1314                 {
1315                         FILE *ffp;
1316                         char buff[1024];
1317                         char xtmp[82];
1318
1319                         strcpy(xtmp, "");
1320
1321                         if (!get_string(_("ファイル名: ", "File name: "), xtmp, 80)) continue;
1322                         my_fclose(fff);
1323                         path_build(buff, sizeof(buff), ANGBAND_DIR_USER, xtmp);
1324
1325                         /* Hack -- Re-Open the file */
1326                         fff = my_fopen(path, "r");
1327
1328                         ffp = my_fopen(buff, "w");
1329
1330                         if (!(fff && ffp))
1331                         {
1332                                 msg_print(_("ファイルを開けません。", "Failed to open file."));
1333                                 skey = ESCAPE;
1334                                 break;
1335                         }
1336
1337                         sprintf(xtmp, "%s: %s", creature_ptr->name, what ? what : caption);
1338                         my_fputs(ffp, xtmp, 80);
1339                         my_fputs(ffp, "\n", 80);
1340
1341                         while (!my_fgets(fff, buff, sizeof(buff)))
1342                                 my_fputs(ffp, buff, 80);
1343                         my_fclose(fff);
1344                         my_fclose(ffp);
1345                         fff = my_fopen(path, "r");
1346                 }
1347
1348                 if ((skey == ESCAPE) || (skey == '<')) break;
1349
1350                 if (skey == KTRL('q')) skey = 'q';
1351
1352                 if (skey == 'q') break;
1353         }
1354
1355         my_fclose(fff);
1356         return (skey != 'q');
1357 }
1358
1359
1360 /*!
1361  * @brief ヘルプを表示するコマンドのメインルーチン
1362  * Peruse the On-Line-Help
1363  * @param creature_ptr プレーヤーへの参照ポインタ
1364  * @return なし
1365  * @details
1366  */
1367 void do_cmd_help(player_type *creature_ptr)
1368 {
1369         screen_save();
1370         (void)show_file(creature_ptr, TRUE, _("jhelp.hlp", "help.hlp"), NULL, 0, 0);
1371         screen_load();
1372 }
1373
1374
1375 /*!
1376  * @brief プレイヤーの名前をチェックして修正する
1377  * Process the player name.
1378  * @param player_ptr プレーヤーへの参照ポインタ
1379  * @param sf セーブファイル名に合わせた修正を行うならばTRUE
1380  * @return なし
1381  * @details
1382  * Extract a clean "base name".
1383  * Build the savefile name if needed.
1384  */
1385 void process_player_name(player_type *creature_ptr, bool sf)
1386 {
1387         char old_player_base[32] = "";
1388         if (current_world_ptr->character_generated)
1389                 strcpy(old_player_base, creature_ptr->base_name);
1390
1391         for (int i = 0; creature_ptr->name[i]; i++)
1392         {
1393 #ifdef JP
1394                 if (iskanji(creature_ptr->name[i]))
1395                 {
1396                         i++;
1397                         continue;
1398                 }
1399
1400                 if (iscntrl((unsigned char)creature_ptr->name[i]))
1401 #else
1402                 if (iscntrl(creature_ptr->name[i]))
1403 #endif
1404                 {
1405                         quit_fmt(_("'%s' という名前は不正なコントロールコードを含んでいます。", "The name '%s' contains control chars!"), creature_ptr->name);
1406                 }
1407         }
1408
1409         int k = 0;
1410         for (int i = 0; creature_ptr->name[i]; i++)
1411         {
1412 #ifdef JP
1413                 unsigned char c = creature_ptr->name[i];
1414 #else
1415                 char c = creature_ptr->name[i];
1416 #endif
1417
1418 #ifdef JP
1419                 if (iskanji(c)) {
1420                         if (k + 2 >= sizeof(creature_ptr->base_name) || !creature_ptr->name[i + 1])
1421                                 break;
1422
1423                         creature_ptr->base_name[k++] = c;
1424                         i++;
1425                         creature_ptr->base_name[k++] = creature_ptr->name[i];
1426                 }
1427 #ifdef SJIS
1428                 else if (iskana(c)) creature_ptr->base_name[k++] = c;
1429 #endif
1430                 else
1431 #endif
1432                         if (!strncmp(PATH_SEP, creature_ptr->name + i, strlen(PATH_SEP)))
1433                         {
1434                                 creature_ptr->base_name[k++] = '_';
1435                                 i += strlen(PATH_SEP);
1436                         }
1437 #if defined(WINDOWS)
1438                         else if (my_strchr("\"*,/:;<>?\\|", c))
1439                                 creature_ptr->base_name[k++] = '_';
1440 #endif
1441                         else if (isprint(c))
1442                                 creature_ptr->base_name[k++] = c;
1443         }
1444
1445         creature_ptr->base_name[k] = '\0';
1446         if (!creature_ptr->base_name[0])
1447                 strcpy(creature_ptr->base_name, "PLAYER");
1448
1449 #ifdef SAVEFILE_MUTABLE
1450         sf = TRUE;
1451 #endif
1452         if (!savefile_base[0] && savefile[0])
1453         {
1454                 concptr s = savefile;
1455                 while (TRUE)
1456                 {
1457                         concptr t;
1458                         t = my_strstr(s, PATH_SEP);
1459                         if (!t)
1460                                 break;
1461                         s = t + 1;
1462                 }
1463
1464                 strcpy(savefile_base, s);
1465         }
1466
1467         if (!savefile_base[0] || !savefile[0])
1468                 sf = TRUE;
1469
1470         if (sf)
1471         {
1472                 char temp[128];
1473                 strcpy(savefile_base, creature_ptr->base_name);
1474
1475 #ifdef SAVEFILE_USE_UID
1476                 /* Rename the savefile, using the creature_ptr->player_uid and creature_ptr->base_name */
1477                 (void)sprintf(temp, "%d.%s", creature_ptr->player_uid, creature_ptr->base_name);
1478 #else
1479                 /* Rename the savefile, using the creature_ptr->base_name */
1480                 (void)sprintf(temp, "%s", creature_ptr->base_name);
1481 #endif
1482                 path_build(savefile, sizeof(savefile), ANGBAND_DIR_SAVE, temp);
1483         }
1484
1485         if (current_world_ptr->character_generated && !streq(old_player_base, creature_ptr->base_name))
1486         {
1487                 autopick_load_pref(creature_ptr, FALSE);
1488         }
1489 }
1490
1491
1492 /*!
1493  * @brief プレイヤーの名前を変更するコマンドのメインルーチン
1494  * Gets a name for the character, reacting to name changes.
1495  * @param creature_ptr プレーヤーへの参照ポインタ
1496  * @return なし
1497  * @details
1498  * <pre>
1499  * Assumes that "display_player()" has just been called
1500  * Perhaps we should NOT ask for a name (at "birth()") on
1501  * Unix machines?  XXX XXX
1502  * What a horrible name for a global function.
1503  * </pre>
1504  */
1505 void get_name(player_type *creature_ptr)
1506 {
1507         char tmp[64];
1508         strcpy(tmp, creature_ptr->name);
1509
1510         if (get_string(_("キャラクターの名前を入力して下さい: ", "Enter a name for your character: "), tmp, 15))
1511         {
1512                 strcpy(creature_ptr->name, tmp);
1513         }
1514
1515         if (strlen(creature_ptr->name) == 0)
1516         {
1517                 strcpy(creature_ptr->name, "PLAYER");
1518         }
1519
1520         strcpy(tmp, ap_ptr->title);
1521 #ifdef JP
1522         if (ap_ptr->no == 1)
1523                 strcat(tmp, "の");
1524 #else
1525         strcat(tmp, " ");
1526 #endif
1527         strcat(tmp, creature_ptr->name);
1528
1529         Term_erase(34, 1, 255);
1530         c_put_str(TERM_L_BLUE, tmp, 1, 34);
1531         clear_from(22);
1532 }
1533
1534
1535 /*!
1536  * @brief セーブするコマンドのメインルーチン
1537  * Save the game
1538  * @param creature_ptr プレーヤーへの参照ポインタ
1539  * @param is_autosave オートセーブ中の処理ならばTRUE
1540  * @return なし
1541  * @details
1542  */
1543 void do_cmd_save_game(player_type *creature_ptr, int is_autosave)
1544 {
1545         if (is_autosave)
1546         {
1547                 msg_print(_("自動セーブ中", "Autosaving the game..."));
1548         }
1549         else
1550         {
1551                 disturb(creature_ptr, TRUE, TRUE);
1552         }
1553
1554         msg_print(NULL);
1555         handle_stuff(creature_ptr);
1556         prt(_("ゲームをセーブしています...", "Saving game..."), 0, 0);
1557         Term_fresh();
1558         (void)strcpy(creature_ptr->died_from, _("(セーブ)", "(saved)"));
1559         signals_ignore_tstp();
1560         if (save_player(creature_ptr))
1561         {
1562                 prt(_("ゲームをセーブしています... 終了", "Saving game... done."), 0, 0);
1563         }
1564         else
1565         {
1566                 prt(_("ゲームをセーブしています... 失敗!", "Saving game... failed!"), 0, 0);
1567         }
1568
1569         signals_handle_tstp();
1570         Term_fresh();
1571         (void)strcpy(creature_ptr->died_from, _("(元気に生きている)", "(alive and well)"));
1572         current_world_ptr->is_loading_now = FALSE;
1573         update_creature(creature_ptr);
1574         mproc_init(creature_ptr->current_floor_ptr);
1575         current_world_ptr->is_loading_now = TRUE;
1576 }
1577
1578
1579 /*!
1580  * @brief セーブ後にゲーム中断フラグを立てる/
1581  * Save the game and exit
1582  * @return なし
1583  * @details
1584  */
1585 void do_cmd_save_and_exit(player_type *creature_ptr)
1586 {
1587         creature_ptr->playing = FALSE;
1588         creature_ptr->leaving = TRUE;
1589         exe_write_diary(creature_ptr, DIARY_GAMESTART, 0, _("----ゲーム中断----", "---- Save and Exit Game ----"));
1590 }
1591
1592
1593 /*!
1594  * @brief 異常発生時のゲーム緊急終了処理 /
1595  * Handle abrupt death of the visual system
1596  * @param creature_ptr プレーヤーへの参照ポインタ
1597  * @return なし
1598  * @details
1599  * This routine is called only in very rare situations, and only
1600  * by certain visual systems, when they experience fatal errors.
1601  */
1602 void exit_game_panic(player_type *creature_ptr)
1603 {
1604         if (!current_world_ptr->character_generated || current_world_ptr->character_saved)
1605                 quit(_("緊急事態", "panic"));
1606         msg_flag = FALSE;
1607
1608         prt("", 0, 0);
1609         disturb(creature_ptr, TRUE, TRUE);
1610         if (creature_ptr->chp < 0) creature_ptr->is_dead = FALSE;
1611
1612         creature_ptr->panic_save = 1;
1613         signals_ignore_tstp();
1614         (void)strcpy(creature_ptr->died_from, _("(緊急セーブ)", "(panic save)"));
1615         if (!save_player(creature_ptr)) quit(_("緊急セーブ失敗!", "panic save failed!"));
1616         quit(_("緊急セーブ成功!", "panic save succeeded!"));
1617 }
1618
1619
1620 /*!
1621  * @brief ファイルからランダムに行を一つ取得する /
1622  * Get a random line from a file
1623  * @param file_name ファイル名
1624  * @param entry 特定条件時のN:タグヘッダID
1625  * @param output 出力先の文字列参照ポインタ
1626  * @return エラーコード
1627  * @details
1628  * <pre>
1629  * Based on the monster speech patch by Matt Graham,
1630  * </pre>
1631  */
1632 errr get_rnd_line(concptr file_name, int entry, char *output)
1633 {
1634         char buf[1024];
1635         path_build(buf, sizeof(buf), ANGBAND_DIR_FILE, file_name);
1636         FILE *fp;
1637         fp = my_fopen(buf, "r");
1638         if (!fp) return -1;
1639
1640         int test;
1641         int line_num = 0;
1642         while (TRUE)
1643         {
1644                 if (my_fgets(fp, buf, sizeof(buf)) != 0)
1645                 {
1646                         my_fclose(fp);
1647                         return -1;
1648                 }
1649
1650                 line_num++;
1651                 if ((buf[0] != 'N') || (buf[1] != ':')) continue;
1652
1653                 if (buf[2] == '*')
1654                 {
1655                         break;
1656                 }
1657                 else if (buf[2] == 'M')
1658                 {
1659                         if (r_info[entry].flags1 & RF1_MALE) break;
1660                 }
1661                 else if (buf[2] == 'F')
1662                 {
1663                         if (r_info[entry].flags1 & RF1_FEMALE) break;
1664                 }
1665                 else if (sscanf(&(buf[2]), "%d", &test) != EOF)
1666                 {
1667                         if (test == entry) break;
1668                 }
1669
1670                 msg_format("Error in line %d of %s!", line_num, file_name);
1671                 my_fclose(fp);
1672                 return -1;
1673         }
1674
1675         int counter;
1676         for (counter = 0; ; counter++)
1677         {
1678                 while (TRUE)
1679                 {
1680                         test = my_fgets(fp, buf, sizeof(buf));
1681                         if (!test)
1682                         {
1683                                 /* Ignore lines starting with 'N:' */
1684                                 if ((buf[0] == 'N') && (buf[1] == ':')) continue;
1685
1686                                 if (buf[0] != '#') break;
1687                         }
1688                         else break;
1689                 }
1690
1691                 if (!buf[0]) break;
1692
1693                 if (one_in_(counter + 1)) strcpy(output, buf);
1694         }
1695
1696         my_fclose(fp);
1697         return counter ? 0 : -1;
1698 }
1699
1700
1701 #ifdef JP
1702 /*!
1703  * @brief ファイルからランダムに行を一つ取得する(日本語文字列のみ) /
1704  * @param file_name ファイル名
1705  * @param entry 特定条件時のN:タグヘッダID
1706  * @param output 出力先の文字列参照ポインタ
1707  * @param count 試行回数
1708  * @return エラーコード
1709  * @details
1710  */
1711 errr get_rnd_line_jonly(concptr file_name, int entry, char *output, int count)
1712 {
1713         errr result = 1;
1714         for (int i = 0; i < count; i++)
1715         {
1716                 result = get_rnd_line(file_name, entry, output);
1717                 if (result) break;
1718                 bool kanji = FALSE;
1719                 for (int j = 0; output[j]; j++) kanji |= iskanji(output[j]);
1720                 if (kanji) break;
1721         }
1722
1723         return result;
1724 }
1725 #endif
1726
1727
1728 /*!
1729  * @brief 自動拾いファイルを読み込む /
1730  * @param creature_ptr プレーヤーへの参照ポインタ
1731  * @param name ファイル名
1732  * @details
1733  */
1734 errr process_autopick_file(player_type *creature_ptr, concptr name)
1735 {
1736         char buf[1024];
1737         path_build(buf, sizeof(buf), ANGBAND_DIR_USER, name);
1738         errr err = process_pref_file_aux(creature_ptr, buf, PREF_TYPE_AUTOPICK);
1739         return err;
1740 }
1741
1742
1743 /*!
1744  * @brief プレイヤーの生い立ちファイルを読み込む /
1745  * Process file for player's history editor.
1746  * @param creature_ptr プレーヤーへの参照ポインタ
1747  * @param name ファイル名
1748  * @return エラーコード
1749  * @details
1750  */
1751 errr process_histpref_file(player_type *creature_ptr, concptr name)
1752 {
1753         bool old_character_xtra = current_world_ptr->character_xtra;
1754         char buf[1024];
1755         path_build(buf, sizeof(buf), ANGBAND_DIR_USER, name);
1756
1757         /* Hack -- prevent modification birth options in this file */
1758         current_world_ptr->character_xtra = TRUE;
1759         errr err = process_pref_file_aux(creature_ptr, buf, PREF_TYPE_HISTPREF);
1760         current_world_ptr->character_xtra = old_character_xtra;
1761         return err;
1762 }
1763
1764
1765 /*!
1766  * @brief ファイル位置をシーク /
1767  * @param creature_ptr プレーヤーへの参照ポインタ
1768  * @param fd ファイルディスクリプタ
1769  * @param where ファイルバイト位置
1770  * @param flag FALSEならば現ファイルを超えた位置へシーク時エラー、TRUEなら足りない間を0で埋め尽くす
1771  * @return エラーコード
1772  * @details
1773  */
1774 static errr counts_seek(player_type *creature_ptr, int fd, u32b where, bool flag)
1775 {
1776         char temp1[128], temp2[128];
1777 #ifdef SAVEFILE_USE_UID
1778         (void)sprintf(temp1, "%d.%s.%d%d%d", creature_ptr->player_uid, savefile_base, creature_ptr->pclass, creature_ptr->pseikaku, creature_ptr->age);
1779 #else
1780         (void)sprintf(temp1, "%s.%d%d%d", savefile_base, creature_ptr->pclass, creature_ptr->pseikaku, creature_ptr->age);
1781 #endif
1782         for (int i = 0; temp1[i]; i++)
1783                 temp1[i] ^= (i + 1) * 63;
1784
1785         int seekpoint = 0;
1786         u32b zero_header[3] = { 0L, 0L, 0L };
1787         while (TRUE)
1788         {
1789                 if (fd_seek(fd, seekpoint + 3 * sizeof(u32b)))
1790                         return 1;
1791                 if (fd_read(fd, (char*)(temp2), sizeof(temp2)))
1792                 {
1793                         if (!flag)
1794                                 return 1;
1795                         /* add new name */
1796                         fd_seek(fd, seekpoint);
1797                         fd_write(fd, (char*)zero_header, 3 * sizeof(u32b));
1798                         fd_write(fd, (char*)(temp1), sizeof(temp1));
1799                         break;
1800                 }
1801
1802                 if (strcmp(temp1, temp2) == 0)
1803                         break;
1804
1805                 seekpoint += 128 + 3 * sizeof(u32b);
1806         }
1807
1808         return fd_seek(fd, seekpoint + where * sizeof(u32b));
1809 }
1810
1811
1812 /*!
1813  * @brief ファイル位置を読み込む
1814  * @param creature_ptr プレーヤーへの参照ポインタ
1815  * @param where ファイルバイト位置
1816  * @return エラーコード
1817  * @details
1818  */
1819 u32b counts_read(player_type *creature_ptr, int where)
1820 {
1821         char buf[1024];
1822         path_build(buf, sizeof(buf), ANGBAND_DIR_DATA, _("z_info_j.raw", "z_info.raw"));
1823         int fd = fd_open(buf, O_RDONLY);
1824
1825         u32b count = 0;
1826         if (counts_seek(creature_ptr, fd, where, FALSE) ||
1827                 fd_read(fd, (char*)(&count), sizeof(u32b)))
1828                 count = 0;
1829
1830         (void)fd_close(fd);
1831
1832         return count;
1833 }
1834
1835
1836 /*!
1837  * @brief ファイル位置に書き込む /
1838  * @param creature_ptr プレーヤーへの参照ポインタ
1839  * @param where ファイルバイト位置
1840  * @param count 書き込む値
1841  * @return エラーコード
1842  * @details
1843  */
1844 errr counts_write(player_type *creature_ptr, int where, u32b count)
1845 {
1846         char buf[1024];
1847         path_build(buf, sizeof(buf), ANGBAND_DIR_DATA, _("z_info_j.raw", "z_info.raw"));
1848
1849         safe_setuid_grab();
1850         int fd = fd_open(buf, O_RDWR);
1851         safe_setuid_drop();
1852         if (fd < 0)
1853         {
1854                 FILE_TYPE(FILE_TYPE_DATA);
1855                 safe_setuid_grab();
1856                 fd = fd_make(buf, 0644);
1857                 safe_setuid_drop();
1858         }
1859
1860         safe_setuid_grab();
1861         errr err = fd_lock(fd, F_WRLCK);
1862         safe_setuid_drop();
1863         if (err) return 1;
1864
1865         counts_seek(creature_ptr, fd, where, TRUE);
1866         fd_write(fd, (char*)(&count), sizeof(u32b));
1867         safe_setuid_grab();
1868         err = fd_lock(fd, F_UNLCK);
1869         safe_setuid_drop();
1870
1871         if (err) return 1;
1872
1873         (void)fd_close(fd);
1874         return 0;
1875 }
1876
1877
1878 /*!
1879  * @brief 墓のアスキーアートテンプレを読み込む
1880  * @param buf テンプレへのバッファ
1881  * @param buf_size バッファの長さ
1882  * @return なし
1883  */
1884 void read_dead_file(char *buf, size_t buf_size)
1885 {
1886         path_build(buf, buf_size, ANGBAND_DIR_FILE, _("dead_j.txt", "dead.txt"));
1887
1888         FILE *fp;
1889         fp = my_fopen(buf, "r");
1890         if (!fp) return;
1891
1892         int i = 0;
1893         while (my_fgets(fp, buf, buf_size) == 0)
1894         {
1895                 put_str(buf, i++, 0);
1896         }
1897
1898         my_fclose(fp);
1899 }