b_print.c revision 68651
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/bio.h> 73 74#ifdef BN_LLONG 75# ifndef HAVE_LONG_LONG 76# define HAVE_LONG_LONG 1 77# endif 78#endif 79 80/***************************************************************************/ 81 82/* 83 * Copyright Patrick Powell 1995 84 * This code is based on code written by Patrick Powell <papowell@astart.com> 85 * It may be used for any purpose as long as this notice remains intact 86 * on all source code distributions. 87 */ 88 89/* 90 * This code contains numerious changes and enhancements which were 91 * made by lots of contributors over the last years to Patrick Powell's 92 * original code: 93 * 94 * o Patrick Powell <papowell@astart.com> (1995) 95 * o Brandon Long <blong@fiction.net> (1996, for Mutt) 96 * o Thomas Roessler <roessler@guug.de> (1998, for Mutt) 97 * o Michael Elkins <me@cs.hmc.edu> (1998, for Mutt) 98 * o Andrew Tridgell <tridge@samba.org> (1998, for Samba) 99 * o Luke Mewburn <lukem@netbsd.org> (1999, for LukemFTP) 100 * o Ralf S. Engelschall <rse@engelschall.com> (1999, for Pth) 101 * o ... (for OpenSSL) 102 */ 103 104#if HAVE_LONG_DOUBLE 105#define LDOUBLE long double 106#else 107#define LDOUBLE double 108#endif 109 110#if HAVE_LONG_LONG 111#define LLONG long long 112#else 113#define LLONG long 114#endif 115 116static void fmtstr (char **, char **, size_t *, size_t *, 117 const char *, int, int, int); 118static void fmtint (char **, char **, size_t *, size_t *, 119 LLONG, int, int, int, int); 120static void fmtfp (char **, char **, size_t *, size_t *, 121 LDOUBLE, int, int, int); 122static void doapr_outch (char **, char **, size_t *, size_t *, int); 123static void _dopr(char **sbuffer, char **buffer, 124 size_t *maxlen, size_t *retlen, int *truncated, 125 const char *format, va_list args); 126 127/* format read states */ 128#define DP_S_DEFAULT 0 129#define DP_S_FLAGS 1 130#define DP_S_MIN 2 131#define DP_S_DOT 3 132#define DP_S_MAX 4 133#define DP_S_MOD 5 134#define DP_S_CONV 6 135#define DP_S_DONE 7 136 137/* format flags - Bits */ 138#define DP_F_MINUS (1 << 0) 139#define DP_F_PLUS (1 << 1) 140#define DP_F_SPACE (1 << 2) 141#define DP_F_NUM (1 << 3) 142#define DP_F_ZERO (1 << 4) 143#define DP_F_UP (1 << 5) 144#define DP_F_UNSIGNED (1 << 6) 145 146/* conversion flags */ 147#define DP_C_SHORT 1 148#define DP_C_LONG 2 149#define DP_C_LDOUBLE 3 150#define DP_C_LLONG 4 151 152/* some handy macros */ 153#define char_to_int(p) (p - '0') 154#define MAX(p,q) ((p >= q) ? p : q) 155 156static void 157_dopr( 158 char **sbuffer, 159 char **buffer, 160 size_t *maxlen, 161 size_t *retlen, 162 int *truncated, 163 const char *format, 164 va_list args) 165{ 166 char ch; 167 LLONG value; 168 LDOUBLE fvalue; 169 char *strvalue; 170 int min; 171 int max; 172 int state; 173 int flags; 174 int cflags; 175 size_t currlen; 176 177 state = DP_S_DEFAULT; 178 flags = currlen = cflags = min = 0; 179 max = -1; 180 ch = *format++; 181 182 while (state != DP_S_DONE) { 183 if (ch == '\0' || (buffer == NULL && currlen >= *maxlen)) 184 state = DP_S_DONE; 185 186 switch (state) { 187 case DP_S_DEFAULT: 188 if (ch == '%') 189 state = DP_S_FLAGS; 190 else 191 doapr_outch(sbuffer,buffer, &currlen, maxlen, ch); 192 ch = *format++; 193 break; 194 case DP_S_FLAGS: 195 switch (ch) { 196 case '-': 197 flags |= DP_F_MINUS; 198 ch = *format++; 199 break; 200 case '+': 201 flags |= DP_F_PLUS; 202 ch = *format++; 203 break; 204 case ' ': 205 flags |= DP_F_SPACE; 206 ch = *format++; 207 break; 208 case '#': 209 flags |= DP_F_NUM; 210 ch = *format++; 211 break; 212 case '0': 213 flags |= DP_F_ZERO; 214 ch = *format++; 215 break; 216 default: 217 state = DP_S_MIN; 218 break; 219 } 220 break; 221 case DP_S_MIN: 222 if (isdigit((unsigned char)ch)) { 223 min = 10 * min + char_to_int(ch); 224 ch = *format++; 225 } else if (ch == '*') { 226 min = va_arg(args, int); 227 ch = *format++; 228 state = DP_S_DOT; 229 } else 230 state = DP_S_DOT; 231 break; 232 case DP_S_DOT: 233 if (ch == '.') { 234 state = DP_S_MAX; 235 ch = *format++; 236 } else 237 state = DP_S_MOD; 238 break; 239 case DP_S_MAX: 240 if (isdigit((unsigned char)ch)) { 241 if (max < 0) 242 max = 0; 243 max = 10 * max + char_to_int(ch); 244 ch = *format++; 245 } else if (ch == '*') { 246 max = va_arg(args, int); 247 ch = *format++; 248 state = DP_S_MOD; 249 } else 250 state = DP_S_MOD; 251 break; 252 case DP_S_MOD: 253 switch (ch) { 254 case 'h': 255 cflags = DP_C_SHORT; 256 ch = *format++; 257 break; 258 case 'l': 259 if (*format == 'l') { 260 cflags = DP_C_LLONG; 261 format++; 262 } else 263 cflags = DP_C_LONG; 264 ch = *format++; 265 break; 266 case 'q': 267 cflags = DP_C_LLONG; 268 ch = *format++; 269 break; 270 case 'L': 271 cflags = DP_C_LDOUBLE; 272 ch = *format++; 273 break; 274 default: 275 break; 276 } 277 state = DP_S_CONV; 278 break; 279 case DP_S_CONV: 280 switch (ch) { 281 case 'd': 282 case 'i': 283 switch (cflags) { 284 case DP_C_SHORT: 285 value = (short int)va_arg(args, int); 286 break; 287 case DP_C_LONG: 288 value = va_arg(args, long int); 289 break; 290 case DP_C_LLONG: 291 value = va_arg(args, LLONG); 292 break; 293 default: 294 value = va_arg(args, int); 295 break; 296 } 297 fmtint(sbuffer, buffer, &currlen, maxlen, 298 value, 10, min, max, flags); 299 break; 300 case 'X': 301 flags |= DP_F_UP; 302 /* FALLTHROUGH */ 303 case 'x': 304 case 'o': 305 case 'u': 306 flags |= DP_F_UNSIGNED; 307 switch (cflags) { 308 case DP_C_SHORT: 309 value = (unsigned short int)va_arg(args, unsigned int); 310 break; 311 case DP_C_LONG: 312 value = (LLONG) va_arg(args, 313 unsigned long int); 314 break; 315 case DP_C_LLONG: 316 value = va_arg(args, unsigned LLONG); 317 break; 318 default: 319 value = (LLONG) va_arg(args, 320 unsigned int); 321 break; 322 } 323 fmtint(sbuffer, buffer, &currlen, maxlen, value, 324 ch == 'o' ? 8 : (ch == 'u' ? 10 : 16), 325 min, max, flags); 326 break; 327 case 'f': 328 if (cflags == DP_C_LDOUBLE) 329 fvalue = va_arg(args, LDOUBLE); 330 else 331 fvalue = va_arg(args, double); 332 fmtfp(sbuffer, buffer, &currlen, maxlen, 333 fvalue, min, max, flags); 334 break; 335 case 'E': 336 flags |= DP_F_UP; 337 case 'e': 338 if (cflags == DP_C_LDOUBLE) 339 fvalue = va_arg(args, LDOUBLE); 340 else 341 fvalue = va_arg(args, double); 342 break; 343 case 'G': 344 flags |= DP_F_UP; 345 case 'g': 346 if (cflags == DP_C_LDOUBLE) 347 fvalue = va_arg(args, LDOUBLE); 348 else 349 fvalue = va_arg(args, double); 350 break; 351 case 'c': 352 doapr_outch(sbuffer, buffer, &currlen, maxlen, 353 va_arg(args, int)); 354 break; 355 case 's': 356 strvalue = va_arg(args, char *); 357 if (max < 0) { 358 if (buffer) 359 max = INT_MAX; 360 else 361 max = *maxlen; 362 } 363 fmtstr(sbuffer, buffer, &currlen, maxlen, strvalue, 364 flags, min, max); 365 break; 366 case 'p': 367 value = (long)va_arg(args, void *); 368 fmtint(sbuffer, buffer, &currlen, maxlen, 369 value, 16, min, max, flags); 370 break; 371 case 'n': /* XXX */ 372 if (cflags == DP_C_SHORT) { 373 short int *num; 374 num = va_arg(args, short int *); 375 *num = currlen; 376 } else if (cflags == DP_C_LONG) { /* XXX */ 377 long int *num; 378 num = va_arg(args, long int *); 379 *num = (long int) currlen; 380 } else if (cflags == DP_C_LLONG) { /* XXX */ 381 LLONG *num; 382 num = va_arg(args, LLONG *); 383 *num = (LLONG) currlen; 384 } else { 385 int *num; 386 num = va_arg(args, int *); 387 *num = currlen; 388 } 389 break; 390 case '%': 391 doapr_outch(sbuffer, buffer, &currlen, maxlen, ch); 392 break; 393 case 'w': 394 /* not supported yet, treat as next char */ 395 ch = *format++; 396 break; 397 default: 398 /* unknown, skip */ 399 break; 400 } 401 ch = *format++; 402 state = DP_S_DEFAULT; 403 flags = cflags = min = 0; 404 max = -1; 405 break; 406 case DP_S_DONE: 407 break; 408 default: 409 break; 410 } 411 } 412 *truncated = (currlen > *maxlen - 1); 413 if (*truncated) 414 currlen = *maxlen - 1; 415 doapr_outch(sbuffer, buffer, &currlen, maxlen, '\0'); 416 *retlen = currlen - 1; 417 return; 418} 419 420static void 421fmtstr( 422 char **sbuffer, 423 char **buffer, 424 size_t *currlen, 425 size_t *maxlen, 426 const char *value, 427 int flags, 428 int min, 429 int max) 430{ 431 int padlen, strln; 432 int cnt = 0; 433 434 if (value == 0) 435 value = "<NULL>"; 436 for (strln = 0; value[strln]; ++strln) 437 ; 438 padlen = min - strln; 439 if (padlen < 0) 440 padlen = 0; 441 if (flags & DP_F_MINUS) 442 padlen = -padlen; 443 444 while ((padlen > 0) && (cnt < max)) { 445 doapr_outch(sbuffer, buffer, currlen, maxlen, ' '); 446 --padlen; 447 ++cnt; 448 } 449 while (*value && (cnt < max)) { 450 doapr_outch(sbuffer, buffer, currlen, maxlen, *value++); 451 ++cnt; 452 } 453 while ((padlen < 0) && (cnt < max)) { 454 doapr_outch(sbuffer, buffer, currlen, maxlen, ' '); 455 ++padlen; 456 ++cnt; 457 } 458} 459 460static void 461fmtint( 462 char **sbuffer, 463 char **buffer, 464 size_t *currlen, 465 size_t *maxlen, 466 LLONG value, 467 int base, 468 int min, 469 int max, 470 int flags) 471{ 472 int signvalue = 0; 473 unsigned LLONG uvalue; 474 char convert[20]; 475 int place = 0; 476 int spadlen = 0; 477 int zpadlen = 0; 478 int caps = 0; 479 480 if (max < 0) 481 max = 0; 482 uvalue = value; 483 if (!(flags & DP_F_UNSIGNED)) { 484 if (value < 0) { 485 signvalue = '-'; 486 uvalue = -value; 487 } else if (flags & DP_F_PLUS) 488 signvalue = '+'; 489 else if (flags & DP_F_SPACE) 490 signvalue = ' '; 491 } 492 if (flags & DP_F_UP) 493 caps = 1; 494 do { 495 convert[place++] = 496 (caps ? "0123456789ABCDEF" : "0123456789abcdef") 497 [uvalue % (unsigned) base]; 498 uvalue = (uvalue / (unsigned) base); 499 } while (uvalue && (place < 20)); 500 if (place == 20) 501 place--; 502 convert[place] = 0; 503 504 zpadlen = max - place; 505 spadlen = min - MAX(max, place) - (signvalue ? 1 : 0); 506 if (zpadlen < 0) 507 zpadlen = 0; 508 if (spadlen < 0) 509 spadlen = 0; 510 if (flags & DP_F_ZERO) { 511 zpadlen = MAX(zpadlen, spadlen); 512 spadlen = 0; 513 } 514 if (flags & DP_F_MINUS) 515 spadlen = -spadlen; 516 517 /* spaces */ 518 while (spadlen > 0) { 519 doapr_outch(sbuffer, buffer, currlen, maxlen, ' '); 520 --spadlen; 521 } 522 523 /* sign */ 524 if (signvalue) 525 doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue); 526 527 /* zeros */ 528 if (zpadlen > 0) { 529 while (zpadlen > 0) { 530 doapr_outch(sbuffer, buffer, currlen, maxlen, '0'); 531 --zpadlen; 532 } 533 } 534 /* digits */ 535 while (place > 0) 536 doapr_outch(sbuffer, buffer, currlen, maxlen, convert[--place]); 537 538 /* left justified spaces */ 539 while (spadlen < 0) { 540 doapr_outch(sbuffer, buffer, currlen, maxlen, ' '); 541 ++spadlen; 542 } 543 return; 544} 545 546static LDOUBLE 547abs_val(LDOUBLE value) 548{ 549 LDOUBLE result = value; 550 if (value < 0) 551 result = -value; 552 return result; 553} 554 555static LDOUBLE 556pow10(int exp) 557{ 558 LDOUBLE result = 1; 559 while (exp) { 560 result *= 10; 561 exp--; 562 } 563 return result; 564} 565 566static long 567round(LDOUBLE value) 568{ 569 long intpart; 570 intpart = (long) value; 571 value = value - intpart; 572 if (value >= 0.5) 573 intpart++; 574 return intpart; 575} 576 577static void 578fmtfp( 579 char **sbuffer, 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 doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue); 661 --padlen; 662 signvalue = 0; 663 } 664 while (padlen > 0) { 665 doapr_outch(sbuffer, buffer, currlen, maxlen, '0'); 666 --padlen; 667 } 668 } 669 while (padlen > 0) { 670 doapr_outch(sbuffer, buffer, currlen, maxlen, ' '); 671 --padlen; 672 } 673 if (signvalue) 674 doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue); 675 676 while (iplace > 0) 677 doapr_outch(sbuffer, 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 doapr_outch(sbuffer, buffer, currlen, maxlen, '.'); 685 686 while (fplace > 0) 687 doapr_outch(sbuffer, buffer, currlen, maxlen, fconvert[--fplace]); 688 } 689 while (zpadlen > 0) { 690 doapr_outch(sbuffer, buffer, currlen, maxlen, '0'); 691 --zpadlen; 692 } 693 694 while (padlen < 0) { 695 doapr_outch(sbuffer, buffer, currlen, maxlen, ' '); 696 ++padlen; 697 } 698} 699 700static void 701doapr_outch( 702 char **sbuffer, 703 char **buffer, 704 size_t *currlen, 705 size_t *maxlen, 706 int c) 707{ 708 /* If we haven't at least one buffer, someone has doe a big booboo */ 709 assert(*sbuffer != NULL || buffer != NULL); 710 711 if (buffer) { 712 while (*currlen >= *maxlen) { 713 if (*buffer == NULL) { 714 assert(*sbuffer != NULL); 715 if (*maxlen == 0) 716 *maxlen = 1024; 717 *buffer = OPENSSL_malloc(*maxlen); 718 if (*currlen > 0) 719 memcpy(*buffer, *sbuffer, *currlen); 720 *sbuffer = NULL; 721 } else { 722 *maxlen += 1024; 723 *buffer = OPENSSL_realloc(*buffer, *maxlen); 724 } 725 } 726 /* What to do if *buffer is NULL? */ 727 assert(*sbuffer != NULL || *buffer != NULL); 728 } 729 730 if (*currlen < *maxlen) { 731 if (*sbuffer) 732 (*sbuffer)[(*currlen)++] = (char)c; 733 else 734 (*buffer)[(*currlen)++] = (char)c; 735 } 736 737 return; 738} 739 740/***************************************************************************/ 741 742int BIO_printf (BIO *bio, const char *format, ...) 743 { 744 va_list args; 745 int ret; 746 747 va_start(args, format); 748 749 ret = BIO_vprintf(bio, format, args); 750 751 va_end(args); 752 return(ret); 753 } 754 755int BIO_vprintf (BIO *bio, const char *format, va_list args) 756 { 757 int ret; 758 size_t retlen; 759 MS_STATIC char hugebuf[1024*10]; 760 char *hugebufp = hugebuf; 761 size_t hugebufsize = sizeof(hugebuf); 762 char *dynbuf = NULL; 763 int ignored; 764 765 dynbuf = NULL; 766 CRYPTO_push_info("doapr()"); 767 _dopr(&hugebufp, &dynbuf, &hugebufsize, 768 &retlen, &ignored, format, args); 769 if (dynbuf) 770 { 771 ret=BIO_write(bio, dynbuf, (int)retlen); 772 OPENSSL_free(dynbuf); 773 } 774 else 775 { 776 ret=BIO_write(bio, hugebuf, (int)retlen); 777 } 778 CRYPTO_pop_info(); 779 return(ret); 780 } 781 782/* As snprintf is not available everywhere, we provide our own implementation. 783 * This function has nothing to do with BIOs, but it's closely related 784 * to BIO_printf, and we need *some* name prefix ... 785 * (XXX the function should be renamed, but to what?) */ 786int BIO_snprintf(char *buf, size_t n, const char *format, ...) 787 { 788 va_list args; 789 int ret; 790 791 va_start(args, format); 792 793 ret = BIO_vsnprintf(buf, n, format, args); 794 795 va_end(args); 796 return(ret); 797 } 798 799int BIO_vsnprintf(char *buf, size_t n, const char *format, va_list args) 800 { 801 size_t retlen; 802 int truncated; 803 804 _dopr(&buf, NULL, &n, &retlen, &truncated, format, args); 805 806 if (truncated) 807 /* In case of truncation, return -1 like traditional snprintf. 808 * (Current drafts for ISO/IEC 9899 say snprintf should return 809 * the number of characters that would have been written, 810 * had the buffer been large enough.) */ 811 return -1; 812 else 813 return (retlen <= INT_MAX) ? retlen : -1; 814 } 815