+
+/*
+ * 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},
+ };
+
+ static const struct {
+ cptr keyname;
+ int keycode;
+ } gcu_special_key_list[] = {
+ {"A", SKEY_UP},
+ {"B", SKEY_DOWN},
+ {"C", SKEY_RIGHT},
+ {"D", SKEY_LEFT},
+ {"1~", SKEY_TOP},
+ {"4~", SKEY_BOTTOM},
+ {"5~", SKEY_PGUP},
+ {"6~", SKEY_PGDOWN},
+ {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);
+ }
+ }
+
+ if (prefix(str, "\\e["))
+ {
+ str += 3;
+
+ for (i = 0; gcu_special_key_list[i].keyname; i++)
+ {
+ if (streq(str, gcu_special_key_list[i].keyname))
+ {
+ return gcu_special_key_list[i].keycode;
+ }
+ }
+ }
+
+ /* 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);
+}