OSDN Git Service

Merge branch 'feature/Fix-Calc-Slaying' 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                                         prt(format(_("[変愚蛮怒 %d.%d.%d, %s, %d/%d]", "[Hengband %d.%d.%d, %s, Line %d/%d]"), FAKE_VER_MAJOR - 10, FAKE_VER_MINOR, FAKE_VER_PATCH,
311                         caption, line, size),
312                     0, 0);
313
314
315                 if (show_version)
316                 {
317                         char title[127];
318                         put_version(title);
319                         prt(format("[%s]", title), 0, 0);
320                 }
321                 else
322                 {
323                         prt(format(_("[%s, %d/%d]", "[%s, Line %d/%d]"),
324                                 caption, line, size), 0, 0);
325                 }
326
327                 if (size <= rows)
328                 {
329                         prt(_("[キー:(?)ヘルプ (ESC)終了]", "[Press ESC to exit.]"), hgt - 1, 0);
330                 }
331                 else
332                 {
333 #ifdef JP
334                         if (reverse)
335                                 prt("[キー:(RET/スペース)↑ (-)↓ (?)ヘルプ (ESC)終了]", hgt - 1, 0);
336                         else
337                                 prt("[キー:(RET/スペース)↓ (-)↑ (?)ヘルプ (ESC)終了]", hgt - 1, 0);
338 #else
339                         prt("[Press Return, Space, -, =, /, |, or ESC to exit.]", hgt - 1, 0);
340 #endif
341                 }
342
343                 skey = inkey_special(TRUE);
344                 switch (skey)
345                 {
346                 case '?':
347                         if (strcmp(name, _("jhelpinfo.txt", "helpinfo.txt")) != 0)
348                                 show_file(creature_ptr, TRUE, _("jhelpinfo.txt", "helpinfo.txt"), NULL, 0, mode);
349                         break;
350                 case '=':
351                         prt(_("強調: ", "Show: "), hgt - 1, 0);
352
353                         char back_str[81];
354                         strcpy(back_str, shower_str);
355                         if (askfor(shower_str, 80))
356                         {
357                                 if (shower_str[0])
358                                 {
359                                         str_tolower(shower_str);
360                                         shower = shower_str;
361                                 }
362                                 else shower = NULL;
363                         }
364                         else strcpy(shower_str, back_str);
365                         break;
366
367                 case '/':
368                 case KTRL('s'):
369                         prt(_("検索: ", "Find: "), hgt - 1, 0);
370                         strcpy(back_str, finder_str);
371                         if (askfor(finder_str, 80))
372                         {
373                                 if (finder_str[0])
374                                 {
375                                         find = finder_str;
376                                         back = line;
377                                         line = line + 1;
378                                         str_tolower(finder_str);
379                                         shower = finder_str;
380                                 }
381                                 else shower = NULL;
382                         }
383                         else strcpy(finder_str, back_str);
384                         break;
385
386                 case '#':
387                 {
388                         char tmp[81];
389                         prt(_("行: ", "Goto Line: "), hgt - 1, 0);
390                         strcpy(tmp, "0");
391
392                         if (askfor(tmp, 80)) line = atoi(tmp);
393                         break;
394                 }
395
396                 case SKEY_TOP:
397                         line = 0;
398                         break;
399
400                 case SKEY_BOTTOM:
401                         line = ((size - 1) / rows) * rows;
402                         break;
403
404                 case '%':
405                 {
406                         char tmp[81];
407                         prt(_("ファイル・ネーム: ", "Goto File: "), hgt - 1, 0);
408                         strcpy(tmp, _("jhelp.hlp", "help.hlp"));
409
410                         if (askfor(tmp, 80))
411                         {
412                                 if (!show_file(creature_ptr, TRUE, tmp, NULL, 0, mode)) skey = 'q';
413                         }
414
415                         break;
416                 }
417
418                 case '-':
419                         line = line + (reverse ? rows : -rows);
420                         if (line < 0) line = 0;
421                         break;
422
423                 case SKEY_PGUP:
424                         line = line - rows;
425                         if (line < 0) line = 0;
426                         break;
427
428                 case '\n':
429                 case '\r':
430                         line = line + (reverse ? -1 : 1);
431                         if (line < 0) line = 0;
432                         break;
433
434                 case '8':
435                 case SKEY_UP:
436                         line--;
437                         if (line < 0) line = 0;
438                         break;
439
440                 case '2':
441                 case SKEY_DOWN:
442                         line++;
443                         break;
444
445                 case ' ':
446                         line = line + (reverse ? -rows : rows);
447                         if (line < 0) line = 0;
448                         break;
449
450                 case SKEY_PGDOWN:
451                         line = line + rows;
452                         break;
453                 }
454
455                 if (menu)
456                 {
457                         int key = -1;
458                         if (!(skey & SKEY_MASK) && isalpha(skey))
459                                 key = skey - 'A';
460
461                         if ((key > -1) && hook[key][0])
462                         {
463                                 /* Recurse on that file */
464                                 if (!show_file(creature_ptr, TRUE, hook[key], NULL, 0, mode))
465                                         skey = 'q';
466                         }
467                 }
468
469                 if (skey == '|')
470                 {
471                         FILE *ffp;
472                         char buff[1024];
473                         char xtmp[82];
474
475                         strcpy(xtmp, "");
476
477                         if (!get_string(_("ファイル名: ", "File name: "), xtmp, 80)) continue;
478                         angband_fclose(fff);
479                         path_build(buff, sizeof(buff), ANGBAND_DIR_USER, xtmp);
480
481                         /* Hack -- Re-Open the file */
482                         fff = angband_fopen(path, "r");
483
484                         ffp = angband_fopen(buff, "w");
485
486                         if (!(fff && ffp))
487                         {
488                                 msg_print(_("ファイルを開けません。", "Failed to open file."));
489                                 skey = ESCAPE;
490                                 break;
491                         }
492
493                         sprintf(xtmp, "%s: %s", creature_ptr->name, what ? what : caption);
494                         angband_fputs(ffp, xtmp, 80);
495                         angband_fputs(ffp, "\n", 80);
496
497                         while (!angband_fgets(fff, buff, sizeof(buff)))
498                                 angband_fputs(ffp, buff, 80);
499                         angband_fclose(fff);
500                         angband_fclose(ffp);
501                         fff = angband_fopen(path, "r");
502                 }
503
504                 if ((skey == ESCAPE) || (skey == '<')) break;
505
506                 if (skey == KTRL('q')) skey = 'q';
507
508                 if (skey == 'q') break;
509         }
510
511         angband_fclose(fff);
512         return (skey != 'q');
513 }
514
515 /*
516  * Convert string to lower case
517  */
518 void str_tolower(char *str)
519 {
520     for (; *str; str++) {
521 #ifdef JP
522         if (iskanji(*str)) {
523             str++;
524             continue;
525         }
526 #endif
527         *str = (char)tolower(*str);
528     }
529 }