Annotation of embedaddon/rsync/lib/snprintf.c, revision 1.1.1.2
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:
1.1.1.2 ! misho 40: * gcc -I.. -DTEST_SNPRINTF -o snprintf snprintf.c -lm
1.1 misho 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.
1.1.1.2 ! misho 92: *
! 93: * Darren Tucker (dtucker@zip.com.au) 2005
! 94: * Fix bug allowing read overruns of the source string with "%.*s"
! 95: * Usually harmless unless the read runs outside the process' allocation
! 96: * (eg if your malloc does guard pages) in which case it will segfault.
! 97: * From OpenSSH. Also added test for same.
! 98: *
! 99: * Simo Sorce (idra@samba.org) Jan 2006
! 100: *
! 101: * Add support for position independent parameters
! 102: * fix fmtstr now it conforms to sprintf wrt min.max
! 103: *
1.1 misho 104: **************************************************************/
105:
106: #include "config.h"
107:
108: #ifdef TEST_SNPRINTF /* need math library headers for testing */
109:
110: /* In test mode, we pretend that this system doesn't have any snprintf
111: * functions, regardless of what config.h says. */
112: # undef HAVE_SNPRINTF
113: # undef HAVE_VSNPRINTF
114: # undef HAVE_C99_VSNPRINTF
115: # undef HAVE_ASPRINTF
116: # undef HAVE_VASPRINTF
117: # include <math.h>
118: #endif /* TEST_SNPRINTF */
119:
120: #ifdef HAVE_STRING_H
121: #include <string.h>
122: #endif
123:
124: #ifdef HAVE_STRINGS_H
125: #include <strings.h>
126: #endif
127: #ifdef HAVE_CTYPE_H
128: #include <ctype.h>
129: #endif
130: #include <sys/types.h>
131: #include <stdarg.h>
132: #ifdef HAVE_STDLIB_H
133: #include <stdlib.h>
134: #endif
135:
136: #if defined(HAVE_SNPRINTF) && defined(HAVE_VSNPRINTF) && defined(HAVE_C99_VSNPRINTF)
137: /* only include stdio.h if we are not re-defining snprintf or vsnprintf */
138: #include <stdio.h>
139: /* make the compiler happy with an empty file */
140: void dummy_snprintf(void);
141: void dummy_snprintf(void) {}
142: #endif /* HAVE_SNPRINTF, etc */
143:
1.1.1.2 ! misho 144: #ifdef STDC_HEADERS
! 145: #include <stddef.h>
! 146: #endif
! 147:
1.1 misho 148: #ifdef HAVE_LONG_DOUBLE
149: #define LDOUBLE long double
150: #else
151: #define LDOUBLE double
152: #endif
153:
1.1.1.2 ! misho 154: #if !defined HAVE_LONG_LONG && SIZEOF_LONG_LONG
! 155: #define HAVE_LONG_LONG 1
! 156: #endif
! 157: #ifdef HAVE_LONG_LONG
1.1 misho 158: #define LLONG long long
159: #else
160: #define LLONG long
161: #endif
162:
163: #ifndef VA_COPY
164: #if defined HAVE_VA_COPY || defined va_copy
165: #define VA_COPY(dest, src) va_copy(dest, src)
166: #else
167: #ifdef HAVE___VA_COPY
168: #define VA_COPY(dest, src) __va_copy(dest, src)
169: #else
170: #define VA_COPY(dest, src) (dest) = (src)
171: #endif
172: #endif
1.1.1.2 ! misho 173: #endif
! 174:
! 175: /* yes this really must be a ||. Don't muck with this (tridge) */
! 176: #if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
1.1 misho 177:
178: /*
179: * dopr(): poor man's version of doprintf
180: */
181:
182: /* format read states */
183: #define DP_S_DEFAULT 0
184: #define DP_S_FLAGS 1
185: #define DP_S_MIN 2
186: #define DP_S_DOT 3
187: #define DP_S_MAX 4
188: #define DP_S_MOD 5
189: #define DP_S_CONV 6
190: #define DP_S_DONE 7
191:
192: /* format flags - Bits */
193: #define DP_F_MINUS (1 << 0)
194: #define DP_F_PLUS (1 << 1)
195: #define DP_F_SPACE (1 << 2)
196: #define DP_F_NUM (1 << 3)
197: #define DP_F_ZERO (1 << 4)
198: #define DP_F_UP (1 << 5)
199: #define DP_F_UNSIGNED (1 << 6)
200:
201: /* Conversion Flags */
1.1.1.2 ! misho 202: #define DP_C_CHAR 1
! 203: #define DP_C_SHORT 2
! 204: #define DP_C_LONG 3
! 205: #define DP_C_LDOUBLE 4
! 206: #define DP_C_LLONG 5
! 207: #define DP_C_SIZET 6
! 208:
! 209: /* Chunk types */
! 210: #define CNK_FMT_STR 0
! 211: #define CNK_INT 1
! 212: #define CNK_OCTAL 2
! 213: #define CNK_UINT 3
! 214: #define CNK_HEX 4
! 215: #define CNK_FLOAT 5
! 216: #define CNK_CHAR 6
! 217: #define CNK_STRING 7
! 218: #define CNK_PTR 8
! 219: #define CNK_NUM 9
! 220: #define CNK_PRCNT 10
1.1 misho 221:
222: #define char_to_int(p) ((p)- '0')
223: #ifndef MAX
224: #define MAX(p,q) (((p) >= (q)) ? (p) : (q))
225: #endif
226:
1.1.1.2 ! misho 227: struct pr_chunk {
! 228: int type; /* chunk type */
! 229: int num; /* parameter number */
! 230: int min;
! 231: int max;
! 232: int flags;
! 233: int cflags;
! 234: int start;
! 235: int len;
! 236: LLONG value;
! 237: LDOUBLE fvalue;
! 238: char *strvalue;
! 239: void *pnum;
! 240: struct pr_chunk *min_star;
! 241: struct pr_chunk *max_star;
! 242: struct pr_chunk *next;
! 243: };
! 244:
! 245: struct pr_chunk_x {
! 246: struct pr_chunk **chunks;
! 247: int num;
! 248: };
1.1 misho 249:
1.1.1.2 ! misho 250: static int dopr(char *buffer, size_t maxlen, const char *format,
1.1 misho 251: va_list args_in);
252: static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
253: char *value, int flags, int min, int max);
254: static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
1.1.1.2 ! misho 255: LLONG value, int base, int min, int max, int flags);
1.1 misho 256: static void fmtfp(char *buffer, size_t *currlen, size_t maxlen,
257: LDOUBLE fvalue, int min, int max, int flags);
258: static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
1.1.1.2 ! misho 259: static struct pr_chunk *new_chunk(void);
! 260: static int add_cnk_list_entry(struct pr_chunk_x **list,
! 261: int max_num, struct pr_chunk *chunk);
1.1 misho 262:
1.1.1.2 ! misho 263: static int dopr(char *buffer, size_t maxlen, const char *format, va_list args_in)
1.1 misho 264: {
265: char ch;
266: int state;
1.1.1.2 ! misho 267: int pflag;
! 268: int pnum;
! 269: int pfirst;
1.1 misho 270: size_t currlen;
271: va_list args;
1.1.1.2 ! misho 272: const char *base;
! 273: struct pr_chunk *chunks = NULL;
! 274: struct pr_chunk *cnk = NULL;
! 275: struct pr_chunk_x *clist = NULL;
! 276: int max_pos;
! 277: int ret = -1;
1.1 misho 278:
279: VA_COPY(args, args_in);
1.1.1.2 ! misho 280:
1.1 misho 281: state = DP_S_DEFAULT;
1.1.1.2 ! misho 282: pfirst = 1;
! 283: pflag = 0;
! 284: pnum = 0;
! 285:
! 286: max_pos = 0;
! 287: base = format;
1.1 misho 288: ch = *format++;
289:
1.1.1.2 ! misho 290: /* retrieve the string structure as chunks */
1.1 misho 291: while (state != DP_S_DONE) {
292: if (ch == '\0')
293: state = DP_S_DONE;
294:
295: switch(state) {
296: case DP_S_DEFAULT:
1.1.1.2 ! misho 297:
! 298: if (cnk) {
! 299: cnk->next = new_chunk();
! 300: cnk = cnk->next;
! 301: } else {
! 302: cnk = new_chunk();
! 303: }
! 304: if (!cnk) goto done;
! 305: if (!chunks) chunks = cnk;
! 306:
! 307: if (ch == '%') {
1.1 misho 308: state = DP_S_FLAGS;
1.1.1.2 ! misho 309: ch = *format++;
! 310: } else {
! 311: cnk->type = CNK_FMT_STR;
! 312: cnk->start = format - base -1;
! 313: while ((ch != '\0') && (ch != '%')) ch = *format++;
! 314: cnk->len = format - base - cnk->start -1;
! 315: }
1.1 misho 316: break;
317: case DP_S_FLAGS:
318: switch (ch) {
319: case '-':
1.1.1.2 ! misho 320: cnk->flags |= DP_F_MINUS;
1.1 misho 321: ch = *format++;
322: break;
323: case '+':
1.1.1.2 ! misho 324: cnk->flags |= DP_F_PLUS;
1.1 misho 325: ch = *format++;
326: break;
327: case ' ':
1.1.1.2 ! misho 328: cnk->flags |= DP_F_SPACE;
1.1 misho 329: ch = *format++;
330: break;
331: case '#':
1.1.1.2 ! misho 332: cnk->flags |= DP_F_NUM;
1.1 misho 333: ch = *format++;
334: break;
335: case '0':
1.1.1.2 ! misho 336: cnk->flags |= DP_F_ZERO;
! 337: ch = *format++;
! 338: break;
! 339: case 'I':
! 340: /* internationalization not supported yet */
1.1 misho 341: ch = *format++;
342: break;
343: default:
344: state = DP_S_MIN;
345: break;
346: }
347: break;
348: case DP_S_MIN:
349: if (isdigit((unsigned char)ch)) {
1.1.1.2 ! misho 350: cnk->min = 10 * cnk->min + char_to_int (ch);
! 351: ch = *format++;
! 352: } else if (ch == '$') {
! 353: if (!pfirst && !pflag) {
! 354: /* parameters must be all positioned or none */
! 355: goto done;
! 356: }
! 357: if (pfirst) {
! 358: pfirst = 0;
! 359: pflag = 1;
! 360: }
! 361: if (cnk->min == 0) /* what ?? */
! 362: goto done;
! 363: cnk->num = cnk->min;
! 364: cnk->min = 0;
1.1 misho 365: ch = *format++;
366: } else if (ch == '*') {
1.1.1.2 ! misho 367: if (pfirst) pfirst = 0;
! 368: cnk->min_star = new_chunk();
! 369: if (!cnk->min_star) /* out of memory :-( */
! 370: goto done;
! 371: cnk->min_star->type = CNK_INT;
! 372: if (pflag) {
! 373: int num;
! 374: ch = *format++;
! 375: if (!isdigit((unsigned char)ch)) {
! 376: /* parameters must be all positioned or none */
! 377: goto done;
! 378: }
! 379: for (num = 0; isdigit((unsigned char)ch); ch = *format++) {
! 380: num = 10 * num + char_to_int(ch);
! 381: }
! 382: cnk->min_star->num = num;
! 383: if (ch != '$') /* what ?? */
! 384: goto done;
! 385: } else {
! 386: cnk->min_star->num = ++pnum;
! 387: }
! 388: max_pos = add_cnk_list_entry(&clist, max_pos, cnk->min_star);
! 389: if (max_pos == 0) /* out of memory :-( */
! 390: goto done;
1.1 misho 391: ch = *format++;
392: state = DP_S_DOT;
393: } else {
1.1.1.2 ! misho 394: if (pfirst) pfirst = 0;
1.1 misho 395: state = DP_S_DOT;
396: }
397: break;
398: case DP_S_DOT:
399: if (ch == '.') {
400: state = DP_S_MAX;
401: ch = *format++;
402: } else {
403: state = DP_S_MOD;
404: }
405: break;
406: case DP_S_MAX:
407: if (isdigit((unsigned char)ch)) {
1.1.1.2 ! misho 408: if (cnk->max < 0)
! 409: cnk->max = 0;
! 410: cnk->max = 10 * cnk->max + char_to_int (ch);
! 411: ch = *format++;
! 412: } else if (ch == '$') {
! 413: if (!pfirst && !pflag) {
! 414: /* parameters must be all positioned or none */
! 415: goto done;
! 416: }
! 417: if (cnk->max <= 0) /* what ?? */
! 418: goto done;
! 419: cnk->num = cnk->max;
! 420: cnk->max = -1;
1.1 misho 421: ch = *format++;
422: } else if (ch == '*') {
1.1.1.2 ! misho 423: cnk->max_star = new_chunk();
! 424: if (!cnk->max_star) /* out of memory :-( */
! 425: goto done;
! 426: cnk->max_star->type = CNK_INT;
! 427: if (pflag) {
! 428: int num;
! 429: ch = *format++;
! 430: if (!isdigit((unsigned char)ch)) {
! 431: /* parameters must be all positioned or none */
! 432: goto done;
! 433: }
! 434: for (num = 0; isdigit((unsigned char)ch); ch = *format++) {
! 435: num = 10 * num + char_to_int(ch);
! 436: }
! 437: cnk->max_star->num = num;
! 438: if (ch != '$') /* what ?? */
! 439: goto done;
! 440: } else {
! 441: cnk->max_star->num = ++pnum;
! 442: }
! 443: max_pos = add_cnk_list_entry(&clist, max_pos, cnk->max_star);
! 444: if (max_pos == 0) /* out of memory :-( */
! 445: goto done;
! 446:
1.1 misho 447: ch = *format++;
448: state = DP_S_MOD;
449: } else {
450: state = DP_S_MOD;
451: }
452: break;
453: case DP_S_MOD:
454: switch (ch) {
455: case 'h':
1.1.1.2 ! misho 456: cnk->cflags = DP_C_SHORT;
1.1 misho 457: ch = *format++;
1.1.1.2 ! misho 458: if (ch == 'h') {
! 459: cnk->cflags = DP_C_CHAR;
! 460: ch = *format++;
! 461: }
1.1 misho 462: break;
463: case 'l':
1.1.1.2 ! misho 464: cnk->cflags = DP_C_LONG;
1.1 misho 465: ch = *format++;
466: if (ch == 'l') { /* It's a long long */
1.1.1.2 ! misho 467: cnk->cflags = DP_C_LLONG;
1.1 misho 468: ch = *format++;
469: }
470: break;
471: case 'L':
1.1.1.2 ! misho 472: cnk->cflags = DP_C_LDOUBLE;
! 473: ch = *format++;
! 474: break;
! 475: case 'z':
! 476: cnk->cflags = DP_C_SIZET;
1.1 misho 477: ch = *format++;
478: break;
479: default:
480: break;
481: }
482: state = DP_S_CONV;
483: break;
484: case DP_S_CONV:
1.1.1.2 ! misho 485: if (cnk->num == 0) cnk->num = ++pnum;
! 486: max_pos = add_cnk_list_entry(&clist, max_pos, cnk);
! 487: if (max_pos == 0) /* out of memory :-( */
! 488: goto done;
! 489:
1.1 misho 490: switch (ch) {
491: case 'd':
492: case 'i':
1.1.1.2 ! misho 493: cnk->type = CNK_INT;
1.1 misho 494: break;
495: case 'o':
1.1.1.2 ! misho 496: cnk->type = CNK_OCTAL;
! 497: cnk->flags |= DP_F_UNSIGNED;
1.1 misho 498: break;
499: case 'u':
1.1.1.2 ! misho 500: cnk->type = CNK_UINT;
! 501: cnk->flags |= DP_F_UNSIGNED;
1.1 misho 502: break;
503: case 'X':
1.1.1.2 ! misho 504: cnk->flags |= DP_F_UP;
1.1 misho 505: case 'x':
1.1.1.2 ! misho 506: cnk->type = CNK_HEX;
! 507: cnk->flags |= DP_F_UNSIGNED;
1.1 misho 508: break;
1.1.1.2 ! misho 509: case 'A':
! 510: /* hex float not supported yet */
1.1 misho 511: case 'E':
512: case 'G':
1.1.1.2 ! misho 513: case 'F':
! 514: cnk->flags |= DP_F_UP;
! 515: case 'a':
! 516: /* hex float not supported yet */
! 517: case 'e':
! 518: case 'f':
1.1 misho 519: case 'g':
1.1.1.2 ! misho 520: cnk->type = CNK_FLOAT;
1.1 misho 521: break;
522: case 'c':
1.1.1.2 ! misho 523: cnk->type = CNK_CHAR;
1.1 misho 524: break;
525: case 's':
1.1.1.2 ! misho 526: cnk->type = CNK_STRING;
1.1 misho 527: break;
528: case 'p':
1.1.1.2 ! misho 529: cnk->type = CNK_PTR;
! 530: cnk->flags |= DP_F_UNSIGNED;
1.1 misho 531: break;
532: case 'n':
1.1.1.2 ! misho 533: cnk->type = CNK_NUM;
1.1 misho 534: break;
535: case '%':
1.1.1.2 ! misho 536: cnk->type = CNK_PRCNT;
1.1 misho 537: break;
538: default:
1.1.1.2 ! misho 539: /* Unknown, bail out*/
! 540: goto done;
1.1 misho 541: }
542: ch = *format++;
543: state = DP_S_DEFAULT;
544: break;
545: case DP_S_DONE:
546: break;
547: default:
548: /* hmm? */
549: break; /* some picky compilers need this */
550: }
551: }
1.1.1.2 ! misho 552:
! 553: /* retrieve the format arguments */
! 554: for (pnum = 0; pnum < max_pos; pnum++) {
! 555: int i;
! 556:
! 557: if (clist[pnum].num == 0) {
! 558: /* ignoring a parameter should not be permitted
! 559: * all parameters must be matched at least once
! 560: * BUT seem some system ignore this rule ...
! 561: * at least my glibc based system does --SSS
! 562: */
! 563: #ifdef DEBUG_SNPRINTF
! 564: printf("parameter at position %d not used\n", pnum+1);
! 565: #endif
! 566: /* eat the parameter */
! 567: va_arg (args, int);
! 568: continue;
! 569: }
! 570: for (i = 1; i < clist[pnum].num; i++) {
! 571: if (clist[pnum].chunks[0]->type != clist[pnum].chunks[i]->type) {
! 572: /* nooo noo no!
! 573: * all the references to a parameter
! 574: * must be of the same type
! 575: */
! 576: goto done;
! 577: }
! 578: }
! 579: cnk = clist[pnum].chunks[0];
! 580: switch (cnk->type) {
! 581: case CNK_INT:
! 582: if (cnk->cflags == DP_C_SHORT)
! 583: cnk->value = va_arg (args, int);
! 584: else if (cnk->cflags == DP_C_LONG)
! 585: cnk->value = va_arg (args, long int);
! 586: else if (cnk->cflags == DP_C_LLONG)
! 587: cnk->value = va_arg (args, LLONG);
! 588: else if (cnk->cflags == DP_C_SIZET)
! 589: cnk->value = va_arg (args, ssize_t);
! 590: else
! 591: cnk->value = va_arg (args, int);
! 592:
! 593: for (i = 1; i < clist[pnum].num; i++) {
! 594: clist[pnum].chunks[i]->value = cnk->value;
! 595: }
! 596: break;
! 597:
! 598: case CNK_OCTAL:
! 599: case CNK_UINT:
! 600: case CNK_HEX:
! 601: if (cnk->cflags == DP_C_SHORT)
! 602: cnk->value = va_arg (args, unsigned int);
! 603: else if (cnk->cflags == DP_C_LONG)
! 604: cnk->value = (unsigned long int)va_arg (args, unsigned long int);
! 605: else if (cnk->cflags == DP_C_LLONG)
! 606: cnk->value = (LLONG)va_arg (args, unsigned LLONG);
! 607: else if (cnk->cflags == DP_C_SIZET)
! 608: cnk->value = (size_t)va_arg (args, size_t);
! 609: else
! 610: cnk->value = (unsigned int)va_arg (args, unsigned int);
! 611:
! 612: for (i = 1; i < clist[pnum].num; i++) {
! 613: clist[pnum].chunks[i]->value = cnk->value;
! 614: }
! 615: break;
! 616:
! 617: case CNK_FLOAT:
! 618: if (cnk->cflags == DP_C_LDOUBLE)
! 619: cnk->fvalue = va_arg (args, LDOUBLE);
! 620: else
! 621: cnk->fvalue = va_arg (args, double);
! 622:
! 623: for (i = 1; i < clist[pnum].num; i++) {
! 624: clist[pnum].chunks[i]->fvalue = cnk->fvalue;
! 625: }
! 626: break;
! 627:
! 628: case CNK_CHAR:
! 629: cnk->value = va_arg (args, int);
! 630:
! 631: for (i = 1; i < clist[pnum].num; i++) {
! 632: clist[pnum].chunks[i]->value = cnk->value;
! 633: }
! 634: break;
! 635:
! 636: case CNK_STRING:
! 637: cnk->strvalue = va_arg (args, char *);
! 638: if (!cnk->strvalue) cnk->strvalue = "(NULL)";
! 639:
! 640: for (i = 1; i < clist[pnum].num; i++) {
! 641: clist[pnum].chunks[i]->strvalue = cnk->strvalue;
! 642: }
! 643: break;
! 644:
! 645: case CNK_PTR:
! 646: cnk->strvalue = va_arg (args, void *);
! 647: for (i = 1; i < clist[pnum].num; i++) {
! 648: clist[pnum].chunks[i]->strvalue = cnk->strvalue;
! 649: }
! 650: break;
! 651:
! 652: case CNK_NUM:
! 653: if (cnk->cflags == DP_C_CHAR)
! 654: cnk->pnum = va_arg (args, char *);
! 655: else if (cnk->cflags == DP_C_SHORT)
! 656: cnk->pnum = va_arg (args, short int *);
! 657: else if (cnk->cflags == DP_C_LONG)
! 658: cnk->pnum = va_arg (args, long int *);
! 659: else if (cnk->cflags == DP_C_LLONG)
! 660: cnk->pnum = va_arg (args, LLONG *);
! 661: else if (cnk->cflags == DP_C_SIZET)
! 662: cnk->pnum = va_arg (args, ssize_t *);
! 663: else
! 664: cnk->pnum = va_arg (args, int *);
! 665:
! 666: for (i = 1; i < clist[pnum].num; i++) {
! 667: clist[pnum].chunks[i]->pnum = cnk->pnum;
! 668: }
! 669: break;
! 670:
! 671: case CNK_PRCNT:
! 672: break;
! 673:
! 674: default:
! 675: /* what ?? */
! 676: goto done;
! 677: }
! 678: }
! 679: /* print out the actual string from chunks */
! 680: currlen = 0;
! 681: cnk = chunks;
! 682: while (cnk) {
! 683: int len, min, max;
! 684:
! 685: if (cnk->min_star) min = cnk->min_star->value;
! 686: else min = cnk->min;
! 687: if (cnk->max_star) max = cnk->max_star->value;
! 688: else max = cnk->max;
! 689:
! 690: switch (cnk->type) {
! 691:
! 692: case CNK_FMT_STR:
! 693: if (maxlen != 0 && maxlen > currlen) {
! 694: if (maxlen > (currlen + cnk->len)) len = cnk->len;
! 695: else len = maxlen - currlen;
! 696:
! 697: memcpy(&(buffer[currlen]), &(base[cnk->start]), len);
! 698: }
! 699: currlen += cnk->len;
! 700:
! 701: break;
! 702:
! 703: case CNK_INT:
! 704: case CNK_UINT:
! 705: fmtint (buffer, &currlen, maxlen, cnk->value, 10, min, max, cnk->flags);
! 706: break;
! 707:
! 708: case CNK_OCTAL:
! 709: fmtint (buffer, &currlen, maxlen, cnk->value, 8, min, max, cnk->flags);
! 710: break;
! 711:
! 712: case CNK_HEX:
! 713: fmtint (buffer, &currlen, maxlen, cnk->value, 16, min, max, cnk->flags);
! 714: break;
! 715:
! 716: case CNK_FLOAT:
! 717: fmtfp (buffer, &currlen, maxlen, cnk->fvalue, min, max, cnk->flags);
! 718: break;
! 719:
! 720: case CNK_CHAR:
! 721: dopr_outch (buffer, &currlen, maxlen, cnk->value);
! 722: break;
! 723:
! 724: case CNK_STRING:
! 725: if (max == -1) {
! 726: max = strlen(cnk->strvalue);
! 727: }
! 728: fmtstr (buffer, &currlen, maxlen, cnk->strvalue, cnk->flags, min, max);
! 729: break;
! 730:
! 731: case CNK_PTR:
! 732: fmtint (buffer, &currlen, maxlen, (long)(cnk->strvalue), 16, min, max, cnk->flags);
! 733: break;
! 734:
! 735: case CNK_NUM:
! 736: if (cnk->cflags == DP_C_CHAR)
! 737: *((char *)(cnk->pnum)) = (char)currlen;
! 738: else if (cnk->cflags == DP_C_SHORT)
! 739: *((short int *)(cnk->pnum)) = (short int)currlen;
! 740: else if (cnk->cflags == DP_C_LONG)
! 741: *((long int *)(cnk->pnum)) = (long int)currlen;
! 742: else if (cnk->cflags == DP_C_LLONG)
! 743: *((LLONG *)(cnk->pnum)) = (LLONG)currlen;
! 744: else if (cnk->cflags == DP_C_SIZET)
! 745: *((ssize_t *)(cnk->pnum)) = (ssize_t)currlen;
! 746: else
! 747: *((int *)(cnk->pnum)) = (int)currlen;
! 748: break;
! 749:
! 750: case CNK_PRCNT:
! 751: dopr_outch (buffer, &currlen, maxlen, '%');
! 752: break;
! 753:
! 754: default:
! 755: /* what ?? */
! 756: goto done;
! 757: }
! 758: cnk = cnk->next;
! 759: }
1.1 misho 760: if (maxlen != 0) {
761: if (currlen < maxlen - 1)
762: buffer[currlen] = '\0';
763: else if (maxlen > 0)
764: buffer[maxlen - 1] = '\0';
765: }
1.1.1.2 ! misho 766: ret = currlen;
! 767:
! 768: done:
! 769: va_end(args);
! 770:
! 771: while (chunks) {
! 772: cnk = chunks->next;
! 773: free(chunks);
! 774: chunks = cnk;
! 775: }
! 776: if (clist) {
! 777: for (pnum = 0; pnum < max_pos; pnum++) {
! 778: if (clist[pnum].chunks) free(clist[pnum].chunks);
! 779: }
! 780: free(clist);
! 781: }
! 782: return ret;
1.1 misho 783: }
784:
785: static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
786: char *value, int flags, int min, int max)
787: {
788: int padlen, strln; /* amount to pad */
789: int cnt = 0;
790:
791: #ifdef DEBUG_SNPRINTF
792: printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value);
793: #endif
794: if (value == 0) {
795: value = "<NULL>";
796: }
797:
1.1.1.2 ! misho 798: for (strln = 0; strln < max && value[strln]; ++strln); /* strlen */
1.1 misho 799: padlen = min - strln;
800: if (padlen < 0)
801: padlen = 0;
802: if (flags & DP_F_MINUS)
803: padlen = -padlen; /* Left Justify */
804:
1.1.1.2 ! misho 805: while (padlen > 0) {
1.1 misho 806: dopr_outch (buffer, currlen, maxlen, ' ');
807: --padlen;
808: }
809: while (*value && (cnt < max)) {
810: dopr_outch (buffer, currlen, maxlen, *value++);
811: ++cnt;
812: }
1.1.1.2 ! misho 813: while (padlen < 0) {
1.1 misho 814: dopr_outch (buffer, currlen, maxlen, ' ');
815: ++padlen;
816: }
817: }
818:
819: /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
820:
821: static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
1.1.1.2 ! misho 822: LLONG value, int base, int min, int max, int flags)
1.1 misho 823: {
824: int signvalue = 0;
1.1.1.2 ! misho 825: unsigned LLONG uvalue;
1.1 misho 826: char convert[20];
827: int place = 0;
828: int spadlen = 0; /* amount to space pad */
829: int zpadlen = 0; /* amount to zero pad */
830: int caps = 0;
831:
832: if (max < 0)
833: max = 0;
834:
835: uvalue = value;
836:
837: if(!(flags & DP_F_UNSIGNED)) {
838: if( value < 0 ) {
839: signvalue = '-';
840: uvalue = -value;
841: } else {
842: if (flags & DP_F_PLUS) /* Do a sign (+/i) */
843: signvalue = '+';
844: else if (flags & DP_F_SPACE)
845: signvalue = ' ';
846: }
847: }
848:
849: if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
850:
851: do {
852: convert[place++] =
853: (caps? "0123456789ABCDEF":"0123456789abcdef")
854: [uvalue % (unsigned)base ];
855: uvalue = (uvalue / (unsigned)base );
856: } while(uvalue && (place < 20));
857: if (place == 20) place--;
858: convert[place] = 0;
859:
860: zpadlen = max - place;
861: spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
862: if (zpadlen < 0) zpadlen = 0;
863: if (spadlen < 0) spadlen = 0;
864: if (flags & DP_F_ZERO) {
865: zpadlen = MAX(zpadlen, spadlen);
866: spadlen = 0;
867: }
868: if (flags & DP_F_MINUS)
869: spadlen = -spadlen; /* Left Justifty */
870:
871: #ifdef DEBUG_SNPRINTF
872: printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
873: zpadlen, spadlen, min, max, place);
874: #endif
875:
876: /* Spaces */
877: while (spadlen > 0) {
878: dopr_outch (buffer, currlen, maxlen, ' ');
879: --spadlen;
880: }
881:
882: /* Sign */
883: if (signvalue)
884: dopr_outch (buffer, currlen, maxlen, signvalue);
885:
886: /* Zeros */
887: if (zpadlen > 0) {
888: while (zpadlen > 0) {
889: dopr_outch (buffer, currlen, maxlen, '0');
890: --zpadlen;
891: }
892: }
893:
894: /* Digits */
895: while (place > 0)
896: dopr_outch (buffer, currlen, maxlen, convert[--place]);
897:
898: /* Left Justified spaces */
899: while (spadlen < 0) {
900: dopr_outch (buffer, currlen, maxlen, ' ');
901: ++spadlen;
902: }
903: }
904:
905: static LDOUBLE abs_val(LDOUBLE value)
906: {
907: LDOUBLE result = value;
908:
909: if (value < 0)
910: result = -value;
911:
912: return result;
913: }
914:
915: static LDOUBLE POW10(int exp)
916: {
917: LDOUBLE result = 1;
918:
919: while (exp) {
920: result *= 10;
921: exp--;
922: }
923:
924: return result;
925: }
926:
927: static LLONG ROUND(LDOUBLE value)
928: {
929: LLONG intpart;
930:
931: intpart = (LLONG)value;
932: value = value - intpart;
933: if (value >= 0.5) intpart++;
934:
935: return intpart;
936: }
937:
938: /* a replacement for modf that doesn't need the math library. Should
939: be portable, but slow */
940: static double my_modf(double x0, double *iptr)
941: {
942: int i;
1.1.1.2 ! misho 943: LLONG l=0;
1.1 misho 944: double x = x0;
945: double f = 1.0;
946:
947: for (i=0;i<100;i++) {
948: l = (long)x;
1.1.1.2 ! misho 949: if (l <= (x+1) && l >= (x-1)) break;
1.1 misho 950: x *= 0.1;
951: f *= 10.0;
952: }
953:
1.1.1.2 ! misho 954: if (i == 100) {
! 955: /* yikes! the number is beyond what we can handle. What do we do? */
! 956: (*iptr) = 0;
! 957: return 0;
! 958: }
! 959:
! 960: if (i != 0) {
! 961: double i2;
! 962: double ret;
! 963:
! 964: ret = my_modf(x0-l*f, &i2);
! 965: (*iptr) = l*f + i2;
! 966: return ret;
! 967: }
! 968:
! 969: (*iptr) = l;
! 970: return x - (*iptr);
1.1 misho 971: }
972:
973:
974: static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
975: LDOUBLE fvalue, int min, int max, int flags)
976: {
977: int signvalue = 0;
978: double ufvalue;
979: char iconvert[311];
980: char fconvert[311];
981: int iplace = 0;
982: int fplace = 0;
983: int padlen = 0; /* amount to pad */
984: int zpadlen = 0;
985: int caps = 0;
986: int idx;
987: double intpart;
988: double fracpart;
989: double temp;
990:
991: /*
992: * AIX manpage says the default is 0, but Solaris says the default
993: * is 6, and sprintf on AIX defaults to 6
994: */
995: if (max < 0)
996: max = 6;
997:
998: ufvalue = abs_val (fvalue);
999:
1000: if (fvalue < 0) {
1001: signvalue = '-';
1002: } else {
1003: if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
1004: signvalue = '+';
1005: } else {
1006: if (flags & DP_F_SPACE)
1007: signvalue = ' ';
1008: }
1009: }
1010:
1011: #if 0
1012: if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
1013: #endif
1014:
1015: #if 0
1016: if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */
1017: #endif
1018:
1019: /*
1.1.1.2 ! misho 1020: * Sorry, we only support 9 digits past the decimal because of our
1.1 misho 1021: * conversion method
1022: */
1.1.1.2 ! misho 1023: if (max > 9)
! 1024: max = 9;
1.1 misho 1025:
1026: /* We "cheat" by converting the fractional part to integer by
1027: * multiplying by a factor of 10
1028: */
1029:
1030: temp = ufvalue;
1031: my_modf(temp, &intpart);
1032:
1033: fracpart = ROUND((POW10(max)) * (ufvalue - intpart));
1034:
1035: if (fracpart >= POW10(max)) {
1036: intpart++;
1037: fracpart -= POW10(max);
1038: }
1039:
1040:
1041: /* Convert integer part */
1042: do {
1043: temp = intpart*0.1;
1044: my_modf(temp, &intpart);
1045: idx = (int) ((temp -intpart +0.05)* 10.0);
1046: /* idx = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */
1047: /* printf ("%llf, %f, %x\n", temp, intpart, idx); */
1048: iconvert[iplace++] =
1049: (caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
1050: } while (intpart && (iplace < 311));
1051: if (iplace == 311) iplace--;
1052: iconvert[iplace] = 0;
1053:
1054: /* Convert fractional part */
1055: if (fracpart)
1056: {
1057: do {
1058: temp = fracpart*0.1;
1059: my_modf(temp, &fracpart);
1060: idx = (int) ((temp -fracpart +0.05)* 10.0);
1061: /* idx = (int) ((((temp/10) -fracpart) +0.05) *10); */
1062: /* printf ("%lf, %lf, %ld\n", temp, fracpart, idx ); */
1063: fconvert[fplace++] =
1064: (caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
1065: } while(fracpart && (fplace < 311));
1066: if (fplace == 311) fplace--;
1067: }
1068: fconvert[fplace] = 0;
1069:
1070: /* -1 for decimal point, another -1 if we are printing a sign */
1071: padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
1072: zpadlen = max - fplace;
1073: if (zpadlen < 0) zpadlen = 0;
1074: if (padlen < 0)
1075: padlen = 0;
1076: if (flags & DP_F_MINUS)
1077: padlen = -padlen; /* Left Justifty */
1078:
1079: if ((flags & DP_F_ZERO) && (padlen > 0)) {
1080: if (signvalue) {
1081: dopr_outch (buffer, currlen, maxlen, signvalue);
1082: --padlen;
1083: signvalue = 0;
1084: }
1085: while (padlen > 0) {
1086: dopr_outch (buffer, currlen, maxlen, '0');
1087: --padlen;
1088: }
1089: }
1090: while (padlen > 0) {
1091: dopr_outch (buffer, currlen, maxlen, ' ');
1092: --padlen;
1093: }
1094: if (signvalue)
1095: dopr_outch (buffer, currlen, maxlen, signvalue);
1096:
1097: while (iplace > 0)
1098: dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
1099:
1100: #ifdef DEBUG_SNPRINTF
1101: printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
1102: #endif
1103:
1104: /*
1105: * Decimal point. This should probably use locale to find the correct
1106: * char to print out.
1107: */
1108: if (max > 0) {
1109: dopr_outch (buffer, currlen, maxlen, '.');
1110:
1111: while (zpadlen > 0) {
1112: dopr_outch (buffer, currlen, maxlen, '0');
1113: --zpadlen;
1114: }
1115:
1116: while (fplace > 0)
1117: dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
1118: }
1119:
1120: while (padlen < 0) {
1121: dopr_outch (buffer, currlen, maxlen, ' ');
1122: ++padlen;
1123: }
1124: }
1125:
1126: static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
1127: {
1128: if (*currlen < maxlen) {
1129: buffer[(*currlen)] = c;
1130: }
1131: (*currlen)++;
1132: }
1133:
1.1.1.2 ! misho 1134: static struct pr_chunk *new_chunk(void) {
! 1135: struct pr_chunk *new_c = (struct pr_chunk *)malloc(sizeof(struct pr_chunk));
! 1136:
! 1137: if (!new_c)
! 1138: return NULL;
! 1139:
! 1140: new_c->type = 0;
! 1141: new_c->num = 0;
! 1142: new_c->min = 0;
! 1143: new_c->min_star = NULL;
! 1144: new_c->max = -1;
! 1145: new_c->max_star = NULL;
! 1146: new_c->flags = 0;
! 1147: new_c->cflags = 0;
! 1148: new_c->start = 0;
! 1149: new_c->len = 0;
! 1150: new_c->value = 0;
! 1151: new_c->fvalue = 0;
! 1152: new_c->strvalue = NULL;
! 1153: new_c->pnum = NULL;
! 1154: new_c->next = NULL;
! 1155:
! 1156: return new_c;
! 1157: }
! 1158:
! 1159: static int add_cnk_list_entry(struct pr_chunk_x **list,
! 1160: int max_num, struct pr_chunk *chunk) {
! 1161: struct pr_chunk_x *l;
! 1162: struct pr_chunk **c;
! 1163: int max;
! 1164: int cnum;
! 1165: int i, pos;
! 1166:
! 1167: if (chunk->num > max_num) {
! 1168: max = chunk->num;
! 1169:
! 1170: if (*list == NULL) {
! 1171: l = (struct pr_chunk_x *)malloc(sizeof(struct pr_chunk_x) * max);
! 1172: pos = 0;
! 1173: } else {
! 1174: l = (struct pr_chunk_x *)realloc(*list, sizeof(struct pr_chunk_x) * max);
! 1175: pos = max_num;
! 1176: }
! 1177: if (l == NULL) {
! 1178: for (i = 0; i < max; i++) {
! 1179: if ((*list)[i].chunks) free((*list)[i].chunks);
! 1180: }
! 1181: return 0;
! 1182: }
! 1183: for (i = pos; i < max; i++) {
! 1184: l[i].chunks = NULL;
! 1185: l[i].num = 0;
! 1186: }
! 1187: } else {
! 1188: l = *list;
! 1189: max = max_num;
! 1190: }
! 1191:
! 1192: i = chunk->num - 1;
! 1193: cnum = l[i].num + 1;
! 1194: if (l[i].chunks == NULL) {
! 1195: c = (struct pr_chunk **)malloc(sizeof(struct pr_chunk *) * cnum);
! 1196: } else {
! 1197: c = (struct pr_chunk **)realloc(l[i].chunks, sizeof(struct pr_chunk *) * cnum);
! 1198: }
! 1199: if (c == NULL) {
! 1200: for (i = 0; i < max; i++) {
! 1201: if (l[i].chunks) free(l[i].chunks);
! 1202: }
! 1203: return 0;
! 1204: }
! 1205: c[l[i].num] = chunk;
! 1206: l[i].chunks = c;
! 1207: l[i].num = cnum;
! 1208:
! 1209: *list = l;
! 1210: return max;
! 1211: }
! 1212:
1.1 misho 1213: int rsync_vsnprintf (char *str, size_t count, const char *fmt, va_list args)
1214: {
1215: return dopr(str, count, fmt, args);
1216: }
1217: #define vsnprintf rsync_vsnprintf
1218: #endif
1219:
1220: /* yes this really must be a ||. Don't muck with this (tridge)
1221: *
1222: * The logic for these two is that we need our own definition if the
1223: * OS *either* has no definition of *sprintf, or if it does have one
1224: * that doesn't work properly according to the autoconf test.
1225: */
1226: #if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
1227: int rsync_snprintf(char *str,size_t count,const char *fmt,...)
1228: {
1229: size_t ret;
1230: va_list ap;
1231:
1232: va_start(ap, fmt);
1233: ret = vsnprintf(str, count, fmt, ap);
1234: va_end(ap);
1235: return ret;
1236: }
1237: #define snprintf rsync_snprintf
1238: #endif
1239:
1240: #ifndef HAVE_VASPRINTF
1241: int vasprintf(char **ptr, const char *format, va_list ap)
1242: {
1243: int ret;
1244: va_list ap2;
1245:
1246: VA_COPY(ap2, ap);
1247: ret = vsnprintf(NULL, 0, format, ap2);
1.1.1.2 ! misho 1248: va_end(ap2);
! 1249: if (ret < 0) return ret;
1.1 misho 1250:
1251: (*ptr) = (char *)malloc(ret+1);
1252: if (!*ptr) return -1;
1253:
1254: VA_COPY(ap2, ap);
1255: ret = vsnprintf(*ptr, ret+1, format, ap2);
1.1.1.2 ! misho 1256: va_end(ap2);
1.1 misho 1257:
1258: return ret;
1259: }
1260: #endif
1261:
1262:
1263: #ifndef HAVE_ASPRINTF
1264: int asprintf(char **ptr, const char *format, ...)
1265: {
1266: va_list ap;
1267: int ret;
1268:
1269: *ptr = NULL;
1270: va_start(ap, format);
1271: ret = vasprintf(ptr, format, ap);
1272: va_end(ap);
1273:
1274: return ret;
1275: }
1276: #endif
1277:
1278: #ifdef TEST_SNPRINTF
1279:
1280: int sprintf(char *str,const char *fmt,...);
1.1.1.2 ! misho 1281: int printf(const char *fmt,...);
1.1 misho 1282:
1283: int main (void)
1284: {
1285: char buf1[1024];
1286: char buf2[1024];
1.1.1.2 ! misho 1287: char *buf3;
1.1 misho 1288: char *fp_fmt[] = {
1289: "%1.1f",
1290: "%-1.5f",
1291: "%1.5f",
1292: "%123.9f",
1293: "%10.5f",
1294: "% 10.5f",
1295: "%+22.9f",
1296: "%+4.9f",
1297: "%01.3f",
1298: "%4f",
1299: "%3.1f",
1300: "%3.2f",
1301: "%.0f",
1302: "%f",
1.1.1.2 ! misho 1303: "%-8.8f",
! 1304: "%-9.9f",
1.1 misho 1305: NULL
1306: };
1307: double fp_nums[] = { 6442452944.1234, -1.5, 134.21, 91340.2, 341.1234, 203.9, 0.96, 0.996,
1308: 0.9996, 1.996, 4.136, 5.030201, 0.00205,
1309: /* END LIST */ 0};
1310: char *int_fmt[] = {
1311: "%-1.5d",
1312: "%1.5d",
1313: "%123.9d",
1314: "%5.5d",
1315: "%10.5d",
1316: "% 10.5d",
1317: "%+22.33d",
1318: "%01.3d",
1319: "%4d",
1320: "%d",
1321: NULL
1322: };
1.1.1.2 ! misho 1323: long int_nums[] = { -1, 134, 91340, 341, 0203, 1234567890, 0};
1.1 misho 1324: char *str_fmt[] = {
1.1.1.2 ! misho 1325: "%10.5s",
! 1326: "%-10.5s",
! 1327: "%5.10s",
! 1328: "%-5.10s",
! 1329: "%10.1s",
! 1330: "%0.10s",
! 1331: "%10.0s",
! 1332: "%1.10s",
1.1 misho 1333: "%s",
1334: "%.1s",
1335: "%.10s",
1336: "%10s",
1337: NULL
1338: };
1339: char *str_vals[] = {"hello", "a", "", "a longer string", NULL};
1.1.1.2 ! misho 1340: #ifdef HAVE_LONG_LONG
! 1341: char *ll_fmt[] = {
! 1342: "%llu",
! 1343: NULL
! 1344: };
! 1345: LLONG ll_nums[] = { 134, 91340, 341, 0203, 1234567890, 128006186140000000LL, 0};
! 1346: #endif
1.1 misho 1347: int x, y;
1348: int fail = 0;
1349: int num = 0;
1.1.1.2 ! misho 1350: int l1, l2;
! 1351: char *ss_fmt[] = {
! 1352: "%zd",
! 1353: "%zu",
! 1354: NULL
! 1355: };
! 1356: size_t ss_nums[] = {134, 91340, 123456789, 0203, 1234567890, 0};
1.1 misho 1357:
1358: printf ("Testing snprintf format codes against system sprintf...\n");
1359:
1360: for (x = 0; fp_fmt[x] ; x++) {
1361: for (y = 0; fp_nums[y] != 0 ; y++) {
1.1.1.2 ! misho 1362: buf1[0] = buf2[0] = '\0';
! 1363: l1 = snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]);
! 1364: l2 = sprintf (buf2, fp_fmt[x], fp_nums[y]);
! 1365: buf1[1023] = buf2[1023] = '\0';
! 1366: if (strcmp (buf1, buf2) || (l1 != l2)) {
! 1367: printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
! 1368: fp_fmt[x], l1, buf1, l2, buf2);
1.1 misho 1369: fail++;
1370: }
1371: num++;
1372: }
1373: }
1374:
1375: for (x = 0; int_fmt[x] ; x++) {
1376: for (y = 0; int_nums[y] != 0 ; y++) {
1.1.1.2 ! misho 1377: buf1[0] = buf2[0] = '\0';
! 1378: l1 = snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]);
! 1379: l2 = sprintf (buf2, int_fmt[x], int_nums[y]);
! 1380: buf1[1023] = buf2[1023] = '\0';
! 1381: if (strcmp (buf1, buf2) || (l1 != l2)) {
! 1382: printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
! 1383: int_fmt[x], l1, buf1, l2, buf2);
1.1 misho 1384: fail++;
1385: }
1386: num++;
1387: }
1388: }
1389:
1390: for (x = 0; str_fmt[x] ; x++) {
1391: for (y = 0; str_vals[y] != 0 ; y++) {
1.1.1.2 ! misho 1392: buf1[0] = buf2[0] = '\0';
! 1393: l1 = snprintf(buf1, sizeof(buf1), str_fmt[x], str_vals[y]);
! 1394: l2 = sprintf (buf2, str_fmt[x], str_vals[y]);
! 1395: buf1[1023] = buf2[1023] = '\0';
! 1396: if (strcmp (buf1, buf2) || (l1 != l2)) {
! 1397: printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
! 1398: str_fmt[x], l1, buf1, l2, buf2);
1.1 misho 1399: fail++;
1400: }
1.1.1.2 ! misho 1401: num++;
! 1402: }
! 1403: }
! 1404:
! 1405: #ifdef HAVE_LONG_LONG
! 1406: for (x = 0; ll_fmt[x] ; x++) {
! 1407: for (y = 0; ll_nums[y] != 0 ; y++) {
! 1408: buf1[0] = buf2[0] = '\0';
! 1409: l1 = snprintf(buf1, sizeof(buf1), ll_fmt[x], ll_nums[y]);
! 1410: l2 = sprintf (buf2, ll_fmt[x], ll_nums[y]);
! 1411: buf1[1023] = buf2[1023] = '\0';
! 1412: if (strcmp (buf1, buf2) || (l1 != l2)) {
! 1413: printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
! 1414: ll_fmt[x], l1, buf1, l2, buf2);
1.1 misho 1415: fail++;
1416: }
1417: num++;
1418: }
1419: }
1.1.1.2 ! misho 1420: #endif
1.1 misho 1421:
1.1.1.2 ! misho 1422: #define BUFSZ 2048
! 1423:
! 1424: buf1[0] = buf2[0] = '\0';
! 1425: if ((buf3 = malloc(BUFSZ)) == NULL) {
! 1426: fail++;
! 1427: } else {
! 1428: num++;
! 1429: memset(buf3, 'a', BUFSZ);
! 1430: snprintf(buf1, sizeof(buf1), "%.*s", 1, buf3);
! 1431: buf1[1023] = '\0';
! 1432: if (strcmp(buf1, "a") != 0) {
! 1433: printf("length limit buf1 '%s' expected 'a'\n", buf1);
! 1434: fail++;
! 1435: }
! 1436: }
! 1437:
! 1438: buf1[0] = buf2[0] = '\0';
! 1439: l1 = snprintf(buf1, sizeof(buf1), "%4$*1$d %2$s %3$*1$.*1$f", 3, "pos test", 12.3456, 9);
! 1440: l2 = sprintf(buf2, "%4$*1$d %2$s %3$*1$.*1$f", 3, "pos test", 12.3456, 9);
! 1441: buf1[1023] = buf2[1023] = '\0';
! 1442: if (strcmp(buf1, buf2) || (l1 != l2)) {
! 1443: printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
! 1444: "%4$*1$d %2$s %3$*1$.*1$f", l1, buf1, l2, buf2);
! 1445: fail++;
! 1446: }
! 1447:
! 1448: buf1[0] = buf2[0] = '\0';
! 1449: l1 = snprintf(buf1, sizeof(buf1), "%4$*4$d %2$s %3$*4$.*4$f", 3, "pos test", 12.3456, 9);
! 1450: l2 = sprintf(buf2, "%4$*4$d %2$s %3$*4$.*4$f", 3, "pos test", 12.3456, 9);
! 1451: buf1[1023] = buf2[1023] = '\0';
! 1452: if (strcmp(buf1, buf2)) {
! 1453: printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
! 1454: "%4$*1$d %2$s %3$*1$.*1$f", l1, buf1, l2, buf2);
! 1455: fail++;
! 1456: }
! 1457:
! 1458: for (x = 0; ss_fmt[x] ; x++) {
! 1459: for (y = 0; ss_nums[y] != 0 ; y++) {
! 1460: buf1[0] = buf2[0] = '\0';
! 1461: l1 = snprintf(buf1, sizeof(buf1), ss_fmt[x], ss_nums[y]);
! 1462: l2 = sprintf (buf2, ss_fmt[x], ss_nums[y]);
! 1463: buf1[1023] = buf2[1023] = '\0';
! 1464: if (strcmp (buf1, buf2) || (l1 != l2)) {
! 1465: printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
! 1466: ss_fmt[x], l1, buf1, l2, buf2);
! 1467: fail++;
! 1468: }
! 1469: num++;
! 1470: }
! 1471: }
! 1472: #if 0
! 1473: buf1[0] = buf2[0] = '\0';
! 1474: l1 = snprintf(buf1, sizeof(buf1), "%lld", (LLONG)1234567890);
! 1475: l2 = sprintf(buf2, "%lld", (LLONG)1234567890);
! 1476: buf1[1023] = buf2[1023] = '\0';
! 1477: if (strcmp(buf1, buf2)) {
! 1478: printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
! 1479: "%lld", l1, buf1, l2, buf2);
! 1480: fail++;
! 1481: }
! 1482:
! 1483: buf1[0] = buf2[0] = '\0';
! 1484: l1 = snprintf(buf1, sizeof(buf1), "%Lf", (LDOUBLE)890.1234567890123);
! 1485: l2 = sprintf(buf2, "%Lf", (LDOUBLE)890.1234567890123);
! 1486: buf1[1023] = buf2[1023] = '\0';
! 1487: if (strcmp(buf1, buf2)) {
! 1488: printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
! 1489: "%Lf", l1, buf1, l2, buf2);
! 1490: fail++;
! 1491: }
! 1492: #endif
1.1 misho 1493: printf ("%d tests failed out of %d.\n", fail, num);
1494:
1495: printf("seeing how many digits we support\n");
1496: {
1497: double v0 = 0.12345678901234567890123456789012345678901;
1498: for (x=0; x<100; x++) {
1499: double p = pow(10, x);
1500: double r = v0*p;
1501: snprintf(buf1, sizeof(buf1), "%1.1f", r);
1502: sprintf(buf2, "%1.1f", r);
1503: if (strcmp(buf1, buf2)) {
1504: printf("we seem to support %d digits\n", x-1);
1505: break;
1506: }
1507: }
1508: }
1509:
1510: return 0;
1511: }
1512: #endif /* TEST_SNPRINTF */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>