OSDN Git Service

[Refactor] #1489 Moved player-class.* and player-class-types.h to player-info/
[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-info/class-info.h"
25 #include "player-info/race-info.h"
26 #include "realm/realm-names-table.h"
27 #include "system/player-type-definition.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)
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);
103                 break;
104             case PREF_TYPE_HISTPREF:
105                 (void)process_histpref_file(creature_ptr, file_read__buf + 2);
106                 break;
107             default:
108                 (void)process_pref_file(creature_ptr, file_read__buf + 2);
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(nullptr);
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  * @param only_user_dir trueを指定するとANGBAND_DIR_USERからの読み込みのみ行う
144  * @return エラーコード
145  * @details
146  * <pre>
147  * See the functions above for a list of legal "commands".
148  * We also accept the special "?" and "%" directives, which
149  * allow conditional evaluation and filename inclusion.
150  * </pre>
151  */
152 errr process_pref_file(player_type *creature_ptr, concptr name, bool only_user_dir)
153 {
154     char buf[1024];
155     errr err1 = 0;
156     if (!only_user_dir) {
157         path_build(buf, sizeof(buf), ANGBAND_DIR_PREF, name);
158
159         err1 = process_pref_file_aux(creature_ptr, buf, PREF_TYPE_NORMAL);
160         if (err1 > 0)
161             return err1;
162     }
163
164     path_build(buf, sizeof(buf), ANGBAND_DIR_USER, name);
165     errr err2 = process_pref_file_aux(creature_ptr, buf, PREF_TYPE_NORMAL);
166     if (err2 < 0 && !err1)
167         return -2;
168
169     return err2;
170 }
171
172 /*!
173  * @brief 自動拾いファイルを読み込む /
174  * @param creature_ptr プレーヤーへの参照ポインタ
175  * @param name ファイル名
176  * @details
177  */
178 errr process_autopick_file(player_type *creature_ptr, concptr name)
179 {
180     char buf[1024];
181     path_build(buf, sizeof(buf), ANGBAND_DIR_USER, name);
182     errr err = process_pref_file_aux(creature_ptr, buf, PREF_TYPE_AUTOPICK);
183     return err;
184 }
185
186 /*!
187  * @brief プレイヤーの生い立ちファイルを読み込む /
188  * Process file for player's history editor.
189  * @param creature_ptr プレーヤーへの参照ポインタ
190  * @param name ファイル名
191  * @return エラーコード
192  * @details
193  */
194 errr process_histpref_file(player_type *creature_ptr, concptr name)
195 {
196     bool old_character_xtra = current_world_ptr->character_xtra;
197     char buf[1024];
198     path_build(buf, sizeof(buf), ANGBAND_DIR_USER, name);
199
200     /* Hack -- prevent modification birth options in this file */
201     current_world_ptr->character_xtra = true;
202     errr err = process_pref_file_aux(creature_ptr, buf, PREF_TYPE_HISTPREF);
203     current_world_ptr->character_xtra = old_character_xtra;
204     return err;
205 }
206
207 /*!
208  * @brief prfファイルのフォーマットに従った内容を出力する /
209  * Dump a formatted line, using "vstrnfmt()".
210  * @param fmt 出力内容
211  */
212 void auto_dump_printf(FILE *auto_dump_stream, concptr fmt, ...)
213 {
214     va_list vp;
215     char buf[1024];
216     va_start(vp, fmt);
217     (void)vstrnfmt(buf, sizeof(buf), fmt, vp);
218     va_end(vp);
219     for (concptr p = buf; *p; p++) {
220         if (*p == '\n')
221             auto_dump_line_num++;
222     }
223
224     fprintf(auto_dump_stream, "%s", buf);
225 }
226
227 /*!
228  * @brief prfファイルをファイルオープンする /
229  * Open file to append auto dump.
230  * @param buf ファイル名
231  * @param mark 出力するヘッダマーク
232  * @return ファイルポインタを取得できたらTRUEを返す
233  */
234 bool open_auto_dump(FILE **fpp, concptr buf, concptr mark)
235 {
236     char header_mark_str[80];
237     concptr auto_dump_mark = mark;
238     sprintf(header_mark_str, auto_dump_header, auto_dump_mark);
239     remove_auto_dump(buf, mark);
240     *fpp = angband_fopen(buf, "a");
241     if (!fpp) {
242         msg_format(_("%s を開くことができませんでした。", "Failed to open %s."), buf);
243         msg_print(nullptr);
244         return false;
245     }
246
247     fprintf(*fpp, "%s\n", header_mark_str);
248     auto_dump_line_num = 0;
249     auto_dump_printf(*fpp, _("# *警告!!* 以降の行は自動生成されたものです。\n", "# *Warning!*  The lines below are an automatic dump.\n"));
250     auto_dump_printf(
251         *fpp, _("# *警告!!* 後で自動的に削除されるので編集しないでください。\n", "# Don't edit them; changes will be deleted and replaced automatically.\n"));
252     return true;
253 }
254
255 /*!
256  * @brief prfファイルをファイルクローズする /
257  * Append foot part and close auto dump.
258  */
259 void close_auto_dump(FILE **fpp, concptr auto_dump_mark)
260 {
261     char footer_mark_str[80];
262     sprintf(footer_mark_str, auto_dump_footer, auto_dump_mark);
263     auto_dump_printf(*fpp, _("# *警告!!* 以降の行は自動生成されたものです。\n", "# *Warning!*  The lines below are an automatic dump.\n"));
264     auto_dump_printf(
265         *fpp, _("# *警告!!* 後で自動的に削除されるので編集しないでください。\n", "# Don't edit them; changes will be deleted and replaced automatically.\n"));
266     fprintf(*fpp, "%s (%d)\n", footer_mark_str, auto_dump_line_num);
267     angband_fclose(*fpp);
268 }
269
270 /*!
271  * @brief 全ユーザプロファイルをロードする / Load some "user pref files"
272  * @paaram player_ptr プレーヤーへの参照ポインタ
273  * @note
274  * Modified by Arcum Dagsson to support
275  * separate macro files for different realms.
276  */
277 void load_all_pref_files(player_type *player_ptr)
278 {
279     char buf[1024];
280     sprintf(buf, "user.prf");
281     process_pref_file(player_ptr, buf);
282     sprintf(buf, "user-%s.prf", ANGBAND_SYS);
283     process_pref_file(player_ptr, buf);
284     sprintf(buf, "%s.prf", rp_ptr->title);
285     process_pref_file(player_ptr, buf);
286     sprintf(buf, "%s.prf", cp_ptr->title);
287     process_pref_file(player_ptr, buf);
288     sprintf(buf, "%s.prf", player_ptr->base_name);
289     process_pref_file(player_ptr, buf);
290     if (player_ptr->realm1 != REALM_NONE) {
291         sprintf(buf, "%s.prf", realm_names[player_ptr->realm1]);
292         process_pref_file(player_ptr, buf);
293     }
294
295     if (player_ptr->realm2 != REALM_NONE) {
296         sprintf(buf, "%s.prf", realm_names[player_ptr->realm2]);
297         process_pref_file(player_ptr, buf);
298     }
299
300     autopick_load_pref(player_ptr, false);
301 }
302
303 /*!
304  * @brief 生い立ちメッセージをファイルからロードする。
305  */
306 bool read_histpref(player_type *creature_ptr)
307 {
308     char buf[80];
309     errr err;
310     int i, j, n;
311     char *s, *t;
312     char temp[64 * 4];
313     char histbuf[HISTPREF_LIMIT];
314
315     if (!get_check(_("生い立ち設定ファイルをロードしますか? ", "Load background history preference file? ")))
316         return false;
317
318     histbuf[0] = '\0';
319     histpref_buf = histbuf;
320
321     sprintf(buf, _("histedit-%s.prf", "histpref-%s.prf"), creature_ptr->base_name);
322     err = process_histpref_file(creature_ptr, buf);
323
324     if (0 > err) {
325         strcpy(buf, _("histedit.prf", "histpref.prf"));
326         err = process_histpref_file(creature_ptr, buf);
327     }
328
329     if (err) {
330         msg_print(_("生い立ち設定ファイルの読み込みに失敗しました。", "Failed to load background history preference."));
331         msg_print(nullptr);
332         histpref_buf = nullptr;
333         return false;
334     } else if (!histpref_buf[0]) {
335         msg_print(_("有効な生い立ち設定はこのファイルにありません。", "There does not exist valid background history preference."));
336         msg_print(nullptr);
337         histpref_buf = nullptr;
338         return false;
339     }
340
341     for (i = 0; i < 4; i++)
342         creature_ptr->history[i][0] = '\0';
343
344     /* loop */
345     for (s = histpref_buf; *s == ' '; s++)
346         ;
347
348     n = strlen(s);
349     while ((n > 0) && (s[n - 1] == ' '))
350         s[--n] = '\0';
351
352     shape_buffer(s, 60, temp, sizeof(temp));
353     t = temp;
354     for (i = 0; i < 4; i++) {
355         if (t[0] == 0)
356             break;
357         else {
358             strcpy(creature_ptr->history[i], t);
359             t += strlen(t) + 1;
360         }
361     }
362
363     for (i = 0; i < 4; i++) {
364         /* loop */
365         for (j = 0; creature_ptr->history[i][j]; j++)
366             ;
367
368         for (; j < 59; j++)
369             creature_ptr->history[i][j] = ' ';
370         creature_ptr->history[i][59] = '\0';
371     }
372
373     histpref_buf = nullptr;
374     return true;
375 }