OSDN Git Service

Merge pull request #716 from sikabane-works/release/3.0.0Alpha16
[hengbandforosx/hengbandosx.git] / src / io / read-pref-file.cpp
1 /*
2  * @brief プレイヤーのインターフェイスに関するコマンドの実装 / Interface commands
3  * @date 2020/03/01
4  * @author Mogami & Hourier
5  * -Mogami-
6  * remove_auto_dump(orig_file, mark)
7  *     Remove the old automatic dump of type "mark".
8  * auto_dump_printf(fmt, ...)
9  *     Dump a formatted string using fprintf().
10  * open_auto_dump(buf, mark)
11  *     Open a file, remove old dump, and add new header.
12  * close_auto_dump(void)
13  *     Add a footer, and close the file.
14  */
15
16 #include "io/read-pref-file.h"
17 #include "autopick/autopick-pref-processor.h"
18 #include "autopick/autopick-reader-writer.h"
19 #include "core/asking-player.h"
20 #include "io-dump/dump-remover.h"
21 #include "io/files-util.h"
22 #include "io/interpret-pref-file.h"
23 #include "io/pref-file-expressor.h"
24 #include "player/player-class.h"
25 #include "player/player-race.h"
26 #include "realm/realm-names-table.h"
27 #include "system/system-variables.h"
28 #include "util/angband-files.h"
29 #include "util/buffer-shaper.h"
30 #include "view/display-messages.h"
31 #include "world/world.h"
32
33 //!< @todo コールバック関数に変更するので、いずれ消す.
34 #define PREF_TYPE_NORMAL 0
35 #define PREF_TYPE_AUTOPICK 1
36 #define PREF_TYPE_HISTPREF 2
37
38 char auto_dump_header[] = "# vvvvvvv== %s ==vvvvvvv";
39 char auto_dump_footer[] = "# ^^^^^^^== %s ==^^^^^^^";
40
41 // Mark strings for auto dump
42
43 // Variables for auto dump
44 static int auto_dump_line_num;
45
46 /*!
47  * @brief process_pref_fileのサブルーチン /
48  * Open the "user pref file" and parse it.
49  * @param creature_ptr プレーヤーへの参照ポインタ
50  * @param name 読み込むファイル名
51  * @param preftype prefファイルのタイプ
52  * @return エラーコード
53  * @todo 関数名を変更する
54  */
55 static errr process_pref_file_aux(player_type *creature_ptr, concptr name, int preftype, void (*process_autopick_file_command)(char *))
56 {
57     FILE *fp;
58     fp = angband_fopen(name, "r");
59     if (!fp)
60         return -1;
61
62     int line = -1;
63     errr err = 0;
64     bool bypass = FALSE;
65     while (angband_fgets(fp, file_read__buf, FILE_READ_BUFF_SIZE) == 0) {
66         line++;
67         if (!file_read__buf[0])
68             continue;
69
70 #ifdef JP
71         if (!iskanji(file_read__buf[0]))
72 #endif
73             if (iswspace(file_read__buf[0]))
74                 continue;
75
76         if (file_read__buf[0] == '#')
77             continue;
78         strcpy(file_read__swp, file_read__buf);
79
80         /* Process "?:<expr>" */
81         if ((file_read__buf[0] == '?') && (file_read__buf[1] == ':')) {
82             char f;
83             char *s;
84             s = file_read__buf + 2;
85             concptr v = process_pref_file_expr(creature_ptr, &s, &f);
86             bypass = streq(v, "0");
87             continue;
88         }
89
90         if (bypass)
91             continue;
92
93         /* Process "%:<file>" */
94         if (file_read__buf[0] == '%') {
95             static int depth_count = 0;
96             if (depth_count > 20)
97                 continue;
98
99             depth_count++;
100             switch (preftype) {
101             case PREF_TYPE_AUTOPICK:
102                 (void)process_autopick_file(creature_ptr, file_read__buf + 2, process_autopick_file_command);
103                 break;
104             case PREF_TYPE_HISTPREF:
105                 (void)process_histpref_file(creature_ptr, file_read__buf + 2, process_autopick_file_command);
106                 break;
107             default:
108                 (void)process_pref_file(creature_ptr, file_read__buf + 2, process_autopick_file_command);
109                 break;
110             }
111
112             depth_count--;
113             continue;
114         }
115
116         err = interpret_pref_file(creature_ptr, file_read__buf);
117         if (err != 0) {
118             if (preftype != PREF_TYPE_AUTOPICK)
119                 break;
120
121             (*process_autopick_file_command)(file_read__buf);
122             err = 0;
123         }
124     }
125
126     if (err != 0) {
127         /* Print error message */
128         /* ToDo: Add better error messages */
129         msg_format(_("ファイル'%s'の%d行でエラー番号%dのエラー。", "Error %d in line %d of file '%s'."), _(name, err), line, _(err, name));
130         msg_format(_("('%s'を解析中)", "Parsing '%s'"), file_read__swp);
131         msg_print(NULL);
132     }
133
134     angband_fclose(fp);
135     return (err);
136 }
137
138 /*!
139  * @brief pref設定ファイルを読み込み設定を反映させる /
140  * Process the "user pref file" with the given name
141  * @param creature_ptr プレーヤーへの参照ポインタ
142  * @param name 読み込むファイル名
143  * @return エラーコード
144  * @details
145  * <pre>
146  * See the functions above for a list of legal "commands".
147  * We also accept the special "?" and "%" directives, which
148  * allow conditional evaluation and filename inclusion.
149  * </pre>
150  */
151 errr process_pref_file(player_type *creature_ptr, concptr name, void (*process_autopick_file_command)(char *))
152 {
153     char buf[1024];
154     path_build(buf, sizeof(buf), ANGBAND_DIR_PREF, name);
155
156     errr err1 = process_pref_file_aux(creature_ptr, buf, PREF_TYPE_NORMAL, process_autopick_file_command);
157     if (err1 > 0)
158         return err1;
159
160     path_build(buf, sizeof(buf), ANGBAND_DIR_USER, name);
161     errr err2 = process_pref_file_aux(creature_ptr, buf, PREF_TYPE_NORMAL, process_autopick_file_command);
162     if (err2 < 0 && !err1)
163         return -2;
164
165     return err2;
166 }
167
168 /*!
169  * @brief 自動拾いファイルを読み込む /
170  * @param creature_ptr プレーヤーへの参照ポインタ
171  * @param name ファイル名
172  * @details
173  */
174 errr process_autopick_file(player_type *creature_ptr, concptr name, void (*process_autopick_file_command)(char *))
175 {
176     char buf[1024];
177     path_build(buf, sizeof(buf), ANGBAND_DIR_USER, name);
178     errr err = process_pref_file_aux(creature_ptr, buf, PREF_TYPE_AUTOPICK, process_autopick_file_command);
179     return err;
180 }
181
182 /*!
183  * @brief プレイヤーの生い立ちファイルを読み込む /
184  * Process file for player's history editor.
185  * @param creature_ptr プレーヤーへの参照ポインタ
186  * @param name ファイル名
187  * @return エラーコード
188  * @details
189  */
190 errr process_histpref_file(player_type *creature_ptr, concptr name, void (*process_autopick_file_command)(char *))
191 {
192     bool old_character_xtra = current_world_ptr->character_xtra;
193     char buf[1024];
194     path_build(buf, sizeof(buf), ANGBAND_DIR_USER, name);
195
196     /* Hack -- prevent modification birth options in this file */
197     current_world_ptr->character_xtra = TRUE;
198     errr err = process_pref_file_aux(creature_ptr, buf, PREF_TYPE_HISTPREF, process_autopick_file_command);
199     current_world_ptr->character_xtra = old_character_xtra;
200     return err;
201 }
202
203 /*!
204  * @brief prfファイルのフォーマットに従った内容を出力する /
205  * Dump a formatted line, using "vstrnfmt()".
206  * @param fmt 出力内容
207  */
208 void auto_dump_printf(FILE *auto_dump_stream, concptr fmt, ...)
209 {
210     va_list vp;
211     char buf[1024];
212     va_start(vp, fmt);
213     (void)vstrnfmt(buf, sizeof(buf), fmt, vp);
214     va_end(vp);
215     for (concptr p = buf; *p; p++) {
216         if (*p == '\n')
217             auto_dump_line_num++;
218     }
219
220     fprintf(auto_dump_stream, "%s", buf);
221 }
222
223 /*!
224  * @brief prfファイルをファイルオープンする /
225  * Open file to append auto dump.
226  * @param buf ファイル名
227  * @param mark 出力するヘッダマーク
228  * @return ファイルポインタを取得できたらTRUEを返す
229  */
230 bool open_auto_dump(FILE **fpp, concptr buf, concptr mark)
231 {
232     char header_mark_str[80];
233     concptr auto_dump_mark = mark;
234     sprintf(header_mark_str, auto_dump_header, auto_dump_mark);
235     remove_auto_dump(buf, mark);
236     *fpp = angband_fopen(buf, "a");
237     if (!fpp) {
238         msg_format(_("%s を開くことができませんでした。", "Failed to open %s."), buf);
239         msg_print(NULL);
240         return FALSE;
241     }
242
243     fprintf(*fpp, "%s\n", header_mark_str);
244     auto_dump_line_num = 0;
245     auto_dump_printf(*fpp, _("# *警告!!* 以降の行は自動生成されたものです。\n", "# *Warning!*  The lines below are an automatic dump.\n"));
246     auto_dump_printf(
247         *fpp, _("# *警告!!* 後で自動的に削除されるので編集しないでください。\n", "# Don't edit them; changes will be deleted and replaced automatically.\n"));
248     return TRUE;
249 }
250
251 /*!
252  * @brief prfファイルをファイルクローズする /
253  * Append foot part and close auto dump.
254  * @return なし
255  */
256 void close_auto_dump(FILE **fpp, concptr auto_dump_mark)
257 {
258     char footer_mark_str[80];
259     sprintf(footer_mark_str, auto_dump_footer, auto_dump_mark);
260     auto_dump_printf(*fpp, _("# *警告!!* 以降の行は自動生成されたものです。\n", "# *Warning!*  The lines below are an automatic dump.\n"));
261     auto_dump_printf(
262         *fpp, _("# *警告!!* 後で自動的に削除されるので編集しないでください。\n", "# Don't edit them; changes will be deleted and replaced automatically.\n"));
263     fprintf(*fpp, "%s (%d)\n", footer_mark_str, auto_dump_line_num);
264     angband_fclose(*fpp);
265 }
266
267 /*!
268  * @brief 全ユーザプロファイルをロードする / Load some "user pref files"
269  * @paaram player_ptr プレーヤーへの参照ポインタ
270  * @return なし
271  * @note
272  * Modified by Arcum Dagsson to support
273  * separate macro files for different realms.
274  */
275 void load_all_pref_files(player_type *player_ptr)
276 {
277     char buf[1024];
278     sprintf(buf, "user.prf");
279     process_pref_file(player_ptr, buf, process_autopick_file_command);
280     sprintf(buf, "user-%s.prf", ANGBAND_SYS);
281     process_pref_file(player_ptr, buf, process_autopick_file_command);
282     sprintf(buf, "%s.prf", rp_ptr->title);
283     process_pref_file(player_ptr, buf, process_autopick_file_command);
284     sprintf(buf, "%s.prf", cp_ptr->title);
285     process_pref_file(player_ptr, buf, process_autopick_file_command);
286     sprintf(buf, "%s.prf", player_ptr->base_name);
287     process_pref_file(player_ptr, buf, process_autopick_file_command);
288     if (player_ptr->realm1 != REALM_NONE && player_ptr->pclass != CLASS_ELEMENTALIST) {
289         sprintf(buf, "%s.prf", realm_names[player_ptr->realm1]);
290         process_pref_file(player_ptr, buf, process_autopick_file_command);
291     }
292
293     if (player_ptr->realm2 != REALM_NONE) {
294         sprintf(buf, "%s.prf", realm_names[player_ptr->realm2]);
295         process_pref_file(player_ptr, buf, process_autopick_file_command);
296     }
297
298     autopick_load_pref(player_ptr, FALSE);
299 }
300
301 /*!
302  * @brief 生い立ちメッセージをファイルからロードする。
303  * @return なし
304  */
305 bool read_histpref(player_type *creature_ptr, void (*process_autopick_file_command)(char *))
306 {
307     char buf[80];
308     errr err;
309     int i, j, n;
310     char *s, *t;
311     char temp[64 * 4];
312     char histbuf[HISTPREF_LIMIT];
313
314     if (!get_check(_("生い立ち設定ファイルをロードしますか? ", "Load background history preference file? ")))
315         return FALSE;
316
317     histbuf[0] = '\0';
318     histpref_buf = histbuf;
319
320     sprintf(buf, _("histedit-%s.prf", "histpref-%s.prf"), creature_ptr->base_name);
321     err = process_histpref_file(creature_ptr, buf, process_autopick_file_command);
322
323     if (0 > err) {
324         strcpy(buf, _("histedit.prf", "histpref.prf"));
325         err = process_histpref_file(creature_ptr, buf, process_autopick_file_command);
326     }
327
328     if (err) {
329         msg_print(_("生い立ち設定ファイルの読み込みに失敗しました。", "Failed to load background history preference."));
330         msg_print(NULL);
331         histpref_buf = NULL;
332         return FALSE;
333     } else if (!histpref_buf[0]) {
334         msg_print(_("有効な生い立ち設定はこのファイルにありません。", "There does not exist valid background history preference."));
335         msg_print(NULL);
336         histpref_buf = NULL;
337         return FALSE;
338     }
339
340     for (i = 0; i < 4; i++)
341         creature_ptr->history[i][0] = '\0';
342
343     /* loop */
344     for (s = histpref_buf; *s == ' '; s++)
345         ;
346
347     n = strlen(s);
348     while ((n > 0) && (s[n - 1] == ' '))
349         s[--n] = '\0';
350
351     shape_buffer(s, 60, temp, sizeof(temp));
352     t = temp;
353     for (i = 0; i < 4; i++) {
354         if (t[0] == 0)
355             break;
356         else {
357             strcpy(creature_ptr->history[i], t);
358             t += strlen(t) + 1;
359         }
360     }
361
362     for (i = 0; i < 4; i++) {
363         /* loop */
364         for (j = 0; creature_ptr->history[i][j]; j++)
365             ;
366
367         for (; j < 59; j++)
368             creature_ptr->history[i][j] = ' ';
369         creature_ptr->history[i][59] = '\0';
370     }
371
372     histpref_buf = NULL;
373     return TRUE;
374 }