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.
8296341Sdelphij *
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).
15296341Sdelphij *
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.
22296341Sdelphij *
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 :-).
37296341Sdelphij * 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)"
40296341Sdelphij *
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.
52296341Sdelphij *
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
66296341Sdelphij/*
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
77296341Sdelphij# 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
97296341Sdelphij/*-
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
113296341Sdelphij# define LDOUBLE long double
11459191Skris#else
115296341Sdelphij# define LDOUBLE double
11659191Skris#endif
11759191Skris
118238405Sjkim#ifdef HAVE_LONG_LONG
119238405Sjkim# if defined(_WIN32) && !defined(__GNUC__)
120296341Sdelphij#  define LLONG __int64
12179998Skris# else
122296341Sdelphij#  define LLONG long long
12379998Skris# endif
12459191Skris#else
125296341Sdelphij# define LLONG long
12659191Skris#endif
12759191Skris
128296341Sdelphijstatic int fmtstr(char **, char **, size_t *, size_t *,
129296341Sdelphij                  const char *, int, int, int);
130296341Sdelphijstatic int fmtint(char **, char **, size_t *, size_t *,
131296341Sdelphij                  LLONG, int, int, int, int);
132296341Sdelphijstatic int fmtfp(char **, char **, size_t *, size_t *,
133296341Sdelphij                 LDOUBLE, int, int, int);
134296341Sdelphijstatic int doapr_outch(char **, char **, size_t *, size_t *, int);
135296341Sdelphijstatic int _dopr(char **sbuffer, char **buffer,
136296341Sdelphij                 size_t *maxlen, size_t *retlen, int *truncated,
137296341Sdelphij                 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
168296341Sdelphijstatic int
169296341Sdelphij_dopr(char **sbuffer,
170296341Sdelphij      char **buffer,
171296341Sdelphij      size_t *maxlen,
172296341Sdelphij      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
199296341Sdelphij                if(!doapr_outch(sbuffer, buffer, &currlen, maxlen, ch))
200296341Sdelphij                    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                }
306296341Sdelphij                if (!fmtint(sbuffer, buffer, &currlen, maxlen, value, 10, min,
307296341Sdelphij                            max, flags))
308296341Sdelphij                    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:
322296341Sdelphij                    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:
328296341Sdelphij                    value = (LLONG) va_arg(args, unsigned int);
32959191Skris                    break;
33059191Skris                }
331296341Sdelphij                if (!fmtint(sbuffer, buffer, &currlen, maxlen, value,
332296341Sdelphij                            ch == 'o' ? 8 : (ch == 'u' ? 10 : 16),
333296341Sdelphij                            min, max, flags))
334296341Sdelphij                    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);
341296341Sdelphij                if (!fmtfp(sbuffer, buffer, &currlen, maxlen, fvalue, min, max,
342296341Sdelphij                           flags))
343296341Sdelphij                    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':
362296341Sdelphij                if(!doapr_outch(sbuffer, buffer, &currlen, maxlen,
363296341Sdelphij                            va_arg(args, int)))
364296341Sdelphij                    return 0;
36559191Skris                break;
36659191Skris            case 's':
36759191Skris                strvalue = va_arg(args, char *);
36868651Skris                if (max < 0) {
369296341Sdelphij                    if (buffer)
370296341Sdelphij                        max = INT_MAX;
371296341Sdelphij                    else
372296341Sdelphij                        max = *maxlen;
373296341Sdelphij                }
374296341Sdelphij                if (!fmtstr(sbuffer, buffer, &currlen, maxlen, strvalue,
375296341Sdelphij                            flags, min, max))
376296341Sdelphij                    return 0;
37759191Skris                break;
37859191Skris            case 'p':
37959191Skris                value = (long)va_arg(args, void *);
380296341Sdelphij                if (!fmtint(sbuffer, buffer, &currlen, maxlen,
381296341Sdelphij                            value, 16, min, max, flags | DP_F_NUM))
382296341Sdelphij                    return 0;
38359191Skris                break;
384296341Sdelphij            case 'n':          /* XXX */
38559191Skris                if (cflags == DP_C_SHORT) {
38659191Skris                    short int *num;
38759191Skris                    num = va_arg(args, short int *);
38859191Skris                    *num = currlen;
38959191Skris                } else if (cflags == DP_C_LONG) { /* XXX */
39059191Skris                    long int *num;
39159191Skris                    num = va_arg(args, long int *);
392296341Sdelphij                    *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 {
398296341Sdelphij                    int *num;
39959191Skris                    num = va_arg(args, int *);
40059191Skris                    *num = currlen;
40159191Skris                }
40259191Skris                break;
40359191Skris            case '%':
404296341Sdelphij                if(!doapr_outch(sbuffer, buffer, &currlen, maxlen, ch))
405296341Sdelphij                    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    }
42668651Skris    *truncated = (currlen > *maxlen - 1);
42768651Skris    if (*truncated)
42859191Skris        currlen = *maxlen - 1;
429296341Sdelphij    if(!doapr_outch(sbuffer, buffer, &currlen, maxlen, '\0'))
430296341Sdelphij        return 0;
43168651Skris    *retlen = currlen - 1;
432296341Sdelphij    return 1;
43359191Skris}
43459191Skris
435296341Sdelphijstatic int
436296341Sdelphijfmtstr(char **sbuffer,
437296341Sdelphij       char **buffer,
438296341Sdelphij       size_t *currlen,
439296341Sdelphij       size_t *maxlen, const char *value, int flags, int min, int max)
44059191Skris{
441296341Sdelphij    int padlen;
442296341Sdelphij    size_t strln;
44359191Skris    int cnt = 0;
44459191Skris
44559191Skris    if (value == 0)
44659191Skris        value = "<NULL>";
447296341Sdelphij
448296341Sdelphij    strln = strlen(value);
449296341Sdelphij    if (strln > INT_MAX)
450296341Sdelphij        strln = INT_MAX;
451296341Sdelphij
45259191Skris    padlen = min - strln;
453296341Sdelphij    if (min < 0 || padlen < 0)
45459191Skris        padlen = 0;
45559191Skris    if (flags & DP_F_MINUS)
45659191Skris        padlen = -padlen;
45759191Skris
45859191Skris    while ((padlen > 0) && (cnt < max)) {
459296341Sdelphij        if(!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
460296341Sdelphij            return 0;
46159191Skris        --padlen;
46259191Skris        ++cnt;
46359191Skris    }
46459191Skris    while (*value && (cnt < max)) {
465296341Sdelphij        if(!doapr_outch(sbuffer, buffer, currlen, maxlen, *value++))
466296341Sdelphij            return 0;
46759191Skris        ++cnt;
46859191Skris    }
46959191Skris    while ((padlen < 0) && (cnt < max)) {
470296341Sdelphij        if(!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
471296341Sdelphij            return 0;
47259191Skris        ++padlen;
47359191Skris        ++cnt;
47459191Skris    }
475296341Sdelphij    return 1;
47659191Skris}
47759191Skris
478296341Sdelphijstatic int
479296341Sdelphijfmtint(char **sbuffer,
480296341Sdelphij       char **buffer,
481296341Sdelphij       size_t *currlen,
482296341Sdelphij       size_t *maxlen, LLONG value, int base, int min, int max, int flags)
48359191Skris{
48459191Skris    int signvalue = 0;
485160814Ssimon    const char *prefix = "";
48659191Skris    unsigned LLONG uvalue;
487296341Sdelphij    char convert[DECIMAL_SIZE(value) + 3];
48859191Skris    int place = 0;
48959191Skris    int spadlen = 0;
49059191Skris    int zpadlen = 0;
49159191Skris    int caps = 0;
49259191Skris
49359191Skris    if (max < 0)
49459191Skris        max = 0;
49559191Skris    uvalue = value;
49659191Skris    if (!(flags & DP_F_UNSIGNED)) {
49759191Skris        if (value < 0) {
49859191Skris            signvalue = '-';
49959191Skris            uvalue = -value;
50059191Skris        } else if (flags & DP_F_PLUS)
50159191Skris            signvalue = '+';
50259191Skris        else if (flags & DP_F_SPACE)
50359191Skris            signvalue = ' ';
50459191Skris    }
505120631Snectar    if (flags & DP_F_NUM) {
506296341Sdelphij        if (base == 8)
507296341Sdelphij            prefix = "0";
508296341Sdelphij        if (base == 16)
509296341Sdelphij            prefix = "0x";
510120631Snectar    }
51159191Skris    if (flags & DP_F_UP)
51259191Skris        caps = 1;
51359191Skris    do {
514296341Sdelphij        convert[place++] = (caps ? "0123456789ABCDEF" : "0123456789abcdef")
515296341Sdelphij            [uvalue % (unsigned)base];
516296341Sdelphij        uvalue = (uvalue / (unsigned)base);
517160814Ssimon    } while (uvalue && (place < (int)sizeof(convert)));
518160814Ssimon    if (place == sizeof(convert))
51959191Skris        place--;
52059191Skris    convert[place] = 0;
52159191Skris
52259191Skris    zpadlen = max - place;
523296341Sdelphij    spadlen =
524296341Sdelphij        min - OSSL_MAX(max, place) - (signvalue ? 1 : 0) - strlen(prefix);
52559191Skris    if (zpadlen < 0)
52659191Skris        zpadlen = 0;
52759191Skris    if (spadlen < 0)
52859191Skris        spadlen = 0;
52959191Skris    if (flags & DP_F_ZERO) {
53079998Skris        zpadlen = OSSL_MAX(zpadlen, spadlen);
53159191Skris        spadlen = 0;
53259191Skris    }
53359191Skris    if (flags & DP_F_MINUS)
53459191Skris        spadlen = -spadlen;
53559191Skris
53659191Skris    /* spaces */
53759191Skris    while (spadlen > 0) {
538296341Sdelphij        if(!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
539296341Sdelphij            return 0;
54059191Skris        --spadlen;
54159191Skris    }
54259191Skris
54359191Skris    /* sign */
54459191Skris    if (signvalue)
545296341Sdelphij        if(!doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue))
546296341Sdelphij            return 0;
54759191Skris
548120631Snectar    /* prefix */
549120631Snectar    while (*prefix) {
550296341Sdelphij        if(!doapr_outch(sbuffer, buffer, currlen, maxlen, *prefix))
551296341Sdelphij            return 0;
552296341Sdelphij        prefix++;
553120631Snectar    }
554120631Snectar
55559191Skris    /* zeros */
55659191Skris    if (zpadlen > 0) {
55759191Skris        while (zpadlen > 0) {
558296341Sdelphij            if(!doapr_outch(sbuffer, buffer, currlen, maxlen, '0'))
559296341Sdelphij                return 0;
56059191Skris            --zpadlen;
56159191Skris        }
56259191Skris    }
56359191Skris    /* digits */
564296341Sdelphij    while (place > 0) {
565296341Sdelphij        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, convert[--place]))
566296341Sdelphij            return 0;
567296341Sdelphij    }
56859191Skris
56959191Skris    /* left justified spaces */
57059191Skris    while (spadlen < 0) {
571296341Sdelphij        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
572296341Sdelphij            return 0;
57359191Skris        ++spadlen;
57459191Skris    }
575296341Sdelphij    return 1;
57659191Skris}
57759191Skris
578296341Sdelphijstatic LDOUBLE abs_val(LDOUBLE value)
57959191Skris{
58059191Skris    LDOUBLE result = value;
58159191Skris    if (value < 0)
58259191Skris        result = -value;
58359191Skris    return result;
58459191Skris}
58559191Skris
586296341Sdelphijstatic LDOUBLE pow_10(int in_exp)
58759191Skris{
58859191Skris    LDOUBLE result = 1;
589127128Snectar    while (in_exp) {
59059191Skris        result *= 10;
591127128Snectar        in_exp--;
59259191Skris    }
59359191Skris    return result;
59459191Skris}
59559191Skris
596296341Sdelphijstatic long roundv(LDOUBLE value)
59759191Skris{
59859191Skris    long intpart;
599296341Sdelphij    intpart = (long)value;
60059191Skris    value = value - intpart;
60159191Skris    if (value >= 0.5)
60259191Skris        intpart++;
60359191Skris    return intpart;
60459191Skris}
60559191Skris
606296341Sdelphijstatic int
607296341Sdelphijfmtfp(char **sbuffer,
608296341Sdelphij      char **buffer,
609296341Sdelphij      size_t *currlen,
610296341Sdelphij      size_t *maxlen, LDOUBLE fvalue, int min, int max, int flags)
61159191Skris{
61259191Skris    int signvalue = 0;
61359191Skris    LDOUBLE ufvalue;
61459191Skris    char iconvert[20];
61559191Skris    char fconvert[20];
61659191Skris    int iplace = 0;
61759191Skris    int fplace = 0;
61859191Skris    int padlen = 0;
61959191Skris    int zpadlen = 0;
62059191Skris    long intpart;
62159191Skris    long fracpart;
622160814Ssimon    long max10;
62359191Skris
62459191Skris    if (max < 0)
62559191Skris        max = 6;
62659191Skris    ufvalue = abs_val(fvalue);
62759191Skris    if (fvalue < 0)
62859191Skris        signvalue = '-';
62959191Skris    else if (flags & DP_F_PLUS)
63059191Skris        signvalue = '+';
63159191Skris    else if (flags & DP_F_SPACE)
63259191Skris        signvalue = ' ';
63359191Skris
63459191Skris    intpart = (long)ufvalue;
63559191Skris
636296341Sdelphij    /*
637296341Sdelphij     * sorry, we only support 9 digits past the decimal because of our
638296341Sdelphij     * conversion method
639296341Sdelphij     */
64059191Skris    if (max > 9)
64159191Skris        max = 9;
64259191Skris
643296341Sdelphij    /*
644296341Sdelphij     * we "cheat" by converting the fractional part to integer by multiplying
645296341Sdelphij     * by a factor of 10
646296341Sdelphij     */
647160814Ssimon    max10 = roundv(pow_10(max));
648160814Ssimon    fracpart = roundv(pow_10(max) * (ufvalue - intpart));
64959191Skris
650160814Ssimon    if (fracpart >= max10) {
65159191Skris        intpart++;
652160814Ssimon        fracpart -= max10;
65359191Skris    }
65459191Skris
65559191Skris    /* convert integer part */
65659191Skris    do {
657296341Sdelphij        iconvert[iplace++] = "0123456789"[intpart % 10];
65859191Skris        intpart = (intpart / 10);
659160814Ssimon    } while (intpart && (iplace < (int)sizeof(iconvert)));
660127128Snectar    if (iplace == sizeof iconvert)
66159191Skris        iplace--;
66259191Skris    iconvert[iplace] = 0;
66359191Skris
66459191Skris    /* convert fractional part */
66559191Skris    do {
666296341Sdelphij        fconvert[fplace++] = "0123456789"[fracpart % 10];
66759191Skris        fracpart = (fracpart / 10);
66879998Skris    } while (fplace < max);
669127128Snectar    if (fplace == sizeof fconvert)
67059191Skris        fplace--;
67159191Skris    fconvert[fplace] = 0;
67259191Skris
67359191Skris    /* -1 for decimal point, another -1 if we are printing a sign */
67459191Skris    padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
67559191Skris    zpadlen = max - fplace;
67659191Skris    if (zpadlen < 0)
67759191Skris        zpadlen = 0;
67859191Skris    if (padlen < 0)
67959191Skris        padlen = 0;
68059191Skris    if (flags & DP_F_MINUS)
68159191Skris        padlen = -padlen;
68259191Skris
68359191Skris    if ((flags & DP_F_ZERO) && (padlen > 0)) {
68459191Skris        if (signvalue) {
685296341Sdelphij            if (!doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue))
686296341Sdelphij                return 0;
68759191Skris            --padlen;
68859191Skris            signvalue = 0;
68959191Skris        }
69059191Skris        while (padlen > 0) {
691296341Sdelphij            if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '0'))
692296341Sdelphij                return 0;
69359191Skris            --padlen;
69459191Skris        }
69559191Skris    }
69659191Skris    while (padlen > 0) {
697296341Sdelphij        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
698296341Sdelphij            return 0;
69959191Skris        --padlen;
70059191Skris    }
701296341Sdelphij    if (signvalue && !doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue))
702296341Sdelphij        return 0;
70359191Skris
704296341Sdelphij    while (iplace > 0) {
705296341Sdelphij        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, iconvert[--iplace]))
706296341Sdelphij            return 0;
707296341Sdelphij    }
70859191Skris
70959191Skris    /*
71059191Skris     * Decimal point. This should probably use locale to find the correct
71159191Skris     * char to print out.
71259191Skris     */
713120631Snectar    if (max > 0 || (flags & DP_F_NUM)) {
714296341Sdelphij        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '.'))
715296341Sdelphij            return 0;
71659191Skris
717296341Sdelphij        while (fplace > 0) {
718296341Sdelphij            if(!doapr_outch(sbuffer, buffer, currlen, maxlen,
719296341Sdelphij                            fconvert[--fplace]))
720296341Sdelphij                return 0;
721296341Sdelphij        }
72259191Skris    }
72359191Skris    while (zpadlen > 0) {
724296341Sdelphij        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '0'))
725296341Sdelphij            return 0;
72659191Skris        --zpadlen;
72759191Skris    }
72859191Skris
72959191Skris    while (padlen < 0) {
730296341Sdelphij        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
731296341Sdelphij            return 0;
73259191Skris        ++padlen;
73359191Skris    }
734296341Sdelphij    return 1;
73559191Skris}
73659191Skris
737296341Sdelphij#define BUFFER_INC  1024
738296341Sdelphij
739296341Sdelphijstatic int
740296341Sdelphijdoapr_outch(char **sbuffer,
741296341Sdelphij            char **buffer, size_t *currlen, size_t *maxlen, int c)
74259191Skris{
74368651Skris    /* If we haven't at least one buffer, someone has doe a big booboo */
74468651Skris    assert(*sbuffer != NULL || buffer != NULL);
74559191Skris
746296341Sdelphij    /* |currlen| must always be <= |*maxlen| */
747296341Sdelphij    assert(*currlen <= *maxlen);
748296341Sdelphij
749296341Sdelphij    if (buffer && *currlen == *maxlen) {
750296341Sdelphij        if (*maxlen > INT_MAX - BUFFER_INC)
751296341Sdelphij            return 0;
752296341Sdelphij
753296341Sdelphij        *maxlen += BUFFER_INC;
754296341Sdelphij        if (*buffer == NULL) {
755296341Sdelphij            *buffer = OPENSSL_malloc(*maxlen);
756296341Sdelphij            if (*buffer == NULL)
757296341Sdelphij                return 0;
758296341Sdelphij            if (*currlen > 0) {
759296341Sdelphij                assert(*sbuffer != NULL);
760296341Sdelphij                memcpy(*buffer, *sbuffer, *currlen);
761296341Sdelphij            }
762296341Sdelphij            *sbuffer = NULL;
763296341Sdelphij        } else {
764296341Sdelphij            char *tmpbuf;
765296341Sdelphij            tmpbuf = OPENSSL_realloc(*buffer, *maxlen);
766296341Sdelphij            if (tmpbuf == NULL)
767296341Sdelphij                return 0;
768296341Sdelphij            *buffer = tmpbuf;
769296341Sdelphij        }
77059191Skris    }
77168651Skris
77268651Skris    if (*currlen < *maxlen) {
773296341Sdelphij        if (*sbuffer)
774296341Sdelphij            (*sbuffer)[(*currlen)++] = (char)c;
775296341Sdelphij        else
776296341Sdelphij            (*buffer)[(*currlen)++] = (char)c;
77759191Skris    }
77859191Skris
779296341Sdelphij    return 1;
78059191Skris}
78168651Skris
78268651Skris/***************************************************************************/
78368651Skris
784296341Sdelphijint BIO_printf(BIO *bio, const char *format, ...)
785296341Sdelphij{
786296341Sdelphij    va_list args;
787296341Sdelphij    int ret;
78868651Skris
789296341Sdelphij    va_start(args, format);
79068651Skris
791296341Sdelphij    ret = BIO_vprintf(bio, format, args);
79268651Skris
793296341Sdelphij    va_end(args);
794296341Sdelphij    return (ret);
795296341Sdelphij}
79668651Skris
797296341Sdelphijint BIO_vprintf(BIO *bio, const char *format, va_list args)
798296341Sdelphij{
799296341Sdelphij    int ret;
800296341Sdelphij    size_t retlen;
801296341Sdelphij    char hugebuf[1024 * 2];     /* Was previously 10k, which is unreasonable
802296341Sdelphij                                 * in small-stack environments, like threads
803296341Sdelphij                                 * or DOS programs. */
804296341Sdelphij    char *hugebufp = hugebuf;
805296341Sdelphij    size_t hugebufsize = sizeof(hugebuf);
806296341Sdelphij    char *dynbuf = NULL;
807296341Sdelphij    int ignored;
80868651Skris
809296341Sdelphij    dynbuf = NULL;
810296341Sdelphij    CRYPTO_push_info("doapr()");
811296341Sdelphij    if (!_dopr(&hugebufp, &dynbuf, &hugebufsize, &retlen, &ignored, format,
812296341Sdelphij                args)) {
813296341Sdelphij        OPENSSL_free(dynbuf);
814296341Sdelphij        return -1;
815296341Sdelphij    }
816296341Sdelphij    if (dynbuf) {
817296341Sdelphij        ret = BIO_write(bio, dynbuf, (int)retlen);
818296341Sdelphij        OPENSSL_free(dynbuf);
819296341Sdelphij    } else {
820296341Sdelphij        ret = BIO_write(bio, hugebuf, (int)retlen);
821296341Sdelphij    }
822296341Sdelphij    CRYPTO_pop_info();
823296341Sdelphij    return (ret);
824296341Sdelphij}
82568651Skris
826296341Sdelphij/*
827296341Sdelphij * As snprintf is not available everywhere, we provide our own
828296341Sdelphij * implementation. This function has nothing to do with BIOs, but it's
829296341Sdelphij * closely related to BIO_printf, and we need *some* name prefix ... (XXX the
830296341Sdelphij * function should be renamed, but to what?)
831296341Sdelphij */
83268651Skrisint BIO_snprintf(char *buf, size_t n, const char *format, ...)
833296341Sdelphij{
834296341Sdelphij    va_list args;
835296341Sdelphij    int ret;
83668651Skris
837296341Sdelphij    va_start(args, format);
83868651Skris
839296341Sdelphij    ret = BIO_vsnprintf(buf, n, format, args);
84068651Skris
841296341Sdelphij    va_end(args);
842296341Sdelphij    return (ret);
843296341Sdelphij}
84468651Skris
84568651Skrisint BIO_vsnprintf(char *buf, size_t n, const char *format, va_list args)
846296341Sdelphij{
847296341Sdelphij    size_t retlen;
848296341Sdelphij    int truncated;
84968651Skris
850296341Sdelphij    if(!_dopr(&buf, NULL, &n, &retlen, &truncated, format, args))
851296341Sdelphij        return -1;
85268651Skris
853296341Sdelphij    if (truncated)
854296341Sdelphij        /*
855296341Sdelphij         * In case of truncation, return -1 like traditional snprintf.
856296341Sdelphij         * (Current drafts for ISO/IEC 9899 say snprintf should return the
857296341Sdelphij         * number of characters that would have been written, had the buffer
858296341Sdelphij         * been large enough.)
859296341Sdelphij         */
860296341Sdelphij        return -1;
861296341Sdelphij    else
862296341Sdelphij        return (retlen <= INT_MAX) ? (int)retlen : -1;
863296341Sdelphij}
864