1/* 2 SDL - Simple DirectMedia Layer 3 Copyright (C) 1997-2012 Sam Lantinga 4 5 This library is free software; you can redistribute it and/or 6 modify it under the terms of the GNU Lesser General Public 7 License as published by the Free Software Foundation; either 8 version 2.1 of the License, or (at your option) any later version. 9 10 This library is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 Lesser General Public License for more details. 14 15 You should have received a copy of the GNU Lesser General Public 16 License along with this library; if not, write to the Free Software 17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 19 Sam Lantinga 20 slouken@libsdl.org 21*/ 22#include "SDL_config.h" 23 24/* This file contains portable string manipulation functions for SDL */ 25 26#include "SDL_stdinc.h" 27 28 29#define SDL_isupperhex(X) (((X) >= 'A') && ((X) <= 'F')) 30#define SDL_islowerhex(X) (((X) >= 'a') && ((X) <= 'f')) 31 32#if !defined(HAVE_SSCANF) || !defined(HAVE_STRTOL) 33static size_t SDL_ScanLong(const char *text, int radix, long *valuep) 34{ 35 const char *textstart = text; 36 long value = 0; 37 SDL_bool negative = SDL_FALSE; 38 39 if ( *text == '-' ) { 40 negative = SDL_TRUE; 41 ++text; 42 } 43 if ( radix == 16 && SDL_strncmp(text, "0x", 2) == 0 ) { 44 text += 2; 45 } 46 for ( ; ; ) { 47 int v; 48 if ( SDL_isdigit((unsigned char) *text) ) { 49 v = *text - '0'; 50 } else if ( radix == 16 && SDL_isupperhex(*text) ) { 51 v = 10 + (*text - 'A'); 52 } else if ( radix == 16 && SDL_islowerhex(*text) ) { 53 v = 10 + (*text - 'a'); 54 } else { 55 break; 56 } 57 value *= radix; 58 value += v; 59 ++text; 60 } 61 if ( valuep ) { 62 if ( negative && value ) { 63 *valuep = -value; 64 } else { 65 *valuep = value; 66 } 67 } 68 return (text - textstart); 69} 70#endif 71 72#if !defined(HAVE_SSCANF) || !defined(HAVE_STRTOUL) || !defined(HAVE_STRTOD) 73static size_t SDL_ScanUnsignedLong(const char *text, int radix, unsigned long *valuep) 74{ 75 const char *textstart = text; 76 unsigned long value = 0; 77 78 if ( radix == 16 && SDL_strncmp(text, "0x", 2) == 0 ) { 79 text += 2; 80 } 81 for ( ; ; ) { 82 int v; 83 if ( SDL_isdigit((unsigned char) *text) ) { 84 v = *text - '0'; 85 } else if ( radix == 16 && SDL_isupperhex(*text) ) { 86 v = 10 + (*text - 'A'); 87 } else if ( radix == 16 && SDL_islowerhex(*text) ) { 88 v = 10 + (*text - 'a'); 89 } else { 90 break; 91 } 92 value *= radix; 93 value += v; 94 ++text; 95 } 96 if ( valuep ) { 97 *valuep = value; 98 } 99 return (text - textstart); 100} 101#endif 102 103#ifndef HAVE_SSCANF 104static size_t SDL_ScanUintPtrT(const char *text, int radix, uintptr_t *valuep) 105{ 106 const char *textstart = text; 107 uintptr_t value = 0; 108 109 if ( radix == 16 && SDL_strncmp(text, "0x", 2) == 0 ) { 110 text += 2; 111 } 112 for ( ; ; ) { 113 int v; 114 if ( SDL_isdigit((unsigned char) *text) ) { 115 v = *text - '0'; 116 } else if ( radix == 16 && SDL_isupperhex(*text) ) { 117 v = 10 + (*text - 'A'); 118 } else if ( radix == 16 && SDL_islowerhex(*text) ) { 119 v = 10 + (*text - 'a'); 120 } else { 121 break; 122 } 123 value *= radix; 124 value += v; 125 ++text; 126 } 127 if ( valuep ) { 128 *valuep = value; 129 } 130 return (text - textstart); 131} 132#endif 133 134#ifdef SDL_HAS_64BIT_TYPE 135#if !defined(HAVE_SSCANF) || !defined(HAVE_STRTOLL) 136static size_t SDL_ScanLongLong(const char *text, int radix, Sint64 *valuep) 137{ 138 const char *textstart = text; 139 Sint64 value = 0; 140 SDL_bool negative = SDL_FALSE; 141 142 if ( *text == '-' ) { 143 negative = SDL_TRUE; 144 ++text; 145 } 146 if ( radix == 16 && SDL_strncmp(text, "0x", 2) == 0 ) { 147 text += 2; 148 } 149 for ( ; ; ) { 150 int v; 151 if ( SDL_isdigit((unsigned char) *text) ) { 152 v = *text - '0'; 153 } else if ( radix == 16 && SDL_isupperhex(*text) ) { 154 v = 10 + (*text - 'A'); 155 } else if ( radix == 16 && SDL_islowerhex(*text) ) { 156 v = 10 + (*text - 'a'); 157 } else { 158 break; 159 } 160 value *= radix; 161 value += v; 162 ++text; 163 } 164 if ( valuep ) { 165 if ( negative && value ) { 166 *valuep = -value; 167 } else { 168 *valuep = value; 169 } 170 } 171 return (text - textstart); 172} 173#endif 174 175#if !defined(HAVE_SSCANF) || !defined(HAVE_STRTOULL) 176static size_t SDL_ScanUnsignedLongLong(const char *text, int radix, Uint64 *valuep) 177{ 178 const char *textstart = text; 179 Uint64 value = 0; 180 181 if ( radix == 16 && SDL_strncmp(text, "0x", 2) == 0 ) { 182 text += 2; 183 } 184 for ( ; ; ) { 185 int v; 186 if ( SDL_isdigit((unsigned char) *text) ) { 187 v = *text - '0'; 188 } else if ( radix == 16 && SDL_isupperhex(*text) ) { 189 v = 10 + (*text - 'A'); 190 } else if ( radix == 16 && SDL_islowerhex(*text) ) { 191 v = 10 + (*text - 'a'); 192 } else { 193 break; 194 } 195 value *= radix; 196 value += v; 197 ++text; 198 } 199 if ( valuep ) { 200 *valuep = value; 201 } 202 return (text - textstart); 203} 204#endif 205#endif /* SDL_HAS_64BIT_TYPE */ 206 207#if !defined(HAVE_SSCANF) || !defined(HAVE_STRTOD) 208static size_t SDL_ScanFloat(const char *text, double *valuep) 209{ 210 const char *textstart = text; 211 unsigned long lvalue = 0; 212 double value = 0.0; 213 SDL_bool negative = SDL_FALSE; 214 215 if ( *text == '-' ) { 216 negative = SDL_TRUE; 217 ++text; 218 } 219 text += SDL_ScanUnsignedLong(text, 10, &lvalue); 220 value += lvalue; 221 if ( *text == '.' ) { 222 int mult = 10; 223 ++text; 224 while ( SDL_isdigit((unsigned char) *text) ) { 225 lvalue = *text - '0'; 226 value += (double)lvalue / mult; 227 mult *= 10; 228 ++text; 229 } 230 } 231 if ( valuep ) { 232 if ( negative && value ) { 233 *valuep = -value; 234 } else { 235 *valuep = value; 236 } 237 } 238 return (text - textstart); 239} 240#endif 241 242#ifndef SDL_memset 243void *SDL_memset(void *dst, int c, size_t len) 244{ 245 size_t left = (len % 4); 246 if ( len >= 4 ) { 247 Uint32 value = 0; 248 Uint32 *dstp = (Uint32 *)dst; 249 int i; 250 for (i = 0; i < 4; ++i) { 251 value <<= 8; 252 value |= c; 253 } 254 len /= 4; 255 while ( len-- ) { 256 *dstp++ = value; 257 } 258 } 259 if ( left > 0 ) { 260 Uint8 value = (Uint8)c; 261 Uint8 *dstp = (Uint8 *)dst; 262 switch(left) { 263 case 3: 264 *dstp++ = value; 265 case 2: 266 *dstp++ = value; 267 case 1: 268 *dstp++ = value; 269 } 270 } 271 return dst; 272} 273#endif 274 275#ifndef SDL_memcpy 276void *SDL_memcpy(void *dst, const void *src, size_t len) 277{ 278 char *srcp = (char *)src; 279 char *dstp = (char *)dst; 280 while ( len-- ) { 281 *dstp++ = *srcp++; 282 } 283 return dst; 284} 285#endif 286 287#ifndef SDL_revcpy 288void *SDL_revcpy(void *dst, const void *src, size_t len) 289{ 290 char *srcp = (char *)src; 291 char *dstp = (char *)dst; 292 srcp += len-1; 293 dstp += len-1; 294 while ( len-- ) { 295 *dstp-- = *srcp--; 296 } 297 return dst; 298} 299#endif 300 301#ifndef SDL_memcmp 302int SDL_memcmp(const void *s1, const void *s2, size_t len) 303{ 304 char *s1p = (char *)s1; 305 char *s2p = (char *)s2; 306 while ( len-- ) { 307 if ( *s1p != *s2p ) { 308 return (*s1p - *s2p); 309 } 310 ++s1p; 311 ++s2p; 312 } 313 return 0; 314} 315#endif 316 317#ifndef HAVE_STRLEN 318size_t SDL_strlen(const char *string) 319{ 320 size_t len = 0; 321 while ( *string++ ) { 322 ++len; 323 } 324 return len; 325} 326#endif 327 328#ifndef HAVE_STRLCPY 329size_t SDL_strlcpy(char *dst, const char *src, size_t maxlen) 330{ 331 size_t srclen = SDL_strlen(src); 332 if ( maxlen > 0 ) { 333 size_t len = SDL_min(srclen, maxlen-1); 334 SDL_memcpy(dst, src, len); 335 dst[len] = '\0'; 336 } 337 return srclen; 338} 339#endif 340 341#ifndef HAVE_STRLCAT 342size_t SDL_strlcat(char *dst, const char *src, size_t maxlen) 343{ 344 size_t dstlen = SDL_strlen(dst); 345 size_t srclen = SDL_strlen(src); 346 if ( dstlen < maxlen ) { 347 SDL_strlcpy(dst+dstlen, src, maxlen-dstlen); 348 } 349 return dstlen+srclen; 350} 351#endif 352 353#ifndef HAVE_STRDUP 354char *SDL_strdup(const char *string) 355{ 356 size_t len = SDL_strlen(string)+1; 357 char *newstr = SDL_malloc(len); 358 if ( newstr ) { 359 SDL_strlcpy(newstr, string, len); 360 } 361 return newstr; 362} 363#endif 364 365#ifndef HAVE__STRREV 366char *SDL_strrev(char *string) 367{ 368 size_t len = SDL_strlen(string); 369 char *a = &string[0]; 370 char *b = &string[len-1]; 371 len /= 2; 372 while ( len-- ) { 373 char c = *a; 374 *a++ = *b; 375 *b-- = c; 376 } 377 return string; 378} 379#endif 380 381#ifndef HAVE__STRUPR 382char *SDL_strupr(char *string) 383{ 384 char *bufp = string; 385 while ( *bufp ) { 386 *bufp = SDL_toupper((unsigned char) *bufp); 387 ++bufp; 388 } 389 return string; 390} 391#endif 392 393#ifndef HAVE__STRLWR 394char *SDL_strlwr(char *string) 395{ 396 char *bufp = string; 397 while ( *bufp ) { 398 *bufp = SDL_tolower((unsigned char) *bufp); 399 ++bufp; 400 } 401 return string; 402} 403#endif 404 405#ifndef HAVE_STRCHR 406char *SDL_strchr(const char *string, int c) 407{ 408 while ( *string ) { 409 if ( *string == c ) { 410 return (char *)string; 411 } 412 ++string; 413 } 414 return NULL; 415} 416#endif 417 418#ifndef HAVE_STRRCHR 419char *SDL_strrchr(const char *string, int c) 420{ 421 const char *bufp = string + SDL_strlen(string) - 1; 422 while ( bufp >= string ) { 423 if ( *bufp == c ) { 424 return (char *)bufp; 425 } 426 --bufp; 427 } 428 return NULL; 429} 430#endif 431 432#ifndef HAVE_STRSTR 433char *SDL_strstr(const char *haystack, const char *needle) 434{ 435 size_t length = SDL_strlen(needle); 436 while ( *haystack ) { 437 if ( SDL_strncmp(haystack, needle, length) == 0 ) { 438 return (char *)haystack; 439 } 440 ++haystack; 441 } 442 return NULL; 443} 444#endif 445 446#if !defined(HAVE__LTOA) || !defined(HAVE__I64TOA) || \ 447 !defined(HAVE__ULTOA) || !defined(HAVE__UI64TOA) 448static const char ntoa_table[] = { 449 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 450 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 451 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 452 'U', 'V', 'W', 'X', 'Y', 'Z' 453}; 454#endif /* ntoa() conversion table */ 455 456#ifndef HAVE__LTOA 457char *SDL_ltoa(long value, char *string, int radix) 458{ 459 char *bufp = string; 460 461 if ( value < 0 ) { 462 *bufp++ = '-'; 463 value = -value; 464 } 465 if ( value ) { 466 while ( value > 0 ) { 467 *bufp++ = ntoa_table[value % radix]; 468 value /= radix; 469 } 470 } else { 471 *bufp++ = '0'; 472 } 473 *bufp = '\0'; 474 475 /* The numbers went into the string backwards. :) */ 476 if ( *string == '-' ) { 477 SDL_strrev(string+1); 478 } else { 479 SDL_strrev(string); 480 } 481 482 return string; 483} 484#endif 485 486#ifndef HAVE__ULTOA 487char *SDL_ultoa(unsigned long value, char *string, int radix) 488{ 489 char *bufp = string; 490 491 if ( value ) { 492 while ( value > 0 ) { 493 *bufp++ = ntoa_table[value % radix]; 494 value /= radix; 495 } 496 } else { 497 *bufp++ = '0'; 498 } 499 *bufp = '\0'; 500 501 /* The numbers went into the string backwards. :) */ 502 SDL_strrev(string); 503 504 return string; 505} 506#endif 507 508#ifndef HAVE_STRTOL 509long SDL_strtol(const char *string, char **endp, int base) 510{ 511 size_t len; 512 long value; 513 514 if ( !base ) { 515 if ( (SDL_strlen(string) > 2) && (SDL_strncmp(string, "0x", 2) == 0) ) { 516 base = 16; 517 } else { 518 base = 10; 519 } 520 } 521 522 len = SDL_ScanLong(string, base, &value); 523 if ( endp ) { 524 *endp = (char *)string + len; 525 } 526 return value; 527} 528#endif 529 530#ifndef HAVE_STRTOUL 531unsigned long SDL_strtoul(const char *string, char **endp, int base) 532{ 533 size_t len; 534 unsigned long value; 535 536 if ( !base ) { 537 if ( (SDL_strlen(string) > 2) && (SDL_strncmp(string, "0x", 2) == 0) ) { 538 base = 16; 539 } else { 540 base = 10; 541 } 542 } 543 544 len = SDL_ScanUnsignedLong(string, base, &value); 545 if ( endp ) { 546 *endp = (char *)string + len; 547 } 548 return value; 549} 550#endif 551 552#ifdef SDL_HAS_64BIT_TYPE 553 554#ifndef HAVE__I64TOA 555char *SDL_lltoa(Sint64 value, char *string, int radix) 556{ 557 char *bufp = string; 558 559 if ( value < 0 ) { 560 *bufp++ = '-'; 561 value = -value; 562 } 563 if ( value ) { 564 while ( value > 0 ) { 565 *bufp++ = ntoa_table[value % radix]; 566 value /= radix; 567 } 568 } else { 569 *bufp++ = '0'; 570 } 571 *bufp = '\0'; 572 573 /* The numbers went into the string backwards. :) */ 574 if ( *string == '-' ) { 575 SDL_strrev(string+1); 576 } else { 577 SDL_strrev(string); 578 } 579 580 return string; 581} 582#endif 583 584#ifndef HAVE__UI64TOA 585char *SDL_ulltoa(Uint64 value, char *string, int radix) 586{ 587 char *bufp = string; 588 589 if ( value ) { 590 while ( value > 0 ) { 591 *bufp++ = ntoa_table[value % radix]; 592 value /= radix; 593 } 594 } else { 595 *bufp++ = '0'; 596 } 597 *bufp = '\0'; 598 599 /* The numbers went into the string backwards. :) */ 600 SDL_strrev(string); 601 602 return string; 603} 604#endif 605 606#ifndef HAVE_STRTOLL 607Sint64 SDL_strtoll(const char *string, char **endp, int base) 608{ 609 size_t len; 610 Sint64 value; 611 612 if ( !base ) { 613 if ( (SDL_strlen(string) > 2) && (SDL_strncmp(string, "0x", 2) == 0) ) { 614 base = 16; 615 } else { 616 base = 10; 617 } 618 } 619 620 len = SDL_ScanLongLong(string, base, &value); 621 if ( endp ) { 622 *endp = (char *)string + len; 623 } 624 return value; 625} 626#endif 627 628#ifndef HAVE_STRTOULL 629Uint64 SDL_strtoull(const char *string, char **endp, int base) 630{ 631 size_t len; 632 Uint64 value; 633 634 if ( !base ) { 635 if ( (SDL_strlen(string) > 2) && (SDL_strncmp(string, "0x", 2) == 0) ) { 636 base = 16; 637 } else { 638 base = 10; 639 } 640 } 641 642 len = SDL_ScanUnsignedLongLong(string, base, &value); 643 if ( endp ) { 644 *endp = (char *)string + len; 645 } 646 return value; 647} 648#endif 649 650#endif /* SDL_HAS_64BIT_TYPE */ 651 652#ifndef HAVE_STRTOD 653double SDL_strtod(const char *string, char **endp) 654{ 655 size_t len; 656 double value; 657 658 len = SDL_ScanFloat(string, &value); 659 if ( endp ) { 660 *endp = (char *)string + len; 661 } 662 return value; 663} 664#endif 665 666#ifndef HAVE_STRCMP 667int SDL_strcmp(const char *str1, const char *str2) 668{ 669 while (*str1 && *str2) { 670 if ( *str1 != *str2 ) 671 break; 672 ++str1; 673 ++str2; 674 } 675 return (int)((unsigned char)*str1 - (unsigned char)*str2); 676} 677#endif 678 679#ifndef HAVE_STRNCMP 680int SDL_strncmp(const char *str1, const char *str2, size_t maxlen) 681{ 682 while ( *str1 && *str2 && maxlen ) { 683 if ( *str1 != *str2 ) 684 break; 685 ++str1; 686 ++str2; 687 --maxlen; 688 } 689 if ( ! maxlen ) { 690 return 0; 691 } 692 return (int)((unsigned char)*str1 - (unsigned char)*str2); 693} 694#endif 695 696#if !defined(HAVE_STRCASECMP) && !defined(HAVE__STRICMP) 697int SDL_strcasecmp(const char *str1, const char *str2) 698{ 699 char a = 0; 700 char b = 0; 701 while ( *str1 && *str2 ) { 702 a = SDL_tolower((unsigned char) *str1); 703 b = SDL_tolower((unsigned char) *str2); 704 if ( a != b ) 705 break; 706 ++str1; 707 ++str2; 708 } 709 return (int)((unsigned char)a - (unsigned char)b); 710} 711#endif 712 713#if !defined(HAVE_STRNCASECMP) && !defined(HAVE__STRNICMP) 714int SDL_strncasecmp(const char *str1, const char *str2, size_t maxlen) 715{ 716 char a = 0; 717 char b = 0; 718 while ( *str1 && *str2 && maxlen ) { 719 a = SDL_tolower((unsigned char) *str1); 720 b = SDL_tolower((unsigned char) *str2); 721 if ( a != b ) 722 break; 723 ++str1; 724 ++str2; 725 --maxlen; 726 } 727 return (int)((unsigned char)a - (unsigned char)b); 728} 729#endif 730 731#ifndef HAVE_SSCANF 732int SDL_sscanf(const char *text, const char *fmt, ...) 733{ 734 va_list ap; 735 int retval = 0; 736 737 va_start(ap, fmt); 738 while ( *fmt ) { 739 if ( *fmt == ' ' ) { 740 while ( SDL_isspace((unsigned char) *text) ) { 741 ++text; 742 } 743 ++fmt; 744 continue; 745 } 746 if ( *fmt == '%' ) { 747 SDL_bool done = SDL_FALSE; 748 long count = 0; 749 int radix = 10; 750 enum { 751 DO_SHORT, 752 DO_INT, 753 DO_LONG, 754 DO_LONGLONG 755 } inttype = DO_INT; 756 SDL_bool suppress = SDL_FALSE; 757 758 ++fmt; 759 if ( *fmt == '%' ) { 760 if ( *text == '%' ) { 761 ++text; 762 ++fmt; 763 continue; 764 } 765 break; 766 } 767 if ( *fmt == '*' ) { 768 suppress = SDL_TRUE; 769 ++fmt; 770 } 771 fmt += SDL_ScanLong(fmt, 10, &count); 772 773 if ( *fmt == 'c' ) { 774 if ( ! count ) { 775 count = 1; 776 } 777 if ( suppress ) { 778 while ( count-- ) { 779 ++text; 780 } 781 } else { 782 char *valuep = va_arg(ap, char*); 783 while ( count-- ) { 784 *valuep++ = *text++; 785 } 786 ++retval; 787 } 788 continue; 789 } 790 791 while ( SDL_isspace((unsigned char) *text) ) { 792 ++text; 793 } 794 795 /* FIXME: implement more of the format specifiers */ 796 while (!done) { 797 switch(*fmt) { 798 case '*': 799 suppress = SDL_TRUE; 800 break; 801 case 'h': 802 if ( inttype > DO_SHORT ) { 803 ++inttype; 804 } 805 break; 806 case 'l': 807 if ( inttype < DO_LONGLONG ) { 808 ++inttype; 809 } 810 break; 811 case 'I': 812 if ( SDL_strncmp(fmt, "I64", 3) == 0 ) { 813 fmt += 2; 814 inttype = DO_LONGLONG; 815 } 816 break; 817 case 'i': 818 { 819 int index = 0; 820 if ( text[index] == '-' ) { 821 ++index; 822 } 823 if ( text[index] == '0' ) { 824 if ( SDL_tolower((unsigned char) text[index+1]) == 'x' ) { 825 radix = 16; 826 } else { 827 radix = 8; 828 } 829 } 830 } 831 /* Fall through to %d handling */ 832 case 'd': 833#ifdef SDL_HAS_64BIT_TYPE 834 if ( inttype == DO_LONGLONG ) { 835 Sint64 value; 836 text += SDL_ScanLongLong(text, radix, &value); 837 if ( ! suppress ) { 838 Sint64 *valuep = va_arg(ap, Sint64*); 839 *valuep = value; 840 ++retval; 841 } 842 } 843 else 844#endif /* SDL_HAS_64BIT_TYPE */ 845 { 846 long value; 847 text += SDL_ScanLong(text, radix, &value); 848 if ( ! suppress ) { 849 switch (inttype) { 850 case DO_SHORT: 851 { short* valuep = va_arg(ap, short*); 852 *valuep = (short)value; 853 } 854 break; 855 case DO_INT: 856 { int* valuep = va_arg(ap, int*); 857 *valuep = (int)value; 858 } 859 break; 860 case DO_LONG: 861 { long* valuep = va_arg(ap, long*); 862 *valuep = value; 863 } 864 break; 865 case DO_LONGLONG: 866 /* Handled above */ 867 break; 868 } 869 ++retval; 870 } 871 } 872 done = SDL_TRUE; 873 break; 874 case 'o': 875 if ( radix == 10 ) { 876 radix = 8; 877 } 878 /* Fall through to unsigned handling */ 879 case 'x': 880 case 'X': 881 if ( radix == 10 ) { 882 radix = 16; 883 } 884 /* Fall through to unsigned handling */ 885 case 'u': 886#ifdef SDL_HAS_64BIT_TYPE 887 if ( inttype == DO_LONGLONG ) { 888 Uint64 value; 889 text += SDL_ScanUnsignedLongLong(text, radix, &value); 890 if ( ! suppress ) { 891 Uint64 *valuep = va_arg(ap, Uint64*); 892 *valuep = value; 893 ++retval; 894 } 895 } 896 else 897#endif /* SDL_HAS_64BIT_TYPE */ 898 { 899 unsigned long value; 900 text += SDL_ScanUnsignedLong(text, radix, &value); 901 if ( ! suppress ) { 902 switch (inttype) { 903 case DO_SHORT: 904 { short* valuep = va_arg(ap, short*); 905 *valuep = (short)value; 906 } 907 break; 908 case DO_INT: 909 { int* valuep = va_arg(ap, int*); 910 *valuep = (int)value; 911 } 912 break; 913 case DO_LONG: 914 { long* valuep = va_arg(ap, long*); 915 *valuep = value; 916 } 917 break; 918 case DO_LONGLONG: 919 /* Handled above */ 920 break; 921 } 922 ++retval; 923 } 924 } 925 done = SDL_TRUE; 926 break; 927 case 'p': 928 { 929 uintptr_t value; 930 text += SDL_ScanUintPtrT(text, 16, &value); 931 if ( ! suppress ) { 932 void** valuep = va_arg(ap, void**); 933 *valuep = (void*)value; 934 ++retval; 935 } 936 } 937 done = SDL_TRUE; 938 break; 939 case 'f': 940 { 941 double value; 942 text += SDL_ScanFloat(text, &value); 943 if ( ! suppress ) { 944 float* valuep = va_arg(ap, float*); 945 *valuep = (float)value; 946 ++retval; 947 } 948 } 949 done = SDL_TRUE; 950 break; 951 case 's': 952 if ( suppress ) { 953 while ( !SDL_isspace((unsigned char) *text) ) { 954 ++text; 955 if ( count ) { 956 if ( --count == 0 ) { 957 break; 958 } 959 } 960 } 961 } else { 962 char *valuep = va_arg(ap, char*); 963 while ( !SDL_isspace((unsigned char) *text) ) { 964 *valuep++ = *text++; 965 if ( count ) { 966 if ( --count == 0 ) { 967 break; 968 } 969 } 970 } 971 *valuep = '\0'; 972 ++retval; 973 } 974 done = SDL_TRUE; 975 break; 976 default: 977 done = SDL_TRUE; 978 break; 979 } 980 ++fmt; 981 } 982 continue; 983 } 984 if ( *text == *fmt ) { 985 ++text; 986 ++fmt; 987 continue; 988 } 989 /* Text didn't match format specifier */ 990 break; 991 } 992 va_end(ap); 993 994 return retval; 995} 996#endif 997 998#ifndef HAVE_SNPRINTF 999int SDL_snprintf(char *text, size_t maxlen, const char *fmt, ...) 1000{ 1001 va_list ap; 1002 int retval; 1003 1004 va_start(ap, fmt); 1005 retval = SDL_vsnprintf(text, maxlen, fmt, ap); 1006 va_end(ap); 1007 1008 return retval; 1009} 1010#endif 1011 1012#ifndef HAVE_VSNPRINTF 1013static size_t SDL_PrintLong(char *text, long value, int radix, size_t maxlen) 1014{ 1015 char num[130]; 1016 size_t size; 1017 1018 SDL_ltoa(value, num, radix); 1019 size = SDL_strlen(num); 1020 if ( size >= maxlen ) { 1021 size = maxlen-1; 1022 } 1023 SDL_strlcpy(text, num, size+1); 1024 1025 return size; 1026} 1027static size_t SDL_PrintUnsignedLong(char *text, unsigned long value, int radix, size_t maxlen) 1028{ 1029 char num[130]; 1030 size_t size; 1031 1032 SDL_ultoa(value, num, radix); 1033 size = SDL_strlen(num); 1034 if ( size >= maxlen ) { 1035 size = maxlen-1; 1036 } 1037 SDL_strlcpy(text, num, size+1); 1038 1039 return size; 1040} 1041#ifdef SDL_HAS_64BIT_TYPE 1042static size_t SDL_PrintLongLong(char *text, Sint64 value, int radix, size_t maxlen) 1043{ 1044 char num[130]; 1045 size_t size; 1046 1047 SDL_lltoa(value, num, radix); 1048 size = SDL_strlen(num); 1049 if ( size >= maxlen ) { 1050 size = maxlen-1; 1051 } 1052 SDL_strlcpy(text, num, size+1); 1053 1054 return size; 1055} 1056static size_t SDL_PrintUnsignedLongLong(char *text, Uint64 value, int radix, size_t maxlen) 1057{ 1058 char num[130]; 1059 size_t size; 1060 1061 SDL_ulltoa(value, num, radix); 1062 size = SDL_strlen(num); 1063 if ( size >= maxlen ) { 1064 size = maxlen-1; 1065 } 1066 SDL_strlcpy(text, num, size+1); 1067 1068 return size; 1069} 1070#endif /* SDL_HAS_64BIT_TYPE */ 1071static size_t SDL_PrintFloat(char *text, double arg, size_t maxlen) 1072{ 1073 char *textstart = text; 1074 if ( arg ) { 1075 /* This isn't especially accurate, but hey, it's easy. :) */ 1076 const double precision = 0.00000001; 1077 size_t len; 1078 unsigned long value; 1079 1080 if ( arg < 0 ) { 1081 *text++ = '-'; 1082 --maxlen; 1083 arg = -arg; 1084 } 1085 value = (unsigned long)arg; 1086 len = SDL_PrintUnsignedLong(text, value, 10, maxlen); 1087 text += len; 1088 maxlen -= len; 1089 arg -= value; 1090 if ( arg > precision && maxlen ) { 1091 int mult = 10; 1092 *text++ = '.'; 1093 while ( (arg > precision) && maxlen ) { 1094 value = (unsigned long)(arg * mult); 1095 len = SDL_PrintUnsignedLong(text, value, 10, maxlen); 1096 text += len; 1097 maxlen -= len; 1098 arg -= (double)value / mult; 1099 mult *= 10; 1100 } 1101 } 1102 } else { 1103 *text++ = '0'; 1104 } 1105 return (text - textstart); 1106} 1107static size_t SDL_PrintString(char *text, const char *string, size_t maxlen) 1108{ 1109 char *textstart = text; 1110 while ( *string && maxlen-- ) { 1111 *text++ = *string++; 1112 } 1113 return (text - textstart); 1114} 1115int SDL_vsnprintf(char *text, size_t maxlen, const char *fmt, va_list ap) 1116{ 1117 char *textstart = text; 1118 if ( maxlen <= 0 ) { 1119 return 0; 1120 } 1121 --maxlen; /* For the trailing '\0' */ 1122 while ( *fmt && maxlen ) { 1123 if ( *fmt == '%' ) { 1124 SDL_bool done = SDL_FALSE; 1125 size_t len = 0; 1126 SDL_bool do_lowercase = SDL_FALSE; 1127 int radix = 10; 1128 enum { 1129 DO_INT, 1130 DO_LONG, 1131 DO_LONGLONG 1132 } inttype = DO_INT; 1133 1134 ++fmt; 1135 /* FIXME: implement more of the format specifiers */ 1136 while ( *fmt == '.' || (*fmt >= '0' && *fmt <= '9') ) { 1137 ++fmt; 1138 } 1139 while (!done) { 1140 switch(*fmt) { 1141 case '%': 1142 *text = '%'; 1143 len = 1; 1144 done = SDL_TRUE; 1145 break; 1146 case 'c': 1147 /* char is promoted to int when passed through (...) */ 1148 *text = (char)va_arg(ap, int); 1149 len = 1; 1150 done = SDL_TRUE; 1151 break; 1152 case 'h': 1153 /* short is promoted to int when passed through (...) */ 1154 break; 1155 case 'l': 1156 if ( inttype < DO_LONGLONG ) { 1157 ++inttype; 1158 } 1159 break; 1160 case 'I': 1161 if ( SDL_strncmp(fmt, "I64", 3) == 0 ) { 1162 fmt += 2; 1163 inttype = DO_LONGLONG; 1164 } 1165 break; 1166 case 'i': 1167 case 'd': 1168 switch (inttype) { 1169 case DO_INT: 1170 len = SDL_PrintLong(text, (long)va_arg(ap, int), radix, maxlen); 1171 break; 1172 case DO_LONG: 1173 len = SDL_PrintLong(text, va_arg(ap, long), radix, maxlen); 1174 break; 1175 case DO_LONGLONG: 1176#ifdef SDL_HAS_64BIT_TYPE 1177 len = SDL_PrintLongLong(text, va_arg(ap, Sint64), radix, maxlen); 1178#else 1179 len = SDL_PrintLong(text, va_arg(ap, long), radix, maxlen); 1180#endif 1181 break; 1182 } 1183 done = SDL_TRUE; 1184 break; 1185 case 'p': 1186 case 'x': 1187 do_lowercase = SDL_TRUE; 1188 /* Fall through to 'X' handling */ 1189 case 'X': 1190 if ( radix == 10 ) { 1191 radix = 16; 1192 } 1193 if ( *fmt == 'p' ) { 1194 inttype = DO_LONG; 1195 } 1196 /* Fall through to unsigned handling */ 1197 case 'o': 1198 if ( radix == 10 ) { 1199 radix = 8; 1200 } 1201 /* Fall through to unsigned handling */ 1202 case 'u': 1203 switch (inttype) { 1204 case DO_INT: 1205 len = SDL_PrintUnsignedLong(text, (unsigned long)va_arg(ap, unsigned int), radix, maxlen); 1206 break; 1207 case DO_LONG: 1208 len = SDL_PrintUnsignedLong(text, va_arg(ap, unsigned long), radix, maxlen); 1209 break; 1210 case DO_LONGLONG: 1211#ifdef SDL_HAS_64BIT_TYPE 1212 len = SDL_PrintUnsignedLongLong(text, va_arg(ap, Uint64), radix, maxlen); 1213#else 1214 len = SDL_PrintUnsignedLong(text, va_arg(ap, unsigned long), radix, maxlen); 1215#endif 1216 break; 1217 } 1218 if ( do_lowercase ) { 1219 SDL_strlwr(text); 1220 } 1221 done = SDL_TRUE; 1222 break; 1223 case 'f': 1224 len = SDL_PrintFloat(text, va_arg(ap, double), maxlen); 1225 done = SDL_TRUE; 1226 break; 1227 case 's': 1228 len = SDL_PrintString(text, va_arg(ap, char*), maxlen); 1229 done = SDL_TRUE; 1230 break; 1231 default: 1232 done = SDL_TRUE; 1233 break; 1234 } 1235 ++fmt; 1236 } 1237 text += len; 1238 maxlen -= len; 1239 } else { 1240 *text++ = *fmt++; 1241 --maxlen; 1242 } 1243 } 1244 *text = '\0'; 1245 1246 return (text - textstart); 1247} 1248#endif 1249