114113SN/A/* crypto/bio/b_print.c */
214113SN/A/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
314113SN/A * All rights reserved.
414113SN/A *
514113SN/A * This package is an SSL implementation written
614113SN/A * by Eric Young (eay@cryptsoft.com).
714113SN/A * The implementation was written so as to conform with Netscapes SSL.
814113SN/A *
914113SN/A * This library is free for commercial and non-commercial use as long as
1014113SN/A * the following conditions are aheared to.  The following conditions
1114113SN/A * apply to all code found in this distribution, be it the RC4, RSA,
1214113SN/A * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
1314113SN/A * included with this distribution is covered by the same copyright terms
1414113SN/A * except that the holder is Tim Hudson (tjh@cryptsoft.com).
1514113SN/A *
1614113SN/A * Copyright remains Eric Young's, and as such any Copyright notices in
1714113SN/A * the code are not to be removed.
1814113SN/A * If this package is used in a product, Eric Young should be given attribution
1914113SN/A * as the author of the parts of the library used.
2014113SN/A * This can be in the form of a textual message at program startup or
2114113SN/A * in documentation (online or textual) provided with the package.
2214113SN/A *
2314113SN/A * Redistribution and use in source and binary forms, with or without
2415424Splevart * modification, are permitted provided that the following conditions
2514113SN/A * are met:
2614113SN/A * 1. Redistributions of source code must retain the copyright
2714113SN/A *    notice, this list of conditions and the following disclaimer.
2814113SN/A * 2. Redistributions in binary form must reproduce the above copyright
2915424Splevart *    notice, this list of conditions and the following disclaimer in the
3014113SN/A *    documentation and/or other materials provided with the distribution.
3114113SN/A * 3. All advertising materials mentioning features or use of this software
3214113SN/A *    must display the following acknowledgement:
3314113SN/A *    "This product includes cryptographic software written by
3414113SN/A *     Eric Young (eay@cryptsoft.com)"
3514113SN/A *    The word 'cryptographic' can be left out if the rouines from the library
3614113SN/A *    being used are not cryptographic related :-).
3714113SN/A * 4. If you include any Windows specific code (or a derivative thereof) from
3814113SN/A *    the apps directory (application code) you must include an acknowledgement:
3914113SN/A *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
4014113SN/A *
4114113SN/A * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
4214113SN/A * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4315424Splevart * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4414113SN/A * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
4514113SN/A * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4614113SN/A * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4714113SN/A * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4814113SN/A * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4914113SN/A * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5014113SN/A * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5114113SN/A * SUCH DAMAGE.
5214113SN/A *
5314113SN/A * The licence and distribution terms for any publically available version or
5414113SN/A * derivative of this code cannot be changed.  i.e. this code cannot simply be
5514113SN/A * copied and put under another distribution licence
5614113SN/A * [including the GNU Public Licence.]
5714113SN/A */
5814113SN/A
5914113SN/A/* disable assert() unless BIO_DEBUG has been defined */
6014113SN/A#ifndef BIO_DEBUG
6114113SN/A# ifndef NDEBUG
6214113SN/A#  define NDEBUG
6314113SN/A# endif
6414113SN/A#endif
6514113SN/A
6614113SN/A/*
6714113SN/A * Stolen from tjh's ssl/ssl_trc.c stuff.
6814113SN/A */
6914113SN/A
7014113SN/A#include <stdio.h>
7114113SN/A#include <string.h>
7214113SN/A#include <ctype.h>
7314113SN/A#include <assert.h>
7414113SN/A#include <limits.h>
7514113SN/A#include "cryptlib.h"
7614113SN/A#ifndef NO_SYS_TYPES_H
7714113SN/A# include <sys/types.h>
7814113SN/A#endif
7914113SN/A#include <openssl/bn.h>         /* To get BN_LLONG properly defined */
8014113SN/A#include <openssl/bio.h>
8114113SN/A
8214113SN/A#if defined(BN_LLONG) || defined(SIXTY_FOUR_BIT)
8314113SN/A# ifndef HAVE_LONG_LONG
8414113SN/A#  define HAVE_LONG_LONG 1
8514113SN/A# endif
8614113SN/A#endif
8714113SN/A
8814113SN/A/***************************************************************************/
8914113SN/A
9014113SN/A/*
9114113SN/A * Copyright Patrick Powell 1995
9214113SN/A * This code is based on code written by Patrick Powell <papowell@astart.com>
9314113SN/A * It may be used for any purpose as long as this notice remains intact
9414113SN/A * on all source code distributions.
9514113SN/A */
9614113SN/A
9714113SN/A/*-
9814113SN/A * This code contains numerious changes and enhancements which were
9914113SN/A * made by lots of contributors over the last years to Patrick Powell's
10014113SN/A * original code:
10114113SN/A *
10214113SN/A * o Patrick Powell <papowell@astart.com>      (1995)
10314113SN/A * o Brandon Long <blong@fiction.net>          (1996, for Mutt)
10414113SN/A * o Thomas Roessler <roessler@guug.de>        (1998, for Mutt)
10514113SN/A * o Michael Elkins <me@cs.hmc.edu>            (1998, for Mutt)
10614113SN/A * o Andrew Tridgell <tridge@samba.org>        (1998, for Samba)
10714113SN/A * o Luke Mewburn <lukem@netbsd.org>           (1999, for LukemFTP)
10814113SN/A * o Ralf S. Engelschall <rse@engelschall.com> (1999, for Pth)
10914113SN/A * o ...                                       (for OpenSSL)
11014113SN/A */
11114113SN/A
11214113SN/A#ifdef HAVE_LONG_DOUBLE
11314113SN/A# define LDOUBLE long double
11414113SN/A#else
11514113SN/A# define LDOUBLE double
11614113SN/A#endif
11714113SN/A
11814113SN/A#ifdef HAVE_LONG_LONG
11914113SN/A# if defined(_WIN32) && !defined(__GNUC__)
12014113SN/A#  define LLONG __int64
12114113SN/A# else
12214113SN/A#  define LLONG long long
12314113SN/A# endif
12414113SN/A#else
12514113SN/A# define LLONG long
12614113SN/A#endif
12714113SN/A
12814113SN/Astatic int fmtstr(char **, char **, size_t *, size_t *,
12914113SN/A                  const char *, int, int, int);
13014113SN/Astatic int fmtint(char **, char **, size_t *, size_t *,
13114113SN/A                  LLONG, int, int, int, int);
13214113SN/Astatic int fmtfp(char **, char **, size_t *, size_t *,
13314113SN/A                 LDOUBLE, int, int, int);
13414113SN/Astatic int doapr_outch(char **, char **, size_t *, size_t *, int);
13514113SN/Astatic int _dopr(char **sbuffer, char **buffer,
13614113SN/A                 size_t *maxlen, size_t *retlen, int *truncated,
13714113SN/A                 const char *format, va_list args);
13814113SN/A
13914113SN/A/* format read states */
14014113SN/A#define DP_S_DEFAULT    0
14114113SN/A#define DP_S_FLAGS      1
14214113SN/A#define DP_S_MIN        2
14314113SN/A#define DP_S_DOT        3
14414113SN/A#define DP_S_MAX        4
14514113SN/A#define DP_S_MOD        5
14614113SN/A#define DP_S_CONV       6
14714113SN/A#define DP_S_DONE       7
14814113SN/A
14914113SN/A/* format flags - Bits */
15014113SN/A#define DP_F_MINUS      (1 << 0)
15114113SN/A#define DP_F_PLUS       (1 << 1)
15214113SN/A#define DP_F_SPACE      (1 << 2)
15314113SN/A#define DP_F_NUM        (1 << 3)
15414113SN/A#define DP_F_ZERO       (1 << 4)
15514113SN/A#define DP_F_UP         (1 << 5)
15614113SN/A#define DP_F_UNSIGNED   (1 << 6)
15714113SN/A
15814113SN/A/* conversion flags */
15914113SN/A#define DP_C_SHORT      1
16014113SN/A#define DP_C_LONG       2
16114113SN/A#define DP_C_LDOUBLE    3
16214113SN/A#define DP_C_LLONG      4
16314113SN/A
16414113SN/A/* some handy macros */
16514113SN/A#define char_to_int(p) (p - '0')
16614113SN/A#define OSSL_MAX(p,q) ((p >= q) ? p : q)
16714113SN/A
16814113SN/Astatic int
16914113SN/A_dopr(char **sbuffer,
17014113SN/A      char **buffer,
17114113SN/A      size_t *maxlen,
17214113SN/A      size_t *retlen, int *truncated, const char *format, va_list args)
17314113SN/A{
17414113SN/A    char ch;
17514113SN/A    LLONG value;
17614113SN/A    LDOUBLE fvalue;
17714113SN/A    char *strvalue;
17814113SN/A    int min;
17914113SN/A    int max;
18014113SN/A    int state;
18114113SN/A    int flags;
18214113SN/A    int cflags;
18314113SN/A    size_t currlen;
18414113SN/A
18514113SN/A    state = DP_S_DEFAULT;
18614113SN/A    flags = currlen = cflags = min = 0;
18714113SN/A    max = -1;
18814113SN/A    ch = *format++;
18914113SN/A
19014113SN/A    while (state != DP_S_DONE) {
19114113SN/A        if (ch == '\0' || (buffer == NULL && currlen >= *maxlen))
19214113SN/A            state = DP_S_DONE;
19314113SN/A
19414113SN/A        switch (state) {
19514113SN/A        case DP_S_DEFAULT:
19614113SN/A            if (ch == '%')
19714113SN/A                state = DP_S_FLAGS;
19814113SN/A            else
19914113SN/A                if(!doapr_outch(sbuffer, buffer, &currlen, maxlen, ch))
20014113SN/A                    return 0;
20114113SN/A            ch = *format++;
20214113SN/A            break;
20314113SN/A        case DP_S_FLAGS:
20414113SN/A            switch (ch) {
20514113SN/A            case '-':
20614113SN/A                flags |= DP_F_MINUS;
20714113SN/A                ch = *format++;
20814113SN/A                break;
20914113SN/A            case '+':
21014113SN/A                flags |= DP_F_PLUS;
21114113SN/A                ch = *format++;
21214113SN/A                break;
21314113SN/A            case ' ':
21414113SN/A                flags |= DP_F_SPACE;
21514113SN/A                ch = *format++;
21614113SN/A                break;
21714113SN/A            case '#':
21814113SN/A                flags |= DP_F_NUM;
21914113SN/A                ch = *format++;
22014113SN/A                break;
22114113SN/A            case '0':
22214113SN/A                flags |= DP_F_ZERO;
22314113SN/A                ch = *format++;
22414113SN/A                break;
22514113SN/A            default:
22614113SN/A                state = DP_S_MIN;
22714113SN/A                break;
22814113SN/A            }
22914113SN/A            break;
23014113SN/A        case DP_S_MIN:
23114113SN/A            if (isdigit((unsigned char)ch)) {
23214113SN/A                min = 10 * min + char_to_int(ch);
23314113SN/A                ch = *format++;
23414113SN/A            } else if (ch == '*') {
23514113SN/A                min = va_arg(args, int);
23614113SN/A                ch = *format++;
23714113SN/A                state = DP_S_DOT;
23814113SN/A            } else
23914113SN/A                state = DP_S_DOT;
24014113SN/A            break;
24114113SN/A        case DP_S_DOT:
24214113SN/A            if (ch == '.') {
24314113SN/A                state = DP_S_MAX;
24414113SN/A                ch = *format++;
24514113SN/A            } else
24614113SN/A                state = DP_S_MOD;
24714113SN/A            break;
24814113SN/A        case DP_S_MAX:
24914113SN/A            if (isdigit((unsigned char)ch)) {
25014113SN/A                if (max < 0)
25114113SN/A                    max = 0;
25214113SN/A                max = 10 * max + char_to_int(ch);
25314113SN/A                ch = *format++;
25414113SN/A            } else if (ch == '*') {
25514113SN/A                max = va_arg(args, int);
25614113SN/A                ch = *format++;
25714113SN/A                state = DP_S_MOD;
25814113SN/A            } else
25914113SN/A                state = DP_S_MOD;
26014113SN/A            break;
26114113SN/A        case DP_S_MOD:
26214113SN/A            switch (ch) {
26314113SN/A            case 'h':
26414113SN/A                cflags = DP_C_SHORT;
26514113SN/A                ch = *format++;
26614113SN/A                break;
26714113SN/A            case 'l':
26814113SN/A                if (*format == 'l') {
26914113SN/A                    cflags = DP_C_LLONG;
27014113SN/A                    format++;
27114113SN/A                } else
27214113SN/A                    cflags = DP_C_LONG;
27314113SN/A                ch = *format++;
27414113SN/A                break;
27514113SN/A            case 'q':
27614113SN/A                cflags = DP_C_LLONG;
27714113SN/A                ch = *format++;
27814113SN/A                break;
27914113SN/A            case 'L':
28014113SN/A                cflags = DP_C_LDOUBLE;
28114113SN/A                ch = *format++;
28214113SN/A                break;
28314113SN/A            default:
28414113SN/A                break;
28514113SN/A            }
28614113SN/A            state = DP_S_CONV;
28714113SN/A            break;
28814113SN/A        case DP_S_CONV:
28914113SN/A            switch (ch) {
29014113SN/A            case 'd':
29114113SN/A            case 'i':
29214113SN/A                switch (cflags) {
29314113SN/A                case DP_C_SHORT:
29414113SN/A                    value = (short int)va_arg(args, int);
29514113SN/A                    break;
29614113SN/A                case DP_C_LONG:
29714113SN/A                    value = va_arg(args, long int);
29814113SN/A                    break;
29914113SN/A                case DP_C_LLONG:
30014113SN/A                    value = va_arg(args, LLONG);
30114113SN/A                    break;
30214113SN/A                default:
30314113SN/A                    value = va_arg(args, int);
30414113SN/A                    break;
30514113SN/A                }
30614113SN/A                if (!fmtint(sbuffer, buffer, &currlen, maxlen, value, 10, min,
30714113SN/A                            max, flags))
30814113SN/A                    return 0;
30914113SN/A                break;
31014113SN/A            case 'X':
31114113SN/A                flags |= DP_F_UP;
31214113SN/A                /* FALLTHROUGH */
31314113SN/A            case 'x':
31414113SN/A            case 'o':
31514113SN/A            case 'u':
31614113SN/A                flags |= DP_F_UNSIGNED;
31714113SN/A                switch (cflags) {
31814113SN/A                case DP_C_SHORT:
31914113SN/A                    value = (unsigned short int)va_arg(args, unsigned int);
32014113SN/A                    break;
32114113SN/A                case DP_C_LONG:
32214113SN/A                    value = (LLONG) va_arg(args, unsigned long int);
32314113SN/A                    break;
32414113SN/A                case DP_C_LLONG:
32514113SN/A                    value = va_arg(args, unsigned LLONG);
32614113SN/A                    break;
32714113SN/A                default:
32814113SN/A                    value = (LLONG) va_arg(args, unsigned int);
32914113SN/A                    break;
33014113SN/A                }
33114113SN/A                if (!fmtint(sbuffer, buffer, &currlen, maxlen, value,
33214113SN/A                            ch == 'o' ? 8 : (ch == 'u' ? 10 : 16),
33314113SN/A                            min, max, flags))
33414113SN/A                    return 0;
33514113SN/A                break;
33614113SN/A            case 'f':
33714113SN/A                if (cflags == DP_C_LDOUBLE)
33814113SN/A                    fvalue = va_arg(args, LDOUBLE);
33914113SN/A                else
34014113SN/A                    fvalue = va_arg(args, double);
34114113SN/A                if (!fmtfp(sbuffer, buffer, &currlen, maxlen, fvalue, min, max,
34214113SN/A                           flags))
34314113SN/A                    return 0;
34414113SN/A                break;
34514113SN/A            case 'E':
34614113SN/A                flags |= DP_F_UP;
34714113SN/A            case 'e':
34814113SN/A                if (cflags == DP_C_LDOUBLE)
34914113SN/A                    fvalue = va_arg(args, LDOUBLE);
35014113SN/A                else
35114113SN/A                    fvalue = va_arg(args, double);
35214113SN/A                break;
35314113SN/A            case 'G':
35414113SN/A                flags |= DP_F_UP;
35514113SN/A            case 'g':
35614113SN/A                if (cflags == DP_C_LDOUBLE)
35714113SN/A                    fvalue = va_arg(args, LDOUBLE);
35814113SN/A                else
35914113SN/A                    fvalue = va_arg(args, double);
36014113SN/A                break;
36114113SN/A            case 'c':
36214113SN/A                if(!doapr_outch(sbuffer, buffer, &currlen, maxlen,
36314113SN/A                            va_arg(args, int)))
36414113SN/A                    return 0;
36514113SN/A                break;
36614113SN/A            case 's':
36714113SN/A                strvalue = va_arg(args, char *);
36814113SN/A                if (max < 0) {
36914113SN/A                    if (buffer)
37014113SN/A                        max = INT_MAX;
37114113SN/A                    else
37214113SN/A                        max = *maxlen;
37314113SN/A                }
37414113SN/A                if (!fmtstr(sbuffer, buffer, &currlen, maxlen, strvalue,
37514113SN/A                            flags, min, max))
37614113SN/A                    return 0;
37714113SN/A                break;
37814113SN/A            case 'p':
37914113SN/A                value = (long)va_arg(args, void *);
38015424Splevart                if (!fmtint(sbuffer, buffer, &currlen, maxlen,
38114113SN/A                            value, 16, min, max, flags | DP_F_NUM))
38214113SN/A                    return 0;
38314113SN/A                break;
38414113SN/A            case 'n':          /* XXX */
38514113SN/A                if (cflags == DP_C_SHORT) {
38614113SN/A                    short int *num;
38714113SN/A                    num = va_arg(args, short int *);
38814113SN/A                    *num = currlen;
38914113SN/A                } else if (cflags == DP_C_LONG) { /* XXX */
39014113SN/A                    long int *num;
39114113SN/A                    num = va_arg(args, long int *);
39214113SN/A                    *num = (long int)currlen;
39314113SN/A                } else if (cflags == DP_C_LLONG) { /* XXX */
39414113SN/A                    LLONG *num;
39514113SN/A                    num = va_arg(args, LLONG *);
39614113SN/A                    *num = (LLONG) currlen;
39714113SN/A                } else {
39814113SN/A                    int *num;
39914113SN/A                    num = va_arg(args, int *);
40014113SN/A                    *num = currlen;
40114113SN/A                }
40214113SN/A                break;
40314113SN/A            case '%':
40414113SN/A                if(!doapr_outch(sbuffer, buffer, &currlen, maxlen, ch))
40514113SN/A                    return 0;
40614113SN/A                break;
40714113SN/A            case 'w':
40814113SN/A                /* not supported yet, treat as next char */
40914113SN/A                ch = *format++;
41014113SN/A                break;
41114113SN/A            default:
41214113SN/A                /* unknown, skip */
41314113SN/A                break;
41414113SN/A            }
41514113SN/A            ch = *format++;
41614113SN/A            state = DP_S_DEFAULT;
41714113SN/A            flags = cflags = min = 0;
41814113SN/A            max = -1;
41914113SN/A            break;
42014113SN/A        case DP_S_DONE:
42114113SN/A            break;
42214113SN/A        default:
42314113SN/A            break;
42414113SN/A        }
42514113SN/A    }
42614113SN/A    *truncated = (currlen > *maxlen - 1);
42714113SN/A    if (*truncated)
42814113SN/A        currlen = *maxlen - 1;
42914113SN/A    if(!doapr_outch(sbuffer, buffer, &currlen, maxlen, '\0'))
43014113SN/A        return 0;
43114113SN/A    *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