OSDN Git Service

#37287 (2.2.0.85) z-term.c, z-rand.c, z-form.c 中のVCコンパイラ警告を修正。C4710は抑制。 / Fix warning...
[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                                 /* 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, "%ld", 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, "%d", 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                                         switch (aux[q-1])
515                                         {
516                                                 case 'u':
517                                                         sprintf(tmp, "%lu", arg);
518                                                         break;
519                                                 case 'o':
520                                                         sprintf(tmp, "%lo", arg);
521                                                         break;
522                                                 case 'x':
523                                                         sprintf(tmp, "%lx", arg);
524                                                         break;
525                                                 case 'X':
526                                                         sprintf(tmp, "%lX", arg);
527                                                         break;
528                                                 default:
529                                                         sprintf(tmp, "");
530                                                         break;
531                                         }
532
533                                 }
534                                 else
535                                 {
536                                         unsigned int arg;
537
538                                         /* Access next argument */
539                                         arg = va_arg(vp, unsigned int);
540
541                                         /* Format the argument */
542                                         switch (aux[q - 1])
543                                         {
544                                         case 'u':
545                                                 sprintf(tmp, "%u", arg);
546                                                 break;
547                                         case 'o':
548                                                 sprintf(tmp, "%o", arg);
549                                                 break;
550                                         case 'x':
551                                                 sprintf(tmp, "%x", arg);
552                                                 break;
553                                         case 'X':
554                                                 sprintf(tmp, "%X", arg);
555                                                 break;
556                                         default:
557                                                 sprintf(tmp, "");
558                                                 break;
559                                         }
560                                 }
561
562                                 /* Done */
563                                 break;
564                         }
565
566                         /* Floating Point -- various formats */
567                         case 'f':
568                         case 'e': case 'E':
569                         case 'g': case 'G':
570                         {
571                                 double arg;
572
573                                 /* Access next argument */
574                                 arg = va_arg(vp, double);
575
576                                 /* Format the argument */
577                                 switch (aux[q - 1])
578                                 {
579                                 case 'f':
580                                         sprintf(tmp, "%f", arg);
581                                         break;
582                                 case 'e':
583                                         sprintf(tmp, "%e", arg);
584                                         break;
585                                 case 'E':
586                                         sprintf(tmp, "%E", arg);
587                                         break;
588                                 case 'g':
589                                         sprintf(tmp, "%g", arg);
590                                         break;
591                                 case 'G':
592                                         sprintf(tmp, "%G", arg);
593                                         break;
594                                 default:
595                                         sprintf(tmp, aux, arg);
596                                         break;
597                                 }
598
599                                 /* Done */
600                                 break;
601                         }
602
603                         /* Pointer -- implementation varies */
604                         case 'p':
605                         {
606                                 vptr arg;
607
608                                 /* Access next argument */
609                                 arg = va_arg(vp, vptr);
610
611                                 /* Format the argument */
612                                 sprintf(tmp, "%p", arg);
613
614                                 /* Done */
615                                 break;
616                         }
617
618                         /* String */
619                         case 's':
620                         {
621                                 cptr arg;
622                                 char arg2[1024];
623
624                                 /* Access next argument */
625                                 arg = va_arg(vp, cptr);
626
627                                 /* Hack -- convert NULL to EMPTY */
628                                 if (!arg) arg = "";
629
630                                 /* Prevent buffer overflows */
631                                 strncpy(arg2, arg, 1024);
632                                 arg2[1023] = '\0';
633
634                                 /* Format the argument */
635                                 sprintf(tmp, "%s", arg2);
636
637                                 /* Done */
638                                 break;
639                         }
640
641                         /* User defined data */
642                         case 'V':
643                         case 'v':
644                         {
645                                 vptr arg;
646
647                                 /* Access next argument */
648                                 arg = va_arg(vp, vptr);
649
650                                 /* Format the "user data" */
651                                 (void)vstrnfmt_aux(tmp, 1000, aux[q-1] == 'V' ? "%V" : "%v", arg);
652
653                                 /* Done */
654                                 break;
655                         }
656
657
658                         /* Oops */
659                         default:
660                         {
661                                 /* Error -- illegal format char */
662                                 buf[0] = '\0';
663
664                                 /* Return "error" */
665                                 return (0);
666                         }
667                 }
668
669
670 #ifdef JP
671                 for (q = 0; tmp[q]; q++) if (iskanji(tmp[q])) { do_xtra=FALSE;break;} 
672 #endif
673                 /* Mega-Hack -- handle "capitilization" */
674                 if (do_xtra)
675                 {
676                         /* Now append "tmp" to "buf" */
677                         for (q = 0; tmp[q]; q++)
678                         {
679                                 /* Notice first non-space */
680                                 if (!iswspace(tmp[q]))
681                                 {
682                                         /* Capitalize if possible */
683                                         if (islower(tmp[q]))
684                                                 tmp[q] = (char)toupper(tmp[q]);
685
686                                         /* Done */
687                                         break;
688                                 }
689                         }
690                 }
691
692                 /* Now append "tmp" to "buf" */
693                 for (q = 0; tmp[q]; q++)
694                 {
695                         /* Check total length */
696                         if (n == max-1) break;
697
698                         /* Save the character */
699                         buf[n++] = tmp[q];
700                 }
701         }
702
703
704         /* Terminate buffer */
705         buf[n] = '\0';
706
707         /* Return length */
708         return (n);
709 }
710
711
712 /*
713  * Do a vstrnfmt (see above) into a (growable) static buffer.
714  * This buffer is usable for very short term formatting of results.
715  */
716 char *vformat(cptr fmt, va_list vp)
717 {
718         static char *format_buf = NULL;
719         static huge format_len = 0;
720
721         /* Initial allocation */
722         if (!format_buf)
723         {
724                 format_len = 1024;
725                 C_MAKE(format_buf, format_len, char);
726         }
727
728         /* Null format yields last result */
729         if (!fmt) return (format_buf);
730
731         /* Keep going until successful */
732         while (1)
733         {
734                 uint len;
735
736                 /* Build the string */
737                 len = vstrnfmt(format_buf, format_len, fmt, vp);
738
739                 /* Success */
740                 if (len < format_len-1) break;
741
742                 /* Grow the buffer */
743                 C_KILL(format_buf, format_len, char);
744                 format_len = format_len * 2;
745                 C_MAKE(format_buf, format_len, char);
746         }
747
748         /* Return the new buffer */
749         return (format_buf);
750 }
751
752
753
754 /*
755  * Do a vstrnfmt (see above) into a buffer of a given size.
756  */
757 uint strnfmt(char *buf, uint max, cptr fmt, ...)
758 {
759         uint len;
760
761         va_list vp;
762
763         /* Begin the Varargs Stuff */
764         va_start(vp, fmt);
765
766         /* Do a virtual fprintf to stderr */
767         len = vstrnfmt(buf, max, fmt, vp);
768
769         /* End the Varargs Stuff */
770         va_end(vp);
771
772         /* Return the number of bytes written */
773         return (len);
774 }
775
776
777 /*
778  * Do a vstrnfmt (see above) into a buffer of unknown size.
779  * Since the buffer size is unknown, the user better verify the args.
780  */
781 uint strfmt(char *buf, cptr fmt, ...)
782 {
783         uint len;
784
785         va_list vp;
786
787         /* Begin the Varargs Stuff */
788         va_start(vp, fmt);
789
790         /* Build the string, assume 32K buffer */
791         len = vstrnfmt(buf, 32767, fmt, vp);
792
793         /* End the Varargs Stuff */
794         va_end(vp);
795
796         /* Return the number of bytes written */
797         return (len);
798 }
799
800
801
802
803 /*
804  * Do a vstrnfmt() into (see above) into a (growable) static buffer.
805  * This buffer is usable for very short term formatting of results.
806  * Note that the buffer is (technically) writable, but only up to
807  * the length of the string contained inside it.
808  */
809 char *format(cptr fmt, ...)
810 {
811         char *res;
812         va_list vp;
813
814         /* Begin the Varargs Stuff */
815         va_start(vp, fmt);
816
817         /* Format the args */
818         res = vformat(fmt, vp);
819
820         /* End the Varargs Stuff */
821         va_end(vp);
822
823         /* Return the result */
824         return (res);
825 }
826
827
828
829
830 /*
831  * Vararg interface to plog()
832  */
833 void plog_fmt(cptr fmt, ...)
834 {
835         char *res;
836         va_list vp;
837
838         /* Begin the Varargs Stuff */
839         va_start(vp, fmt);
840
841         /* Format the args */
842         res = vformat(fmt, vp);
843
844         /* End the Varargs Stuff */
845         va_end(vp);
846
847         /* Call plog */
848         plog(res);
849 }
850
851
852
853 /*
854  * Vararg interface to quit()
855  */
856 void quit_fmt(cptr fmt, ...)
857 {
858         char *res;
859         va_list vp;
860
861         /* Begin the Varargs Stuff */
862         va_start(vp, fmt);
863
864         /* Format */
865         res = vformat(fmt, vp);
866
867         /* End the Varargs Stuff */
868         va_end(vp);
869
870         /* Call quit() */
871         quit(res);
872 }
873
874
875
876 /*
877  * Vararg interface to core()
878  */
879 void core_fmt(cptr fmt, ...)
880 {
881         char *res;
882         va_list vp;
883
884         /* Begin the Varargs Stuff */
885         va_start(vp, fmt);
886
887         /* If requested, Do a virtual fprintf to stderr */
888         res = vformat(fmt, vp);
889
890         /* End the Varargs Stuff */
891         va_end(vp);
892
893         /* Call core() */
894         core(res);
895 }
896
897