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