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#ifdef HAVE_LONG_LONG
119# if defined(_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 = (short int)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    /*
427     * We have to truncate if there is no dynamic buffer and we have filled the
428     * static buffer.
429     */
430    if (buffer == NULL) {
431        *truncated = (currlen > *maxlen - 1);
432        if (*truncated)
433            currlen = *maxlen - 1;
434    }
435    if(!doapr_outch(sbuffer, buffer, &currlen, maxlen, '\0'))
436        return 0;
437    *retlen = currlen - 1;
438    return 1;
439}
440
441static int
442fmtstr(char **sbuffer,
443       char **buffer,
444       size_t *currlen,
445       size_t *maxlen, const char *value, int flags, int min, int max)
446{
447    int padlen;
448    size_t strln;
449    int cnt = 0;
450
451    if (value == 0)
452        value = "<NULL>";
453
454    strln = strlen(value);
455    if (strln > INT_MAX)
456        strln = INT_MAX;
457
458    padlen = min - strln;
459    if (min < 0 || padlen < 0)
460        padlen = 0;
461    if (flags & DP_F_MINUS)
462        padlen = -padlen;
463
464    while ((padlen > 0) && (cnt < max)) {
465        if(!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
466            return 0;
467        --padlen;
468        ++cnt;
469    }
470    while (*value && (cnt < max)) {
471        if(!doapr_outch(sbuffer, buffer, currlen, maxlen, *value++))
472            return 0;
473        ++cnt;
474    }
475    while ((padlen < 0) && (cnt < max)) {
476        if(!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
477            return 0;
478        ++padlen;
479        ++cnt;
480    }
481    return 1;
482}
483
484static int
485fmtint(char **sbuffer,
486       char **buffer,
487       size_t *currlen,
488       size_t *maxlen, LLONG value, int base, int min, int max, int flags)
489{
490    int signvalue = 0;
491    const char *prefix = "";
492    unsigned LLONG uvalue;
493    char convert[DECIMAL_SIZE(value) + 3];
494    int place = 0;
495    int spadlen = 0;
496    int zpadlen = 0;
497    int caps = 0;
498
499    if (max < 0)
500        max = 0;
501    uvalue = value;
502    if (!(flags & DP_F_UNSIGNED)) {
503        if (value < 0) {
504            signvalue = '-';
505            uvalue = 0 - (unsigned LLONG)value;
506        } else if (flags & DP_F_PLUS)
507            signvalue = '+';
508        else if (flags & DP_F_SPACE)
509            signvalue = ' ';
510    }
511    if (flags & DP_F_NUM) {
512        if (base == 8)
513            prefix = "0";
514        if (base == 16)
515            prefix = "0x";
516    }
517    if (flags & DP_F_UP)
518        caps = 1;
519    do {
520        convert[place++] = (caps ? "0123456789ABCDEF" : "0123456789abcdef")
521            [uvalue % (unsigned)base];
522        uvalue = (uvalue / (unsigned)base);
523    } while (uvalue && (place < (int)sizeof(convert)));
524    if (place == sizeof(convert))
525        place--;
526    convert[place] = 0;
527
528    zpadlen = max - place;
529    spadlen =
530        min - OSSL_MAX(max, place) - (signvalue ? 1 : 0) - strlen(prefix);
531    if (zpadlen < 0)
532        zpadlen = 0;
533    if (spadlen < 0)
534        spadlen = 0;
535    if (flags & DP_F_ZERO) {
536        zpadlen = OSSL_MAX(zpadlen, spadlen);
537        spadlen = 0;
538    }
539    if (flags & DP_F_MINUS)
540        spadlen = -spadlen;
541
542    /* spaces */
543    while (spadlen > 0) {
544        if(!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
545            return 0;
546        --spadlen;
547    }
548
549    /* sign */
550    if (signvalue)
551        if(!doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue))
552            return 0;
553
554    /* prefix */
555    while (*prefix) {
556        if(!doapr_outch(sbuffer, buffer, currlen, maxlen, *prefix))
557            return 0;
558        prefix++;
559    }
560
561    /* zeros */
562    if (zpadlen > 0) {
563        while (zpadlen > 0) {
564            if(!doapr_outch(sbuffer, buffer, currlen, maxlen, '0'))
565                return 0;
566            --zpadlen;
567        }
568    }
569    /* digits */
570    while (place > 0) {
571        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, convert[--place]))
572            return 0;
573    }
574
575    /* left justified spaces */
576    while (spadlen < 0) {
577        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
578            return 0;
579        ++spadlen;
580    }
581    return 1;
582}
583
584static LDOUBLE abs_val(LDOUBLE value)
585{
586    LDOUBLE result = value;
587    if (value < 0)
588        result = -value;
589    return result;
590}
591
592static LDOUBLE pow_10(int in_exp)
593{
594    LDOUBLE result = 1;
595    while (in_exp) {
596        result *= 10;
597        in_exp--;
598    }
599    return result;
600}
601
602static long roundv(LDOUBLE value)
603{
604    long intpart;
605    intpart = (long)value;
606    value = value - intpart;
607    if (value >= 0.5)
608        intpart++;
609    return intpart;
610}
611
612static int
613fmtfp(char **sbuffer,
614      char **buffer,
615      size_t *currlen,
616      size_t *maxlen, LDOUBLE fvalue, int min, int max, int flags)
617{
618    int signvalue = 0;
619    LDOUBLE ufvalue;
620    char iconvert[20];
621    char fconvert[20];
622    int iplace = 0;
623    int fplace = 0;
624    int padlen = 0;
625    int zpadlen = 0;
626    long intpart;
627    long fracpart;
628    long max10;
629
630    if (max < 0)
631        max = 6;
632    ufvalue = abs_val(fvalue);
633    if (fvalue < 0)
634        signvalue = '-';
635    else if (flags & DP_F_PLUS)
636        signvalue = '+';
637    else if (flags & DP_F_SPACE)
638        signvalue = ' ';
639
640    intpart = (long)ufvalue;
641
642    /*
643     * sorry, we only support 9 digits past the decimal because of our
644     * conversion method
645     */
646    if (max > 9)
647        max = 9;
648
649    /*
650     * we "cheat" by converting the fractional part to integer by multiplying
651     * by a factor of 10
652     */
653    max10 = roundv(pow_10(max));
654    fracpart = roundv(pow_10(max) * (ufvalue - intpart));
655
656    if (fracpart >= max10) {
657        intpart++;
658        fracpart -= max10;
659    }
660
661    /* convert integer part */
662    do {
663        iconvert[iplace++] = "0123456789"[intpart % 10];
664        intpart = (intpart / 10);
665    } while (intpart && (iplace < (int)sizeof(iconvert)));
666    if (iplace == sizeof(iconvert))
667        iplace--;
668    iconvert[iplace] = 0;
669
670    /* convert fractional part */
671    do {
672        fconvert[fplace++] = "0123456789"[fracpart % 10];
673        fracpart = (fracpart / 10);
674    } while (fplace < max);
675    if (fplace == sizeof(fconvert))
676        fplace--;
677    fconvert[fplace] = 0;
678
679    /* -1 for decimal point, another -1 if we are printing a sign */
680    padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
681    zpadlen = max - fplace;
682    if (zpadlen < 0)
683        zpadlen = 0;
684    if (padlen < 0)
685        padlen = 0;
686    if (flags & DP_F_MINUS)
687        padlen = -padlen;
688
689    if ((flags & DP_F_ZERO) && (padlen > 0)) {
690        if (signvalue) {
691            if (!doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue))
692                return 0;
693            --padlen;
694            signvalue = 0;
695        }
696        while (padlen > 0) {
697            if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '0'))
698                return 0;
699            --padlen;
700        }
701    }
702    while (padlen > 0) {
703        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
704            return 0;
705        --padlen;
706    }
707    if (signvalue && !doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue))
708        return 0;
709
710    while (iplace > 0) {
711        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, iconvert[--iplace]))
712            return 0;
713    }
714
715    /*
716     * Decimal point. This should probably use locale to find the correct
717     * char to print out.
718     */
719    if (max > 0 || (flags & DP_F_NUM)) {
720        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '.'))
721            return 0;
722
723        while (fplace > 0) {
724            if(!doapr_outch(sbuffer, buffer, currlen, maxlen,
725                            fconvert[--fplace]))
726                return 0;
727        }
728    }
729    while (zpadlen > 0) {
730        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '0'))
731            return 0;
732        --zpadlen;
733    }
734
735    while (padlen < 0) {
736        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
737            return 0;
738        ++padlen;
739    }
740    return 1;
741}
742
743#define BUFFER_INC  1024
744
745static int
746doapr_outch(char **sbuffer,
747            char **buffer, size_t *currlen, size_t *maxlen, int c)
748{
749    /* If we haven't at least one buffer, someone has doe a big booboo */
750    assert(*sbuffer != NULL || buffer != NULL);
751
752    /* |currlen| must always be <= |*maxlen| */
753    assert(*currlen <= *maxlen);
754
755    if (buffer && *currlen == *maxlen) {
756        if (*maxlen > INT_MAX - BUFFER_INC)
757            return 0;
758
759        *maxlen += BUFFER_INC;
760        if (*buffer == NULL) {
761            *buffer = OPENSSL_malloc(*maxlen);
762            if (*buffer == NULL)
763                return 0;
764            if (*currlen > 0) {
765                assert(*sbuffer != NULL);
766                memcpy(*buffer, *sbuffer, *currlen);
767            }
768            *sbuffer = NULL;
769        } else {
770            char *tmpbuf;
771            tmpbuf = OPENSSL_realloc(*buffer, *maxlen);
772            if (tmpbuf == NULL)
773                return 0;
774            *buffer = tmpbuf;
775        }
776    }
777
778    if (*currlen < *maxlen) {
779        if (*sbuffer)
780            (*sbuffer)[(*currlen)++] = (char)c;
781        else
782            (*buffer)[(*currlen)++] = (char)c;
783    }
784
785    return 1;
786}
787
788/***************************************************************************/
789
790int BIO_printf(BIO *bio, const char *format, ...)
791{
792    va_list args;
793    int ret;
794
795    va_start(args, format);
796
797    ret = BIO_vprintf(bio, format, args);
798
799    va_end(args);
800    return (ret);
801}
802
803int BIO_vprintf(BIO *bio, const char *format, va_list args)
804{
805    int ret;
806    size_t retlen;
807    char hugebuf[1024 * 2];     /* Was previously 10k, which is unreasonable
808                                 * in small-stack environments, like threads
809                                 * or DOS programs. */
810    char *hugebufp = hugebuf;
811    size_t hugebufsize = sizeof(hugebuf);
812    char *dynbuf = NULL;
813    int ignored;
814
815    dynbuf = NULL;
816    CRYPTO_push_info("doapr()");
817    if (!_dopr(&hugebufp, &dynbuf, &hugebufsize, &retlen, &ignored, format,
818                args)) {
819        OPENSSL_free(dynbuf);
820        return -1;
821    }
822    if (dynbuf) {
823        ret = BIO_write(bio, dynbuf, (int)retlen);
824        OPENSSL_free(dynbuf);
825    } else {
826        ret = BIO_write(bio, hugebuf, (int)retlen);
827    }
828    CRYPTO_pop_info();
829    return (ret);
830}
831
832/*
833 * As snprintf is not available everywhere, we provide our own
834 * implementation. This function has nothing to do with BIOs, but it's
835 * closely related to BIO_printf, and we need *some* name prefix ... (XXX the
836 * function should be renamed, but to what?)
837 */
838int BIO_snprintf(char *buf, size_t n, const char *format, ...)
839{
840    va_list args;
841    int ret;
842
843    va_start(args, format);
844
845    ret = BIO_vsnprintf(buf, n, format, args);
846
847    va_end(args);
848    return (ret);
849}
850
851int BIO_vsnprintf(char *buf, size_t n, const char *format, va_list args)
852{
853    size_t retlen;
854    int truncated;
855
856    if(!_dopr(&buf, NULL, &n, &retlen, &truncated, format, args))
857        return -1;
858
859    if (truncated)
860        /*
861         * In case of truncation, return -1 like traditional snprintf.
862         * (Current drafts for ISO/IEC 9899 say snprintf should return the
863         * number of characters that would have been written, had the buffer
864         * been large enough.)
865         */
866        return -1;
867    else
868        return (retlen <= INT_MAX) ? (int)retlen : -1;
869}
870