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