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