OSDN Git Service

[Refactor] #40413 Separated asking-player.c/h from util.c/h
[hengband/hengband.git] / src / util / util.c
1 /* File: util.c */
2
3 /*
4  * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke
5  *
6  * This software may be copied and distributed for educational, research,
7  * and not for profit purposes provided that this copyright and statement
8  * are included in all such copies.  Other copyrights may also apply.
9  */
10
11  /* Purpose: Angband utilities -BEN- */
12
13 #include "system/angband.h"
14 #include "util/util.h"
15 #include "cmd-io/cmd-dump.h"
16 #include "cmd-io/cmd-menu-content-table.h"
17 #include "cmd-io/macro-util.h"
18 #include "core/asking-player.h"
19 #include "core/output-updater.h"
20 #include "core/stuff-handler.h"
21 #include "dungeon/quest.h"
22 #include "floor/floor.h"
23 #include "game-option/cheat-options.h"
24 #include "game-option/disturbance-options.h"
25 #include "game-option/input-options.h"
26 #include "game-option/map-screen-options.h"
27 #include "game-option/option-flags.h"
28 #include "game-option/special-options.h"
29 #include "io/files-util.h"
30 #include "io/input-key-acceptor.h"
31 #include "io/input-key-processor.h"
32 #include "io/signal-handlers.h"
33 #include "io/write-diary.h"
34 #include "locale/japanese.h"
35 #include "main/music-definitions-table.h"
36 #include "main/sound-of-music.h"
37 #include "monster-race/monster-race-hook.h"
38 #include "player/player-class.h"
39 #include "system/system-variables.h"
40 #include "term/gameterm.h"
41 #include "term/term-color-types.h"
42 #include "util/quarks.h"
43 #include "util/string-processor.h"
44 #include "view/display-main-window.h"
45 #include "view/display-messages.h"
46 #include "world/world.h"
47
48 /*!
49  * 10進数から16進数への変換テーブル /
50  * Global array for converting numbers to uppercase hecidecimal digit
51  * This array can also be used to convert a number to an octal digit
52  */
53 const char hexsym[16] =
54 {
55         '0', '1', '2', '3', '4', '5', '6', '7',
56         '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
57 };
58
59 /*
60  * Keymaps for each "mode" associated with each keypress.
61  */
62 concptr keymap_act[KEYMAP_MODES][256];
63
64 /*
65  * Array of macro types [MACRO_MAX]
66  */
67 bool *macro__cmd;
68
69 /*
70  * Current macro action [1024]
71  */
72 char *macro__buf;
73
74 bool get_com_no_macros = FALSE; /* Expand macros in "get_com" or not */
75
76 bool use_menu;
77
78 pos_list tmp_pos;
79
80 int max_macrotrigger = 0; /*!< 現在登録中のマクロ(トリガー)の数 */
81 concptr macro_template = NULL; /*!< Angband設定ファイルのT: タグ情報から読み込んだ長いTコードを処理するために利用する文字列ポインタ */
82 concptr macro_modifier_chr; /*!< &x# で指定されるマクロトリガーに関する情報を記録する文字列ポインタ */
83 concptr macro_modifier_name[MAX_MACRO_MOD]; /*!< マクロ上で取り扱う特殊キーを文字列上で表現するためのフォーマットを記録した文字列ポインタ配列 */
84 concptr macro_trigger_name[MAX_MACRO_TRIG]; /*!< マクロのトリガーコード */
85 concptr macro_trigger_keycode[2][MAX_MACRO_TRIG];  /*!< マクロの内容 */
86
87 s16b command_cmd;               /* Current "Angband Command" */
88 COMMAND_ARG command_arg;        /*!< 各種コマンドの汎用的な引数として扱う / Gives argument of current command */
89 COMMAND_NUM command_rep;        /*!< 各種コマンドの汎用的なリピート数として扱う / Gives repetition of current command */
90 DIRECTION command_dir;          /*!< 各種コマンドの汎用的な方向値処理として扱う/ Gives direction of current command */
91 s16b command_see;               /* アイテム使用時等にリストを表示させるかどうか (ゲームオプションの他、様々なタイミングでONになったりOFFになったりする模様……) */
92 s16b command_wrk;               /* アイテムの使用許可状況 (ex. 装備品のみ、床上もOK等) */
93 TERM_LEN command_gap = 999;         /* アイテムの表示に使う (詳細未調査) */
94 s16b command_new;               /* Command chaining from inven/equip view */
95
96 /*
97  * Move the cursor
98  */
99 void move_cursor(int row, int col)
100 {
101         Term_gotoxy(col, row);
102 }
103
104 /*
105  * Flush all input chars.  Actually, remember the flush,
106  * and do a "special flush" before the next "inkey()".
107  *
108  * This is not only more efficient, but also necessary to make sure
109  * that various "inkey()" codes are not "lost" along the way.
110  */
111 void flush(void)
112 {
113         inkey_xtra = TRUE;
114 }
115
116
117 /*
118  * Hack -- prevent "accidents" in "screen_save()" or "screen_load()"
119  */
120 static int screen_depth = 0;
121
122
123 /*
124  * Save the screen, and increase the "icky" depth.
125  *
126  * This function must match exactly one call to "screen_load()".
127  */
128 void screen_save()
129 {
130         msg_print(NULL);
131         if (screen_depth++ == 0) Term_save();
132
133         current_world_ptr->character_icky++;
134 }
135
136
137 /*
138  * Load the screen, and decrease the "icky" depth.
139  *
140  * This function must match exactly one call to "screen_save()".
141  */
142 void screen_load()
143 {
144         msg_print(NULL);
145         if (--screen_depth == 0) Term_load();
146
147         current_world_ptr->character_icky--;
148 }
149
150
151 /*
152  * Display a string on the screen using an attribute.
153  *
154  * At the given location, using the given attribute, if allowed,
155  * add the given string.  Do not clear the line.
156  */
157 void c_put_str(TERM_COLOR attr, concptr str, TERM_LEN row, TERM_LEN col)
158 {
159         Term_putstr(col, row, -1, attr, str);
160 }
161
162
163 /*
164  * As above, but in "white"
165  */
166 void put_str(concptr str, TERM_LEN row, TERM_LEN col)
167 {
168         Term_putstr(col, row, -1, TERM_WHITE, str);
169 }
170
171
172 /*
173  * Display a string on the screen using an attribute, and clear
174  * to the end of the line.
175  */
176 void c_prt(TERM_COLOR attr, concptr str, TERM_LEN row, TERM_LEN col)
177 {
178         Term_erase(col, row, 255);
179         Term_addstr(-1, attr, str);
180 }
181
182
183 /*
184  * As above, but in "white"
185  */
186 void prt(concptr str, TERM_LEN row, TERM_LEN col)
187 {
188         /* Spawn */
189         c_prt(TERM_WHITE, str, row, col);
190 }
191
192
193 /*
194  * Print some (colored) text to the screen at the current cursor position,
195  * automatically "wrapping" existing text (at spaces) when necessary to
196  * avoid placing any text into the last column, and clearing every line
197  * before placing any text in that line.  Also, allow "newline" to force
198  * a "wrap" to the next line.  Advance the cursor as needed so sequential
199  * calls to this function will work correctly.
200  *
201  * Once this function has been called, the cursor should not be moved
202  * until all the related "c_roff()" calls to the window are complete.
203  *
204  * This function will correctly handle any width up to the maximum legal
205  * value of 256, though it works best for a standard 80 character width.
206  */
207 void c_roff(TERM_COLOR a, concptr str)
208 {
209         int w, h;
210         (void)Term_get_size(&w, &h);
211
212         int x, y;
213         (void)Term_locate(&x, &y);
214
215         if (y == h - 1 && x > w - 3) return;
216
217         for (concptr s = str; *s; s++)
218         {
219                 char ch;
220 #ifdef JP
221                 int k_flag = iskanji(*s);
222 #endif
223                 if (*s == '\n')
224                 {
225                         x = 0;
226                         y++;
227                         if (y == h) break;
228
229                         Term_erase(x, y, 255);
230                         break;
231                 }
232
233 #ifdef JP
234                 ch = ((k_flag || isprint(*s)) ? *s : ' ');
235 #else
236                 ch = (isprint(*s) ? *s : ' ');
237 #endif
238
239 #ifdef JP
240                 if ((x >= ((k_flag) ? w - 2 : w - 1)) && (ch != ' '))
241 #else
242                 if ((x >= w - 1) && (ch != ' '))
243 #endif
244                 {
245                         int i, n = 0;
246
247                         TERM_COLOR av[256];
248                         char cv[256];
249                         if (x < w)
250 #ifdef JP
251                         {
252                                 /* 現在が半角文字の場合 */
253                                 if (!k_flag)
254 #endif
255                                 {
256                                         for (i = w - 2; i >= 0; i--)
257                                         {
258                                                 Term_what(i, y, &av[i], &cv[i]);
259                                                 if (cv[i] == ' ') break;
260
261                                                 n = i;
262 #ifdef JP
263                                                 if (cv[i] == '(') break;
264 #endif
265                                         }
266                                 }
267 #ifdef JP
268                                 else
269                                 {
270                                         /* 現在が全角文字のとき */
271                                         /* 文頭が「。」「、」等になるときは、その1つ前の語で改行 */
272                                         if (strncmp(s, "。", 2) == 0 || strncmp(s, "、", 2) == 0)
273                                         {
274                                                 Term_what(x, y, &av[x], &cv[x]);
275                                                 Term_what(x - 1, y, &av[x - 1], &cv[x - 1]);
276                                                 Term_what(x - 2, y, &av[x - 2], &cv[x - 2]);
277                                                 n = x - 2;
278                                                 cv[x] = '\0';
279                                         }
280                                 }
281                         }
282 #endif
283                         if (n == 0) n = w;
284
285                         Term_erase(n, y, 255);
286                         x = 0;
287                         y++;
288                         if (y == h) break;
289
290                         Term_erase(x, y, 255);
291                         for (i = n; i < w - 1; i++)
292                         {
293 #ifdef JP
294                                 if (cv[i] == '\0') break;
295 #endif
296                                 Term_addch(av[i], cv[i]);
297                                 if (++x > w) x = w;
298                         }
299                 }
300
301 #ifdef JP
302                 Term_addch((byte)(a | 0x10), ch);
303 #else
304                 Term_addch(a, ch);
305 #endif
306
307 #ifdef JP
308                 if (k_flag)
309                 {
310                         s++;
311                         x++;
312                         ch = *s;
313                         Term_addch((byte)(a | 0x20), ch);
314                 }
315 #endif
316
317                 if (++x > w) x = w;
318         }
319 }
320
321
322 /*
323  * As above, but in "white"
324  */
325 void roff(concptr str)
326 {
327         /* Spawn */
328         c_roff(TERM_WHITE, str);
329 }
330
331
332 /*
333  * Clear part of the screen
334  */
335 void clear_from(int row)
336 {
337         for (int y = row; y < Term->hgt; y++)
338         {
339                 Term_erase(0, y, 255);
340         }
341 }
342
343
344 /*
345  * Hack -- special buffer to hold the action of the current keymap
346  */
347 static char request_command_buffer[256];
348
349 static char inkey_from_menu(player_type *player_ptr)
350 {
351         char cmd;
352         int basey, basex;
353         int num = 0, max_num, old_num = 0;
354         int menu = 0;
355         bool kisuu;
356
357         if (player_ptr->y - panel_row_min > 10) basey = 2;
358         else basey = 13;
359         basex = 15;
360
361         prt("", 0, 0);
362         screen_save();
363
364         floor_type* floor_ptr = player_ptr->current_floor_ptr;
365         while (TRUE)
366         {
367                 int i;
368                 char sub_cmd;
369                 concptr menu_name;
370                 if (!menu) old_num = num;
371                 put_str("+----------------------------------------------------+", basey, basex);
372                 put_str("|                                                    |", basey + 1, basex);
373                 put_str("|                                                    |", basey + 2, basex);
374                 put_str("|                                                    |", basey + 3, basex);
375                 put_str("|                                                    |", basey + 4, basex);
376                 put_str("|                                                    |", basey + 5, basex);
377                 put_str("+----------------------------------------------------+", basey + 6, basex);
378
379                 for (i = 0; i < 10; i++)
380                 {
381                         int hoge;
382                         if (!menu_info[menu][i].cmd) break;
383                         menu_name = menu_info[menu][i].name;
384                         for (hoge = 0; ; hoge++)
385                         {
386                                 if (!special_menu_info[hoge].name[0]) break;
387                                 if ((menu != special_menu_info[hoge].window) || (i != special_menu_info[hoge].number)) continue;
388                                 switch (special_menu_info[hoge].jouken)
389                                 {
390                                 case MENU_CLASS:
391                                         if (player_ptr->pclass == special_menu_info[hoge].jouken_naiyou) menu_name = special_menu_info[hoge].name;
392                                         break;
393                                 case MENU_WILD:
394                                         if (!floor_ptr->dun_level && !floor_ptr->inside_arena && !floor_ptr->inside_quest)
395                                         {
396                                                 if ((byte)player_ptr->wild_mode == special_menu_info[hoge].jouken_naiyou) menu_name = special_menu_info[hoge].name;
397                                         }
398                                         break;
399                                 default:
400                                         break;
401                                 }
402                         }
403
404                         put_str(menu_name, basey + 1 + i / 2, basex + 4 + (i % 2) * 24);
405                 }
406
407                 max_num = i;
408                 kisuu = max_num % 2;
409                 put_str(_("》", "> "), basey + 1 + num / 2, basex + 2 + (num % 2) * 24);
410
411                 move_cursor_relative(player_ptr->y, player_ptr->x);
412                 sub_cmd = inkey();
413                 if ((sub_cmd == ' ') || (sub_cmd == 'x') || (sub_cmd == 'X') || (sub_cmd == '\r') || (sub_cmd == '\n'))
414                 {
415                         if (menu_info[menu][num].fin)
416                         {
417                                 cmd = menu_info[menu][num].cmd;
418                                 use_menu = TRUE;
419                                 break;
420                         }
421                         else
422                         {
423                                 menu = menu_info[menu][num].cmd;
424                                 num = 0;
425                                 basey += 2;
426                                 basex += 8;
427                         }
428                 }
429                 else if ((sub_cmd == ESCAPE) || (sub_cmd == 'z') || (sub_cmd == 'Z') || (sub_cmd == '0'))
430                 {
431                         if (!menu)
432                         {
433                                 cmd = ESCAPE;
434                                 break;
435                         }
436                         else
437                         {
438                                 menu = 0;
439                                 num = old_num;
440                                 basey -= 2;
441                                 basex -= 8;
442                                 screen_load();
443                                 screen_save();
444                         }
445                 }
446                 else if ((sub_cmd == '2') || (sub_cmd == 'j') || (sub_cmd == 'J'))
447                 {
448                         if (kisuu)
449                         {
450                                 if (num % 2)
451                                         num = (num + 2) % (max_num - 1);
452                                 else
453                                         num = (num + 2) % (max_num + 1);
454                         }
455                         else num = (num + 2) % max_num;
456                 }
457                 else if ((sub_cmd == '8') || (sub_cmd == 'k') || (sub_cmd == 'K'))
458                 {
459                         if (kisuu)
460                         {
461                                 if (num % 2)
462                                         num = (num + max_num - 3) % (max_num - 1);
463                                 else
464                                         num = (num + max_num - 1) % (max_num + 1);
465                         }
466                         else num = (num + max_num - 2) % max_num;
467                 }
468                 else if ((sub_cmd == '4') || (sub_cmd == '6') || (sub_cmd == 'h') || (sub_cmd == 'H') || (sub_cmd == 'l') || (sub_cmd == 'L'))
469                 {
470                         if ((num % 2) || (num == max_num - 1))
471                         {
472                                 num--;
473                         }
474                         else if (num < max_num - 1)
475                         {
476                                 num++;
477                         }
478                 }
479         }
480
481         screen_load();
482         if (!inkey_next) inkey_next = "";
483
484         return (cmd);
485 }
486
487
488 /*
489  * Request a command from the user.
490  *
491  * Sets player_ptr->command_cmd, player_ptr->command_dir, player_ptr->command_rep,
492  * player_ptr->command_arg.  May modify player_ptr->command_new.
493  *
494  * Note that "caret" ("^") is treated specially, and is used to
495  * allow manual input of control characters.  This can be used
496  * on many machines to request repeated tunneling (Ctrl-H) and
497  * on the Macintosh to request "Control-Caret".
498  *
499  * Note that "backslash" is treated specially, and is used to bypass any
500  * keymap entry for the following character.  This is useful for macros.
501  *
502  * Note that this command is used both in the dungeon and in
503  * stores, and must be careful to work in both situations.
504  *
505  * Note that "player_ptr->command_new" may not work any more.
506  */
507 void request_command(player_type *player_ptr, int shopping)
508 {
509         s16b cmd;
510         int mode;
511
512         concptr act;
513
514 #ifdef JP
515         int caretcmd = 0;
516 #endif
517         if (rogue_like_commands)
518         {
519                 mode = KEYMAP_MODE_ROGUE;
520         }
521         else
522         {
523                 mode = KEYMAP_MODE_ORIG;
524         }
525
526         command_cmd = 0;
527         command_arg = 0;
528         command_dir = 0;
529         use_menu = FALSE;
530
531         while (TRUE)
532         {
533                 if (command_new)
534                 {
535                         msg_erase();
536                         cmd = command_new;
537                         command_new = 0;
538                 }
539                 else
540                 {
541                         msg_flag = FALSE;
542                         num_more = 0;
543                         inkey_flag = TRUE;
544                         cmd = inkey();
545                         if (!shopping && command_menu && ((cmd == '\r') || (cmd == '\n') || (cmd == 'x') || (cmd == 'X'))
546                                 && !keymap_act[mode][(byte)(cmd)])
547                                 cmd = inkey_from_menu(player_ptr);
548                 }
549
550                 prt("", 0, 0);
551                 if (cmd == '0')
552                 {
553                         COMMAND_ARG old_arg = command_arg;
554                         command_arg = 0;
555                         prt(_("回数: ", "Count: "), 0, 0);
556                         while (TRUE)
557                         {
558                                 cmd = inkey();
559                                 if ((cmd == 0x7F) || (cmd == KTRL('H')))
560                                 {
561                                         command_arg = command_arg / 10;
562                                         prt(format(_("回数: %d", "Count: %d"), command_arg), 0, 0);
563                                 }
564                                 else if (cmd >= '0' && cmd <= '9')
565                                 {
566                                         if (command_arg >= 1000)
567                                         {
568                                                 bell();
569                                                 command_arg = 9999;
570                                         }
571                                         else
572                                         {
573                                                 command_arg = command_arg * 10 + D2I(cmd);
574                                         }
575
576                                         prt(format(_("回数: %d", "Count: %d"), command_arg), 0, 0);
577                                 }
578                                 else
579                                 {
580                                         break;
581                                 }
582                         }
583
584                         if (command_arg == 0)
585                         {
586                                 command_arg = 99;
587                                 prt(format(_("回数: %d", "Count: %d"), command_arg), 0, 0);
588                         }
589
590                         if (old_arg != 0)
591                         {
592                                 command_arg = old_arg;
593                                 prt(format(_("回数: %d", "Count: %d"), command_arg), 0, 0);
594                         }
595
596                         if ((cmd == ' ') || (cmd == '\n') || (cmd == '\r'))
597                         {
598                                 if (!get_com(_("コマンド: ", "Command: "), (char *)&cmd, FALSE))
599                                 {
600                                         command_arg = 0;
601                                         continue;
602                                 }
603                         }
604                 }
605
606                 if (cmd == '\\')
607                 {
608                         (void)get_com(_("コマンド: ", "Command: "), (char *)&cmd, FALSE);
609                         if (!inkey_next) inkey_next = "";
610                 }
611
612                 if (cmd == '^')
613                 {
614                         if (get_com(_("CTRL: ", "Control: "), (char *)&cmd, FALSE)) cmd = KTRL(cmd);
615                 }
616
617                 act = keymap_act[mode][(byte)(cmd)];
618                 if (act && !inkey_next)
619                 {
620                         (void)strnfmt(request_command_buffer, 256, "%s", act);
621                         inkey_next = request_command_buffer;
622                         continue;
623                 }
624
625                 if (!cmd) continue;
626
627                 command_cmd = (byte)cmd;
628                 break;
629         }
630
631         if (always_repeat && (command_arg <= 0))
632         {
633                 if (angband_strchr("TBDoc+", (char)command_cmd))
634                 {
635                         command_arg = 99;
636                 }
637         }
638
639         if (shopping == 1)
640         {
641                 switch (command_cmd)
642                 {
643                 case 'p': command_cmd = 'g'; break;
644
645                 case 'm': command_cmd = 'g'; break;
646
647                 case 's': command_cmd = 'd'; break;
648                 }
649         }
650
651 #ifdef JP
652         for (int i = 0; i < 256; i++)
653         {
654                 concptr s;
655                 if ((s = keymap_act[mode][i]) != NULL)
656                 {
657                         if (*s == command_cmd && *(s + 1) == 0)
658                         {
659                                 caretcmd = i;
660                                 break;
661                         }
662                 }
663         }
664
665         if (!caretcmd)
666                 caretcmd = command_cmd;
667 #endif
668
669         for (int i = INVEN_RARM; i < INVEN_TOTAL; i++)
670         {
671                 object_type *o_ptr = &player_ptr->inventory_list[i];
672                 if (!o_ptr->k_idx) continue;
673
674                 if (!o_ptr->inscription) continue;
675
676                 concptr s = quark_str(o_ptr->inscription);
677                 s = angband_strchr(s, '^');
678                 while (s)
679                 {
680 #ifdef JP
681                         if ((s[1] == caretcmd) || (s[1] == '*'))
682 #else
683                         if ((s[1] == command_cmd) || (s[1] == '*'))
684 #endif
685                         {
686                                 if (!get_check(_("本当ですか? ", "Are you sure? ")))
687                                 {
688                                         command_cmd = ' ';
689                                 }
690                         }
691
692                         s = angband_strchr(s + 1, '^');
693                 }
694         }
695
696         prt("", 0, 0);
697 }
698
699
700 /*
701  * Check a char for "vowel-hood"
702  */
703 bool is_a_vowel(int ch)
704 {
705         switch (ch)
706         {
707         case 'a':
708         case 'e':
709         case 'i':
710         case 'o':
711         case 'u':
712         case 'A':
713         case 'E':
714         case 'I':
715         case 'O':
716         case 'U':
717                 return TRUE;
718         }
719
720         return FALSE;
721 }
722
723
724 /*
725  * GH
726  * Called from cmd4.c and a few other places. Just extracts
727  * a direction from the keymap for ch (the last direction,
728  * in fact) byte or char here? I'm thinking that keymaps should
729  * generally only apply to single keys, which makes it no more
730  * than 128, so a char should suffice... but keymap_act is 256...
731  */
732 int get_keymap_dir(char ch)
733 {
734         int d = 0;
735
736         if (isdigit(ch))
737         {
738                 d = D2I(ch);
739         }
740         else
741         {
742                 BIT_FLAGS mode;
743                 if (rogue_like_commands)
744                 {
745                         mode = KEYMAP_MODE_ROGUE;
746                 }
747                 else
748                 {
749                         mode = KEYMAP_MODE_ORIG;
750                 }
751
752                 concptr act = keymap_act[mode][(byte)(ch)];
753                 if (act)
754                 {
755                         for (concptr s = act; *s; ++s)
756                         {
757                                 if (isdigit(*s)) d = D2I(*s);
758                         }
759                 }
760         }
761
762         if (d == 5) d = 0;
763
764         return (d);
765 }
766
767
768 #define REPEAT_MAX              20
769
770 /* Number of chars saved */
771 static int repeat__cnt = 0;
772
773 /* Current index */
774 static int repeat__idx = 0;
775
776 /* Saved "stuff" */
777 static COMMAND_CODE repeat__key[REPEAT_MAX];
778
779 void repeat_push(COMMAND_CODE what)
780 {
781         if (repeat__cnt == REPEAT_MAX) return;
782
783         repeat__key[repeat__cnt++] = what;
784         ++repeat__idx;
785 }
786
787
788 bool repeat_pull(COMMAND_CODE *what)
789 {
790         if (repeat__idx == repeat__cnt) return FALSE;
791
792         *what = repeat__key[repeat__idx++];
793         return TRUE;
794 }
795
796 void repeat_check(void)
797 {
798         if (command_cmd == ESCAPE) return;
799         if (command_cmd == ' ') return;
800         if (command_cmd == '\r') return;
801         if (command_cmd == '\n') return;
802
803         COMMAND_CODE what;
804         if (command_cmd == 'n')
805         {
806                 repeat__idx = 0;
807                 if (repeat_pull(&what))
808                 {
809                         command_cmd = what;
810                 }
811         }
812         else
813         {
814                 repeat__cnt = 0;
815                 repeat__idx = 0;
816                 what = command_cmd;
817                 repeat_push(what);
818         }
819 }
820
821
822 /*
823  * Array size for which InsertionSort
824  * is used instead of QuickSort
825  */
826 #define CUTOFF 4
827
828
829  /*
830   * Exchange two sort-entries
831   * (should probably be coded inline
832   * for speed increase)
833   */
834 static void swap(tag_type *a, tag_type *b)
835 {
836         tag_type temp;
837
838         temp = *a;
839         *a = *b;
840         *b = temp;
841 }
842
843
844 /*
845  * Insertion-Sort algorithm
846  * (used by the Quicksort algorithm)
847  */
848 static void InsertionSort(tag_type elements[], int number)
849 {
850         tag_type tmp;
851         for (int i = 1; i < number; i++)
852         {
853                 tmp = elements[i];
854                 int j;
855                 for (j = i; (j > 0) && (elements[j - 1].tag > tmp.tag); j--)
856                         elements[j] = elements[j - 1];
857                 elements[j] = tmp;
858         }
859 }
860
861
862 /*
863  * Helper function for Quicksort
864  */
865 static tag_type median3(tag_type elements[], int left, int right)
866 {
867         int center = (left + right) / 2;
868
869         if (elements[left].tag > elements[center].tag)
870                 swap(&elements[left], &elements[center]);
871         if (elements[left].tag > elements[right].tag)
872                 swap(&elements[left], &elements[right]);
873         if (elements[center].tag > elements[right].tag)
874                 swap(&elements[center], &elements[right]);
875
876         swap(&elements[center], &elements[right - 1]);
877         return (elements[right - 1]);
878 }
879
880
881 /*
882  * Quicksort algorithm
883  *
884  * The "median of three" pivot selection eliminates
885  * the bad case of already sorted input.
886  *
887  * We use InsertionSort for smaller sub-arrays,
888  * because it is faster in this case.
889  *
890  * For details see: "Data Structures and Algorithm
891  * Analysis in C" by Mark Allen Weiss.
892  */
893 static void quicksort(tag_type elements[], int left, int right)
894 {
895         tag_type pivot;
896         if (left + CUTOFF <= right)
897         {
898                 pivot = median3(elements, left, right);
899
900                 int i = left;
901                 int j = right - 1;
902
903                 while (TRUE)
904                 {
905                         while (elements[++i].tag < pivot.tag);
906                         while (elements[--j].tag > pivot.tag);
907
908                         if (i < j)
909                                 swap(&elements[i], &elements[j]);
910                         else
911                                 break;
912                 }
913
914                 swap(&elements[i], &elements[right - 1]);
915
916                 quicksort(elements, left, i - 1);
917                 quicksort(elements, i + 1, right);
918         }
919         else
920         {
921                 InsertionSort(elements + left, right - left + 1);
922         }
923 }
924
925
926 /*
927  * Frontend for the sorting algorithm
928  *
929  * Sorts an array of tagged pointers
930  * with <number> elements.
931  */
932 void tag_sort(tag_type elements[], int number)
933 {
934         quicksort(elements, 0, number - 1);
935 }
936
937 /*
938  * Add a series of keypresses to the "queue".
939  *
940  * Return any errors generated by Term_keypress() in doing so, or SUCCESS
941  * if there are none.
942  *
943  * Catch the "out of space" error before anything is printed.
944  *
945  * NB: The keys added here will be interpreted by any macros or keymaps.
946  */
947 errr type_string(concptr str, uint len)
948 {
949         errr err = 0;
950         term *old = Term;
951         if (!str) return -1;
952         if (!len) len = strlen(str);
953
954         Term_activate(term_screen);
955         for (concptr s = str; s < str + len; s++)
956         {
957                 if (*s == '\0') break;
958
959                 err = Term_keypress(*s);
960                 if (err) break;
961         }
962
963         Term_activate(old);
964         return err;
965 }
966
967
968 void roff_to_buf(concptr str, int maxlen, char *tbuf, size_t bufsize)
969 {
970         int read_pt = 0;
971         int write_pt = 0;
972         int line_len = 0;
973         int word_punct = 0;
974         char ch[3];
975         ch[2] = '\0';
976
977         while (str[read_pt])
978         {
979 #ifdef JP
980                 bool kinsoku = FALSE;
981                 bool kanji;
982 #endif
983                 int ch_len = 1;
984                 ch[0] = str[read_pt];
985                 ch[1] = '\0';
986 #ifdef JP
987                 kanji = iskanji(ch[0]);
988
989                 if (kanji)
990                 {
991                         ch[1] = str[read_pt + 1];
992                         ch_len = 2;
993
994                         if (strcmp(ch, "。") == 0 ||
995                                 strcmp(ch, "、") == 0 ||
996                                 strcmp(ch, "ィ") == 0 ||
997                                 strcmp(ch, "ー") == 0)
998                                 kinsoku = TRUE;
999                 }
1000                 else if (!isprint(ch[0]))
1001                         ch[0] = ' ';
1002 #else
1003                 if (!isprint(ch[0]))
1004                         ch[0] = ' ';
1005 #endif
1006
1007                 if (line_len + ch_len > maxlen - 1 || str[read_pt] == '\n')
1008                 {
1009                         int word_len = read_pt - word_punct;
1010 #ifdef JP
1011                         if (kanji && !kinsoku)
1012                                 /* nothing */;
1013                         else
1014 #endif
1015                                 if (ch[0] == ' ' || word_len >= line_len / 2)
1016                                         read_pt++;
1017                                 else
1018                                 {
1019                                         read_pt = word_punct;
1020                                         if (str[word_punct] == ' ')
1021                                                 read_pt++;
1022                                         write_pt -= word_len;
1023                                 }
1024
1025                         tbuf[write_pt++] = '\0';
1026                         line_len = 0;
1027                         word_punct = read_pt;
1028                         continue;
1029                 }
1030
1031                 if (ch[0] == ' ')
1032                         word_punct = read_pt;
1033
1034 #ifdef JP
1035                 if (!kinsoku) word_punct = read_pt;
1036 #endif
1037
1038                 if ((size_t)(write_pt + 3) >= bufsize) break;
1039
1040                 tbuf[write_pt++] = ch[0];
1041                 line_len++;
1042                 read_pt++;
1043 #ifdef JP
1044                 if (kanji)
1045                 {
1046                         tbuf[write_pt++] = ch[1];
1047                         line_len++;
1048                         read_pt++;
1049                 }
1050 #endif
1051         }
1052
1053         tbuf[write_pt] = '\0';
1054         tbuf[write_pt + 1] = '\0';
1055         return;
1056 }
1057
1058
1059 /*
1060  * The angband_strcpy() function copies up to 'bufsize'-1 characters from 'src'
1061  * to 'buf' and NUL-terminates the result.  The 'buf' and 'src' strings may
1062  * not overlap.
1063  *
1064  * angband_strcpy() returns strlen(src).  This makes checking for truncation
1065  * easy.  Example: if (angband_strcpy(buf, src, sizeof(buf)) >= sizeof(buf)) ...;
1066  *
1067  * This function should be equivalent to the strlcpy() function in BSD.
1068  */
1069 size_t angband_strcpy(char *buf, concptr src, size_t bufsize)
1070 {
1071 #ifdef JP
1072         char *d = buf;
1073         concptr s = src;
1074         size_t len = 0;
1075
1076         if (bufsize > 0) {
1077                 /* reserve for NUL termination */
1078                 bufsize--;
1079
1080                 /* Copy as many bytes as will fit */
1081                 while (*s && (len < bufsize))
1082                 {
1083                         if (iskanji(*s))
1084                         {
1085                                 if (len + 1 >= bufsize || !*(s + 1)) break;
1086                                 *d++ = *s++;
1087                                 *d++ = *s++;
1088                                 len += 2;
1089                         }
1090                         else
1091                         {
1092                                 *d++ = *s++;
1093                                 len++;
1094                         }
1095                 }
1096                 *d = '\0';
1097         }
1098
1099         while (*s++) len++;
1100         return len;
1101
1102 #else
1103         size_t len = strlen(src);
1104         size_t ret = len;
1105         if (bufsize == 0) return ret;
1106
1107         if (len >= bufsize) len = bufsize - 1;
1108
1109         (void)memcpy(buf, src, len);
1110         buf[len] = '\0';
1111         return ret;
1112 #endif
1113 }
1114
1115
1116 /*
1117  * The angband_strcat() tries to append a string to an existing NUL-terminated string.
1118  * It never writes more characters into the buffer than indicated by 'bufsize' and
1119  * NUL-terminates the buffer.  The 'buf' and 'src' strings may not overlap.
1120  *
1121  * angband_strcat() returns strlen(buf) + strlen(src).  This makes checking for
1122  * truncation easy.  Example:
1123  * if (angband_strcat(buf, src, sizeof(buf)) >= sizeof(buf)) ...;
1124  *
1125  * This function should be equivalent to the strlcat() function in BSD.
1126  */
1127 size_t angband_strcat(char *buf, concptr src, size_t bufsize)
1128 {
1129         size_t dlen = strlen(buf);
1130         if (dlen < bufsize - 1)
1131         {
1132                 return (dlen + angband_strcpy(buf + dlen, src, bufsize - dlen));
1133         }
1134         else
1135         {
1136                 return (dlen + strlen(src));
1137         }
1138 }
1139
1140
1141 /*
1142  * A copy of ANSI strstr()
1143  *
1144  * angband_strstr() can handle Kanji strings correctly.
1145  */
1146 char *angband_strstr(concptr haystack, concptr needle)
1147 {
1148         int l1 = strlen(haystack);
1149         int l2 = strlen(needle);
1150
1151         if (l1 >= l2)
1152         {
1153                 for (int i = 0; i <= l1 - l2; i++)
1154                 {
1155                         if (!strncmp(haystack + i, needle, l2))
1156                                 return (char *)haystack + i;
1157
1158 #ifdef JP
1159                         if (iskanji(*(haystack + i))) i++;
1160 #endif
1161                 }
1162         }
1163
1164         return NULL;
1165 }
1166
1167
1168 /*
1169  * A copy of ANSI strchr()
1170  *
1171  * angband_strchr() can handle Kanji strings correctly.
1172  */
1173 char *angband_strchr(concptr ptr, char ch)
1174 {
1175         for (; *ptr != '\0'; ptr++)
1176         {
1177                 if (*ptr == ch) return (char *)ptr;
1178
1179 #ifdef JP
1180                 if (iskanji(*ptr)) ptr++;
1181 #endif
1182         }
1183
1184         return NULL;
1185 }
1186
1187
1188 /*
1189  * Convert string to lower case
1190  */
1191 void str_tolower(char *str)
1192 {
1193         for (; *str; str++)
1194         {
1195 #ifdef JP
1196                 if (iskanji(*str))
1197                 {
1198                         str++;
1199                         continue;
1200                 }
1201 #endif
1202                 *str = (char)tolower(*str);
1203         }
1204 }