OSDN Git Service

Merge pull request #716 from sikabane-works/release/3.0.0Alpha16
[hengbandforosx/hengbandosx.git] / src / util / string-processor.cpp
1 #include "util/string-processor.h"
2 #include "util/int-char-converter.h"
3
4 /*!
5  * 10進数から16進数への変換テーブル /
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
8  */
9 const char hexsym[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
10
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]; /*!< マクロの内容 */
17
18 /*
19  * Convert a decimal to a single digit octal number
20  */
21 static char octify(uint i) { return (hexsym[i % 8]); }
22
23 /*
24  * Convert a decimal to a single digit hex number
25  */
26 static char hexify(uint i) { return (hexsym[i % 16]); }
27
28 /*
29  * Convert a octal-digit into a decimal
30  */
31 static int deoct(char c)
32 {
33     if (isdigit(c))
34         return (D2I(c));
35     return 0;
36 }
37
38 /*
39  * Convert a hexidecimal-digit into a decimal
40  */
41 static int dehex(char c)
42 {
43     if (isdigit(c))
44         return (D2I(c));
45     if (islower(c))
46         return (A2I(c) + 10);
47     if (isupper(c))
48         return (A2I(tolower(c)) + 10);
49     return 0;
50 }
51
52 static char force_upper(char a) { return (islower(a)) ? toupper(a) : a; }
53
54 static int angband_stricmp(concptr a, concptr b)
55 {
56     for (concptr s1 = a, s2 = b; TRUE; s1++, s2++) {
57         char z1 = force_upper(*s1);
58         char z2 = force_upper(*s2);
59         if (z1 < z2)
60             return -1;
61         if (z1 > z2)
62             return 1;
63         if (!z1)
64             return 0;
65     }
66 }
67
68 static int angband_strnicmp(concptr a, concptr b, int n)
69 {
70     for (concptr s1 = a, s2 = b; n > 0; s1++, s2++, n--) {
71         char z1 = force_upper(*s1);
72         char z2 = force_upper(*s2);
73         if (z1 < z2)
74             return -1;
75         if (z1 > z2)
76             return 1;
77         if (!z1)
78             return 0;
79     }
80
81     return 0;
82 }
83
84 static void trigger_text_to_ascii(char **bufptr, concptr *strptr)
85 {
86     char *s = *bufptr;
87     concptr str = *strptr;
88     bool mod_status[MAX_MACRO_MOD];
89
90     int i, len = 0;
91     int shiftstatus = 0;
92     concptr key_code;
93
94     if (macro_template == NULL)
95         return;
96
97     for (i = 0; macro_modifier_chr[i]; i++)
98         mod_status[i] = FALSE;
99     str++;
100
101     /* Examine modifier keys */
102     while (TRUE) {
103         for (i = 0; macro_modifier_chr[i]; i++) {
104             len = strlen(macro_modifier_name[i]);
105
106             if (!angband_strnicmp(str, macro_modifier_name[i], len))
107                 break;
108         }
109
110         if (!macro_modifier_chr[i])
111             break;
112         str += len;
113         mod_status[i] = TRUE;
114         if ('S' == macro_modifier_chr[i])
115             shiftstatus = 1;
116     }
117
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]) {
121             break;
122         }
123     }
124
125     if (i == max_macrotrigger) {
126         str = angband_strchr(str, ']');
127         if (str) {
128             *s++ = (char)31;
129             *s++ = '\r';
130             *bufptr = s;
131             *strptr = str; /* where **strptr == ']' */
132         }
133
134         return;
135     }
136
137     key_code = macro_trigger_keycode[shiftstatus][i];
138     str += len;
139
140     *s++ = (char)31;
141     for (i = 0; macro_template[i]; i++) {
142         char ch = macro_template[i];
143         switch (ch) {
144         case '&':
145             for (int j = 0; macro_modifier_chr[j]; j++) {
146                 if (mod_status[j])
147                     *s++ = macro_modifier_chr[j];
148             }
149
150             break;
151         case '#':
152             strcpy(s, key_code);
153             s += strlen(key_code);
154             break;
155         default:
156             *s++ = ch;
157             break;
158         }
159     }
160
161     *s++ = '\r';
162
163     *bufptr = s;
164     *strptr = str; /* where **strptr == ']' */
165     return;
166 }
167
168 /*
169  * Hack -- convert a printable string into real ascii
170  *
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.
174  */
175 void text_to_ascii(char *buf, concptr str)
176 {
177     char *s = buf;
178     while (*str) {
179         if (*str == '\\') {
180             str++;
181             if (!(*str))
182                 break;
183
184             if (*str == '[') {
185                 trigger_text_to_ascii(&s, &str);
186             } else {
187                 if (*str == 'x') {
188                     *s = 16 * (char)dehex(*++str);
189                     *s++ += (char)dehex(*++str);
190                 } else if (*str == '\\') {
191                     *s++ = '\\';
192                 } else if (*str == '^') {
193                     *s++ = '^';
194                 } else if (*str == 's') {
195                     *s++ = ' ';
196                 } else if (*str == 'e') {
197                     *s++ = ESCAPE;
198                 } else if (*str == 'b') {
199                     *s++ = '\b';
200                 } else if (*str == 'n') {
201                     *s++ = '\n';
202                 } else if (*str == 'r') {
203                     *s++ = '\r';
204                 } else if (*str == 't') {
205                     *s++ = '\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);
218                 }
219             }
220
221             str++;
222         } else if (*str == '^') {
223             str++;
224             *s++ = (*str++ & 037);
225         } else {
226             *s++ = *str++;
227         }
228     }
229
230     *s = '\0';
231 }
232
233 static bool trigger_ascii_to_text(char **bufptr, concptr *strptr)
234 {
235     char *s = *bufptr;
236     concptr str = *strptr;
237     char key_code[100];
238     int i;
239     if (macro_template == NULL)
240         return FALSE;
241
242     *s++ = '\\';
243     *s++ = '[';
244
245     concptr tmp;
246     for (i = 0; macro_template[i]; i++) {
247         char ch = macro_template[i];
248
249         switch (ch) {
250         case '&':
251             while ((tmp = angband_strchr(macro_modifier_chr, *str)) != 0) {
252                 int j = (int)(tmp - macro_modifier_chr);
253                 tmp = macro_modifier_name[j];
254                 while (*tmp)
255                     *s++ = *tmp++;
256                 str++;
257             }
258
259             break;
260         case '#': {
261             int j;
262             for (j = 0; *str && *str != '\r'; j++)
263                 key_code[j] = *str++;
264             key_code[j] = '\0';
265             break;
266         }
267         default:
268             if (ch != *str)
269                 return FALSE;
270             str++;
271         }
272     }
273
274     if (*str++ != '\r')
275         return FALSE;
276
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]))
279             break;
280     }
281
282     if (i == max_macrotrigger)
283         return FALSE;
284
285     tmp = macro_trigger_name[i];
286     while (*tmp)
287         *s++ = *tmp++;
288
289     *s++ = ']';
290
291     *bufptr = s;
292     *strptr = str;
293     return TRUE;
294 }
295
296 /*
297  * Hack -- convert a string into a printable form
298  */
299 void ascii_to_text(char *buf, concptr str)
300 {
301     char *s = buf;
302     while (*str) {
303         byte i = (byte)(*str++);
304         if (i == 31) {
305             if (!trigger_ascii_to_text(&s, &str)) {
306                 *s++ = '^';
307                 *s++ = '_';
308             }
309         } else {
310             if (i == ESCAPE) {
311                 *s++ = '\\';
312                 *s++ = 'e';
313             } else if (i == ' ') {
314                 *s++ = '\\';
315                 *s++ = 's';
316             } else if (i == '\b') {
317                 *s++ = '\\';
318                 *s++ = 'b';
319             } else if (i == '\t') {
320                 *s++ = '\\';
321                 *s++ = 't';
322             } else if (i == '\n') {
323                 *s++ = '\\';
324                 *s++ = 'n';
325             } else if (i == '\r') {
326                 *s++ = '\\';
327                 *s++ = 'r';
328             } else if (i == '^') {
329                 *s++ = '\\';
330                 *s++ = '^';
331             } else if (i == '\\') {
332                 *s++ = '\\';
333                 *s++ = '\\';
334             } else if (i < 32) {
335                 *s++ = '^';
336                 *s++ = i + 64;
337             } else if (i < 127) {
338                 *s++ = i;
339             } else if (i < 64) {
340                 *s++ = '\\';
341                 *s++ = '0';
342                 *s++ = octify(i / 8);
343                 *s++ = octify(i % 8);
344             } else {
345                 *s++ = '\\';
346                 *s++ = 'x';
347                 *s++ = hexify(i / 16);
348                 *s++ = hexify(i % 16);
349             }
350         }
351     }
352
353     *s = '\0';
354 }
355
356 /*
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
359  * not overlap.
360  *
361  * angband_strcpy() returns strlen(src).  This makes checking for truncation
362  * easy.  Example: if (angband_strcpy(buf, src, sizeof(buf)) >= sizeof(buf)) ...;
363  *
364  * This function should be equivalent to the strlcpy() function in BSD.
365  */
366 size_t angband_strcpy(char *buf, concptr src, size_t bufsize)
367 {
368 #ifdef JP
369     char *d = buf;
370     concptr s = src;
371     size_t len = 0;
372
373     if (bufsize > 0) {
374         /* reserve for NUL termination */
375         bufsize--;
376
377         /* Copy as many bytes as will fit */
378         while (*s && (len < bufsize)) {
379             if (iskanji(*s)) {
380                 if (len + 1 >= bufsize || !*(s + 1))
381                     break;
382                 *d++ = *s++;
383                 *d++ = *s++;
384                 len += 2;
385             } else {
386                 *d++ = *s++;
387                 len++;
388             }
389         }
390         *d = '\0';
391     }
392
393     while (*s++)
394         len++;
395     return len;
396
397 #else
398     size_t len = strlen(src);
399     size_t ret = len;
400     if (bufsize == 0)
401         return ret;
402
403     if (len >= bufsize)
404         len = bufsize - 1;
405
406     (void)memcpy(buf, src, len);
407     buf[len] = '\0';
408     return ret;
409 #endif
410 }
411
412 /*
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.
416  *
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)) ...;
420  *
421  * This function should be equivalent to the strlcat() function in BSD.
422  */
423 size_t angband_strcat(char *buf, concptr src, size_t bufsize)
424 {
425     size_t dlen = strlen(buf);
426     if (dlen < bufsize - 1) {
427         return (dlen + angband_strcpy(buf + dlen, src, bufsize - dlen));
428     } else {
429         return (dlen + strlen(src));
430     }
431 }
432
433 /*
434  * A copy of ANSI strstr()
435  *
436  * angband_strstr() can handle Kanji strings correctly.
437  */
438 char *angband_strstr(concptr haystack, concptr needle)
439 {
440     int l1 = strlen(haystack);
441     int l2 = strlen(needle);
442
443     if (l1 >= l2) {
444         for (int i = 0; i <= l1 - l2; i++) {
445             if (!strncmp(haystack + i, needle, l2))
446                 return (char *)haystack + i;
447
448 #ifdef JP
449             if (iskanji(*(haystack + i)))
450                 i++;
451 #endif
452         }
453     }
454
455     return NULL;
456 }
457
458 /*
459  * A copy of ANSI strchr()
460  *
461  * angband_strchr() can handle Kanji strings correctly.
462  */
463 char *angband_strchr(concptr ptr, char ch)
464 {
465     for (; *ptr != '\0'; ptr++) {
466         if (*ptr == ch)
467             return (char *)ptr;
468
469 #ifdef JP
470         if (iskanji(*ptr))
471             ptr++;
472 #endif
473     }
474
475     return NULL;
476 }
477
478 /*!
479  * @brief 左側の空白を除去
480  * @param p char型のポインタ
481  * @return 除去後のポインタ
482  */
483 char *ltrim(char *p)
484 {
485     while (p[0] == ' ')
486         p++;
487     return p;
488 }
489
490 /*!
491  * @brief 右側の空白を除去
492  * @param p char型のポインタ
493  * @return 除去後のポインタ
494  */
495 char *rtrim(char *p)
496 {
497     int i = strlen(p) - 1;
498     while (p[i] == ' ')
499         p[i--] = '\0';
500     return p;
501 }
502
503 /*!
504  * @brief 文字列の後方から一致するかどうか比較する
505  * @param s1 比較元文字列ポインタ
506  * @param s2 比較先文字列ポインタ
507  * @param len 比較する長さ
508  * @return 等しい場合は0、p1が大きい場合は-1、p2が大きい場合は1
509  * @detail
510  * strncmpの後方から比較する版
511  */
512 int strrncmp(const char *s1, const char *s2, int len)
513 {
514     int i;
515     int l1 = strlen(s1);
516     int l2 = strlen(s2);
517
518     for (i = 1; i <= len; i++) {
519         int p1 = l1 - i;
520         int p2 = l2 - i;
521
522         if (l1 != l2) {
523             if (p1 < 0)
524                 return (-1);
525             if (p2 < 0)
526                 return (1);
527         } else {
528             if (p1 < 0)
529                 return (0);
530         }
531
532         if (s1[p1] < s2[p2])
533             return (-1);
534         if (s1[p1] > s2[p2])
535             return (-1);
536     }
537
538     return (0);
539 }