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