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-exceptions.h"
7 #include "system/angband-version.h"
8 #include "system/player-type-definition.h"
9 #include "term/gameterm.h"
10 #include "term/screen-processor.h"
11 #include "term/term-color-types.h"
12 #include "term/z-form.h"
13 #include "util/angband-files.h"
14 #include "util/int-char-converter.h"
15 #include "util/string-processor.h"
16 #include "view/display-messages.h"
21 * @brief ファイル内容の一行をコンソールに出力する
22 * Display single line of on-line help file
28 * You can insert some special color tag to change text color.
30 * WHITETEXT [[[[y|SOME TEXT WHICH IS DISPLAYED IN YELLOW| WHITETEXT
31 * A colored segment is between "[[[[y|" and the last "|".
32 * You can use any single character in place of the "|".
36 static void show_file_aux_line(concptr str, int cy, concptr shower)
40 byte textcolor = TERM_WHITE;
41 byte focuscolor = TERM_YELLOW;
47 ptr = angband_strstr(lcstr, shower);
48 textcolor = (ptr == nullptr) ? TERM_L_DARK : TERM_WHITE;
54 static const char tag_str[] = "[[[[";
55 byte color = textcolor;
57 for (int i = 0; str[i];) {
58 int len = strlen(&str[i]);
59 int showercol = len + 1;
60 int bracketcol = len + 1;
63 ptr = angband_strstr(&lcstr[i], shower);
65 showercol = ptr - &lcstr[i];
69 ptr = in_tag ? angband_strchr(&str[i], in_tag) : angband_strstr(&str[i], tag_str);
71 bracketcol = ptr - &str[i];
73 if (bracketcol < endcol) {
76 if (showercol < endcol) {
80 term_addstr(endcol, color, &str[i]);
84 if (shower && endcol == showercol) {
85 int showerlen = strlen(shower);
86 term_addstr(showerlen, focuscolor, &str[i]);
92 if (endcol != bracketcol) {
103 i += sizeof(tag_str) - 1;
104 color = color_char_to_attr(str[i]);
105 if (color == 255 || str[i + 1] == '\0') {
107 term_addstr(-1, color, tag_str);
108 cx += sizeof(tag_str) - 1;
117 term_erase(cx, cy, 255);
121 * @brief ファイル内容をコンソールに出力する
122 * Recursive file perusal.
123 * @param player_ptr プレイヤーへの参照ポインタ
124 * @param show_version TRUEならばコンソール上にゲームのバージョンを表示する
125 * @param name ファイル名の文字列
126 * @param what 内容キャプションの文字列
131 * Process various special text in the input file, including
132 * the "menu" structures used by the "help file" system.
133 * Return FALSE on 'q' to exit from a deep, otherwise TRUE.
137 bool show_file(PlayerType *player_ptr, bool show_version, std::string_view name_with_tag, int initial_line, uint32_t mode, std::string_view what)
139 TermCenteredOffsetSetter tcos(MAIN_TERM_MIN_COLS, std::nullopt);
142 term_get_size(&wid, &hgt);
144 char finder_str[81] = "";
145 char shower_str[81] = "";
147 auto stripped_names = str_split(name_with_tag, '#');
148 auto &name = stripped_names[0];
149 auto tag = stripped_names.size() > 1 ? stripped_names[1] : "";
150 std::filesystem::path path_reopen("");
152 std::stringstream caption;
156 fff = angband_fopen(path_reopen, FileOpenMode::READ);
161 caption << _("ヘルプ・ファイル'", "Help file '");
162 caption << name << "'";
163 path_reopen = path_build(ANGBAND_DIR_HELP, name);
164 fff = angband_fopen(path_reopen, FileOpenMode::READ);
169 caption << _("スポイラー・ファイル'", "Info file '");
170 caption << name << "'";
171 path_reopen = path_build(ANGBAND_DIR_INFO, name);
172 fff = angband_fopen(path_reopen, FileOpenMode::READ);
177 path_reopen = path_build(ANGBAND_DIR, name);
178 caption << _("スポイラー・ファイル'", "Info file '");
179 caption << name << "'";
180 fff = angband_fopen(path_reopen, FileOpenMode::READ);
183 const auto open_error_mes = format(_("'%s'をオープンできません。", "Cannot open '%s'."), name.data());
185 THROW_EXCEPTION(std::runtime_error, open_error_mes);
188 const auto caption_str = caption.str();
194 auto reverse = initial_line < 0;
195 auto line = initial_line;
198 if (angband_fgets(fff, buf, sizeof(buf))) {
201 if (!prefix(str, "***** ")) {
206 if ((str[6] == '[') && isalpha(str[7])) {
207 int k = str[7] - 'A';
209 if ((str[8] == ']') && (str[9] == ' ')) {
210 angband_strcpy(hook[k], str + 10, sizeof(hook[k]));
220 size_t len = strlen(str);
221 if (str[len - 1] == '>') {
223 if (!tag.empty() && streq(str + 7, tag)) {
232 line = ((size - 1) / rows) * rows;
237 concptr find = nullptr;
238 concptr shower = nullptr;
240 if (line >= size - rows) {
249 fff = angband_fopen(path_reopen, FileOpenMode::READ);
251 THROW_EXCEPTION(std::runtime_error, open_error_mes);
257 while (next < line) {
258 if (angband_fgets(fff, buf, sizeof(buf))) {
261 if (prefix(buf, "***** ")) {
268 for (row_count = 0; row_count < rows;) {
273 if (angband_fgets(fff, buf, sizeof(buf))) {
276 if (prefix(buf, "***** ")) {
280 if (find && !row_count) {
284 if (!angband_strstr(lc_buf, find)) {
290 show_file_aux_line(str, row_count + 2, shower);
294 while (row_count < rows) {
295 term_erase(0, row_count + 2, 255);
307 constexpr auto title = _("[%s, %s, %d/%d]", "[%s, %s, Line %d/%d]");
308 prt(format(title, get_version().data(), caption_str.data(), line, size), 0, 0);
310 constexpr auto title = _("[%s, %d/%d]", "[%s, Line %d/%d]");
311 prt(format(title, caption_str.data(), line, size), 0, 0);
315 prt(_("[キー:(?)ヘルプ (ESC)終了]", "[Press ESC to exit.]"), hgt - 1, 0);
319 prt("[キー:(RET/スペース)↑ (-)↓ (?)ヘルプ (ESC)終了]", hgt - 1, 0);
321 prt("[キー:(RET/スペース)↓ (-)↑ (?)ヘルプ (ESC)終了]", hgt - 1, 0);
324 prt("[Press Return, Space, -, =, /, |, or ESC to exit.]", hgt - 1, 0);
328 skey = inkey_special(true);
331 if (name != _("jhelpinfo.txt", "helpinfo.txt")) {
332 show_file(player_ptr, true, _("jhelpinfo.txt", "helpinfo.txt"), 0, mode);
336 prt(_("強調: ", "Show: "), hgt - 1, 0);
339 strcpy(back_str, shower_str);
340 if (askfor(shower_str, 80)) {
342 str_tolower(shower_str);
348 strcpy(shower_str, back_str);
354 prt(_("検索: ", "Find: "), hgt - 1, 0);
355 strcpy(back_str, finder_str);
356 if (askfor(finder_str, 80)) {
361 str_tolower(finder_str);
367 strcpy(finder_str, back_str);
373 prt(_("行: ", "Goto Line: "), hgt - 1, 0);
376 if (askfor(tmp, 80)) {
387 line = ((size - 1) / rows) * rows;
392 prt(_("ファイル・ネーム: ", "Goto File: "), hgt - 1, 0);
393 strcpy(tmp, _("jhelp.hlp", "help.hlp"));
395 if (askfor(tmp, 80)) {
396 if (!show_file(player_ptr, true, tmp, 0, mode)) {
405 line = line + (reverse ? rows : -rows);
420 line = line + (reverse ? -1 : 1);
440 line = line + (reverse ? -rows : rows);
453 if (!(skey & SKEY_MASK) && isalpha(skey)) {
457 if ((key > -1) && hook[key][0]) {
458 /* Recurse on that file */
459 if (!show_file(player_ptr, true, hook[key], 0, mode)) {
469 if (!get_string(_("ファイル名: ", "File name: "), xtmp, 80)) {
474 fff = angband_fopen(path_reopen, FileOpenMode::READ);
475 const auto &path_xtemp = path_build(ANGBAND_DIR_USER, xtmp);
476 ffp = angband_fopen(path_xtemp, FileOpenMode::WRITE);
479 msg_print(_("ファイルを開けません。", "Failed to open file."));
484 fprintf(ffp, "%s: %s\n", player_ptr->name, !what.empty() ? what.data() : caption_str.data());
486 while (!angband_fgets(fff, buff, sizeof(buff))) {
487 angband_fputs(ffp, buff, 80);
491 fff = angband_fopen(path_reopen, FileOpenMode::READ);
494 if ((skey == ESCAPE) || (skey == '<')) {
498 if (skey == KTRL('q')) {
512 * Convert string to lower case
514 void str_tolower(char *str)
516 for (; *str; str++) {
523 *str = (char)tolower(*str);