Include bn.h so we get BN_LLONG properly defined. Otherwise, we can forget things...
[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/bn.h>         /* To get BN_LLONG properly defined */
73 #include <openssl/bio.h>
74
75 #ifdef BN_LLONG
76 # ifndef HAVE_LONG_LONG
77 #  define HAVE_LONG_LONG 1
78 # endif
79 #endif
80
81 /***************************************************************************/
82
83 /*
84  * Copyright Patrick Powell 1995
85  * This code is based on code written by Patrick Powell <papowell@astart.com>
86  * It may be used for any purpose as long as this notice remains intact
87  * on all source code distributions.
88  */
89
90 /*
91  * This code contains numerious changes and enhancements which were
92  * made by lots of contributors over the last years to Patrick Powell's
93  * original code:
94  *
95  * o Patrick Powell <papowell@astart.com>      (1995)
96  * o Brandon Long <blong@fiction.net>          (1996, for Mutt)
97  * o Thomas Roessler <roessler@guug.de>        (1998, for Mutt)
98  * o Michael Elkins <me@cs.hmc.edu>            (1998, for Mutt)
99  * o Andrew Tridgell <tridge@samba.org>        (1998, for Samba)
100  * o Luke Mewburn <lukem@netbsd.org>           (1999, for LukemFTP)
101  * o Ralf S. Engelschall <rse@engelschall.com> (1999, for Pth)
102  * o ...                                       (for OpenSSL)
103  */
104
105 #if HAVE_LONG_DOUBLE
106 #define LDOUBLE long double
107 #else
108 #define LDOUBLE double
109 #endif
110
111 #if HAVE_LONG_LONG
112 #define LLONG long long
113 #else
114 #define LLONG long
115 #endif
116
117 static void fmtstr     (char **, char **, size_t *, size_t *,
118                         const char *, int, int, int);
119 static void fmtint     (char **, char **, size_t *, size_t *,
120                         LLONG, int, int, int, int);
121 static void fmtfp      (char **, char **, size_t *, size_t *,
122                         LDOUBLE, int, int, int);
123 static void doapr_outch (char **, char **, size_t *, size_t *, int);
124 static void _dopr(char **sbuffer, char **buffer,
125                   size_t *maxlen, size_t *retlen, int *truncated,
126                   const char *format, va_list args);
127
128 /* format read states */
129 #define DP_S_DEFAULT    0
130 #define DP_S_FLAGS      1
131 #define DP_S_MIN        2
132 #define DP_S_DOT        3
133 #define DP_S_MAX        4
134 #define DP_S_MOD        5
135 #define DP_S_CONV       6
136 #define DP_S_DONE       7
137
138 /* format flags - Bits */
139 #define DP_F_MINUS      (1 << 0)
140 #define DP_F_PLUS       (1 << 1)
141 #define DP_F_SPACE      (1 << 2)
142 #define DP_F_NUM        (1 << 3)
143 #define DP_F_ZERO       (1 << 4)
144 #define DP_F_UP         (1 << 5)
145 #define DP_F_UNSIGNED   (1 << 6)
146
147 /* conversion flags */
148 #define DP_C_SHORT      1
149 #define DP_C_LONG       2
150 #define DP_C_LDOUBLE    3
151 #define DP_C_LLONG      4
152
153 /* some handy macros */
154 #define char_to_int(p) (p - '0')
155 #define OSSL_MAX(p,q) ((p >= q) ? p : q)
156
157 static void
158 _dopr(
159     char **sbuffer,
160     char **buffer,
161     size_t *maxlen,
162     size_t *retlen,
163     int *truncated,
164     const char *format,
165     va_list args)
166 {
167     char ch;
168     LLONG value;
169     LDOUBLE fvalue;
170     char *strvalue;
171     int min;
172     int max;
173     int state;
174     int flags;
175     int cflags;
176     size_t currlen;
177
178     state = DP_S_DEFAULT;
179     flags = currlen = cflags = min = 0;
180     max = -1;
181     ch = *format++;
182
183     while (state != DP_S_DONE) {
184         if (ch == '\0' || (buffer == NULL && currlen >= *maxlen))
185             state = DP_S_DONE;
186
187         switch (state) {
188         case DP_S_DEFAULT:
189             if (ch == '%')
190                 state = DP_S_FLAGS;
191             else
192                 doapr_outch(sbuffer,buffer, &currlen, maxlen, ch);
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                 fmtint(sbuffer, buffer, &currlen, maxlen,
299                        value, 10, min, max, flags);
300                 break;
301             case 'X':
302                 flags |= DP_F_UP;
303                 /* FALLTHROUGH */
304             case 'x':
305             case 'o':
306             case 'u':
307                 flags |= DP_F_UNSIGNED;
308                 switch (cflags) {
309                 case DP_C_SHORT:
310                     value = (unsigned short int)va_arg(args, unsigned int);
311                     break;
312                 case DP_C_LONG:
313                     value = (LLONG) va_arg(args,
314                         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,
321                         unsigned int);
322                     break;
323                 }
324                 fmtint(sbuffer, buffer, &currlen, maxlen, value,
325                        ch == 'o' ? 8 : (ch == 'u' ? 10 : 16),
326                        min, max, flags);
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                 fmtfp(sbuffer, buffer, &currlen, maxlen,
334                       fvalue, min, max, flags);
335                 break;
336             case 'E':
337                 flags |= DP_F_UP;
338             case 'e':
339                 if (cflags == DP_C_LDOUBLE)
340                     fvalue = va_arg(args, LDOUBLE);
341                 else
342                     fvalue = va_arg(args, double);
343                 break;
344             case 'G':
345                 flags |= DP_F_UP;
346             case 'g':
347                 if (cflags == DP_C_LDOUBLE)
348                     fvalue = va_arg(args, LDOUBLE);
349                 else
350                     fvalue = va_arg(args, double);
351                 break;
352             case 'c':
353                 doapr_outch(sbuffer, buffer, &currlen, maxlen,
354                     va_arg(args, int));
355                 break;
356             case 's':
357                 strvalue = va_arg(args, char *);
358                 if (max < 0) {
359                     if (buffer)
360                         max = INT_MAX;
361                     else
362                         max = *maxlen;
363                 }
364                 fmtstr(sbuffer, buffer, &currlen, maxlen, strvalue,
365                        flags, min, max);
366                 break;
367             case 'p':
368                 value = (long)va_arg(args, void *);
369                 fmtint(sbuffer, buffer, &currlen, maxlen,
370                     value, 16, min, max, flags);
371                 break;
372             case 'n': /* XXX */
373                 if (cflags == DP_C_SHORT) {
374                     short int *num;
375                     num = va_arg(args, short int *);
376                     *num = currlen;
377                 } else if (cflags == DP_C_LONG) { /* XXX */
378                     long int *num;
379                     num = va_arg(args, long int *);
380                     *num = (long int) currlen;
381                 } else if (cflags == DP_C_LLONG) { /* XXX */
382                     LLONG *num;
383                     num = va_arg(args, LLONG *);
384                     *num = (LLONG) currlen;
385                 } else {
386                     int    *num;
387                     num = va_arg(args, int *);
388                     *num = currlen;
389                 }
390                 break;
391             case '%':
392                 doapr_outch(sbuffer, buffer, &currlen, maxlen, ch);
393                 break;
394             case 'w':
395                 /* not supported yet, treat as next char */
396                 ch = *format++;
397                 break;
398             default:
399                 /* unknown, skip */
400                 break;
401             }
402             ch = *format++;
403             state = DP_S_DEFAULT;
404             flags = cflags = min = 0;
405             max = -1;
406             break;
407         case DP_S_DONE:
408             break;
409         default:
410             break;
411         }
412     }
413     *truncated = (currlen > *maxlen - 1);
414     if (*truncated)
415         currlen = *maxlen - 1;
416     doapr_outch(sbuffer, buffer, &currlen, maxlen, '\0');
417     *retlen = currlen - 1;
418     return;
419 }
420
421 static void
422 fmtstr(
423     char **sbuffer,
424     char **buffer,
425     size_t *currlen,
426     size_t *maxlen,
427     const char *value,
428     int flags,
429     int min,
430     int max)
431 {
432     int padlen, strln;
433     int cnt = 0;
434
435     if (value == 0)
436         value = "<NULL>";
437     for (strln = 0; value[strln]; ++strln)
438         ;
439     padlen = min - strln;
440     if (padlen < 0)
441         padlen = 0;
442     if (flags & DP_F_MINUS)
443         padlen = -padlen;
444
445     while ((padlen > 0) && (cnt < max)) {
446         doapr_outch(sbuffer, buffer, currlen, maxlen, ' ');
447         --padlen;
448         ++cnt;
449     }
450     while (*value && (cnt < max)) {
451         doapr_outch(sbuffer, buffer, currlen, maxlen, *value++);
452         ++cnt;
453     }
454     while ((padlen < 0) && (cnt < max)) {
455         doapr_outch(sbuffer, buffer, currlen, maxlen, ' ');
456         ++padlen;
457         ++cnt;
458     }
459 }
460
461 static void
462 fmtint(
463     char **sbuffer,
464     char **buffer,
465     size_t *currlen,
466     size_t *maxlen,
467     LLONG value,
468     int base,
469     int min,
470     int max,
471     int flags)
472 {
473     int signvalue = 0;
474     unsigned LLONG uvalue;
475     char convert[20];
476     int place = 0;
477     int spadlen = 0;
478     int zpadlen = 0;
479     int caps = 0;
480
481     if (max < 0)
482         max = 0;
483     uvalue = value;
484     if (!(flags & DP_F_UNSIGNED)) {
485         if (value < 0) {
486             signvalue = '-';
487             uvalue = -value;
488         } else if (flags & DP_F_PLUS)
489             signvalue = '+';
490         else if (flags & DP_F_SPACE)
491             signvalue = ' ';
492     }
493     if (flags & DP_F_UP)
494         caps = 1;
495     do {
496         convert[place++] =
497             (caps ? "0123456789ABCDEF" : "0123456789abcdef")
498             [uvalue % (unsigned) base];
499         uvalue = (uvalue / (unsigned) base);
500     } while (uvalue && (place < 20));
501     if (place == 20)
502         place--;
503     convert[place] = 0;
504
505     zpadlen = max - place;
506     spadlen = min - OSSL_MAX(max, place) - (signvalue ? 1 : 0);
507     if (zpadlen < 0)
508         zpadlen = 0;
509     if (spadlen < 0)
510         spadlen = 0;
511     if (flags & DP_F_ZERO) {
512         zpadlen = OSSL_MAX(zpadlen, spadlen);
513         spadlen = 0;
514     }
515     if (flags & DP_F_MINUS)
516         spadlen = -spadlen;
517
518     /* spaces */
519     while (spadlen > 0) {
520         doapr_outch(sbuffer, buffer, currlen, maxlen, ' ');
521         --spadlen;
522     }
523
524     /* sign */
525     if (signvalue)
526         doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue);
527
528     /* zeros */
529     if (zpadlen > 0) {
530         while (zpadlen > 0) {
531             doapr_outch(sbuffer, buffer, currlen, maxlen, '0');
532             --zpadlen;
533         }
534     }
535     /* digits */
536     while (place > 0)
537         doapr_outch(sbuffer, buffer, currlen, maxlen, convert[--place]);
538
539     /* left justified spaces */
540     while (spadlen < 0) {
541         doapr_outch(sbuffer, buffer, currlen, maxlen, ' ');
542         ++spadlen;
543     }
544     return;
545 }
546
547 static LDOUBLE
548 abs_val(LDOUBLE value)
549 {
550     LDOUBLE result = value;
551     if (value < 0)
552         result = -value;
553     return result;
554 }
555
556 static LDOUBLE
557 pow10(int exp)
558 {
559     LDOUBLE result = 1;
560     while (exp) {
561         result *= 10;
562         exp--;
563     }
564     return result;
565 }
566
567 static long
568 round(LDOUBLE value)
569 {
570     long intpart;
571     intpart = (long) value;
572     value = value - intpart;
573     if (value >= 0.5)
574         intpart++;
575     return intpart;
576 }
577
578 static void
579 fmtfp(
580     char **sbuffer,
581     char **buffer,
582     size_t *currlen,
583     size_t *maxlen,
584     LDOUBLE fvalue,
585     int min,
586     int max,
587     int flags)
588 {
589     int signvalue = 0;
590     LDOUBLE ufvalue;
591     char iconvert[20];
592     char fconvert[20];
593     int iplace = 0;
594     int fplace = 0;
595     int padlen = 0;
596     int zpadlen = 0;
597     int caps = 0;
598     long intpart;
599     long fracpart;
600
601     if (max < 0)
602         max = 6;
603     ufvalue = abs_val(fvalue);
604     if (fvalue < 0)
605         signvalue = '-';
606     else if (flags & DP_F_PLUS)
607         signvalue = '+';
608     else if (flags & DP_F_SPACE)
609         signvalue = ' ';
610
611     intpart = (long)ufvalue;
612
613     /* sorry, we only support 9 digits past the decimal because of our
614        conversion method */
615     if (max > 9)
616         max = 9;
617
618     /* we "cheat" by converting the fractional part to integer by
619        multiplying by a factor of 10 */
620     fracpart = round((pow10(max)) * (ufvalue - intpart));
621
622     if (fracpart >= pow10(max)) {
623         intpart++;
624         fracpart -= (long)pow10(max);
625     }
626
627     /* convert integer part */
628     do {
629         iconvert[iplace++] =
630             (caps ? "0123456789ABCDEF"
631               : "0123456789abcdef")[intpart % 10];
632         intpart = (intpart / 10);
633     } while (intpart && (iplace < 20));
634     if (iplace == 20)
635         iplace--;
636     iconvert[iplace] = 0;
637
638     /* convert fractional part */
639     do {
640         fconvert[fplace++] =
641             (caps ? "0123456789ABCDEF"
642               : "0123456789abcdef")[fracpart % 10];
643         fracpart = (fracpart / 10);
644     } while (fplace < max);
645     if (fplace == 20)
646         fplace--;
647     fconvert[fplace] = 0;
648
649     /* -1 for decimal point, another -1 if we are printing a sign */
650     padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
651     zpadlen = max - fplace;
652     if (zpadlen < 0)
653         zpadlen = 0;
654     if (padlen < 0)
655         padlen = 0;
656     if (flags & DP_F_MINUS)
657         padlen = -padlen;
658
659     if ((flags & DP_F_ZERO) && (padlen > 0)) {
660         if (signvalue) {
661             doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue);
662             --padlen;
663             signvalue = 0;
664         }
665         while (padlen > 0) {
666             doapr_outch(sbuffer, buffer, currlen, maxlen, '0');
667             --padlen;
668         }
669     }
670     while (padlen > 0) {
671         doapr_outch(sbuffer, buffer, currlen, maxlen, ' ');
672         --padlen;
673     }
674     if (signvalue)
675         doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue);
676
677     while (iplace > 0)
678         doapr_outch(sbuffer, buffer, currlen, maxlen, iconvert[--iplace]);
679
680     /*
681      * Decimal point. This should probably use locale to find the correct
682      * char to print out.
683      */
684     if (max > 0) {
685         doapr_outch(sbuffer, buffer, currlen, maxlen, '.');
686
687         while (fplace > 0)
688             doapr_outch(sbuffer, buffer, currlen, maxlen, fconvert[--fplace]);
689     }
690     while (zpadlen > 0) {
691         doapr_outch(sbuffer, buffer, currlen, maxlen, '0');
692         --zpadlen;
693     }
694
695     while (padlen < 0) {
696         doapr_outch(sbuffer, buffer, currlen, maxlen, ' ');
697         ++padlen;
698     }
699 }
700
701 static void
702 doapr_outch(
703     char **sbuffer,
704     char **buffer,
705     size_t *currlen,
706     size_t *maxlen,
707     int c)
708 {
709     /* If we haven't at least one buffer, someone has doe a big booboo */
710     assert(*sbuffer != NULL || buffer != NULL);
711
712     if (buffer) {
713         while (*currlen >= *maxlen) {
714             if (*buffer == NULL) {
715                 assert(*sbuffer != NULL);
716                 if (*maxlen == 0)
717                     *maxlen = 1024;
718                 *buffer = OPENSSL_malloc(*maxlen);
719                 if (*currlen > 0)
720                     memcpy(*buffer, *sbuffer, *currlen);
721                 *sbuffer = NULL;
722             } else {
723                 *maxlen += 1024;
724                 *buffer = OPENSSL_realloc(*buffer, *maxlen);
725             }
726         }
727         /* What to do if *buffer is NULL? */
728         assert(*sbuffer != NULL || *buffer != NULL);
729     }
730
731     if (*currlen < *maxlen) {
732         if (*sbuffer)
733             (*sbuffer)[(*currlen)++] = (char)c;
734         else
735             (*buffer)[(*currlen)++] = (char)c;
736     }
737
738     return;
739 }
740
741 /***************************************************************************/
742
743 int BIO_printf (BIO *bio, const char *format, ...)
744         {
745         va_list args;
746         int ret;
747
748         va_start(args, format);
749
750         ret = BIO_vprintf(bio, format, args);
751
752         va_end(args);
753         return(ret);
754         }
755
756 int BIO_vprintf (BIO *bio, const char *format, va_list args)
757         {
758         int ret;
759         size_t retlen;
760         MS_STATIC char hugebuf[1024*10];
761         char *hugebufp = hugebuf;
762         size_t hugebufsize = sizeof(hugebuf);
763         char *dynbuf = NULL;
764         int ignored;
765
766         dynbuf = NULL;
767         CRYPTO_push_info("doapr()");
768         _dopr(&hugebufp, &dynbuf, &hugebufsize,
769                 &retlen, &ignored, format, args);
770         if (dynbuf)
771                 {
772                 ret=BIO_write(bio, dynbuf, (int)retlen);
773                 OPENSSL_free(dynbuf);
774                 }
775         else
776                 {
777                 ret=BIO_write(bio, hugebuf, (int)retlen);
778                 }
779         CRYPTO_pop_info();
780         return(ret);
781         }
782
783 /* As snprintf is not available everywhere, we provide our own implementation.
784  * This function has nothing to do with BIOs, but it's closely related
785  * to BIO_printf, and we need *some* name prefix ...
786  * (XXX  the function should be renamed, but to what?) */
787 int BIO_snprintf(char *buf, size_t n, const char *format, ...)
788         {
789         va_list args;
790         int ret;
791
792         va_start(args, format);
793
794         ret = BIO_vsnprintf(buf, n, format, args);
795
796         va_end(args);
797         return(ret);
798         }
799
800 int BIO_vsnprintf(char *buf, size_t n, const char *format, va_list args)
801         {
802         size_t retlen;
803         int truncated;
804
805         _dopr(&buf, NULL, &n, &retlen, &truncated, format, args);
806
807         if (truncated)
808                 /* In case of truncation, return -1 like traditional snprintf.
809                  * (Current drafts for ISO/IEC 9899 say snprintf should return
810                  * the number of characters that would have been written,
811                  * had the buffer been large enough.) */
812                 return -1;
813         else
814                 return (retlen <= INT_MAX) ? retlen : -1;
815         }