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