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