OSDN Git Service

Use return value of write function
[hengband/hengband.git] / src / util.c
index 763c07a..0da8e97 100644 (file)
@@ -1,15 +1,23 @@
 /* File: util.c */
 
-/* Purpose: Angband utilities -BEN- */
+/*
+ * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke
+ *
+ * This software may be copied and distributed for educational, research,
+ * and not for profit purposes provided that this copyright and statement
+ * are included in all such copies.  Other copyrights may also apply.
+ */
 
+/* Purpose: Angband utilities -BEN- */
 
 #include "angband.h"
 
 
-
-
 static int num_more = 0;
 
+/* Save macro trigger string for use in inkey_special() */
+static char inkey_macro_trigger_string[1024];
+
 #if 0
 #ifndef HAS_STRICMP
 
@@ -91,10 +99,12 @@ int usleep(huge usecs)
 
 
 /*
-* Hack -- External functions
-*/
-extern struct passwd *getpwuid();
-extern struct passwd *getpwnam();
+ * Hack -- External functions
+ */
+#ifdef SET_UID
+extern struct passwd *getpwuid(uid_t uid);
+extern struct passwd *getpwnam(const char *name);
+#endif
 
 
 /*
@@ -197,7 +207,7 @@ errr path_parse(char *buf, int max, cptr file)
        /* File needs no parsing */
        if (file[0] != '~')
        {
-               strcpy(buf, file);
+               (void)strnfmt(buf, max, "%s", file);
                return (0);
        }
 
@@ -205,7 +215,7 @@ errr path_parse(char *buf, int max, cptr file)
        u = file+1;
 
        /* Look for non-user portion of the file */
-       s = strstr(u, PATH_SEP);
+       s = my_strstr(u, PATH_SEP);
 
        /* Hack -- no long user names */
        if (s && (s >= u + sizeof(user))) return (1);
@@ -230,10 +240,8 @@ errr path_parse(char *buf, int max, cptr file)
        if (!pw) return (1);
 
        /* Make use of the info */
-       (void)strcpy(buf, pw->pw_dir);
-
-       /* Append the rest of the filename, if any */
-       if (s) (void)strcat(buf, s);
+       if (s) strnfmt(buf, max, "%s%s", pw->pw_dir, s);
+       else strnfmt(buf, max, "%s", pw->pw_dir);
 
        /* Success */
        return (0);
@@ -254,6 +262,11 @@ errr path_parse(char *buf, int max, cptr file)
        /* Accept the filename */
        (void)strnfmt(buf, max, "%s", file);
 
+#if defined(MAC_MPW) && defined(CARBON)
+     /* Fix it according to the current operating system */
+    convert_pathname(buf);
+#endif /* MAC_MPW && CARBON */
+
        /* Success */
        return (0);
 }
@@ -280,7 +293,11 @@ static errr path_temp(char *buf, int max)
        if (!s) return (-1);
 
        /* Format to length */
+#ifndef WIN32
        (void)strnfmt(buf, max, "%s", s);
+#else
+       (void)strnfmt(buf, max, ".%s", s);
+#endif
 
        /* Success */
        return (0);
