OSDN Git Service

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