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