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