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