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