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