prprf.c (27882B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 /* 7 ** Portable safe sprintf code. 8 ** 9 ** Author: Kipp E.B. Hickman 10 */ 11 #include <stdarg.h> 12 #include <stddef.h> 13 #include <stdio.h> 14 #include <string.h> 15 #include "primpl.h" 16 #include "prprf.h" 17 #include "prlong.h" 18 #include "prlog.h" 19 #include "prmem.h" 20 21 #if defined(_MSC_VER) && _MSC_VER < 1900 22 # define snprintf _snprintf 23 #endif 24 25 /* 26 ** WARNING: This code may *NOT* call PR_LOG (because PR_LOG calls it) 27 */ 28 29 /* 30 ** XXX This needs to be internationalized! 31 */ 32 33 typedef struct SprintfStateStr SprintfState; 34 35 struct SprintfStateStr { 36 int (*stuff)(SprintfState* ss, const char* sp, PRUint32 len); 37 38 char* base; 39 char* cur; 40 PRUint32 maxlen; /* Must not exceed PR_INT32_MAX. */ 41 42 int (*func)(void* arg, const char* sp, PRUint32 len); 43 void* arg; 44 }; 45 46 /* 47 ** Numbered Argument 48 */ 49 struct NumArg { 50 int type; /* type of the numbered argument */ 51 union { /* the numbered argument */ 52 int i; 53 unsigned int ui; 54 PRInt32 i32; 55 PRUint32 ui32; 56 PRInt64 ll; 57 PRUint64 ull; 58 double d; 59 const char* s; 60 int* ip; 61 #ifdef WIN32 62 const WCHAR* ws; 63 #endif 64 } u; 65 }; 66 67 #define NAS_DEFAULT_NUM 20 /* default number of NumberedArgument array */ 68 69 /* 70 ** For numeric types, the signed versions must have even values, 71 ** and their corresponding unsigned versions must have the subsequent 72 ** odd value. 73 */ 74 #define TYPE_INT16 0 75 #define TYPE_UINT16 1 76 #define TYPE_INTN 2 77 #define TYPE_UINTN 3 78 #define TYPE_INT32 4 79 #define TYPE_UINT32 5 80 #define TYPE_INT64 6 81 #define TYPE_UINT64 7 82 #define TYPE_STRING 8 83 #define TYPE_DOUBLE 9 84 #define TYPE_INTSTR 10 85 #ifdef WIN32 86 # define TYPE_WSTRING 11 87 #endif 88 #define TYPE_UNKNOWN 20 89 90 #define FLAG_LEFT 0x1 91 #define FLAG_SIGNED 0x2 92 #define FLAG_SPACED 0x4 93 #define FLAG_ZEROS 0x8 94 #define FLAG_NEG 0x10 95 96 /* 97 ** Fill into the buffer using the data in src 98 */ 99 static int fill2(SprintfState* ss, const char* src, int srclen, int width, 100 int flags) { 101 char space = ' '; 102 int rv; 103 104 width -= srclen; 105 if ((width > 0) && ((flags & FLAG_LEFT) == 0)) { /* Right adjusting */ 106 if (flags & FLAG_ZEROS) { 107 space = '0'; 108 } 109 while (--width >= 0) { 110 rv = (*ss->stuff)(ss, &space, 1); 111 if (rv < 0) { 112 return rv; 113 } 114 } 115 } 116 117 /* Copy out the source data */ 118 rv = (*ss->stuff)(ss, src, srclen); 119 if (rv < 0) { 120 return rv; 121 } 122 123 if ((width > 0) && ((flags & FLAG_LEFT) != 0)) { /* Left adjusting */ 124 while (--width >= 0) { 125 rv = (*ss->stuff)(ss, &space, 1); 126 if (rv < 0) { 127 return rv; 128 } 129 } 130 } 131 return 0; 132 } 133 134 /* 135 ** Fill a number. The order is: optional-sign zero-filling conversion-digits 136 */ 137 static int fill_n(SprintfState* ss, const char* src, int srclen, int width, 138 int prec, int type, int flags) { 139 int zerowidth = 0; 140 int precwidth = 0; 141 int signwidth = 0; 142 int leftspaces = 0; 143 int rightspaces = 0; 144 int cvtwidth; 145 int rv; 146 char sign; 147 148 if ((type & 1) == 0) { 149 if (flags & FLAG_NEG) { 150 sign = '-'; 151 signwidth = 1; 152 } else if (flags & FLAG_SIGNED) { 153 sign = '+'; 154 signwidth = 1; 155 } else if (flags & FLAG_SPACED) { 156 sign = ' '; 157 signwidth = 1; 158 } 159 } 160 cvtwidth = signwidth + srclen; 161 162 if (prec > 0) { 163 if (prec > srclen) { 164 precwidth = prec - srclen; /* Need zero filling */ 165 cvtwidth += precwidth; 166 } 167 } 168 169 if ((flags & FLAG_ZEROS) && (prec < 0)) { 170 if (width > cvtwidth) { 171 zerowidth = width - cvtwidth; /* Zero filling */ 172 cvtwidth += zerowidth; 173 } 174 } 175 176 if (flags & FLAG_LEFT) { 177 if (width > cvtwidth) { 178 /* Space filling on the right (i.e. left adjusting) */ 179 rightspaces = width - cvtwidth; 180 } 181 } else { 182 if (width > cvtwidth) { 183 /* Space filling on the left (i.e. right adjusting) */ 184 leftspaces = width - cvtwidth; 185 } 186 } 187 while (--leftspaces >= 0) { 188 rv = (*ss->stuff)(ss, " ", 1); 189 if (rv < 0) { 190 return rv; 191 } 192 } 193 if (signwidth) { 194 rv = (*ss->stuff)(ss, &sign, 1); 195 if (rv < 0) { 196 return rv; 197 } 198 } 199 while (--precwidth >= 0) { 200 rv = (*ss->stuff)(ss, "0", 1); 201 if (rv < 0) { 202 return rv; 203 } 204 } 205 while (--zerowidth >= 0) { 206 rv = (*ss->stuff)(ss, "0", 1); 207 if (rv < 0) { 208 return rv; 209 } 210 } 211 rv = (*ss->stuff)(ss, src, srclen); 212 if (rv < 0) { 213 return rv; 214 } 215 while (--rightspaces >= 0) { 216 rv = (*ss->stuff)(ss, " ", 1); 217 if (rv < 0) { 218 return rv; 219 } 220 } 221 return 0; 222 } 223 224 /* 225 ** Convert a long into its printable form 226 */ 227 static int cvt_l(SprintfState* ss, long num, int width, int prec, int radix, 228 int type, int flags, const char* hexp) { 229 char cvtbuf[100]; 230 char* cvt; 231 int digits; 232 233 /* according to the man page this needs to happen */ 234 if ((prec == 0) && (num == 0)) { 235 return 0; 236 } 237 238 /* 239 ** Converting decimal is a little tricky. In the unsigned case we 240 ** need to stop when we hit 10 digits. In the signed case, we can 241 ** stop when the number is zero. 242 */ 243 cvt = cvtbuf + sizeof(cvtbuf); 244 digits = 0; 245 while (num) { 246 int digit = (((unsigned long)num) % radix) & 0xF; 247 *--cvt = hexp[digit]; 248 digits++; 249 num = (long)(((unsigned long)num) / radix); 250 } 251 if (digits == 0) { 252 *--cvt = '0'; 253 digits++; 254 } 255 256 /* 257 ** Now that we have the number converted without its sign, deal with 258 ** the sign and zero padding. 259 */ 260 return fill_n(ss, cvt, digits, width, prec, type, flags); 261 } 262 263 /* 264 ** Convert a 64-bit integer into its printable form 265 */ 266 static int cvt_ll(SprintfState* ss, PRInt64 num, int width, int prec, int radix, 267 int type, int flags, const char* hexp) { 268 char cvtbuf[100]; 269 char* cvt; 270 int digits; 271 PRInt64 rad; 272 273 /* according to the man page this needs to happen */ 274 if ((prec == 0) && (LL_IS_ZERO(num))) { 275 return 0; 276 } 277 278 /* 279 ** Converting decimal is a little tricky. In the unsigned case we 280 ** need to stop when we hit 10 digits. In the signed case, we can 281 ** stop when the number is zero. 282 */ 283 LL_I2L(rad, radix); 284 cvt = cvtbuf + sizeof(cvtbuf); 285 digits = 0; 286 while (!LL_IS_ZERO(num)) { 287 PRInt32 digit; 288 PRInt64 quot, rem; 289 LL_UDIVMOD(", &rem, num, rad); 290 LL_L2I(digit, rem); 291 *--cvt = hexp[digit & 0xf]; 292 digits++; 293 num = quot; 294 } 295 if (digits == 0) { 296 *--cvt = '0'; 297 digits++; 298 } 299 300 /* 301 ** Now that we have the number converted without its sign, deal with 302 ** the sign and zero padding. 303 */ 304 return fill_n(ss, cvt, digits, width, prec, type, flags); 305 } 306 307 /* 308 ** Convert a double precision floating point number into its printable 309 ** form. 310 ** 311 ** XXX stop using snprintf to convert floating point 312 */ 313 static int cvt_f(SprintfState* ss, double d, const char* fmt0, 314 const char* fmt1) { 315 char fin[20]; 316 char fout[300]; 317 int amount = fmt1 - fmt0; 318 319 if (amount <= 0 || amount >= sizeof(fin)) { 320 /* Totally bogus % command to snprintf. Just ignore it */ 321 return 0; 322 } 323 memcpy(fin, fmt0, amount); 324 fin[amount] = 0; 325 326 /* Convert floating point using the native snprintf code */ 327 #ifdef DEBUG 328 { 329 const char* p = fin; 330 while (*p) { 331 PR_ASSERT(*p != 'L'); 332 p++; 333 } 334 } 335 #endif 336 memset(fout, 0, sizeof(fout)); 337 snprintf(fout, sizeof(fout), fin, d); 338 /* Explicitly null-terminate fout because on Windows snprintf doesn't 339 * append a null-terminator if the buffer is too small. */ 340 fout[sizeof(fout) - 1] = '\0'; 341 342 return (*ss->stuff)(ss, fout, strlen(fout)); 343 } 344 345 /* 346 ** Convert a string into its printable form. "width" is the output 347 ** width. "prec" is the maximum number of characters of "s" to output, 348 ** where -1 means until NUL. 349 */ 350 static int cvt_s(SprintfState* ss, const char* str, int width, int prec, 351 int flags) { 352 int slen; 353 354 if (prec == 0) { 355 return 0; 356 } 357 358 /* Limit string length by precision value */ 359 if (!str) { 360 str = "(null)"; 361 } 362 if (prec > 0) { 363 /* this is: slen = strnlen(str, prec); */ 364 register const char* s; 365 366 for (s = str; prec && *s; s++, prec--); 367 slen = s - str; 368 } else { 369 slen = strlen(str); 370 } 371 372 /* and away we go */ 373 return fill2(ss, str, slen, width, flags); 374 } 375 376 /* 377 ** BuildArgArray stands for Numbered Argument list Sprintf 378 ** for example, 379 ** fmt = "%4$i, %2$d, %3s, %1d"; 380 ** the number must start from 1, and no gap among them 381 */ 382 383 static struct NumArg* BuildArgArray(const char* fmt, va_list ap, int* rv, 384 struct NumArg* nasArray) { 385 int number = 0, cn = 0, i; 386 const char* p; 387 char c; 388 struct NumArg* nas; 389 390 /* 391 ** first pass: 392 ** determine how many legal % I have got, then allocate space 393 */ 394 395 p = fmt; 396 *rv = 0; 397 i = 0; 398 while ((c = *p++) != 0) { 399 if (c != '%') { 400 continue; 401 } 402 if ((c = *p++) == '%') { /* skip %% case */ 403 continue; 404 } 405 406 while (c != 0) { 407 if (c > '9' || c < '0') { 408 if (c == '$') { /* numbered argument case */ 409 if (i > 0) { 410 *rv = -1; 411 return NULL; 412 } 413 number++; 414 } else { /* non-numbered argument case */ 415 if (number > 0) { 416 *rv = -1; 417 return NULL; 418 } 419 i = 1; 420 } 421 break; 422 } 423 424 c = *p++; 425 } 426 } 427 428 if (number == 0) { 429 return NULL; 430 } 431 432 if (number > NAS_DEFAULT_NUM) { 433 nas = (struct NumArg*)PR_MALLOC(number * sizeof(struct NumArg)); 434 if (!nas) { 435 *rv = -1; 436 return NULL; 437 } 438 } else { 439 nas = nasArray; 440 } 441 442 for (i = 0; i < number; i++) { 443 nas[i].type = TYPE_UNKNOWN; 444 } 445 446 /* 447 ** second pass: 448 ** set nas[].type 449 */ 450 451 p = fmt; 452 while ((c = *p++) != 0) { 453 if (c != '%') { 454 continue; 455 } 456 c = *p++; 457 if (c == '%') { 458 continue; 459 } 460 461 cn = 0; 462 while (c && c != '$') { /* should improve error check later */ 463 cn = cn * 10 + c - '0'; 464 c = *p++; 465 } 466 467 if (!c || cn < 1 || cn > number) { 468 *rv = -1; 469 break; 470 } 471 472 /* nas[cn] starts from 0, and make sure nas[cn].type is not assigned */ 473 cn--; 474 if (nas[cn].type != TYPE_UNKNOWN) { 475 continue; 476 } 477 478 c = *p++; 479 480 /* width */ 481 if (c == '*') { 482 /* not supported feature, for the argument is not numbered */ 483 *rv = -1; 484 break; 485 } 486 487 while ((c >= '0') && (c <= '9')) { 488 c = *p++; 489 } 490 491 /* precision */ 492 if (c == '.') { 493 c = *p++; 494 if (c == '*') { 495 /* not supported feature, for the argument is not numbered */ 496 *rv = -1; 497 break; 498 } 499 500 while ((c >= '0') && (c <= '9')) { 501 c = *p++; 502 } 503 } 504 505 /* size */ 506 nas[cn].type = TYPE_INTN; 507 if (c == 'h') { 508 nas[cn].type = TYPE_INT16; 509 c = *p++; 510 } else if (c == 'L') { 511 /* XXX not quite sure here */ 512 nas[cn].type = TYPE_INT64; 513 c = *p++; 514 } else if (c == 'l') { 515 nas[cn].type = TYPE_INT32; 516 c = *p++; 517 if (c == 'l') { 518 nas[cn].type = TYPE_INT64; 519 c = *p++; 520 } 521 } else if (c == 'z') { 522 if (sizeof(size_t) == sizeof(PRInt32)) { 523 nas[cn].type = TYPE_INT32; 524 } else if (sizeof(size_t) == sizeof(PRInt64)) { 525 nas[cn].type = TYPE_INT64; 526 } else { 527 nas[cn].type = TYPE_UNKNOWN; 528 } 529 c = *p++; 530 } 531 532 /* format */ 533 switch (c) { 534 case 'd': 535 case 'c': 536 case 'i': 537 case 'o': 538 case 'u': 539 case 'x': 540 case 'X': 541 break; 542 543 case 'e': 544 case 'f': 545 case 'g': 546 nas[cn].type = TYPE_DOUBLE; 547 break; 548 549 case 'p': 550 /* XXX should use cpp */ 551 if (sizeof(void*) == sizeof(PRInt32)) { 552 nas[cn].type = TYPE_UINT32; 553 } else if (sizeof(void*) == sizeof(PRInt64)) { 554 nas[cn].type = TYPE_UINT64; 555 } else if (sizeof(void*) == sizeof(PRIntn)) { 556 nas[cn].type = TYPE_UINTN; 557 } else { 558 nas[cn].type = TYPE_UNKNOWN; 559 } 560 break; 561 562 case 'S': 563 #ifdef WIN32 564 nas[cn].type = TYPE_WSTRING; 565 break; 566 #endif 567 case 'C': 568 case 'E': 569 case 'G': 570 /* XXX not supported I suppose */ 571 PR_ASSERT(0); 572 nas[cn].type = TYPE_UNKNOWN; 573 break; 574 575 case 's': 576 nas[cn].type = TYPE_STRING; 577 break; 578 579 case 'n': 580 nas[cn].type = TYPE_INTSTR; 581 break; 582 583 default: 584 PR_ASSERT(0); 585 nas[cn].type = TYPE_UNKNOWN; 586 break; 587 } 588 589 /* get a legal para. */ 590 if (nas[cn].type == TYPE_UNKNOWN) { 591 *rv = -1; 592 break; 593 } 594 } 595 596 /* 597 ** third pass 598 ** fill the nas[cn].ap 599 */ 600 601 if (*rv < 0) { 602 if (nas != nasArray) { 603 PR_DELETE(nas); 604 } 605 return NULL; 606 } 607 608 cn = 0; 609 while (cn < number) { 610 if (nas[cn].type == TYPE_UNKNOWN) { 611 cn++; 612 continue; 613 } 614 615 switch (nas[cn].type) { 616 case TYPE_INT16: 617 case TYPE_UINT16: 618 case TYPE_INTN: 619 nas[cn].u.i = va_arg(ap, int); 620 break; 621 622 case TYPE_UINTN: 623 nas[cn].u.ui = va_arg(ap, unsigned int); 624 break; 625 626 case TYPE_INT32: 627 nas[cn].u.i32 = va_arg(ap, PRInt32); 628 break; 629 630 case TYPE_UINT32: 631 nas[cn].u.ui32 = va_arg(ap, PRUint32); 632 break; 633 634 case TYPE_INT64: 635 nas[cn].u.ll = va_arg(ap, PRInt64); 636 break; 637 638 case TYPE_UINT64: 639 nas[cn].u.ull = va_arg(ap, PRUint64); 640 break; 641 642 case TYPE_STRING: 643 nas[cn].u.s = va_arg(ap, char*); 644 break; 645 646 #ifdef WIN32 647 case TYPE_WSTRING: 648 nas[cn].u.ws = va_arg(ap, WCHAR*); 649 break; 650 #endif 651 652 case TYPE_INTSTR: 653 nas[cn].u.ip = va_arg(ap, int*); 654 break; 655 656 case TYPE_DOUBLE: 657 nas[cn].u.d = va_arg(ap, double); 658 break; 659 660 default: 661 if (nas != nasArray) { 662 PR_DELETE(nas); 663 } 664 *rv = -1; 665 return NULL; 666 } 667 668 cn++; 669 } 670 671 return nas; 672 } 673 674 /* 675 ** The workhorse sprintf code. 676 */ 677 static int dosprintf(SprintfState* ss, const char* fmt, va_list ap) { 678 char c; 679 int flags, width, prec, radix, type; 680 union { 681 char ch; 682 int i; 683 long l; 684 PRInt64 ll; 685 double d; 686 const char* s; 687 int* ip; 688 #ifdef WIN32 689 const WCHAR* ws; 690 #endif 691 } u; 692 const char* fmt0; 693 static char* hex = "0123456789abcdef"; 694 static char* HEX = "0123456789ABCDEF"; 695 char* hexp; 696 int rv, i; 697 struct NumArg* nas = NULL; 698 struct NumArg* nap = NULL; 699 struct NumArg nasArray[NAS_DEFAULT_NUM]; 700 char pattern[20]; 701 const char* dolPt = NULL; /* in "%4$.2f", dolPt will point to . */ 702 #ifdef WIN32 703 char* pBuf = NULL; 704 #endif 705 706 /* 707 ** build an argument array, IF the fmt is numbered argument 708 ** list style, to contain the Numbered Argument list pointers 709 */ 710 711 nas = BuildArgArray(fmt, ap, &rv, nasArray); 712 if (rv < 0) { 713 /* the fmt contains error Numbered Argument format, jliu@netscape.com */ 714 PR_ASSERT(0); 715 return rv; 716 } 717 718 while ((c = *fmt++) != 0) { 719 if (c != '%') { 720 rv = (*ss->stuff)(ss, fmt - 1, 1); 721 if (rv < 0) { 722 return rv; 723 } 724 continue; 725 } 726 fmt0 = fmt - 1; 727 728 /* 729 ** Gobble up the % format string. Hopefully we have handled all 730 ** of the strange cases! 731 */ 732 flags = 0; 733 c = *fmt++; 734 if (c == '%') { 735 /* quoting a % with %% */ 736 rv = (*ss->stuff)(ss, fmt - 1, 1); 737 if (rv < 0) { 738 return rv; 739 } 740 continue; 741 } 742 743 if (nas != NULL) { 744 /* the fmt contains the Numbered Arguments feature */ 745 i = 0; 746 while (c && c != '$') { /* should improve error check later */ 747 i = (i * 10) + (c - '0'); 748 c = *fmt++; 749 } 750 751 if (nas[i - 1].type == TYPE_UNKNOWN) { 752 if (nas && (nas != nasArray)) { 753 PR_DELETE(nas); 754 } 755 return -1; 756 } 757 758 nap = &nas[i - 1]; 759 dolPt = fmt; 760 c = *fmt++; 761 } 762 763 /* 764 * Examine optional flags. Note that we do not implement the 765 * '#' flag of sprintf(). The ANSI C spec. of the '#' flag is 766 * somewhat ambiguous and not ideal, which is perhaps why 767 * the various sprintf() implementations are inconsistent 768 * on this feature. 769 */ 770 while ((c == '-') || (c == '+') || (c == ' ') || (c == '0')) { 771 if (c == '-') { 772 flags |= FLAG_LEFT; 773 } 774 if (c == '+') { 775 flags |= FLAG_SIGNED; 776 } 777 if (c == ' ') { 778 flags |= FLAG_SPACED; 779 } 780 if (c == '0') { 781 flags |= FLAG_ZEROS; 782 } 783 c = *fmt++; 784 } 785 if (flags & FLAG_SIGNED) { 786 flags &= ~FLAG_SPACED; 787 } 788 if (flags & FLAG_LEFT) { 789 flags &= ~FLAG_ZEROS; 790 } 791 792 /* width */ 793 if (c == '*') { 794 c = *fmt++; 795 width = va_arg(ap, int); 796 } else { 797 width = 0; 798 while ((c >= '0') && (c <= '9')) { 799 width = (width * 10) + (c - '0'); 800 c = *fmt++; 801 } 802 } 803 804 /* precision */ 805 prec = -1; 806 if (c == '.') { 807 c = *fmt++; 808 if (c == '*') { 809 c = *fmt++; 810 prec = va_arg(ap, int); 811 } else { 812 prec = 0; 813 while ((c >= '0') && (c <= '9')) { 814 prec = (prec * 10) + (c - '0'); 815 c = *fmt++; 816 } 817 } 818 } 819 820 /* size */ 821 type = TYPE_INTN; 822 if (c == 'h') { 823 type = TYPE_INT16; 824 c = *fmt++; 825 } else if (c == 'L') { 826 /* XXX not quite sure here */ 827 type = TYPE_INT64; 828 c = *fmt++; 829 } else if (c == 'l') { 830 type = TYPE_INT32; 831 c = *fmt++; 832 if (c == 'l') { 833 type = TYPE_INT64; 834 c = *fmt++; 835 } 836 } else if (c == 'z') { 837 if (sizeof(size_t) == sizeof(PRInt32)) { 838 type = TYPE_INT32; 839 } else if (sizeof(size_t) == sizeof(PRInt64)) { 840 type = TYPE_INT64; 841 } 842 c = *fmt++; 843 } 844 845 /* format */ 846 hexp = hex; 847 switch (c) { 848 case 'd': 849 case 'i': /* decimal/integer */ 850 radix = 10; 851 goto fetch_and_convert; 852 853 case 'o': /* octal */ 854 radix = 8; 855 type |= 1; 856 goto fetch_and_convert; 857 858 case 'u': /* unsigned decimal */ 859 radix = 10; 860 type |= 1; 861 goto fetch_and_convert; 862 863 case 'x': /* unsigned hex */ 864 radix = 16; 865 type |= 1; 866 goto fetch_and_convert; 867 868 case 'X': /* unsigned HEX */ 869 radix = 16; 870 hexp = HEX; 871 type |= 1; 872 goto fetch_and_convert; 873 874 fetch_and_convert: 875 switch (type) { 876 case TYPE_INT16: 877 u.l = nas ? nap->u.i : va_arg(ap, int); 878 if (u.l < 0) { 879 u.l = -u.l; 880 flags |= FLAG_NEG; 881 } 882 goto do_long; 883 case TYPE_UINT16: 884 u.l = (nas ? nap->u.i : va_arg(ap, int)) & 0xffff; 885 goto do_long; 886 case TYPE_INTN: 887 u.l = nas ? nap->u.i : va_arg(ap, int); 888 if (u.l < 0) { 889 u.l = -u.l; 890 flags |= FLAG_NEG; 891 } 892 goto do_long; 893 case TYPE_UINTN: 894 u.l = (long)(nas ? nap->u.ui : va_arg(ap, unsigned int)); 895 goto do_long; 896 897 case TYPE_INT32: 898 u.l = nas ? nap->u.i32 : va_arg(ap, PRInt32); 899 if (u.l < 0) { 900 u.l = -u.l; 901 flags |= FLAG_NEG; 902 } 903 goto do_long; 904 case TYPE_UINT32: 905 u.l = (long)(nas ? nap->u.ui32 : va_arg(ap, PRUint32)); 906 do_long: 907 rv = cvt_l(ss, u.l, width, prec, radix, type, flags, hexp); 908 if (rv < 0) { 909 return rv; 910 } 911 break; 912 913 case TYPE_INT64: 914 u.ll = nas ? nap->u.ll : va_arg(ap, PRInt64); 915 if (!LL_GE_ZERO(u.ll)) { 916 LL_NEG(u.ll, u.ll); 917 flags |= FLAG_NEG; 918 } 919 goto do_longlong; 920 case TYPE_UINT64: 921 u.ll = nas ? nap->u.ull : va_arg(ap, PRUint64); 922 do_longlong: 923 rv = cvt_ll(ss, u.ll, width, prec, radix, type, flags, hexp); 924 if (rv < 0) { 925 return rv; 926 } 927 break; 928 } 929 break; 930 931 case 'e': 932 case 'E': 933 case 'f': 934 case 'g': 935 u.d = nas ? nap->u.d : va_arg(ap, double); 936 if (nas != NULL) { 937 i = fmt - dolPt; 938 if (i < sizeof(pattern)) { 939 pattern[0] = '%'; 940 memcpy(&pattern[1], dolPt, i); 941 rv = cvt_f(ss, u.d, pattern, &pattern[i + 1]); 942 } 943 } else { 944 rv = cvt_f(ss, u.d, fmt0, fmt); 945 } 946 947 if (rv < 0) { 948 return rv; 949 } 950 break; 951 952 case 'c': 953 u.ch = nas ? nap->u.i : va_arg(ap, int); 954 if ((flags & FLAG_LEFT) == 0) { 955 while (width-- > 1) { 956 rv = (*ss->stuff)(ss, " ", 1); 957 if (rv < 0) { 958 return rv; 959 } 960 } 961 } 962 rv = (*ss->stuff)(ss, &u.ch, 1); 963 if (rv < 0) { 964 return rv; 965 } 966 if (flags & FLAG_LEFT) { 967 while (width-- > 1) { 968 rv = (*ss->stuff)(ss, " ", 1); 969 if (rv < 0) { 970 return rv; 971 } 972 } 973 } 974 break; 975 976 case 'p': 977 if (sizeof(void*) == sizeof(PRInt32)) { 978 type = TYPE_UINT32; 979 } else if (sizeof(void*) == sizeof(PRInt64)) { 980 type = TYPE_UINT64; 981 } else if (sizeof(void*) == sizeof(int)) { 982 type = TYPE_UINTN; 983 } else { 984 PR_ASSERT(0); 985 break; 986 } 987 radix = 16; 988 goto fetch_and_convert; 989 990 #ifndef WIN32 991 case 'S': 992 /* XXX not supported I suppose */ 993 PR_ASSERT(0); 994 break; 995 #endif 996 997 #if 0 998 case 'C': 999 case 'E': 1000 case 'G': 1001 /* XXX not supported I suppose */ 1002 PR_ASSERT(0); 1003 break; 1004 #endif 1005 1006 #ifdef WIN32 1007 case 'S': 1008 u.ws = nas ? nap->u.ws : va_arg(ap, const WCHAR*); 1009 1010 /* Get the required size in rv */ 1011 rv = WideCharToMultiByte(CP_ACP, 0, u.ws, -1, NULL, 0, NULL, NULL); 1012 if (rv == 0) { 1013 rv = 1; 1014 } 1015 pBuf = PR_MALLOC(rv); 1016 WideCharToMultiByte(CP_ACP, 0, u.ws, -1, pBuf, (int)rv, NULL, NULL); 1017 pBuf[rv - 1] = '\0'; 1018 1019 rv = cvt_s(ss, pBuf, width, prec, flags); 1020 1021 /* We don't need the allocated buffer anymore */ 1022 PR_Free(pBuf); 1023 if (rv < 0) { 1024 return rv; 1025 } 1026 break; 1027 1028 #endif 1029 1030 case 's': 1031 u.s = nas ? nap->u.s : va_arg(ap, const char*); 1032 rv = cvt_s(ss, u.s, width, prec, flags); 1033 if (rv < 0) { 1034 return rv; 1035 } 1036 break; 1037 1038 case 'n': 1039 u.ip = nas ? nap->u.ip : va_arg(ap, int*); 1040 if (u.ip) { 1041 *u.ip = ss->cur - ss->base; 1042 } 1043 break; 1044 1045 default: 1046 /* Not a % token after all... skip it */ 1047 #if 0 1048 PR_ASSERT(0); 1049 #endif 1050 rv = (*ss->stuff)(ss, "%", 1); 1051 if (rv < 0) { 1052 return rv; 1053 } 1054 rv = (*ss->stuff)(ss, fmt - 1, 1); 1055 if (rv < 0) { 1056 return rv; 1057 } 1058 } 1059 } 1060 1061 /* Stuff trailing NUL */ 1062 rv = (*ss->stuff)(ss, "\0", 1); 1063 1064 if (nas && (nas != nasArray)) { 1065 PR_DELETE(nas); 1066 } 1067 1068 return rv; 1069 } 1070 1071 /************************************************************************/ 1072 1073 static int FuncStuff(SprintfState* ss, const char* sp, PRUint32 len) { 1074 int rv; 1075 1076 /* 1077 ** We will add len to ss->maxlen at the end of the function. First check 1078 ** if ss->maxlen + len would overflow or be greater than PR_INT32_MAX. 1079 */ 1080 if (PR_UINT32_MAX - ss->maxlen < len || ss->maxlen + len > PR_INT32_MAX) { 1081 return -1; 1082 } 1083 rv = (*ss->func)(ss->arg, sp, len); 1084 if (rv < 0) { 1085 return rv; 1086 } 1087 ss->maxlen += len; 1088 return 0; 1089 } 1090 1091 PR_IMPLEMENT(PRUint32) 1092 PR_sxprintf(PRStuffFunc func, void* arg, const char* fmt, ...) { 1093 va_list ap; 1094 PRUint32 rv; 1095 1096 va_start(ap, fmt); 1097 rv = PR_vsxprintf(func, arg, fmt, ap); 1098 va_end(ap); 1099 return rv; 1100 } 1101 1102 PR_IMPLEMENT(PRUint32) 1103 PR_vsxprintf(PRStuffFunc func, void* arg, const char* fmt, va_list ap) { 1104 SprintfState ss; 1105 int rv; 1106 1107 ss.stuff = FuncStuff; 1108 ss.func = func; 1109 ss.arg = arg; 1110 ss.maxlen = 0; 1111 rv = dosprintf(&ss, fmt, ap); 1112 return (rv < 0) ? (PRUint32)-1 : ss.maxlen; 1113 } 1114 1115 /* 1116 ** Stuff routine that automatically grows the malloc'd output buffer 1117 ** before it overflows. 1118 */ 1119 static int GrowStuff(SprintfState* ss, const char* sp, PRUint32 len) { 1120 ptrdiff_t off; 1121 char* newbase; 1122 PRUint32 newlen; 1123 1124 off = ss->cur - ss->base; 1125 if (PR_UINT32_MAX - len < off) { 1126 /* off + len would be too big. */ 1127 return -1; 1128 } 1129 if (off + len >= ss->maxlen) { 1130 /* Grow the buffer */ 1131 PRUint32 increment = (len > 32) ? len : 32; 1132 if (PR_UINT32_MAX - ss->maxlen < increment) { 1133 /* ss->maxlen + increment would overflow. */ 1134 return -1; 1135 } 1136 newlen = ss->maxlen + increment; 1137 if (newlen > PR_INT32_MAX) { 1138 return -1; 1139 } 1140 if (ss->base) { 1141 newbase = (char*)PR_REALLOC(ss->base, newlen); 1142 } else { 1143 newbase = (char*)PR_MALLOC(newlen); 1144 } 1145 if (!newbase) { 1146 /* Ran out of memory */ 1147 return -1; 1148 } 1149 ss->base = newbase; 1150 ss->maxlen = newlen; 1151 ss->cur = ss->base + off; 1152 } 1153 1154 /* Copy data */ 1155 while (len) { 1156 --len; 1157 *ss->cur++ = *sp++; 1158 } 1159 PR_ASSERT((PRUint32)(ss->cur - ss->base) <= ss->maxlen); 1160 return 0; 1161 } 1162 1163 /* 1164 ** sprintf into a malloc'd buffer 1165 */ 1166 PR_IMPLEMENT(char*) PR_smprintf(const char* fmt, ...) { 1167 va_list ap; 1168 char* rv; 1169 1170 va_start(ap, fmt); 1171 rv = PR_vsmprintf(fmt, ap); 1172 va_end(ap); 1173 return rv; 1174 } 1175 1176 /* 1177 ** Free memory allocated, for the caller, by PR_smprintf 1178 */ 1179 PR_IMPLEMENT(void) PR_smprintf_free(char* mem) { PR_DELETE(mem); } 1180 1181 PR_IMPLEMENT(char*) PR_vsmprintf(const char* fmt, va_list ap) { 1182 SprintfState ss; 1183 int rv; 1184 1185 ss.stuff = GrowStuff; 1186 ss.base = 0; 1187 ss.cur = 0; 1188 ss.maxlen = 0; 1189 rv = dosprintf(&ss, fmt, ap); 1190 if (rv < 0) { 1191 if (ss.base) { 1192 PR_DELETE(ss.base); 1193 } 1194 return 0; 1195 } 1196 return ss.base; 1197 } 1198 1199 /* 1200 ** Stuff routine that discards overflow data 1201 */ 1202 static int LimitStuff(SprintfState* ss, const char* sp, PRUint32 len) { 1203 PRUint32 limit = ss->maxlen - (ss->cur - ss->base); 1204 1205 if (len > limit) { 1206 len = limit; 1207 } 1208 while (len) { 1209 --len; 1210 *ss->cur++ = *sp++; 1211 } 1212 return 0; 1213 } 1214 1215 /* 1216 ** sprintf into a fixed size buffer. Make sure there is a NUL at the end 1217 ** when finished. 1218 */ 1219 PR_IMPLEMENT(PRUint32) 1220 PR_snprintf(char* out, PRUint32 outlen, const char* fmt, ...) { 1221 va_list ap; 1222 PRUint32 rv; 1223 1224 va_start(ap, fmt); 1225 rv = PR_vsnprintf(out, outlen, fmt, ap); 1226 va_end(ap); 1227 return rv; 1228 } 1229 1230 PR_IMPLEMENT(PRUint32) 1231 PR_vsnprintf(char* out, PRUint32 outlen, const char* fmt, va_list ap) { 1232 SprintfState ss; 1233 PRUint32 n; 1234 1235 PR_ASSERT(outlen != 0 && outlen <= PR_INT32_MAX); 1236 if (outlen == 0 || outlen > PR_INT32_MAX) { 1237 return 0; 1238 } 1239 1240 ss.stuff = LimitStuff; 1241 ss.base = out; 1242 ss.cur = out; 1243 ss.maxlen = outlen; 1244 (void)dosprintf(&ss, fmt, ap); 1245 1246 /* If we added chars, and we didn't append a null, do it now. */ 1247 if ((ss.cur != ss.base) && (*(ss.cur - 1) != '\0')) { 1248 *(ss.cur - 1) = '\0'; 1249 } 1250 1251 n = ss.cur - ss.base; 1252 return n ? n - 1 : n; 1253 } 1254 1255 PR_IMPLEMENT(char*) PR_sprintf_append(char* last, const char* fmt, ...) { 1256 va_list ap; 1257 char* rv; 1258 1259 va_start(ap, fmt); 1260 rv = PR_vsprintf_append(last, fmt, ap); 1261 va_end(ap); 1262 return rv; 1263 } 1264 1265 PR_IMPLEMENT(char*) 1266 PR_vsprintf_append(char* last, const char* fmt, va_list ap) { 1267 SprintfState ss; 1268 int rv; 1269 1270 ss.stuff = GrowStuff; 1271 if (last) { 1272 size_t lastlen = strlen(last); 1273 if (lastlen > PR_INT32_MAX) { 1274 return 0; 1275 } 1276 ss.base = last; 1277 ss.cur = last + lastlen; 1278 ss.maxlen = lastlen; 1279 } else { 1280 ss.base = 0; 1281 ss.cur = 0; 1282 ss.maxlen = 0; 1283 } 1284 rv = dosprintf(&ss, fmt, ap); 1285 if (rv < 0) { 1286 if (ss.base) { 1287 PR_DELETE(ss.base); 1288 } 1289 return 0; 1290 } 1291 return ss.base; 1292 }