OSDN Git Service

Merge remote-tracking branch 'remotes/origin/feature/Fix-Num-Blow' into develop
[hengband/hengband.git] / src / core / show-file.c
1 #include "core/show-file.h"
2 #include "core/asking-player.h"
3 #include "io/files-util.h"
4 #include "io/input-key-acceptor.h"
5 #include "main/sound-of-music.h"
6 #include "system/angband-version.h"
7 #include "term/gameterm.h"
8 #include "term/screen-processor.h"
9 #include "term/term-color-types.h"
10 #include "util/angband-files.h"
11 #include "util/int-char-converter.h"
12 #include "util/string-processor.h"
13 #include "view/display-messages.h"
14
15 /*!
16  * todo 表示とそれ以外を分割する
17  * @brief ファイル内容の一行をコンソールに出力する
18  * Display single line of on-line help file
19  * @param str 出力する文字列
20  * @param cy コンソールの行
21  * @param shower 確認中
22  * @return なし
23  * @details
24  * <pre>
25  * You can insert some special color tag to change text color.
26  * Such as...
27  * WHITETEXT [[[[y|SOME TEXT WHICH IS DISPLAYED IN YELLOW| WHITETEXT
28  * A colored segment is between "[[[[y|" and the last "|".
29  * You can use any single character in place of the "|".
30  * </pre>
31  */
32 static void show_file_aux_line(concptr str, int cy, concptr shower)
33 {
34         char lcstr[1024];
35         if (shower)
36         {
37                 strcpy(lcstr, str);
38                 str_tolower(lcstr);
39         }
40
41         int cx = 0;
42         term_gotoxy(cx, cy);
43
44         static const char tag_str[] = "[[[[";
45         byte color = TERM_WHITE;
46         char in_tag = '\0';
47         for (int i = 0; str[i];)
48         {
49                 int len = strlen(&str[i]);
50                 int showercol = len + 1;
51                 int bracketcol = len + 1;
52                 int endcol = len;
53                 concptr ptr;
54                 if (shower)
55                 {
56                         ptr = angband_strstr(&lcstr[i], shower);
57                         if (ptr) showercol = ptr - &lcstr[i];
58                 }
59
60                 ptr = in_tag ? angband_strchr(&str[i], in_tag) : angband_strstr(&str[i], tag_str);
61                 if (ptr) bracketcol = ptr - &str[i];
62                 if (bracketcol < endcol) endcol = bracketcol;
63                 if (showercol < endcol) endcol = showercol;
64
65                 term_addstr(endcol, color, &str[i]);
66                 cx += endcol;
67                 i += endcol;
68
69                 if (shower && endcol == showercol)
70                 {
71                         int showerlen = strlen(shower);
72                         term_addstr(showerlen, TERM_YELLOW, &str[i]);
73                         cx += showerlen;
74                         i += showerlen;
75                         continue;
76                 }
77
78                 if (endcol != bracketcol) continue;
79
80                 if (in_tag)
81                 {
82                         i++;
83                         in_tag = '\0';
84                         color = TERM_WHITE;
85                         continue;
86                 }
87
88                 i += sizeof(tag_str) - 1;
89                 color = color_char_to_attr(str[i]);
90                 if (color == 255 || str[i + 1] == '\0')
91                 {
92                         color = TERM_WHITE;
93                         term_addstr(-1, TERM_WHITE, tag_str);
94                         cx += sizeof(tag_str) - 1;
95                         continue;
96                 }
97
98                 i++;
99                 in_tag = str[i];
100                 i++;
101         }
102
103         term_erase(cx, cy, 255);
104 }
105
106
107 /*!
108  * todo 表示とそれ以外を分割する
109  * @brief ファイル内容をコンソールに出力する
110  * Recursive file perusal.
111  * @param creature_ptr プレーヤーへの参照ポインタ
112  * @param show_version TRUEならばコンソール上にゲームのバージョンを表示する
113  * @param name ファイル名の文字列
114  * @param what 内容キャプションの文字列
115  * @param line 表示の現在行
116  * @param mode オプション
117  * @return なし
118  * @details
119  * <pre>
120  * Process various special text in the input file, including
121  * the "menu" structures used by the "help file" system.
122  * Return FALSE on 'q' to exit from a deep, otherwise TRUE.
123  * </pre>
124  */
125 bool show_file(player_type *creature_ptr, bool show_version, concptr name, concptr what, int line, BIT_FLAGS mode)
126 {
127         int wid, hgt;
128         term_get_size(&wid, &hgt);
129
130         char finder_str[81];
131         strcpy(finder_str, "");
132
133         char shower_str[81];
134         strcpy(shower_str, "");
135
136         char caption[128];
137         strcpy(caption, "");
138
139         char hook[68][32];
140         for (int i = 0; i < 68; i++)
141         {
142                 hook[i][0] = '\0';
143         }
144
145         char filename[1024];
146         strcpy(filename, name);
147         int n = strlen(filename);
148
149         concptr tag = NULL;
150         for (int i = 0; i < n; i++)
151         {
152                 if (filename[i] == '#')
153                 {
154                         filename[i] = '\0';
155                         tag = filename + i + 1;
156                         break;
157                 }
158         }
159
160         name = filename;
161         FILE *fff = NULL;
162         char path[1024];
163         if (what)
164         {
165                 strcpy(caption, what);
166                 strcpy(path, name);
167                 fff = angband_fopen(path, "r");
168         }
169
170         if (!fff)
171         {
172                 sprintf(caption, _("ヘルプ・ファイル'%s'", "Help file '%s'"), name);
173                 path_build(path, sizeof(path), ANGBAND_DIR_HELP, name);
174                 fff = angband_fopen(path, "r");
175         }
176
177         if (!fff)
178         {
179                 sprintf(caption, _("スポイラー・ファイル'%s'", "Info file '%s'"), name);
180                 path_build(path, sizeof(path), ANGBAND_DIR_INFO, name);
181                 fff = angband_fopen(path, "r");
182         }
183
184         if (!fff)
185         {
186                 path_build(path, sizeof(path), ANGBAND_DIR, name);
187
188                 for (int i = 0; path[i]; i++)
189                         if ('\\' == path[i])
190                                 path[i] = PATH_SEP[0];
191
192                 sprintf(caption, _("スポイラー・ファイル'%s'", "Info file '%s'"), name);
193                 fff = angband_fopen(path, "r");
194         }
195
196         if (!fff)
197         {
198                 msg_format(_("'%s'をオープンできません。", "Cannot open '%s'."), name);
199                 msg_print(NULL);
200
201                 return TRUE;
202         }
203
204         int skey;
205         int next = 0;
206         int size = 0;
207         int back = 0;
208         bool menu = FALSE;
209         char buf[1024];
210         bool reverse = (line < 0);
211         while (TRUE)
212         {
213                 char *str = buf;
214                 if (angband_fgets(fff, buf, sizeof(buf))) break;
215                 if (!prefix(str, "***** "))
216                 {
217                         next++;
218                         continue;
219                 }
220
221                 if ((str[6] == '[') && isalpha(str[7]))
222                 {
223                         int k = str[7] - 'A';
224                         menu = TRUE;
225                         if ((str[8] == ']') && (str[9] == ' '))
226                         {
227                                 strncpy(hook[k], str + 10, 31);
228                                 hook[k][31] = '\0';
229                         }
230
231                         continue;
232                 }
233
234                 if (str[6] != '<') continue;
235
236                 size_t len = strlen(str);
237                 if (str[len - 1] == '>')
238                 {
239                         str[len - 1] = '\0';
240                         if (tag && streq(str + 7, tag)) line = next;
241                 }
242         }
243
244         size = next;
245         int rows = hgt - 4;
246         if (line == -1)
247                 line = ((size - 1) / rows)*rows;
248
249         term_clear();
250
251         concptr find = NULL;
252         while (TRUE)
253         {
254                 if (line >= size - rows)
255                         line = size - rows;
256                 if (line < 0) line = 0;
257
258                 if (next > line)
259                 {
260                         angband_fclose(fff);
261                         fff = angband_fopen(path, "r");
262                         if (!fff) return FALSE;
263
264                         next = 0;
265                 }
266
267                 while (next < line)
268                 {
269                         if (angband_fgets(fff, buf, sizeof(buf))) break;
270                         if (prefix(buf, "***** ")) continue;
271                         next++;
272                 }
273
274                 int row_count = 0;
275                 concptr shower = NULL;
276                 for (int i = 0; i < rows; i++)
277                 {
278                         concptr str = buf;
279                         if (!i) line = next;
280                         if (angband_fgets(fff, buf, sizeof(buf))) break;
281                         if (prefix(buf, "***** ")) continue;
282                         next++;
283                         if (find && !i)
284                         {
285                                 char lc_buf[1024];
286                                 strcpy(lc_buf, str);
287                                 str_tolower(lc_buf);
288                                 if (!angband_strstr(lc_buf, find)) continue;
289                         }
290
291                         find = NULL;
292                         show_file_aux_line(str, i + 2, shower);
293                         row_count++;
294                 }
295
296                 while (row_count < rows)
297                 {
298                         term_erase(0, row_count + 2, 255);
299                         row_count++;
300                 }
301
302                 if (find)
303                 {
304                         bell();
305                         line = back;
306                         find = NULL;
307                         continue;
308                 }
309
310                 if (show_version)
311                 {
312                         prt(format(_("[変愚蛮怒 %d.%d.%d, %s, %d/%d]", "[Hengband %d.%d.%d, %s, Line %d/%d]"),
313                                 FAKE_VER_MAJOR - 10, FAKE_VER_MINOR, FAKE_VER_PATCH,
314                                 caption, line, size), 0, 0);
315                 }
316                 else
317                 {
318                         prt(format(_("[%s, %d/%d]", "[%s, Line %d/%d]"),
319                                 caption, line, size), 0, 0);
320                 }
321
322                 if (size <= rows)
323                 {
324                         prt(_("[キー:(?)ヘルプ (ESC)終了]", "[Press ESC to exit.]"), hgt - 1, 0);
325                 }
326                 else
327                 {
328 #ifdef JP
329                         if (reverse)
330                                 prt("[キー:(RET/スペース)↑ (-)↓ (?)ヘルプ (ESC)終了]", hgt - 1, 0);
331                         else
332                                 prt("[キー:(RET/スペース)↓ (-)↑ (?)ヘルプ (ESC)終了]", hgt - 1, 0);
333 #else
334                         prt("[Press Return, Space, -, =, /, |, or ESC to exit.]", hgt - 1, 0);
335 #endif
336                 }
337
338                 skey = inkey_special(TRUE);
339                 switch (skey)
340                 {
341                 case '?':
342                         if (strcmp(name, _("jhelpinfo.txt", "helpinfo.txt")) != 0)
343                                 show_file(creature_ptr, TRUE, _("jhelpinfo.txt", "helpinfo.txt"), NULL, 0, mode);
344                         break;
345                 case '=':
346                         prt(_("強調: ", "Show: "), hgt - 1, 0);
347
348                         char back_str[81];
349                         strcpy(back_str, shower_str);
350                         if (askfor(shower_str, 80))
351                         {
352                                 if (shower_str[0])
353                                 {
354                                         str_tolower(shower_str);
355                                         shower = shower_str;
356                                 }
357                                 else shower = NULL;
358                         }
359                         else strcpy(shower_str, back_str);
360                         break;
361
362                 case '/':
363                 case KTRL('s'):
364                         prt(_("検索: ", "Find: "), hgt - 1, 0);
365                         strcpy(back_str, finder_str);
366                         if (askfor(finder_str, 80))
367                         {
368                                 if (finder_str[0])
369                                 {
370                                         find = finder_str;
371                                         back = line;
372                                         line = line + 1;
373                                         str_tolower(finder_str);
374                                         shower = finder_str;
375                                 }
376                                 else shower = NULL;
377                         }
378                         else strcpy(finder_str, back_str);
379                         break;
380
381                 case '#':
382                 {
383                         char tmp[81];
384                         prt(_("行: ", "Goto Line: "), hgt - 1, 0);
385                         strcpy(tmp, "0");
386
387                         if (askfor(tmp, 80)) line = atoi(tmp);
388                         break;
389                 }
390
391                 case SKEY_TOP:
392                         line = 0;
393                         break;
394
395                 case SKEY_BOTTOM:
396                         line = ((size - 1) / rows) * rows;
397                         break;
398
399                 case '%':
400                 {
401                         char tmp[81];
402                         prt(_("ファイル・ネーム: ", "Goto File: "), hgt - 1, 0);
403                         strcpy(tmp, _("jhelp.hlp", "help.hlp"));
404
405                         if (askfor(tmp, 80))
406                         {
407                                 if (!show_file(creature_ptr, TRUE, tmp, NULL, 0, mode)) skey = 'q';
408                         }
409
410                         break;
411                 }
412
413                 case '-':
414                         line = line + (reverse ? rows : -rows);
415                         if (line < 0) line = 0;
416                         break;
417
418                 case SKEY_PGUP:
419                         line = line - rows;
420                         if (line < 0) line = 0;
421                         break;
422
423                 case '\n':
424                 case '\r':
425                         line = line + (reverse ? -1 : 1);
426                         if (line < 0) line = 0;
427                         break;
428
429                 case '8':
430                 case SKEY_UP:
431                         line--;
432                         if (line < 0) line = 0;
433                         break;
434
435                 case '2':
436                 case SKEY_DOWN:
437                         line++;
438                         break;
439
440                 case ' ':
441                         line = line + (reverse ? -rows : rows);
442                         if (line < 0) line = 0;
443                         break;
444
445                 case SKEY_PGDOWN:
446                         line = line + rows;
447                         break;
448                 }
449
450                 if (menu)
451                 {
452                         int key = -1;
453                         if (!(skey & SKEY_MASK) && isalpha(skey))
454                                 key = skey - 'A';
455
456                         if ((key > -1) && hook[key][0])
457                         {
458                                 /* Recurse on that file */
459                                 if (!show_file(creature_ptr, TRUE, hook[key], NULL, 0, mode))
460                                         skey = 'q';
461                         }
462                 }
463
464                 if (skey == '|')
465                 {
466                         FILE *ffp;
467                         char buff[1024];
468                         char xtmp[82];
469
470                         strcpy(xtmp, "");
471
472                         if (!get_string(_("ファイル名: ", "File name: "), xtmp, 80)) continue;
473                         angband_fclose(fff);
474                         path_build(buff, sizeof(buff), ANGBAND_DIR_USER, xtmp);
475
476                         /* Hack -- Re-Open the file */
477                         fff = angband_fopen(path, "r");
478
479                         ffp = angband_fopen(buff, "w");
480
481                         if (!(fff && ffp))
482                         {
483                                 msg_print(_("ファイルを開けません。", "Failed to open file."));
484                                 skey = ESCAPE;
485                                 break;
486                         }
487
488                         sprintf(xtmp, "%s: %s", creature_ptr->name, what ? what : caption);
489                         angband_fputs(ffp, xtmp, 80);
490                         angband_fputs(ffp, "\n", 80);
491
492                         while (!angband_fgets(fff, buff, sizeof(buff)))
493                                 angband_fputs(ffp, buff, 80);
494                         angband_fclose(fff);
495                         angband_fclose(ffp);
496                         fff = angband_fopen(path, "r");
497                 }
498
499                 if ((skey == ESCAPE) || (skey == '<')) break;
500
501                 if (skey == KTRL('q')) skey = 'q';
502
503                 if (skey == 'q') break;
504         }
505
506         angband_fclose(fff);
507         return (skey != 'q');
508 }
509
510 /*
511  * Convert string to lower case
512  */
513 void str_tolower(char *str)
514 {
515     for (; *str; str++) {
516 #ifdef JP
517         if (iskanji(*str)) {
518             str++;
519             continue;
520         }
521 #endif
522         *str = (char)tolower(*str);
523     }
524 }