1 /**************************************************************
2 * Original:
3 * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
4 * A bombproof version of doprnt (dopr) included.
5 * Sigh. This sort of thing is always nasty do deal with. Note that
6 * the version here does not include floating point...
7 *
8 * snprintf() is used instead of sprintf() as it does limit checks
9 * for string length. This covers a nasty loophole.
10 *
11 * The other functions are there to prevent NULL pointers from
12 * causing nast effects.
13 *
14 * More Recently:
15 * Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
16 * This was ugly. It is still ugly. I opted out of floating point
17 * numbers, but the formatter understands just about everything
18 * from the normal C string format, at least as far as I can tell from
19 * the Solaris 2.5 printf(3S) man page.
20 *
21 * Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
22 * Ok, added some minimal floating point support, which means this
23 * probably requires libm on most operating systems. Don't yet
24 * support the exponent (e,E) and sigfig (g,G). Also, fmtint()
25 * was pretty badly broken, it just wasn't being exercised in ways
26 * which showed it, so that's been fixed. Also, formated the code
27 * to mutt conventions, and removed dead code left over from the
28 * original. Also, there is now a builtin-test, just compile with:
29 * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
30 * and run snprintf for results.
31 *
32 * Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
33 * The PGP code was using unsigned hexadecimal formats.
34 * Unfortunately, unsigned formats simply didn't work.
35 *
36 * Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
37 * The original code assumed that both snprintf() and vsnprintf() were
38 * missing. Some systems only have snprintf() but not vsnprintf(), so
39 * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
40 *
41 **************************************************************/
42
43 #include <config.h>
44
45 #if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
46
47 #include <string.h>
48 # include <ctype.h>
49 #include <sys/types.h>
50
51 /* varargs declarations: */
52
53 #if defined(HAVE_STDARG_H)
54 # include <stdarg.h>
55 # define HAVE_STDARGS /* let's hope that works everywhere (mj) */
56 # define VA_LOCAL_DECL va_list ap
57 # define VA_START(f) va_start(ap, f)
58 # define VA_SHIFT(v,t) ; /* no-op for ANSI */
59 # define VA_END va_end(ap)
60 #else
61 # if defined(HAVE_VARARGS_H)
62 # include <varargs.h>
63 # undef HAVE_STDARGS
64 # define VA_LOCAL_DECL va_list ap
65 # define VA_START(f) va_start(ap) /* f is ignored! */
66 # define VA_SHIFT(v,t) v = va_arg(ap,t)
67 # define VA_END va_end(ap)
68 # else
69 /*XX ** NO VARARGS ** XX*/
70 # endif
71 #endif
72
73 /*int snprintf (char *str, size_t count, const char *fmt, ...);*/
74 /*int vsnprintf (char *str, size_t count, const char *fmt, va_list arg);*/
75
76 static void dopr (char *buffer, size_t maxlen, const char *format,
77 va_list args);
78 static void fmtstr (char *buffer, size_t *currlen, size_t maxlen,
79 char *value, int flags, int min, int max);
80 static void fmtint (char *buffer, size_t *currlen, size_t maxlen,
81 long value, int base, int min, int max, int flags);
82 static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
83 long double fvalue, int min, int max, int flags);
84 static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c );
85
86 /*
87 * dopr(): poor man's version of doprintf
88 */
89
90 /* format read states */
91 #define DP_S_DEFAULT 0
92 #define DP_S_FLAGS 1
93 #define DP_S_MIN 2
94 #define DP_S_DOT 3
95 #define DP_S_MAX 4
96 #define DP_S_MOD 5
97 #define DP_S_CONV 6
98 #define DP_S_DONE 7
99
100 /* format flags - Bits */
101 #define DP_F_MINUS (1 << 0)
102 #define DP_F_PLUS (1 << 1)
103 #define DP_F_SPACE (1 << 2)
104 #define DP_F_NUM (1 << 3)
105 #define DP_F_ZERO (1 << 4)
106 #define DP_F_UP (1 << 5)
107 #define DP_F_UNSIGNED (1 << 6)
108
109 /* Conversion Flags */
110 #define DP_C_SHORT 1
111 #define DP_C_LONG 2
112 #define DP_C_LDOUBLE 3
113
114 #define char_to_int(p) (p - '0')
115
116 #ifndef MAX
117 #define MAX(p,q) ((p >= q) ? p : q)
118 #endif /* MAX */
119
dopr(char * buffer,size_t maxlen,const char * format,va_list args)120 static void dopr (char *buffer, size_t maxlen, const char *format, va_list args)
121 {
122 char ch;
123 long value;
124 long double fvalue;
125 char *strvalue;
126 int min;
127 int max;
128 int state;
129 int flags;
130 int cflags;
131 size_t currlen;
132
133 state = DP_S_DEFAULT;
134 currlen = flags = cflags = min = 0;
135 max = -1;
136 ch = *format++;
137
138 while (state != DP_S_DONE)
139 {
140 if ((ch == '\0') || (currlen >= maxlen))
141 state = DP_S_DONE;
142
143 switch(state)
144 {
145 case DP_S_DEFAULT:
146 if (ch == '%')
147 state = DP_S_FLAGS;
148 else
149 dopr_outch (buffer, &currlen, maxlen, ch);
150 ch = *format++;
151 break;
152 case DP_S_FLAGS:
153 switch (ch)
154 {
155 case '-':
156 flags |= DP_F_MINUS;
157 ch = *format++;
158 break;
159 case '+':
160 flags |= DP_F_PLUS;
161 ch = *format++;
162 break;
163 case ' ':
164 flags |= DP_F_SPACE;
165 ch = *format++;
166 break;
167 case '#':
168 flags |= DP_F_NUM;
169 ch = *format++;
170 break;
171 case '0':
172 flags |= DP_F_ZERO;
173 ch = *format++;
174 break;
175 default:
176 state = DP_S_MIN;
177 break;
178 }
179 break;
180 case DP_S_MIN:
181 if (isdigit((unsigned char)ch))
182 {
183 min = 10*min + char_to_int (ch);
184 ch = *format++;
185 }
186 else if (ch == '*')
187 {
188 min = va_arg (args, int);
189 ch = *format++;
190 state = DP_S_DOT;
191 }
192 else
193 state = DP_S_DOT;
194 break;
195 case DP_S_DOT:
196 if (ch == '.')
197 {
198 state = DP_S_MAX;
199 ch = *format++;
200 }
201 else
202 state = DP_S_MOD;
203 break;
204 case DP_S_MAX:
205 if (isdigit((unsigned char)ch))
206 {
207 if (max < 0)
208 max = 0;
209 max = 10*max + char_to_int (ch);
210 ch = *format++;
211 }
212 else if (ch == '*')
213 {
214 max = va_arg (args, int);
215 ch = *format++;
216 state = DP_S_MOD;
217 }
218 else
219 state = DP_S_MOD;
220 break;
221 case DP_S_MOD:
222 /* Currently, we don't support Long Long, bummer */
223 switch (ch)
224 {
225 case 'h':
226 cflags = DP_C_SHORT;
227 ch = *format++;
228 break;
229 case 'l':
230 cflags = DP_C_LONG;
231 ch = *format++;
232 break;
233 case 'L':
234 cflags = DP_C_LDOUBLE;
235 ch = *format++;
236 break;
237 default:
238 break;
239 }
240 state = DP_S_CONV;
241 break;
242 case DP_S_CONV:
243 switch (ch)
244 {
245 case 'd':
246 case 'i':
247 if (cflags == DP_C_SHORT)
248 value = (short int) va_arg (args, int);
249 else if (cflags == DP_C_LONG)
250 value = va_arg (args, long int);
251 else
252 value = va_arg (args, int);
253 fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
254 break;
255 case 'o':
256 flags |= DP_F_UNSIGNED;
257 if (cflags == DP_C_SHORT)
258 value = (unsigned short int) va_arg (args, int);
259 else if (cflags == DP_C_LONG)
260 value = va_arg (args, unsigned long int);
261 else
262 value = va_arg (args, unsigned int);
263 fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
264 break;
265 case 'u':
266 flags |= DP_F_UNSIGNED;
267 if (cflags == DP_C_SHORT)
268 value = (unsigned short int) va_arg (args, int);
269 else if (cflags == DP_C_LONG)
270 value = va_arg (args, unsigned long int);
271 else
272 value = va_arg (args, unsigned int);
273 fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
274 break;
275 case 'X':
276 flags |= DP_F_UP;
277
278 GCC_FALLTHROUGH
279
280 case 'x':
281 flags |= DP_F_UNSIGNED;
282 if (cflags == DP_C_SHORT)
283 value = (unsigned short int) va_arg (args, int);
284 else if (cflags == DP_C_LONG)
285 value = va_arg (args, unsigned long int);
286 else
287 value = va_arg (args, unsigned int);
288 fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
289 break;
290 case 'f':
291 if (cflags == DP_C_LDOUBLE)
292 fvalue = va_arg (args, long double);
293 else
294 fvalue = va_arg (args, double);
295 /* um, floating point? */
296 fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
297 break;
298 case 'E':
299 flags |= DP_F_UP;
300
301 GCC_FALLTHROUGH
302
303 case 'e':
304 if (cflags == DP_C_LDOUBLE)
305 fvalue = va_arg (args, long double);
306 else
307 fvalue = va_arg (args, double);
308 break;
309 case 'G':
310 flags |= DP_F_UP;
311
312 GCC_FALLTHROUGH
313
314 case 'g':
315 if (cflags == DP_C_LDOUBLE)
316 fvalue = va_arg (args, long double);
317 else
318 fvalue = va_arg (args, double);
319 break;
320 case 'c':
321 dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
322 break;
323 case 's':
324 strvalue = va_arg (args, char *);
325 if (max < 0)
326 max = maxlen; /* ie, no max */
327 fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
328 break;
329 case 'p':
330 strvalue = va_arg (args, void *);
331 fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
332 break;
333 case 'n':
334 if (cflags == DP_C_SHORT)
335 {
336 short int *num;
337 num = va_arg (args, short int *);
338 *num = currlen;
339 }
340 else if (cflags == DP_C_LONG)
341 {
342 long int *num;
343 num = va_arg (args, long int *);
344 *num = currlen;
345 }
346 else
347 {
348 int *num;
349 num = va_arg (args, int *);
350 *num = currlen;
351 }
352 break;
353 case '%':
354 dopr_outch (buffer, &currlen, maxlen, ch);
355 break;
356 case 'w':
357 /* not supported yet, treat as next char */
358 ch = *format++;
359 break;
360 default:
361 /* Unknown, skip */
362 break;
363 }
364 ch = *format++;
365 state = DP_S_DEFAULT;
366 flags = cflags = min = 0;
367 max = -1;
368 break;
369 case DP_S_DONE:
370 break;
371 default:
372 /* hmm? */
373 break; /* some picky compilers need this */
374 }
375 }
376 if (currlen < maxlen - 1)
377 buffer[currlen] = '\0';
378 else
379 buffer[maxlen - 1] = '\0';
380 }
381
fmtstr(char * buffer,size_t * currlen,size_t maxlen,char * value,int flags,int min,int max)382 static void fmtstr (char *buffer, size_t *currlen, size_t maxlen,
383 char *value, int flags, int min, int max)
384 {
385 int padlen, strln; /* amount to pad */
386 int cnt = 0;
387
388 if (value == 0)
389 {
390 value = "<NULL>";
391 }
392
393 for (strln = 0; value[strln]; ++strln); /* strlen */
394 padlen = min - strln;
395 if (padlen < 0)
396 padlen = 0;
397 if (flags & DP_F_MINUS)
398 padlen = -padlen; /* Left Justify */
399
400 while ((padlen > 0) && (cnt < max))
401 {
402 dopr_outch (buffer, currlen, maxlen, ' ');
403 --padlen;
404 ++cnt;
405 }
406 while (*value && (cnt < max))
407 {
408 dopr_outch (buffer, currlen, maxlen, *value++);
409 ++cnt;
410 }
411 while ((padlen < 0) && (cnt < max))
412 {
413 dopr_outch (buffer, currlen, maxlen, ' ');
414 ++padlen;
415 ++cnt;
416 }
417 }
418
419 /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
420
fmtint(char * buffer,size_t * currlen,size_t maxlen,long value,int base,int min,int max,int flags)421 static void fmtint (char *buffer, size_t *currlen, size_t maxlen,
422 long value, int base, int min, int max, int flags)
423 {
424 int signvalue = 0;
425 unsigned long uvalue;
426 char convert[20];
427 int place = 0;
428 int spadlen = 0; /* amount to space pad */
429 int zpadlen = 0; /* amount to zero pad */
430 int caps = 0;
431
432 if (max < 0)
433 max = 0;
434
435 uvalue = value;
436
437 if(!(flags & DP_F_UNSIGNED))
438 {
439 if( value < 0 ) {
440 signvalue = '-';
441 uvalue = -value;
442 }
443 else
444 if (flags & DP_F_PLUS) /* Do a sign (+/i) */
445 signvalue = '+';
446 else
447 if (flags & DP_F_SPACE)
448 signvalue = ' ';
449 }
450
451 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
452
453 do {
454 convert[place++] =
455 (caps? "0123456789ABCDEF":"0123456789abcdef")
456 [uvalue % (unsigned)base ];
457 uvalue = (uvalue / (unsigned)base );
458 } while(uvalue && (place < 20));
459 if (place == 20) place--;
460 convert[place] = 0;
461
462 zpadlen = max - place;
463 spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
464 if (zpadlen < 0) zpadlen = 0;
465 if (spadlen < 0) spadlen = 0;
466 if (flags & DP_F_ZERO)
467 {
468 zpadlen = MAX(zpadlen, spadlen);
469 spadlen = 0;
470 }
471 if (flags & DP_F_MINUS)
472 spadlen = -spadlen; /* Left Justifty */
473
474 #ifdef DEBUG_SNPRINTF
475 dprint (1, (debugfile, "zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
476 zpadlen, spadlen, min, max, place));
477 #endif
478
479 /* Spaces */
480 while (spadlen > 0)
481 {
482 dopr_outch (buffer, currlen, maxlen, ' ');
483 --spadlen;
484 }
485
486 /* Sign */
487 if (signvalue)
488 dopr_outch (buffer, currlen, maxlen, signvalue);
489
490 /* Zeros */
491 if (zpadlen > 0)
492 {
493 while (zpadlen > 0)
494 {
495 dopr_outch (buffer, currlen, maxlen, '0');
496 --zpadlen;
497 }
498 }
499
500 /* Digits */
501 while (place > 0)
502 dopr_outch (buffer, currlen, maxlen, convert[--place]);
503
504 /* Left Justified spaces */
505 while (spadlen < 0) {
506 dopr_outch (buffer, currlen, maxlen, ' ');
507 ++spadlen;
508 }
509 }
510
abs_val(long double value)511 static long double abs_val (long double value)
512 {
513 long double result = value;
514
515 if (value < 0)
516 result = -value;
517
518 return result;
519 }
520
my_pow10(int exp)521 static long double my_pow10 (int exp)
522 {
523 long double result = 1;
524
525 while (exp)
526 {
527 result *= 10;
528 exp--;
529 }
530
531 return result;
532 }
533
my_round(long double value)534 static long my_round (long double value)
535 {
536 long intpart;
537
538 intpart = value;
539 value = value - intpart;
540 if (value >= 0.5)
541 intpart++;
542
543 return intpart;
544 }
545
fmtfp(char * buffer,size_t * currlen,size_t maxlen,long double fvalue,int min,int max,int flags)546 static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
547 long double fvalue, int min, int max, int flags)
548 {
549 int signvalue = 0;
550 long double ufvalue;
551 char iconvert[20];
552 char fconvert[20];
553 int iplace = 0;
554 int fplace = 0;
555 int padlen = 0; /* amount to pad */
556 int zpadlen = 0;
557 int caps = 0;
558 long intpart;
559 long fracpart;
560
561 /*
562 * AIX manpage says the default is 0, but Solaris says the default
563 * is 6, and sprintf on AIX defaults to 6
564 */
565 if (max < 0)
566 max = 6;
567
568 ufvalue = abs_val (fvalue);
569
570 if (fvalue < 0)
571 signvalue = '-';
572 else
573 if (flags & DP_F_PLUS) /* Do a sign (+/i) */
574 signvalue = '+';
575 else
576 if (flags & DP_F_SPACE)
577 signvalue = ' ';
578
579 #if 0
580 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
581 #endif
582
583 intpart = ufvalue;
584
585 /*
586 * Sorry, we only support 9 digits past the decimal because of our
587 * conversion method
588 */
589 if (max > 9)
590 max = 9;
591
592 /* We "cheat" by converting the fractional part to integer by
593 * multiplying by a factor of 10
594 */
595 fracpart = my_round ((my_pow10 (max)) * (ufvalue - intpart));
596
597 if (fracpart >= my_pow10 (max))
598 {
599 intpart++;
600 fracpart -= my_pow10 (max);
601 }
602
603 #ifdef DEBUG_SNPRINTF
604 dprint (1, (debugfile, "fmtfp: %f =? %d.%d\n", fvalue, intpart, fracpart));
605 #endif
606
607 /* Convert integer part */
608 do {
609 iconvert[iplace++] =
610 (caps? "0123456789ABCDEF":"0123456789abcdef")[intpart % 10];
611 intpart = (intpart / 10);
612 } while(intpart && (iplace < 20));
613 if (iplace == 20) iplace--;
614 iconvert[iplace] = 0;
615
616 /* Convert fractional part */
617 do {
618 fconvert[fplace++] =
619 (caps? "0123456789ABCDEF":"0123456789abcdef")[fracpart % 10];
620 fracpart = (fracpart / 10);
621 } while(fracpart && (fplace < 20));
622 if (fplace == 20) fplace--;
623 fconvert[fplace] = 0;
624
625 /* -1 for decimal point, another -1 if we are printing a sign */
626 padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
627 zpadlen = max - fplace;
628 if (zpadlen < 0)
629 zpadlen = 0;
630 if (padlen < 0)
631 padlen = 0;
632 if (flags & DP_F_MINUS)
633 padlen = -padlen; /* Left Justifty */
634
635 if ((flags & DP_F_ZERO) && (padlen > 0))
636 {
637 if (signvalue)
638 {
639 dopr_outch (buffer, currlen, maxlen, signvalue);
640 --padlen;
641 signvalue = 0;
642 }
643 while (padlen > 0)
644 {
645 dopr_outch (buffer, currlen, maxlen, '0');
646 --padlen;
647 }
648 }
649 while (padlen > 0)
650 {
651 dopr_outch (buffer, currlen, maxlen, ' ');
652 --padlen;
653 }
654 if (signvalue)
655 dopr_outch (buffer, currlen, maxlen, signvalue);
656
657 while (iplace > 0)
658 dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
659
660 /*
661 * Decimal point. This should probably use locale to find the correct
662 * char to print out.
663 */
664 dopr_outch (buffer, currlen, maxlen, '.');
665
666 while (fplace > 0)
667 dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
668
669 while (zpadlen > 0)
670 {
671 dopr_outch (buffer, currlen, maxlen, '0');
672 --zpadlen;
673 }
674
675 while (padlen < 0)
676 {
677 dopr_outch (buffer, currlen, maxlen, ' ');
678 ++padlen;
679 }
680 }
681
dopr_outch(char * buffer,size_t * currlen,size_t maxlen,char c)682 static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c)
683 {
684 if (*currlen < maxlen)
685 buffer[(*currlen)++] = c;
686 }
687 #endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */
688
689 #ifndef HAVE_VSNPRINTF
vsnprintf(char * str,size_t count,const char * fmt,va_list args)690 int vsnprintf (char *str, size_t count, const char *fmt, va_list args)
691 {
692 str[0] = 0;
693 dopr(str, count, fmt, args);
694 return(strlen(str));
695 }
696 #endif /* !HAVE_VSNPRINTF */
697
698 #ifndef HAVE_SNPRINTF
699 /* VARARGS3 */
700 #ifdef HAVE_STDARGS
snprintf(char * str,size_t count,const char * fmt,...)701 int snprintf (char *str,size_t count,const char *fmt,...)
702 #else
703 int snprintf (va_alist) va_dcl
704 #endif
705 {
706 #ifndef HAVE_STDARGS
707 char *str;
708 size_t count;
709 char *fmt;
710 #endif
711 VA_LOCAL_DECL;
712
713 VA_START (fmt);
714 VA_SHIFT (str, char *);
715 VA_SHIFT (count, size_t );
716 VA_SHIFT (fmt, char *);
717 (void) vsnprintf(str, count, fmt, ap);
718 VA_END;
719 return(strlen(str));
720 }
721
722 #ifdef TEST_SNPRINTF
723 #ifndef LONG_STRING
724 #define LONG_STRING 1024
725 #endif
main(void)726 int main (void)
727 {
728 char buf1[LONG_STRING];
729 char buf2[LONG_STRING];
730 char *fp_fmt[] = {
731 "%-1.5f",
732 "%1.5f",
733 "%123.9f",
734 "%10.5f",
735 "% 10.5f",
736 "%+22.9f",
737 "%+4.9f",
738 "%01.3f",
739 "%4f",
740 "%3.1f",
741 "%3.2f",
742 NULL
743 };
744 double fp_nums[] = { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
745 0.9996, 1.996, 4.136, 0};
746 char *int_fmt[] = {
747 "%-1.5d",
748 "%1.5d",
749 "%123.9d",
750 "%5.5d",
751 "%10.5d",
752 "% 10.5d",
753 "%+22.33d",
754 "%01.3d",
755 "%4d",
756 NULL
757 };
758 long int_nums[] = { -1, 134, 91340, 341, 0203, 0};
759 int x, y;
760 int fail = 0;
761 int num = 0;
762
763 printf ("Testing snprintf format codes against system sprintf...\n");
764
765 for (x = 0; fp_fmt[x] != NULL ; x++)
766 for (y = 0; fp_nums[y] != 0 ; y++)
767 {
768 snprintf (buf1, sizeof (buf1), fp_fmt[x], fp_nums[y]);
769 sprintf (buf2, fp_fmt[x], fp_nums[y]);
770 if (strcmp (buf1, buf2))
771 {
772 printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
773 fp_fmt[x], buf1, buf2);
774 fail++;
775 }
776 num++;
777 }
778
779 for (x = 0; int_fmt[x] != NULL ; x++)
780 for (y = 0; int_nums[y] != 0 ; y++)
781 {
782 snprintf (buf1, sizeof (buf1), int_fmt[x], int_nums[y]);
783 sprintf (buf2, int_fmt[x], int_nums[y]);
784 if (strcmp (buf1, buf2))
785 {
786 printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
787 int_fmt[x], buf1, buf2);
788 fail++;
789 }
790 num++;
791 }
792 printf ("%d tests failed out of %d.\n", fail, num);
793 }
794 #endif /* SNPRINTF_TEST */
795
796 #endif /* !HAVE_SNPRINTF */
797