a62f5516354811e8b5fa2cf870f370ce7d50a609
[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 /* 
60  * Stolen from tjh's ssl/ssl_trc.c stuff.
61  */
62
63 #include <stdio.h>
64 #include <string.h>
65 #include <ctype.h>
66 #include <assert.h>
67 #include <limits.h>
68 #include "cryptlib.h"
69 #ifndef NO_SYS_TYPES_H
70 #include <sys/types.h>
71 #endif
72 #include <openssl/bio.h>
73
74 #ifdef BN_LLONG
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 #if HAVE_LONG_DOUBLE
105 #define LDOUBLE long double
106 #else
107 #define LDOUBLE double
108 #endif
109
110 #if HAVE_LONG_LONG
111 #define LLONG long long
112 #else
113 #define LLONG long
114 #endif
115
116 static void fmtstr     (char **, char **, size_t *, size_t *,
117                         const char *, int, int, int);
118 static void fmtint     (char **, char **, size_t *, size_t *,
119                         LLONG, int, int, int, int);
120 static void fmtfp      (char **, char **, size_t *, size_t *,
121                         LDOUBLE, int, int, int);
122 static void doapr_outch (char **, char **, size_t *, size_t *, int);
123 static void _dopr(char **sbuffer, char **buffer,
124                   size_t *maxlen, size_t *retlen, int *truncated,
125                   const char *format, va_list args);
126
127 /* format read states */
128 #define DP_S_DEFAULT    0
129 #define DP_S_FLAGS      1
130 #define DP_S_MIN        2
131 #define DP_S_DOT        3
132 #define DP_S_MAX        4
133 #define DP_S_MOD        5
134 #define DP_S_CONV       6
135 #define DP_S_DONE       7
136
137 /* format flags - Bits */
138 #define DP_F_MINUS      (1 << 0)
139 #define DP_F_PLUS       (1 << 1)
140 #define DP_F_SPACE      (1 << 2)
141 #define DP_F_NUM        (1 << 3)
142 #define DP_F_ZERO       (1 << 4)
143 #define DP_F_UP         (1 << 5)
144 #define DP_F_UNSIGNED   (1 << 6)
145
146 /* conversion flags */
147 #define DP_C_SHORT      1
148 #define DP_C_LONG       2
149 #define DP_C_LDOUBLE    3
150 #define DP_C_LLONG      4
151
152 /* some handy macros */
153 #define char_to_int(p) (p - '0')
154 #define MAX(p,q) ((p >= q) ? p : q)
155
156 static void
157 _dopr(
158     char **sbuffer,
159     char **buffer,
160     size_t *maxlen,
161     size_t *retlen,
162     int *truncated,
163     const char *format,
164     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                 doapr_outch(sbuffer,buffer, &currlen, maxlen, ch);
192             ch = *format++;
193             break;
194         case DP_S_FLAGS:
195             switch (ch) {
196             case '-':
197                 flags |= DP_F_MINUS;
198                 ch = *format++;
199                 break;
200             case '+':
201                 flags |= DP_F_PLUS;
202                 ch = *format++;
203                 break;
204             case ' ':
205                 flags |= DP_F_SPACE;
206                 ch = *format++;
207                 break;
208             case '#':
209                 flags |= DP_F_NUM;
210                 ch = *format++;
211                 break;
212             case '0':
213                 flags |= DP_F_ZERO;
214                 ch = *format++;
215                 break;
216             default:
217                 state = DP_S_MIN;
218                 break;
219             }
220             break;
221         case DP_S_MIN:
222             if (isdigit((unsigned char)ch)) {
223                 min = 10 * min + char_to_int(ch);
224                 ch = *format++;
225             } else if (ch == '*') {
226                 min = va_arg(args, int);
227                 ch = *format++;
228                 state = DP_S_DOT;
229             } else
230                 state = DP_S_DOT;
231             break;
232         case DP_S_DOT:
233             if (ch == '.') {
234                 state = DP_S_MAX;
235                 ch = *format++;
236             } else
237                 state = DP_S_MOD;
238             break;
239         case DP_S_MAX:
240             if (isdigit((unsigned char)ch)) {
241                 if (max < 0)
242                     max = 0;
243                 max = 10 * max + char_to_int(ch);
244                 ch = *format++;
245             } else if (ch == '*') {
246                 max = va_arg(args, int);
247                 ch = *format++;
248                 state = DP_S_MOD;
249             } else
250                 state = DP_S_MOD;
251             break;
252         case DP_S_MOD:
253             switch (ch) {
254             case 'h':
255                 cflags = DP_C_SHORT;
256                 ch = *format++;
257                 break;
258             case 'l':
259                 if (*format == 'l') {
260                     cflags = DP_C_LLONG;
261                     format++;
262                 } else
263                     cflags = DP_C_LONG;
264                 ch = *format++;
265                 break;
266             case 'q':
267                 cflags = DP_C_LLONG;
268                 ch = *format++;
269                 break;
270             case 'L':
271                 cflags = DP_C_LDOUBLE;
272                 ch = *format++;
273                 break;
274             default:
275                 break;
276             }
277             state = DP_S_CONV;
278             break;
279         case DP_S_CONV:
280             switch (ch) {
281             case 'd':
282             case 'i':
283                 switch (cflags) {
284                 case DP_C_SHORT:
285                     value = (short int)va_arg(args, int);
286                     break;
287                 case DP_C_LONG:
288                     value = va_arg(args, long int);
289                     break;
290                 case DP_C_LLONG:
291                     value = va_arg(args, LLONG);
292                     break;
293                 default:
294                     value = va_arg(args, int);
295                     break;
296                 }
297                 fmtint(sbuffer, buffer, &currlen, maxlen,
298                        value, 10, min, max, flags);
299                 break;
300             case 'X':
301                 flags |= DP_F_UP;
302                 /* FALLTHROUGH */
303             case 'x':
304             case 'o':
305             case 'u':
306                 flags |= DP_F_UNSIGNED;
307                 switch (cflags) {
308                 case DP_C_SHORT:
309                     value = (unsigned short int)va_arg(args, unsigned int);
310                     break;
311                 case DP_C_LONG:
312                     value = (LLONG) va_arg(args,
313                         unsigned long int);
314                     break;
315                 case DP_C_LLONG:
316                     value = va_arg(args, unsigned LLONG);
317                     break;
318                 default:
319                     value = (LLONG) va_arg(args,
320                         unsigned int);
321                     break;
322                 }
323                 fmtint(sbuffer, buffer, &currlen, maxlen, value,
324                        ch == 'o' ? 8 : (ch == 'u' ? 10 : 16),
325                        min, max, flags);
326                 break;
327             case 'f':
328                 if (cflags == DP_C_LDOUBLE)
329                     fvalue = va_arg(args, LDOUBLE);
330                 else
331                     fvalue = va_arg(args, double);
332                 fmtfp(sbuffer, buffer, &currlen, maxlen,
333                       fvalue, min, max, flags);
334                 break;
335             case 'E':
336                 flags |= DP_F_UP;
337             case 'e':
338                 if (cflags == DP_C_LDOUBLE)
339                     fvalue = va_arg(args, LDOUBLE);
340                 else
341                     fvalue = va_arg(args, double);
342                 break;
343             case 'G':
344                 flags |= DP_F_UP;
345             case 'g':
346                 if (cflags == DP_C_LDOUBLE)
347                     fvalue = va_arg(args, LDOUBLE);
348                 else
349                     fvalue = va_arg(args, double);
350                 break;
351             case 'c':
352                 doapr_outch(sbuffer, buffer, &currlen, maxlen,
353                     va_arg(args, int));
354                 break;
355             case 's':
356                 strvalue = va_arg(args, char *);
357                 if (max < 0) {
358                     if (buffer)
359                         max = INT_MAX;
360                     else
361                         max = *maxlen;
362                 }
363                 fmtstr(sbuffer, buffer, &currlen, maxlen, strvalue,
364                        flags, min, max);
365                 break;
366             case 'p':
367                 value = (long)va_arg(args, void *);
368                 fmtint(sbuffer, buffer, &currlen, maxlen,
369                     value, 16, min, max, flags);
370                 break;
371             case 'n': /* XXX */
372                 if (cflags == DP_C_SHORT) {
373                     short int *num;
374                     num = va_arg(args, short int *);
375                     *num = currlen;
376                 } else if (cflags == DP_C_LONG) { /* XXX */
377                     long int *num;
378                     num = va_arg(args, long int *);
379                     *num = (long int) currlen;
380                 } else if (cflags == DP_C_LLONG) { /* XXX */
381                     LLONG *num;
382                     num = va_arg(args, LLONG *);
383                     *num = (LLONG) currlen;
384                 } else {
385                     int    *num;
386                     num = va_arg(args, int *);
387                     *num = currlen;
388                 }
389                 break;
390             case '%':
391                 doapr_outch(sbuffer, buffer, &currlen, maxlen, ch);
392                 break;
393             case 'w':
394                 /* not supported yet, treat as next char */
395                 ch = *format++;
396                 break;
397             default:
398                 /* unknown, skip */
399                 break;
400             }
401             ch = *format++;
402             state = DP_S_DEFAULT;
403             flags = cflags = min = 0;
404             max = -1;
405             break;
406         case DP_S_DONE:
407             break;
408         default:
409             break;
410         }
411     }
412     *truncated = (currlen > *maxlen - 1);
413     if (*truncated)
414         currlen = *maxlen - 1;
415     doapr_outch(sbuffer, buffer, &currlen, maxlen, '\0');
416     *retlen = currlen - 1;
417     return;
418 }
419
420 static void
421 fmtstr(
422     char **sbuffer,
423     char **buffer,
424     size_t *currlen,
425     size_t *maxlen,
426     const char *value,
427     int flags,
428     int min,
429     int max)
430 {
431     int padlen, strln;
432     int cnt = 0;
433
434     if (value == 0)
435         value = "<NULL>";
436     for (strln = 0; value[strln]; ++strln)
437         ;
438     padlen = min - strln;
439     if (padlen < 0)
440         padlen = 0;
441     if (flags & DP_F_MINUS)
442         padlen = -padlen;
443
444     while ((padlen > 0) && (cnt < max)) {
445         doapr_outch(sbuffer, buffer, currlen, maxlen, ' ');
446         --padlen;
447         ++cnt;
448     }
449     while (*value && (cnt < max)) {
450         doapr_outch(sbuffer, buffer, currlen, maxlen, *value++);
451         ++cnt;
452     }
453     while ((padlen < 0) && (cnt < max)) {
454         doapr_outch(sbuffer, buffer, currlen, maxlen, ' ');
455         ++padlen;
456         ++cnt;
457     }
458 }
459
460 static void
461 fmtint(
462     char **sbuffer,
463     char **buffer,
464     size_t *currlen,
465     size_t *maxlen,
466     LLONG value,
467     int base,
468     int min,
469     int max,
470     int flags)
471 {
472     int signvalue = 0;
473     unsigned LLONG uvalue;
474     char convert[20];
475     int place = 0;
476     int spadlen = 0;
477     int zpadlen = 0;
478     int caps = 0;
479
480     if (max < 0)
481         max = 0;
482     uvalue = value;
483     if (!(flags & DP_F_UNSIGNED)) {
484         if (value < 0) {
485             signvalue = '-';
486             uvalue = -value;
487         } else if (flags & DP_F_PLUS)
488             signvalue = '+';
489         else if (flags & DP_F_SPACE)
490             signvalue = ' ';
491     }
492     if (flags & DP_F_UP)
493         caps = 1;
494     do {
495         convert[place++] =
496             (caps ? "0123456789ABCDEF" : "0123456789abcdef")
497             [uvalue % (unsigned) base];
498         uvalue = (uvalue / (unsigned) base);
499     } while (uvalue && (place < 20));
500     if (place == 20)
501         place--;
502     convert[place] = 0;
503
504     zpadlen = max - place;
505     spadlen = min - MAX(max, place) - (signvalue ? 1 : 0);
506     if (zpadlen < 0)
507         zpadlen = 0;
508     if (spadlen < 0)
509         spadlen = 0;
510     if (flags & DP_F_ZERO) {
511         zpadlen = MAX(zpadlen, spadlen);
512         spadlen = 0;
513     }
514     if (flags & DP_F_MINUS)
515         spadlen = -spadlen;
516
517     /* spaces */
518     while (spadlen > 0) {
519         doapr_outch(sbuffer, buffer, currlen, maxlen, ' ');
520         --spadlen;
521     }
522
523     /* sign */
524     if (signvalue)
525         doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue);
526
527     /* zeros */
528     if (zpadlen > 0) {
529         while (zpadlen > 0) {
530             doapr_outch(sbuffer, buffer, currlen, maxlen, '0');
531             --zpadlen;
532         }
533     }
534     /* digits */
535     while (place > 0)
536         doapr_outch(sbuffer, buffer, currlen, maxlen, convert[--place]);
537
538     /* left justified spaces */
539     while (spadlen < 0) {
540         doapr_outch(sbuffer, buffer, currlen, maxlen, ' ');
541         ++spadlen;
542     }
543     return;
544 }
545
546 static LDOUBLE
547 abs_val(LDOUBLE value)
548 {
549     LDOUBLE result = value;
550     if (value < 0)
551         result = -value;
552     return result;
553 }
554
555 static LDOUBLE
556 pow10(int exp)
557 {
558     LDOUBLE result = 1;
559     while (exp) {
560         result *= 10;
561         exp--;
562     }
563     return result;
564 }
565
566 static long
567 round(LDOUBLE value)
568 {
569     long intpart;
570     intpart = (long) value;
571     value = value - intpart;
572     if (value >= 0.5)
573         intpart++;
574     return intpart;
575 }
576
577 static void
578 fmtfp(
579     char **sbuffer,
580     char **buffer,
581     size_t *currlen,
582     size_t *maxlen,
583     LDOUBLE fvalue,
584     int min,
585     int max,
586     int flags)
587 {
588     int signvalue = 0;
589     LDOUBLE ufvalue;
590     char iconvert[20];
591     char fconvert[20];
592     int iplace = 0;
593     int fplace = 0;
594     int padlen = 0;
595     int zpadlen = 0;
596     int caps = 0;
597     long intpart;
598     long fracpart;
599
600     if (max < 0)
601         max = 6;
602     ufvalue = abs_val(fvalue);
603     if (fvalue < 0)
604         signvalue = '-';
605     else if (flags & DP_F_PLUS)
606         signvalue = '+';
607     else if (flags & DP_F_SPACE)
608         signvalue = ' ';
609
610     intpart = (long)ufvalue;
611
612     /* sorry, we only support 9 digits past the decimal because of our
613        conversion method */
614     if (max > 9)
615         max = 9;
616
617     /* we "cheat" by converting the fractional part to integer by
618        multiplying by a factor of 10 */
619     fracpart = round((pow10(max)) * (ufvalue - intpart));
620
621     if (fracpart >= pow10(max)) {
622         intpart++;
623         fracpart -= (long)pow10(max);
624     }
625
626     /* convert integer part */
627     do {
628         iconvert[iplace++] =
629             (caps ? "0123456789ABCDEF"
630               : "0123456789abcdef")[intpart % 10];
631         intpart = (intpart / 10);
632     } while (intpart && (iplace < 20));
633     if (iplace == 20)
634         iplace--;
635     iconvert[iplace] = 0;
636
637     /* convert fractional part */
638     do {
639         fconvert[fplace++] =
640             (caps ? "0123456789ABCDEF"
641               : "0123456789abcdef")[fracpart % 10];
642         fracpart = (fracpart / 10);
643     } while (fracpart && (fplace < 20));
644     if (fplace == 20)
645         fplace--;
646     fconvert[fplace] = 0;
647
648     /* -1 for decimal point, another -1 if we are printing a sign */
649     padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
650     zpadlen = max - fplace;
651     if (zpadlen < 0)
652         zpadlen = 0;
653     if (padlen < 0)
654         padlen = 0;
655     if (flags & DP_F_MINUS)
656         padlen = -padlen;
657
658     if ((flags & DP_F_ZERO) && (padlen > 0)) {
659         if (signvalue) {
660             doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue);
661             --padlen;
662             signvalue = 0;
663         }
664         while (padlen > 0) {
665             doapr_outch(sbuffer, buffer, currlen, maxlen, '0');
666             --padlen;
667         }
668     }
669     while (padlen > 0) {
670         doapr_outch(sbuffer, buffer, currlen, maxlen, ' ');
671         --padlen;
672     }
673     if (signvalue)
674         doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue);
675
676     while (iplace > 0)
677         doapr_outch(sbuffer, buffer, currlen, maxlen, iconvert[--iplace]);
678
679     /*
680      * Decimal point. This should probably use locale to find the correct
681      * char to print out.
682      */
683     if (max > 0) {
684         doapr_outch(sbuffer, buffer, currlen, maxlen, '.');
685
686         while (fplace > 0)
687             doapr_outch(sbuffer, buffer, currlen, maxlen, fconvert[--fplace]);
688     }
689     while (zpadlen > 0) {
690         doapr_outch(sbuffer, buffer, currlen, maxlen, '0');
691         --zpadlen;
692     }
693
694     while (padlen < 0) {
695         doapr_outch(sbuffer, buffer, currlen, maxlen, ' ');
696         ++padlen;
697     }
698 }
699
700 static void
701 doapr_outch(
702     char **sbuffer,
703     char **buffer,
704     size_t *currlen,
705     size_t *maxlen,
706     int c)
707 {
708     /* If we haven't at least one buffer, someone has doe a big booboo */
709     assert(*sbuffer != NULL || buffer != NULL);
710
711     if (buffer) {
712         while (*currlen >= *maxlen) {
713             if (*buffer == NULL) {
714                 assert(*sbuffer != NULL);
715                 if (*maxlen == 0)
716                     *maxlen = 1024;
717                 *buffer = OPENSSL_malloc(*maxlen);
718                 if (*currlen > 0)
719                     memcpy(*buffer, *sbuffer, *currlen);
720                 *sbuffer = NULL;
721             } else {
722                 *maxlen += 1024;
723                 *buffer = OPENSSL_realloc(*buffer, *maxlen);
724             }
725         }
726         /* What to do if *buffer is NULL? */
727         assert(*sbuffer != NULL || *buffer != NULL);
728     }
729
730     if (*currlen < *maxlen) {
731         if (*sbuffer)
732             (*sbuffer)[(*currlen)++] = (char)c;
733         else
734             (*buffer)[(*currlen)++] = (char)c;
735     }
736
737     return;
738 }
739
740 /***************************************************************************/
741
742 int BIO_printf (BIO *bio, const char *format, ...)
743         {
744         va_list args;
745         int ret;
746
747         va_start(args, format);
748
749         ret = BIO_vprintf(bio, format, args);
750
751         va_end(args);
752         return(ret);
753         }
754
755 int BIO_vprintf (BIO *bio, const char *format, va_list args)
756         {
757         int ret;
758         size_t retlen;
759         MS_STATIC char hugebuf[1024*10];
760         char *hugebufp = hugebuf;
761         size_t hugebufsize = sizeof(hugebuf);
762         char *dynbuf = NULL;
763         int ignored;
764
765         dynbuf = NULL;
766         CRYPTO_push_info("doapr()");
767         _dopr(&hugebufp, &dynbuf, &hugebufsize,
768                 &retlen, &ignored, format, args);
769         if (dynbuf)
770                 {
771                 ret=BIO_write(bio, dynbuf, (int)retlen);
772                 OPENSSL_free(dynbuf);
773                 }
774         else
775                 {
776                 ret=BIO_write(bio, hugebuf, (int)retlen);
777                 }
778         CRYPTO_pop_info();
779         return(ret);
780         }
781
782 /* As snprintf is not available everywhere, we provide our own implementation.
783  * This function has nothing to do with BIOs, but it's closely related
784  * to BIO_printf, and we need *some* name prefix ...
785  * (XXX  the function should be renamed, but to what?) */
786 int BIO_snprintf(char *buf, size_t n, const char *format, ...)
787         {
788         va_list args;
789         int ret;
790
791         va_start(args, format);
792
793         ret = BIO_vsnprintf(buf, n, format, args);
794
795         va_end(args);
796         return(ret);
797         }
798
799 int BIO_vsnprintf(char *buf, size_t n, const char *format, va_list args)
800         {
801         size_t retlen;
802         int truncated;
803
804         _dopr(&buf, NULL, &n, &retlen, &truncated, format, args);
805
806         if (truncated)
807                 /* In case of truncation, return -1 like traditional snprintf.
808                  * (Current drafts for ISO/IEC 9899 say snprintf should return
809                  * the number of characters that would have been written,
810                  * had the buffer been large enough.) */
811                 return -1;
812         else
813                 return (retlen <= INT_MAX) ? retlen : -1;
814         }