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