1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1999 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al. 9 * 10 * This software is licensed as described in the file COPYING, which 11 * you should have received as part of this distribution. The terms 12 * are also available at http://curl.haxx.se/docs/copyright.html. 13 * 14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 15 * copies of the Software, and permit persons to whom the Software is 16 * furnished to do so, under the terms of the COPYING file. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 * 22 * Purpose: 23 * A merge of Bjorn Reese's format() function and Daniel's dsprintf() 24 * 1.0. A full blooded printf() clone with full support for <num>$ 25 * everywhere (parameters, widths and precisions) including variabled 26 * sized parameters (like doubles, long longs, long doubles and even 27 * void * in 64-bit architectures). 28 * 29 * Current restrictions: 30 * - Max 128 parameters 31 * - No 'long double' support. 32 * 33 * If you ever want truly portable and good *printf() clones, the project that 34 * took on from here is named 'Trio' and you find more details on the trio web 35 * page at http://daniel.haxx.se/trio/ 36 */ 37 38#include "curl_setup.h" 39 40#if defined(DJGPP) && (DJGPP_MINOR < 4) 41#undef _MPRINTF_REPLACE /* don't use x_was_used() here */ 42#endif 43 44#include <curl/mprintf.h> 45 46#include "curl_memory.h" 47/* The last #include file should be: */ 48#include "memdebug.h" 49 50#ifndef SIZEOF_LONG_DOUBLE 51#define SIZEOF_LONG_DOUBLE 0 52#endif 53 54/* 55 * If SIZEOF_SIZE_T has not been defined, default to the size of long. 56 */ 57 58#ifndef SIZEOF_SIZE_T 59# define SIZEOF_SIZE_T CURL_SIZEOF_LONG 60#endif 61 62#ifdef HAVE_LONGLONG 63# define LONG_LONG_TYPE long long 64# define HAVE_LONG_LONG_TYPE 65#else 66# if defined(_MSC_VER) && (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64) 67# define LONG_LONG_TYPE __int64 68# define HAVE_LONG_LONG_TYPE 69# else 70# undef LONG_LONG_TYPE 71# undef HAVE_LONG_LONG_TYPE 72# endif 73#endif 74 75/* 76 * Max integer data types that mprintf.c is capable 77 */ 78 79#ifdef HAVE_LONG_LONG_TYPE 80# define mp_intmax_t LONG_LONG_TYPE 81# define mp_uintmax_t unsigned LONG_LONG_TYPE 82#else 83# define mp_intmax_t long 84# define mp_uintmax_t unsigned long 85#endif 86 87#define BUFFSIZE 256 /* buffer for long-to-str and float-to-str calcs */ 88#define MAX_PARAMETERS 128 /* lame static limit */ 89 90#ifdef __AMIGA__ 91# undef FORMAT_INT 92#endif 93 94/* Lower-case digits. */ 95static const char lower_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; 96 97/* Upper-case digits. */ 98static const char upper_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 99 100#define OUTCHAR(x) \ 101 do{ \ 102 if(stream((unsigned char)(x), (FILE *)data) != -1) \ 103 done++; \ 104 else \ 105 return done; /* return immediately on failure */ \ 106 } WHILE_FALSE 107 108/* Data type to read from the arglist */ 109typedef enum { 110 FORMAT_UNKNOWN = 0, 111 FORMAT_STRING, 112 FORMAT_PTR, 113 FORMAT_INT, 114 FORMAT_INTPTR, 115 FORMAT_LONG, 116 FORMAT_LONGLONG, 117 FORMAT_DOUBLE, 118 FORMAT_LONGDOUBLE, 119 FORMAT_WIDTH /* For internal use */ 120} FormatType; 121 122/* conversion and display flags */ 123enum { 124 FLAGS_NEW = 0, 125 FLAGS_SPACE = 1<<0, 126 FLAGS_SHOWSIGN = 1<<1, 127 FLAGS_LEFT = 1<<2, 128 FLAGS_ALT = 1<<3, 129 FLAGS_SHORT = 1<<4, 130 FLAGS_LONG = 1<<5, 131 FLAGS_LONGLONG = 1<<6, 132 FLAGS_LONGDOUBLE = 1<<7, 133 FLAGS_PAD_NIL = 1<<8, 134 FLAGS_UNSIGNED = 1<<9, 135 FLAGS_OCTAL = 1<<10, 136 FLAGS_HEX = 1<<11, 137 FLAGS_UPPER = 1<<12, 138 FLAGS_WIDTH = 1<<13, /* '*' or '*<num>$' used */ 139 FLAGS_WIDTHPARAM = 1<<14, /* width PARAMETER was specified */ 140 FLAGS_PREC = 1<<15, /* precision was specified */ 141 FLAGS_PRECPARAM = 1<<16, /* precision PARAMETER was specified */ 142 FLAGS_CHAR = 1<<17, /* %c story */ 143 FLAGS_FLOATE = 1<<18, /* %e or %E */ 144 FLAGS_FLOATG = 1<<19 /* %g or %G */ 145}; 146 147typedef struct { 148 FormatType type; 149 int flags; 150 long width; /* width OR width parameter number */ 151 long precision; /* precision OR precision parameter number */ 152 union { 153 char *str; 154 void *ptr; 155 union { 156 mp_intmax_t as_signed; 157 mp_uintmax_t as_unsigned; 158 } num; 159 double dnum; 160 } data; 161} va_stack_t; 162 163struct nsprintf { 164 char *buffer; 165 size_t length; 166 size_t max; 167}; 168 169struct asprintf { 170 char *buffer; /* allocated buffer */ 171 size_t len; /* length of string */ 172 size_t alloc; /* length of alloc */ 173 int fail; /* (!= 0) if an alloc has failed and thus 174 the output is not the complete data */ 175}; 176 177static long dprintf_DollarString(char *input, char **end) 178{ 179 int number=0; 180 while(ISDIGIT(*input)) { 181 number *= 10; 182 number += *input-'0'; 183 input++; 184 } 185 if(number && ('$'==*input++)) { 186 *end = input; 187 return number; 188 } 189 return 0; 190} 191 192static int dprintf_IsQualifierNoDollar(char c) 193{ 194 switch (c) { 195 case '-': case '+': case ' ': case '#': case '.': 196 case '0': case '1': case '2': case '3': case '4': 197 case '5': case '6': case '7': case '8': case '9': 198 case 'h': case 'l': case 'L': case 'z': case 'q': 199 case '*': case 'O': 200 return 1; /* true */ 201 default: 202 return 0; /* false */ 203 } 204} 205 206/****************************************************************** 207 * 208 * Pass 1: 209 * Create an index with the type of each parameter entry and its 210 * value (may vary in size) 211 * 212 ******************************************************************/ 213 214static long dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos, 215 va_list arglist) 216{ 217 char *fmt = (char *)format; 218 int param_num = 0; 219 long this_param; 220 long width; 221 long precision; 222 int flags; 223 long max_param=0; 224 long i; 225 226 while(*fmt) { 227 if(*fmt++ == '%') { 228 if(*fmt == '%') { 229 fmt++; 230 continue; /* while */ 231 } 232 233 flags = FLAGS_NEW; 234 235 /* Handle the positional case (N$) */ 236 237 param_num++; 238 239 this_param = dprintf_DollarString(fmt, &fmt); 240 if(0 == this_param) 241 /* we got no positional, get the next counter */ 242 this_param = param_num; 243 244 if(this_param > max_param) 245 max_param = this_param; 246 247 /* 248 * The parameter with number 'i' should be used. Next, we need 249 * to get SIZE and TYPE of the parameter. Add the information 250 * to our array. 251 */ 252 253 width = 0; 254 precision = 0; 255 256 /* Handle the flags */ 257 258 while(dprintf_IsQualifierNoDollar(*fmt)) { 259 switch (*fmt++) { 260 case ' ': 261 flags |= FLAGS_SPACE; 262 break; 263 case '+': 264 flags |= FLAGS_SHOWSIGN; 265 break; 266 case '-': 267 flags |= FLAGS_LEFT; 268 flags &= ~FLAGS_PAD_NIL; 269 break; 270 case '#': 271 flags |= FLAGS_ALT; 272 break; 273 case '.': 274 flags |= FLAGS_PREC; 275 if('*' == *fmt) { 276 /* The precision is picked from a specified parameter */ 277 278 flags |= FLAGS_PRECPARAM; 279 fmt++; 280 param_num++; 281 282 i = dprintf_DollarString(fmt, &fmt); 283 if(i) 284 precision = i; 285 else 286 precision = param_num; 287 288 if(precision > max_param) 289 max_param = precision; 290 } 291 else { 292 flags |= FLAGS_PREC; 293 precision = strtol(fmt, &fmt, 10); 294 } 295 break; 296 case 'h': 297 flags |= FLAGS_SHORT; 298 break; 299 case 'l': 300 if(flags & FLAGS_LONG) 301 flags |= FLAGS_LONGLONG; 302 else 303 flags |= FLAGS_LONG; 304 break; 305 case 'L': 306 flags |= FLAGS_LONGDOUBLE; 307 break; 308 case 'q': 309 flags |= FLAGS_LONGLONG; 310 break; 311 case 'z': 312 /* the code below generates a warning if -Wunreachable-code is 313 used */ 314#if (SIZEOF_SIZE_T > CURL_SIZEOF_LONG) 315 flags |= FLAGS_LONGLONG; 316#else 317 flags |= FLAGS_LONG; 318#endif 319 break; 320 case 'O': 321#if (CURL_SIZEOF_CURL_OFF_T > CURL_SIZEOF_LONG) 322 flags |= FLAGS_LONGLONG; 323#else 324 flags |= FLAGS_LONG; 325#endif 326 break; 327 case '0': 328 if(!(flags & FLAGS_LEFT)) 329 flags |= FLAGS_PAD_NIL; 330 /* FALLTHROUGH */ 331 case '1': case '2': case '3': case '4': 332 case '5': case '6': case '7': case '8': case '9': 333 flags |= FLAGS_WIDTH; 334 width = strtol(fmt-1, &fmt, 10); 335 break; 336 case '*': /* Special case */ 337 flags |= FLAGS_WIDTHPARAM; 338 param_num++; 339 340 i = dprintf_DollarString(fmt, &fmt); 341 if(i) 342 width = i; 343 else 344 width = param_num; 345 if(width > max_param) 346 max_param=width; 347 break; 348 default: 349 break; 350 } 351 } /* switch */ 352 353 /* Handle the specifier */ 354 355 i = this_param - 1; 356 357 switch (*fmt) { 358 case 'S': 359 flags |= FLAGS_ALT; 360 /* FALLTHROUGH */ 361 case 's': 362 vto[i].type = FORMAT_STRING; 363 break; 364 case 'n': 365 vto[i].type = FORMAT_INTPTR; 366 break; 367 case 'p': 368 vto[i].type = FORMAT_PTR; 369 break; 370 case 'd': case 'i': 371 vto[i].type = FORMAT_INT; 372 break; 373 case 'u': 374 vto[i].type = FORMAT_INT; 375 flags |= FLAGS_UNSIGNED; 376 break; 377 case 'o': 378 vto[i].type = FORMAT_INT; 379 flags |= FLAGS_OCTAL; 380 break; 381 case 'x': 382 vto[i].type = FORMAT_INT; 383 flags |= FLAGS_HEX; 384 break; 385 case 'X': 386 vto[i].type = FORMAT_INT; 387 flags |= FLAGS_HEX|FLAGS_UPPER; 388 break; 389 case 'c': 390 vto[i].type = FORMAT_INT; 391 flags |= FLAGS_CHAR; 392 break; 393 case 'f': 394 vto[i].type = FORMAT_DOUBLE; 395 break; 396 case 'e': 397 vto[i].type = FORMAT_DOUBLE; 398 flags |= FLAGS_FLOATE; 399 break; 400 case 'E': 401 vto[i].type = FORMAT_DOUBLE; 402 flags |= FLAGS_FLOATE|FLAGS_UPPER; 403 break; 404 case 'g': 405 vto[i].type = FORMAT_DOUBLE; 406 flags |= FLAGS_FLOATG; 407 break; 408 case 'G': 409 vto[i].type = FORMAT_DOUBLE; 410 flags |= FLAGS_FLOATG|FLAGS_UPPER; 411 break; 412 default: 413 vto[i].type = FORMAT_UNKNOWN; 414 break; 415 } /* switch */ 416 417 vto[i].flags = flags; 418 vto[i].width = width; 419 vto[i].precision = precision; 420 421 if(flags & FLAGS_WIDTHPARAM) { 422 /* we have the width specified from a parameter, so we make that 423 parameter's info setup properly */ 424 vto[i].width = width - 1; 425 i = width - 1; 426 vto[i].type = FORMAT_WIDTH; 427 vto[i].flags = FLAGS_NEW; 428 vto[i].precision = vto[i].width = 0; /* can't use width or precision 429 of width! */ 430 } 431 if(flags & FLAGS_PRECPARAM) { 432 /* we have the precision specified from a parameter, so we make that 433 parameter's info setup properly */ 434 vto[i].precision = precision - 1; 435 i = precision - 1; 436 vto[i].type = FORMAT_WIDTH; 437 vto[i].flags = FLAGS_NEW; 438 vto[i].precision = vto[i].width = 0; /* can't use width or precision 439 of width! */ 440 } 441 *endpos++ = fmt + 1; /* end of this sequence */ 442 } 443 } 444 445 /* Read the arg list parameters into our data list */ 446 for(i=0; i<max_param; i++) { 447 if((i + 1 < max_param) && (vto[i + 1].type == FORMAT_WIDTH)) { 448 /* Width/precision arguments must be read before the main argument 449 * they are attached to 450 */ 451 vto[i + 1].data.num.as_signed = (mp_intmax_t)va_arg(arglist, int); 452 } 453 454 switch (vto[i].type) { 455 case FORMAT_STRING: 456 vto[i].data.str = va_arg(arglist, char *); 457 break; 458 459 case FORMAT_INTPTR: 460 case FORMAT_UNKNOWN: 461 case FORMAT_PTR: 462 vto[i].data.ptr = va_arg(arglist, void *); 463 break; 464 465 case FORMAT_INT: 466#ifdef HAVE_LONG_LONG_TYPE 467 if((vto[i].flags & FLAGS_LONGLONG) && (vto[i].flags & FLAGS_UNSIGNED)) 468 vto[i].data.num.as_unsigned = 469 (mp_uintmax_t)va_arg(arglist, mp_uintmax_t); 470 else if(vto[i].flags & FLAGS_LONGLONG) 471 vto[i].data.num.as_signed = 472 (mp_intmax_t)va_arg(arglist, mp_intmax_t); 473 else 474#endif 475 { 476 if((vto[i].flags & FLAGS_LONG) && (vto[i].flags & FLAGS_UNSIGNED)) 477 vto[i].data.num.as_unsigned = 478 (mp_uintmax_t)va_arg(arglist, unsigned long); 479 else if(vto[i].flags & FLAGS_LONG) 480 vto[i].data.num.as_signed = 481 (mp_intmax_t)va_arg(arglist, long); 482 else if(vto[i].flags & FLAGS_UNSIGNED) 483 vto[i].data.num.as_unsigned = 484 (mp_uintmax_t)va_arg(arglist, unsigned int); 485 else 486 vto[i].data.num.as_signed = 487 (mp_intmax_t)va_arg(arglist, int); 488 } 489 break; 490 491 case FORMAT_DOUBLE: 492 vto[i].data.dnum = va_arg(arglist, double); 493 break; 494 495 case FORMAT_WIDTH: 496 /* Argument has been read. Silently convert it into an integer 497 * for later use 498 */ 499 vto[i].type = FORMAT_INT; 500 break; 501 502 default: 503 break; 504 } 505 } 506 507 return max_param; 508 509} 510 511static int dprintf_formatf( 512 void *data, /* untouched by format(), just sent to the stream() function in 513 the second argument */ 514 /* function pointer called for each output character */ 515 int (*stream)(int, FILE *), 516 const char *format, /* %-formatted string */ 517 va_list ap_save) /* list of parameters */ 518{ 519 /* Base-36 digits for numbers. */ 520 const char *digits = lower_digits; 521 522 /* Pointer into the format string. */ 523 char *f; 524 525 /* Number of characters written. */ 526 int done = 0; 527 528 long param; /* current parameter to read */ 529 long param_num=0; /* parameter counter */ 530 531 va_stack_t vto[MAX_PARAMETERS]; 532 char *endpos[MAX_PARAMETERS]; 533 char **end; 534 535 char work[BUFFSIZE]; 536 537 va_stack_t *p; 538 539 /* Do the actual %-code parsing */ 540 dprintf_Pass1(format, vto, endpos, ap_save); 541 542 end = &endpos[0]; /* the initial end-position from the list dprintf_Pass1() 543 created for us */ 544 545 f = (char *)format; 546 while(*f != '\0') { 547 /* Format spec modifiers. */ 548 int is_alt; 549 550 /* Width of a field. */ 551 long width; 552 553 /* Precision of a field. */ 554 long prec; 555 556 /* Decimal integer is negative. */ 557 int is_neg; 558 559 /* Base of a number to be written. */ 560 long base; 561 562 /* Integral values to be written. */ 563 mp_uintmax_t num; 564 565 /* Used to convert negative in positive. */ 566 mp_intmax_t signed_num; 567 568 if(*f != '%') { 569 /* This isn't a format spec, so write everything out until the next one 570 OR end of string is reached. */ 571 do { 572 OUTCHAR(*f); 573 } while(*++f && ('%' != *f)); 574 continue; 575 } 576 577 ++f; 578 579 /* Check for "%%". Note that although the ANSI standard lists 580 '%' as a conversion specifier, it says "The complete format 581 specification shall be `%%'," so we can avoid all the width 582 and precision processing. */ 583 if(*f == '%') { 584 ++f; 585 OUTCHAR('%'); 586 continue; 587 } 588 589 /* If this is a positional parameter, the position must follow immediately 590 after the %, thus create a %<num>$ sequence */ 591 param=dprintf_DollarString(f, &f); 592 593 if(!param) 594 param = param_num; 595 else 596 --param; 597 598 param_num++; /* increase this always to allow "%2$s %1$s %s" and then the 599 third %s will pick the 3rd argument */ 600 601 p = &vto[param]; 602 603 /* pick up the specified width */ 604 if(p->flags & FLAGS_WIDTHPARAM) 605 width = (long)vto[p->width].data.num.as_signed; 606 else 607 width = p->width; 608 609 /* pick up the specified precision */ 610 if(p->flags & FLAGS_PRECPARAM) { 611 prec = (long)vto[p->precision].data.num.as_signed; 612 param_num++; /* since the precision is extraced from a parameter, we 613 must skip that to get to the next one properly */ 614 } 615 else if(p->flags & FLAGS_PREC) 616 prec = p->precision; 617 else 618 prec = -1; 619 620 is_alt = (p->flags & FLAGS_ALT) ? 1 : 0; 621 622 switch (p->type) { 623 case FORMAT_INT: 624 num = p->data.num.as_unsigned; 625 if(p->flags & FLAGS_CHAR) { 626 /* Character. */ 627 if(!(p->flags & FLAGS_LEFT)) 628 while(--width > 0) 629 OUTCHAR(' '); 630 OUTCHAR((char) num); 631 if(p->flags & FLAGS_LEFT) 632 while(--width > 0) 633 OUTCHAR(' '); 634 break; 635 } 636 if(p->flags & FLAGS_UNSIGNED) { 637 /* Decimal unsigned integer. */ 638 base = 10; 639 goto unsigned_number; 640 } 641 if(p->flags & FLAGS_OCTAL) { 642 /* Octal unsigned integer. */ 643 base = 8; 644 goto unsigned_number; 645 } 646 if(p->flags & FLAGS_HEX) { 647 /* Hexadecimal unsigned integer. */ 648 649 digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits; 650 base = 16; 651 goto unsigned_number; 652 } 653 654 /* Decimal integer. */ 655 base = 10; 656 657 is_neg = (p->data.num.as_signed < (mp_intmax_t)0) ? 1 : 0; 658 if(is_neg) { 659 /* signed_num might fail to hold absolute negative minimum by 1 */ 660 signed_num = p->data.num.as_signed + (mp_intmax_t)1; 661 signed_num = -signed_num; 662 num = (mp_uintmax_t)signed_num; 663 num += (mp_uintmax_t)1; 664 } 665 666 goto number; 667 668 unsigned_number: 669 /* Unsigned number of base BASE. */ 670 is_neg = 0; 671 672 number: 673 /* Number of base BASE. */ 674 { 675 char *workend = &work[sizeof(work) - 1]; 676 char *w; 677 678 /* Supply a default precision if none was given. */ 679 if(prec == -1) 680 prec = 1; 681 682 /* Put the number in WORK. */ 683 w = workend; 684 while(num > 0) { 685 *w-- = digits[num % base]; 686 num /= base; 687 } 688 width -= (long)(workend - w); 689 prec -= (long)(workend - w); 690 691 if(is_alt && base == 8 && prec <= 0) { 692 *w-- = '0'; 693 --width; 694 } 695 696 if(prec > 0) { 697 width -= prec; 698 while(prec-- > 0) 699 *w-- = '0'; 700 } 701 702 if(is_alt && base == 16) 703 width -= 2; 704 705 if(is_neg || (p->flags & FLAGS_SHOWSIGN) || (p->flags & FLAGS_SPACE)) 706 --width; 707 708 if(!(p->flags & FLAGS_LEFT) && !(p->flags & FLAGS_PAD_NIL)) 709 while(width-- > 0) 710 OUTCHAR(' '); 711 712 if(is_neg) 713 OUTCHAR('-'); 714 else if(p->flags & FLAGS_SHOWSIGN) 715 OUTCHAR('+'); 716 else if(p->flags & FLAGS_SPACE) 717 OUTCHAR(' '); 718 719 if(is_alt && base == 16) { 720 OUTCHAR('0'); 721 if(p->flags & FLAGS_UPPER) 722 OUTCHAR('X'); 723 else 724 OUTCHAR('x'); 725 } 726 727 if(!(p->flags & FLAGS_LEFT) && (p->flags & FLAGS_PAD_NIL)) 728 while(width-- > 0) 729 OUTCHAR('0'); 730 731 /* Write the number. */ 732 while(++w <= workend) { 733 OUTCHAR(*w); 734 } 735 736 if(p->flags & FLAGS_LEFT) 737 while(width-- > 0) 738 OUTCHAR(' '); 739 } 740 break; 741 742 case FORMAT_STRING: 743 /* String. */ 744 { 745 static const char null[] = "(nil)"; 746 const char *str; 747 size_t len; 748 749 str = (char *) p->data.str; 750 if(str == NULL) { 751 /* Write null[] if there's space. */ 752 if(prec == -1 || prec >= (long) sizeof(null) - 1) { 753 str = null; 754 len = sizeof(null) - 1; 755 /* Disable quotes around (nil) */ 756 p->flags &= (~FLAGS_ALT); 757 } 758 else { 759 str = ""; 760 len = 0; 761 } 762 } 763 else 764 len = strlen(str); 765 766 if(prec != -1 && (size_t) prec < len) 767 len = (size_t)prec; 768 width -= (long)len; 769 770 if(p->flags & FLAGS_ALT) 771 OUTCHAR('"'); 772 773 if(!(p->flags&FLAGS_LEFT)) 774 while(width-- > 0) 775 OUTCHAR(' '); 776 777 while(len-- > 0) 778 OUTCHAR(*str++); 779 if(p->flags&FLAGS_LEFT) 780 while(width-- > 0) 781 OUTCHAR(' '); 782 783 if(p->flags & FLAGS_ALT) 784 OUTCHAR('"'); 785 } 786 break; 787 788 case FORMAT_PTR: 789 /* Generic pointer. */ 790 { 791 void *ptr; 792 ptr = (void *) p->data.ptr; 793 if(ptr != NULL) { 794 /* If the pointer is not NULL, write it as a %#x spec. */ 795 base = 16; 796 digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits; 797 is_alt = 1; 798 num = (size_t) ptr; 799 is_neg = 0; 800 goto number; 801 } 802 else { 803 /* Write "(nil)" for a nil pointer. */ 804 static const char strnil[] = "(nil)"; 805 const char *point; 806 807 width -= (long)(sizeof(strnil) - 1); 808 if(p->flags & FLAGS_LEFT) 809 while(width-- > 0) 810 OUTCHAR(' '); 811 for(point = strnil; *point != '\0'; ++point) 812 OUTCHAR(*point); 813 if(! (p->flags & FLAGS_LEFT)) 814 while(width-- > 0) 815 OUTCHAR(' '); 816 } 817 } 818 break; 819 820 case FORMAT_DOUBLE: 821 { 822 char formatbuf[32]="%"; 823 char *fptr = &formatbuf[1]; 824 size_t left = sizeof(formatbuf)-strlen(formatbuf); 825 int len; 826 827 width = -1; 828 if(p->flags & FLAGS_WIDTH) 829 width = p->width; 830 else if(p->flags & FLAGS_WIDTHPARAM) 831 width = (long)vto[p->width].data.num.as_signed; 832 833 prec = -1; 834 if(p->flags & FLAGS_PREC) 835 prec = p->precision; 836 else if(p->flags & FLAGS_PRECPARAM) 837 prec = (long)vto[p->precision].data.num.as_signed; 838 839 if(p->flags & FLAGS_LEFT) 840 *fptr++ = '-'; 841 if(p->flags & FLAGS_SHOWSIGN) 842 *fptr++ = '+'; 843 if(p->flags & FLAGS_SPACE) 844 *fptr++ = ' '; 845 if(p->flags & FLAGS_ALT) 846 *fptr++ = '#'; 847 848 *fptr = 0; 849 850 if(width >= 0) { 851 /* RECURSIVE USAGE */ 852 len = curl_msnprintf(fptr, left, "%ld", width); 853 fptr += len; 854 left -= len; 855 } 856 if(prec >= 0) { 857 /* RECURSIVE USAGE */ 858 len = curl_msnprintf(fptr, left, ".%ld", prec); 859 fptr += len; 860 } 861 if(p->flags & FLAGS_LONG) 862 *fptr++ = 'l'; 863 864 if(p->flags & FLAGS_FLOATE) 865 *fptr++ = (char)((p->flags & FLAGS_UPPER) ? 'E':'e'); 866 else if(p->flags & FLAGS_FLOATG) 867 *fptr++ = (char)((p->flags & FLAGS_UPPER) ? 'G' : 'g'); 868 else 869 *fptr++ = 'f'; 870 871 *fptr = 0; /* and a final zero termination */ 872 873 /* NOTE NOTE NOTE!! Not all sprintf implementations return number of 874 output characters */ 875 (sprintf)(work, formatbuf, p->data.dnum); 876 877 for(fptr=work; *fptr; fptr++) 878 OUTCHAR(*fptr); 879 } 880 break; 881 882 case FORMAT_INTPTR: 883 /* Answer the count of characters written. */ 884#ifdef HAVE_LONG_LONG_TYPE 885 if(p->flags & FLAGS_LONGLONG) 886 *(LONG_LONG_TYPE *) p->data.ptr = (LONG_LONG_TYPE)done; 887 else 888#endif 889 if(p->flags & FLAGS_LONG) 890 *(long *) p->data.ptr = (long)done; 891 else if(!(p->flags & FLAGS_SHORT)) 892 *(int *) p->data.ptr = (int)done; 893 else 894 *(short *) p->data.ptr = (short)done; 895 break; 896 897 default: 898 break; 899 } 900 f = *end++; /* goto end of %-code */ 901 902 } 903 return done; 904} 905 906/* fputc() look-alike */ 907static int addbyter(int output, FILE *data) 908{ 909 struct nsprintf *infop=(struct nsprintf *)data; 910 unsigned char outc = (unsigned char)output; 911 912 if(infop->length < infop->max) { 913 /* only do this if we haven't reached max length yet */ 914 infop->buffer[0] = outc; /* store */ 915 infop->buffer++; /* increase pointer */ 916 infop->length++; /* we are now one byte larger */ 917 return outc; /* fputc() returns like this on success */ 918 } 919 return -1; 920} 921 922int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format, 923 va_list ap_save) 924{ 925 int retcode; 926 struct nsprintf info; 927 928 info.buffer = buffer; 929 info.length = 0; 930 info.max = maxlength; 931 932 retcode = dprintf_formatf(&info, addbyter, format, ap_save); 933 if(info.max) { 934 /* we terminate this with a zero byte */ 935 if(info.max == info.length) 936 /* we're at maximum, scrap the last letter */ 937 info.buffer[-1] = 0; 938 else 939 info.buffer[0] = 0; 940 } 941 return retcode; 942} 943 944int curl_msnprintf(char *buffer, size_t maxlength, const char *format, ...) 945{ 946 int retcode; 947 va_list ap_save; /* argument pointer */ 948 va_start(ap_save, format); 949 retcode = curl_mvsnprintf(buffer, maxlength, format, ap_save); 950 va_end(ap_save); 951 return retcode; 952} 953 954/* fputc() look-alike */ 955static int alloc_addbyter(int output, FILE *data) 956{ 957 struct asprintf *infop=(struct asprintf *)data; 958 unsigned char outc = (unsigned char)output; 959 960 if(!infop->buffer) { 961 infop->buffer = malloc(32); 962 if(!infop->buffer) { 963 infop->fail = 1; 964 return -1; /* fail */ 965 } 966 infop->alloc = 32; 967 infop->len =0; 968 } 969 else if(infop->len+1 >= infop->alloc) { 970 char *newptr; 971 972 newptr = realloc(infop->buffer, infop->alloc*2); 973 974 if(!newptr) { 975 infop->fail = 1; 976 return -1; /* fail */ 977 } 978 infop->buffer = newptr; 979 infop->alloc *= 2; 980 } 981 982 infop->buffer[ infop->len ] = outc; 983 984 infop->len++; 985 986 return outc; /* fputc() returns like this on success */ 987} 988 989char *curl_maprintf(const char *format, ...) 990{ 991 va_list ap_save; /* argument pointer */ 992 int retcode; 993 struct asprintf info; 994 995 info.buffer = NULL; 996 info.len = 0; 997 info.alloc = 0; 998 info.fail = 0; 999 1000 va_start(ap_save, format); 1001 retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save); 1002 va_end(ap_save); 1003 if((-1 == retcode) || info.fail) { 1004 if(info.alloc) 1005 free(info.buffer); 1006 return NULL; 1007 } 1008 if(info.alloc) { 1009 info.buffer[info.len] = 0; /* we terminate this with a zero byte */ 1010 return info.buffer; 1011 } 1012 else 1013 return strdup(""); 1014} 1015 1016char *curl_mvaprintf(const char *format, va_list ap_save) 1017{ 1018 int retcode; 1019 struct asprintf info; 1020 1021 info.buffer = NULL; 1022 info.len = 0; 1023 info.alloc = 0; 1024 info.fail = 0; 1025 1026 retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save); 1027 if((-1 == retcode) || info.fail) { 1028 if(info.alloc) 1029 free(info.buffer); 1030 return NULL; 1031 } 1032 1033 if(info.alloc) { 1034 info.buffer[info.len] = 0; /* we terminate this with a zero byte */ 1035 return info.buffer; 1036 } 1037 else 1038 return strdup(""); 1039} 1040 1041static int storebuffer(int output, FILE *data) 1042{ 1043 char **buffer = (char **)data; 1044 unsigned char outc = (unsigned char)output; 1045 **buffer = outc; 1046 (*buffer)++; 1047 return outc; /* act like fputc() ! */ 1048} 1049 1050int curl_msprintf(char *buffer, const char *format, ...) 1051{ 1052 va_list ap_save; /* argument pointer */ 1053 int retcode; 1054 va_start(ap_save, format); 1055 retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save); 1056 va_end(ap_save); 1057 *buffer=0; /* we terminate this with a zero byte */ 1058 return retcode; 1059} 1060 1061int curl_mprintf(const char *format, ...) 1062{ 1063 int retcode; 1064 va_list ap_save; /* argument pointer */ 1065 va_start(ap_save, format); 1066 1067 retcode = dprintf_formatf(stdout, fputc, format, ap_save); 1068 va_end(ap_save); 1069 return retcode; 1070} 1071 1072int curl_mfprintf(FILE *whereto, const char *format, ...) 1073{ 1074 int retcode; 1075 va_list ap_save; /* argument pointer */ 1076 va_start(ap_save, format); 1077 retcode = dprintf_formatf(whereto, fputc, format, ap_save); 1078 va_end(ap_save); 1079 return retcode; 1080} 1081 1082int curl_mvsprintf(char *buffer, const char *format, va_list ap_save) 1083{ 1084 int retcode; 1085 retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save); 1086 *buffer=0; /* we terminate this with a zero byte */ 1087 return retcode; 1088} 1089 1090int curl_mvprintf(const char *format, va_list ap_save) 1091{ 1092 return dprintf_formatf(stdout, fputc, format, ap_save); 1093} 1094 1095int curl_mvfprintf(FILE *whereto, const char *format, va_list ap_save) 1096{ 1097 return dprintf_formatf(whereto, fputc, format, ap_save); 1098} 1099