bio/b_print.c: recognize even 'j' format modifier.
[openssl.git] / crypto / bio / b_print.c
1 /*
2  * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the OpenSSL license (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9
10 #include <stdio.h>
11 #include <string.h>
12 #include <ctype.h>
13 #include "internal/numbers.h"
14 #include "internal/cryptlib.h"
15 #ifndef NO_SYS_TYPES_H
16 # include <sys/types.h>
17 #endif
18 #include <openssl/bn.h>         /* To get BN_LLONG properly defined */
19 #include <openssl/bio.h>
20
21 #if defined(BN_LLONG) || defined(SIXTY_FOUR_BIT)
22 # ifndef HAVE_LONG_LONG
23 #  define HAVE_LONG_LONG 1
24 # endif
25 #endif
26
27 /*
28  * Copyright Patrick Powell 1995
29  * This code is based on code written by Patrick Powell <papowell@astart.com>
30  * It may be used for any purpose as long as this notice remains intact
31  * on all source code distributions.
32  */
33
34 #ifdef HAVE_LONG_DOUBLE
35 # define LDOUBLE long double
36 #else
37 # define LDOUBLE double
38 #endif
39
40 #ifdef HAVE_LONG_LONG
41 # if defined(_WIN32) && !defined(__GNUC__)
42 #  define LLONG __int64
43 # else
44 #  define LLONG long long
45 # endif
46 #else
47 # define LLONG long
48 #endif
49
50 static int fmtstr(char **, char **, size_t *, size_t *,
51                   const char *, int, int, int);
52 static int fmtint(char **, char **, size_t *, size_t *,
53                   LLONG, int, int, int, int);
54 static int fmtfp(char **, char **, size_t *, size_t *,
55                  LDOUBLE, int, int, int, int);
56 static int doapr_outch(char **, char **, size_t *, size_t *, int);
57 static int _dopr(char **sbuffer, char **buffer,
58                  size_t *maxlen, size_t *retlen, int *truncated,
59                  const char *format, va_list args);
60
61 /* format read states */
62 #define DP_S_DEFAULT    0
63 #define DP_S_FLAGS      1
64 #define DP_S_MIN        2
65 #define DP_S_DOT        3
66 #define DP_S_MAX        4
67 #define DP_S_MOD        5
68 #define DP_S_CONV       6
69 #define DP_S_DONE       7
70
71 /* format flags - Bits */
72 /* left-aligned padding */
73 #define DP_F_MINUS      (1 << 0)
74 /* print an explicit '+' for a value with positive sign */
75 #define DP_F_PLUS       (1 << 1)
76 /* print an explicit ' ' for a value with positive sign */
77 #define DP_F_SPACE      (1 << 2)
78 /* print 0/0x prefix for octal/hex and decimal point for floating point */
79 #define DP_F_NUM        (1 << 3)
80 /* print leading zeroes */
81 #define DP_F_ZERO       (1 << 4)
82 /* print HEX in UPPPERcase */
83 #define DP_F_UP         (1 << 5)
84 /* treat value as unsigned */
85 #define DP_F_UNSIGNED   (1 << 6)
86
87 /* conversion flags */
88 #define DP_C_SHORT      1
89 #define DP_C_LONG       2
90 #define DP_C_LDOUBLE    3
91 #define DP_C_LLONG      4
92 #define DP_C_SIZE       5
93
94 /* Floating point formats */
95 #define F_FORMAT        0
96 #define E_FORMAT        1
97 #define G_FORMAT        2
98
99 /* some handy macros */
100 #define char_to_int(p) (p - '0')
101 #define OSSL_MAX(p,q) ((p >= q) ? p : q)
102
103 static int
104 _dopr(char **sbuffer,
105       char **buffer,
106       size_t *maxlen,
107       size_t *retlen, int *truncated, const char *format, va_list args)
108 {
109     char ch;
110     LLONG value;
111     LDOUBLE fvalue;
112     char *strvalue;
113     int min;
114     int max;
115     int state;
116     int flags;
117     int cflags;
118     size_t currlen;
119
120     state = DP_S_DEFAULT;
121     flags = currlen = cflags = min = 0;
122     max = -1;
123     ch = *format++;
124
125     while (state != DP_S_DONE) {
126         if (ch == '\0' || (buffer == NULL && currlen >= *maxlen))
127             state = DP_S_DONE;
128
129         switch (state) {
130         case DP_S_DEFAULT:
131             if (ch == '%')
132                 state = DP_S_FLAGS;
133             else
134                 if(!doapr_outch(sbuffer, buffer, &currlen, maxlen, ch))
135                     return 0;
136             ch = *format++;
137             break;
138         case DP_S_FLAGS:
139             switch (ch) {
140             case '-':
141                 flags |= DP_F_MINUS;
142                 ch = *format++;
143                 break;
144             case '+':
145                 flags |= DP_F_PLUS;
146                 ch = *format++;
147                 break;
148             case ' ':
149                 flags |= DP_F_SPACE;
150                 ch = *format++;
151                 break;
152             case '#':
153                 flags |= DP_F_NUM;
154                 ch = *format++;
155                 break;
156             case '0':
157                 flags |= DP_F_ZERO;
158                 ch = *format++;
159                 break;
160             default:
161                 state = DP_S_MIN;
162                 break;
163             }
164             break;
165         case DP_S_MIN:
166             if (isdigit((unsigned char)ch)) {
167                 min = 10 * min + char_to_int(ch);
168                 ch = *format++;
169             } else if (ch == '*') {
170                 min = va_arg(args, int);
171                 ch = *format++;
172                 state = DP_S_DOT;
173             } else
174                 state = DP_S_DOT;
175             break;
176         case DP_S_DOT:
177             if (ch == '.') {
178                 state = DP_S_MAX;
179                 ch = *format++;
180             } else
181                 state = DP_S_MOD;
182             break;
183         case DP_S_MAX:
184             if (isdigit((unsigned char)ch)) {
185                 if (max < 0)
186                     max = 0;
187                 max = 10 * max + char_to_int(ch);
188                 ch = *format++;
189             } else if (ch == '*') {
190                 max = va_arg(args, int);
191                 ch = *format++;
192                 state = DP_S_MOD;
193             } else
194                 state = DP_S_MOD;
195             break;
196         case DP_S_MOD:
197             switch (ch) {
198             case 'h':
199                 cflags = DP_C_SHORT;
200                 ch = *format++;
201                 break;
202             case 'l':
203                 if (*format == 'l') {
204                     cflags = DP_C_LLONG;
205                     format++;
206                 } else
207                     cflags = DP_C_LONG;
208                 ch = *format++;
209                 break;
210             case 'q':
211             case 'j':
212                 cflags = DP_C_LLONG;
213                 ch = *format++;
214                 break;
215             case 'L':
216                 cflags = DP_C_LDOUBLE;
217                 ch = *format++;
218                 break;
219             case 'z':
220                 cflags = DP_C_SIZE;
221                 ch = *format++;
222                 break;
223             default:
224                 break;
225             }
226             state = DP_S_CONV;
227             break;
228         case DP_S_CONV:
229             switch (ch) {
230             case 'd':
231             case 'i':
232                 switch (cflags) {
233                 case DP_C_SHORT:
234                     value = (short int)va_arg(args, int);
235                     break;
236                 case DP_C_LONG:
237                     value = va_arg(args, long int);
238                     break;
239                 case DP_C_LLONG:
240                     value = va_arg(args, LLONG);
241                     break;
242                 case DP_C_SIZE:
243                     value = va_arg(args, ossl_ssize_t);
244                     break;
245                 default:
246                     value = va_arg(args, int);
247                     break;
248                 }
249                 if (!fmtint(sbuffer, buffer, &currlen, maxlen, value, 10, min,
250                             max, flags))
251                     return 0;
252                 break;
253             case 'X':
254                 flags |= DP_F_UP;
255                 /* FALLTHROUGH */
256             case 'x':
257             case 'o':
258             case 'u':
259                 flags |= DP_F_UNSIGNED;
260                 switch (cflags) {
261                 case DP_C_SHORT:
262                     value = (unsigned short int)va_arg(args, unsigned int);
263                     break;
264                 case DP_C_LONG:
265                     value = (LLONG)va_arg(args, unsigned long int);
266                     break;
267                 case DP_C_LLONG:
268                     value = va_arg(args, unsigned LLONG);
269                     break;
270                 case DP_C_SIZE:
271                     value = va_arg(args, size_t);
272                     break;
273                 default:
274                     value = (LLONG)va_arg(args, unsigned int);
275                     break;
276                 }
277                 if (!fmtint(sbuffer, buffer, &currlen, maxlen, value,
278                             ch == 'o' ? 8 : (ch == 'u' ? 10 : 16),
279                             min, max, flags))
280                     return 0;
281                 break;
282             case 'f':
283                 if (cflags == DP_C_LDOUBLE)
284                     fvalue = va_arg(args, LDOUBLE);
285                 else
286                     fvalue = va_arg(args, double);
287                 if (!fmtfp(sbuffer, buffer, &currlen, maxlen, fvalue, min, max,
288                            flags, F_FORMAT))
289                     return 0;
290                 break;
291             case 'E':
292                 flags |= DP_F_UP;
293             case 'e':
294                 if (cflags == DP_C_LDOUBLE)
295                     fvalue = va_arg(args, LDOUBLE);
296                 else
297                     fvalue = va_arg(args, double);
298                 if (!fmtfp(sbuffer, buffer, &currlen, maxlen, fvalue, min, max,
299                            flags, E_FORMAT))
300                     return 0;
301                 break;
302             case 'G':
303                 flags |= DP_F_UP;
304             case 'g':
305                 if (cflags == DP_C_LDOUBLE)
306                     fvalue = va_arg(args, LDOUBLE);
307                 else
308                     fvalue = va_arg(args, double);
309                 if (!fmtfp(sbuffer, buffer, &currlen, maxlen, fvalue, min, max,
310                            flags, G_FORMAT))
311                     return 0;
312                 break;
313             case 'c':
314                 if(!doapr_outch(sbuffer, buffer, &currlen, maxlen,
315                             va_arg(args, int)))
316                     return 0;
317                 break;
318             case 's':
319                 strvalue = va_arg(args, char *);
320                 if (max < 0) {
321                     if (buffer)
322                         max = INT_MAX;
323                     else
324                         max = *maxlen;
325                 }
326                 if (!fmtstr(sbuffer, buffer, &currlen, maxlen, strvalue,
327                             flags, min, max))
328                     return 0;
329                 break;
330             case 'p':
331                 value = (size_t)va_arg(args, void *);
332                 if (!fmtint(sbuffer, buffer, &currlen, maxlen,
333                             value, 16, min, max, flags | DP_F_NUM))
334                     return 0;
335                 break;
336             case 'n':          /* XXX */
337                 if (cflags == DP_C_SHORT) {
338                     short int *num;
339                     num = va_arg(args, short int *);
340                     *num = currlen;
341                 } else if (cflags == DP_C_LONG) { /* XXX */
342                     long int *num;
343                     num = va_arg(args, long int *);
344                     *num = (long int)currlen;
345                 } else if (cflags == DP_C_LLONG) { /* XXX */
346                     LLONG *num;
347                     num = va_arg(args, LLONG *);
348                     *num = (LLONG) currlen;
349                 } else {
350                     int *num;
351                     num = va_arg(args, int *);
352                     *num = currlen;
353                 }
354                 break;
355             case '%':
356                 if(!doapr_outch(sbuffer, buffer, &currlen, maxlen, ch))
357                     return 0;
358                 break;
359             case 'w':
360                 /* not supported yet, treat as next char */
361                 ch = *format++;
362                 break;
363             default:
364                 /* unknown, skip */
365                 break;
366             }
367             ch = *format++;
368             state = DP_S_DEFAULT;
369             flags = cflags = min = 0;
370             max = -1;
371             break;
372         case DP_S_DONE:
373             break;
374         default:
375             break;
376         }
377     }
378     /*
379      * We have to truncate if there is no dynamic buffer and we have filled the
380      * static buffer.
381      */
382     if (buffer == NULL) {
383         *truncated = (currlen > *maxlen - 1);
384         if (*truncated)
385             currlen = *maxlen - 1;
386     }
387     if(!doapr_outch(sbuffer, buffer, &currlen, maxlen, '\0'))
388         return 0;
389     *retlen = currlen - 1;
390     return 1;
391 }
392
393 static int
394 fmtstr(char **sbuffer,
395        char **buffer,
396        size_t *currlen,
397        size_t *maxlen, const char *value, int flags, int min, int max)
398 {
399     int padlen;
400     size_t strln;
401     int cnt = 0;
402
403     if (value == 0)
404         value = "<NULL>";
405
406     strln = OPENSSL_strnlen(value, max < 0 ? SIZE_MAX : (size_t)max);
407
408     padlen = min - strln;
409     if (min < 0 || padlen < 0)
410         padlen = 0;
411     if (max >= 0) {
412         /*
413          * Calculate the maximum output including padding.
414          * Make sure max doesn't overflow into negativity
415          */
416         if (max < INT_MAX - padlen)
417             max += padlen;
418         else
419             max = INT_MAX;
420     }
421     if (flags & DP_F_MINUS)
422         padlen = -padlen;
423
424     while ((padlen > 0) && (max < 0 || cnt < max)) {
425         if(!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
426             return 0;
427         --padlen;
428         ++cnt;
429     }
430     while (strln > 0 && (max < 0 || cnt < max)) {
431         if(!doapr_outch(sbuffer, buffer, currlen, maxlen, *value++))
432             return 0;
433         --strln;
434         ++cnt;
435     }
436     while ((padlen < 0) && (max < 0 || cnt < max)) {
437         if(!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
438             return 0;
439         ++padlen;
440         ++cnt;
441     }
442     return 1;
443 }
444
445 static int
446 fmtint(char **sbuffer,
447        char **buffer,
448        size_t *currlen,
449        size_t *maxlen, LLONG value, int base, int min, int max, int flags)
450 {
451     int signvalue = 0;
452     const char *prefix = "";
453     unsigned LLONG uvalue;
454     char convert[DECIMAL_SIZE(value) + 3];
455     int place = 0;
456     int spadlen = 0;
457     int zpadlen = 0;
458     int caps = 0;
459
460     if (max < 0)
461         max = 0;
462     uvalue = value;
463     if (!(flags & DP_F_UNSIGNED)) {
464         if (value < 0) {
465             signvalue = '-';
466             uvalue = 0 - (unsigned LLONG)value;
467         } else if (flags & DP_F_PLUS)
468             signvalue = '+';
469         else if (flags & DP_F_SPACE)
470             signvalue = ' ';
471     }
472     if (flags & DP_F_NUM) {
473         if (base == 8)
474             prefix = "0";
475         if (base == 16)
476             prefix = "0x";
477     }
478     if (flags & DP_F_UP)
479         caps = 1;
480     do {
481         convert[place++] = (caps ? "0123456789ABCDEF" : "0123456789abcdef")
482             [uvalue % (unsigned)base];
483         uvalue = (uvalue / (unsigned)base);
484     } while (uvalue && (place < (int)sizeof(convert)));
485     if (place == sizeof(convert))
486         place--;
487     convert[place] = 0;
488
489     zpadlen = max - place;
490     spadlen =
491         min - OSSL_MAX(max, place) - (signvalue ? 1 : 0) - strlen(prefix);
492     if (zpadlen < 0)
493         zpadlen = 0;
494     if (spadlen < 0)
495         spadlen = 0;
496     if (flags & DP_F_ZERO) {
497         zpadlen = OSSL_MAX(zpadlen, spadlen);
498         spadlen = 0;
499     }
500     if (flags & DP_F_MINUS)
501         spadlen = -spadlen;
502
503     /* spaces */
504     while (spadlen > 0) {
505         if(!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
506             return 0;
507         --spadlen;
508     }
509
510     /* sign */
511     if (signvalue)
512         if(!doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue))
513             return 0;
514
515     /* prefix */
516     while (*prefix) {
517         if(!doapr_outch(sbuffer, buffer, currlen, maxlen, *prefix))
518             return 0;
519         prefix++;
520     }
521
522     /* zeros */
523     if (zpadlen > 0) {
524         while (zpadlen > 0) {
525             if(!doapr_outch(sbuffer, buffer, currlen, maxlen, '0'))
526                 return 0;
527             --zpadlen;
528         }
529     }
530     /* digits */
531     while (place > 0) {
532         if (!doapr_outch(sbuffer, buffer, currlen, maxlen, convert[--place]))
533             return 0;
534     }
535
536     /* left justified spaces */
537     while (spadlen < 0) {
538         if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
539             return 0;
540         ++spadlen;
541     }
542     return 1;
543 }
544
545 static LDOUBLE abs_val(LDOUBLE value)
546 {
547     LDOUBLE result = value;
548     if (value < 0)
549         result = -value;
550     return result;
551 }
552
553 static LDOUBLE pow_10(int in_exp)
554 {
555     LDOUBLE result = 1;
556     while (in_exp) {
557         result *= 10;
558         in_exp--;
559     }
560     return result;
561 }
562
563 static long roundv(LDOUBLE value)
564 {
565     long intpart;
566     intpart = (long)value;
567     value = value - intpart;
568     if (value >= 0.5)
569         intpart++;
570     return intpart;
571 }
572
573 static int
574 fmtfp(char **sbuffer,
575       char **buffer,
576       size_t *currlen,
577       size_t *maxlen, LDOUBLE fvalue, int min, int max, int flags, int style)
578 {
579     int signvalue = 0;
580     LDOUBLE ufvalue;
581     LDOUBLE tmpvalue;
582     char iconvert[20];
583     char fconvert[20];
584     char econvert[20];
585     int iplace = 0;
586     int fplace = 0;
587     int eplace = 0;
588     int padlen = 0;
589     int zpadlen = 0;
590     long exp = 0;
591     unsigned long intpart;
592     unsigned long fracpart;
593     unsigned long max10;
594     int realstyle;
595
596     if (max < 0)
597         max = 6;
598
599     if (fvalue < 0)
600         signvalue = '-';
601     else if (flags & DP_F_PLUS)
602         signvalue = '+';
603     else if (flags & DP_F_SPACE)
604         signvalue = ' ';
605
606     /*
607      * G_FORMAT sometimes prints like E_FORMAT and sometimes like F_FORMAT
608      * depending on the number to be printed. Work out which one it is and use
609      * that from here on.
610      */
611     if (style == G_FORMAT) {
612         if (fvalue == 0.0) {
613             realstyle = F_FORMAT;
614         } else if (fvalue < 0.0001) {
615             realstyle = E_FORMAT;
616         } else if ((max == 0 && fvalue >= 10)
617                     || (max > 0 && fvalue >= pow_10(max))) {
618             realstyle = E_FORMAT;
619         } else {
620             realstyle = F_FORMAT;
621         }
622     } else {
623         realstyle = style;
624     }
625
626     if (style != F_FORMAT) {
627         tmpvalue = fvalue;
628         /* Calculate the exponent */
629         if (fvalue != 0.0) {
630             while (tmpvalue < 1) {
631                 tmpvalue *= 10;
632                 exp--;
633             }
634             while (tmpvalue > 10) {
635                 tmpvalue /= 10;
636                 exp++;
637             }
638         }
639         if (style == G_FORMAT) {
640             /*
641              * In G_FORMAT the "precision" represents significant digits. We
642              * always have at least 1 significant digit.
643              */
644             if (max == 0)
645                 max = 1;
646             /* Now convert significant digits to decimal places */
647             if (realstyle == F_FORMAT) {
648                 max -= (exp + 1);
649                 if (max < 0) {
650                     /*
651                      * Should not happen. If we're in F_FORMAT then exp < max?
652                      */
653                     return 0;
654                 }
655             } else {
656                 /*
657                  * In E_FORMAT there is always one significant digit in front
658                  * of the decimal point, so:
659                  * significant digits == 1 + decimal places
660                  */
661                 max--;
662             }
663         }
664         if (realstyle == E_FORMAT)
665             fvalue = tmpvalue;
666     }
667     ufvalue = abs_val(fvalue);
668     if (ufvalue > ULONG_MAX) {
669         /* Number too big */
670         return 0;
671     }
672     intpart = (unsigned long)ufvalue;
673
674     /*
675      * sorry, we only support 9 digits past the decimal because of our
676      * conversion method
677      */
678     if (max > 9)
679         max = 9;
680
681     /*
682      * we "cheat" by converting the fractional part to integer by multiplying
683      * by a factor of 10
684      */
685     max10 = roundv(pow_10(max));
686     fracpart = roundv(pow_10(max) * (ufvalue - intpart));
687
688     if (fracpart >= max10) {
689         intpart++;
690         fracpart -= max10;
691     }
692
693     /* convert integer part */
694     do {
695         iconvert[iplace++] = "0123456789"[intpart % 10];
696         intpart = (intpart / 10);
697     } while (intpart && (iplace < (int)sizeof(iconvert)));
698     if (iplace == sizeof iconvert)
699         iplace--;
700     iconvert[iplace] = 0;
701
702     /* convert fractional part */
703     while (fplace < max) {
704         if (style == G_FORMAT && fplace == 0 && (fracpart % 10) == 0) {
705             /* We strip trailing zeros in G_FORMAT */
706             max--;
707             fracpart = fracpart / 10;
708             if (fplace < max)
709                 continue;
710             break;
711         }
712         fconvert[fplace++] = "0123456789"[fracpart % 10];
713         fracpart = (fracpart / 10);
714     }
715
716     if (fplace == sizeof fconvert)
717         fplace--;
718     fconvert[fplace] = 0;
719
720     /* convert exponent part */
721     if (realstyle == E_FORMAT) {
722         int tmpexp;
723         if (exp < 0)
724             tmpexp = -exp;
725         else
726             tmpexp = exp;
727
728         do {
729             econvert[eplace++] = "0123456789"[tmpexp % 10];
730             tmpexp = (tmpexp / 10);
731         } while (tmpexp > 0 && eplace < (int)sizeof(econvert));
732         /* Exponent is huge!! Too big to print */
733         if (tmpexp > 0)
734             return 0;
735         /* Add a leading 0 for single digit exponents */
736         if (eplace == 1)
737             econvert[eplace++] = '0';
738     }
739
740     /*
741      * -1 for decimal point (if we have one, i.e. max > 0),
742      * another -1 if we are printing a sign
743      */
744     padlen = min - iplace - max - (max > 0 ? 1 : 0) - ((signvalue) ? 1 : 0);
745     /* Take some off for exponent prefix "+e" and exponent */
746     if (realstyle == E_FORMAT)
747         padlen -= 2 + eplace;
748     zpadlen = max - fplace;
749     if (zpadlen < 0)
750         zpadlen = 0;
751     if (padlen < 0)
752         padlen = 0;
753     if (flags & DP_F_MINUS)
754         padlen = -padlen;
755
756     if ((flags & DP_F_ZERO) && (padlen > 0)) {
757         if (signvalue) {
758             if (!doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue))
759                 return 0;
760             --padlen;
761             signvalue = 0;
762         }
763         while (padlen > 0) {
764             if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '0'))
765                 return 0;
766             --padlen;
767         }
768     }
769     while (padlen > 0) {
770         if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
771             return 0;
772         --padlen;
773     }
774     if (signvalue && !doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue))
775         return 0;
776
777     while (iplace > 0) {
778         if (!doapr_outch(sbuffer, buffer, currlen, maxlen, iconvert[--iplace]))
779             return 0;
780     }
781
782     /*
783      * Decimal point. This should probably use locale to find the correct
784      * char to print out.
785      */
786     if (max > 0 || (flags & DP_F_NUM)) {
787         if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '.'))
788             return 0;
789
790         while (fplace > 0) {
791             if(!doapr_outch(sbuffer, buffer, currlen, maxlen,
792                             fconvert[--fplace]))
793                 return 0;
794         }
795     }
796     while (zpadlen > 0) {
797         if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '0'))
798             return 0;
799         --zpadlen;
800     }
801     if (realstyle == E_FORMAT) {
802         char ech;
803
804         if ((flags & DP_F_UP) == 0)
805             ech = 'e';
806         else
807             ech = 'E';
808         if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ech))
809                 return 0;
810         if (exp < 0) {
811             if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '-'))
812                     return 0;
813         } else {
814             if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '+'))
815                     return 0;
816         }
817         while (eplace > 0) {
818             if (!doapr_outch(sbuffer, buffer, currlen, maxlen,
819                              econvert[--eplace]))
820                 return 0;
821         }
822     }
823
824     while (padlen < 0) {
825         if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
826             return 0;
827         ++padlen;
828     }
829     return 1;
830 }
831
832 #define BUFFER_INC  1024
833
834 static int
835 doapr_outch(char **sbuffer,
836             char **buffer, size_t *currlen, size_t *maxlen, int c)
837 {
838     /* If we haven't at least one buffer, someone has doe a big booboo */
839     OPENSSL_assert(*sbuffer != NULL || buffer != NULL);
840
841     /* |currlen| must always be <= |*maxlen| */
842     OPENSSL_assert(*currlen <= *maxlen);
843
844     if (buffer && *currlen == *maxlen) {
845         if (*maxlen > INT_MAX - BUFFER_INC)
846             return 0;
847
848         *maxlen += BUFFER_INC;
849         if (*buffer == NULL) {
850             *buffer = OPENSSL_malloc(*maxlen);
851             if (*buffer == NULL)
852                 return 0;
853             if (*currlen > 0) {
854                 OPENSSL_assert(*sbuffer != NULL);
855                 memcpy(*buffer, *sbuffer, *currlen);
856             }
857             *sbuffer = NULL;
858         } else {
859             char *tmpbuf;
860             tmpbuf = OPENSSL_realloc(*buffer, *maxlen);
861             if (tmpbuf == NULL)
862                 return 0;
863             *buffer = tmpbuf;
864         }
865     }
866
867     if (*currlen < *maxlen) {
868         if (*sbuffer)
869             (*sbuffer)[(*currlen)++] = (char)c;
870         else
871             (*buffer)[(*currlen)++] = (char)c;
872     }
873
874     return 1;
875 }
876
877 /***************************************************************************/
878
879 int BIO_printf(BIO *bio, const char *format, ...)
880 {
881     va_list args;
882     int ret;
883
884     va_start(args, format);
885
886     ret = BIO_vprintf(bio, format, args);
887
888     va_end(args);
889     return (ret);
890 }
891
892 int BIO_vprintf(BIO *bio, const char *format, va_list args)
893 {
894     int ret;
895     size_t retlen;
896     char hugebuf[1024 * 2];     /* Was previously 10k, which is unreasonable
897                                  * in small-stack environments, like threads
898                                  * or DOS programs. */
899     char *hugebufp = hugebuf;
900     size_t hugebufsize = sizeof(hugebuf);
901     char *dynbuf = NULL;
902     int ignored;
903
904     dynbuf = NULL;
905     if (!_dopr(&hugebufp, &dynbuf, &hugebufsize, &retlen, &ignored, format,
906                 args)) {
907         OPENSSL_free(dynbuf);
908         return -1;
909     }
910     if (dynbuf) {
911         ret = BIO_write(bio, dynbuf, (int)retlen);
912         OPENSSL_free(dynbuf);
913     } else {
914         ret = BIO_write(bio, hugebuf, (int)retlen);
915     }
916     return (ret);
917 }
918
919 /*
920  * As snprintf is not available everywhere, we provide our own
921  * implementation. This function has nothing to do with BIOs, but it's
922  * closely related to BIO_printf, and we need *some* name prefix ... (XXX the
923  * function should be renamed, but to what?)
924  */
925 int BIO_snprintf(char *buf, size_t n, const char *format, ...)
926 {
927     va_list args;
928     int ret;
929
930     va_start(args, format);
931
932     ret = BIO_vsnprintf(buf, n, format, args);
933
934     va_end(args);
935     return (ret);
936 }
937
938 int BIO_vsnprintf(char *buf, size_t n, const char *format, va_list args)
939 {
940     size_t retlen;
941     int truncated;
942
943     if(!_dopr(&buf, NULL, &n, &retlen, &truncated, format, args))
944         return -1;
945
946     if (truncated)
947         /*
948          * In case of truncation, return -1 like traditional snprintf.
949          * (Current drafts for ISO/IEC 9899 say snprintf should return the
950          * number of characters that would have been written, had the buffer
951          * been large enough.)
952          */
953         return -1;
954     else
955         return (retlen <= INT_MAX) ? (int)retlen : -1;
956 }