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
286                         /* Continue */
287                         continue;
288                 }
289
290                 /* Skip the "percent" */
291                 s++;
292
293                 /* Pre-process "%%" */
294                 if (*s == '%')
295                 {
296                         /* Check total length */
297                         if (n == max-1) break;
298
299                         /* Save the percent */
300                         buf[n++] = '%';
301
302                         /* Skip the "%" */
303                         s++;
304
305                         /* Continue */
306                         continue;
307                 }
308
309                 /* Pre-process "%n" */
310                 if (*s == 'n')
311                 {
312                         int *arg;
313
314                         /* Access the next argument */
315                         arg = va_arg(vp, int *);
316
317                         /* Save the current length */
318                         (*arg) = n;
319
320                         /* Skip the "n" */
321                         s++;
322
323                         /* Continue */
324                         continue;
325                 }
326
327                 /* Hack -- Pre-process "%r" */
328                 if (*s == 'r')
329                 {
330                         /* Extract the next argument, and save it (globally) */
331                         vstrnfmt_aux = va_arg(vp, vstrnfmt_aux_func);
332
333                         /* Skip the "r" */
334                         s++;
335
336                         /* Continue */
337                         continue;
338                 }
339
340
341                 /* Begin the "aux" string */
342                 q = 0;
343
344                 /* Save the "percent" */
345                 aux[q++] = '%';
346
347                 /* Assume no "long" argument */
348                 do_long = FALSE;
349
350                 /* Assume no "xtra" processing */
351                 do_xtra = FALSE;
352
353                 /* Build the "aux" string */
354                 while (TRUE)
355                 {
356                         /* Error -- format sequence is not terminated */
357                         if (!*s)
358                         {
359                                 /* Terminate the buffer */
360                                 buf[0] = '\0';
361
362                                 /* Return "error" */
363                                 return (0);
364                         }
365
366                         /* Error -- format sequence may be too long */
367                         if (q > 100)
368                         {
369                                 /* Terminate the buffer */
370                                 buf[0] = '\0';
371
372                                 /* Return "error" */
373                                 return (0);
374                         }
375
376                         /* Handle "alphabetic" chars */
377                         if (isalpha(*s))
378                         {
379                                 /* Hack -- handle "long" request */
380                                 if (*s == 'l')
381                                 {
382                                         /* Save the character */
383                                         aux[q++] = *s++;
384
385                                         /* Note the "long" flag */
386                                         do_long = TRUE;
387                                 }
388
389                                 /* Mega-Hack -- handle "extra-long" request */
390                                 else if (*s == 'L')
391                                 {
392                                         /* Error -- illegal format char */
393                                         buf[0] = '\0';
394
395                                         /* Return "error" */
396                                         return (0);
397                                 }
398
399                                 /* Handle normal end of format sequence */
400                                 else
401                                 {
402                                         /* Save the character */
403                                         aux[q++] = *s++;
404
405                                         /* Stop processing the format sequence */
406                                         break;
407                                 }
408                         }
409
410                         /* Handle "non-alphabetic" chars */
411                         else
412                         {
413                                 /* Hack -- Handle 'star' (for "variable length" argument) */
414                                 if (*s == '*')
415                                 {
416                                         int arg;
417
418                                         /* Access the next argument */
419                                         arg = va_arg(vp, int);
420
421                                         /* Hack -- append the "length" */
422                                         sprintf(aux + q, "%d", arg);
423
424                                         /* Hack -- accept the "length" */
425                                         while (aux[q]) q++;
426
427                                         /* Skip the "*" */
428                                         s++;
429                                 }
430
431                                 /* Mega-Hack -- Handle 'caret' (for "uppercase" request) */
432                                 else if (*s == '^')
433                                 {
434                                         /* Note the "xtra" flag */
435                                         do_xtra = TRUE;
436
437                                         /* Skip the "^" */
438                                         s++;
439                                 }
440
441                                 /* Collect "normal" characters (digits, "-", "+", ".", etc) */
442                                 else
443                                 {
444                                         /* Save the character */
445                                         aux[q++] = *s++;
446                                 }
447                         }
448                 }
449
450
451                 /* Terminate "aux" */
452                 aux[q] = '\0';
453
454                 /* Clear "tmp" */
455                 tmp[0] = '\0';
456
457                 /* Process the "format" char */
458                 switch (aux[q-1])
459                 {
460                         /* Simple Character -- standard format */
461                         case 'c':
462                         {
463                                 int arg;
464
465                                 /* Access next argument */
466                                 arg = va_arg(vp, int);
467
468                                 /* Format the argument */
469                                 sprintf(tmp, "%c", arg);
470
471                                 break;
472                         }
473
474                         /* Signed Integers -- standard format */
475                         case 'd': case 'i':
476                         {
477                                 if (do_long)
478                                 {
479                                         long arg;
480
481                                         /* Access next argument */
482                                         arg = va_arg(vp, long);
483
484                                         /* Format the argument */
485                                         sprintf(tmp, aux, arg);
486                                 }
487                                 else
488                                 {
489                                         int arg;
490
491                                         /* Access next argument */
492                                         arg = va_arg(vp, int);
493
494                                         /* Format the argument */
495                                         sprintf(tmp, aux, arg);
496                                 }
497
498                                 break;
499                         }
500
501                         /* Unsigned Integers -- various formats */
502                         case 'u': case 'o': case 'x': case 'X':
503                         {
504                                 if (do_long)
505                                 {
506                                         unsigned long arg;
507
508                                         /* Access next argument */
509                                         arg = va_arg(vp, unsigned long);
510
511                                         sprintf(tmp, aux, arg);
512                                 }
513                                 else
514                                 {
515                                         unsigned int arg;
516
517                                         /* Access next argument */
518                                         arg = va_arg(vp, unsigned int);
519                                         sprintf(tmp, aux, arg);
520
521                                 }
522
523                                 break;
524                         }
525
526                         /* Floating Point -- various formats */
527                         case 'f':
528                         case 'e': case 'E':
529                         case 'g': case 'G':
530                         {
531                                 double arg;
532
533                                 /* Access next argument */
534                                 arg = va_arg(vp, double);
535
536                                 /* Format the argument */
537                                 sprintf(tmp, aux, arg);
538
539                                 break;
540                         }
541
542                         /* Pointer -- implementation varies */
543                         case 'p':
544                         {
545                                 vptr arg;
546
547                                 /* Access next argument */
548                                 arg = va_arg(vp, vptr);
549
550                                 /* Format the argument */
551                                 sprintf(tmp, aux, arg);
552
553                                 break;
554                         }
555
556                         /* String */
557                         case 's':
558                         {
559                                 cptr arg;
560                                 char arg2[1024];
561
562                                 /* Access next argument */
563                                 arg = va_arg(vp, cptr);
564
565                                 /* Hack -- convert NULL to EMPTY */
566                                 if (!arg) arg = "";
567
568                                 /* Prevent buffer overflows */
569                                 strncpy(arg2, arg, 1024);
570                                 arg2[1023] = '\0';
571
572                                 /* Format the argument */
573                                 sprintf(tmp, aux, arg);
574
575                                 break;
576                         }
577
578                         /* User defined data */
579                         case 'V':
580                         case 'v':
581                         {
582                                 vptr arg;
583
584                                 /* Access next argument */
585                                 arg = va_arg(vp, vptr);
586
587                                 /* Format the "user data" */
588                                 sprintf(tmp, aux, arg);
589
590                                 break;
591                         }
592
593
594                         default:
595                         {
596                                 /* Error -- illegal format char */
597                                 buf[0] = '\0';
598
599                                 /* Return "error" */
600                                 return (0);
601                         }
602                 }
603
604
605 #ifdef JP
606                 for (q = 0; tmp[q]; q++) if (iskanji(tmp[q])) { do_xtra=FALSE;break;} 
607 #endif
608                 /* Mega-Hack -- handle "capitilization" */
609                 if (do_xtra)
610                 {
611                         /* Now append "tmp" to "buf" */
612                         for (q = 0; tmp[q]; q++)
613                         {
614                                 /* Notice first non-space */
615                                 if (!iswspace(tmp[q]))
616                                 {
617                                         /* Capitalize if possible */
618                                         if (islower(tmp[q]))
619                                                 tmp[q] = (char)toupper(tmp[q]);
620
621                                         break;
622                                 }
623                         }
624                 }
625
626                 /* Now append "tmp" to "buf" */
627                 for (q = 0; tmp[q]; q++)
628                 {
629                         /* Check total length */
630                         if (n == max-1) break;
631
632                         /* Save the character */
633                         buf[n++] = tmp[q];
634                 }
635         }
636
637
638         /* Terminate buffer */
639         buf[n] = '\0';
640
641         /* Return length */
642         return (n);
643 }
644
645
646 /*
647  * Do a vstrnfmt (see above) into a (growable) static buffer.
648  * This buffer is usable for very short term formatting of results.
649  */
650 char *vformat(cptr fmt, va_list vp)
651 {
652         static char *format_buf = NULL;
653         static huge format_len = 0;
654
655         /* Initial allocation */
656         if (!format_buf)
657         {
658                 format_len = 1024;
659                 C_MAKE(format_buf, format_len, char);
660         }
661
662         /* Null format yields last result */
663         if (!fmt) return (format_buf);
664
665         /* Keep going until successful */
666         while (1)
667         {
668                 uint len;
669
670                 /* Build the string */
671                 len = vstrnfmt(format_buf, format_len, fmt, vp);
672
673                 /* Success */
674                 if (len < format_len-1) break;
675
676                 /* Grow the buffer */
677                 C_KILL(format_buf, format_len, char);
678                 format_len = format_len * 2;
679                 C_MAKE(format_buf, format_len, char);
680         }
681
682         /* Return the new buffer */
683         return (format_buf);
684 }
685
686
687
688 /*
689  * Do a vstrnfmt (see above) into a buffer of a given size.
690  */
691 uint strnfmt(char *buf, uint max, cptr fmt, ...)
692 {
693         uint len;
694
695         va_list vp;
696
697         /* Begin the Varargs Stuff */
698         va_start(vp, fmt);
699
700         /* Do a virtual fprintf to stderr */
701         len = vstrnfmt(buf, max, fmt, vp);
702
703         /* End the Varargs Stuff */
704         va_end(vp);
705
706         /* Return the number of bytes written */
707         return (len);
708 }
709
710
711 /*
712  * Do a vstrnfmt (see above) into a buffer of unknown size.
713  * Since the buffer size is unknown, the user better verify the args.
714  */
715 uint strfmt(char *buf, cptr fmt, ...)
716 {
717         uint len;
718
719         va_list vp;
720
721         /* Begin the Varargs Stuff */
722         va_start(vp, fmt);
723
724         /* Build the string, assume 32K buffer */
725         len = vstrnfmt(buf, 32767, fmt, vp);
726
727         /* End the Varargs Stuff */
728         va_end(vp);
729
730         /* Return the number of bytes written */
731         return (len);
732 }
733
734
735
736
737 /*
738  * Do a vstrnfmt() into (see above) into a (growable) static buffer.
739  * This buffer is usable for very short term formatting of results.
740  * Note that the buffer is (technically) writable, but only up to
741  * the length of the string contained inside it.
742  */
743 char *format(cptr fmt, ...)
744 {
745         char *res;
746         va_list vp;
747
748         /* Begin the Varargs Stuff */
749         va_start(vp, fmt);
750
751         /* Format the args */
752         res = vformat(fmt, vp);
753
754         /* End the Varargs Stuff */
755         va_end(vp);
756
757         /* Return the result */
758         return (res);
759 }
760
761
762
763
764 /*
765  * Vararg interface to plog()
766  */
767 void plog_fmt(cptr fmt, ...)
768 {
769         char *res;
770         va_list vp;
771
772         /* Begin the Varargs Stuff */
773         va_start(vp, fmt);
774
775         /* Format the args */
776         res = vformat(fmt, vp);
777
778         /* End the Varargs Stuff */
779         va_end(vp);
780
781         /* Call plog */
782         plog(res);
783 }
784
785
786
787 /*
788  * Vararg interface to quit()
789  */
790 void quit_fmt(cptr fmt, ...)
791 {
792         char *res;
793         va_list vp;
794
795         /* Begin the Varargs Stuff */
796         va_start(vp, fmt);
797
798         /* Format */
799         res = vformat(fmt, vp);
800
801         /* End the Varargs Stuff */
802         va_end(vp);
803
804         /* Call quit() */
805         quit(res);
806 }
807
808
809
810 /*
811  * Vararg interface to core()
812  */
813 void core_fmt(cptr fmt, ...)
814 {
815         char *res;
816         va_list vp;
817
818         /* Begin the Varargs Stuff */
819         va_start(vp, fmt);
820
821         /* If requested, Do a virtual fprintf to stderr */
822         res = vformat(fmt, vp);
823
824         /* End the Varargs Stuff */
825         va_end(vp);
826
827         /* Call core() */
828         core(res);
829 }
830
831