OSDN Git Service

[Refactor] ダンジョンのモンスター出現フィルターに適用
[hengbandforosx/hengbandosx.git] / src / term / z-form.cpp
1 /* File: z-form.c */
2
3 /*
4  * Copyright (c) 1997 Ben Harrison
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.
9  */
10
11 /* Purpose: Low level text formatting -BEN- */
12
13 #include "term/z-form.h"
14 #include "term/z-util.h"
15 #include "term/z-virt.h"
16 #include <vector>
17
18 /*
19  * Here is some information about the routines in this file.
20  *
21  * In general, the following routines take a "buffer", a "max length",
22  * a "format string", and some "arguments", and use the format string
23  * and the arguments to create a (terminated) string in the buffer
24  * (using only the first "max length" bytes), and return the "length"
25  * of the resulting string, not including the (mandatory) terminator.
26  *
27  * The format strings allow the basic "sprintf()" format sequences, though
28  * some of them are processed slightly more carefully or portably, as well
29  * as a few "special" sequences, including the "%r" and "%v" sequences, and
30  * the "capilitization" sequences of "%C", "%S", and "%V".
31  *
32  * Note that some "limitations" are enforced by the current implementation,
33  * for example, no "format sequence" can exceed 100 characters, including any
34  * "length" restrictions, and the result of combining and "format sequence"
35  * with the relevent "arguments" must not exceed 1000 characters.
36  *
37  * These limitations could be fixed by stealing some of the code from,
38  * say, "vsprintf()" and placing it into my "vstrnfmt()" function.
39  *
40  * Note that a "^" inside a "format sequence" causes the first non-space
41  * character in the string resulting from the combination of the format
42  * sequence and the argument(s) to be "capitalized" if possible.  Note
43  * that the "^" character is removed before the "standard" formatting
44  * routines are called.  Likewise, a "*" inside a "format sequence" is
45  * removed from the "format sequence", and replaced by the textual form
46  * of the next argument in the argument list.  See examples below.
47  *
48  * Legal format characters: %,n,p,c,s,d,i,o,u,X,x,E,e,F,f,G,g,r,v.
49  *
50  * Format("%%")
51  *   Append the literal "%".
52  *   No legal modifiers.
53  *
54  * Format("%n", int *np)
55  *   Save the current length into (*np).
56  *   No legal modifiers.
57  *
58  * Format("%p", vptr v)
59  *   Append the pointer "v" (implementation varies).
60  *   No legal modifiers.
61  *
62  * Format("%E", double r)
63  * Format("%F", double r)
64  * Format("%G", double r)
65  * Format("%e", double r)
66  * Format("%f", double r)
67  * Format("%g", double r)
68  *   Append the double "r", in various formats.
69  *
70  * Format("%ld", long int i)
71  *   Append the long integer "i".
72  *
73  * Format("%Ld", long long int i)
74  *   Append the long long integer "i".
75  *
76  * Format("%d", int i)
77  *   Append the integer "i".
78  *
79  * Format("%lu", unsigned long int i)
80  *   Append the unsigned long integer "i".
81  *
82  * Format("%Lu", unsigned long long int i)
83  *   Append the unsigned long long integer "i".
84  *
85  * Format("%u", unsigned int i)
86  *   Append the unsigned integer "i".
87  *
88  * Format("%lo", unsigned long int i)
89  *   Append the unsigned long integer "i", in octal.
90  *
91  * Format("%o", unsigned int i)
92  *   Append the unsigned integer "i", in octal.
93  *
94  * Format("%lX", unsigned long int i)
95  *   Note -- use all capital letters
96  * Format("%lx", unsigned long int i)
97  *   Append the unsigned long integer "i", in hexidecimal.
98  *
99  * Format("%X", unsigned int i)
100  *   Note -- use all capital letters
101  * Format("%x", unsigned int i)
102  *   Append the unsigned integer "i", in hexidecimal.
103  *
104  * Format("%c", char c)
105  *   Append the character "c".
106  *   Do not use the "+" or "0" flags.
107  *
108  * Format("%s", concptr s)
109  *   Append the string "s".
110  *   Do not use the "+" or "0" flags.
111  *   Note that a "nullptr" value of "s" is converted to the empty string.
112  *
113  * Format("%V", vptr v)
114  *   Note -- possibly significant mode flag
115  * Format("%v", vptr v)
116  *   Append the object "v", using the current "user defined print routine".
117  *   User specified modifiers, often ignored.
118  *
119  * Format("%r", vstrnfmt_aux_func *fp)
120  *   Set the "user defined print routine" (vstrnfmt_aux) to "fp".
121  *   No legal modifiers.
122  *
123  *
124  * For examples below, assume "int n = 0; int m = 100; char buf[100];",
125  * plus "char *s = nullptr;", and unknown values "char *txt; int i;".
126  *
127  * For example: "n = strnfmt(buf, -1, "(Max %d)", i);" will have a
128  * similar effect as "sprintf(buf, "(Max %d)", i); n = strlen(buf);".
129  *
130  * For example: "(void)strnfmt(buf, 16, "%s", txt);" will have a similar
131  * effect as "strncpy(buf, txt, 16); buf[15] = '\0';".
132  *
133  * For example: "if (strnfmt(buf, 16, "%s", txt) < 16) ..." will have
134  * a similar effect as "strcpy(buf, txt)" but with bounds checking.
135  *
136  * For example: "s = buf; s += vstrnfmt(s, -1, ...); ..." will allow
137  * multiple "appends" to "buf" (at the cost of losing the max-length info).
138  *
139  * For example: "s = buf; n = vstrnfmt(s+n, 100-n, ...); ..." will allow
140  * multiple bounded "appends" to "buf", with constant access to "strlen(buf)".
141  *
142  * For example: "format("The %r%v was destroyed!", obj_desc, obj);"
143  * (where "obj_desc(buf, max, fmt, obj)" will "append" a "description"
144  * of the given object to the given buffer, and return the total length)
145  * will return a "useful message" about the object "obj", for example,
146  * "The Large Shield was destroyed!".
147  *
148  * For example: "format("%^-.*s", i, txt)" will produce a string containing
149  * the first "i" characters of "txt", left justified, with the first non-space
150  * character capitilized, if reasonable.
151  */
152
153 /*
154  * The "type" of the "user defined print routine" pointer
155  */
156 typedef uint (*vstrnfmt_aux_func)(char *buf, uint max, concptr fmt, vptr arg);
157
158 /*
159  * The "default" user defined print routine.  Ignore the "fmt" string.
160  */
161 static uint vstrnfmt_aux_dflt(char *buf, uint max, concptr fmt, vptr arg)
162 {
163     uint len;
164     char tmp[32];
165
166     /* XXX XXX */
167     fmt = fmt ? fmt : 0;
168
169     /* Pointer display */
170     sprintf(tmp, "<<%p>>", arg);
171     len = strlen(tmp);
172     if (len >= max) {
173         len = max - 1;
174     }
175     tmp[len] = '\0';
176     strcpy(buf, tmp);
177     return len;
178 }
179
180 /*
181  * The "current" user defined print routine.  It can be changed
182  * dynamically by sending the proper "%r" sequence to "vstrnfmt()"
183  */
184 static vstrnfmt_aux_func vstrnfmt_aux = vstrnfmt_aux_dflt;
185
186 /*
187  * Basic "vararg" format function.
188  *
189  * This function takes a buffer, a max byte count, a format string, and
190  * a va_list of arguments to the format string, and uses the format string
191  * and the arguments to create a string to the buffer.  The string is
192  * derived from the format string and the arguments in the manner of the
193  * "sprintf()" function, but with some extra "format" commands.  Note that
194  * this function will never use more than the given number of bytes in the
195  * buffer, preventing messy invalid memory references.  This function then
196  * returns the total number of non-null bytes written into the buffer.
197  *
198  * Method: Let "str" be the (unlimited) created string, and let "len" be the
199  * smaller of "max-1" and "strlen(str)".  We copy the first "len" chars of
200  * "str" into "buf", place "\0" into buf[len], and return "len".
201  *
202  * In English, we do a sprintf() into "buf", a buffer with size "max",
203  * and we return the resulting value of "strlen(buf)", but we allow some
204  * special format commands, and we are more careful than "sprintf()".
205  *
206  * Typically, "max" is in fact the "size" of "buf", and thus represents
207  * the "number" of chars in "buf" which are ALLOWED to be used.  An
208  * alternative definition would have required "buf" to hold at least
209  * "max+1" characters, and would have used that extra character only
210  * in the case where "buf" was too short for the result.  This would
211  * give an easy test for "overflow", but a less "obvious" semantics.
212  *
213  * Note that if the buffer was "too short" to hold the result, we will
214  * always return "max-1", but we also return "max-1" if the buffer was
215  * "just long enough".  We could have returned "max" if the buffer was
216  * too short, not written a null, and forced the programmer to deal with
217  * this special case, but I felt that it is better to at least give a
218  * "usable" result when the buffer was too long instead of either giving
219  * a memory overwrite like "sprintf()" or a non-terminted string like
220  * "strncpy()".  Note that "strncpy()" also "null-pads" the result.
221  *
222  * Note that in most cases "just long enough" is probably "too short".
223  *
224  * We should also consider extracting and processing the "width" and other
225  * "flags" by hand, it might be more "accurate", and it would allow us to
226  * remove the limit (1000 chars) on the result of format sequences.
227  *
228  * Also, some sequences, such as "%+d" by hand, do not work on all machines,
229  * and could thus be correctly handled here.
230  *
231  * Error detection in this routine is not very graceful, in particular,
232  * if an error is detected in the format string, we simply "pre-terminate"
233  * the given buffer to a length of zero, and return a "length" of zero.
234  * The contents of "buf", except for "buf[0]", may then be undefined.
235  */
236 uint vstrnfmt(char *buf, uint max, concptr fmt, va_list vp)
237 {
238     concptr s;
239
240     /* The argument is "long" */
241     bool do_long;
242
243     /* The argument is "long long" */
244     bool do_long_long;
245
246     /* The argument needs "processing" */
247     bool do_xtra;
248
249     /* Bytes used in buffer */
250     uint n;
251
252     /* Bytes used in format sequence */
253     uint q;
254
255     /* Format sequence */
256     char aux[128];
257
258     /* Resulting string */
259     char tmp[1024];
260
261     /* Mega-Hack -- treat "illegal" length as "infinite" */
262     if (!max) {
263         max = 32767;
264     }
265
266     /* Mega-Hack -- treat "no format" as "empty string" */
267     if (!fmt) {
268         fmt = "";
269     }
270
271     /* Begin the buffer */
272     n = 0;
273
274     /* Begin the format string */
275     s = fmt;
276
277     /* Scan the format string */
278     while (true) {
279         /* All done */
280         if (!*s) {
281             break;
282         }
283
284         /* Normal character */
285         if (*s != '%') {
286             /* Check total length */
287             if (n == max - 1) {
288                 break;
289             }
290
291             /* Save the character */
292             buf[n++] = *s++;
293             continue;
294         }
295
296         /* Skip the "percent" */
297         s++;
298
299         /* Pre-process "%%" */
300         if (*s == '%') {
301             /* Check total length */
302             if (n == max - 1) {
303                 break;
304             }
305
306             /* Save the percent */
307             buf[n++] = '%';
308
309             /* Skip the "%" */
310             s++;
311             continue;
312         }
313
314         /* Pre-process "%n" */
315         if (*s == 'n') {
316             int *arg;
317
318             /* Access the next argument */
319             arg = va_arg(vp, int *);
320
321             /* Save the current length */
322             (*arg) = n;
323
324             /* Skip the "n" */
325             s++;
326             continue;
327         }
328
329         /* Hack -- Pre-process "%r" */
330         if (*s == 'r') {
331             /* Extract the next argument, and save it (globally) */
332             vstrnfmt_aux = va_arg(vp, vstrnfmt_aux_func);
333
334             /* Skip the "r" */
335             s++;
336             continue;
337         }
338
339         /* Begin the "aux" string */
340         q = 0;
341
342         /* Save the "percent" */
343         aux[q++] = '%';
344
345         /* Assume no "long" argument */
346         do_long = false;
347
348         /* Assume no "long long" argument */
349         do_long_long = false;
350
351         /* Assume no "xtra" processing */
352         do_xtra = false;
353
354         /* Build the "aux" string */
355         while (true) {
356             /* Error -- format sequence is not terminated */
357             if (!*s) {
358                 /* Terminate the buffer */
359                 buf[0] = '\0';
360
361                 /* Return "error" */
362                 return 0;
363             }
364
365             /* Error -- format sequence may be too long */
366             if (q > 100) {
367                 /* Terminate the buffer */
368                 buf[0] = '\0';
369
370                 /* Return "error" */
371                 return 0;
372             }
373
374             /* Handle "alphabetic" chars */
375             if (isalpha(*s)) {
376                 /* Hack -- handle "long" request */
377                 if (*s == 'l') {
378                     /* Save the character */
379                     aux[q++] = *s++;
380
381                     /* Note the "long" flag */
382                     do_long = true;
383                 }
384
385                 /* Mega-Hack -- handle "extra-long" request */
386                 else if (*s == 'L') {
387                     /* Save the character */
388                     aux[q++] = 'l';
389                     aux[q++] = 'l';
390                     s++;
391
392                     /* Note the "long long" flag */
393                     do_long_long = true;
394                 }
395
396                 /* Handle normal end of format sequence */
397                 else {
398                     /* Save the character */
399                     aux[q++] = *s++;
400
401                     /* Stop processing the format sequence */
402                     break;
403                 }
404             }
405
406             /* Handle "non-alphabetic" chars */
407             else {
408                 /* Hack -- Handle 'star' (for "variable length" argument) */
409                 if (*s == '*') {
410                     int arg;
411
412                     /* Access the next argument */
413                     arg = va_arg(vp, int);
414
415                     /* Hack -- append the "length" */
416                     sprintf(aux + q, "%d", arg);
417
418                     /* Hack -- accept the "length" */
419                     while (aux[q]) {
420                         q++;
421                     }
422
423                     /* Skip the "*" */
424                     s++;
425                 }
426
427                 /* Mega-Hack -- Handle 'caret' (for "uppercase" request) */
428                 else if (*s == '^') {
429                     /* Note the "xtra" flag */
430                     do_xtra = true;
431
432                     /* Skip the "^" */
433                     s++;
434                 }
435
436                 /* Collect "normal" characters (digits, "-", "+", ".", etc) */
437                 else {
438                     /* Save the character */
439                     aux[q++] = *s++;
440                 }
441             }
442         }
443
444         /* Terminate "aux" */
445         aux[q] = '\0';
446
447         /* Clear "tmp" */
448         tmp[0] = '\0';
449
450         /* Process the "format" char */
451         switch (aux[q - 1]) {
452         /* Simple Character -- standard format */
453         case 'c': {
454             int arg;
455
456             /* Access next argument */
457             arg = va_arg(vp, int);
458
459             /* Format the argument */
460             sprintf(tmp, "%c", arg);
461
462             break;
463         }
464
465         /* Signed Integers -- standard format */
466         case 'd':
467         case 'i': {
468             if (do_long) {
469                 long arg;
470
471                 /* Access next argument */
472                 arg = va_arg(vp, long);
473
474                 /* Format the argument */
475                 sprintf(tmp, aux, arg);
476             } else if (do_long_long) {
477                 long long arg;
478
479                 /* Access next argument */
480                 arg = va_arg(vp, long long);
481
482                 /* Format the argument */
483                 sprintf(tmp, aux, arg);
484             } else {
485                 int arg;
486
487                 /* Access next argument */
488                 arg = va_arg(vp, int);
489
490                 /* Format the argument */
491                 sprintf(tmp, aux, arg);
492             }
493
494             break;
495         }
496
497         /* Unsigned Integers -- various formats */
498         case 'u':
499         case 'o':
500         case 'x':
501         case 'X': {
502             if (do_long) {
503                 ulong arg;
504
505                 /* Access next argument */
506                 arg = va_arg(vp, ulong);
507
508                 sprintf(tmp, aux, arg);
509             } else if (do_long_long) {
510                 unsigned long long arg;
511
512                 /* Access next argument */
513                 arg = va_arg(vp, unsigned long long);
514
515                 sprintf(tmp, aux, arg);
516             } else {
517                 uint arg;
518
519                 /* Access next argument */
520                 arg = va_arg(vp, uint);
521                 sprintf(tmp, aux, arg);
522             }
523
524             break;
525         }
526
527         /* Floating Point -- various formats */
528         case 'f':
529         case 'e':
530         case 'E':
531         case 'g':
532         case 'G': {
533             double arg;
534
535             /* Access next argument */
536             arg = va_arg(vp, double);
537
538             /* Format the argument */
539             sprintf(tmp, aux, arg);
540
541             break;
542         }
543
544         /* Pointer -- implementation varies */
545         case 'p': {
546             vptr arg;
547
548             /* Access next argument */
549             arg = va_arg(vp, vptr);
550
551             /* Format the argument */
552             sprintf(tmp, aux, arg);
553
554             break;
555         }
556
557         /* String */
558         case 's': {
559             concptr arg;
560             char arg2[1024];
561
562             /* Access next argument */
563             arg = va_arg(vp, concptr);
564
565             /* Hack -- convert nullptr to EMPTY */
566             if (!arg) {
567                 arg = "";
568             }
569
570             /* Prevent buffer overflows */
571             strncpy(arg2, arg, 1024);
572             arg2[1023] = '\0';
573
574             /* Format the argument */
575             sprintf(tmp, aux, arg);
576
577             break;
578         }
579
580         /* User defined data */
581         case 'V':
582         case 'v': {
583             vptr arg;
584
585             /* Access next argument */
586             arg = va_arg(vp, vptr);
587
588             /* Format the "user data" */
589             sprintf(tmp, aux, arg);
590
591             break;
592         }
593
594         default: {
595             /* Error -- illegal format char */
596             buf[0] = '\0';
597
598             /* Return "error" */
599             return 0;
600         }
601         }
602
603 #ifdef JP
604         for (q = 0; tmp[q]; q++) {
605             if (iskanji(tmp[q])) {
606                 do_xtra = false;
607                 break;
608             }
609         }
610 #endif
611         /* Mega-Hack -- handle "capitilization" */
612         if (do_xtra) {
613             /* Now append "tmp" to "buf" */
614             for (q = 0; tmp[q]; q++) {
615                 /* Notice first non-space */
616                 if (!iswspace(tmp[q])) {
617                     /* Capitalize if possible */
618                     if (islower(tmp[q])) {
619                         tmp[q] = (char)toupper(tmp[q]);
620                     }
621
622                     break;
623                 }
624             }
625         }
626
627         /* Now append "tmp" to "buf" */
628         for (q = 0; tmp[q]; q++) {
629             /* Check total length */
630             if (n == max - 1) {
631                 break;
632             }
633
634             /* Save the character */
635 #ifdef JP
636             if (iskanji(tmp[q])) {
637                 if (tmp[q + 1]) {
638                     buf[n++] = tmp[q++];
639                 } else {
640                     // 最後の文字が2バイト文字の前半で終わる場合は空白で置き換えて終了する
641                     buf[n++] = ' ';
642                     break;
643                 }
644             }
645 #endif
646             buf[n++] = tmp[q];
647         }
648     }
649
650     /* Terminate buffer */
651     buf[n] = '\0';
652
653     /* Return length */
654     return n;
655 }
656
657 /*
658  * Do a vstrnfmt (see above) into a (growable) static buffer.
659  * This buffer is usable for very short term formatting of results.
660  */
661 char *vformat(concptr fmt, va_list vp)
662 {
663     /* Initial allocation */
664     static std::vector<char> format_buf(1024);
665
666     /* Null format yields last result */
667     if (!fmt) {
668         return format_buf.data();
669     }
670
671     /* Keep going until successful */
672     while (true) {
673         uint len;
674
675         /* Build the string */
676         len = vstrnfmt(format_buf.data(), format_buf.size(), fmt, vp);
677
678         /* Success */
679         if (len < format_buf.size() - 1) {
680             break;
681         }
682
683         /* Grow the buffer */
684         format_buf.resize(format_buf.size() * 2);
685     }
686
687     /* Return the new buffer */
688     return format_buf.data();
689 }
690
691 /*
692  * Do a vstrnfmt (see above) into a buffer of a given size.
693  */
694 uint strnfmt(char *buf, uint max, concptr fmt, ...)
695 {
696     uint len;
697
698     va_list vp;
699
700     /* Begin the Varargs Stuff */
701     va_start(vp, fmt);
702
703     /* Do a virtual fprintf to stderr */
704     len = vstrnfmt(buf, max, fmt, vp);
705
706     /* End the Varargs Stuff */
707     va_end(vp);
708
709     /* Return the number of bytes written */
710     return len;
711 }
712
713 /*
714  * Do a vstrnfmt (see above) into a buffer of unknown size.
715  * Since the buffer size is unknown, the user better verify the args.
716  */
717 uint strfmt(char *buf, concptr fmt, ...)
718 {
719     uint len;
720
721     va_list vp;
722
723     /* Begin the Varargs Stuff */
724     va_start(vp, fmt);
725
726     /* Build the string, assume 32K buffer */
727     len = vstrnfmt(buf, 32767, fmt, vp);
728
729     /* End the Varargs Stuff */
730     va_end(vp);
731
732     /* Return the number of bytes written */
733     return len;
734 }
735
736 /*
737  * Do a vstrnfmt() into (see above) into a (growable) static buffer.
738  * This buffer is usable for very short term formatting of results.
739  * Note that the buffer is (technically) writable, but only up to
740  * the length of the string contained inside it.
741  */
742 char *format(concptr fmt, ...)
743 {
744     char *res;
745     va_list vp;
746
747     /* Begin the Varargs Stuff */
748     va_start(vp, fmt);
749
750     /* Format the args */
751     res = vformat(fmt, vp);
752
753     /* End the Varargs Stuff */
754     va_end(vp);
755
756     /* Return the result */
757     return res;
758 }
759
760 /*
761  * Vararg interface to plog()
762  */
763 void plog_fmt(concptr fmt, ...)
764 {
765     char *res;
766     va_list vp;
767
768     /* Begin the Varargs Stuff */
769     va_start(vp, fmt);
770
771     /* Format the args */
772     res = vformat(fmt, vp);
773
774     /* End the Varargs Stuff */
775     va_end(vp);
776
777     /* Call plog */
778     plog(res);
779 }
780
781 /*
782  * Vararg interface to quit()
783  */
784 void quit_fmt(concptr fmt, ...)
785 {
786     char *res;
787     va_list vp;
788
789     /* Begin the Varargs Stuff */
790     va_start(vp, fmt);
791
792     /* Format */
793     res = vformat(fmt, vp);
794
795     /* End the Varargs Stuff */
796     va_end(vp);
797
798     /* Call quit() */
799     quit(res);
800 }
801
802 /*
803  * Vararg interface to core()
804  */
805 void core_fmt(concptr fmt, ...)
806 {
807     char *res;
808     va_list vp;
809
810     /* Begin the Varargs Stuff */
811     va_start(vp, fmt);
812
813     /* If requested, Do a virtual fprintf to stderr */
814     res = vformat(fmt, vp);
815
816     /* End the Varargs Stuff */
817     va_end(vp);
818
819     /* Call core() */
820     core(res);
821 }