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