Home | History | Annotate | Download | only in bio
      1 /* crypto/bio/b_print.c */
      2 /* Copyright (C) 1995-1998 Eric Young (eay (at) cryptsoft.com)
      3  * All rights reserved.
      4  *
      5  * This package is an SSL implementation written
      6  * by Eric Young (eay (at) cryptsoft.com).
      7  * The implementation was written so as to conform with Netscapes SSL.
      8  *
      9  * This library is free for commercial and non-commercial use as long as
     10  * the following conditions are aheared to.  The following conditions
     11  * apply to all code found in this distribution, be it the RC4, RSA,
     12  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
     13  * included with this distribution is covered by the same copyright terms
     14  * except that the holder is Tim Hudson (tjh (at) cryptsoft.com).
     15  *
     16  * Copyright remains Eric Young's, and as such any Copyright notices in
     17  * the code are not to be removed.
     18  * If this package is used in a product, Eric Young should be given attribution
     19  * as the author of the parts of the library used.
     20  * This can be in the form of a textual message at program startup or
     21  * in documentation (online or textual) provided with the package.
     22  *
     23  * Redistribution and use in source and binary forms, with or without
     24  * modification, are permitted provided that the following conditions
     25  * are met:
     26  * 1. Redistributions of source code must retain the copyright
     27  *    notice, this list of conditions and the following disclaimer.
     28  * 2. Redistributions in binary form must reproduce the above copyright
     29  *    notice, this list of conditions and the following disclaimer in the
     30  *    documentation and/or other materials provided with the distribution.
     31  * 3. All advertising materials mentioning features or use of this software
     32  *    must display the following acknowledgement:
     33  *    "This product includes cryptographic software written by
     34  *     Eric Young (eay (at) cryptsoft.com)"
     35  *    The word 'cryptographic' can be left out if the rouines from the library
     36  *    being used are not cryptographic related :-).
     37  * 4. If you include any Windows specific code (or a derivative thereof) from
     38  *    the apps directory (application code) you must include an acknowledgement:
     39  *    "This product includes software written by Tim Hudson (tjh (at) cryptsoft.com)"
     40  *
     41  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
     42  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     43  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     44  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     45  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     46  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     47  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     48  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     49  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     50  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     51  * SUCH DAMAGE.
     52  *
     53  * The licence and distribution terms for any publically available version or
     54  * derivative of this code cannot be changed.  i.e. this code cannot simply be
     55  * copied and put under another distribution licence
     56  * [including the GNU Public Licence.]
     57  */
     58 
     59 /* disable assert() unless BIO_DEBUG has been defined */
     60 #ifndef BIO_DEBUG
     61 # ifndef NDEBUG
     62 #  define NDEBUG
     63 # endif
     64 #endif
     65 
     66 /*
     67  * Stolen from tjh's ssl/ssl_trc.c stuff.
     68  */
     69 
     70 #include <stdio.h>
     71 #include <string.h>
     72 #include <ctype.h>
     73 #include <assert.h>
     74 #include <limits.h>
     75 #include "cryptlib.h"
     76 #ifndef NO_SYS_TYPES_H
     77 #include <sys/types.h>
     78 #endif
     79 #include <openssl/bn.h>         /* To get BN_LLONG properly defined */
     80 #include <openssl/bio.h>
     81 
     82 #if defined(BN_LLONG) || defined(SIXTY_FOUR_BIT)
     83 # ifndef HAVE_LONG_LONG
     84 #  define HAVE_LONG_LONG 1
     85 # endif
     86 #endif
     87 
     88 /***************************************************************************/
     89 
     90 /*
     91  * Copyright Patrick Powell 1995
     92  * This code is based on code written by Patrick Powell <papowell (at) astart.com>
     93  * It may be used for any purpose as long as this notice remains intact
     94  * on all source code distributions.
     95  */
     96 
     97 /*
     98  * This code contains numerious changes and enhancements which were
     99  * made by lots of contributors over the last years to Patrick Powell's
    100  * original code:
    101  *
    102  * o Patrick Powell <papowell (at) astart.com>      (1995)
    103  * o Brandon Long <blong (at) fiction.net>          (1996, for Mutt)
    104  * o Thomas Roessler <roessler (at) guug.de>        (1998, for Mutt)
    105  * o Michael Elkins <me (at) cs.hmc.edu>            (1998, for Mutt)
    106  * o Andrew Tridgell <tridge (at) samba.org>        (1998, for Samba)
    107  * o Luke Mewburn <lukem (at) netbsd.org>           (1999, for LukemFTP)
    108  * o Ralf S. Engelschall <rse (at) engelschall.com> (1999, for Pth)
    109  * o ...                                       (for OpenSSL)
    110  */
    111 
    112 #ifdef HAVE_LONG_DOUBLE
    113 #define LDOUBLE long double
    114 #else
    115 #define LDOUBLE double
    116 #endif
    117 
    118 #ifdef HAVE_LONG_LONG
    119 # if defined(_WIN32) && !defined(__GNUC__)
    120 # define LLONG __int64
    121 # else
    122 # define LLONG long long
    123 # endif
    124 #else
    125 #define LLONG long
    126 #endif
    127 
    128 static void fmtstr     (char **, char **, size_t *, size_t *,
    129 			const char *, int, int, int);
    130 static void fmtint     (char **, char **, size_t *, size_t *,
    131 			LLONG, int, int, int, int);
    132 static void fmtfp      (char **, char **, size_t *, size_t *,
    133 			LDOUBLE, int, int, int);
    134 static void doapr_outch (char **, char **, size_t *, size_t *, int);
    135 static void _dopr(char **sbuffer, char **buffer,
    136 		  size_t *maxlen, size_t *retlen, int *truncated,
    137 		  const char *format, va_list args);
    138 
    139 /* format read states */
    140 #define DP_S_DEFAULT    0
    141 #define DP_S_FLAGS      1
    142 #define DP_S_MIN        2
    143 #define DP_S_DOT        3
    144 #define DP_S_MAX        4
    145 #define DP_S_MOD        5
    146 #define DP_S_CONV       6
    147 #define DP_S_DONE       7
    148 
    149 /* format flags - Bits */
    150 #define DP_F_MINUS      (1 << 0)
    151 #define DP_F_PLUS       (1 << 1)
    152 #define DP_F_SPACE      (1 << 2)
    153 #define DP_F_NUM        (1 << 3)
    154 #define DP_F_ZERO       (1 << 4)
    155 #define DP_F_UP         (1 << 5)
    156 #define DP_F_UNSIGNED   (1 << 6)
    157 
    158 /* conversion flags */
    159 #define DP_C_SHORT      1
    160 #define DP_C_LONG       2
    161 #define DP_C_LDOUBLE    3
    162 #define DP_C_LLONG      4
    163 
    164 /* some handy macros */
    165 #define char_to_int(p) (p - '0')
    166 #define OSSL_MAX(p,q) ((p >= q) ? p : q)
    167 
    168 static void
    169 _dopr(
    170     char **sbuffer,
    171     char **buffer,
    172     size_t *maxlen,
    173     size_t *retlen,
    174     int *truncated,
    175     const char *format,
    176     va_list args)
    177 {
    178     char ch;
    179     LLONG value;
    180     LDOUBLE fvalue;
    181     char *strvalue;
    182     int min;
    183     int max;
    184     int state;
    185     int flags;
    186     int cflags;
    187     size_t currlen;
    188 
    189     state = DP_S_DEFAULT;
    190     flags = currlen = cflags = min = 0;
    191     max = -1;
    192     ch = *format++;
    193 
    194     while (state != DP_S_DONE) {
    195         if (ch == '\0' || (buffer == NULL && currlen >= *maxlen))
    196             state = DP_S_DONE;
    197 
    198         switch (state) {
    199         case DP_S_DEFAULT:
    200             if (ch == '%')
    201                 state = DP_S_FLAGS;
    202             else
    203                 doapr_outch(sbuffer,buffer, &currlen, maxlen, ch);
    204             ch = *format++;
    205             break;
    206         case DP_S_FLAGS:
    207             switch (ch) {
    208             case '-':
    209                 flags |= DP_F_MINUS;
    210                 ch = *format++;
    211                 break;
    212             case '+':
    213                 flags |= DP_F_PLUS;
    214                 ch = *format++;
    215                 break;
    216             case ' ':
    217                 flags |= DP_F_SPACE;
    218                 ch = *format++;
    219                 break;
    220             case '#':
    221                 flags |= DP_F_NUM;
    222                 ch = *format++;
    223                 break;
    224             case '0':
    225                 flags |= DP_F_ZERO;
    226                 ch = *format++;
    227                 break;
    228             default:
    229                 state = DP_S_MIN;
    230                 break;
    231             }
    232             break;
    233         case DP_S_MIN:
    234             if (isdigit((unsigned char)ch)) {
    235                 min = 10 * min + char_to_int(ch);
    236                 ch = *format++;
    237             } else if (ch == '*') {
    238                 min = va_arg(args, int);
    239                 ch = *format++;
    240                 state = DP_S_DOT;
    241             } else
    242                 state = DP_S_DOT;
    243             break;
    244         case DP_S_DOT:
    245             if (ch == '.') {
    246                 state = DP_S_MAX;
    247                 ch = *format++;
    248             } else
    249                 state = DP_S_MOD;
    250             break;
    251         case DP_S_MAX:
    252             if (isdigit((unsigned char)ch)) {
    253                 if (max < 0)
    254                     max = 0;
    255                 max = 10 * max + char_to_int(ch);
    256                 ch = *format++;
    257             } else if (ch == '*') {
    258                 max = va_arg(args, int);
    259                 ch = *format++;
    260                 state = DP_S_MOD;
    261             } else
    262                 state = DP_S_MOD;
    263             break;
    264         case DP_S_MOD:
    265             switch (ch) {
    266             case 'h':
    267                 cflags = DP_C_SHORT;
    268                 ch = *format++;
    269                 break;
    270             case 'l':
    271                 if (*format == 'l') {
    272                     cflags = DP_C_LLONG;
    273                     format++;
    274                 } else
    275                     cflags = DP_C_LONG;
    276                 ch = *format++;
    277                 break;
    278             case 'q':
    279                 cflags = DP_C_LLONG;
    280                 ch = *format++;
    281                 break;
    282             case 'L':
    283                 cflags = DP_C_LDOUBLE;
    284                 ch = *format++;
    285                 break;
    286             default:
    287                 break;
    288             }
    289             state = DP_S_CONV;
    290             break;
    291         case DP_S_CONV:
    292             switch (ch) {
    293             case 'd':
    294             case 'i':
    295                 switch (cflags) {
    296                 case DP_C_SHORT:
    297                     value = (short int)va_arg(args, int);
    298                     break;
    299                 case DP_C_LONG:
    300                     value = va_arg(args, long int);
    301                     break;
    302                 case DP_C_LLONG:
    303                     value = va_arg(args, LLONG);
    304                     break;
    305                 default:
    306                     value = va_arg(args, int);
    307                     break;
    308                 }
    309                 fmtint(sbuffer, buffer, &currlen, maxlen,
    310                        value, 10, min, max, flags);
    311                 break;
    312             case 'X':
    313                 flags |= DP_F_UP;
    314                 /* FALLTHROUGH */
    315             case 'x':
    316             case 'o':
    317             case 'u':
    318                 flags |= DP_F_UNSIGNED;
    319                 switch (cflags) {
    320                 case DP_C_SHORT:
    321                     value = (unsigned short int)va_arg(args, unsigned int);
    322                     break;
    323                 case DP_C_LONG:
    324                     value = (LLONG) va_arg(args,
    325                         unsigned long int);
    326                     break;
    327                 case DP_C_LLONG:
    328                     value = va_arg(args, unsigned LLONG);
    329                     break;
    330                 default:
    331                     value = (LLONG) va_arg(args,
    332                         unsigned int);
    333                     break;
    334                 }
    335                 fmtint(sbuffer, buffer, &currlen, maxlen, value,
    336                        ch == 'o' ? 8 : (ch == 'u' ? 10 : 16),
    337                        min, max, flags);
    338                 break;
    339             case 'f':
    340                 if (cflags == DP_C_LDOUBLE)
    341                     fvalue = va_arg(args, LDOUBLE);
    342                 else
    343                     fvalue = va_arg(args, double);
    344                 fmtfp(sbuffer, buffer, &currlen, maxlen,
    345                       fvalue, min, max, flags);
    346                 break;
    347             case 'E':
    348                 flags |= DP_F_UP;
    349             case 'e':
    350                 if (cflags == DP_C_LDOUBLE)
    351                     fvalue = va_arg(args, LDOUBLE);
    352                 else
    353                     fvalue = va_arg(args, double);
    354                 break;
    355             case 'G':
    356                 flags |= DP_F_UP;
    357             case 'g':
    358                 if (cflags == DP_C_LDOUBLE)
    359                     fvalue = va_arg(args, LDOUBLE);
    360                 else
    361                     fvalue = va_arg(args, double);
    362                 break;
    363             case 'c':
    364                 doapr_outch(sbuffer, buffer, &currlen, maxlen,
    365                     va_arg(args, int));
    366                 break;
    367             case 's':
    368                 strvalue = va_arg(args, char *);
    369                 if (max < 0) {
    370 		    if (buffer)
    371 			max = INT_MAX;
    372 		    else
    373 			max = *maxlen;
    374 		}
    375                 fmtstr(sbuffer, buffer, &currlen, maxlen, strvalue,
    376                        flags, min, max);
    377                 break;
    378             case 'p':
    379                 value = (long)va_arg(args, void *);
    380                 fmtint(sbuffer, buffer, &currlen, maxlen,
    381                     value, 16, min, max, flags|DP_F_NUM);
    382                 break;
    383             case 'n': /* XXX */
    384                 if (cflags == DP_C_SHORT) {
    385                     short int *num;
    386                     num = va_arg(args, short int *);
    387                     *num = currlen;
    388                 } else if (cflags == DP_C_LONG) { /* XXX */
    389                     long int *num;
    390                     num = va_arg(args, long int *);
    391                     *num = (long int) currlen;
    392                 } else if (cflags == DP_C_LLONG) { /* XXX */
    393                     LLONG *num;
    394                     num = va_arg(args, LLONG *);
    395                     *num = (LLONG) currlen;
    396                 } else {
    397                     int    *num;
    398                     num = va_arg(args, int *);
    399                     *num = currlen;
    400                 }
    401                 break;
    402             case '%':
    403                 doapr_outch(sbuffer, buffer, &currlen, maxlen, ch);
    404                 break;
    405             case 'w':
    406                 /* not supported yet, treat as next char */
    407                 ch = *format++;
    408                 break;
    409             default:
    410                 /* unknown, skip */
    411                 break;
    412             }
    413             ch = *format++;
    414             state = DP_S_DEFAULT;
    415             flags = cflags = min = 0;
    416             max = -1;
    417             break;
    418         case DP_S_DONE:
    419             break;
    420         default:
    421             break;
    422         }
    423     }
    424     *truncated = (currlen > *maxlen - 1);
    425     if (*truncated)
    426         currlen = *maxlen - 1;
    427     doapr_outch(sbuffer, buffer, &currlen, maxlen, '\0');
    428     *retlen = currlen - 1;
    429     return;
    430 }
    431 
    432 static void
    433 fmtstr(
    434     char **sbuffer,
    435     char **buffer,
    436     size_t *currlen,
    437     size_t *maxlen,
    438     const char *value,
    439     int flags,
    440     int min,
    441     int max)
    442 {
    443     int padlen, strln;
    444     int cnt = 0;
    445 
    446     if (value == 0)
    447         value = "<NULL>";
    448     for (strln = 0; value[strln]; ++strln)
    449         ;
    450     padlen = min - strln;
    451     if (padlen < 0)
    452         padlen = 0;
    453     if (flags & DP_F_MINUS)
    454         padlen = -padlen;
    455 
    456     while ((padlen > 0) && (cnt < max)) {
    457         doapr_outch(sbuffer, buffer, currlen, maxlen, ' ');
    458         --padlen;
    459         ++cnt;
    460     }
    461     while (*value && (cnt < max)) {
    462         doapr_outch(sbuffer, buffer, currlen, maxlen, *value++);
    463         ++cnt;
    464     }
    465     while ((padlen < 0) && (cnt < max)) {
    466         doapr_outch(sbuffer, buffer, currlen, maxlen, ' ');
    467         ++padlen;
    468         ++cnt;
    469     }
    470 }
    471 
    472 static void
    473 fmtint(
    474     char **sbuffer,
    475     char **buffer,
    476     size_t *currlen,
    477     size_t *maxlen,
    478     LLONG value,
    479     int base,
    480     int min,
    481     int max,
    482     int flags)
    483 {
    484     int signvalue = 0;
    485     const char *prefix = "";
    486     unsigned LLONG uvalue;
    487     char convert[DECIMAL_SIZE(value)+3];
    488     int place = 0;
    489     int spadlen = 0;
    490     int zpadlen = 0;
    491     int caps = 0;
    492 
    493     if (max < 0)
    494         max = 0;
    495     uvalue = value;
    496     if (!(flags & DP_F_UNSIGNED)) {
    497         if (value < 0) {
    498             signvalue = '-';
    499             uvalue = -value;
    500         } else if (flags & DP_F_PLUS)
    501             signvalue = '+';
    502         else if (flags & DP_F_SPACE)
    503             signvalue = ' ';
    504     }
    505     if (flags & DP_F_NUM) {
    506 	if (base == 8) prefix = "0";
    507 	if (base == 16) prefix = "0x";
    508     }
    509     if (flags & DP_F_UP)
    510         caps = 1;
    511     do {
    512         convert[place++] =
    513             (caps ? "0123456789ABCDEF" : "0123456789abcdef")
    514             [uvalue % (unsigned) base];
    515         uvalue = (uvalue / (unsigned) base);
    516     } while (uvalue && (place < (int)sizeof(convert)));
    517     if (place == sizeof(convert))
    518         place--;
    519     convert[place] = 0;
    520 
    521     zpadlen = max - place;
    522     spadlen = min - OSSL_MAX(max, place) - (signvalue ? 1 : 0) - strlen(prefix);
    523     if (zpadlen < 0)
    524         zpadlen = 0;
    525     if (spadlen < 0)
    526         spadlen = 0;
    527     if (flags & DP_F_ZERO) {
    528         zpadlen = OSSL_MAX(zpadlen, spadlen);
    529         spadlen = 0;
    530     }
    531     if (flags & DP_F_MINUS)
    532         spadlen = -spadlen;
    533 
    534     /* spaces */
    535     while (spadlen > 0) {
    536         doapr_outch(sbuffer, buffer, currlen, maxlen, ' ');
    537         --spadlen;
    538     }
    539 
    540     /* sign */
    541     if (signvalue)
    542         doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue);
    543 
    544     /* prefix */
    545     while (*prefix) {
    546 	doapr_outch(sbuffer, buffer, currlen, maxlen, *prefix);
    547 	prefix++;
    548     }
    549 
    550     /* zeros */
    551     if (zpadlen > 0) {
    552         while (zpadlen > 0) {
    553             doapr_outch(sbuffer, buffer, currlen, maxlen, '0');
    554             --zpadlen;
    555         }
    556     }
    557     /* digits */
    558     while (place > 0)
    559         doapr_outch(sbuffer, buffer, currlen, maxlen, convert[--place]);
    560 
    561     /* left justified spaces */
    562     while (spadlen < 0) {
    563         doapr_outch(sbuffer, buffer, currlen, maxlen, ' ');
    564         ++spadlen;
    565     }
    566     return;
    567 }
    568 
    569 static LDOUBLE
    570 abs_val(LDOUBLE value)
    571 {
    572     LDOUBLE result = value;
    573     if (value < 0)
    574         result = -value;
    575     return result;
    576 }
    577 
    578 static LDOUBLE
    579 pow_10(int in_exp)
    580 {
    581     LDOUBLE result = 1;
    582     while (in_exp) {
    583         result *= 10;
    584         in_exp--;
    585     }
    586     return result;
    587 }
    588 
    589 static long
    590 roundv(LDOUBLE value)
    591 {
    592     long intpart;
    593     intpart = (long) value;
    594     value = value - intpart;
    595     if (value >= 0.5)
    596         intpart++;
    597     return intpart;
    598 }
    599 
    600 static void
    601 fmtfp(
    602     char **sbuffer,
    603     char **buffer,
    604     size_t *currlen,
    605     size_t *maxlen,
    606     LDOUBLE fvalue,
    607     int min,
    608     int max,
    609     int flags)
    610 {
    611     int signvalue = 0;
    612     LDOUBLE ufvalue;
    613     char iconvert[20];
    614     char fconvert[20];
    615     int iplace = 0;
    616     int fplace = 0;
    617     int padlen = 0;
    618     int zpadlen = 0;
    619     int caps = 0;
    620     long intpart;
    621     long fracpart;
    622     long max10;
    623 
    624     if (max < 0)
    625         max = 6;
    626     ufvalue = abs_val(fvalue);
    627     if (fvalue < 0)
    628         signvalue = '-';
    629     else if (flags & DP_F_PLUS)
    630         signvalue = '+';
    631     else if (flags & DP_F_SPACE)
    632         signvalue = ' ';
    633 
    634     intpart = (long)ufvalue;
    635 
    636     /* sorry, we only support 9 digits past the decimal because of our
    637        conversion method */
    638     if (max > 9)
    639         max = 9;
    640 
    641     /* we "cheat" by converting the fractional part to integer by
    642        multiplying by a factor of 10 */
    643     max10 = roundv(pow_10(max));
    644     fracpart = roundv(pow_10(max) * (ufvalue - intpart));
    645 
    646     if (fracpart >= max10) {
    647         intpart++;
    648         fracpart -= max10;
    649     }
    650 
    651     /* convert integer part */
    652     do {
    653         iconvert[iplace++] =
    654             (caps ? "0123456789ABCDEF"
    655               : "0123456789abcdef")[intpart % 10];
    656         intpart = (intpart / 10);
    657     } while (intpart && (iplace < (int)sizeof(iconvert)));
    658     if (iplace == sizeof iconvert)
    659         iplace--;
    660     iconvert[iplace] = 0;
    661 
    662     /* convert fractional part */
    663     do {
    664         fconvert[fplace++] =
    665             (caps ? "0123456789ABCDEF"
    666               : "0123456789abcdef")[fracpart % 10];
    667         fracpart = (fracpart / 10);
    668     } while (fplace < max);
    669     if (fplace == sizeof fconvert)
    670         fplace--;
    671     fconvert[fplace] = 0;
    672 
    673     /* -1 for decimal point, another -1 if we are printing a sign */
    674     padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
    675     zpadlen = max - fplace;
    676     if (zpadlen < 0)
    677         zpadlen = 0;
    678     if (padlen < 0)
    679         padlen = 0;
    680     if (flags & DP_F_MINUS)
    681         padlen = -padlen;
    682 
    683     if ((flags & DP_F_ZERO) && (padlen > 0)) {
    684         if (signvalue) {
    685             doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue);
    686             --padlen;
    687             signvalue = 0;
    688         }
    689         while (padlen > 0) {
    690             doapr_outch(sbuffer, buffer, currlen, maxlen, '0');
    691             --padlen;
    692         }
    693     }
    694     while (padlen > 0) {
    695         doapr_outch(sbuffer, buffer, currlen, maxlen, ' ');
    696         --padlen;
    697     }
    698     if (signvalue)
    699         doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue);
    700 
    701     while (iplace > 0)
    702         doapr_outch(sbuffer, buffer, currlen, maxlen, iconvert[--iplace]);
    703 
    704     /*
    705      * Decimal point. This should probably use locale to find the correct
    706      * char to print out.
    707      */
    708     if (max > 0 || (flags & DP_F_NUM)) {
    709         doapr_outch(sbuffer, buffer, currlen, maxlen, '.');
    710 
    711         while (fplace > 0)
    712             doapr_outch(sbuffer, buffer, currlen, maxlen, fconvert[--fplace]);
    713     }
    714     while (zpadlen > 0) {
    715         doapr_outch(sbuffer, buffer, currlen, maxlen, '0');
    716         --zpadlen;
    717     }
    718 
    719     while (padlen < 0) {
    720         doapr_outch(sbuffer, buffer, currlen, maxlen, ' ');
    721         ++padlen;
    722     }
    723 }
    724 
    725 static void
    726 doapr_outch(
    727     char **sbuffer,
    728     char **buffer,
    729     size_t *currlen,
    730     size_t *maxlen,
    731     int c)
    732 {
    733     /* If we haven't at least one buffer, someone has doe a big booboo */
    734     assert(*sbuffer != NULL || buffer != NULL);
    735 
    736     if (buffer) {
    737 	while (*currlen >= *maxlen) {
    738 	    if (*buffer == NULL) {
    739 		if (*maxlen == 0)
    740 		    *maxlen = 1024;
    741 		*buffer = OPENSSL_malloc(*maxlen);
    742 		if (*currlen > 0) {
    743 		    assert(*sbuffer != NULL);
    744 		    memcpy(*buffer, *sbuffer, *currlen);
    745 		}
    746 		*sbuffer = NULL;
    747 	    } else {
    748 		*maxlen += 1024;
    749 		*buffer = OPENSSL_realloc(*buffer, *maxlen);
    750 	    }
    751 	}
    752 	/* What to do if *buffer is NULL? */
    753 	assert(*sbuffer != NULL || *buffer != NULL);
    754     }
    755 
    756     if (*currlen < *maxlen) {
    757 	if (*sbuffer)
    758 	    (*sbuffer)[(*currlen)++] = (char)c;
    759 	else
    760 	    (*buffer)[(*currlen)++] = (char)c;
    761     }
    762 
    763     return;
    764 }
    765 
    766 /***************************************************************************/
    767 
    768 int BIO_printf (BIO *bio, const char *format, ...)
    769 	{
    770 	va_list args;
    771 	int ret;
    772 
    773 	va_start(args, format);
    774 
    775 	ret = BIO_vprintf(bio, format, args);
    776 
    777 	va_end(args);
    778 	return(ret);
    779 	}
    780 
    781 int BIO_vprintf (BIO *bio, const char *format, va_list args)
    782 	{
    783 	int ret;
    784 	size_t retlen;
    785 	char hugebuf[1024*2];	/* Was previously 10k, which is unreasonable
    786 				   in small-stack environments, like threads
    787 				   or DOS programs. */
    788 	char *hugebufp = hugebuf;
    789 	size_t hugebufsize = sizeof(hugebuf);
    790 	char *dynbuf = NULL;
    791 	int ignored;
    792 
    793 	dynbuf = NULL;
    794 	CRYPTO_push_info("doapr()");
    795 	_dopr(&hugebufp, &dynbuf, &hugebufsize,
    796 		&retlen, &ignored, format, args);
    797 	if (dynbuf)
    798 		{
    799 		ret=BIO_write(bio, dynbuf, (int)retlen);
    800 		OPENSSL_free(dynbuf);
    801 		}
    802 	else
    803 		{
    804 		ret=BIO_write(bio, hugebuf, (int)retlen);
    805 		}
    806 	CRYPTO_pop_info();
    807 	return(ret);
    808 	}
    809 
    810 /* As snprintf is not available everywhere, we provide our own implementation.
    811  * This function has nothing to do with BIOs, but it's closely related
    812  * to BIO_printf, and we need *some* name prefix ...
    813  * (XXX  the function should be renamed, but to what?) */
    814 int BIO_snprintf(char *buf, size_t n, const char *format, ...)
    815 	{
    816 	va_list args;
    817 	int ret;
    818 
    819 	va_start(args, format);
    820 
    821 	ret = BIO_vsnprintf(buf, n, format, args);
    822 
    823 	va_end(args);
    824 	return(ret);
    825 	}
    826 
    827 int BIO_vsnprintf(char *buf, size_t n, const char *format, va_list args)
    828 	{
    829 	size_t retlen;
    830 	int truncated;
    831 
    832 	_dopr(&buf, NULL, &n, &retlen, &truncated, format, args);
    833 
    834 	if (truncated)
    835 		/* In case of truncation, return -1 like traditional snprintf.
    836 		 * (Current drafts for ISO/IEC 9899 say snprintf should return
    837 		 * the number of characters that would have been written,
    838 		 * had the buffer been large enough.) */
    839 		return -1;
    840 	else
    841 		return (retlen <= INT_MAX) ? (int)retlen : -1;
    842 	}
    843