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