b_print.c revision 1.3
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/* 60 * Stolen from tjh's ssl/ssl_trc.c stuff. 61 */ 62 63#include <stdio.h> 64#include <stdarg.h> 65#include <string.h> 66#include <ctype.h> 67#include "cryptlib.h" 68#ifndef NO_SYS_TYPES_H 69#include <sys/types.h> 70#endif 71#include <openssl/bio.h> 72 73#ifdef BN_LLONG 74# ifndef HAVE_LONG_LONG 75# define HAVE_LONG_LONG 76# endif 77#endif 78 79static void dopr (char *buffer, size_t maxlen, size_t *retlen, 80 const char *format, va_list args); 81 82int BIO_printf (BIO *bio, ...) 83 { 84 va_list args; 85 char *format; 86 int ret; 87 size_t retlen; 88 MS_STATIC char hugebuf[1024*2]; /* 10k in one chunk is the limit */ 89 90 va_start(args, bio); 91 format=va_arg(args, char *); 92 93 hugebuf[0]='\0'; 94 dopr(hugebuf, sizeof(hugebuf), &retlen, format, args); 95 ret=BIO_write(bio, hugebuf, (int)retlen); 96 97 va_end(args); 98 return(ret); 99 } 100 101/* 102 * Copyright Patrick Powell 1995 103 * This code is based on code written by Patrick Powell <papowell@astart.com> 104 * It may be used for any purpose as long as this notice remains intact 105 * on all source code distributions. 106 */ 107 108/* 109 * This code contains numerious changes and enhancements which were 110 * made by lots of contributors over the last years to Patrick Powell's 111 * original code: 112 * 113 * o Patrick Powell <papowell@astart.com> (1995) 114 * o Brandon Long <blong@fiction.net> (1996, for Mutt) 115 * o Thomas Roessler <roessler@guug.de> (1998, for Mutt) 116 * o Michael Elkins <me@cs.hmc.edu> (1998, for Mutt) 117 * o Andrew Tridgell <tridge@samba.org> (1998, for Samba) 118 * o Luke Mewburn <lukem@netbsd.org> (1999, for LukemFTP) 119 * o Ralf S. Engelschall <rse@engelschall.com> (1999, for Pth) 120 */ 121 122#if HAVE_LONG_DOUBLE 123#define LDOUBLE long double 124#else 125#define LDOUBLE double 126#endif 127 128#if HAVE_LONG_LONG 129#define LLONG long long 130#else 131#define LLONG long 132#endif 133 134static void fmtstr (char *, size_t *, size_t, char *, int, int, int); 135static void fmtint (char *, size_t *, size_t, LLONG, int, int, int, int); 136static void fmtfp (char *, size_t *, size_t, LDOUBLE, int, int, int); 137static void dopr_outch (char *, size_t *, size_t, int); 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 MAX(p,q) ((p >= q) ? p : q) 167 168static void 169dopr( 170 char *buffer, 171 size_t maxlen, 172 size_t *retlen, 173 const char *format, 174 va_list args) 175{ 176 char ch; 177 LLONG value; 178 LDOUBLE fvalue; 179 char *strvalue; 180 int min; 181 int max; 182 int state; 183 int flags; 184 int cflags; 185 size_t currlen; 186 187 state = DP_S_DEFAULT; 188 flags = currlen = cflags = min = 0; 189 max = -1; 190 ch = *format++; 191 192 while (state != DP_S_DONE) { 193 if ((ch == '\0') || (currlen >= maxlen)) 194 state = DP_S_DONE; 195 196 switch (state) { 197 case DP_S_DEFAULT: 198 if (ch == '%') 199 state = DP_S_FLAGS; 200 else 201 dopr_outch(buffer, &currlen, maxlen, ch); 202 ch = *format++; 203 break; 204 case DP_S_FLAGS: 205 switch (ch) { 206 case '-': 207 flags |= DP_F_MINUS; 208 ch = *format++; 209 break; 210 case '+': 211 flags |= DP_F_PLUS; 212 ch = *format++; 213 break; 214 case ' ': 215 flags |= DP_F_SPACE; 216 ch = *format++; 217 break; 218 case '#': 219 flags |= DP_F_NUM; 220 ch = *format++; 221 break; 222 case '0': 223 flags |= DP_F_ZERO; 224 ch = *format++; 225 break; 226 default: 227 state = DP_S_MIN; 228 break; 229 } 230 break; 231 case DP_S_MIN: 232 if (isdigit((unsigned char)ch)) { 233 min = 10 * min + char_to_int(ch); 234 ch = *format++; 235 } else if (ch == '*') { 236 min = va_arg(args, int); 237 ch = *format++; 238 state = DP_S_DOT; 239 } else 240 state = DP_S_DOT; 241 break; 242 case DP_S_DOT: 243 if (ch == '.') { 244 state = DP_S_MAX; 245 ch = *format++; 246 } else 247 state = DP_S_MOD; 248 break; 249 case DP_S_MAX: 250 if (isdigit((unsigned char)ch)) { 251 if (max < 0) 252 max = 0; 253 max = 10 * max + char_to_int(ch); 254 ch = *format++; 255 } else if (ch == '*') { 256 max = va_arg(args, int); 257 ch = *format++; 258 state = DP_S_MOD; 259 } else 260 state = DP_S_MOD; 261 break; 262 case DP_S_MOD: 263 switch (ch) { 264 case 'h': 265 cflags = DP_C_SHORT; 266 ch = *format++; 267 break; 268 case 'l': 269 if (*format == 'l') { 270 cflags = DP_C_LLONG; 271 format++; 272 } else 273 cflags = DP_C_LONG; 274 ch = *format++; 275 break; 276 case 'q': 277 cflags = DP_C_LLONG; 278 ch = *format++; 279 break; 280 case 'L': 281 cflags = DP_C_LDOUBLE; 282 ch = *format++; 283 break; 284 default: 285 break; 286 } 287 state = DP_S_CONV; 288 break; 289 case DP_S_CONV: 290 switch (ch) { 291 case 'd': 292 case 'i': 293 switch (cflags) { 294 case DP_C_SHORT: 295 value = (short int)va_arg(args, int); 296 break; 297 case DP_C_LONG: 298 value = va_arg(args, long int); 299 break; 300 case DP_C_LLONG: 301 value = va_arg(args, LLONG); 302 break; 303 default: 304 value = va_arg(args, int); 305 break; 306 } 307 fmtint(buffer, &currlen, maxlen, value, 10, min, max, flags); 308 break; 309 case 'X': 310 flags |= DP_F_UP; 311 /* FALLTHROUGH */ 312 case 'x': 313 case 'o': 314 case 'u': 315 flags |= DP_F_UNSIGNED; 316 switch (cflags) { 317 case DP_C_SHORT: 318 value = (unsigned short int)va_arg(args, unsigned int); 319 break; 320 case DP_C_LONG: 321 value = (LLONG) va_arg(args, 322 unsigned long int); 323 break; 324 case DP_C_LLONG: 325 value = va_arg(args, unsigned LLONG); 326 break; 327 default: 328 value = (LLONG) va_arg(args, 329 unsigned int); 330 break; 331 } 332 fmtint(buffer, &currlen, maxlen, value, 333 ch == 'o' ? 8 : (ch == 'u' ? 10 : 16), 334 min, max, flags); 335 break; 336 case 'f': 337 if (cflags == DP_C_LDOUBLE) 338 fvalue = va_arg(args, LDOUBLE); 339 else 340 fvalue = va_arg(args, double); 341 fmtfp(buffer, &currlen, maxlen, fvalue, min, max, flags); 342 break; 343 case 'E': 344 flags |= DP_F_UP; 345 case 'e': 346 if (cflags == DP_C_LDOUBLE) 347 fvalue = va_arg(args, LDOUBLE); 348 else 349 fvalue = va_arg(args, double); 350 break; 351 case 'G': 352 flags |= DP_F_UP; 353 case 'g': 354 if (cflags == DP_C_LDOUBLE) 355 fvalue = va_arg(args, LDOUBLE); 356 else 357 fvalue = va_arg(args, double); 358 break; 359 case 'c': 360 dopr_outch(buffer, &currlen, maxlen, 361 va_arg(args, int)); 362 break; 363 case 's': 364 strvalue = va_arg(args, char *); 365 if (max < 0) 366 max = maxlen; 367 fmtstr(buffer, &currlen, maxlen, strvalue, 368 flags, min, max); 369 break; 370 case 'p': 371 value = (long)va_arg(args, void *); 372 fmtint(buffer, &currlen, maxlen, 373 value, 16, min, max, flags); 374 break; 375 case 'n': /* XXX */ 376 if (cflags == DP_C_SHORT) { 377 short int *num; 378 num = va_arg(args, short int *); 379 *num = currlen; 380 } else if (cflags == DP_C_LONG) { /* XXX */ 381 long int *num; 382 num = va_arg(args, long int *); 383 *num = (long int) currlen; 384 } else if (cflags == DP_C_LLONG) { /* XXX */ 385 LLONG *num; 386 num = va_arg(args, LLONG *); 387 *num = (LLONG) currlen; 388 } else { 389 int *num; 390 num = va_arg(args, int *); 391 *num = currlen; 392 } 393 break; 394 case '%': 395 dopr_outch(buffer, &currlen, maxlen, ch); 396 break; 397 case 'w': 398 /* not supported yet, treat as next char */ 399 ch = *format++; 400 break; 401 default: 402 /* unknown, skip */ 403 break; 404 } 405 ch = *format++; 406 state = DP_S_DEFAULT; 407 flags = cflags = min = 0; 408 max = -1; 409 break; 410 case DP_S_DONE: 411 break; 412 default: 413 break; 414 } 415 } 416 if (currlen >= maxlen - 1) 417 currlen = maxlen - 1; 418 buffer[currlen] = '\0'; 419 *retlen = currlen; 420 return; 421} 422 423static void 424fmtstr( 425 char *buffer, 426 size_t *currlen, 427 size_t maxlen, 428 char *value, 429 int flags, 430 int min, 431 int max) 432{ 433 int padlen, strln; 434 int cnt = 0; 435 436 if (value == 0) 437 value = "<NULL>"; 438 for (strln = 0; value[strln]; ++strln) 439 ; 440 padlen = min - strln; 441 if (padlen < 0) 442 padlen = 0; 443 if (flags & DP_F_MINUS) 444 padlen = -padlen; 445 446 while ((padlen > 0) && (cnt < max)) { 447 dopr_outch(buffer, currlen, maxlen, ' '); 448 --padlen; 449 ++cnt; 450 } 451 while (*value && (cnt < max)) { 452 dopr_outch(buffer, currlen, maxlen, *value++); 453 ++cnt; 454 } 455 while ((padlen < 0) && (cnt < max)) { 456 dopr_outch(buffer, currlen, maxlen, ' '); 457 ++padlen; 458 ++cnt; 459 } 460} 461 462static void 463fmtint( 464 char *buffer, 465 size_t *currlen, 466 size_t maxlen, 467 LLONG value, 468 int base, 469 int min, 470 int max, 471 int flags) 472{ 473 int signvalue = 0; 474 unsigned LLONG uvalue; 475 char convert[20]; 476 int place = 0; 477 int spadlen = 0; 478 int zpadlen = 0; 479 int caps = 0; 480 481 if (max < 0) 482 max = 0; 483 uvalue = value; 484 if (!(flags & DP_F_UNSIGNED)) { 485 if (value < 0) { 486 signvalue = '-'; 487 uvalue = -value; 488 } else if (flags & DP_F_PLUS) 489 signvalue = '+'; 490 else if (flags & DP_F_SPACE) 491 signvalue = ' '; 492 } 493 if (flags & DP_F_UP) 494 caps = 1; 495 do { 496 convert[place++] = 497 (caps ? "0123456789ABCDEF" : "0123456789abcdef") 498 [uvalue % (unsigned) base]; 499 uvalue = (uvalue / (unsigned) base); 500 } while (uvalue && (place < 20)); 501 if (place == 20) 502 place--; 503 convert[place] = 0; 504 505 zpadlen = max - place; 506 spadlen = min - MAX(max, place) - (signvalue ? 1 : 0); 507 if (zpadlen < 0) 508 zpadlen = 0; 509 if (spadlen < 0) 510 spadlen = 0; 511 if (flags & DP_F_ZERO) { 512 zpadlen = MAX(zpadlen, spadlen); 513 spadlen = 0; 514 } 515 if (flags & DP_F_MINUS) 516 spadlen = -spadlen; 517 518 /* spaces */ 519 while (spadlen > 0) { 520 dopr_outch(buffer, currlen, maxlen, ' '); 521 --spadlen; 522 } 523 524 /* sign */ 525 if (signvalue) 526 dopr_outch(buffer, currlen, maxlen, signvalue); 527 528 /* zeros */ 529 if (zpadlen > 0) { 530 while (zpadlen > 0) { 531 dopr_outch(buffer, currlen, maxlen, '0'); 532 --zpadlen; 533 } 534 } 535 /* digits */ 536 while (place > 0) 537 dopr_outch(buffer, currlen, maxlen, convert[--place]); 538 539 /* left justified spaces */ 540 while (spadlen < 0) { 541 dopr_outch(buffer, currlen, maxlen, ' '); 542 ++spadlen; 543 } 544 return; 545} 546 547static LDOUBLE 548abs_val(LDOUBLE value) 549{ 550 LDOUBLE result = value; 551 if (value < 0) 552 result = -value; 553 return result; 554} 555 556static LDOUBLE 557pow10(int exp) 558{ 559 LDOUBLE result = 1; 560 while (exp) { 561 result *= 10; 562 exp--; 563 } 564 return result; 565} 566 567static long 568round(LDOUBLE value) 569{ 570 long intpart; 571 intpart = (long) value; 572 value = value - intpart; 573 if (value >= 0.5) 574 intpart++; 575 return intpart; 576} 577 578static void 579fmtfp( 580 char *buffer, 581 size_t *currlen, 582 size_t maxlen, 583 LDOUBLE fvalue, 584 int min, 585 int max, 586 int flags) 587{ 588 int signvalue = 0; 589 LDOUBLE ufvalue; 590 char iconvert[20]; 591 char fconvert[20]; 592 int iplace = 0; 593 int fplace = 0; 594 int padlen = 0; 595 int zpadlen = 0; 596 int caps = 0; 597 long intpart; 598 long fracpart; 599 600 if (max < 0) 601 max = 6; 602 ufvalue = abs_val(fvalue); 603 if (fvalue < 0) 604 signvalue = '-'; 605 else if (flags & DP_F_PLUS) 606 signvalue = '+'; 607 else if (flags & DP_F_SPACE) 608 signvalue = ' '; 609 610 intpart = (long)ufvalue; 611 612 /* sorry, we only support 9 digits past the decimal because of our 613 conversion method */ 614 if (max > 9) 615 max = 9; 616 617 /* we "cheat" by converting the fractional part to integer by 618 multiplying by a factor of 10 */ 619 fracpart = round((pow10(max)) * (ufvalue - intpart)); 620 621 if (fracpart >= pow10(max)) { 622 intpart++; 623 fracpart -= (long)pow10(max); 624 } 625 626 /* convert integer part */ 627 do { 628 iconvert[iplace++] = 629 (caps ? "0123456789ABCDEF" 630 : "0123456789abcdef")[intpart % 10]; 631 intpart = (intpart / 10); 632 } while (intpart && (iplace < 20)); 633 if (iplace == 20) 634 iplace--; 635 iconvert[iplace] = 0; 636 637 /* convert fractional part */ 638 do { 639 fconvert[fplace++] = 640 (caps ? "0123456789ABCDEF" 641 : "0123456789abcdef")[fracpart % 10]; 642 fracpart = (fracpart / 10); 643 } while (fracpart && (fplace < 20)); 644 if (fplace == 20) 645 fplace--; 646 fconvert[fplace] = 0; 647 648 /* -1 for decimal point, another -1 if we are printing a sign */ 649 padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); 650 zpadlen = max - fplace; 651 if (zpadlen < 0) 652 zpadlen = 0; 653 if (padlen < 0) 654 padlen = 0; 655 if (flags & DP_F_MINUS) 656 padlen = -padlen; 657 658 if ((flags & DP_F_ZERO) && (padlen > 0)) { 659 if (signvalue) { 660 dopr_outch(buffer, currlen, maxlen, signvalue); 661 --padlen; 662 signvalue = 0; 663 } 664 while (padlen > 0) { 665 dopr_outch(buffer, currlen, maxlen, '0'); 666 --padlen; 667 } 668 } 669 while (padlen > 0) { 670 dopr_outch(buffer, currlen, maxlen, ' '); 671 --padlen; 672 } 673 if (signvalue) 674 dopr_outch(buffer, currlen, maxlen, signvalue); 675 676 while (iplace > 0) 677 dopr_outch(buffer, currlen, maxlen, iconvert[--iplace]); 678 679 /* 680 * Decimal point. This should probably use locale to find the correct 681 * char to print out. 682 */ 683 if (max > 0) { 684 dopr_outch(buffer, currlen, maxlen, '.'); 685 686 while (fplace > 0) 687 dopr_outch(buffer, currlen, maxlen, fconvert[--fplace]); 688 } 689 while (zpadlen > 0) { 690 dopr_outch(buffer, currlen, maxlen, '0'); 691 --zpadlen; 692 } 693 694 while (padlen < 0) { 695 dopr_outch(buffer, currlen, maxlen, ' '); 696 ++padlen; 697 } 698} 699 700static void 701dopr_outch( 702 char *buffer, 703 size_t *currlen, 704 size_t maxlen, 705 int c) 706{ 707 if (*currlen < maxlen) 708 buffer[(*currlen)++] = (char)c; 709 return; 710} 711