1 #include "util/string-processor.h"
2 #include "util/int-char-converter.h"
6 * Global array for converting numbers to uppercase hecidecimal digit
7 * This array can also be used to convert a number to an octal digit
9 const char hexsym[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
11 int max_macrotrigger = 0; /*!< 現在登録中のマクロ(トリガー)の数 */
12 concptr macro_template = NULL; /*!< Angband設定ファイルのT: タグ情報から読み込んだ長いTコードを処理するために利用する文字列ポインタ */
13 concptr macro_modifier_chr; /*!< &x# で指定されるマクロトリガーに関する情報を記録する文字列ポインタ */
14 concptr macro_modifier_name[MAX_MACRO_MOD]; /*!< マクロ上で取り扱う特殊キーを文字列上で表現するためのフォーマットを記録した文字列ポインタ配列 */
15 concptr macro_trigger_name[MAX_MACRO_TRIG]; /*!< マクロのトリガーコード */
16 concptr macro_trigger_keycode[2][MAX_MACRO_TRIG]; /*!< マクロの内容 */
19 * Convert a decimal to a single digit octal number
21 static char octify(uint i) { return (hexsym[i % 8]); }
24 * Convert a decimal to a single digit hex number
26 static char hexify(uint i) { return (hexsym[i % 16]); }
29 * Convert a octal-digit into a decimal
31 static int deoct(char c)
39 * Convert a hexidecimal-digit into a decimal
41 static int dehex(char c)
48 return (A2I(tolower(c)) + 10);
52 static char force_upper(char a) { return (islower(a)) ? toupper(a) : a; }
54 static int angband_stricmp(concptr a, concptr b)
56 for (concptr s1 = a, s2 = b; TRUE; s1++, s2++) {
57 char z1 = force_upper(*s1);
58 char z2 = force_upper(*s2);
68 static int angband_strnicmp(concptr a, concptr b, int n)
70 for (concptr s1 = a, s2 = b; n > 0; s1++, s2++, n--) {
71 char z1 = force_upper(*s1);
72 char z2 = force_upper(*s2);
84 static void trigger_text_to_ascii(char **bufptr, concptr *strptr)
87 concptr str = *strptr;
88 bool mod_status[MAX_MACRO_MOD];
94 if (macro_template == NULL)
97 for (i = 0; macro_modifier_chr[i]; i++)
98 mod_status[i] = FALSE;
101 /* Examine modifier keys */
103 for (i = 0; macro_modifier_chr[i]; i++) {
104 len = strlen(macro_modifier_name[i]);
106 if (!angband_strnicmp(str, macro_modifier_name[i], len))
110 if (!macro_modifier_chr[i])
113 mod_status[i] = TRUE;
114 if ('S' == macro_modifier_chr[i])
118 for (i = 0; i < max_macrotrigger; i++) {
119 len = strlen(macro_trigger_name[i]);
120 if (!angband_strnicmp(str, macro_trigger_name[i], len) && ']' == str[len]) {
125 if (i == max_macrotrigger) {
126 str = angband_strchr(str, ']');
131 *strptr = str; /* where **strptr == ']' */
137 key_code = macro_trigger_keycode[shiftstatus][i];
141 for (i = 0; macro_template[i]; i++) {
142 char ch = macro_template[i];
145 for (int j = 0; macro_modifier_chr[j]; j++) {
147 *s++ = macro_modifier_chr[j];
153 s += strlen(key_code);
164 *strptr = str; /* where **strptr == ']' */
169 * Hack -- convert a printable string into real ascii
171 * I have no clue if this function correctly handles, for example,
172 * parsing "\xFF" into a (signed) char. Whoever thought of making
173 * the "sign" of a "char" undefined is a complete moron. Oh well.
175 void text_to_ascii(char *buf, concptr str)
185 trigger_text_to_ascii(&s, &str);
188 *s = 16 * (char)dehex(*++str);
189 *s++ += (char)dehex(*++str);
190 } else if (*str == '\\') {
192 } else if (*str == '^') {
194 } else if (*str == 's') {
196 } else if (*str == 'e') {
198 } else if (*str == 'b') {
200 } else if (*str == 'n') {
202 } else if (*str == 'r') {
204 } else if (*str == 't') {
206 } else if (*str == '0') {
207 *s = 8 * (char)deoct(*++str);
208 *s++ += (char)deoct(*++str);
209 } else if (*str == '1') {
210 *s = 64 + 8 * (char)deoct(*++str);
211 *s++ += (char)deoct(*++str);
212 } else if (*str == '2') {
213 *s = 64 * 2 + 8 * (char)deoct(*++str);
214 *s++ += (char)deoct(*++str);
215 } else if (*str == '3') {
216 *s = 64 * 3 + 8 * (char)deoct(*++str);
217 *s++ += (char)deoct(*++str);
222 } else if (*str == '^') {
224 *s++ = (*str++ & 037);
233 static bool trigger_ascii_to_text(char **bufptr, concptr *strptr)
236 concptr str = *strptr;
239 if (macro_template == NULL)
246 for (i = 0; macro_template[i]; i++) {
247 char ch = macro_template[i];
251 while ((tmp = angband_strchr(macro_modifier_chr, *str)) != 0) {
252 int j = (int)(tmp - macro_modifier_chr);
253 tmp = macro_modifier_name[j];
262 for (j = 0; *str && *str != '\r'; j++)
263 key_code[j] = *str++;
277 for (i = 0; i < max_macrotrigger; i++) {
278 if (!angband_stricmp(key_code, macro_trigger_keycode[0][i]) || !angband_stricmp(key_code, macro_trigger_keycode[1][i]))
282 if (i == max_macrotrigger)
285 tmp = macro_trigger_name[i];
297 * Hack -- convert a string into a printable form
299 void ascii_to_text(char *buf, concptr str)
303 byte i = (byte)(*str++);
305 if (!trigger_ascii_to_text(&s, &str)) {
313 } else if (i == ' ') {
316 } else if (i == '\b') {
319 } else if (i == '\t') {
322 } else if (i == '\n') {
325 } else if (i == '\r') {
328 } else if (i == '^') {
331 } else if (i == '\\') {
337 } else if (i < 127) {
342 *s++ = octify(i / 8);
343 *s++ = octify(i % 8);
347 *s++ = hexify(i / 16);
348 *s++ = hexify(i % 16);
357 * The angband_strcpy() function copies up to 'bufsize'-1 characters from 'src'
358 * to 'buf' and NUL-terminates the result. The 'buf' and 'src' strings may
361 * angband_strcpy() returns strlen(src). This makes checking for truncation
362 * easy. Example: if (angband_strcpy(buf, src, sizeof(buf)) >= sizeof(buf)) ...;
364 * This function should be equivalent to the strlcpy() function in BSD.
366 size_t angband_strcpy(char *buf, concptr src, size_t bufsize)
374 /* reserve for NUL termination */
377 /* Copy as many bytes as will fit */
378 while (*s && (len < bufsize)) {
380 if (len + 1 >= bufsize || !*(s + 1))
398 size_t len = strlen(src);
406 (void)memcpy(buf, src, len);
413 * The angband_strcat() tries to append a string to an existing NUL-terminated string.
414 * It never writes more characters into the buffer than indicated by 'bufsize' and
415 * NUL-terminates the buffer. The 'buf' and 'src' strings may not overlap.
417 * angband_strcat() returns strlen(buf) + strlen(src). This makes checking for
418 * truncation easy. Example:
419 * if (angband_strcat(buf, src, sizeof(buf)) >= sizeof(buf)) ...;
421 * This function should be equivalent to the strlcat() function in BSD.
423 size_t angband_strcat(char *buf, concptr src, size_t bufsize)
425 size_t dlen = strlen(buf);
426 if (dlen < bufsize - 1) {
427 return (dlen + angband_strcpy(buf + dlen, src, bufsize - dlen));
429 return (dlen + strlen(src));
434 * A copy of ANSI strstr()
436 * angband_strstr() can handle Kanji strings correctly.
438 char *angband_strstr(concptr haystack, concptr needle)
440 int l1 = strlen(haystack);
441 int l2 = strlen(needle);
444 for (int i = 0; i <= l1 - l2; i++) {
445 if (!strncmp(haystack + i, needle, l2))
446 return (char *)haystack + i;
449 if (iskanji(*(haystack + i)))
459 * A copy of ANSI strchr()
461 * angband_strchr() can handle Kanji strings correctly.
463 char *angband_strchr(concptr ptr, char ch)
465 for (; *ptr != '\0'; ptr++) {
480 * @param p char型のポインタ
492 * @param p char型のポインタ
497 int i = strlen(p) - 1;
504 * @brief 文字列の後方から一致するかどうか比較する
505 * @param s1 比較元文字列ポインタ
506 * @param s2 比較先文字列ポインタ
508 * @return 等しい場合は0、p1が大きい場合は-1、p2が大きい場合は1
512 int strrncmp(const char *s1, const char *s2, int len)
518 for (i = 1; i <= len; i++) {
542 * @brief 文字列の両端の空白を削除する
544 * 文字列 str の両端にある空白(スペースおよびタブ)を削除し、
545 * 削除した文字列を std::string 型のオブジェクトとして返す。
546 * 文字列全体が空白の場合は空文字列を返す。
548 * @param str 操作の対象とする文字列
549 * @return std::string strの両端の空白を削除した文字列
551 std::string str_trim(std::string_view str)
553 const auto start_pos = str.find_first_not_of(" \t");
554 const auto end_pos = str.find_last_not_of(" \t");
556 if (start_pos == std::string_view::npos || end_pos == std::string_view::npos) {
557 return std::string();
560 return std::string(str.substr(start_pos, end_pos - start_pos + 1));
564 * @brief 文字列の右端の空白を削除する
566 * 文字列 str の右端にある空白(スペースおよびタブ)を削除し、
567 * 削除した文字列を std::string 型のオブジェクトとして返す。
568 * 文字列全体が空白の場合は空文字列を返す。
570 * @param str 操作の対象とする文字列
571 * @return std::string strの右端の空白を削除した文字列
573 std::string str_rtrim(std::string_view str)
575 const auto end_pos = str.find_last_not_of(" \t");
577 if (end_pos == std::string_view::npos) {
578 return std::string();
581 return std::string(str.substr(0, end_pos + 1));
585 * @brief 文字列の左端の空白を削除する
587 * 文字列 str の左端にある空白(スペースおよびタブ)を削除し、
588 * 削除した文字列を std::string 型のオブジェクトとして返す。
589 * 文字列全体が空白の場合は空文字列を返す。
591 * @param str 操作の対象とする文字列
592 * @return std::string strの左端の空白を削除した文字列
594 std::string str_ltrim(std::string_view str)
596 const auto start_pos = str.find_first_not_of(" \t");
598 if (start_pos == std::string_view::npos) {
599 return std::string();
602 return std::string(str.substr(start_pos));
606 * @brief 文字列を指定した文字で分割する
608 * 文字列 str を delim で指定した文字で分割し、分割した文字列を要素とする配列を
609 * std::vector<std::string> 型のオブジェクトとして返す。
611 * @param str 操作の対象とする文字列
612 * @param delim 文字列を分割する文字
613 * @param trim trueの場合、分割した文字列の両端の空白を削除する
614 * @return std::vector<std::string> 分割した文字列を要素とする配列
616 std::vector<std::string> str_split(std::string_view str, char delim, bool trim)
618 std::vector<std::string> result;
620 auto make_str = [trim](std::string_view sv) { return trim ? str_trim(sv) : std::string(sv); };
624 for (size_t i = 0; i < str.size(); ++i) {
625 if (str[i] == delim) {
626 result.push_back(make_str(str.substr(0, i)));
627 str.remove_prefix(i + 1);
637 result.push_back(make_str(str));
644 * @brief 文字列から指定した文字を取り除く
646 * 文字列 str から文字列 erase_chars に含まれる文字をすべて削除し、
647 * 削除した文字列を std::string 型のオブジェクトとして返す。
649 * @param str 操作の対象とする文字列
650 * @param erase_chars 削除する文字を指定する文字列
651 * @return std::string 指定した文字をすべて削除した文字列
653 std::string str_erase(std::string str, std::string_view erase_chars)
655 for (auto it = str.begin(); it != str.end();) {
656 if (erase_chars.find(*it) != std::string_view::npos) {