OSDN Git Service

d0d6c888e831b63b373e7356ef2abb40d614db7f
[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, aux, arg);
470
471                                 /* Done */
472                                 break;
473                         }
474
475                         /* Signed Integers -- standard format */
476                         case 'd': case 'i':
477                         {
478                                 if (do_long)
479                                 {
480                                         long arg;
481
482                                         /* Access next argument */
483                                         arg = va_arg(vp, long);
484
485                                         /* Format the argument */
486                                         sprintf(tmp, aux, arg);
487                                 }
488                                 else
489                                 {
490                                         int arg;
491
492                                         /* Access next argument */
493                                         arg = va_arg(vp, int);
494
495                                         /* Format the argument */
496                                         sprintf(tmp, aux, arg);
497                                 }
498
499                                 /* Done */
500                                 break;
501                         }
502
503                         /* Unsigned Integers -- various formats */
504                         case 'u': case 'o': case 'x': case 'X':
505                         {
506                                 if (do_long)
507                                 {
508                                         unsigned long arg;
509
510                                         /* Access next argument */
511                                         arg = va_arg(vp, unsigned long);
512
513                                         /* Format the argument */
514                                         sprintf(tmp, aux, arg);
515                                 }
516                                 else
517                                 {
518                                         unsigned int arg;
519
520                                         /* Access next argument */
521                                         arg = va_arg(vp, unsigned int);
522
523                                         /* Format the argument */
524                                         sprintf(tmp, aux, arg);
525                                 }
526
527                                 /* Done */
528                                 break;
529                         }
530
531                         /* Floating Point -- various formats */
532                         case 'f':
533                         case 'e': case 'E':
534                         case 'g': case 'G':
535                         {
536                                 double arg;
537
538                                 /* Access next argument */
539                                 arg = va_arg(vp, double);
540
541                                 /* Format the argument */
542                                 sprintf(tmp, aux, arg);
543
544                                 /* Done */
545                                 break;
546                         }
547
548                         /* Pointer -- implementation varies */
549                         case 'p':
550                         {
551                                 vptr arg;
552
553                                 /* Access next argument */
554                                 arg = va_arg(vp, vptr);
555
556                                 /* Format the argument */
557                                 sprintf(tmp, aux, arg);
558
559                                 /* Done */
560                                 break;
561                         }
562
563                         /* String */
564                         case 's':
565                         {
566                                 cptr arg;
567                                 char arg2[1024];
568
569                                 /* Access next argument */
570                                 arg = va_arg(vp, cptr);
571
572                                 /* Hack -- convert NULL to EMPTY */
573                                 if (!arg) arg = "";
574
575                                 /* Prevent buffer overflows */
576                                 strncpy(arg2, arg, 1024);
577                                 arg2[1023] = '\0';
578
579                                 /* Format the argument */
580                                 sprintf(tmp, aux, arg2);
581
582                                 /* Done */
583                                 break;
584                         }
585
586                         /* User defined data */
587                         case 'V':
588                         case 'v':
589                         {
590                                 vptr arg;
591
592                                 /* Access next argument */
593                                 arg = va_arg(vp, vptr);
594
595                                 /* Format the "user data" */
596                                 (void)vstrnfmt_aux(tmp, 1000, aux, arg);
597
598                                 /* Done */
599                                 break;
600                         }
601
602
603                         /* Oops */
604                         default:
605                         {
606                                 /* Error -- illegal format char */
607                                 buf[0] = '\0';
608
609                                 /* Return "error" */
610                                 return (0);
611                         }
612                 }
613
614
615 #ifdef JP
616                 for (q = 0; tmp[q]; q++) if (iskanji(tmp[q])) { do_xtra=FALSE;break;} 
617 #endif
618                 /* Mega-Hack -- handle "capitilization" */
619                 if (do_xtra)
620                 {
621                         /* Now append "tmp" to "buf" */
622                         for (q = 0; tmp[q]; q++)
623                         {
624                                 /* Notice first non-space */
625                                 if (!iswspace(tmp[q]))
626                                 {
627                                         /* Capitalize if possible */
628                                         if (islower(tmp[q]))
629                                                 tmp[q] = toupper(tmp[q]);
630
631                                         /* Done */
632                                         break;
633                                 }
634                         }
635                 }
636
637                 /* Now append "tmp" to "buf" */
638                 for (q = 0; tmp[q]; q++)
639                 {
640                         /* Check total length */
641                         if (n == max-1) break;
642
643                         /* Save the character */
644                         buf[n++] = tmp[q];
645                 }
646         }
647
648
649         /* Terminate buffer */
650         buf[n] = '\0';
651
652         /* Return length */
653         return (n);
654 }
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(cptr fmt, va_list vp)
662 {
663         static char *format_buf = NULL;
664         static huge format_len = 0;
665
666         /* Initial allocation */
667         if (!format_buf)
668         {
669                 format_len = 1024;
670                 C_MAKE(format_buf, format_len, char);
671         }
672
673         /* Null format yields last result */
674         if (!fmt) return (format_buf);
675
676         /* Keep going until successful */
677         while (1)
678         {
679                 uint len;
680
681                 /* Build the string */
682                 len = vstrnfmt(format_buf, format_len, fmt, vp);
683
684                 /* Success */
685                 if (len < format_len-1) break;
686
687                 /* Grow the buffer */
688                 C_KILL(format_buf, format_len, char);
689                 format_len = format_len * 2;
690                 C_MAKE(format_buf, format_len, char);
691         }
692
693         /* Return the new buffer */
694         return (format_buf);
695 }
696
697
698
699 /*
700  * Do a vstrnfmt (see above) into a buffer of a given size.
701  */
702 uint strnfmt(char *buf, uint max, cptr fmt, ...)
703 {
704         uint len;
705
706         va_list vp;
707
708         /* Begin the Varargs Stuff */
709         va_start(vp, fmt);
710
711         /* Do a virtual fprintf to stderr */
712         len = vstrnfmt(buf, max, fmt, vp);
713
714         /* End the Varargs Stuff */
715         va_end(vp);
716
717         /* Return the number of bytes written */
718         return (len);
719 }
720
721
722 /*
723  * Do a vstrnfmt (see above) into a buffer of unknown size.
724  * Since the buffer size is unknown, the user better verify the args.
725  */
726 uint strfmt(char *buf, cptr fmt, ...)
727 {
728         uint len;
729
730         va_list vp;
731
732         /* Begin the Varargs Stuff */
733         va_start(vp, fmt);
734
735         /* Build the string, assume 32K buffer */
736         len = vstrnfmt(buf, 32767, fmt, vp);
737
738         /* End the Varargs Stuff */
739         va_end(vp);
740
741         /* Return the number of bytes written */
742         return (len);
743 }
744
745
746
747
748 /*
749  * Do a vstrnfmt() into (see above) into a (growable) static buffer.
750  * This buffer is usable for very short term formatting of results.
751  * Note that the buffer is (technically) writable, but only up to
752  * the length of the string contained inside it.
753  */
754 char *format(cptr fmt, ...)
755 {
756         char *res;
757         va_list vp;
758
759         /* Begin the Varargs Stuff */
760         va_start(vp, fmt);
761
762         /* Format the args */
763         res = vformat(fmt, vp);
764
765         /* End the Varargs Stuff */
766         va_end(vp);
767
768         /* Return the result */
769         return (res);
770 }
771
772
773
774
775 /*
776  * Vararg interface to plog()
777  */
778 void plog_fmt(cptr fmt, ...)
779 {
780         char *res;
781         va_list vp;
782
783         /* Begin the Varargs Stuff */
784         va_start(vp, fmt);
785
786         /* Format the args */
787         res = vformat(fmt, vp);
788
789         /* End the Varargs Stuff */
790         va_end(vp);
791
792         /* Call plog */
793         plog(res);
794 }
795
796
797
798 /*
799  * Vararg interface to quit()
800  */
801 void quit_fmt(cptr fmt, ...)
802 {
803         char *res;
804         va_list vp;
805
806         /* Begin the Varargs Stuff */
807         va_start(vp, fmt);
808
809         /* Format */
810         res = vformat(fmt, vp);
811
812         /* End the Varargs Stuff */
813         va_end(vp);
814
815         /* Call quit() */
816         quit(res);
817 }
818
819
820
821 /*
822  * Vararg interface to core()
823  */
824 void core_fmt(cptr fmt, ...)
825 {
826         char *res;
827         va_list vp;
828
829         /* Begin the Varargs Stuff */
830         va_start(vp, fmt);
831
832         /* If requested, Do a virtual fprintf to stderr */
833         res = vformat(fmt, vp);
834
835         /* End the Varargs Stuff */
836         va_end(vp);
837
838         /* Call core() */
839         core(res);
840 }
841
842