OSDN Git Service

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