b_print.c revision 1.6
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 <string.h> 65#include <ctype.h> 66#include <assert.h> 67#include <limits.h> 68#include "cryptlib.h" 69#ifndef NO_SYS_TYPES_H 70#include <sys/types.h> 71#endif 72#include <openssl/bn.h> /* To get BN_LLONG properly defined */ 73#include <openssl/bio.h> 74 75#ifdef BN_LLONG 76# ifndef HAVE_LONG_LONG 77# define HAVE_LONG_LONG 1 78# endif 79#endif 80 81/***************************************************************************/ 82 83/* 84 * Copyright Patrick Powell 1995 85 * This code is based on code written by Patrick Powell <papowell@astart.com> 86 * It may be used for any purpose as long as this notice remains intact 87 * on all source code distributions. 88 */ 89 90/* 91 * This code contains numerious changes and enhancements which were 92 * made by lots of contributors over the last years to Patrick Powell's 93 * original code: 94 * 95 * o Patrick Powell <papowell@astart.com> (1995) 96 * o Brandon Long <blong@fiction.net> (1996, for Mutt) 97 * o Thomas Roessler <roessler@guug.de> (1998, for Mutt) 98 * o Michael Elkins <me@cs.hmc.edu> (1998, for Mutt) 99 * o Andrew Tridgell <tridge@samba.org> (1998, for Samba) 100 * o Luke Mewburn <lukem@netbsd.org> (1999, for LukemFTP) 101 * o Ralf S. Engelschall <rse@engelschall.com> (1999, for Pth) 102 * o ... (for OpenSSL) 103 */ 104 105#if HAVE_LONG_DOUBLE 106#define LDOUBLE long double 107#else 108#define LDOUBLE double 109#endif 110 111#if HAVE_LONG_LONG 112#define LLONG long long 113#else 114#define LLONG long 115#endif 116 117static void fmtstr (char **, char **, size_t *, size_t *, 118 const char *, int, int, int); 119static void fmtint (char **, char **, size_t *, size_t *, 120 LLONG, int, int, int, int); 121static void fmtfp (char **, char **, size_t *, size_t *, 122 LDOUBLE, int, int, int); 123static void doapr_outch (char **, char **, size_t *, size_t *, int); 124static void _dopr(char **sbuffer, char **buffer, 125 size_t *maxlen, size_t *retlen, int *truncated, 126 const char *format, va_list args); 127 128/* format read states */ 129#define DP_S_DEFAULT 0 130#define DP_S_FLAGS 1 131#define DP_S_MIN 2 132#define DP_S_DOT 3 133#define DP_S_MAX 4 134#define DP_S_MOD 5 135#define DP_S_CONV 6 136#define DP_S_DONE 7 137 138/* format flags - Bits */ 139#define DP_F_MINUS (1 << 0) 140#define DP_F_PLUS (1 << 1) 141#define DP_F_SPACE (1 << 2) 142#define DP_F_NUM (1 << 3) 143#define DP_F_ZERO (1 << 4) 144#define DP_F_UP (1 << 5) 145#define DP_F_UNSIGNED (1 << 6) 146 147/* conversion flags */ 148#define DP_C_SHORT 1 149#define DP_C_LONG 2 150#define DP_C_LDOUBLE 3 151#define DP_C_LLONG 4 152 153/* some handy macros */ 154#define char_to_int(p) (p - '0') 155#define MAX(p,q) ((p >= q) ? p : q) 156 157static void 158_dopr( 159 char **sbuffer, 160 char **buffer, 161 size_t *maxlen, 162 size_t *retlen, 163 int *truncated, 164 const char *format, 165 va_list args) 166{ 167 char ch; 168 LLONG value; 169 LDOUBLE fvalue; 170 char *strvalue; 171 int min; 172 int max; 173 int state; 174 int flags; 175 int cflags; 176 size_t currlen; 177 178 state = DP_S_DEFAULT; 179 flags = currlen = cflags = min = 0; 180 max = -1; 181 ch = *format++; 182 183 while (state != DP_S_DONE) { 184 if (ch == '\0' || (buffer == NULL && currlen >= *maxlen)) 185 state = DP_S_DONE; 186 187 switch (state) { 188 case DP_S_DEFAULT: 189 if (ch == '%') 190 state = DP_S_FLAGS; 191 else 192 doapr_outch(sbuffer,buffer, &currlen, maxlen, ch); 193 ch = *format++; 194 break; 195 case DP_S_FLAGS: 196 switch (ch) { 197 case '-': 198 flags |= DP_F_MINUS; 199 ch = *format++; 200 break; 201 case '+': 202 flags |= DP_F_PLUS; 203 ch = *format++; 204 break; 205 case ' ': 206 flags |= DP_F_SPACE; 207 ch = *format++; 208 break; 209 case '#': 210 flags |= DP_F_NUM; 211 ch = *format++; 212 break; 213 case '0': 214 flags |= DP_F_ZERO; 215 ch = *format++; 216 break; 217 default: 218 state = DP_S_MIN; 219 break; 220 } 221 break; 222 case DP_S_MIN: 223 if (isdigit((unsigned char)ch)) { 224 min = 10 * min + char_to_int(ch); 225 ch = *format++; 226 } else if (ch == '*') { 227 min = va_arg(args, int); 228 ch = *format++; 229 state = DP_S_DOT; 230 } else 231 state = DP_S_DOT; 232 break; 233 case DP_S_DOT: 234 if (ch == '.') { 235 state = DP_S_MAX; 236 ch = *format++; 237 } else 238 state = DP_S_MOD; 239 break; 240 case DP_S_MAX: 241 if (isdigit((unsigned char)ch)) { 242 if (max < 0) 243 max = 0; 244 max = 10 * max + char_to_int(ch); 245 ch = *format++; 246 } else if (ch == '*') { 247 max = va_arg(args, int); 248 ch = *format++; 249 state = DP_S_MOD; 250 } else 251 state = DP_S_MOD; 252 break; 253 case DP_S_MOD: 254 switch (ch) { 255 case 'h': 256 cflags = DP_C_SHORT; 257 ch = *format++; 258 break; 259 case 'l': 260 if (*format == 'l') { 261 cflags = DP_C_LLONG; 262 format++; 263 } else 264 cflags = DP_C_LONG; 265 ch = *format++; 266 break; 267 case 'q': 268 cflags = DP_C_LLONG; 269 ch = *format++; 270 break; 271 case 'L': 272 cflags = DP_C_LDOUBLE; 273 ch = *format++; 274 break; 275 default: 276 break; 277 } 278 state = DP_S_CONV; 279 break; 280 case DP_S_CONV: 281 switch (ch) { 282 case 'd': 283 case 'i': 284 switch (cflags) { 285 case DP_C_SHORT: 286 value = (short int)va_arg(args, int); 287 break; 288 case DP_C_LONG: 289 value = va_arg(args, long int); 290 break; 291 case DP_C_LLONG: 292 value = va_arg(args, LLONG); 293 break; 294 default: 295 value = va_arg(args, int); 296 break; 297 } 298 fmtint(sbuffer, buffer, &currlen, maxlen, 299 value, 10, min, max, flags); 300 break; 301 case 'X': 302 flags |= DP_F_UP; 303 /* FALLTHROUGH */ 304 case 'x': 305 case 'o': 306 case 'u': 307 flags |= DP_F_UNSIGNED; 308 switch (cflags) { 309 case DP_C_SHORT: 310 value = (unsigned short int)va_arg(args, unsigned int); 311 break; 312 case DP_C_LONG: 313 value = (LLONG) va_arg(args, 314 unsigned long int); 315 break; 316 case DP_C_LLONG: 317 value = va_arg(args, unsigned LLONG); 318 break; 319 default: 320 value = (LLONG) va_arg(args, 321 unsigned int); 322 break; 323 } 324 fmtint(sbuffer, buffer, &currlen, maxlen, value, 325 ch == 'o' ? 8 : (ch == 'u' ? 10 : 16), 326 min, max, flags); 327 break; 328 case 'f': 329 if (cflags == DP_C_LDOUBLE) 330 fvalue = va_arg(args, LDOUBLE); 331 else 332 fvalue = va_arg(args, double); 333 fmtfp(sbuffer, buffer, &currlen, maxlen, 334 fvalue, min, max, flags); 335 break; 336 case 'E': 337 flags |= DP_F_UP; 338 case 'e': 339 if (cflags == DP_C_LDOUBLE) 340 fvalue = va_arg(args, LDOUBLE); 341 else 342 fvalue = va_arg(args, double); 343 break; 344 case 'G': 345 flags |= DP_F_UP; 346 case 'g': 347 if (cflags == DP_C_LDOUBLE) 348 fvalue = va_arg(args, LDOUBLE); 349 else 350 fvalue = va_arg(args, double); 351 break; 352 case 'c': 353 doapr_outch(sbuffer, buffer, &currlen, maxlen, 354 va_arg(args, int)); 355 break; 356 case 's': 357 strvalue = va_arg(args, char *); 358 if (max < 0) { 359 if (buffer) 360 max = INT_MAX; 361 else 362 max = *maxlen; 363 } 364 fmtstr(sbuffer, buffer, &currlen, maxlen, strvalue, 365 flags, min, max); 366 break; 367 case 'p': 368 value = (long)va_arg(args, void *); 369 fmtint(sbuffer, buffer, &currlen, maxlen, 370 value, 16, min, max, flags); 371 break; 372 case 'n': /* XXX */ 373 if (cflags == DP_C_SHORT) { 374 short int *num; 375 num = va_arg(args, short int *); 376 *num = currlen; 377 } else if (cflags == DP_C_LONG) { /* XXX */ 378 long int *num; 379 num = va_arg(args, long int *); 380 *num = (long int) currlen; 381 } else if (cflags == DP_C_LLONG) { /* XXX */ 382 LLONG *num; 383 num = va_arg(args, LLONG *); 384 *num = (LLONG) currlen; 385 } else { 386 int *num; 387 num = va_arg(args, int *); 388 *num = currlen; 389 } 390 break; 391 case '%': 392 doapr_outch(sbuffer, buffer, &currlen, maxlen, ch); 393 break; 394 case 'w': 395 /* not supported yet, treat as next char */ 396 ch = *format++; 397 break; 398 default: 399 /* unknown, skip */ 400 break; 401 } 402 ch = *format++; 403 state = DP_S_DEFAULT; 404 flags = cflags = min = 0; 405 max = -1; 406 break; 407 case DP_S_DONE: 408 break; 409 default: 410 break; 411 } 412 } 413 *truncated = (currlen > *maxlen - 1); 414 if (*truncated) 415 currlen = *maxlen - 1; 416 doapr_outch(sbuffer, buffer, &currlen, maxlen, '\0'); 417 *retlen = currlen - 1; 418 return; 419} 420 421static void 422fmtstr( 423 char **sbuffer, 424 char **buffer, 425 size_t *currlen, 426 size_t *maxlen, 427 const char *value, 428 int flags, 429 int min, 430 int max) 431{ 432 int padlen, strln; 433 int cnt = 0; 434 435 if (value == 0) 436 value = "<NULL>"; 437 for (strln = 0; value[strln]; ++strln) 438 ; 439 padlen = min - strln; 440 if (padlen < 0) 441 padlen = 0; 442 if (flags & DP_F_MINUS) 443 padlen = -padlen; 444 445 while ((padlen > 0) && (cnt < max)) { 446 doapr_outch(sbuffer, buffer, currlen, maxlen, ' '); 447 --padlen; 448 ++cnt; 449 } 450 while (*value && (cnt < max)) { 451 doapr_outch(sbuffer, buffer, currlen, maxlen, *value++); 452 ++cnt; 453 } 454 while ((padlen < 0) && (cnt < max)) { 455 doapr_outch(sbuffer, buffer, currlen, maxlen, ' '); 456 ++padlen; 457 ++cnt; 458 } 459} 460 461static void 462fmtint( 463 char **sbuffer, 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 doapr_outch(sbuffer, buffer, currlen, maxlen, ' '); 521 --spadlen; 522 } 523 524 /* sign */ 525 if (signvalue) 526 doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue); 527 528 /* zeros */ 529 if (zpadlen > 0) { 530 while (zpadlen > 0) { 531 doapr_outch(sbuffer, buffer, currlen, maxlen, '0'); 532 --zpadlen; 533 } 534 } 535 /* digits */ 536 while (place > 0) 537 doapr_outch(sbuffer, buffer, currlen, maxlen, convert[--place]); 538 539 /* left justified spaces */ 540 while (spadlen < 0) { 541 doapr_outch(sbuffer, 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 **sbuffer, 581 char **buffer, 582 size_t *currlen, 583 size_t *maxlen, 584 LDOUBLE fvalue, 585 int min, 586 int max, 587 int flags) 588{ 589 int signvalue = 0; 590 LDOUBLE ufvalue; 591 char iconvert[20]; 592 char fconvert[20]; 593 int iplace = 0; 594 int fplace = 0; 595 int padlen = 0; 596 int zpadlen = 0; 597 int caps = 0; 598 long intpart; 599 long fracpart; 600 601 if (max < 0) 602 max = 6; 603 ufvalue = abs_val(fvalue); 604 if (fvalue < 0) 605 signvalue = '-'; 606 else if (flags & DP_F_PLUS) 607 signvalue = '+'; 608 else if (flags & DP_F_SPACE) 609 signvalue = ' '; 610 611 intpart = (long)ufvalue; 612 613 /* sorry, we only support 9 digits past the decimal because of our 614 conversion method */ 615 if (max > 9) 616 max = 9; 617 618 /* we "cheat" by converting the fractional part to integer by 619 multiplying by a factor of 10 */ 620 fracpart = round((pow10(max)) * (ufvalue - intpart)); 621 622 if (fracpart >= pow10(max)) { 623 intpart++; 624 fracpart -= (long)pow10(max); 625 } 626 627 /* convert integer part */ 628 do { 629 iconvert[iplace++] = 630 (caps ? "0123456789ABCDEF" 631 : "0123456789abcdef")[intpart % 10]; 632 intpart = (intpart / 10); 633 } while (intpart && (iplace < 20)); 634 if (iplace == 20) 635 iplace--; 636 iconvert[iplace] = 0; 637 638 /* convert fractional part */ 639 do { 640 fconvert[fplace++] = 641 (caps ? "0123456789ABCDEF" 642 : "0123456789abcdef")[fracpart % 10]; 643 fracpart = (fracpart / 10); 644 } while (fracpart && (fplace < 20)); 645 if (fplace == 20) 646 fplace--; 647 fconvert[fplace] = 0; 648 649 /* -1 for decimal point, another -1 if we are printing a sign */ 650 padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); 651 zpadlen = max - fplace; 652 if (zpadlen < 0) 653 zpadlen = 0; 654 if (padlen < 0) 655 padlen = 0; 656 if (flags & DP_F_MINUS) 657 padlen = -padlen; 658 659 if ((flags & DP_F_ZERO) && (padlen > 0)) { 660 if (signvalue) { 661 doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue); 662 --padlen; 663 signvalue = 0; 664 } 665 while (padlen > 0) { 666 doapr_outch(sbuffer, buffer, currlen, maxlen, '0'); 667 --padlen; 668 } 669 } 670 while (padlen > 0) { 671 doapr_outch(sbuffer, buffer, currlen, maxlen, ' '); 672 --padlen; 673 } 674 if (signvalue) 675 doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue); 676 677 while (iplace > 0) 678 doapr_outch(sbuffer, buffer, currlen, maxlen, iconvert[--iplace]); 679 680 /* 681 * Decimal point. This should probably use locale to find the correct 682 * char to print out. 683 */ 684 if (max > 0) { 685 doapr_outch(sbuffer, buffer, currlen, maxlen, '.'); 686 687 while (fplace > 0) 688 doapr_outch(sbuffer, buffer, currlen, maxlen, fconvert[--fplace]); 689 } 690 while (zpadlen > 0) { 691 doapr_outch(sbuffer, buffer, currlen, maxlen, '0'); 692 --zpadlen; 693 } 694 695 while (padlen < 0) { 696 doapr_outch(sbuffer, buffer, currlen, maxlen, ' '); 697 ++padlen; 698 } 699} 700 701static void 702doapr_outch( 703 char **sbuffer, 704 char **buffer, 705 size_t *currlen, 706 size_t *maxlen, 707 int c) 708{ 709 /* If we haven't at least one buffer, someone has doe a big booboo */ 710 assert(*sbuffer != NULL || buffer != NULL); 711 712 if (buffer) { 713 while (*currlen >= *maxlen) { 714 if (*buffer == NULL) { 715 assert(*sbuffer != NULL); 716 if (*maxlen == 0) 717 *maxlen = 1024; 718 *buffer = OPENSSL_malloc(*maxlen); 719 if (*currlen > 0) 720 memcpy(*buffer, *sbuffer, *currlen); 721 *sbuffer = NULL; 722 } else { 723 *maxlen += 1024; 724 *buffer = OPENSSL_realloc(*buffer, *maxlen); 725 } 726 } 727 /* What to do if *buffer is NULL? */ 728 assert(*sbuffer != NULL || *buffer != NULL); 729 } 730 731 if (*currlen < *maxlen) { 732 if (*sbuffer) 733 (*sbuffer)[(*currlen)++] = (char)c; 734 else 735 (*buffer)[(*currlen)++] = (char)c; 736 } 737 738 return; 739} 740 741/***************************************************************************/ 742 743int BIO_printf (BIO *bio, const char *format, ...) 744 { 745 va_list args; 746 int ret; 747 748 va_start(args, format); 749 750 ret = BIO_vprintf(bio, format, args); 751 752 va_end(args); 753 return(ret); 754 } 755 756int BIO_vprintf (BIO *bio, const char *format, va_list args) 757 { 758 int ret; 759 size_t retlen; 760 MS_STATIC char hugebuf[1024*10]; 761 char *hugebufp = hugebuf; 762 size_t hugebufsize = sizeof(hugebuf); 763 char *dynbuf = NULL; 764 int ignored; 765 766 dynbuf = NULL; 767 CRYPTO_push_info("doapr()"); 768 _dopr(&hugebufp, &dynbuf, &hugebufsize, 769 &retlen, &ignored, format, args); 770 if (dynbuf) 771 { 772 ret=BIO_write(bio, dynbuf, (int)retlen); 773 OPENSSL_free(dynbuf); 774 } 775 else 776 { 777 ret=BIO_write(bio, hugebuf, (int)retlen); 778 } 779 CRYPTO_pop_info(); 780 return(ret); 781 } 782 783/* As snprintf is not available everywhere, we provide our own implementation. 784 * This function has nothing to do with BIOs, but it's closely related 785 * to BIO_printf, and we need *some* name prefix ... 786 * (XXX the function should be renamed, but to what?) */ 787int BIO_snprintf(char *buf, size_t n, const char *format, ...) 788 { 789 va_list args; 790 int ret; 791 792 va_start(args, format); 793 794 ret = BIO_vsnprintf(buf, n, format, args); 795 796 va_end(args); 797 return(ret); 798 } 799 800int BIO_vsnprintf(char *buf, size_t n, const char *format, va_list args) 801 { 802 size_t retlen; 803 int truncated; 804 805 _dopr(&buf, NULL, &n, &retlen, &truncated, format, args); 806 807 if (truncated) 808 /* In case of truncation, return -1 like traditional snprintf. 809 * (Current drafts for ISO/IEC 9899 say snprintf should return 810 * the number of characters that would have been written, 811 * had the buffer been large enough.) */ 812 return -1; 813 else 814 return (retlen <= INT_MAX) ? retlen : -1; 815 } 816