b_print.c revision 296317
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 = 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    long intpart;
621    long fracpart;
622    long max10;
623
624    if (max < 0)
625        max = 6;
626    ufvalue = abs_val(fvalue);
627    if (fvalue < 0)
628        signvalue = '-';
629    else if (flags & DP_F_PLUS)
630        signvalue = '+';
631    else if (flags & DP_F_SPACE)
632        signvalue = ' ';
633
634    intpart = (long)ufvalue;
635
636    /*
637     * sorry, we only support 9 digits past the decimal because of our
638     * conversion method
639     */
640    if (max > 9)
641        max = 9;
642
643    /*
644     * we "cheat" by converting the fractional part to integer by multiplying
645     * by a factor of 10
646     */
647    max10 = roundv(pow_10(max));
648    fracpart = roundv(pow_10(max) * (ufvalue - intpart));
649
650    if (fracpart >= max10) {
651        intpart++;
652        fracpart -= max10;
653    }
654
655    /* convert integer part */
656    do {
657        iconvert[iplace++] = "0123456789"[intpart % 10];
658        intpart = (intpart / 10);
659    } while (intpart && (iplace < (int)sizeof(iconvert)));
660    if (iplace == sizeof iconvert)
661        iplace--;
662    iconvert[iplace] = 0;
663
664    /* convert fractional part */
665    do {
666        fconvert[fplace++] = "0123456789"[fracpart % 10];
667        fracpart = (fracpart / 10);
668    } while (fplace < max);
669    if (fplace == sizeof fconvert)
670        fplace--;
671    fconvert[fplace] = 0;
672
673    /* -1 for decimal point, another -1 if we are printing a sign */
674    padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
675    zpadlen = max - fplace;
676    if (zpadlen < 0)
677        zpadlen = 0;
678    if (padlen < 0)
679        padlen = 0;
680    if (flags & DP_F_MINUS)
681        padlen = -padlen;
682
683    if ((flags & DP_F_ZERO) && (padlen > 0)) {
684        if (signvalue) {
685            if (!doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue))
686                return 0;
687            --padlen;
688            signvalue = 0;
689        }
690        while (padlen > 0) {
691            if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '0'))
692                return 0;
693            --padlen;
694        }
695    }
696    while (padlen > 0) {
697        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
698            return 0;
699        --padlen;
700    }
701    if (signvalue && !doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue))
702        return 0;
703
704    while (iplace > 0) {
705        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, iconvert[--iplace]))
706            return 0;
707    }
708
709    /*
710     * Decimal point. This should probably use locale to find the correct
711     * char to print out.
712     */
713    if (max > 0 || (flags & DP_F_NUM)) {
714        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '.'))
715            return 0;
716
717        while (fplace > 0) {
718            if(!doapr_outch(sbuffer, buffer, currlen, maxlen,
719                            fconvert[--fplace]))
720                return 0;
721        }
722    }
723    while (zpadlen > 0) {
724        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '0'))
725            return 0;
726        --zpadlen;
727    }
728
729    while (padlen < 0) {
730        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
731            return 0;
732        ++padlen;
733    }
734    return 1;
735}
736
737#define BUFFER_INC  1024
738
739static int
740doapr_outch(char **sbuffer,
741            char **buffer, size_t *currlen, size_t *maxlen, int c)
742{
743    /* If we haven't at least one buffer, someone has doe a big booboo */
744    assert(*sbuffer != NULL || buffer != NULL);
745
746    /* |currlen| must always be <= |*maxlen| */
747    assert(*currlen <= *maxlen);
748
749    if (buffer && *currlen == *maxlen) {
750        if (*maxlen > INT_MAX - BUFFER_INC)
751            return 0;
752
753        *maxlen += BUFFER_INC;
754        if (*buffer == NULL) {
755            *buffer = OPENSSL_malloc(*maxlen);
756            if (*buffer == NULL)
757                return 0;
758            if (*currlen > 0) {
759                assert(*sbuffer != NULL);
760                memcpy(*buffer, *sbuffer, *currlen);
761            }
762            *sbuffer = NULL;
763        } else {
764            char *tmpbuf;
765            tmpbuf = OPENSSL_realloc(*buffer, *maxlen);
766            if (tmpbuf == NULL)
767                return 0;
768            *buffer = tmpbuf;
769        }
770    }
771
772    if (*currlen < *maxlen) {
773        if (*sbuffer)
774            (*sbuffer)[(*currlen)++] = (char)c;
775        else
776            (*buffer)[(*currlen)++] = (char)c;
777    }
778
779    return 1;
780}
781
782/***************************************************************************/
783
784int BIO_printf(BIO *bio, const char *format, ...)
785{
786    va_list args;
787    int ret;
788
789    va_start(args, format);
790
791    ret = BIO_vprintf(bio, format, args);
792
793    va_end(args);
794    return (ret);
795}
796
797int BIO_vprintf(BIO *bio, const char *format, va_list args)
798{
799    int ret;
800    size_t retlen;
801    char hugebuf[1024 * 2];     /* Was previously 10k, which is unreasonable
802                                 * in small-stack environments, like threads
803                                 * or DOS programs. */
804    char *hugebufp = hugebuf;
805    size_t hugebufsize = sizeof(hugebuf);
806    char *dynbuf = NULL;
807    int ignored;
808
809    dynbuf = NULL;
810    CRYPTO_push_info("doapr()");
811    if (!_dopr(&hugebufp, &dynbuf, &hugebufsize, &retlen, &ignored, format,
812                args)) {
813        OPENSSL_free(dynbuf);
814        return -1;
815    }
816    if (dynbuf) {
817        ret = BIO_write(bio, dynbuf, (int)retlen);
818        OPENSSL_free(dynbuf);
819    } else {
820        ret = BIO_write(bio, hugebuf, (int)retlen);
821    }
822    CRYPTO_pop_info();
823    return (ret);
824}
825
826/*
827 * As snprintf is not available everywhere, we provide our own
828 * implementation. This function has nothing to do with BIOs, but it's
829 * closely related to BIO_printf, and we need *some* name prefix ... (XXX the
830 * function should be renamed, but to what?)
831 */
832int BIO_snprintf(char *buf, size_t n, const char *format, ...)
833{
834    va_list args;
835    int ret;
836
837    va_start(args, format);
838
839    ret = BIO_vsnprintf(buf, n, format, args);
840
841    va_end(args);
842    return (ret);
843}
844
845int BIO_vsnprintf(char *buf, size_t n, const char *format, va_list args)
846{
847    size_t retlen;
848    int truncated;
849
850    if(!_dopr(&buf, NULL, &n, &retlen, &truncated, format, args))
851        return -1;
852
853    if (truncated)
854        /*
855         * In case of truncation, return -1 like traditional snprintf.
856         * (Current drafts for ISO/IEC 9899 say snprintf should return the
857         * number of characters that would have been written, had the buffer
858         * been large enough.)
859         */
860        return -1;
861    else
862        return (retlen <= INT_MAX) ? (int)retlen : -1;
863}
864