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