155714Skris/* crypto/bio/b_print.c */
255714Skris/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
355714Skris * All rights reserved.
455714Skris *
555714Skris * This package is an SSL implementation written
655714Skris * by Eric Young (eay@cryptsoft.com).
755714Skris * The implementation was written so as to conform with Netscapes SSL.
8280297Sjkim *
955714Skris * This library is free for commercial and non-commercial use as long as
1055714Skris * the following conditions are aheared to.  The following conditions
1155714Skris * apply to all code found in this distribution, be it the RC4, RSA,
1255714Skris * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
1355714Skris * included with this distribution is covered by the same copyright terms
1455714Skris * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15280297Sjkim *
1655714Skris * Copyright remains Eric Young's, and as such any Copyright notices in
1755714Skris * the code are not to be removed.
1855714Skris * If this package is used in a product, Eric Young should be given attribution
1955714Skris * as the author of the parts of the library used.
2055714Skris * This can be in the form of a textual message at program startup or
2155714Skris * in documentation (online or textual) provided with the package.
22280297Sjkim *
2355714Skris * Redistribution and use in source and binary forms, with or without
2455714Skris * modification, are permitted provided that the following conditions
2555714Skris * are met:
2655714Skris * 1. Redistributions of source code must retain the copyright
2755714Skris *    notice, this list of conditions and the following disclaimer.
2855714Skris * 2. Redistributions in binary form must reproduce the above copyright
2955714Skris *    notice, this list of conditions and the following disclaimer in the
3055714Skris *    documentation and/or other materials provided with the distribution.
3155714Skris * 3. All advertising materials mentioning features or use of this software
3255714Skris *    must display the following acknowledgement:
3355714Skris *    "This product includes cryptographic software written by
3455714Skris *     Eric Young (eay@cryptsoft.com)"
3555714Skris *    The word 'cryptographic' can be left out if the rouines from the library
3655714Skris *    being used are not cryptographic related :-).
37280297Sjkim * 4. If you include any Windows specific code (or a derivative thereof) from
3855714Skris *    the apps directory (application code) you must include an acknowledgement:
3955714Skris *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40280297Sjkim *
4155714Skris * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
4255714Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4355714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4455714Skris * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
4555714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4655714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4755714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4855714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4955714Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5055714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5155714Skris * SUCH DAMAGE.
52280297Sjkim *
5355714Skris * The licence and distribution terms for any publically available version or
5455714Skris * derivative of this code cannot be changed.  i.e. this code cannot simply be
5555714Skris * copied and put under another distribution licence
5655714Skris * [including the GNU Public Licence.]
5755714Skris */
5855714Skris
59100936Snectar/* disable assert() unless BIO_DEBUG has been defined */
60100936Snectar#ifndef BIO_DEBUG
61100936Snectar# ifndef NDEBUG
62100936Snectar#  define NDEBUG
63100936Snectar# endif
64100936Snectar#endif
65100936Snectar
66280297Sjkim/*
6755714Skris * Stolen from tjh's ssl/ssl_trc.c stuff.
6855714Skris */
6955714Skris
7055714Skris#include <stdio.h>
7159191Skris#include <string.h>
7259191Skris#include <ctype.h>
7359191Skris#include <assert.h>
7459191Skris#include <limits.h>
7555714Skris#include "cryptlib.h"
7659191Skris#ifndef NO_SYS_TYPES_H
77280297Sjkim# include <sys/types.h>
7859191Skris#endif
7979998Skris#include <openssl/bn.h>         /* To get BN_LLONG properly defined */
8055714Skris#include <openssl/bio.h>
8155714Skris
82194206Ssimon#if defined(BN_LLONG) || defined(SIXTY_FOUR_BIT)
8359191Skris# ifndef HAVE_LONG_LONG
8459191Skris#  define HAVE_LONG_LONG 1
8559191Skris# endif
8659191Skris#endif
8759191Skris
8868651Skris/***************************************************************************/
8959191Skris
9059191Skris/*
9159191Skris * Copyright Patrick Powell 1995
9259191Skris * This code is based on code written by Patrick Powell <papowell@astart.com>
9359191Skris * It may be used for any purpose as long as this notice remains intact
9459191Skris * on all source code distributions.
9559191Skris */
9659191Skris
97280297Sjkim/*-
9859191Skris * This code contains numerious changes and enhancements which were
9959191Skris * made by lots of contributors over the last years to Patrick Powell's
10059191Skris * original code:
10159191Skris *
10259191Skris * o Patrick Powell <papowell@astart.com>      (1995)
10359191Skris * o Brandon Long <blong@fiction.net>          (1996, for Mutt)
10459191Skris * o Thomas Roessler <roessler@guug.de>        (1998, for Mutt)
10559191Skris * o Michael Elkins <me@cs.hmc.edu>            (1998, for Mutt)
10659191Skris * o Andrew Tridgell <tridge@samba.org>        (1998, for Samba)
10759191Skris * o Luke Mewburn <lukem@netbsd.org>           (1999, for LukemFTP)
10859191Skris * o Ralf S. Engelschall <rse@engelschall.com> (1999, for Pth)
10968651Skris * o ...                                       (for OpenSSL)
11059191Skris */
11159191Skris
112101613Snectar#ifdef HAVE_LONG_DOUBLE
113280297Sjkim# define LDOUBLE long double
11459191Skris#else
115280297Sjkim# define LDOUBLE double
11659191Skris#endif
11759191Skris
118238405Sjkim#ifdef HAVE_LONG_LONG
119238405Sjkim# if defined(_WIN32) && !defined(__GNUC__)
120280297Sjkim#  define LLONG __int64
12179998Skris# else
122280297Sjkim#  define LLONG long long
12379998Skris# endif
12459191Skris#else
125280297Sjkim# define LLONG long
12659191Skris#endif
12759191Skris
128296279Sjkimstatic int fmtstr(char **, char **, size_t *, size_t *,
129296279Sjkim                  const char *, int, int, int);
130296279Sjkimstatic int fmtint(char **, char **, size_t *, size_t *,
131296279Sjkim                  LLONG, int, int, int, int);
132296279Sjkimstatic int fmtfp(char **, char **, size_t *, size_t *,
133296279Sjkim                 LDOUBLE, int, int, int);
134296279Sjkimstatic int doapr_outch(char **, char **, size_t *, size_t *, int);
135296279Sjkimstatic int _dopr(char **sbuffer, char **buffer,
136296279Sjkim                 size_t *maxlen, size_t *retlen, int *truncated,
137296279Sjkim                 const char *format, va_list args);
13859191Skris
13959191Skris/* format read states */
14059191Skris#define DP_S_DEFAULT    0
14159191Skris#define DP_S_FLAGS      1
14259191Skris#define DP_S_MIN        2
14359191Skris#define DP_S_DOT        3
14459191Skris#define DP_S_MAX        4
14559191Skris#define DP_S_MOD        5
14659191Skris#define DP_S_CONV       6
14759191Skris#define DP_S_DONE       7
14859191Skris
14959191Skris/* format flags - Bits */
15059191Skris#define DP_F_MINUS      (1 << 0)
15159191Skris#define DP_F_PLUS       (1 << 1)
15259191Skris#define DP_F_SPACE      (1 << 2)
15359191Skris#define DP_F_NUM        (1 << 3)
15459191Skris#define DP_F_ZERO       (1 << 4)
15559191Skris#define DP_F_UP         (1 << 5)
15659191Skris#define DP_F_UNSIGNED   (1 << 6)
15759191Skris
15859191Skris/* conversion flags */
15959191Skris#define DP_C_SHORT      1
16059191Skris#define DP_C_LONG       2
16159191Skris#define DP_C_LDOUBLE    3
16259191Skris#define DP_C_LLONG      4
16359191Skris
16459191Skris/* some handy macros */
16559191Skris#define char_to_int(p) (p - '0')
16679998Skris#define OSSL_MAX(p,q) ((p >= q) ? p : q)
16759191Skris
168296279Sjkimstatic int
169280297Sjkim_dopr(char **sbuffer,
170280297Sjkim      char **buffer,
171280297Sjkim      size_t *maxlen,
172280297Sjkim      size_t *retlen, int *truncated, const char *format, va_list args)
17359191Skris{
17459191Skris    char ch;
17559191Skris    LLONG value;
17659191Skris    LDOUBLE fvalue;
17759191Skris    char *strvalue;
17859191Skris    int min;
17959191Skris    int max;
18059191Skris    int state;
18159191Skris    int flags;
18259191Skris    int cflags;
18359191Skris    size_t currlen;
18459191Skris
18559191Skris    state = DP_S_DEFAULT;
18659191Skris    flags = currlen = cflags = min = 0;
18759191Skris    max = -1;
18859191Skris    ch = *format++;
18959191Skris
19059191Skris    while (state != DP_S_DONE) {
19168651Skris        if (ch == '\0' || (buffer == NULL && currlen >= *maxlen))
19259191Skris            state = DP_S_DONE;
19359191Skris
19459191Skris        switch (state) {
19559191Skris        case DP_S_DEFAULT:
19659191Skris            if (ch == '%')
19759191Skris                state = DP_S_FLAGS;
19859191Skris            else
199296279Sjkim                if(!doapr_outch(sbuffer, buffer, &currlen, maxlen, ch))
200296279Sjkim                    return 0;
20159191Skris            ch = *format++;
20259191Skris            break;
20359191Skris        case DP_S_FLAGS:
20459191Skris            switch (ch) {
20559191Skris            case '-':
20659191Skris                flags |= DP_F_MINUS;
20759191Skris                ch = *format++;
20859191Skris                break;
20959191Skris            case '+':
21059191Skris                flags |= DP_F_PLUS;
21159191Skris                ch = *format++;
21259191Skris                break;
21359191Skris            case ' ':
21459191Skris                flags |= DP_F_SPACE;
21559191Skris                ch = *format++;
21659191Skris                break;
21759191Skris            case '#':
21859191Skris                flags |= DP_F_NUM;
21959191Skris                ch = *format++;
22059191Skris                break;
22159191Skris            case '0':
22259191Skris                flags |= DP_F_ZERO;
22359191Skris                ch = *format++;
22459191Skris                break;
22559191Skris            default:
22659191Skris                state = DP_S_MIN;
22759191Skris                break;
22859191Skris            }
22959191Skris            break;
23059191Skris        case DP_S_MIN:
23159191Skris            if (isdigit((unsigned char)ch)) {
23259191Skris                min = 10 * min + char_to_int(ch);
23359191Skris                ch = *format++;
23459191Skris            } else if (ch == '*') {
23559191Skris                min = va_arg(args, int);
23659191Skris                ch = *format++;
23759191Skris                state = DP_S_DOT;
23859191Skris            } else
23959191Skris                state = DP_S_DOT;
24059191Skris            break;
24159191Skris        case DP_S_DOT:
24259191Skris            if (ch == '.') {
24359191Skris                state = DP_S_MAX;
24459191Skris                ch = *format++;
24559191Skris            } else
24659191Skris                state = DP_S_MOD;
24759191Skris            break;
24859191Skris        case DP_S_MAX:
24959191Skris            if (isdigit((unsigned char)ch)) {
25059191Skris                if (max < 0)
25159191Skris                    max = 0;
25259191Skris                max = 10 * max + char_to_int(ch);
25359191Skris                ch = *format++;
25459191Skris            } else if (ch == '*') {
25559191Skris                max = va_arg(args, int);
25659191Skris                ch = *format++;
25759191Skris                state = DP_S_MOD;
25859191Skris            } else
25959191Skris                state = DP_S_MOD;
26059191Skris            break;
26159191Skris        case DP_S_MOD:
26259191Skris            switch (ch) {
26359191Skris            case 'h':
26459191Skris                cflags = DP_C_SHORT;
26559191Skris                ch = *format++;
26659191Skris                break;
26759191Skris            case 'l':
26859191Skris                if (*format == 'l') {
26959191Skris                    cflags = DP_C_LLONG;
27059191Skris                    format++;
27159191Skris                } else
27259191Skris                    cflags = DP_C_LONG;
27359191Skris                ch = *format++;
27459191Skris                break;
27559191Skris            case 'q':
27659191Skris                cflags = DP_C_LLONG;
27759191Skris                ch = *format++;
27859191Skris                break;
27959191Skris            case 'L':
28059191Skris                cflags = DP_C_LDOUBLE;
28159191Skris                ch = *format++;
28259191Skris                break;
28359191Skris            default:
28459191Skris                break;
28559191Skris            }
28659191Skris            state = DP_S_CONV;
28759191Skris            break;
28859191Skris        case DP_S_CONV:
28959191Skris            switch (ch) {
29059191Skris            case 'd':
29159191Skris            case 'i':
29259191Skris                switch (cflags) {
29359191Skris                case DP_C_SHORT:
29459191Skris                    value = (short int)va_arg(args, int);
29559191Skris                    break;
29659191Skris                case DP_C_LONG:
29759191Skris                    value = va_arg(args, long int);
29859191Skris                    break;
29959191Skris                case DP_C_LLONG:
30059191Skris                    value = va_arg(args, LLONG);
30159191Skris                    break;
30259191Skris                default:
30359191Skris                    value = va_arg(args, int);
30459191Skris                    break;
30559191Skris                }
306296279Sjkim                if (!fmtint(sbuffer, buffer, &currlen, maxlen, value, 10, min,
307296279Sjkim                            max, flags))
308296279Sjkim                    return 0;
30959191Skris                break;
31059191Skris            case 'X':
31159191Skris                flags |= DP_F_UP;
31259191Skris                /* FALLTHROUGH */
31359191Skris            case 'x':
31459191Skris            case 'o':
31559191Skris            case 'u':
31659191Skris                flags |= DP_F_UNSIGNED;
31759191Skris                switch (cflags) {
31859191Skris                case DP_C_SHORT:
31959191Skris                    value = (unsigned short int)va_arg(args, unsigned int);
32059191Skris                    break;
32159191Skris                case DP_C_LONG:
322280297Sjkim                    value = (LLONG) va_arg(args, unsigned long int);
32359191Skris                    break;
32459191Skris                case DP_C_LLONG:
32559191Skris                    value = va_arg(args, unsigned LLONG);
32659191Skris                    break;
32759191Skris                default:
328280297Sjkim                    value = (LLONG) va_arg(args, unsigned int);
32959191Skris                    break;
33059191Skris                }
331296279Sjkim                if (!fmtint(sbuffer, buffer, &currlen, maxlen, value,
332296279Sjkim                            ch == 'o' ? 8 : (ch == 'u' ? 10 : 16),
333296279Sjkim                            min, max, flags))
334296279Sjkim                    return 0;
33559191Skris                break;
33659191Skris            case 'f':
33759191Skris                if (cflags == DP_C_LDOUBLE)
33859191Skris                    fvalue = va_arg(args, LDOUBLE);
33959191Skris                else
34059191Skris                    fvalue = va_arg(args, double);
341296279Sjkim                if (!fmtfp(sbuffer, buffer, &currlen, maxlen, fvalue, min, max,
342296279Sjkim                           flags))
343296279Sjkim                    return 0;
34459191Skris                break;
34559191Skris            case 'E':
34659191Skris                flags |= DP_F_UP;
34759191Skris            case 'e':
34859191Skris                if (cflags == DP_C_LDOUBLE)
34959191Skris                    fvalue = va_arg(args, LDOUBLE);
35059191Skris                else
35159191Skris                    fvalue = va_arg(args, double);
35259191Skris                break;
35359191Skris            case 'G':
35459191Skris                flags |= DP_F_UP;
35559191Skris            case 'g':
35659191Skris                if (cflags == DP_C_LDOUBLE)
35759191Skris                    fvalue = va_arg(args, LDOUBLE);
35859191Skris                else
35959191Skris                    fvalue = va_arg(args, double);
36059191Skris                break;
36159191Skris            case 'c':
362296279Sjkim                if(!doapr_outch(sbuffer, buffer, &currlen, maxlen,
363296279Sjkim                            va_arg(args, int)))
364296279Sjkim                    return 0;
36559191Skris                break;
36659191Skris            case 's':
36759191Skris                strvalue = va_arg(args, char *);
36868651Skris                if (max < 0) {
369280297Sjkim                    if (buffer)
370280297Sjkim                        max = INT_MAX;
371280297Sjkim                    else
372280297Sjkim                        max = *maxlen;
373280297Sjkim                }
374296279Sjkim                if (!fmtstr(sbuffer, buffer, &currlen, maxlen, strvalue,
375296279Sjkim                            flags, min, max))
376296279Sjkim                    return 0;
37759191Skris                break;
37859191Skris            case 'p':
37959191Skris                value = (long)va_arg(args, void *);
380296279Sjkim                if (!fmtint(sbuffer, buffer, &currlen, maxlen,
381296279Sjkim                            value, 16, min, max, flags | DP_F_NUM))
382296279Sjkim                    return 0;
38359191Skris                break;
384280297Sjkim            case 'n':          /* XXX */
38559191Skris                if (cflags == DP_C_SHORT) {
38659191Skris                    short int *num;
38759191Skris                    num = va_arg(args, short int *);
388326663Sjkim                    *num = (short int)currlen;
38959191Skris                } else if (cflags == DP_C_LONG) { /* XXX */
39059191Skris                    long int *num;
39159191Skris                    num = va_arg(args, long int *);
392280297Sjkim                    *num = (long int)currlen;
39359191Skris                } else if (cflags == DP_C_LLONG) { /* XXX */
39459191Skris                    LLONG *num;
39559191Skris                    num = va_arg(args, LLONG *);
39659191Skris                    *num = (LLONG) currlen;
39759191Skris                } else {
398280297Sjkim                    int *num;
39959191Skris                    num = va_arg(args, int *);
40059191Skris                    *num = currlen;
40159191Skris                }
40259191Skris                break;
40359191Skris            case '%':
404296279Sjkim                if(!doapr_outch(sbuffer, buffer, &currlen, maxlen, ch))
405296279Sjkim                    return 0;
40659191Skris                break;
40759191Skris            case 'w':
40859191Skris                /* not supported yet, treat as next char */
40959191Skris                ch = *format++;
41059191Skris                break;
41159191Skris            default:
41259191Skris                /* unknown, skip */
41359191Skris                break;
41459191Skris            }
41559191Skris            ch = *format++;
41659191Skris            state = DP_S_DEFAULT;
41759191Skris            flags = cflags = min = 0;
41859191Skris            max = -1;
41959191Skris            break;
42059191Skris        case DP_S_DONE:
42159191Skris            break;
42259191Skris        default:
42359191Skris            break;
42459191Skris        }
42559191Skris    }
426306195Sjkim    /*
427306195Sjkim     * We have to truncate if there is no dynamic buffer and we have filled the
428306195Sjkim     * static buffer.
429306195Sjkim     */
430306195Sjkim    if (buffer == NULL) {
431306195Sjkim        *truncated = (currlen > *maxlen - 1);
432306195Sjkim        if (*truncated)
433306195Sjkim            currlen = *maxlen - 1;
434306195Sjkim    }
435296279Sjkim    if(!doapr_outch(sbuffer, buffer, &currlen, maxlen, '\0'))
436296279Sjkim        return 0;
43768651Skris    *retlen = currlen - 1;
438296279Sjkim    return 1;
43959191Skris}
44059191Skris
441296279Sjkimstatic int
442280297Sjkimfmtstr(char **sbuffer,
443280297Sjkim       char **buffer,
444280297Sjkim       size_t *currlen,
445280297Sjkim       size_t *maxlen, const char *value, int flags, int min, int max)
44659191Skris{
447296279Sjkim    int padlen;
448296279Sjkim    size_t strln;
44959191Skris    int cnt = 0;
45059191Skris
45159191Skris    if (value == 0)
45259191Skris        value = "<NULL>";
453296279Sjkim
454296279Sjkim    strln = strlen(value);
455296279Sjkim    if (strln > INT_MAX)
456296279Sjkim        strln = INT_MAX;
457296279Sjkim
45859191Skris    padlen = min - strln;
459296279Sjkim    if (min < 0 || padlen < 0)
46059191Skris        padlen = 0;
46159191Skris    if (flags & DP_F_MINUS)
46259191Skris        padlen = -padlen;
46359191Skris
46459191Skris    while ((padlen > 0) && (cnt < max)) {
465296279Sjkim        if(!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
466296279Sjkim            return 0;
46759191Skris        --padlen;
46859191Skris        ++cnt;
46959191Skris    }
47059191Skris    while (*value && (cnt < max)) {
471296279Sjkim        if(!doapr_outch(sbuffer, buffer, currlen, maxlen, *value++))
472296279Sjkim            return 0;
47359191Skris        ++cnt;
47459191Skris    }
47559191Skris    while ((padlen < 0) && (cnt < max)) {
476296279Sjkim        if(!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
477296279Sjkim            return 0;
47859191Skris        ++padlen;
47959191Skris        ++cnt;
48059191Skris    }
481296279Sjkim    return 1;
48259191Skris}
48359191Skris
484296279Sjkimstatic int
485280297Sjkimfmtint(char **sbuffer,
486280297Sjkim       char **buffer,
487280297Sjkim       size_t *currlen,
488280297Sjkim       size_t *maxlen, LLONG value, int base, int min, int max, int flags)
48959191Skris{
49059191Skris    int signvalue = 0;
491160814Ssimon    const char *prefix = "";
49259191Skris    unsigned LLONG uvalue;
493280297Sjkim    char convert[DECIMAL_SIZE(value) + 3];
49459191Skris    int place = 0;
49559191Skris    int spadlen = 0;
49659191Skris    int zpadlen = 0;
49759191Skris    int caps = 0;
49859191Skris
49959191Skris    if (max < 0)
50059191Skris        max = 0;
50159191Skris    uvalue = value;
50259191Skris    if (!(flags & DP_F_UNSIGNED)) {
50359191Skris        if (value < 0) {
50459191Skris            signvalue = '-';
505326663Sjkim            uvalue = 0 - (unsigned LLONG)value;
50659191Skris        } else if (flags & DP_F_PLUS)
50759191Skris            signvalue = '+';
50859191Skris        else if (flags & DP_F_SPACE)
50959191Skris            signvalue = ' ';
51059191Skris    }
511120631Snectar    if (flags & DP_F_NUM) {
512280297Sjkim        if (base == 8)
513280297Sjkim            prefix = "0";
514280297Sjkim        if (base == 16)
515280297Sjkim            prefix = "0x";
516120631Snectar    }
51759191Skris    if (flags & DP_F_UP)
51859191Skris        caps = 1;
51959191Skris    do {
520280297Sjkim        convert[place++] = (caps ? "0123456789ABCDEF" : "0123456789abcdef")
521280297Sjkim            [uvalue % (unsigned)base];
522280297Sjkim        uvalue = (uvalue / (unsigned)base);
523160814Ssimon    } while (uvalue && (place < (int)sizeof(convert)));
524160814Ssimon    if (place == sizeof(convert))
52559191Skris        place--;
52659191Skris    convert[place] = 0;
52759191Skris
52859191Skris    zpadlen = max - place;
529280297Sjkim    spadlen =
530280297Sjkim        min - OSSL_MAX(max, place) - (signvalue ? 1 : 0) - strlen(prefix);
53159191Skris    if (zpadlen < 0)
53259191Skris        zpadlen = 0;
53359191Skris    if (spadlen < 0)
53459191Skris        spadlen = 0;
53559191Skris    if (flags & DP_F_ZERO) {
53679998Skris        zpadlen = OSSL_MAX(zpadlen, spadlen);
53759191Skris        spadlen = 0;
53859191Skris    }
53959191Skris    if (flags & DP_F_MINUS)
54059191Skris        spadlen = -spadlen;
54159191Skris
54259191Skris    /* spaces */
54359191Skris    while (spadlen > 0) {
544296279Sjkim        if(!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
545296279Sjkim            return 0;
54659191Skris        --spadlen;
54759191Skris    }
54859191Skris
54959191Skris    /* sign */
55059191Skris    if (signvalue)
551296279Sjkim        if(!doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue))
552296279Sjkim            return 0;
55359191Skris
554120631Snectar    /* prefix */
555120631Snectar    while (*prefix) {
556296279Sjkim        if(!doapr_outch(sbuffer, buffer, currlen, maxlen, *prefix))
557296279Sjkim            return 0;
558280297Sjkim        prefix++;
559120631Snectar    }
560120631Snectar
56159191Skris    /* zeros */
56259191Skris    if (zpadlen > 0) {
56359191Skris        while (zpadlen > 0) {
564296279Sjkim            if(!doapr_outch(sbuffer, buffer, currlen, maxlen, '0'))
565296279Sjkim                return 0;
56659191Skris            --zpadlen;
56759191Skris        }
56859191Skris    }
56959191Skris    /* digits */
570296279Sjkim    while (place > 0) {
571296279Sjkim        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, convert[--place]))
572296279Sjkim            return 0;
573296279Sjkim    }
57459191Skris
57559191Skris    /* left justified spaces */
57659191Skris    while (spadlen < 0) {
577296279Sjkim        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
578296279Sjkim            return 0;
57959191Skris        ++spadlen;
58059191Skris    }
581296279Sjkim    return 1;
58259191Skris}
58359191Skris
584280297Sjkimstatic LDOUBLE abs_val(LDOUBLE value)
58559191Skris{
58659191Skris    LDOUBLE result = value;
58759191Skris    if (value < 0)
58859191Skris        result = -value;
58959191Skris    return result;
59059191Skris}
59159191Skris
592280297Sjkimstatic LDOUBLE pow_10(int in_exp)
59359191Skris{
59459191Skris    LDOUBLE result = 1;
595127128Snectar    while (in_exp) {
59659191Skris        result *= 10;
597127128Snectar        in_exp--;
59859191Skris    }
59959191Skris    return result;
60059191Skris}
60159191Skris
602280297Sjkimstatic long roundv(LDOUBLE value)
60359191Skris{
60459191Skris    long intpart;
605280297Sjkim    intpart = (long)value;
60659191Skris    value = value - intpart;
60759191Skris    if (value >= 0.5)
60859191Skris        intpart++;
60959191Skris    return intpart;
61059191Skris}
61159191Skris
612296279Sjkimstatic int
613280297Sjkimfmtfp(char **sbuffer,
614280297Sjkim      char **buffer,
615280297Sjkim      size_t *currlen,
616280297Sjkim      size_t *maxlen, LDOUBLE fvalue, int min, int max, int flags)
61759191Skris{
61859191Skris    int signvalue = 0;
61959191Skris    LDOUBLE ufvalue;
62059191Skris    char iconvert[20];
62159191Skris    char fconvert[20];
62259191Skris    int iplace = 0;
62359191Skris    int fplace = 0;
62459191Skris    int padlen = 0;
62559191Skris    int zpadlen = 0;
62659191Skris    long intpart;
62759191Skris    long fracpart;
628160814Ssimon    long max10;
62959191Skris
63059191Skris    if (max < 0)
63159191Skris        max = 6;
63259191Skris    ufvalue = abs_val(fvalue);
63359191Skris    if (fvalue < 0)
63459191Skris        signvalue = '-';
63559191Skris    else if (flags & DP_F_PLUS)
63659191Skris        signvalue = '+';
63759191Skris    else if (flags & DP_F_SPACE)
63859191Skris        signvalue = ' ';
63959191Skris
64059191Skris    intpart = (long)ufvalue;
64159191Skris
642280297Sjkim    /*
643280297Sjkim     * sorry, we only support 9 digits past the decimal because of our
644280297Sjkim     * conversion method
645280297Sjkim     */
64659191Skris    if (max > 9)
64759191Skris        max = 9;
64859191Skris
649280297Sjkim    /*
650280297Sjkim     * we "cheat" by converting the fractional part to integer by multiplying
651280297Sjkim     * by a factor of 10
652280297Sjkim     */
653160814Ssimon    max10 = roundv(pow_10(max));
654160814Ssimon    fracpart = roundv(pow_10(max) * (ufvalue - intpart));
65559191Skris
656160814Ssimon    if (fracpart >= max10) {
65759191Skris        intpart++;
658160814Ssimon        fracpart -= max10;
65959191Skris    }
66059191Skris
66159191Skris    /* convert integer part */
66259191Skris    do {
663280297Sjkim        iconvert[iplace++] = "0123456789"[intpart % 10];
66459191Skris        intpart = (intpart / 10);
665160814Ssimon    } while (intpart && (iplace < (int)sizeof(iconvert)));
666331638Sjkim    if (iplace == sizeof(iconvert))
66759191Skris        iplace--;
66859191Skris    iconvert[iplace] = 0;
66959191Skris
67059191Skris    /* convert fractional part */
67159191Skris    do {
672280297Sjkim        fconvert[fplace++] = "0123456789"[fracpart % 10];
67359191Skris        fracpart = (fracpart / 10);
67479998Skris    } while (fplace < max);
675331638Sjkim    if (fplace == sizeof(fconvert))
67659191Skris        fplace--;
67759191Skris    fconvert[fplace] = 0;
67859191Skris
67959191Skris    /* -1 for decimal point, another -1 if we are printing a sign */
68059191Skris    padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
68159191Skris    zpadlen = max - fplace;
68259191Skris    if (zpadlen < 0)
68359191Skris        zpadlen = 0;
68459191Skris    if (padlen < 0)
68559191Skris        padlen = 0;
68659191Skris    if (flags & DP_F_MINUS)
68759191Skris        padlen = -padlen;
68859191Skris
68959191Skris    if ((flags & DP_F_ZERO) && (padlen > 0)) {
69059191Skris        if (signvalue) {
691296279Sjkim            if (!doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue))
692296279Sjkim                return 0;
69359191Skris            --padlen;
69459191Skris            signvalue = 0;
69559191Skris        }
69659191Skris        while (padlen > 0) {
697296279Sjkim            if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '0'))
698296279Sjkim                return 0;
69959191Skris            --padlen;
70059191Skris        }
70159191Skris    }
70259191Skris    while (padlen > 0) {
703296279Sjkim        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
704296279Sjkim            return 0;
70559191Skris        --padlen;
70659191Skris    }
707296279Sjkim    if (signvalue && !doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue))
708296279Sjkim        return 0;
70959191Skris
710296279Sjkim    while (iplace > 0) {
711296279Sjkim        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, iconvert[--iplace]))
712296279Sjkim            return 0;
713296279Sjkim    }
71459191Skris
71559191Skris    /*
71659191Skris     * Decimal point. This should probably use locale to find the correct
71759191Skris     * char to print out.
71859191Skris     */
719120631Snectar    if (max > 0 || (flags & DP_F_NUM)) {
720296279Sjkim        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '.'))
721296279Sjkim            return 0;
72259191Skris
723296279Sjkim        while (fplace > 0) {
724296279Sjkim            if(!doapr_outch(sbuffer, buffer, currlen, maxlen,
725296279Sjkim                            fconvert[--fplace]))
726296279Sjkim                return 0;
727296279Sjkim        }
72859191Skris    }
72959191Skris    while (zpadlen > 0) {
730296279Sjkim        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '0'))
731296279Sjkim            return 0;
73259191Skris        --zpadlen;
73359191Skris    }
73459191Skris
73559191Skris    while (padlen < 0) {
736296279Sjkim        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
737296279Sjkim            return 0;
73859191Skris        ++padlen;
73959191Skris    }
740296279Sjkim    return 1;
74159191Skris}
74259191Skris
743296279Sjkim#define BUFFER_INC  1024
744296279Sjkim
745296279Sjkimstatic int
746280297Sjkimdoapr_outch(char **sbuffer,
747280297Sjkim            char **buffer, size_t *currlen, size_t *maxlen, int c)
74859191Skris{
74968651Skris    /* If we haven't at least one buffer, someone has doe a big booboo */
75068651Skris    assert(*sbuffer != NULL || buffer != NULL);
75159191Skris
752284283Sjkim    /* |currlen| must always be <= |*maxlen| */
753284283Sjkim    assert(*currlen <= *maxlen);
754284283Sjkim
755284283Sjkim    if (buffer && *currlen == *maxlen) {
756296279Sjkim        if (*maxlen > INT_MAX - BUFFER_INC)
757296279Sjkim            return 0;
758296279Sjkim
759296279Sjkim        *maxlen += BUFFER_INC;
760284283Sjkim        if (*buffer == NULL) {
761284283Sjkim            *buffer = OPENSSL_malloc(*maxlen);
762296279Sjkim            if (*buffer == NULL)
763296279Sjkim                return 0;
764284283Sjkim            if (*currlen > 0) {
765284283Sjkim                assert(*sbuffer != NULL);
766284283Sjkim                memcpy(*buffer, *sbuffer, *currlen);
767284283Sjkim            }
768284283Sjkim            *sbuffer = NULL;
769284283Sjkim        } else {
770296279Sjkim            char *tmpbuf;
771296279Sjkim            tmpbuf = OPENSSL_realloc(*buffer, *maxlen);
772296279Sjkim            if (tmpbuf == NULL)
773296279Sjkim                return 0;
774296279Sjkim            *buffer = tmpbuf;
775280297Sjkim        }
77659191Skris    }
77768651Skris
77868651Skris    if (*currlen < *maxlen) {
779280297Sjkim        if (*sbuffer)
780280297Sjkim            (*sbuffer)[(*currlen)++] = (char)c;
781280297Sjkim        else
782280297Sjkim            (*buffer)[(*currlen)++] = (char)c;
78359191Skris    }
78459191Skris
785296279Sjkim    return 1;
78659191Skris}
78768651Skris
78868651Skris/***************************************************************************/
78968651Skris
790280297Sjkimint BIO_printf(BIO *bio, const char *format, ...)
791280297Sjkim{
792280297Sjkim    va_list args;
793280297Sjkim    int ret;
79468651Skris
795280297Sjkim    va_start(args, format);
79668651Skris
797280297Sjkim    ret = BIO_vprintf(bio, format, args);
79868651Skris
799280297Sjkim    va_end(args);
800280297Sjkim    return (ret);
801280297Sjkim}
80268651Skris
803280297Sjkimint BIO_vprintf(BIO *bio, const char *format, va_list args)
804280297Sjkim{
805280297Sjkim    int ret;
806280297Sjkim    size_t retlen;
807280297Sjkim    char hugebuf[1024 * 2];     /* Was previously 10k, which is unreasonable
808280297Sjkim                                 * in small-stack environments, like threads
809280297Sjkim                                 * or DOS programs. */
810280297Sjkim    char *hugebufp = hugebuf;
811280297Sjkim    size_t hugebufsize = sizeof(hugebuf);
812280297Sjkim    char *dynbuf = NULL;
813280297Sjkim    int ignored;
81468651Skris
815280297Sjkim    dynbuf = NULL;
816280297Sjkim    CRYPTO_push_info("doapr()");
817296279Sjkim    if (!_dopr(&hugebufp, &dynbuf, &hugebufsize, &retlen, &ignored, format,
818296279Sjkim                args)) {
819296279Sjkim        OPENSSL_free(dynbuf);
820296279Sjkim        return -1;
821296279Sjkim    }
822280297Sjkim    if (dynbuf) {
823280297Sjkim        ret = BIO_write(bio, dynbuf, (int)retlen);
824280297Sjkim        OPENSSL_free(dynbuf);
825280297Sjkim    } else {
826280297Sjkim        ret = BIO_write(bio, hugebuf, (int)retlen);
827280297Sjkim    }
828280297Sjkim    CRYPTO_pop_info();
829280297Sjkim    return (ret);
830280297Sjkim}
83168651Skris
832280297Sjkim/*
833280297Sjkim * As snprintf is not available everywhere, we provide our own
834280297Sjkim * implementation. This function has nothing to do with BIOs, but it's
835280297Sjkim * closely related to BIO_printf, and we need *some* name prefix ... (XXX the
836280297Sjkim * function should be renamed, but to what?)
837280297Sjkim */
83868651Skrisint BIO_snprintf(char *buf, size_t n, const char *format, ...)
839280297Sjkim{
840280297Sjkim    va_list args;
841280297Sjkim    int ret;
84268651Skris
843280297Sjkim    va_start(args, format);
84468651Skris
845280297Sjkim    ret = BIO_vsnprintf(buf, n, format, args);
84668651Skris
847280297Sjkim    va_end(args);
848280297Sjkim    return (ret);
849280297Sjkim}
85068651Skris
85168651Skrisint BIO_vsnprintf(char *buf, size_t n, const char *format, va_list args)
852280297Sjkim{
853280297Sjkim    size_t retlen;
854280297Sjkim    int truncated;
85568651Skris
856296279Sjkim    if(!_dopr(&buf, NULL, &n, &retlen, &truncated, format, args))
857296279Sjkim        return -1;
85868651Skris
859280297Sjkim    if (truncated)
860280297Sjkim        /*
861280297Sjkim         * In case of truncation, return -1 like traditional snprintf.
862280297Sjkim         * (Current drafts for ISO/IEC 9899 say snprintf should return the
863280297Sjkim         * number of characters that would have been written, had the buffer
864280297Sjkim         * been large enough.)
865280297Sjkim         */
866280297Sjkim        return -1;
867280297Sjkim    else
868280297Sjkim        return (retlen <= INT_MAX) ? (int)retlen : -1;
869280297Sjkim}
870