1 /* crypto/bio/b_print.c */
   2 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
   3  * All rights reserved.
   4  *
   5  * This package is an SSL implementation written
   6  * by Eric Young (eay@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@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@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@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@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@astart.com>      (1995)
 103  * o Brandon Long <blong@fiction.net>          (1996, for Mutt)
 104  * o Thomas Roessler <roessler@guug.de>        (1998, for Mutt)
 105  * o Michael Elkins <me@cs.hmc.edu>            (1998, for Mutt)
 106  * o Andrew Tridgell <tridge@samba.org>        (1998, for Samba)
 107  * o Luke Mewburn <lukem@netbsd.org>           (1999, for LukemFTP)
 108  * o Ralf S. Engelschall <rse@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         }