@@ -343,19 +360,19 @@ FILE *my_fopen(cptr file, cptr mode)
 {
        char buf[1024];
 
-#if defined(MACINTOSH) && defined(MAC_MPW)
+#if defined(MAC_MPW) || defined(MACH_O_CARBON)
        FILE *tempfff;
 #endif
 
        /* Hack -- Try to parse the path */
        if (path_parse(buf, 1024, file)) return (NULL);
 
-#if defined(MACINTOSH) && defined(MAC_MPW)
-       if (strchr(mode, 'w'))
+#if defined(MAC_MPW) || defined(MACH_O_CARBON)
+       if (my_strchr(mode, 'w'))
        {
                /* setting file type/creator */
                tempfff = fopen(buf, mode);
-               fsetfileinfo(file, _fcreator, _ftype);
+               fsetfileinfo(buf, _fcreator, _ftype);
                fclose(tempfff);
        }
 #endif
@@ -438,6 +455,17 @@ errr my_fgets(FILE *fff, char *buf, huge n)
                /* Convert weirdness */
                for (s = tmp; *s; s++)
                {
+#if defined(MACINTOSH) || defined(MACH_O_CARBON)
+
+                       /*
+                        * Be nice to the Macintosh, where a file can have Mac or Unix
+                        * end of line, especially since the introduction of OS X.
+                        * MPW tools were also very tolerant to the Unix EOL.
+                        */
+                       if (*s == '\r') *s = '\n';
+
+#endif /* MACINTOSH || MACH_O_CARBON */
+
                        /* Handle newline */
                        if (*s == '\n')
                        {
@@ -458,7 +486,7 @@ errr my_fgets(FILE *fff, char *buf, huge n)
                                buf[i++] = ' ';
 
                                /* Append some more spaces */
-                               while (!(i % 8)) buf[i++] = ' ';
+                               while (0 != (i % 8)) buf[i++] = ' ';
                        }
 
 #ifdef JP
@@ -468,14 +496,13 @@ errr my_fgets(FILE *fff, char *buf, huge n)
                                buf[i++] = *s++;
                                buf[i++] = *s;
                        }
-# ifndef EUC
-       /* È¾³Ñ¤«¤Ê¤ËÂбþ */
-                       else if ((((int)*s & 0xff) > 0xa1) && (((int)*s & 0xff ) < 0xdf))
+
+                       /* È¾³Ñ¤«¤Ê¤ËÂбþ */
+                       else if (iskana(*s))
                        {
                                buf[i++] = *s;
                                if (i >= n) break;
                        }
-# endif
 #endif
                        /* Handle printables */
                        else if (isprint(*s))
@@ -634,7 +661,19 @@ errr fd_copy(cptr file, cptr what)
        /* Copy */
        while ((read_num = read(src_fd, buf, 1024)) > 0)
        {
-               write(dst_fd, buf, read_num);
+               int write_num = 0;
+               while (write_num < read_num)
+               {
+                       int ret = write(dst_fd, buf + write_num, read_num - write_num);
+                       if (ret < 0) {
+                               /* Close files */
+                               fd_close(src_fd);
+                               fd_close(dst_fd);
+
+                               return ret;
+                       }
+                       write_num += ret;
+               }
        }
 
        /* Close files */
@@ -679,13 +718,16 @@ int fd_make(cptr file, int mode)
 
 #else /* BEN_HACK */
 
-# if defined(MACINTOSH) && defined(MAC_MPW)
-
-       /* setting file type and creator -- AR */
-       errr_tmp = open(buf, O_CREAT | O_EXCL | O_WRONLY | O_BINARY, mode);
-       fsetfileinfo(file, _fcreator, _ftype);
-       return(errr_tmp);
-
+#if defined(MAC_MPW) || defined(MACH_O_CARBON)
+       {
+               int fdes;
+               /* Create the file, fail if exists, write-only, binary */
+               fdes = open(buf, O_CREAT | O_EXCL | O_WRONLY | O_BINARY, mode);
+               /* Set creator and type if the file is successfully opened */
+               if (fdes >= 0) fsetfileinfo(buf, _fcreator, _ftype);
+               /* Return the descriptor */
+               return (fdes);
+       }
 # else
        /* Create the file, fail if exists, write-only, binary */
        return (open(buf, O_CREAT | O_EXCL | O_WRONLY | O_BINARY, mode));
@@ -791,9 +833,6 @@ errr fd_seek(int fd, huge n)
        p = lseek(fd, n, SEEK_SET);
 
        /* Failure */
-       if (p < 0) return (1);
-
-       /* Failure */
        if (p != n) return (1);
 
        /* Success */
@@ -1083,7 +1122,7 @@ static void trigger_text_to_ascii(char **bufptr, cptr *strptr)
        /* Invalid trigger name? */
        if (i == max_macrotrigger)
        {
-               str = strchr(str, ']');
+               str = my_strchr(str, ']');
                if (str)
                {
                        *s++ = (char)31;
@@ -1147,7 +1186,10 @@ void text_to_ascii(char *buf, cptr str)
                        /* Skip the backslash */
                        str++;
 
-                        /* Macro Trigger */
+                       /* Paranoia */
+                       if (!(*str)) break;
+
+                       /* Macro Trigger */
                        if (*str == '[')
                        {
                                trigger_text_to_ascii(&s, &str);
@@ -1260,7 +1302,7 @@ void text_to_ascii(char *buf, cptr str)
 }
 
 
-bool trigger_ascii_to_text(char **bufptr, cptr *strptr)
+static bool trigger_ascii_to_text(char **bufptr, cptr *strptr)
 {
        char *s = *bufptr;
        cptr str = *strptr;
@@ -1282,7 +1324,7 @@ bool trigger_ascii_to_text(char **bufptr, cptr *strptr)
                switch(ch)
                {
                case '&':
-                       while ((tmp = strchr(macro_modifier_chr, *str)))
+                       while ((tmp = my_strchr(macro_modifier_chr, *str)))
                        {
                                j = (int)(tmp - macro_modifier_chr);
                                tmp = macro_modifier_name[j];
@@ -1610,21 +1652,6 @@ errr macro_add(cptr pat, cptr act)
 
 
 /*
- * Initialize the "macro" package
- */
-errr macro_init(void)
-{
-       /* Macro patterns */
-       C_MAKE(macro__pat, MACRO_MAX, cptr);
-
-       /* Macro actions */
-       C_MAKE(macro__act, MACRO_MAX, cptr);
-
-       /* Success */
-       return (0);
-}
-
-/*
  * Local variable -- we are inside a "macro action"
  *
  * Do not match any macros until "ascii 30" is found.
@@ -1649,7 +1676,7 @@ static bool parse_under = FALSE;
 void flush(void)
 {
        /* Do it later */
-        inkey_xtra = TRUE;
+       inkey_xtra = TRUE;
 }
 
 
@@ -1708,13 +1735,25 @@ static char inkey_aux(void)
 
        cptr pat, act;
 
-       char buf[1024];
+       char *buf = inkey_macro_trigger_string;
 
        /* Hack : ¥­¡¼ÆþÎÏÂÔ¤Á¤Ç»ß¤Þ¤Ã¤Æ¤¤¤ë¤Î¤Ç¡¢Î®¤ì¤¿¹Ô¤Îµ­²±¤ÏÉÔÍס£ */
        num_more = 0;
 
-       /* Wait for a keypress */
-       (void)(Term_inkey(&ch, TRUE, TRUE));
+       if (parse_macro)
+       {
+               /* Scan next keypress from macro action */
+               if (Term_inkey(&ch, FALSE, TRUE))
+               {
+                       /* Over-flowed? Cancel macro action */
+                       parse_macro = FALSE;
+               }
+       }
+       else
+       {
+               /* Wait for a keypress */
+               (void) (Term_inkey(&ch, TRUE, TRUE));
+       }
 
 
        /* End "macro action" */
@@ -1729,7 +1768,6 @@ static char inkey_aux(void)
        /* Inside "macro trigger" */
        if (parse_under) return (ch);
 
-
        /* Save the first key, advance */
        buf[p++] = ch;
        buf[p] = '\0';
@@ -1766,10 +1804,10 @@ static char inkey_aux(void)
                else
                {
                        /* Increase "wait" */
-                       w += 10;
+                       w += 1;
 
                        /* Excessive delay */
-                       if (w >= 100) break;
+                       if (w >= 10) break;
 
                        /* Delay */
                        Term_xtra(TERM_XTRA_DELAY, w);
@@ -1839,6 +1877,33 @@ static char inkey_aux(void)
 
 
 /*
+ * Cancel macro action on the queue
+ */
+static void forget_macro_action(void)
+{
+       if (!parse_macro) return;
+
+       /* Drop following macro action string */
+       while (TRUE)
+       {
+               char ch;
+
+               /* End loop if no key ready */
+               if (Term_inkey(&ch, FALSE, TRUE)) break;
+
+               /* End loop if no key ready */
+               if (ch == 0) break;
+
+               /* End of "macro action" */
+               if (ch == 30) break;
+       }
+
+       /* No longer inside "macro action" */
+       parse_macro = FALSE;
+}
+
+
+/*
  * Mega-Hack -- special "inkey_next" pointer.  XXX XXX XXX
  *
  * This special pointer allows a sequence of keys to be "inserted" into
@@ -2167,6 +2232,22 @@ char inkey(void)
  */
 
 /*
+ * Initialize the quark array
+ */
+void quark_init(void)
+{
+       /* Quark variables */
+       C_MAKE(quark__str, QUARK_MAX, cptr);
+
+       /* Prepare first quark, which is used when quark_add() is failed */
+       quark__str[1] = string_make("");
+
+       /* There is one quark (+ NULL) */
+       quark__num = 2;
+}
+
+
+/*
  * Add a new "quark" to the set of quarks.
  */
 s16b quark_add(cptr str)
@@ -2180,8 +2261,8 @@ s16b quark_add(cptr str)
                if (streq(quark__str[i], str)) return (i);
        }
 
-       /* Paranoia -- Require room */
-       if (quark__num == QUARK_MAX) return (0);
+       /* Return "" when no room is available */
+       if (quark__num == QUARK_MAX) return 1;
 
        /* New maximal quark */
        quark__num = i + 1;
@@ -2201,8 +2282,8 @@ cptr quark_str(s16b i)
 {
        cptr q;
 
-       /* Verify */
-       if ((i < 0) || (i >= quark__num)) i = 0;
+       /* Return NULL for an invalid index */
+       if ((i < 1) || (i >= quark__num)) return NULL;
 
        /* Access the quark */
        q = quark__str[i];
@@ -2370,7 +2451,7 @@ void message_add(cptr str)
  for (t = buf; *t && (*t != '<' || (*(t+1) != 'x' )); t++) 
      if( iskanji(*t))t++;
 #else
-                for (t = buf; *t && (*t != '<'); t++);
+               for (t = buf; *t && (*t != '<'); t++);
 #endif
 
                if (*t)
@@ -2386,7 +2467,7 @@ void message_add(cptr str)
                }
 
                /* Limit the multiplier to 1000 */
-               if (buf && streq(buf, str) && (j < 1000))
+               if (streq(buf, str) && (j < 1000))
                {
                        j++;
 
@@ -2588,7 +2669,7 @@ static void msg_flush(int x)
        }
        now_damaged = FALSE;
 
-       if (!alive || !nagasu)
+       if (!p_ptr->playing || !nagasu)
        {
                /* Pause for response */
 #ifdef JP
@@ -2963,6 +3044,8 @@ void c_roff(byte a, cptr str)
 
                        /* Clear line, move cursor */
                        Term_erase(x, y, 255);
+
+                       break;
                }
 
                /* Clean up the char */
@@ -3062,7 +3145,7 @@ void c_roff(byte a, cptr str)
 
                /* Dump */
 #ifdef JP
-                Term_addch((byte)(a|0x10), ch);
+               Term_addch((byte)(a|0x10), ch);
 #else
                Term_addch(a, ch);
 #endif
@@ -3113,34 +3196,37 @@ void clear_from(int row)
 
 
 /*
- * Get some input at the cursor location.
+ * Get some string input at the cursor location.
  * Assume the buffer is initialized to a default string.
- * Note that this string is often "empty" (see below).
- * The default buffer is displayed in yellow until cleared.
- * Pressing RETURN right away accepts the default entry.
- * Normal chars clear the default and append the char.
- * Backspace clears the default or deletes the final char.
+ *
+ * The default buffer is in Overwrite mode and displayed in yellow at
+ * first.  Normal chars clear the yellow text and append the char in
+ * white text.
+ *
+ * LEFT (^B) and RIGHT (^F) movement keys move the cursor position.
+ * If the text is still displayed in yellow (Overwite mode), it will
+ * turns into white (Insert mode) when cursor moves.
+ *
+ * DELETE (^D) deletes a char at the cursor position.
+ * BACKSPACE (^H) deletes a char at the left of cursor position.
  * ESCAPE clears the buffer and the window and returns FALSE.
  * RETURN accepts the current buffer contents and returns TRUE.
  */
-bool askfor_aux(char *buf, int len)
+bool askfor_aux(char *buf, int len, bool numpad_cursor)
 {
        int y, x;
+       int pos = 0;
 
-       int i = 0;
-
-       int k = 0;
-
-       bool done = FALSE;
-
+       /*
+        * Text color
+        * TERM_YELLOW : Overwrite mode
+        * TERM_WHITE : Insert mode
+        */
+       byte color = TERM_YELLOW;
 
-#ifdef JP
-    int        k_flag[128];
-#endif
-       /* Locate the cursor */
+       /* Locate the cursor position */
        Term_locate(&x, &y);
 
-
        /* Paranoia -- check len */
        if (len < 1) len = 1;
 
@@ -3150,107 +3236,232 @@ bool askfor_aux(char *buf, int len)
        /* Restrict the length */
        if (x + len > 80) len = 80 - x;
 
-
        /* Paranoia -- Clip the default entry */
        buf[len] = '\0';
 
 
-       /* Display the default answer */
-       Term_erase(x, y, len);
-       Term_putstr(x, y, -1, TERM_YELLOW, buf);
-
-
        /* Process input */
-       while (!done)
+       while (TRUE)
        {
+               int skey;
+
+               /* Display the string */
+               Term_erase(x, y, len);
+               Term_putstr(x, y, -1, color, buf);
+
                /* Place cursor */
-               Term_gotoxy(x + k, y);
+               Term_gotoxy(x + pos, y);
 
-               /* Get a key */
-               i = inkey();
+               /* Get a special key code */
+               skey = inkey_special(numpad_cursor);
 
                /* Analyze the key */
-               switch (i)
+               switch (skey)
                {
-               case ESCAPE:
-                       k = 0;
-                       done = TRUE;
+               case SKEY_LEFT:
+               case KTRL('b'):
+               {
+                       int i = 0;
+
+                       /* Now on insert mode */
+                       color = TERM_WHITE;
+
+                       /* No move at beginning of line */
+                       if (0 == pos) break;
+
+                       while (TRUE)
+                       {
+                               int next_pos = i + 1;
+
+#ifdef JP
+                               if (iskanji(buf[i])) next_pos++;
+#endif
+
+                               /* Is there the cursor at next position? */ 
+                               if (next_pos >= pos) break;
+
+                               /* Move to next */
+                               i = next_pos;
+                       }
+
+                       /* Get previous position */
+                       pos = i;
+
                        break;
+               }
+
+               case SKEY_RIGHT:
+               case KTRL('f'):
+                       /* Now on insert mode */
+                       color = TERM_WHITE;
+
+                       /* No move at end of line */
+                       if ('\0' == buf[pos]) break;
+
+#ifdef JP
+                       /* Move right */
+                       if (iskanji(buf[pos])) pos += 2;
+                       else pos++;
+#else
+                       pos++;
+#endif
+
+                       break;
+
+               case ESCAPE:
+                       /* Cancel input */
+                       buf[0] = '\0';
+                       return FALSE;
 
                case '\n':
                case '\r':
-                       k = strlen(buf);
-                       done = TRUE;
-                       break;
+                       /* Success */
+                       return TRUE;
 
-               case 0x7F:
                case '\010':
+                       /* Backspace */
+               {
+                       int i = 0;
+
+                       /* Now on insert mode */
+                       color = TERM_WHITE;
+
+                       /* No move at beginning of line */
+                       if (0 == pos) break;
+
+                       while (TRUE)
+                       {
+                               int next_pos = i + 1;
+
 #ifdef JP
-                               if (k > 0)
-                               {
-                                       k--;
-                                       if (k_flag[k] != 0)
-                                               k--;
-                               }
-#else
-                       if (k > 0) k--;
+                               if (iskanji(buf[i])) next_pos++;
 #endif
 
+                               /* Is there the cursor at next position? */ 
+                               if (next_pos >= pos) break;
+
+                               /* Move to next */
+                               i = next_pos;
+                       }
+
+                       /* Get previous position */
+                       pos = i;
+
+                       /* Fall through to 'Delete key' */
+               }
+
+               case 0x7F:
+               case KTRL('d'):
+                       /* Delete key */
+               {
+                       int dst, src;
+
+                       /* Now on insert mode */
+                       color = TERM_WHITE;
+
+                       /* No move at end of line */
+                       if ('\0' == buf[pos]) break;
+
+                       /* Position of next character */
+                       src = pos + 1;
+
+#ifdef JP
+                       /* Next character is one more byte away */
+                       if (iskanji(buf[pos])) src++;
+#endif
+
+                       dst = pos;
+
+                       /* Move characters at src to dst */
+                       while ('\0' != (buf[dst++] = buf[src++]))
+                               /* loop */;
+
                        break;
+               }
 
                default:
+               {
+                       /* Insert a character */
+
+                       char tmp[100];
+                       char c;
+
+                       /* Ignore special keys */
+                       if (skey & SKEY_MASK) break;
+
+                       /* Get a character code */
+                       c = (char)skey;
+
+                       if (color == TERM_YELLOW)
+                       {
+                               /* Overwrite default string */
+                               buf[0] = '\0';
+
+                               /* Go to insert mode */
+                               color = TERM_WHITE;
+                       }
+
+                       /* Save right part of string */
+                       strcpy(tmp, buf + pos);
 #ifdef JP
-       {                       /* ÊÒ»³¤µ¤óºîÀ® */
-                int next;
-
-                                if (iskanji (i)) {
-                                        inkey_base = TRUE;
-                                        next = inkey ();
-                                        if (k+1 < len) {
-                                                buf[k++] = i;
-                                                buf[k] = next;
-                                                k_flag[k++] = 1;
-                                        } else
-                                                bell();
-                                } else {
-#ifdef SJIS
-                    if(k<len && (isprint(i) || (0xa0<=i && i<=0xdf))){
-#else
-                    if(k<len && isprint(i)){
-#endif
-                                                buf[k] = i;
-                                                k_flag[k++] = 0;
-                                        } else
-                                                bell();
-                              }
-                }
-#else
-                       if ((k < len) && (isprint(i)))
+                       if (iskanji(c))
                        {
-                               buf[k++] = i;
+                               char next;
+
+                               /* Bypass macro processing */
+                               inkey_base = TRUE;
+                               next = inkey();
+
+                               if (pos + 1 < len)
+                               {
+                                       buf[pos++] = c;
+                                       buf[pos++] = next;
+                               }
+                               else
+                               {
+                                       bell();
+                               }
                        }
                        else
+#endif
                        {
-                               bell();
-                       }
+#ifdef JP
+                               if (pos < len && (isprint(c) || iskana(c)))
+#else
+                               if (pos < len && isprint(c))
 #endif
+                               {
+                                       buf[pos++] = c;
+                               }
+                               else
+                               {
+                                       bell();
+                               }
+                       }
+
+                       /* Terminate */
+                       buf[pos] = '\0';
+
+                       /* Write back the left part of string */
+                       my_strcat(buf, tmp, len + 1);
 
                        break;
-               }
+               } /* default: */
 
-               /* Terminate */
-               buf[k] = '\0';
+               }
 
-               /* Update the entry */
-               Term_erase(x, y, len);
-               Term_putstr(x, y, -1, TERM_WHITE, buf);
-       }
+       } /* while (TRUE) */
+}
 
-       /* Aborted */
-       if (i == ESCAPE) return (FALSE);
 
-       /* Success */
-       return (TRUE);
+/*
+ * Get some string input at the cursor location.
+ *
+ * Allow to use numpad keys as cursor keys.
+ */
+bool askfor(char *buf, int len)
+{
+       return askfor_aux(buf, len, TRUE);
 }
 
 
@@ -3275,7 +3486,7 @@ bool get_string(cptr prompt, char *buf, int len)
        prt(prompt, 0, 0);
 
        /* Ask the user for a string */
-       res = askfor_aux(buf, len);
+       res = askfor(buf, len);
 
        /* Clear prompt */
        prt("", 0, 0);
@@ -3303,11 +3514,13 @@ bool get_check(cptr prompt)
  * mode & CHECK_OKAY_CANCEL : force user to answer 'O'kay or 'C'ancel
  * mode & CHECK_NO_ESCAPE   : don't allow ESCAPE key
  * mode & CHECK_NO_HISTORY  : no message_add
+ * mode & CHECK_DEFAULT_Y   : accept any key as y, except n and Esc.
  */
 bool get_check_strict(cptr prompt, int mode)
 {
        int i;
        char buf[80];
+       bool flag = FALSE;
 
        if (auto_more)
        {
@@ -3326,35 +3539,24 @@ bool get_check_strict(cptr prompt, int mode)
        /* Hack -- Build a "useful" prompt */
        if (mode & CHECK_OKAY_CANCEL)
        {
-#ifdef JP
-               /* (79-8)¥Ð¥¤¥È¤Î»ØÄê, prompt¤¬Ä¹¤«¤Ã¤¿¾ì¹ç, 
-                  (79-9)ʸ»ú¤Î¸å½ªÃ¼Ê¸»ú¤¬½ñ¤­¹þ¤Þ¤ì¤ë.     
-                  ±Ñ¸ì¤ÎÊý¤Îstrncpy¤È¤Ï°ã¤¦¤Î¤ÇÃí°Õ.
-                  else¤ÎÊý¤Îʬ´ô¤âƱÍÍ. --henkma
-               */
-               mb_strlcpy(buf, prompt, 80-15);
-#else
-               strncpy(buf, prompt, 79-15);
-               buf[79-8]='\0';
-#endif
+               my_strcpy(buf, prompt, sizeof(buf)-15);
                strcat(buf, "[(O)k/(C)ancel]");
-
+       }
+       else if (mode & CHECK_DEFAULT_Y)
+       {
+               my_strcpy(buf, prompt, sizeof(buf)-5);
+               strcat(buf, "[Y/n]");
        }
        else
        {
-#ifdef JP
-               mb_strlcpy(buf, prompt, 80-5);
-#else
-               strncpy(buf, prompt, 79-5);
-               buf[79-5]='\0';
-#endif
+               my_strcpy(buf, prompt, sizeof(buf)-5);
                strcat(buf, "[y/n]");
        }
 
        /* Prompt for it */
        prt(buf, 0, 0);
 
-       if (!(mode & CHECK_NO_HISTORY))
+       if (!(mode & CHECK_NO_HISTORY) && p_ptr->playing)
        {
                /* HACK : Add the line to message buffer */
                message_add(buf);
@@ -3366,41 +3568,57 @@ bool get_check_strict(cptr prompt, int mode)
        while (TRUE)
        {
                i = inkey();
-               if (mode & CHECK_OKAY_CANCEL)
+
+               if (!(mode & CHECK_NO_ESCAPE))
                {
-                       if ( i == 'o' || i == 'O' )
+                       if (i == ESCAPE)
                        {
-                               i = 'Y';
+                               flag = FALSE;
                                break;
                        }
                }
-               else if (i == 'y' || i == 'Y')
+
+               if (mode & CHECK_OKAY_CANCEL)
                {
+                       if (i == 'o' || i == 'O')
+                       {
+                               flag = TRUE;
                                break;
+                       }
+                       else if (i == 'c' || i == 'C')
+                       {
+                               flag = FALSE;
+                               break;
+                       }
                }
-               if (!(mode & CHECK_NO_ESCAPE) && (i == ESCAPE)) break;
-               if ( mode & CHECK_OKAY_CANCEL )
+               else
                {
-                       if ( i == 'c' || i == 'C' )
+                       if (i == 'y' || i == 'Y')
+                       {
+                               flag = TRUE;
+                               break;
+                       }
+                       else if (i == 'n' || i == 'N')
                        {
+                               flag = FALSE;
                                break;
                        }
                }
-               else if (i == 'n' || i == 'N')
+
+               if (mode & CHECK_DEFAULT_Y)
                {
-                               break;
+                       flag = TRUE;
+                       break;
                }
+
                bell();
        }
 
        /* Erase the prompt */
        prt("", 0, 0);
 
-       /* Normal negation */
-       if ((i != 'Y') && (i != 'y')) return (FALSE);
-
-       /* Success */
-       return (TRUE);
+       /* Return the flag */
+       return flag;
 }
 
 
@@ -3420,7 +3638,10 @@ bool get_com(cptr prompt, char *command, bool z_escape)
        prt(prompt, 0, 0);
 
        /* Get a key */
-       *command = inkey();
+       if (get_com_no_macros)
+               *command = inkey_special(FALSE);
+       else
+               *command = inkey();
 
        /* Clear the prompt */
        prt("", 0, 0);
@@ -3441,10 +3662,9 @@ bool get_com(cptr prompt, char *command, bool z_escape)
  */
 s16b get_quantity(cptr prompt, int max)
 {
+       bool res;
        int amt;
-
        char tmp[80];
-
        char buf[80];
 
 
@@ -3486,7 +3706,7 @@ s16b get_quantity(cptr prompt, int max)
        {
                /* Build a prompt */
 #ifdef JP
-                       sprintf(tmp, "¤¤¤¯¤Ä¤Ç¤¹¤« (1-%d): ", max);
+               sprintf(tmp, "¤¤¤¯¤Ä¤Ç¤¹¤« (1-%d): ", max);
 #else
                sprintf(tmp, "Quantity (1-%d): ", max);
 #endif
@@ -3496,6 +3716,11 @@ s16b get_quantity(cptr prompt, int max)
                prompt = tmp;
        }
 
+       /* Paranoia XXX XXX XXX */
+       msg_print(NULL);
+
+       /* Display prompt */
+       prt(prompt, 0, 0);
 
        /* Default to one */
        amt = 1;
@@ -3503,8 +3728,17 @@ s16b get_quantity(cptr prompt, int max)
        /* Build the default */
        sprintf(buf, "%d", amt);
 
-       /* Ask for a quantity */
-       if (!get_string(prompt, buf, 6)) return (0);
+       /*
+        * Ask for a quantity
+        * Don't allow to use numpad as cursor key.
+        */
+       res = askfor_aux(buf, 6, FALSE);
+
+       /* Clear prompt */
+       prt("", 0, 0);
+
+       /* Cancelled */
+       if (!res) return 0;
 
        /* Extract a number */
        amt = atoi(buf);
@@ -3534,7 +3768,6 @@ s16b get_quantity(cptr prompt, int max)
  */
 void pause_line(int row)
 {
-       int i;
        prt("", row, 0);
 #ifdef JP
        put_str("[ ²¿¤«¥­¡¼¤ò²¡¤·¤Æ²¼¤µ¤¤ ]", row, 26);
@@ -3542,7 +3775,7 @@ void pause_line(int row)
        put_str("[Press any key to continue]", row, 23);
 #endif
 
-       i = inkey();
+       (void)inkey();
        prt("", row, 0);
 }
 
@@ -3704,7 +3937,7 @@ menu_naiyou menu_info[10][10] =
                {"Items(other)", 4, FALSE},
                {"Equip", 5, FALSE},
                {"Door/Box", 6, FALSE},
-               {"Infomations", 7, FALSE},
+               {"Informations", 7, FALSE},
                {"Options", 8, FALSE},
                {"Other commands", 9, FALSE},
                {"", 0, FALSE},
@@ -3731,7 +3964,7 @@ menu_naiyou menu_info[10][10] =
                {"Target(*)", '*', TRUE},
                {"Dig(T/^t)", 'T', TRUE},
                {"Go up stairs(<)", '<', TRUE},
-               {"Go down staies(>)", '>', TRUE},
+               {"Go down stairs(>)", '>', TRUE},
                {"Command pets(p)", 'p', TRUE},
                {"Search mode ON/OFF(S/#)", 'S', TRUE}
        },
@@ -3796,7 +4029,7 @@ menu_naiyou menu_info[10][10] =
                {"Identify symbol(/)", '/', TRUE},
                {"Show prev messages(^p)", KTRL('P'), TRUE},
                {"Current time(^t/')", KTRL('T'), TRUE},
-               {"Various infomations(~)", '~', TRUE},
+               {"Various informations(~)", '~', TRUE},
                {"Play record menu(|)", '|', TRUE},
                {"", 0, FALSE}
        },
@@ -3846,9 +4079,13 @@ special_menu_naiyou special_menu_info[] =
 {
        {"ĶǽÎÏ/ÆüìǽÎÏ", 0, 0, MENU_CLASS, CLASS_MINDCRAFTER},
        {"¤â¤Î¤Þ¤Í/ÆüìǽÎÏ", 0, 0, MENU_CLASS, CLASS_IMITATOR},
+       {"²Î/ÆüìǽÎÏ", 0, 0, MENU_CLASS, CLASS_BARD},
        {"ɬ»¦µ»/ÆüìǽÎÏ", 0, 0, MENU_CLASS, CLASS_SAMURAI},
        {"Îýµ¤½Ñ/ËâË¡/ÆüìǽÎÏ", 0, 0, MENU_CLASS, CLASS_FORCETRAINER},
+       {"µ»/ÆüìǽÎÏ", 0, 0, MENU_CLASS, CLASS_BERSERKER},
+       {"µ»½Ñ/ÆüìǽÎÏ", 0, 0, MENU_CLASS, CLASS_SMITH},
        {"¶ÀËâË¡/ÆüìǽÎÏ", 0, 0, MENU_CLASS, CLASS_MIRROR_MASTER},
+       {"Ǧ½Ñ/ÆüìǽÎÏ", 0, 0, MENU_CLASS, CLASS_NINJA},
        {"¹­°è¥Þ¥Ã¥×(<)", 2, 6, MENU_WILD, FALSE},
        {"Ä̾ï¥Þ¥Ã¥×(>)", 2, 7, MENU_WILD, TRUE},
        {"", 0, 0, 0, 0},
@@ -3858,9 +4095,13 @@ special_menu_naiyou special_menu_info[] =
 {
        {"MindCraft/Special", 0, 0, MENU_CLASS, CLASS_MINDCRAFTER},
        {"Imitation/Special", 0, 0, MENU_CLASS, CLASS_IMITATOR},
+       {"Song/Special", 0, 0, MENU_CLASS, CLASS_BARD},
        {"Technique/Special", 0, 0, MENU_CLASS, CLASS_SAMURAI},
        {"Mind/Magic/Special", 0, 0, MENU_CLASS, CLASS_FORCETRAINER},
+       {"BrutalPower/Special", 0, 0, MENU_CLASS, CLASS_BERSERKER},
+       {"Technique/Special", 0, 0, MENU_CLASS, CLASS_SMITH},
        {"MirrorMagic/Special", 0, 0, MENU_CLASS, CLASS_MIRROR_MASTER},
+       {"Ninjutsu/Special", 0, 0, MENU_CLASS, CLASS_NINJA},
        {"Enter global map(<)", 2, 6, MENU_WILD, FALSE},
        {"Enter local map(>)", 2, 7, MENU_WILD, TRUE},
        {"", 0, 0, 0, 0},
@@ -4040,7 +4281,7 @@ void request_command(int shopping)
        cptr act;
 
 #ifdef JP
-        int caretcmd = 0;
+       int caretcmd = 0;
 #endif
        /* Roguelike */
        if (rogue_like_commands)
@@ -4290,7 +4531,7 @@ prt(format("
        if (always_repeat && (command_arg <= 0))
        {
                /* Hack -- auto repeat certain commands */
-               if (strchr("TBDoc+", command_cmd))
+               if (my_strchr("TBDoc+", command_cmd))
                {
                        /* Repeat 99 times */
                        command_arg = 99;
@@ -4315,21 +4556,22 @@ prt(format("
        }
 
 #ifdef JP
-        for (i = 0; i < 256; i++)
-        {
-                cptr s;
-                if ((s = keymap_act[mode][i]) != NULL)
-                {
-                        if (*s == command_cmd && *(s+1) == 0)
-                        {
-                                caretcmd = i;
-                                break;
-                        }
-                }
-        }
-        if (!caretcmd)
-                caretcmd = command_cmd;
+       for (i = 0; i < 256; i++)
+       {
+               cptr s;
+               if ((s = keymap_act[mode][i]) != NULL)
+               {
+                       if (*s == command_cmd && *(s+1) == 0)
+                       {
+                               caretcmd = i;
+                               break;
+                       }
+               }
+       }
+       if (!caretcmd)
+               caretcmd = command_cmd;
 #endif
+
        /* Hack -- Scan equipment */
        for (i = INVEN_RARM; i < INVEN_TOTAL; i++)
        {
@@ -4347,14 +4589,14 @@ prt(format("
                s = quark_str(o_ptr->inscription);
 
                /* Find a '^' */
-               s = strchr(s, '^');
+               s = my_strchr(s, '^');
 
                /* Process preventions */
                while (s)
                {
                        /* Check the "restriction" character */
 #ifdef JP
-                        if ((s[1] == caretcmd) || (s[1] == '*'))
+                       if ((s[1] == caretcmd) || (s[1] == '*'))
 #else
                        if ((s[1] == command_cmd) || (s[1] == '*'))
 #endif
@@ -4374,7 +4616,7 @@ prt(format("
                        }
 
                        /* Find another '^' */
-                       s = strchr(s + 1, '^');
+                       s = my_strchr(s + 1, '^');
                }
        }
 
@@ -4426,7 +4668,7 @@ static bool insert_str(char *buf, cptr target, cptr insert)
        int                b_len, t_len, i_len;
 
        /* Attempt to find the target (modify "buf") */
-       buf = strstr(buf, target);
+       buf = my_strstr(buf, target);
 
        /* No target found */
        if (!buf) return (FALSE);
@@ -4478,28 +4720,50 @@ static bool insert_str(char *buf, cptr target, cptr insert)
  */
 int get_keymap_dir(char ch)
 {
-       cptr act, s;
        int d = 0;
 
-       if (rogue_like_commands)
+       /* Already a direction? */
+       if (isdigit(ch))
        {
-               act = keymap_act[KEYMAP_MODE_ROGUE][(byte)ch];
+               d = D2I(ch);
        }
        else
        {
-               act = keymap_act[KEYMAP_MODE_ORIG][(byte)ch];
-       }
+               int mode;
+               cptr act, s;
 
-       if (act)
-       {
-               /* Convert to a direction */
-               for (s = act; *s; ++s)
+               /* Roguelike */
+               if (rogue_like_commands)
                {
-                       /* Use any digits in keymap */
-                       if (isdigit(*s)) d = D2I(*s);
+                       mode = KEYMAP_MODE_ROGUE;
+               }
+
+               /* Original */
+               else
+               {
+                       mode = KEYMAP_MODE_ORIG;
+               }
+
+               /* Extract the action (if any) */
+               act = keymap_act[mode][(byte)(ch)];
+
+               /* Analyze */
+               if (act)
+               {
+                       /* Convert to a direction */
+                       for (s = act; *s; ++s)
+                       {
+                               /* Use any digits in keymap */
+                               if (isdigit(*s)) d = D2I(*s);
+                       }
                }
        }
-       return d;
+
+       /* Paranoia */
+       if (d == 5) d = 0;
+
+       /* Return direction */
+       return (d);
 }
 
 
@@ -4601,14 +4865,9 @@ static void swap(tag_type *a, tag_type *b)
 {
        tag_type temp;
 
-       temp.tag = a->tag;
-       temp.pointer = a->pointer;
-
-       a->tag = b->tag;
-       a->pointer = b->pointer;
-
-       b->tag = temp.tag;
-       b->pointer = temp.pointer;
+       temp = *a;
+       *a = *b;
+       *b = temp;
 }
 
 
@@ -4809,49 +5068,115 @@ void build_gamma_table(int gamma)
 
 #endif /* SUPPORT_GAMMA */
 
-void roff_to_buf(cptr str, int maxlen, char *tbuf)
+
+/*
+ * Add a series of keypresses to the "queue".
+ *
+ * Return any errors generated by Term_keypress() in doing so, or SUCCESS
+ * if there are none.
+ *
+ * Catch the "out of space" error before anything is printed.
+ *
+ * NB: The keys added here will be interpreted by any macros or keymaps.
+ */
+errr type_string(cptr str, uint len)
+{
+       errr err = 0;
+       cptr s;
+
+       term *old = Term;
+
+       /* Paranoia - no string. */
+       if (!str) return -1;
+
+       /* Hack - calculate the string length here if none given. */
+       if (!len) len = strlen(str);
+
+       /* Activate the main window, as all pastes go there. */
+       Term_activate(term_screen);
+
+       for (s = str; s < str+len; s++)
+       {
+               /* Catch end of string */
+               if (*s == '\0') break;
+
+               err = Term_keypress(*s);
+
+               /* Catch errors */
+               if (err) break;
+       }
+
+       /* Activate the original window. */
+       Term_activate(old);
+
+       return err;
+}
+
+
+
+void roff_to_buf(cptr str, int maxlen, char *tbuf, size_t bufsize)
 {
        int read_pt = 0;
        int write_pt = 0;
        int line_len = 0;
        int word_punct = 0;
-       unsigned char ch[3];
+       char ch[3];
        ch[2] = '\0';
 
        while (str[read_pt])
        {
 #ifdef JP
+               bool kinsoku = FALSE;
                bool kanji;
 #endif
+               int ch_len = 1;
+
+               /* Prepare one character */
                ch[0] = str[read_pt];
                ch[1] = '\0';
 #ifdef JP
                kanji  = iskanji(ch[0]);
+
                if (kanji)
+               {
                        ch[1] = str[read_pt+1];
-               if (!kanji && !isprint(ch[0]))
+                       ch_len = 2;
+
+                       if (strcmp(ch, "¡£") == 0 ||
+                           strcmp(ch, "¡¢") == 0 ||
+                           strcmp(ch, "¥£") == 0 ||
+                           strcmp(ch, "¡¼") == 0)
+                               kinsoku = TRUE;
+               }
+               else if (!isprint(ch[0]))
                        ch[0] = ' ';
 #else
                if (!isprint(ch[0]))
                        ch[0] = ' ';
 #endif
 
-               if (line_len >= maxlen - 1 || str[read_pt] == '\n')
+               if (line_len + ch_len > maxlen - 1 || str[read_pt] == '\n')
                {
                        int word_len;
 
                        /* return to better wrapping point. */
                        /* Space character at the end of the line need not to be printed. */
                        word_len = read_pt - word_punct;
-                       if (ch[0] != ' ' && word_len < line_len/2)
+#ifdef JP
+                       if (kanji && !kinsoku)
+                               /* nothing */ ;
+                       else
+#endif
+                       if (ch[0] == ' ' || word_len >= line_len/2)
+                               read_pt++;
+                       else
                        {
                                read_pt = word_punct;
                                if (str[word_punct] == ' ')
                                        read_pt++;
                                write_pt -= word_len;
                        }
-                       else
-                               read_pt++;
+
                        tbuf[write_pt++] = '\0';
                        line_len = 0;
                        word_punct = read_pt;
@@ -4860,11 +5185,12 @@ void roff_to_buf(cptr str, int maxlen, char *tbuf)
                if (ch[0] == ' ')
                        word_punct = read_pt;
 #ifdef JP
-               if (kanji &&
-                   strcmp((char *)ch, "¡£") != 0 && strcmp((char *)ch, "¡¢") != 0 &&
-                   strcmp((char *)ch, "¥£") != 0 && strcmp((char *)ch, "¡¼") != 0)
-                       word_punct = read_pt;
+               if (!kinsoku) word_punct = read_pt;
 #endif
+
+               /* Not enough buffer size */
+               if ((size_t)(write_pt + 3) >= bufsize) break;
+
                tbuf[write_pt++] = ch[0];
                line_len++;
                read_pt++;
@@ -4883,3 +5209,313 @@ void roff_to_buf(cptr str, int maxlen, char *tbuf)
        return;
 }
 
+
+/*
+ * The my_strcpy() function copies up to 'bufsize'-1 characters from 'src'
+ * to 'buf' and NUL-terminates the result.  The 'buf' and 'src' strings may
+ * not overlap.
+ *
+ * my_strcpy() returns strlen(src).  This makes checking for truncation
+ * easy.  Example: if (my_strcpy(buf, src, sizeof(buf)) >= sizeof(buf)) ...;
+ *
+ * This function should be equivalent to the strlcpy() function in BSD.
+ */
+size_t my_strcpy(char *buf, const char *src, size_t bufsize)
+{
+#ifdef JP
+
+       char *d = buf;
+       const char *s = src;
+       size_t len = 0;
+
+       if (bufsize > 0) {
+               /* reserve for NUL termination */
+               bufsize--;
+
+               /* Copy as many bytes as will fit */
+               while (*s && (len < bufsize))
+               {
+                       if (iskanji(*s))
+                       {
+                               if (len + 1 >= bufsize || !*(s+1)) break;
+                               *d++ = *s++;
+                               *d++ = *s++;
+                               len += 2;
+                       }
+                       else
+                       {
+                               *d++ = *s++;
+                               len++;
+                       }
+               }
+               *d = '\0';
+       }
+
+       while(*s++) len++;
+
+       return len;
+
+#else
+
+       size_t len = strlen(src);
+       size_t ret = len;
+
+       /* Paranoia */
+       if (bufsize == 0) return ret;
+
+       /* Truncate */
+       if (len >= bufsize) len = bufsize - 1;
+
+       /* Copy the string and terminate it */
+       (void)memcpy(buf, src, len);
+       buf[len] = '\0';
+
+       /* Return strlen(src) */
+       return ret;
+
+#endif
+}
+
+
+/*
+ * The my_strcat() tries to append a string to an existing NUL-terminated string.
+ * It never writes more characters into the buffer than indicated by 'bufsize' and
+ * NUL-terminates the buffer.  The 'buf' and 'src' strings may not overlap.
+ *
+ * my_strcat() returns strlen(buf) + strlen(src).  This makes checking for
+ * truncation easy.  Example:
+ * if (my_strcat(buf, src, sizeof(buf)) >= sizeof(buf)) ...;
+ *
+ * This function should be equivalent to the strlcat() function in BSD.
+ */
+size_t my_strcat(char *buf, const char *src, size_t bufsize)
+{
+       size_t dlen = strlen(buf);
+
+       /* Is there room left in the buffer? */
+       if (dlen < bufsize - 1)
+       {
+               /* Append as much as possible  */
+               return (dlen + my_strcpy(buf + dlen, src, bufsize - dlen));
+       }
+       else
+       {
+               /* Return without appending */
+               return (dlen + strlen(src));
+       }
+}
+
+
+/*
+ * A copy of ANSI strstr()
+ *
+ * my_strstr() can handle Kanji strings correctly.
+ */
+char *my_strstr(const char *haystack, const char *needle)
+{
+       int i;
+       int l1 = strlen(haystack);
+       int l2 = strlen(needle);
+
+       if (l1 >= l2)
+       {
+               for(i = 0; i <= l1 - l2; i++)
+               {
+                       if(!strncmp(haystack + i, needle, l2))
+                               return (char *)haystack + i;
+
+#ifdef JP
+                       if (iskanji(*(haystack + i))) i++;
+#endif
+               }
+       }
+
+       return NULL;
+}
+
+
+/*
+ * A copy of ANSI strchr()
+ *
+ * my_strchr() can handle Kanji strings correctly.
+ */
+char *my_strchr(const char *ptr, char ch)
+{
+       for ( ; *ptr != '\0'; ptr++)
+       {
+               if (*ptr == ch) return (char *)ptr;
+
+#ifdef JP
+               if (iskanji(*ptr)) ptr++;
+#endif
+       }
+
+       return NULL;
+}
+
+
+/*
+ * Convert string to lower case
+ */
+void str_tolower(char *str)
+{
+       /* Force to be lower case string */
+       for (; *str; str++)
+       {
+#ifdef JP
+               if (iskanji(*str))
+               {
+                       str++;
+                       continue;
+               }
+#endif
+               *str = tolower(*str);
+       }
+}
+
+
+/*
+ * Get a keypress from the user.
+ * And interpret special keys as internal code.
+ *
+ * This function is a Mega-Hack and depend on pref-xxx.prf's.
+ * Currently works on Linux(UNIX), Windows, and Macintosh only.
+ */
+int inkey_special(bool numpad_cursor)
+{
+       static const struct {
+               cptr keyname;
+               int keyflag;
+       } modifier_key_list[] = {
+               {"shift-", SKEY_MOD_SHIFT},
+               {"control-", SKEY_MOD_CONTROL},
+               {NULL, 0},
+       };
+
+       static const struct {
+               bool numpad;
+               cptr keyname;
+               int keycode;
+       } special_key_list[] = {
+               {FALSE, "Down]", SKEY_DOWN},
+               {FALSE, "Left]", SKEY_LEFT},
+               {FALSE, "Right]", SKEY_RIGHT},
+               {FALSE, "Up]", SKEY_UP},
+               {FALSE, "Page_Up]", SKEY_PGUP},
+               {FALSE, "Page_Down]", SKEY_PGDOWN},
+               {FALSE, "Home]", SKEY_TOP},
+               {FALSE, "End]", SKEY_BOTTOM},
+               {TRUE, "KP_Down]", SKEY_DOWN},
+               {TRUE, "KP_Left]", SKEY_LEFT},
+               {TRUE, "KP_Right]", SKEY_RIGHT},
+               {TRUE, "KP_Up]", SKEY_UP},
+               {TRUE, "KP_Page_Up]", SKEY_PGUP},
+               {TRUE, "KP_Page_Down]", SKEY_PGDOWN},
+               {TRUE, "KP_Home]", SKEY_TOP},
+               {TRUE, "KP_End]", SKEY_BOTTOM},
+               {TRUE, "KP_2]", SKEY_DOWN},
+               {TRUE, "KP_4]", SKEY_LEFT},
+               {TRUE, "KP_6]", SKEY_RIGHT},
+               {TRUE, "KP_8]", SKEY_UP},
+               {TRUE, "KP_9]", SKEY_PGUP},
+               {TRUE, "KP_3]", SKEY_PGDOWN},
+               {TRUE, "KP_7]", SKEY_TOP},
+               {TRUE, "KP_1]", SKEY_BOTTOM},
+               {FALSE, NULL, 0},
+       };
+       char buf[1024];
+       cptr str = buf;
+       char key;
+       int skey = 0;
+       int modifier = 0;
+       int i;
+       size_t trig_len;
+
+       /*
+        * Forget macro trigger ----
+        * It's important if we are already expanding macro action
+        */
+       inkey_macro_trigger_string[0] = '\0';
+
+       /* Get a keypress */
+       key = inkey();
+
+       /* Examine trigger string */
+       trig_len = strlen(inkey_macro_trigger_string);
+
+       /* Already known that no special key */
+       if (!trig_len) return (int)((unsigned char)key);
+
+       /*
+        * Hack -- Ignore macro defined on ASCII characters.
+        */
+       if (trig_len == 1 && parse_macro)
+       {
+               char c = inkey_macro_trigger_string[0];
+
+               /* Cancel macro action on the queue */
+               forget_macro_action();
+
+               /* Return the originaly pressed key */
+               return (int)((unsigned char)c);
+       }
+
+       /* Convert the trigger */
+       ascii_to_text(buf, inkey_macro_trigger_string);
+
+       /* Check the prefix "\[" */
+       if (prefix(str, "\\["))
+       {
+               /* Skip "\[" */
+               str += 2;
+
+               /* Examine modifier keys */
+               while (TRUE)
+               {
+                       for (i = 0; modifier_key_list[i].keyname; i++)
+                       {
+                               if (prefix(str, modifier_key_list[i].keyname))
+                               {
+                                       /* Get modifier key flag */
+                                       str += strlen(modifier_key_list[i].keyname);
+                                       modifier |= modifier_key_list[i].keyflag;
+                               }
+                       }
+
+                       /* No more modifier key found */
+                       if (!modifier_key_list[i].keyname) break;
+               }
+
+               /* numpad_as_cursorkey option force numpad keys to input numbers */
+               if (!numpad_as_cursorkey) numpad_cursor = FALSE;
+
+               /* Get a special key code */
+               for (i = 0; special_key_list[i].keyname; i++)
+               {
+                       if ((!special_key_list[i].numpad || numpad_cursor) &&
+                           streq(str, special_key_list[i].keyname))
+                       {
+                               skey = special_key_list[i].keycode;
+                               break;
+                       }
+               }
+
+               /* A special key found */
+               if (skey)
+               {
+                       /* Cancel macro action on the queue */
+                       forget_macro_action();
+
+                       /* Return special key code and modifier flags */
+                       return (skey | modifier);
+               }
+       }
+
+       /* No special key found? */
+
+       /* Don't bother with this trigger no more */
+       inkey_macro_trigger_string[0] = '\0';
+
+       /* Return normal keycode */
+       return (int)((unsigned char)key);
+}