Annotation of embedaddon/rsync/lib/snprintf.c, revision 1.1.1.1
1.1 misho 1: /*
2: * NOTE: If you change this file, please merge it into rsync, samba, etc.
3: */
4:
5: /*
6: * Copyright Patrick Powell 1995
7: * This code is based on code written by Patrick Powell (papowell@astart.com)
8: * It may be used for any purpose as long as this notice remains intact
9: * on all source code distributions
10: */
11:
12: /**************************************************************
13: * Original:
14: * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
15: * A bombproof version of doprnt (dopr) included.
16: * Sigh. This sort of thing is always nasty do deal with. Note that
17: * the version here does not include floating point...
18: *
19: * snprintf() is used instead of sprintf() as it does limit checks
20: * for string length. This covers a nasty loophole.
21: *
22: * The other functions are there to prevent NULL pointers from
23: * causing nast effects.
24: *
25: * More Recently:
26: * Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
27: * This was ugly. It is still ugly. I opted out of floating point
28: * numbers, but the formatter understands just about everything
29: * from the normal C string format, at least as far as I can tell from
30: * the Solaris 2.5 printf(3S) man page.
31: *
32: * Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
33: * Ok, added some minimal floating point support, which means this
34: * probably requires libm on most operating systems. Don't yet
35: * support the exponent (e,E) and sigfig (g,G). Also, fmtint()
36: * was pretty badly broken, it just wasn't being exercised in ways
37: * which showed it, so that's been fixed. Also, formated the code
38: * to mutt conventions, and removed dead code left over from the
39: * original. Also, there is now a builtin-test, just compile with:
40: * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
41: * and run snprintf for results.
42: *
43: * Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
44: * The PGP code was using unsigned hexadecimal formats.
45: * Unfortunately, unsigned formats simply didn't work.
46: *
47: * Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
48: * The original code assumed that both snprintf() and vsnprintf() were
49: * missing. Some systems only have snprintf() but not vsnprintf(), so
50: * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
51: *
52: * Andrew Tridgell (tridge@samba.org) Oct 1998
53: * fixed handling of %.0f
54: * added test for HAVE_LONG_DOUBLE
55: *
56: * tridge@samba.org, idra@samba.org, April 2001
57: * got rid of fcvt code (twas buggy and made testing harder)
58: * added C99 semantics
59: *
60: * date: 2002/12/19 19:56:31; author: herb; state: Exp; lines: +2 -0
61: * actually print args for %g and %e
62: *
63: * date: 2002/06/03 13:37:52; author: jmcd; state: Exp; lines: +8 -0
64: * Since includes.h isn't included here, VA_COPY has to be defined here. I don't
65: * see any include file that is guaranteed to be here, so I'm defining it
66: * locally. Fixes AIX and Solaris builds.
67: *
68: * date: 2002/06/03 03:07:24; author: tridge; state: Exp; lines: +5 -13
69: * put the ifdef for HAVE_VA_COPY in one place rather than in lots of
70: * functions
71: *
72: * date: 2002/05/17 14:51:22; author: jmcd; state: Exp; lines: +21 -4
73: * Fix usage of va_list passed as an arg. Use __va_copy before using it
74: * when it exists.
75: *
76: * date: 2002/04/16 22:38:04; author: idra; state: Exp; lines: +20 -14
77: * Fix incorrect zpadlen handling in fmtfp.
78: * Thanks to Ollie Oldham <ollie.oldham@metro-optix.com> for spotting it.
79: * few mods to make it easier to compile the tests.
80: * addedd the "Ollie" test to the floating point ones.
81: *
82: * Martin Pool (mbp@samba.org) April 2003
83: * Remove NO_CONFIG_H so that the test case can be built within a source
84: * tree with less trouble.
85: * Remove unnecessary SAFE_FREE() definition.
86: *
87: * Martin Pool (mbp@samba.org) May 2003
88: * Put in a prototype for dummy_snprintf() to quiet compiler warnings.
89: *
90: * Move #endif to make sure VA_COPY, LDOUBLE, etc are defined even
91: * if the C library has some snprintf functions already.
92: **************************************************************/
93:
94: #ifndef NO_CONFIG_H
95: #include "config.h"
96: #else
97: #define NULL 0
98: #endif
99:
100: #ifdef TEST_SNPRINTF /* need math library headers for testing */
101:
102: /* In test mode, we pretend that this system doesn't have any snprintf
103: * functions, regardless of what config.h says. */
104: # undef HAVE_SNPRINTF
105: # undef HAVE_VSNPRINTF
106: # undef HAVE_C99_VSNPRINTF
107: # undef HAVE_ASPRINTF
108: # undef HAVE_VASPRINTF
109: # include <math.h>
110: #endif /* TEST_SNPRINTF */
111:
112: #ifdef HAVE_STRING_H
113: #include <string.h>
114: #endif
115:
116: #ifdef HAVE_STRINGS_H
117: #include <strings.h>
118: #endif
119: #ifdef HAVE_CTYPE_H
120: #include <ctype.h>
121: #endif
122: #include <sys/types.h>
123: #include <stdarg.h>
124: #ifdef HAVE_STDLIB_H
125: #include <stdlib.h>
126: #endif
127:
128: #if defined(HAVE_SNPRINTF) && defined(HAVE_VSNPRINTF) && defined(HAVE_C99_VSNPRINTF)
129: /* only include stdio.h if we are not re-defining snprintf or vsnprintf */
130: #include <stdio.h>
131: /* make the compiler happy with an empty file */
132: void dummy_snprintf(void);
133: void dummy_snprintf(void) {}
134: #endif /* HAVE_SNPRINTF, etc */
135:
136: #ifdef HAVE_LONG_DOUBLE
137: #define LDOUBLE long double
138: #else
139: #define LDOUBLE double
140: #endif
141:
142: #if SIZEOF_LONG_LONG
143: #define LLONG long long
144: #else
145: #define LLONG long
146: #endif
147:
148: #ifndef VA_COPY
149: #if defined HAVE_VA_COPY || defined va_copy
150: #define VA_COPY(dest, src) va_copy(dest, src)
151: #else
152: #ifdef HAVE___VA_COPY
153: #define VA_COPY(dest, src) __va_copy(dest, src)
154: #else
155: #define VA_COPY(dest, src) (dest) = (src)
156: #endif
157: #endif
158:
159: /*
160: * dopr(): poor man's version of doprintf
161: */
162:
163: /* format read states */
164: #define DP_S_DEFAULT 0
165: #define DP_S_FLAGS 1
166: #define DP_S_MIN 2
167: #define DP_S_DOT 3
168: #define DP_S_MAX 4
169: #define DP_S_MOD 5
170: #define DP_S_CONV 6
171: #define DP_S_DONE 7
172:
173: /* format flags - Bits */
174: #define DP_F_MINUS (1 << 0)
175: #define DP_F_PLUS (1 << 1)
176: #define DP_F_SPACE (1 << 2)
177: #define DP_F_NUM (1 << 3)
178: #define DP_F_ZERO (1 << 4)
179: #define DP_F_UP (1 << 5)
180: #define DP_F_UNSIGNED (1 << 6)
181:
182: /* Conversion Flags */
183: #define DP_C_SHORT 1
184: #define DP_C_LONG 2
185: #define DP_C_LDOUBLE 3
186: #define DP_C_LLONG 4
187:
188: #define char_to_int(p) ((p)- '0')
189: #ifndef MAX
190: #define MAX(p,q) (((p) >= (q)) ? (p) : (q))
191: #endif
192:
193: /* yes this really must be a ||. Don't muck with this (tridge) */
194: #if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
195:
196: static size_t dopr(char *buffer, size_t maxlen, const char *format,
197: va_list args_in);
198: static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
199: char *value, int flags, int min, int max);
200: static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
201: long value, int base, int min, int max, int flags);
202: static void fmtfp(char *buffer, size_t *currlen, size_t maxlen,
203: LDOUBLE fvalue, int min, int max, int flags);
204: static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
205:
206: static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args_in)
207: {
208: char ch;
209: LLONG value;
210: LDOUBLE fvalue;
211: char *strvalue;
212: int min;
213: int max;
214: int state;
215: int flags;
216: int cflags;
217: size_t currlen;
218: va_list args;
219:
220: VA_COPY(args, args_in);
221:
222: state = DP_S_DEFAULT;
223: currlen = flags = cflags = min = 0;
224: max = -1;
225: ch = *format++;
226:
227: while (state != DP_S_DONE) {
228: if (ch == '\0')
229: state = DP_S_DONE;
230:
231: switch(state) {
232: case DP_S_DEFAULT:
233: if (ch == '%')
234: state = DP_S_FLAGS;
235: else
236: dopr_outch (buffer, &currlen, maxlen, ch);
237: ch = *format++;
238: break;
239: case DP_S_FLAGS:
240: switch (ch) {
241: case '-':
242: flags |= DP_F_MINUS;
243: ch = *format++;
244: break;
245: case '+':
246: flags |= DP_F_PLUS;
247: ch = *format++;
248: break;
249: case ' ':
250: flags |= DP_F_SPACE;
251: ch = *format++;
252: break;
253: case '#':
254: flags |= DP_F_NUM;
255: ch = *format++;
256: break;
257: case '0':
258: flags |= DP_F_ZERO;
259: ch = *format++;
260: break;
261: default:
262: state = DP_S_MIN;
263: break;
264: }
265: break;
266: case DP_S_MIN:
267: if (isdigit((unsigned char)ch)) {
268: min = 10*min + char_to_int (ch);
269: ch = *format++;
270: } else if (ch == '*') {
271: min = va_arg (args, int);
272: ch = *format++;
273: state = DP_S_DOT;
274: } else {
275: state = DP_S_DOT;
276: }
277: break;
278: case DP_S_DOT:
279: if (ch == '.') {
280: state = DP_S_MAX;
281: ch = *format++;
282: } else {
283: state = DP_S_MOD;
284: }
285: break;
286: case DP_S_MAX:
287: if (isdigit((unsigned char)ch)) {
288: if (max < 0)
289: max = 0;
290: max = 10*max + char_to_int (ch);
291: ch = *format++;
292: } else if (ch == '*') {
293: max = va_arg (args, int);
294: ch = *format++;
295: state = DP_S_MOD;
296: } else {
297: state = DP_S_MOD;
298: }
299: break;
300: case DP_S_MOD:
301: switch (ch) {
302: case 'h':
303: cflags = DP_C_SHORT;
304: ch = *format++;
305: break;
306: case 'l':
307: cflags = DP_C_LONG;
308: ch = *format++;
309: if (ch == 'l') { /* It's a long long */
310: cflags = DP_C_LLONG;
311: ch = *format++;
312: }
313: break;
314: case 'L':
315: cflags = DP_C_LDOUBLE;
316: ch = *format++;
317: break;
318: default:
319: break;
320: }
321: state = DP_S_CONV;
322: break;
323: case DP_S_CONV:
324: switch (ch) {
325: case 'd':
326: case 'i':
327: if (cflags == DP_C_SHORT)
328: value = va_arg (args, int);
329: else if (cflags == DP_C_LONG)
330: value = va_arg (args, long int);
331: else if (cflags == DP_C_LLONG)
332: value = va_arg (args, LLONG);
333: else
334: value = va_arg (args, int);
335: fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
336: break;
337: case 'o':
338: flags |= DP_F_UNSIGNED;
339: if (cflags == DP_C_SHORT)
340: value = va_arg (args, unsigned int);
341: else if (cflags == DP_C_LONG)
342: value = (long)va_arg (args, unsigned long int);
343: else if (cflags == DP_C_LLONG)
344: value = (long)va_arg (args, unsigned LLONG);
345: else
346: value = (long)va_arg (args, unsigned int);
347: fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
348: break;
349: case 'u':
350: flags |= DP_F_UNSIGNED;
351: if (cflags == DP_C_SHORT)
352: value = va_arg (args, unsigned int);
353: else if (cflags == DP_C_LONG)
354: value = (long)va_arg (args, unsigned long int);
355: else if (cflags == DP_C_LLONG)
356: value = (LLONG)va_arg (args, unsigned LLONG);
357: else
358: value = (long)va_arg (args, unsigned int);
359: fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
360: break;
361: case 'X':
362: flags |= DP_F_UP;
363: case 'x':
364: flags |= DP_F_UNSIGNED;
365: if (cflags == DP_C_SHORT)
366: value = va_arg (args, unsigned int);
367: else if (cflags == DP_C_LONG)
368: value = (long)va_arg (args, unsigned long int);
369: else if (cflags == DP_C_LLONG)
370: value = (LLONG)va_arg (args, unsigned LLONG);
371: else
372: value = (long)va_arg (args, unsigned int);
373: fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
374: break;
375: case 'f':
376: if (cflags == DP_C_LDOUBLE)
377: fvalue = va_arg (args, LDOUBLE);
378: else
379: fvalue = va_arg (args, double);
380: /* um, floating point? */
381: fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
382: break;
383: case 'E':
384: flags |= DP_F_UP;
385: case 'e':
386: if (cflags == DP_C_LDOUBLE)
387: fvalue = va_arg (args, LDOUBLE);
388: else
389: fvalue = va_arg (args, double);
390: fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
391: break;
392: case 'G':
393: flags |= DP_F_UP;
394: case 'g':
395: if (cflags == DP_C_LDOUBLE)
396: fvalue = va_arg (args, LDOUBLE);
397: else
398: fvalue = va_arg (args, double);
399: fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
400: break;
401: case 'c':
402: dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
403: break;
404: case 's':
405: strvalue = va_arg (args, char *);
406: if (!strvalue) strvalue = "(NULL)";
407: if (max == -1) {
408: max = strlen(strvalue);
409: }
410: if (min > 0 && max >= 0 && min > max) max = min;
411: fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
412: break;
413: case 'p':
414: strvalue = va_arg (args, void *);
415: fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
416: break;
417: case 'n':
418: if (cflags == DP_C_SHORT) {
419: short int *num;
420: num = va_arg (args, short int *);
421: *num = currlen;
422: } else if (cflags == DP_C_LONG) {
423: long int *num;
424: num = va_arg (args, long int *);
425: *num = (long int)currlen;
426: } else if (cflags == DP_C_LLONG) {
427: LLONG *num;
428: num = va_arg (args, LLONG *);
429: *num = (LLONG)currlen;
430: } else {
431: int *num;
432: num = va_arg (args, int *);
433: *num = currlen;
434: }
435: break;
436: case '%':
437: dopr_outch (buffer, &currlen, maxlen, ch);
438: break;
439: case 'w':
440: /* not supported yet, treat as next char */
441: ch = *format++;
442: break;
443: default:
444: /* Unknown, skip */
445: break;
446: }
447: ch = *format++;
448: state = DP_S_DEFAULT;
449: flags = cflags = min = 0;
450: max = -1;
451: break;
452: case DP_S_DONE:
453: break;
454: default:
455: /* hmm? */
456: break; /* some picky compilers need this */
457: }
458: }
459: if (maxlen != 0) {
460: if (currlen < maxlen - 1)
461: buffer[currlen] = '\0';
462: else if (maxlen > 0)
463: buffer[maxlen - 1] = '\0';
464: }
465:
466: return currlen;
467: }
468:
469: static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
470: char *value, int flags, int min, int max)
471: {
472: int padlen, strln; /* amount to pad */
473: int cnt = 0;
474:
475: #ifdef DEBUG_SNPRINTF
476: printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value);
477: #endif
478: if (value == 0) {
479: value = "<NULL>";
480: }
481:
482: for (strln = 0; value[strln]; ++strln); /* strlen */
483: padlen = min - strln;
484: if (padlen < 0)
485: padlen = 0;
486: if (flags & DP_F_MINUS)
487: padlen = -padlen; /* Left Justify */
488:
489: while ((padlen > 0) && (cnt < max)) {
490: dopr_outch (buffer, currlen, maxlen, ' ');
491: --padlen;
492: ++cnt;
493: }
494: while (*value && (cnt < max)) {
495: dopr_outch (buffer, currlen, maxlen, *value++);
496: ++cnt;
497: }
498: while ((padlen < 0) && (cnt < max)) {
499: dopr_outch (buffer, currlen, maxlen, ' ');
500: ++padlen;
501: ++cnt;
502: }
503: }
504:
505: /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
506:
507: static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
508: long value, int base, int min, int max, int flags)
509: {
510: int signvalue = 0;
511: unsigned long uvalue;
512: char convert[20];
513: int place = 0;
514: int spadlen = 0; /* amount to space pad */
515: int zpadlen = 0; /* amount to zero pad */
516: int caps = 0;
517:
518: if (max < 0)
519: max = 0;
520:
521: uvalue = value;
522:
523: if(!(flags & DP_F_UNSIGNED)) {
524: if( value < 0 ) {
525: signvalue = '-';
526: uvalue = -value;
527: } else {
528: if (flags & DP_F_PLUS) /* Do a sign (+/i) */
529: signvalue = '+';
530: else if (flags & DP_F_SPACE)
531: signvalue = ' ';
532: }
533: }
534:
535: if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
536:
537: do {
538: convert[place++] =
539: (caps? "0123456789ABCDEF":"0123456789abcdef")
540: [uvalue % (unsigned)base ];
541: uvalue = (uvalue / (unsigned)base );
542: } while(uvalue && (place < 20));
543: if (place == 20) place--;
544: convert[place] = 0;
545:
546: zpadlen = max - place;
547: spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
548: if (zpadlen < 0) zpadlen = 0;
549: if (spadlen < 0) spadlen = 0;
550: if (flags & DP_F_ZERO) {
551: zpadlen = MAX(zpadlen, spadlen);
552: spadlen = 0;
553: }
554: if (flags & DP_F_MINUS)
555: spadlen = -spadlen; /* Left Justifty */
556:
557: #ifdef DEBUG_SNPRINTF
558: printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
559: zpadlen, spadlen, min, max, place);
560: #endif
561:
562: /* Spaces */
563: while (spadlen > 0) {
564: dopr_outch (buffer, currlen, maxlen, ' ');
565: --spadlen;
566: }
567:
568: /* Sign */
569: if (signvalue)
570: dopr_outch (buffer, currlen, maxlen, signvalue);
571:
572: /* Zeros */
573: if (zpadlen > 0) {
574: while (zpadlen > 0) {
575: dopr_outch (buffer, currlen, maxlen, '0');
576: --zpadlen;
577: }
578: }
579:
580: /* Digits */
581: while (place > 0)
582: dopr_outch (buffer, currlen, maxlen, convert[--place]);
583:
584: /* Left Justified spaces */
585: while (spadlen < 0) {
586: dopr_outch (buffer, currlen, maxlen, ' ');
587: ++spadlen;
588: }
589: }
590:
591: static LDOUBLE abs_val(LDOUBLE value)
592: {
593: LDOUBLE result = value;
594:
595: if (value < 0)
596: result = -value;
597:
598: return result;
599: }
600:
601: static LDOUBLE POW10(int exp)
602: {
603: LDOUBLE result = 1;
604:
605: while (exp) {
606: result *= 10;
607: exp--;
608: }
609:
610: return result;
611: }
612:
613: static LLONG ROUND(LDOUBLE value)
614: {
615: LLONG intpart;
616:
617: intpart = (LLONG)value;
618: value = value - intpart;
619: if (value >= 0.5) intpart++;
620:
621: return intpart;
622: }
623:
624: /* a replacement for modf that doesn't need the math library. Should
625: be portable, but slow */
626: static double my_modf(double x0, double *iptr)
627: {
628: int i;
629: long l;
630: double x = x0;
631: double f = 1.0;
632:
633: for (i=0;i<100;i++) {
634: l = (long)x;
635: if (l <= (x+1) && l >= (x-1)) {
636: if (i != 0) {
637: double i2;
638: double ret;
639:
640: ret = my_modf(x0-l*f, &i2);
641: (*iptr) = l*f + i2;
642: return ret;
643: }
644:
645: (*iptr) = l;
646: return x - (*iptr);
647: }
648: x *= 0.1;
649: f *= 10.0;
650: }
651:
652: /* yikes! the number is beyond what we can handle. What do we do? */
653: (*iptr) = 0;
654: return 0;
655: }
656:
657:
658: static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
659: LDOUBLE fvalue, int min, int max, int flags)
660: {
661: int signvalue = 0;
662: double ufvalue;
663: char iconvert[311];
664: char fconvert[311];
665: int iplace = 0;
666: int fplace = 0;
667: int padlen = 0; /* amount to pad */
668: int zpadlen = 0;
669: int caps = 0;
670: int idx;
671: double intpart;
672: double fracpart;
673: double temp;
674:
675: /*
676: * AIX manpage says the default is 0, but Solaris says the default
677: * is 6, and sprintf on AIX defaults to 6
678: */
679: if (max < 0)
680: max = 6;
681:
682: ufvalue = abs_val (fvalue);
683:
684: if (fvalue < 0) {
685: signvalue = '-';
686: } else {
687: if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
688: signvalue = '+';
689: } else {
690: if (flags & DP_F_SPACE)
691: signvalue = ' ';
692: }
693: }
694:
695: #if 0
696: if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
697: #endif
698:
699: #if 0
700: if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */
701: #endif
702:
703: /*
704: * Sorry, we only support 16 digits past the decimal because of our
705: * conversion method
706: */
707: if (max > 16)
708: max = 16;
709:
710: /* We "cheat" by converting the fractional part to integer by
711: * multiplying by a factor of 10
712: */
713:
714: temp = ufvalue;
715: my_modf(temp, &intpart);
716:
717: fracpart = ROUND((POW10(max)) * (ufvalue - intpart));
718:
719: if (fracpart >= POW10(max)) {
720: intpart++;
721: fracpart -= POW10(max);
722: }
723:
724:
725: /* Convert integer part */
726: do {
727: temp = intpart*0.1;
728: my_modf(temp, &intpart);
729: idx = (int) ((temp -intpart +0.05)* 10.0);
730: /* idx = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */
731: /* printf ("%llf, %f, %x\n", temp, intpart, idx); */
732: iconvert[iplace++] =
733: (caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
734: } while (intpart && (iplace < 311));
735: if (iplace == 311) iplace--;
736: iconvert[iplace] = 0;
737:
738: /* Convert fractional part */
739: if (fracpart)
740: {
741: do {
742: temp = fracpart*0.1;
743: my_modf(temp, &fracpart);
744: idx = (int) ((temp -fracpart +0.05)* 10.0);
745: /* idx = (int) ((((temp/10) -fracpart) +0.05) *10); */
746: /* printf ("%lf, %lf, %ld\n", temp, fracpart, idx ); */
747: fconvert[fplace++] =
748: (caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
749: } while(fracpart && (fplace < 311));
750: if (fplace == 311) fplace--;
751: }
752: fconvert[fplace] = 0;
753:
754: /* -1 for decimal point, another -1 if we are printing a sign */
755: padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
756: zpadlen = max - fplace;
757: if (zpadlen < 0) zpadlen = 0;
758: if (padlen < 0)
759: padlen = 0;
760: if (flags & DP_F_MINUS)
761: padlen = -padlen; /* Left Justifty */
762:
763: if ((flags & DP_F_ZERO) && (padlen > 0)) {
764: if (signvalue) {
765: dopr_outch (buffer, currlen, maxlen, signvalue);
766: --padlen;
767: signvalue = 0;
768: }
769: while (padlen > 0) {
770: dopr_outch (buffer, currlen, maxlen, '0');
771: --padlen;
772: }
773: }
774: while (padlen > 0) {
775: dopr_outch (buffer, currlen, maxlen, ' ');
776: --padlen;
777: }
778: if (signvalue)
779: dopr_outch (buffer, currlen, maxlen, signvalue);
780:
781: while (iplace > 0)
782: dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
783:
784: #ifdef DEBUG_SNPRINTF
785: printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
786: #endif
787:
788: /*
789: * Decimal point. This should probably use locale to find the correct
790: * char to print out.
791: */
792: if (max > 0) {
793: dopr_outch (buffer, currlen, maxlen, '.');
794:
795: while (zpadlen > 0) {
796: dopr_outch (buffer, currlen, maxlen, '0');
797: --zpadlen;
798: }
799:
800: while (fplace > 0)
801: dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
802: }
803:
804: while (padlen < 0) {
805: dopr_outch (buffer, currlen, maxlen, ' ');
806: ++padlen;
807: }
808: }
809:
810: static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
811: {
812: if (*currlen < maxlen) {
813: buffer[(*currlen)] = c;
814: }
815: (*currlen)++;
816: }
817:
818: int rsync_vsnprintf (char *str, size_t count, const char *fmt, va_list args)
819: {
820: return dopr(str, count, fmt, args);
821: }
822: #define vsnprintf rsync_vsnprintf
823: #endif
824:
825: /* yes this really must be a ||. Don't muck with this (tridge)
826: *
827: * The logic for these two is that we need our own definition if the
828: * OS *either* has no definition of *sprintf, or if it does have one
829: * that doesn't work properly according to the autoconf test.
830: */
831: #if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
832: int rsync_snprintf(char *str,size_t count,const char *fmt,...)
833: {
834: size_t ret;
835: va_list ap;
836:
837: va_start(ap, fmt);
838: ret = vsnprintf(str, count, fmt, ap);
839: va_end(ap);
840: return ret;
841: }
842: #define snprintf rsync_snprintf
843: #endif
844:
845: #endif
846:
847: #ifndef HAVE_VASPRINTF
848: int vasprintf(char **ptr, const char *format, va_list ap)
849: {
850: int ret;
851: va_list ap2;
852:
853: VA_COPY(ap2, ap);
854:
855: ret = vsnprintf(NULL, 0, format, ap2);
856: if (ret <= 0) return ret;
857:
858: (*ptr) = (char *)malloc(ret+1);
859: if (!*ptr) return -1;
860:
861: VA_COPY(ap2, ap);
862:
863: ret = vsnprintf(*ptr, ret+1, format, ap2);
864:
865: return ret;
866: }
867: #endif
868:
869:
870: #ifndef HAVE_ASPRINTF
871: int asprintf(char **ptr, const char *format, ...)
872: {
873: va_list ap;
874: int ret;
875:
876: *ptr = NULL;
877: va_start(ap, format);
878: ret = vasprintf(ptr, format, ap);
879: va_end(ap);
880:
881: return ret;
882: }
883: #endif
884:
885: #ifdef TEST_SNPRINTF
886:
887: int sprintf(char *str,const char *fmt,...);
888:
889: int main (void)
890: {
891: char buf1[1024];
892: char buf2[1024];
893: char *fp_fmt[] = {
894: "%1.1f",
895: "%-1.5f",
896: "%1.5f",
897: "%123.9f",
898: "%10.5f",
899: "% 10.5f",
900: "%+22.9f",
901: "%+4.9f",
902: "%01.3f",
903: "%4f",
904: "%3.1f",
905: "%3.2f",
906: "%.0f",
907: "%f",
908: "-16.16f",
909: NULL
910: };
911: double fp_nums[] = { 6442452944.1234, -1.5, 134.21, 91340.2, 341.1234, 203.9, 0.96, 0.996,
912: 0.9996, 1.996, 4.136, 5.030201, 0.00205,
913: /* END LIST */ 0};
914: char *int_fmt[] = {
915: "%-1.5d",
916: "%1.5d",
917: "%123.9d",
918: "%5.5d",
919: "%10.5d",
920: "% 10.5d",
921: "%+22.33d",
922: "%01.3d",
923: "%4d",
924: "%d",
925: NULL
926: };
927: long int_nums[] = { -1, 134, 91340, 341, 0203, 0};
928: char *str_fmt[] = {
929: "10.5s",
930: "5.10s",
931: "10.1s",
932: "0.10s",
933: "10.0s",
934: "1.10s",
935: "%s",
936: "%.1s",
937: "%.10s",
938: "%10s",
939: NULL
940: };
941: char *str_vals[] = {"hello", "a", "", "a longer string", NULL};
942: int x, y;
943: int fail = 0;
944: int num = 0;
945:
946: printf ("Testing snprintf format codes against system sprintf...\n");
947:
948: for (x = 0; fp_fmt[x] ; x++) {
949: for (y = 0; fp_nums[y] != 0 ; y++) {
950: int l1 = snprintf(NULL, 0, fp_fmt[x], fp_nums[y]);
951: int l2 = snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]);
952: sprintf (buf2, fp_fmt[x], fp_nums[y]);
953: if (strcmp (buf1, buf2)) {
954: printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n",
955: fp_fmt[x], buf1, buf2);
956: fail++;
957: }
958: if (l1 != l2) {
959: printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, fp_fmt[x]);
960: fail++;
961: }
962: num++;
963: }
964: }
965:
966: for (x = 0; int_fmt[x] ; x++) {
967: for (y = 0; int_nums[y] != 0 ; y++) {
968: int l1 = snprintf(NULL, 0, int_fmt[x], int_nums[y]);
969: int l2 = snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]);
970: sprintf (buf2, int_fmt[x], int_nums[y]);
971: if (strcmp (buf1, buf2)) {
972: printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n",
973: int_fmt[x], buf1, buf2);
974: fail++;
975: }
976: if (l1 != l2) {
977: printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, int_fmt[x]);
978: fail++;
979: }
980: num++;
981: }
982: }
983:
984: for (x = 0; str_fmt[x] ; x++) {
985: for (y = 0; str_vals[y] != 0 ; y++) {
986: int l1 = snprintf(NULL, 0, str_fmt[x], str_vals[y]);
987: int l2 = snprintf(buf1, sizeof(buf1), str_fmt[x], str_vals[y]);
988: sprintf (buf2, str_fmt[x], str_vals[y]);
989: if (strcmp (buf1, buf2)) {
990: printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n",
991: str_fmt[x], buf1, buf2);
992: fail++;
993: }
994: if (l1 != l2) {
995: printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, str_fmt[x]);
996: fail++;
997: }
998: num++;
999: }
1000: }
1001:
1002: printf ("%d tests failed out of %d.\n", fail, num);
1003:
1004: printf("seeing how many digits we support\n");
1005: {
1006: double v0 = 0.12345678901234567890123456789012345678901;
1007: for (x=0; x<100; x++) {
1008: double p = pow(10, x);
1009: double r = v0*p;
1010: snprintf(buf1, sizeof(buf1), "%1.1f", r);
1011: sprintf(buf2, "%1.1f", r);
1012: if (strcmp(buf1, buf2)) {
1013: printf("we seem to support %d digits\n", x-1);
1014: break;
1015: }
1016: }
1017: }
1018:
1019: return 0;
1020: }
1021: #endif /* TEST_SNPRINTF */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>