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.
8296465Sdelphij *
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).
15296465Sdelphij *
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.
22296465Sdelphij *
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 :-).
37296465Sdelphij * 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)"
40296465Sdelphij *
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.
52296465Sdelphij *
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
66296465Sdelphij/*
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
77296465Sdelphij# 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
97296465Sdelphij/*-
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
113296465Sdelphij# define LDOUBLE long double
11459191Skris#else
115296465Sdelphij# define LDOUBLE double
11659191Skris#endif
11759191Skris
11859191Skris#if HAVE_LONG_LONG
119109998Smarkm# if defined(OPENSSL_SYS_WIN32) && !defined(__GNUC__)
120296465Sdelphij#  define LLONG __int64
12179998Skris# else
122296465Sdelphij#  define LLONG long long
12379998Skris# endif
12459191Skris#else
125296465Sdelphij# define LLONG long
126296465Sdelphij#endif
127296465Sdelphij
128296465Sdelphijstatic int fmtstr(char **, char **, size_t *, size_t *,
129296465Sdelphij                   const char *, int, int, int);
130296465Sdelphijstatic int fmtint(char **, char **, size_t *, size_t *,
131296465Sdelphij                   LLONG, int, int, int, int);
132296465Sdelphijstatic int fmtfp(char **, char **, size_t *, size_t *,
133296465Sdelphij                  LDOUBLE, int, int, int);
134296465Sdelphijstatic int doapr_outch(char **, char **, size_t *, size_t *, int);
135296465Sdelphijstatic int _dopr(char **sbuffer, char **buffer,
136296465Sdelphij                  size_t *maxlen, size_t *retlen, int *truncated,
137296465Sdelphij                  const char *format, va_list args);
138296465Sdelphij
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 */
165296465Sdelphij#define char_to_int(p) (p - '0')
166296465Sdelphij#define OSSL_MAX(p,q) ((p >= q) ? p : q)
167296465Sdelphij
168296465Sdelphijstatic int
169296465Sdelphij_dopr(char **sbuffer,
170296465Sdelphij      char **buffer,
171296465Sdelphij      size_t *maxlen,
172296465Sdelphij      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:
196296465Sdelphij            if (ch == '%')
197296465Sdelphij                state = DP_S_FLAGS;
198296465Sdelphij            else
199296465Sdelphij                if(!doapr_outch(sbuffer, buffer, &currlen, maxlen, ch))
200296465Sdelphij                    return 0;
201296465Sdelphij            ch = *format++;
202296465Sdelphij            break;
203296465Sdelphij        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:
303296465Sdelphij                    value = va_arg(args, int);
304296465Sdelphij                    break;
305296465Sdelphij                }
306296465Sdelphij                if (!fmtint(sbuffer, buffer, &currlen, maxlen, value, 10, min,
307296465Sdelphij                            max, flags))
308296465Sdelphij                    return 0;
309296465Sdelphij                break;
310296465Sdelphij            case 'X':
311296465Sdelphij                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:
322296465Sdelphij                    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:
328296465Sdelphij                    value = (LLONG) va_arg(args, unsigned int);
329296465Sdelphij                    break;
330296465Sdelphij                }
331296465Sdelphij                if (!fmtint(sbuffer, buffer, &currlen, maxlen, value,
332296465Sdelphij                       ch == 'o' ? 8 : (ch == 'u' ? 10 : 16),
333296465Sdelphij                            min, max, flags))
334296465Sdelphij                    return 0;
335296465Sdelphij                break;
336296465Sdelphij            case 'f':
337296465Sdelphij                if (cflags == DP_C_LDOUBLE)
338296465Sdelphij                    fvalue = va_arg(args, LDOUBLE);
339296465Sdelphij                else
340296465Sdelphij                    fvalue = va_arg(args, double);
341296465Sdelphij                if (!fmtfp(sbuffer, buffer, &currlen, maxlen, fvalue, min, max,
342296465Sdelphij                           flags))
343296465Sdelphij                    return 0;
344296465Sdelphij                break;
345296465Sdelphij            case 'E':
346296465Sdelphij                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
359296465Sdelphij                    fvalue = va_arg(args, double);
360296465Sdelphij                break;
361296465Sdelphij            case 'c':
362296465Sdelphij                if(!doapr_outch(sbuffer, buffer, &currlen, maxlen,
363296465Sdelphij                            va_arg(args, int)))
364296465Sdelphij                    return 0;
365296465Sdelphij                break;
366296465Sdelphij            case 's':
367296465Sdelphij                strvalue = va_arg(args, char *);
36868651Skris                if (max < 0) {
369296465Sdelphij                    if (buffer)
370296465Sdelphij                        max = INT_MAX;
371296465Sdelphij                    else
372296465Sdelphij                        max = *maxlen;
373296465Sdelphij                }
374296465Sdelphij                if (!fmtstr(sbuffer, buffer, &currlen, maxlen, strvalue,
375296465Sdelphij                            flags, min, max))
376296465Sdelphij                    return 0;
377296465Sdelphij                break;
378296465Sdelphij            case 'p':
379296465Sdelphij                value = (long)va_arg(args, void *);
380296465Sdelphij                if (!fmtint(sbuffer, buffer, &currlen, maxlen,
381296465Sdelphij                            value, 16, min, max, flags | DP_F_NUM))
382296465Sdelphij                    return 0;
383296465Sdelphij                break;
384296465Sdelphij            case 'n':          /* XXX */
385296465Sdelphij                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 *);
392296465Sdelphij                    *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 {
398296465Sdelphij                    int *num;
39959191Skris                    num = va_arg(args, int *);
40059191Skris                    *num = currlen;
401296465Sdelphij                }
402296465Sdelphij                break;
403296465Sdelphij            case '%':
404296465Sdelphij                if(!doapr_outch(sbuffer, buffer, &currlen, maxlen, ch))
405296465Sdelphij                    return 0;
406296465Sdelphij                break;
407296465Sdelphij            case 'w':
408296465Sdelphij                /* 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    }
426296465Sdelphij    *truncated = (currlen > *maxlen - 1);
427296465Sdelphij    if (*truncated)
428296465Sdelphij        currlen = *maxlen - 1;
429296465Sdelphij    if(!doapr_outch(sbuffer, buffer, &currlen, maxlen, '\0'))
430296465Sdelphij        return 0;
431296465Sdelphij    *retlen = currlen - 1;
432296465Sdelphij    return 1;
433296465Sdelphij}
434296465Sdelphij
435296465Sdelphijstatic int
436296465Sdelphijfmtstr(char **sbuffer,
437296465Sdelphij       char **buffer,
438296465Sdelphij       size_t *currlen,
439296465Sdelphij       size_t *maxlen, const char *value, int flags, int min, int max)
440296465Sdelphij{
441296465Sdelphij    int padlen;
442296465Sdelphij    size_t strln;
443296465Sdelphij    int cnt = 0;
444296465Sdelphij
445296465Sdelphij    if (value == 0)
446296465Sdelphij        value = "<NULL>";
447296465Sdelphij
448296465Sdelphij    strln = strlen(value);
449296465Sdelphij    if (strln > INT_MAX)
450296465Sdelphij        strln = INT_MAX;
451296465Sdelphij
452296465Sdelphij    padlen = min - strln;
453296465Sdelphij    if (min < 0 || padlen < 0)
454296465Sdelphij        padlen = 0;
455296465Sdelphij    if (flags & DP_F_MINUS)
456296465Sdelphij        padlen = -padlen;
457296465Sdelphij
458296465Sdelphij    while ((padlen > 0) && (cnt < max)) {
459296465Sdelphij        if(!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
460296465Sdelphij            return 0;
461296465Sdelphij        --padlen;
462296465Sdelphij        ++cnt;
463296465Sdelphij    }
464296465Sdelphij    while (*value && (cnt < max)) {
465296465Sdelphij        if(!doapr_outch(sbuffer, buffer, currlen, maxlen, *value++))
466296465Sdelphij            return 0;
467296465Sdelphij        ++cnt;
468296465Sdelphij    }
469296465Sdelphij    while ((padlen < 0) && (cnt < max)) {
470296465Sdelphij        if(!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
471296465Sdelphij            return 0;
472296465Sdelphij        ++padlen;
473296465Sdelphij        ++cnt;
474296465Sdelphij    }
475296465Sdelphij    return 1;
476296465Sdelphij}
477296465Sdelphij
478296465Sdelphijstatic int
479296465Sdelphijfmtint(char **sbuffer,
480296465Sdelphij       char **buffer,
481296465Sdelphij       size_t *currlen,
482296465Sdelphij       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;
487296465Sdelphij    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) {
506296465Sdelphij        if (base == 8)
507296465Sdelphij            prefix = "0";
508296465Sdelphij        if (base == 16)
509296465Sdelphij            prefix = "0x";
510120631Snectar    }
51159191Skris    if (flags & DP_F_UP)
51259191Skris        caps = 1;
51359191Skris    do {
514296465Sdelphij        convert[place++] = (caps ? "0123456789ABCDEF" : "0123456789abcdef")
515296465Sdelphij            [uvalue % (unsigned)base];
516296465Sdelphij        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;
523296465Sdelphij    spadlen =
524296465Sdelphij        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;
535296465Sdelphij
536296465Sdelphij    /* spaces */
537296465Sdelphij    while (spadlen > 0) {
538296465Sdelphij        if(!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
539296465Sdelphij            return 0;
540296465Sdelphij        --spadlen;
541296465Sdelphij    }
542296465Sdelphij
543296465Sdelphij    /* sign */
544296465Sdelphij    if (signvalue)
545296465Sdelphij        if(!doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue))
546296465Sdelphij            return 0;
547296465Sdelphij
548296465Sdelphij    /* prefix */
549296465Sdelphij    while (*prefix) {
550296465Sdelphij        if(!doapr_outch(sbuffer, buffer, currlen, maxlen, *prefix))
551296465Sdelphij            return 0;
552296465Sdelphij        prefix++;
553296465Sdelphij    }
554296465Sdelphij
555296465Sdelphij    /* zeros */
556296465Sdelphij    if (zpadlen > 0) {
557296465Sdelphij        while (zpadlen > 0) {
558296465Sdelphij            if(!doapr_outch(sbuffer, buffer, currlen, maxlen, '0'))
559296465Sdelphij                return 0;
560296465Sdelphij            --zpadlen;
561296465Sdelphij        }
562296465Sdelphij    }
563296465Sdelphij    /* digits */
564296465Sdelphij    while (place > 0) {
565296465Sdelphij        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, convert[--place]))
566296465Sdelphij            return 0;
567296465Sdelphij    }
568296465Sdelphij
569296465Sdelphij    /* left justified spaces */
570296465Sdelphij    while (spadlen < 0) {
571296465Sdelphij        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
572296465Sdelphij            return 0;
573296465Sdelphij        ++spadlen;
574296465Sdelphij    }
575296465Sdelphij    return 1;
576296465Sdelphij}
577296465Sdelphij
578296465Sdelphijstatic LDOUBLE abs_val(LDOUBLE value)
57959191Skris{
58059191Skris    LDOUBLE result = value;
58159191Skris    if (value < 0)
58259191Skris        result = -value;
58359191Skris    return result;
58459191Skris}
58559191Skris
586296465Sdelphijstatic 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
596296465Sdelphijstatic long roundv(LDOUBLE value)
59759191Skris{
59859191Skris    long intpart;
599296465Sdelphij    intpart = (long)value;
60059191Skris    value = value - intpart;
60159191Skris    if (value >= 0.5)
60259191Skris        intpart++;
603296465Sdelphij    return intpart;
604296465Sdelphij}
605296465Sdelphij
606296465Sdelphijstatic int
607296465Sdelphijfmtfp(char **sbuffer,
608296465Sdelphij      char **buffer,
609296465Sdelphij      size_t *currlen,
610296465Sdelphij      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    int caps = 0;
62159191Skris    long intpart;
62259191Skris    long fracpart;
623160814Ssimon    long max10;
62459191Skris
62559191Skris    if (max < 0)
62659191Skris        max = 6;
62759191Skris    ufvalue = abs_val(fvalue);
62859191Skris    if (fvalue < 0)
62959191Skris        signvalue = '-';
63059191Skris    else if (flags & DP_F_PLUS)
63159191Skris        signvalue = '+';
63259191Skris    else if (flags & DP_F_SPACE)
63359191Skris        signvalue = ' ';
63459191Skris
63559191Skris    intpart = (long)ufvalue;
63659191Skris
637296465Sdelphij    /*
638296465Sdelphij     * sorry, we only support 9 digits past the decimal because of our
639296465Sdelphij     * conversion method
640296465Sdelphij     */
64159191Skris    if (max > 9)
64259191Skris        max = 9;
64359191Skris
644296465Sdelphij    /*
645296465Sdelphij     * we "cheat" by converting the fractional part to integer by multiplying
646296465Sdelphij     * by a factor of 10
647296465Sdelphij     */
648160814Ssimon    max10 = roundv(pow_10(max));
649160814Ssimon    fracpart = roundv(pow_10(max) * (ufvalue - intpart));
65059191Skris
651160814Ssimon    if (fracpart >= max10) {
65259191Skris        intpart++;
653160814Ssimon        fracpart -= max10;
65459191Skris    }
65559191Skris
65659191Skris    /* convert integer part */
65759191Skris    do {
65859191Skris        iconvert[iplace++] =
659296465Sdelphij            (caps ? "0123456789ABCDEF" : "0123456789abcdef")[intpart % 10];
66059191Skris        intpart = (intpart / 10);
661160814Ssimon    } while (intpart && (iplace < (int)sizeof(iconvert)));
662127128Snectar    if (iplace == sizeof iconvert)
66359191Skris        iplace--;
66459191Skris    iconvert[iplace] = 0;
66559191Skris
66659191Skris    /* convert fractional part */
66759191Skris    do {
66859191Skris        fconvert[fplace++] =
669296465Sdelphij            (caps ? "0123456789ABCDEF" : "0123456789abcdef")[fracpart % 10];
67059191Skris        fracpart = (fracpart / 10);
67179998Skris    } while (fplace < max);
672127128Snectar    if (fplace == sizeof fconvert)
67359191Skris        fplace--;
67459191Skris    fconvert[fplace] = 0;
67559191Skris
67659191Skris    /* -1 for decimal point, another -1 if we are printing a sign */
67759191Skris    padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
67859191Skris    zpadlen = max - fplace;
67959191Skris    if (zpadlen < 0)
68059191Skris        zpadlen = 0;
68159191Skris    if (padlen < 0)
68259191Skris        padlen = 0;
68359191Skris    if (flags & DP_F_MINUS)
68459191Skris        padlen = -padlen;
685296465Sdelphij
686296465Sdelphij    if ((flags & DP_F_ZERO) && (padlen > 0)) {
687296465Sdelphij        if (signvalue) {
688296465Sdelphij            if (!doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue))
689296465Sdelphij                return 0;
690296465Sdelphij            --padlen;
691296465Sdelphij            signvalue = 0;
692296465Sdelphij        }
693296465Sdelphij        while (padlen > 0) {
694296465Sdelphij            if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '0'))
695296465Sdelphij                return 0;
696296465Sdelphij            --padlen;
697296465Sdelphij        }
698296465Sdelphij    }
699296465Sdelphij    while (padlen > 0) {
700296465Sdelphij        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
701296465Sdelphij            return 0;
702296465Sdelphij        --padlen;
703296465Sdelphij    }
704296465Sdelphij    if (signvalue && !doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue))
705296465Sdelphij        return 0;
706296465Sdelphij
707296465Sdelphij    while (iplace > 0) {
708296465Sdelphij        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, iconvert[--iplace]))
709296465Sdelphij            return 0;
710296465Sdelphij    }
711296465Sdelphij
712296465Sdelphij    /*
713296465Sdelphij     * Decimal point. This should probably use locale to find the correct
714296465Sdelphij     * char to print out.
715296465Sdelphij     */
716296465Sdelphij    if (max > 0 || (flags & DP_F_NUM)) {
717296465Sdelphij        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '.'))
718296465Sdelphij            return 0;
719296465Sdelphij
720296465Sdelphij        while (fplace > 0) {
721296465Sdelphij            if(!doapr_outch(sbuffer, buffer, currlen, maxlen,
722296465Sdelphij                            fconvert[--fplace]))
723296465Sdelphij                return 0;
724296465Sdelphij        }
725296465Sdelphij    }
726296465Sdelphij    while (zpadlen > 0) {
727296465Sdelphij        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '0'))
728296465Sdelphij            return 0;
729296465Sdelphij        --zpadlen;
730296465Sdelphij    }
731296465Sdelphij
732296465Sdelphij    while (padlen < 0) {
733296465Sdelphij        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
734296465Sdelphij            return 0;
735296465Sdelphij        ++padlen;
736296465Sdelphij    }
737296465Sdelphij    return 1;
738296465Sdelphij}
739296465Sdelphij
740296465Sdelphij#define BUFFER_INC  1024
741296465Sdelphij
742296465Sdelphijstatic int
743296465Sdelphijdoapr_outch(char **sbuffer,
744296465Sdelphij            char **buffer, size_t *currlen, size_t *maxlen, int c)
745296465Sdelphij{
746296465Sdelphij    /* If we haven't at least one buffer, someone has doe a big booboo */
747296465Sdelphij    assert(*sbuffer != NULL || buffer != NULL);
748296465Sdelphij
749296465Sdelphij    /* |currlen| must always be <= |*maxlen| */
750296465Sdelphij    assert(*currlen <= *maxlen);
751296465Sdelphij
752296465Sdelphij    if (buffer && *currlen == *maxlen) {
753296465Sdelphij        if (*maxlen > INT_MAX - BUFFER_INC)
754296465Sdelphij            return 0;
755296465Sdelphij
756296465Sdelphij        *maxlen += BUFFER_INC;
757296465Sdelphij            if (*buffer == NULL) {
758296465Sdelphij                *buffer = OPENSSL_malloc(*maxlen);
759296465Sdelphij                if (*buffer == NULL)
760296465Sdelphij                    return 0;
761296465Sdelphij                if (*currlen > 0) {
762296465Sdelphij                    assert(*sbuffer != NULL);
763296465Sdelphij                    memcpy(*buffer, *sbuffer, *currlen);
764296465Sdelphij                }
765296465Sdelphij                *sbuffer = NULL;
766296465Sdelphij            } else {
767296465Sdelphij                char *tmpbuf;
768296465Sdelphij                tmpbuf = OPENSSL_realloc(*buffer, *maxlen);
769296465Sdelphij                if (tmpbuf == NULL)
770296465Sdelphij                    return 0;
771296465Sdelphij                *buffer = tmpbuf;
772296465Sdelphij            }
773296465Sdelphij        }
774296465Sdelphij
775296465Sdelphij    if (*currlen < *maxlen) {
776296465Sdelphij        if (*sbuffer)
777296465Sdelphij            (*sbuffer)[(*currlen)++] = (char)c;
778296465Sdelphij        else
779296465Sdelphij            (*buffer)[(*currlen)++] = (char)c;
780296465Sdelphij    }
781296465Sdelphij
782296465Sdelphij    return 1;
783296465Sdelphij}
784296465Sdelphij
785296465Sdelphij/***************************************************************************/
78659191Skris
787296465Sdelphijint BIO_printf(BIO *bio, const char *format, ...)
788296465Sdelphij{
789296465Sdelphij    va_list args;
790296465Sdelphij    int ret;
79159191Skris
792296465Sdelphij    va_start(args, format);
79359191Skris
794296465Sdelphij    ret = BIO_vprintf(bio, format, args);
79559191Skris
796296465Sdelphij    va_end(args);
797296465Sdelphij    return (ret);
79859191Skris}
79959191Skris
800296465Sdelphijint BIO_vprintf(BIO *bio, const char *format, va_list args)
80159191Skris{
802296465Sdelphij    int ret;
803296465Sdelphij    size_t retlen;
804296465Sdelphij    char hugebuf[1024 * 2];     /* Was previously 10k, which is unreasonable
805296465Sdelphij                                 * in small-stack environments, like threads
806296465Sdelphij                                 * or DOS programs. */
807296465Sdelphij    char *hugebufp = hugebuf;
808296465Sdelphij    size_t hugebufsize = sizeof(hugebuf);
809296465Sdelphij    char *dynbuf = NULL;
810296465Sdelphij    int ignored;
811296465Sdelphij
812296465Sdelphij    dynbuf = NULL;
813296465Sdelphij    CRYPTO_push_info("doapr()");
814296465Sdelphij    if (!_dopr(&hugebufp, &dynbuf, &hugebufsize, &retlen, &ignored, format,
815296465Sdelphij                args)) {
816296465Sdelphij        OPENSSL_free(dynbuf);
817296465Sdelphij        return -1;
818296465Sdelphij    }
819296465Sdelphij    if (dynbuf) {
820296465Sdelphij        ret = BIO_write(bio, dynbuf, (int)retlen);
821296465Sdelphij        OPENSSL_free(dynbuf);
822296465Sdelphij    } else {
823296465Sdelphij        ret = BIO_write(bio, hugebuf, (int)retlen);
82459191Skris    }
825296465Sdelphij    CRYPTO_pop_info();
826296465Sdelphij    return (ret);
82759191Skris}
82868651Skris
829296465Sdelphij/*
830296465Sdelphij * As snprintf is not available everywhere, we provide our own
831296465Sdelphij * implementation. This function has nothing to do with BIOs, but it's
832296465Sdelphij * closely related to BIO_printf, and we need *some* name prefix ... (XXX the
833296465Sdelphij * function should be renamed, but to what?)
834296465Sdelphij */
83568651Skrisint BIO_snprintf(char *buf, size_t n, const char *format, ...)
836296465Sdelphij{
837296465Sdelphij    va_list args;
838296465Sdelphij    int ret;
83968651Skris
840296465Sdelphij    va_start(args, format);
84168651Skris
842296465Sdelphij    ret = BIO_vsnprintf(buf, n, format, args);
84368651Skris
844296465Sdelphij    va_end(args);
845296465Sdelphij    return (ret);
846296465Sdelphij}
84768651Skris
84868651Skrisint BIO_vsnprintf(char *buf, size_t n, const char *format, va_list args)
849296465Sdelphij{
850296465Sdelphij    size_t retlen;
851296465Sdelphij    int truncated;
852296465Sdelphij
853296465Sdelphij    if(!_dopr(&buf, NULL, &n, &retlen, &truncated, format, args))
854296465Sdelphij        return -1;
855296465Sdelphij
856296465Sdelphij    if (truncated)
857296465Sdelphij        /*
858296465Sdelphij         * In case of truncation, return -1 like traditional snprintf.
859296465Sdelphij         * (Current drafts for ISO/IEC 9899 say snprintf should return the
860296465Sdelphij         * number of characters that would have been written, had the buffer
861296465Sdelphij         * been large enough.)
862296465Sdelphij         */
863296465Sdelphij        return -1;
864296465Sdelphij    else
865296465Sdelphij        return (retlen <= INT_MAX) ? (int)retlen : -1;
866296465Sdelphij}
867