Fix EBCDIC problem in conf_def.h
[openssl.git] / crypto / bio / b_print.c
1 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
2  * All rights reserved.
3  *
4  * This package is an SSL implementation written
5  * by Eric Young (eay@cryptsoft.com).
6  * The implementation was written so as to conform with Netscapes SSL.
7  *
8  * This library is free for commercial and non-commercial use as long as
9  * the following conditions are aheared to.  The following conditions
10  * apply to all code found in this distribution, be it the RC4, RSA,
11  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
12  * included with this distribution is covered by the same copyright terms
13  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
14  *
15  * Copyright remains Eric Young's, and as such any Copyright notices in
16  * the code are not to be removed.
17  * If this package is used in a product, Eric Young should be given attribution
18  * as the author of the parts of the library used.
19  * This can be in the form of a textual message at program startup or
20  * in documentation (online or textual) provided with the package.
21  *
22  * Redistribution and use in source and binary forms, with or without
23  * modification, are permitted provided that the following conditions
24  * are met:
25  * 1. Redistributions of source code must retain the copyright
26  *    notice, this list of conditions and the following disclaimer.
27  * 2. Redistributions in binary form must reproduce the above copyright
28  *    notice, this list of conditions and the following disclaimer in the
29  *    documentation and/or other materials provided with the distribution.
30  * 3. All advertising materials mentioning features or use of this software
31  *    must display the following acknowledgement:
32  *    "This product includes cryptographic software written by
33  *     Eric Young (eay@cryptsoft.com)"
34  *    The word 'cryptographic' can be left out if the rouines from the library
35  *    being used are not cryptographic related :-).
36  * 4. If you include any Windows specific code (or a derivative thereof) from
37  *    the apps directory (application code) you must include an acknowledgement:
38  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
39  *
40  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
41  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
44  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50  * SUCH DAMAGE.
51  *
52  * The licence and distribution terms for any publically available version or
53  * derivative of this code cannot be changed.  i.e. this code cannot simply be
54  * copied and put under another distribution licence
55  * [including the GNU Public Licence.]
56  */
57
58 /*
59  * Stolen from tjh's ssl/ssl_trc.c stuff.
60  */
61
62 #include <stdio.h>
63 #include <string.h>
64 #include <ctype.h>
65 #include <assert.h>
66 #include <limits.h>
67 #include "internal/cryptlib.h"
68 #ifndef NO_SYS_TYPES_H
69 # include <sys/types.h>
70 #endif
71 #include <openssl/bn.h>         /* To get BN_LLONG properly defined */
72 #include <openssl/bio.h>
73
74 #if defined(BN_LLONG) || defined(SIXTY_FOUR_BIT)
75 # ifndef HAVE_LONG_LONG
76 #  define HAVE_LONG_LONG 1
77 # endif
78 #endif
79
80 /***************************************************************************/
81
82 /*
83  * Copyright Patrick Powell 1995
84  * This code is based on code written by Patrick Powell <papowell@astart.com>
85  * It may be used for any purpose as long as this notice remains intact
86  * on all source code distributions.
87  */
88
89 /*-
90  * This code contains numerious changes and enhancements which were
91  * made by lots of contributors over the last years to Patrick Powell's
92  * original code:
93  *
94  * o Patrick Powell <papowell@astart.com>      (1995)
95  * o Brandon Long <blong@fiction.net>          (1996, for Mutt)
96  * o Thomas Roessler <roessler@guug.de>        (1998, for Mutt)
97  * o Michael Elkins <me@cs.hmc.edu>            (1998, for Mutt)
98  * o Andrew Tridgell <tridge@samba.org>        (1998, for Samba)
99  * o Luke Mewburn <lukem@netbsd.org>           (1999, for LukemFTP)
100  * o Ralf S. Engelschall <rse@engelschall.com> (1999, for Pth)
101  * o ...                                       (for OpenSSL)
102  */
103
104 #ifdef HAVE_LONG_DOUBLE
105 # define LDOUBLE long double
106 #else
107 # define LDOUBLE double
108 #endif
109
110 #ifdef HAVE_LONG_LONG
111 # if defined(_WIN32) && !defined(__GNUC__)
112 #  define LLONG __int64
113 # else
114 #  define LLONG long long
115 # endif
116 #else
117 # define LLONG long
118 #endif
119
120 static int fmtstr(char **, char **, size_t *, size_t *,
121                   const char *, int, int, int);
122 static int fmtint(char **, char **, size_t *, size_t *,
123                   LLONG, int, int, int, int);
124 static int fmtfp(char **, char **, size_t *, size_t *,
125                  LDOUBLE, int, int, int);
126 static int doapr_outch(char **, char **, size_t *, size_t *, int);
127 static int _dopr(char **sbuffer, char **buffer,
128                  size_t *maxlen, size_t *retlen, int *truncated,
129                  const char *format, va_list args);
130
131 /* format read states */
132 #define DP_S_DEFAULT    0
133 #define DP_S_FLAGS      1
134 #define DP_S_MIN        2
135 #define DP_S_DOT        3
136 #define DP_S_MAX        4
137 #define DP_S_MOD        5
138 #define DP_S_CONV       6
139 #define DP_S_DONE       7
140
141 /* format flags - Bits */
142 #define DP_F_MINUS      (1 << 0)
143 #define DP_F_PLUS       (1 << 1)
144 #define DP_F_SPACE      (1 << 2)
145 #define DP_F_NUM        (1 << 3)
146 #define DP_F_ZERO       (1 << 4)
147 #define DP_F_UP         (1 << 5)
148 #define DP_F_UNSIGNED   (1 << 6)
149
150 /* conversion flags */
151 #define DP_C_SHORT      1
152 #define DP_C_LONG       2
153 #define DP_C_LDOUBLE    3
154 #define DP_C_LLONG      4
155
156 /* some handy macros */
157 #define char_to_int(p) (p - '0')
158 #define OSSL_MAX(p,q) ((p >= q) ? p : q)
159
160 static int
161 _dopr(char **sbuffer,
162       char **buffer,
163       size_t *maxlen,
164       size_t *retlen, int *truncated, const char *format, va_list args)
165 {
166     char ch;
167     LLONG value;
168     LDOUBLE fvalue;
169     char *strvalue;
170     int min;
171     int max;
172     int state;
173     int flags;
174     int cflags;
175     size_t currlen;
176
177     state = DP_S_DEFAULT;
178     flags = currlen = cflags = min = 0;
179     max = -1;
180     ch = *format++;
181
182     while (state != DP_S_DONE) {
183         if (ch == '\0' || (buffer == NULL && currlen >= *maxlen))
184             state = DP_S_DONE;
185
186         switch (state) {
187         case DP_S_DEFAULT:
188             if (ch == '%')
189                 state = DP_S_FLAGS;
190             else
191                 if(!doapr_outch(sbuffer, buffer, &currlen, maxlen, ch))
192                     return 0;
193             ch = *format++;
194             break;
195         case DP_S_FLAGS:
196             switch (ch) {
197             case '-':
198                 flags |= DP_F_MINUS;
199                 ch = *format++;
200                 break;
201             case '+':
202                 flags |= DP_F_PLUS;
203                 ch = *format++;
204                 break;
205             case ' ':
206                 flags |= DP_F_SPACE;
207                 ch = *format++;
208                 break;
209             case '#':
210                 flags |= DP_F_NUM;
211                 ch = *format++;
212                 break;
213             case '0':
214                 flags |= DP_F_ZERO;
215                 ch = *format++;
216                 break;
217             default:
218                 state = DP_S_MIN;
219                 break;
220             }
221             break;
222         case DP_S_MIN:
223             if (isdigit((unsigned char)ch)) {
224                 min = 10 * min + char_to_int(ch);
225                 ch = *format++;
226             } else if (ch == '*') {
227                 min = va_arg(args, int);
228                 ch = *format++;
229                 state = DP_S_DOT;
230             } else
231                 state = DP_S_DOT;
232             break;
233         case DP_S_DOT:
234             if (ch == '.') {
235                 state = DP_S_MAX;
236                 ch = *format++;
237             } else
238                 state = DP_S_MOD;
239             break;
240         case DP_S_MAX:
241             if (isdigit((unsigned char)ch)) {
242                 if (max < 0)
243                     max = 0;
244                 max = 10 * max + char_to_int(ch);
245                 ch = *format++;
246             } else if (ch == '*') {
247                 max = va_arg(args, int);
248                 ch = *format++;
249                 state = DP_S_MOD;
250             } else
251                 state = DP_S_MOD;
252             break;
253         case DP_S_MOD:
254             switch (ch) {
255             case 'h':
256                 cflags = DP_C_SHORT;
257                 ch = *format++;
258                 break;
259             case 'l':
260                 if (*format == 'l') {
261                     cflags = DP_C_LLONG;
262                     format++;
263                 } else
264                     cflags = DP_C_LONG;
265                 ch = *format++;
266                 break;
267             case 'q':
268                 cflags = DP_C_LLONG;
269                 ch = *format++;
270                 break;
271             case 'L':
272                 cflags = DP_C_LDOUBLE;
273                 ch = *format++;
274                 break;
275             default:
276                 break;
277             }
278             state = DP_S_CONV;
279             break;
280         case DP_S_CONV:
281             switch (ch) {
282             case 'd':
283             case 'i':
284                 switch (cflags) {
285                 case DP_C_SHORT:
286                     value = (short int)va_arg(args, int);
287                     break;
288                 case DP_C_LONG:
289                     value = va_arg(args, long int);
290                     break;
291                 case DP_C_LLONG:
292                     value = va_arg(args, LLONG);
293                     break;
294                 default:
295                     value = va_arg(args, int);
296                     break;
297                 }
298                 if (!fmtint(sbuffer, buffer, &currlen, maxlen, value, 10, min,
299                             max, flags))
300                     return 0;
301                 break;
302             case 'X':
303                 flags |= DP_F_UP;
304                 /* FALLTHROUGH */
305             case 'x':
306             case 'o':
307             case 'u':
308                 flags |= DP_F_UNSIGNED;
309                 switch (cflags) {
310                 case DP_C_SHORT:
311                     value = (unsigned short int)va_arg(args, unsigned int);
312                     break;
313                 case DP_C_LONG:
314                     value = (LLONG) va_arg(args, unsigned long int);
315                     break;
316                 case DP_C_LLONG:
317                     value = va_arg(args, unsigned LLONG);
318                     break;
319                 default:
320                     value = (LLONG) va_arg(args, unsigned int);
321                     break;
322                 }
323                 if (!fmtint(sbuffer, buffer, &currlen, maxlen, value,
324                             ch == 'o' ? 8 : (ch == 'u' ? 10 : 16),
325                             min, max, flags))
326                     return 0;
327                 break;
328             case 'f':
329                 if (cflags == DP_C_LDOUBLE)
330                     fvalue = va_arg(args, LDOUBLE);
331                 else
332                     fvalue = va_arg(args, double);
333                 if (!fmtfp(sbuffer, buffer, &currlen, maxlen, fvalue, min, max,
334                            flags))
335                     return 0;
336                 break;
337             case 'E':
338                 flags |= DP_F_UP;
339             case 'e':
340                 if (cflags == DP_C_LDOUBLE)
341                     fvalue = va_arg(args, LDOUBLE);
342                 else
343                     fvalue = va_arg(args, double);
344                 break;
345             case 'G':
346                 flags |= DP_F_UP;
347             case 'g':
348                 if (cflags == DP_C_LDOUBLE)
349                     fvalue = va_arg(args, LDOUBLE);
350                 else
351                     fvalue = va_arg(args, double);
352                 break;
353             case 'c':
354                 if(!doapr_outch(sbuffer, buffer, &currlen, maxlen,
355                             va_arg(args, int)))
356                     return 0;
357                 break;
358             case 's':
359                 strvalue = va_arg(args, char *);
360                 if (max < 0) {
361                     if (buffer)
362                         max = INT_MAX;
363                     else
364                         max = *maxlen;
365                 }
366                 if (!fmtstr(sbuffer, buffer, &currlen, maxlen, strvalue,
367                             flags, min, max))
368                     return 0;
369                 break;
370             case 'p':
371                 value = (size_t)va_arg(args, void *);
372                 if (!fmtint(sbuffer, buffer, &currlen, maxlen,
373                             value, 16, min, max, flags | DP_F_NUM))
374                     return 0;
375                 break;
376             case 'n':          /* XXX */
377                 if (cflags == DP_C_SHORT) {
378                     short int *num;
379                     num = va_arg(args, short int *);
380                     *num = currlen;
381                 } else if (cflags == DP_C_LONG) { /* XXX */
382                     long int *num;
383                     num = va_arg(args, long int *);
384                     *num = (long int)currlen;
385                 } else if (cflags == DP_C_LLONG) { /* XXX */
386                     LLONG *num;
387                     num = va_arg(args, LLONG *);
388                     *num = (LLONG) currlen;
389                 } else {
390                     int *num;
391                     num = va_arg(args, int *);
392                     *num = currlen;
393                 }
394                 break;
395             case '%':
396                 if(!doapr_outch(sbuffer, buffer, &currlen, maxlen, ch))
397                     return 0;
398                 break;
399             case 'w':
400                 /* not supported yet, treat as next char */
401                 ch = *format++;
402                 break;
403             default:
404                 /* unknown, skip */
405                 break;
406             }
407             ch = *format++;
408             state = DP_S_DEFAULT;
409             flags = cflags = min = 0;
410             max = -1;
411             break;
412         case DP_S_DONE:
413             break;
414         default:
415             break;
416         }
417     }
418     *truncated = (currlen > *maxlen - 1);
419     if (*truncated)
420         currlen = *maxlen - 1;
421     if(!doapr_outch(sbuffer, buffer, &currlen, maxlen, '\0'))
422         return 0;
423     *retlen = currlen - 1;
424     return 1;
425 }
426
427 static int
428 fmtstr(char **sbuffer,
429        char **buffer,
430        size_t *currlen,
431        size_t *maxlen, const char *value, int flags, int min, int max)
432 {
433     int padlen;
434     size_t strln;
435     int cnt = 0;
436
437     if (value == 0)
438         value = "<NULL>";
439
440     strln = strlen(value);
441     if (strln > INT_MAX)
442         strln = INT_MAX;
443
444     padlen = min - strln;
445     if (min < 0 || padlen < 0)
446         padlen = 0;
447     if (flags & DP_F_MINUS)
448         padlen = -padlen;
449
450     while ((padlen > 0) && (cnt < max)) {
451         if(!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
452             return 0;
453         --padlen;
454         ++cnt;
455     }
456     while (*value && (cnt < max)) {
457         if(!doapr_outch(sbuffer, buffer, currlen, maxlen, *value++))
458             return 0;
459         ++cnt;
460     }
461     while ((padlen < 0) && (cnt < max)) {
462         if(!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
463             return 0;
464         ++padlen;
465         ++cnt;
466     }
467     return 1;
468 }
469
470 static int
471 fmtint(char **sbuffer,
472        char **buffer,
473        size_t *currlen,
474        size_t *maxlen, LLONG value, int base, int min, int max, int flags)
475 {
476     int signvalue = 0;
477     const char *prefix = "";
478     unsigned LLONG uvalue;
479     char convert[DECIMAL_SIZE(value) + 3];
480     int place = 0;
481     int spadlen = 0;
482     int zpadlen = 0;
483     int caps = 0;
484
485     if (max < 0)
486         max = 0;
487     uvalue = value;
488     if (!(flags & DP_F_UNSIGNED)) {
489         if (value < 0) {
490             signvalue = '-';
491             uvalue = -value;
492         } else if (flags & DP_F_PLUS)
493             signvalue = '+';
494         else if (flags & DP_F_SPACE)
495             signvalue = ' ';
496     }
497     if (flags & DP_F_NUM) {
498         if (base == 8)
499             prefix = "0";
500         if (base == 16)
501             prefix = "0x";
502     }
503     if (flags & DP_F_UP)
504         caps = 1;
505     do {
506         convert[place++] = (caps ? "0123456789ABCDEF" : "0123456789abcdef")
507             [uvalue % (unsigned)base];
508         uvalue = (uvalue / (unsigned)base);
509     } while (uvalue && (place < (int)sizeof(convert)));
510     if (place == sizeof(convert))
511         place--;
512     convert[place] = 0;
513
514     zpadlen = max - place;
515     spadlen =
516         min - OSSL_MAX(max, place) - (signvalue ? 1 : 0) - strlen(prefix);
517     if (zpadlen < 0)
518         zpadlen = 0;
519     if (spadlen < 0)
520         spadlen = 0;
521     if (flags & DP_F_ZERO) {
522         zpadlen = OSSL_MAX(zpadlen, spadlen);
523         spadlen = 0;
524     }
525     if (flags & DP_F_MINUS)
526         spadlen = -spadlen;
527
528     /* spaces */
529     while (spadlen > 0) {
530         if(!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
531             return 0;
532         --spadlen;
533     }
534
535     /* sign */
536     if (signvalue)
537         if(!doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue))
538             return 0;
539
540     /* prefix */
541     while (*prefix) {
542         if(!doapr_outch(sbuffer, buffer, currlen, maxlen, *prefix))
543             return 0;
544         prefix++;
545     }
546
547     /* zeros */
548     if (zpadlen > 0) {
549         while (zpadlen > 0) {
550             if(!doapr_outch(sbuffer, buffer, currlen, maxlen, '0'))
551                 return 0;
552             --zpadlen;
553         }
554     }
555     /* digits */
556     while (place > 0) {
557         if (!doapr_outch(sbuffer, buffer, currlen, maxlen, convert[--place]))
558             return 0;
559     }
560
561     /* left justified spaces */
562     while (spadlen < 0) {
563         if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
564             return 0;
565         ++spadlen;
566     }
567     return 1;
568 }
569
570 static LDOUBLE abs_val(LDOUBLE value)
571 {
572     LDOUBLE result = value;
573     if (value < 0)
574         result = -value;
575     return result;
576 }
577
578 static LDOUBLE pow_10(int in_exp)
579 {
580     LDOUBLE result = 1;
581     while (in_exp) {
582         result *= 10;
583         in_exp--;
584     }
585     return result;
586 }
587
588 static long roundv(LDOUBLE value)
589 {
590     long intpart;
591     intpart = (long)value;
592     value = value - intpart;
593     if (value >= 0.5)
594         intpart++;
595     return intpart;
596 }
597
598 static int
599 fmtfp(char **sbuffer,
600       char **buffer,
601       size_t *currlen,
602       size_t *maxlen, LDOUBLE fvalue, int min, int max, int flags)
603 {
604     int signvalue = 0;
605     LDOUBLE ufvalue;
606     char iconvert[20];
607     char fconvert[20];
608     int iplace = 0;
609     int fplace = 0;
610     int padlen = 0;
611     int zpadlen = 0;
612     long intpart;
613     long fracpart;
614     long max10;
615
616     if (max < 0)
617         max = 6;
618     ufvalue = abs_val(fvalue);
619     if (fvalue < 0)
620         signvalue = '-';
621     else if (flags & DP_F_PLUS)
622         signvalue = '+';
623     else if (flags & DP_F_SPACE)
624         signvalue = ' ';
625
626     intpart = (long)ufvalue;
627
628     /*
629      * sorry, we only support 9 digits past the decimal because of our
630      * conversion method
631      */
632     if (max > 9)
633         max = 9;
634
635     /*
636      * we "cheat" by converting the fractional part to integer by multiplying
637      * by a factor of 10
638      */
639     max10 = roundv(pow_10(max));
640     fracpart = roundv(pow_10(max) * (ufvalue - intpart));
641
642     if (fracpart >= max10) {
643         intpart++;
644         fracpart -= max10;
645     }
646
647     /* convert integer part */
648     do {
649         iconvert[iplace++] = "0123456789"[intpart % 10];
650         intpart = (intpart / 10);
651     } while (intpart && (iplace < (int)sizeof(iconvert)));
652     if (iplace == sizeof iconvert)
653         iplace--;
654     iconvert[iplace] = 0;
655
656     /* convert fractional part */
657     do {
658         fconvert[fplace++] = "0123456789"[fracpart % 10];
659         fracpart = (fracpart / 10);
660     } while (fplace < max);
661     if (fplace == sizeof fconvert)
662         fplace--;
663     fconvert[fplace] = 0;
664
665     /* -1 for decimal point, another -1 if we are printing a sign */
666     padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
667     zpadlen = max - fplace;
668     if (zpadlen < 0)
669         zpadlen = 0;
670     if (padlen < 0)
671         padlen = 0;
672     if (flags & DP_F_MINUS)
673         padlen = -padlen;
674
675     if ((flags & DP_F_ZERO) && (padlen > 0)) {
676         if (signvalue) {
677             if (!doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue))
678                 return 0;
679             --padlen;
680             signvalue = 0;
681         }
682         while (padlen > 0) {
683             if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '0'))
684                 return 0;
685             --padlen;
686         }
687     }
688     while (padlen > 0) {
689         if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
690             return 0;
691         --padlen;
692     }
693     if (signvalue && !doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue))
694         return 0;
695
696     while (iplace > 0) {
697         if (!doapr_outch(sbuffer, buffer, currlen, maxlen, iconvert[--iplace]))
698             return 0;
699     }
700
701     /*
702      * Decimal point. This should probably use locale to find the correct
703      * char to print out.
704      */
705     if (max > 0 || (flags & DP_F_NUM)) {
706         if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '.'))
707             return 0;
708
709         while (fplace > 0) {
710             if(!doapr_outch(sbuffer, buffer, currlen, maxlen,
711                             fconvert[--fplace]))
712                 return 0;
713         }
714     }
715     while (zpadlen > 0) {
716         if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '0'))
717             return 0;
718         --zpadlen;
719     }
720
721     while (padlen < 0) {
722         if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
723             return 0;
724         ++padlen;
725     }
726     return 1;
727 }
728
729 #define BUFFER_INC  1024
730
731 static int
732 doapr_outch(char **sbuffer,
733             char **buffer, size_t *currlen, size_t *maxlen, int c)
734 {
735     /* If we haven't at least one buffer, someone has doe a big booboo */
736     assert(*sbuffer != NULL || buffer != NULL);
737
738     /* |currlen| must always be <= |*maxlen| */
739     assert(*currlen <= *maxlen);
740
741     if (buffer && *currlen == *maxlen) {
742         if (*maxlen > INT_MAX - BUFFER_INC)
743             return 0;
744
745         *maxlen += BUFFER_INC;
746         if (*buffer == NULL) {
747             *buffer = OPENSSL_malloc(*maxlen);
748             if (*buffer == NULL)
749                 return 0;
750             if (*currlen > 0) {
751                 assert(*sbuffer != NULL);
752                 memcpy(*buffer, *sbuffer, *currlen);
753             }
754             *sbuffer = NULL;
755         } else {
756             char *tmpbuf;
757             tmpbuf = OPENSSL_realloc(*buffer, *maxlen);
758             if (tmpbuf == NULL)
759                 return 0;
760             *buffer = tmpbuf;
761         }
762     }
763
764     if (*currlen < *maxlen) {
765         if (*sbuffer)
766             (*sbuffer)[(*currlen)++] = (char)c;
767         else
768             (*buffer)[(*currlen)++] = (char)c;
769     }
770
771     return 1;
772 }
773
774 /***************************************************************************/
775
776 int BIO_printf(BIO *bio, const char *format, ...)
777 {
778     va_list args;
779     int ret;
780
781     va_start(args, format);
782
783     ret = BIO_vprintf(bio, format, args);
784
785     va_end(args);
786     return (ret);
787 }
788
789 int BIO_vprintf(BIO *bio, const char *format, va_list args)
790 {
791     int ret;
792     size_t retlen;
793     char hugebuf[1024 * 2];     /* Was previously 10k, which is unreasonable
794                                  * in small-stack environments, like threads
795                                  * or DOS programs. */
796     char *hugebufp = hugebuf;
797     size_t hugebufsize = sizeof(hugebuf);
798     char *dynbuf = NULL;
799     int ignored;
800
801     dynbuf = NULL;
802     if (!_dopr(&hugebufp, &dynbuf, &hugebufsize, &retlen, &ignored, format,
803                 args)) {
804         OPENSSL_free(dynbuf);
805         return -1;
806     }
807     if (dynbuf) {
808         ret = BIO_write(bio, dynbuf, (int)retlen);
809         OPENSSL_free(dynbuf);
810     } else {
811         ret = BIO_write(bio, hugebuf, (int)retlen);
812     }
813     return (ret);
814 }
815
816 /*
817  * As snprintf is not available everywhere, we provide our own
818  * implementation. This function has nothing to do with BIOs, but it's
819  * closely related to BIO_printf, and we need *some* name prefix ... (XXX the
820  * function should be renamed, but to what?)
821  */
822 int BIO_snprintf(char *buf, size_t n, const char *format, ...)
823 {
824     va_list args;
825     int ret;
826
827     va_start(args, format);
828
829     ret = BIO_vsnprintf(buf, n, format, args);
830
831     va_end(args);
832     return (ret);
833 }
834
835 int BIO_vsnprintf(char *buf, size_t n, const char *format, va_list args)
836 {
837     size_t retlen;
838     int truncated;
839
840     if(!_dopr(&buf, NULL, &n, &retlen, &truncated, format, args))
841         return -1;
842
843     if (truncated)
844         /*
845          * In case of truncation, return -1 like traditional snprintf.
846          * (Current drafts for ISO/IEC 9899 say snprintf should return the
847          * number of characters that would have been written, had the buffer
848          * been large enough.)
849          */
850         return -1;
851     else
852         return (retlen <= INT_MAX) ? (int)retlen : -1;
853 }