SDL_string.c (42943B)
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "../SDL_internal.h" 22 23/* This file contains portable string manipulation functions for SDL */ 24 25#include "SDL_stdinc.h" 26 27 28#define SDL_isupperhex(X) (((X) >= 'A') && ((X) <= 'F')) 29#define SDL_islowerhex(X) (((X) >= 'a') && ((X) <= 'f')) 30 31#define UTF8_IsLeadByte(c) ((c) >= 0xC0 && (c) <= 0xF4) 32#define UTF8_IsTrailingByte(c) ((c) >= 0x80 && (c) <= 0xBF) 33 34static int UTF8_TrailingBytes(unsigned char c) 35{ 36 if (c >= 0xC0 && c <= 0xDF) 37 return 1; 38 else if (c >= 0xE0 && c <= 0xEF) 39 return 2; 40 else if (c >= 0xF0 && c <= 0xF4) 41 return 3; 42 else 43 return 0; 44} 45 46#if !defined(HAVE_VSSCANF) || !defined(HAVE_STRTOL) 47static size_t 48SDL_ScanLong(const char *text, int radix, long *valuep) 49{ 50 const char *textstart = text; 51 long value = 0; 52 SDL_bool negative = SDL_FALSE; 53 54 if (*text == '-') { 55 negative = SDL_TRUE; 56 ++text; 57 } 58 if (radix == 16 && SDL_strncmp(text, "0x", 2) == 0) { 59 text += 2; 60 } 61 for (;;) { 62 int v; 63 if (SDL_isdigit((unsigned char) *text)) { 64 v = *text - '0'; 65 } else if (radix == 16 && SDL_isupperhex(*text)) { 66 v = 10 + (*text - 'A'); 67 } else if (radix == 16 && SDL_islowerhex(*text)) { 68 v = 10 + (*text - 'a'); 69 } else { 70 break; 71 } 72 value *= radix; 73 value += v; 74 ++text; 75 } 76 if (valuep) { 77 if (negative && value) { 78 *valuep = -value; 79 } else { 80 *valuep = value; 81 } 82 } 83 return (text - textstart); 84} 85#endif 86 87#if !defined(HAVE_VSSCANF) || !defined(HAVE_STRTOUL) || !defined(HAVE_STRTOD) 88static size_t 89SDL_ScanUnsignedLong(const char *text, int radix, unsigned long *valuep) 90{ 91 const char *textstart = text; 92 unsigned long value = 0; 93 94 if (radix == 16 && SDL_strncmp(text, "0x", 2) == 0) { 95 text += 2; 96 } 97 for (;;) { 98 int v; 99 if (SDL_isdigit((unsigned char) *text)) { 100 v = *text - '0'; 101 } else if (radix == 16 && SDL_isupperhex(*text)) { 102 v = 10 + (*text - 'A'); 103 } else if (radix == 16 && SDL_islowerhex(*text)) { 104 v = 10 + (*text - 'a'); 105 } else { 106 break; 107 } 108 value *= radix; 109 value += v; 110 ++text; 111 } 112 if (valuep) { 113 *valuep = value; 114 } 115 return (text - textstart); 116} 117#endif 118 119#ifndef HAVE_VSSCANF 120static size_t 121SDL_ScanUintPtrT(const char *text, int radix, uintptr_t * valuep) 122{ 123 const char *textstart = text; 124 uintptr_t value = 0; 125 126 if (radix == 16 && SDL_strncmp(text, "0x", 2) == 0) { 127 text += 2; 128 } 129 for (;;) { 130 int v; 131 if (SDL_isdigit((unsigned char) *text)) { 132 v = *text - '0'; 133 } else if (radix == 16 && SDL_isupperhex(*text)) { 134 v = 10 + (*text - 'A'); 135 } else if (radix == 16 && SDL_islowerhex(*text)) { 136 v = 10 + (*text - 'a'); 137 } else { 138 break; 139 } 140 value *= radix; 141 value += v; 142 ++text; 143 } 144 if (valuep) { 145 *valuep = value; 146 } 147 return (text - textstart); 148} 149#endif 150 151#if !defined(HAVE_VSSCANF) || !defined(HAVE_STRTOLL) 152static size_t 153SDL_ScanLongLong(const char *text, int radix, Sint64 * valuep) 154{ 155 const char *textstart = text; 156 Sint64 value = 0; 157 SDL_bool negative = SDL_FALSE; 158 159 if (*text == '-') { 160 negative = SDL_TRUE; 161 ++text; 162 } 163 if (radix == 16 && SDL_strncmp(text, "0x", 2) == 0) { 164 text += 2; 165 } 166 for (;;) { 167 int v; 168 if (SDL_isdigit((unsigned char) *text)) { 169 v = *text - '0'; 170 } else if (radix == 16 && SDL_isupperhex(*text)) { 171 v = 10 + (*text - 'A'); 172 } else if (radix == 16 && SDL_islowerhex(*text)) { 173 v = 10 + (*text - 'a'); 174 } else { 175 break; 176 } 177 value *= radix; 178 value += v; 179 ++text; 180 } 181 if (valuep) { 182 if (negative && value) { 183 *valuep = -value; 184 } else { 185 *valuep = value; 186 } 187 } 188 return (text - textstart); 189} 190#endif 191 192#if !defined(HAVE_VSSCANF) || !defined(HAVE_STRTOULL) 193static size_t 194SDL_ScanUnsignedLongLong(const char *text, int radix, Uint64 * valuep) 195{ 196 const char *textstart = text; 197 Uint64 value = 0; 198 199 if (radix == 16 && SDL_strncmp(text, "0x", 2) == 0) { 200 text += 2; 201 } 202 for (;;) { 203 int v; 204 if (SDL_isdigit((unsigned char) *text)) { 205 v = *text - '0'; 206 } else if (radix == 16 && SDL_isupperhex(*text)) { 207 v = 10 + (*text - 'A'); 208 } else if (radix == 16 && SDL_islowerhex(*text)) { 209 v = 10 + (*text - 'a'); 210 } else { 211 break; 212 } 213 value *= radix; 214 value += v; 215 ++text; 216 } 217 if (valuep) { 218 *valuep = value; 219 } 220 return (text - textstart); 221} 222#endif 223 224#if !defined(HAVE_VSSCANF) || !defined(HAVE_STRTOD) 225static size_t 226SDL_ScanFloat(const char *text, double *valuep) 227{ 228 const char *textstart = text; 229 unsigned long lvalue = 0; 230 double value = 0.0; 231 SDL_bool negative = SDL_FALSE; 232 233 if (*text == '-') { 234 negative = SDL_TRUE; 235 ++text; 236 } 237 text += SDL_ScanUnsignedLong(text, 10, &lvalue); 238 value += lvalue; 239 if (*text == '.') { 240 int mult = 10; 241 ++text; 242 while (SDL_isdigit((unsigned char) *text)) { 243 lvalue = *text - '0'; 244 value += (double) lvalue / mult; 245 mult *= 10; 246 ++text; 247 } 248 } 249 if (valuep) { 250 if (negative && value) { 251 *valuep = -value; 252 } else { 253 *valuep = value; 254 } 255 } 256 return (text - textstart); 257} 258#endif 259 260void * 261SDL_memset(SDL_OUT_BYTECAP(len) void *dst, int c, size_t len) 262{ 263#if defined(HAVE_MEMSET) 264 return memset(dst, c, len); 265#else 266 size_t left; 267 Uint32 *dstp4; 268 Uint8 *dstp1 = (Uint8 *) dst; 269 Uint32 value4 = (c | (c << 8) | (c << 16) | (c << 24)); 270 Uint8 value1 = (Uint8) c; 271 272 /* The destination pointer needs to be aligned on a 4-byte boundary to 273 * execute a 32-bit set. Set first bytes manually if needed until it is 274 * aligned. */ 275 while ((intptr_t)dstp1 & 0x3) { 276 if (len--) { 277 *dstp1++ = value1; 278 } else { 279 return dst; 280 } 281 } 282 283 dstp4 = (Uint32 *) dstp1; 284 left = (len % 4); 285 len /= 4; 286 while (len--) { 287 *dstp4++ = value4; 288 } 289 290 dstp1 = (Uint8 *) dstp4; 291 switch (left) { 292 case 3: 293 *dstp1++ = value1; 294 case 2: 295 *dstp1++ = value1; 296 case 1: 297 *dstp1++ = value1; 298 } 299 300 return dst; 301#endif /* HAVE_MEMSET */ 302} 303 304void * 305SDL_memcpy(SDL_OUT_BYTECAP(len) void *dst, SDL_IN_BYTECAP(len) const void *src, size_t len) 306{ 307#ifdef __GNUC__ 308 /* Presumably this is well tuned for speed. 309 On my machine this is twice as fast as the C code below. 310 */ 311 return __builtin_memcpy(dst, src, len); 312#elif defined(HAVE_MEMCPY) 313 return memcpy(dst, src, len); 314#elif defined(HAVE_BCOPY) 315 bcopy(src, dst, len); 316 return dst; 317#else 318 /* GCC 4.9.0 with -O3 will generate movaps instructions with the loop 319 using Uint32* pointers, so we need to make sure the pointers are 320 aligned before we loop using them. 321 */ 322 if (((intptr_t)src & 0x3) || ((intptr_t)dst & 0x3)) { 323 /* Do an unaligned byte copy */ 324 Uint8 *srcp1 = (Uint8 *)src; 325 Uint8 *dstp1 = (Uint8 *)dst; 326 327 while (len--) { 328 *dstp1++ = *srcp1++; 329 } 330 } else { 331 size_t left = (len % 4); 332 Uint32 *srcp4, *dstp4; 333 Uint8 *srcp1, *dstp1; 334 335 srcp4 = (Uint32 *) src; 336 dstp4 = (Uint32 *) dst; 337 len /= 4; 338 while (len--) { 339 *dstp4++ = *srcp4++; 340 } 341 342 srcp1 = (Uint8 *) srcp4; 343 dstp1 = (Uint8 *) dstp4; 344 switch (left) { 345 case 3: 346 *dstp1++ = *srcp1++; 347 case 2: 348 *dstp1++ = *srcp1++; 349 case 1: 350 *dstp1++ = *srcp1++; 351 } 352 } 353 return dst; 354#endif /* __GNUC__ */ 355} 356 357void * 358SDL_memmove(SDL_OUT_BYTECAP(len) void *dst, SDL_IN_BYTECAP(len) const void *src, size_t len) 359{ 360#if defined(HAVE_MEMMOVE) 361 return memmove(dst, src, len); 362#else 363 char *srcp = (char *) src; 364 char *dstp = (char *) dst; 365 366 if (src < dst) { 367 srcp += len - 1; 368 dstp += len - 1; 369 while (len--) { 370 *dstp-- = *srcp--; 371 } 372 } else { 373 while (len--) { 374 *dstp++ = *srcp++; 375 } 376 } 377 return dst; 378#endif /* HAVE_MEMMOVE */ 379} 380 381int 382SDL_memcmp(const void *s1, const void *s2, size_t len) 383{ 384#if defined(HAVE_MEMCMP) 385 return memcmp(s1, s2, len); 386#else 387 char *s1p = (char *) s1; 388 char *s2p = (char *) s2; 389 while (len--) { 390 if (*s1p != *s2p) { 391 return (*s1p - *s2p); 392 } 393 ++s1p; 394 ++s2p; 395 } 396 return 0; 397#endif /* HAVE_MEMCMP */ 398} 399 400size_t 401SDL_strlen(const char *string) 402{ 403#if defined(HAVE_STRLEN) 404 return strlen(string); 405#else 406 size_t len = 0; 407 while (*string++) { 408 ++len; 409 } 410 return len; 411#endif /* HAVE_STRLEN */ 412} 413 414size_t 415SDL_wcslen(const wchar_t * string) 416{ 417#if defined(HAVE_WCSLEN) 418 return wcslen(string); 419#else 420 size_t len = 0; 421 while (*string++) { 422 ++len; 423 } 424 return len; 425#endif /* HAVE_WCSLEN */ 426} 427 428size_t 429SDL_wcslcpy(SDL_OUT_Z_CAP(maxlen) wchar_t *dst, const wchar_t *src, size_t maxlen) 430{ 431#if defined(HAVE_WCSLCPY) 432 return wcslcpy(dst, src, maxlen); 433#else 434 size_t srclen = SDL_wcslen(src); 435 if (maxlen > 0) { 436 size_t len = SDL_min(srclen, maxlen - 1); 437 SDL_memcpy(dst, src, len * sizeof(wchar_t)); 438 dst[len] = '\0'; 439 } 440 return srclen; 441#endif /* HAVE_WCSLCPY */ 442} 443 444size_t 445SDL_wcslcat(SDL_INOUT_Z_CAP(maxlen) wchar_t *dst, const wchar_t *src, size_t maxlen) 446{ 447#if defined(HAVE_WCSLCAT) 448 return wcslcat(dst, src, maxlen); 449#else 450 size_t dstlen = SDL_wcslen(dst); 451 size_t srclen = SDL_wcslen(src); 452 if (dstlen < maxlen) { 453 SDL_wcslcpy(dst + dstlen, src, maxlen - dstlen); 454 } 455 return dstlen + srclen; 456#endif /* HAVE_WCSLCAT */ 457} 458 459size_t 460SDL_strlcpy(SDL_OUT_Z_CAP(maxlen) char *dst, const char *src, size_t maxlen) 461{ 462#if defined(HAVE_STRLCPY) 463 return strlcpy(dst, src, maxlen); 464#else 465 size_t srclen = SDL_strlen(src); 466 if (maxlen > 0) { 467 size_t len = SDL_min(srclen, maxlen - 1); 468 SDL_memcpy(dst, src, len); 469 dst[len] = '\0'; 470 } 471 return srclen; 472#endif /* HAVE_STRLCPY */ 473} 474 475size_t SDL_utf8strlcpy(SDL_OUT_Z_CAP(dst_bytes) char *dst, const char *src, size_t dst_bytes) 476{ 477 size_t src_bytes = SDL_strlen(src); 478 size_t bytes = SDL_min(src_bytes, dst_bytes - 1); 479 size_t i = 0; 480 char trailing_bytes = 0; 481 if (bytes) 482 { 483 unsigned char c = (unsigned char)src[bytes - 1]; 484 if (UTF8_IsLeadByte(c)) 485 --bytes; 486 else if (UTF8_IsTrailingByte(c)) 487 { 488 for (i = bytes - 1; i != 0; --i) 489 { 490 c = (unsigned char)src[i]; 491 trailing_bytes = UTF8_TrailingBytes(c); 492 if (trailing_bytes) 493 { 494 if (bytes - i != trailing_bytes + 1) 495 bytes = i; 496 497 break; 498 } 499 } 500 } 501 SDL_memcpy(dst, src, bytes); 502 } 503 dst[bytes] = '\0'; 504 return bytes; 505} 506 507size_t 508SDL_strlcat(SDL_INOUT_Z_CAP(maxlen) char *dst, const char *src, size_t maxlen) 509{ 510#if defined(HAVE_STRLCAT) 511 return strlcat(dst, src, maxlen); 512#else 513 size_t dstlen = SDL_strlen(dst); 514 size_t srclen = SDL_strlen(src); 515 if (dstlen < maxlen) { 516 SDL_strlcpy(dst + dstlen, src, maxlen - dstlen); 517 } 518 return dstlen + srclen; 519#endif /* HAVE_STRLCAT */ 520} 521 522char * 523SDL_strdup(const char *string) 524{ 525#if defined(HAVE_STRDUP) 526 return strdup(string); 527#else 528 size_t len = SDL_strlen(string) + 1; 529 char *newstr = SDL_malloc(len); 530 if (newstr) { 531 SDL_strlcpy(newstr, string, len); 532 } 533 return newstr; 534#endif /* HAVE_STRDUP */ 535} 536 537char * 538SDL_strrev(char *string) 539{ 540#if defined(HAVE__STRREV) 541 return _strrev(string); 542#else 543 size_t len = SDL_strlen(string); 544 char *a = &string[0]; 545 char *b = &string[len - 1]; 546 len /= 2; 547 while (len--) { 548 char c = *a; 549 *a++ = *b; 550 *b-- = c; 551 } 552 return string; 553#endif /* HAVE__STRREV */ 554} 555 556char * 557SDL_strupr(char *string) 558{ 559#if defined(HAVE__STRUPR) 560 return _strupr(string); 561#else 562 char *bufp = string; 563 while (*bufp) { 564 *bufp = SDL_toupper((unsigned char) *bufp); 565 ++bufp; 566 } 567 return string; 568#endif /* HAVE__STRUPR */ 569} 570 571char * 572SDL_strlwr(char *string) 573{ 574#if defined(HAVE__STRLWR) 575 return _strlwr(string); 576#else 577 char *bufp = string; 578 while (*bufp) { 579 *bufp = SDL_tolower((unsigned char) *bufp); 580 ++bufp; 581 } 582 return string; 583#endif /* HAVE__STRLWR */ 584} 585 586char * 587SDL_strchr(const char *string, int c) 588{ 589#ifdef HAVE_STRCHR 590 return SDL_const_cast(char*,strchr(string, c)); 591#elif defined(HAVE_INDEX) 592 return SDL_const_cast(char*,index(string, c)); 593#else 594 while (*string) { 595 if (*string == c) { 596 return (char *) string; 597 } 598 ++string; 599 } 600 return NULL; 601#endif /* HAVE_STRCHR */ 602} 603 604char * 605SDL_strrchr(const char *string, int c) 606{ 607#ifdef HAVE_STRRCHR 608 return SDL_const_cast(char*,strrchr(string, c)); 609#elif defined(HAVE_RINDEX) 610 return SDL_const_cast(char*,rindex(string, c)); 611#else 612 const char *bufp = string + SDL_strlen(string) - 1; 613 while (bufp >= string) { 614 if (*bufp == c) { 615 return (char *) bufp; 616 } 617 --bufp; 618 } 619 return NULL; 620#endif /* HAVE_STRRCHR */ 621} 622 623char * 624SDL_strstr(const char *haystack, const char *needle) 625{ 626#if defined(HAVE_STRSTR) 627 return SDL_const_cast(char*,strstr(haystack, needle)); 628#else 629 size_t length = SDL_strlen(needle); 630 while (*haystack) { 631 if (SDL_strncmp(haystack, needle, length) == 0) { 632 return (char *) haystack; 633 } 634 ++haystack; 635 } 636 return NULL; 637#endif /* HAVE_STRSTR */ 638} 639 640#if !defined(HAVE__LTOA) || !defined(HAVE__I64TOA) || \ 641 !defined(HAVE__ULTOA) || !defined(HAVE__UI64TOA) 642static const char ntoa_table[] = { 643 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 644 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 645 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 646 'U', 'V', 'W', 'X', 'Y', 'Z' 647}; 648#endif /* ntoa() conversion table */ 649 650char * 651SDL_itoa(int value, char *string, int radix) 652{ 653#ifdef HAVE_ITOA 654 return itoa(value, string, radix); 655#else 656 return SDL_ltoa((long)value, string, radix); 657#endif /* HAVE_ITOA */ 658} 659 660char * 661SDL_uitoa(unsigned int value, char *string, int radix) 662{ 663#ifdef HAVE__UITOA 664 return _uitoa(value, string, radix); 665#else 666 return SDL_ultoa((unsigned long)value, string, radix); 667#endif /* HAVE__UITOA */ 668} 669 670char * 671SDL_ltoa(long value, char *string, int radix) 672{ 673#if defined(HAVE__LTOA) 674 return _ltoa(value, string, radix); 675#else 676 char *bufp = string; 677 678 if (value < 0) { 679 *bufp++ = '-'; 680 SDL_ultoa(-value, bufp, radix); 681 } else { 682 SDL_ultoa(value, bufp, radix); 683 } 684 685 return string; 686#endif /* HAVE__LTOA */ 687} 688 689char * 690SDL_ultoa(unsigned long value, char *string, int radix) 691{ 692#if defined(HAVE__ULTOA) 693 return _ultoa(value, string, radix); 694#else 695 char *bufp = string; 696 697 if (value) { 698 while (value > 0) { 699 *bufp++ = ntoa_table[value % radix]; 700 value /= radix; 701 } 702 } else { 703 *bufp++ = '0'; 704 } 705 *bufp = '\0'; 706 707 /* The numbers went into the string backwards. :) */ 708 SDL_strrev(string); 709 710 return string; 711#endif /* HAVE__ULTOA */ 712} 713 714char * 715SDL_lltoa(Sint64 value, char *string, int radix) 716{ 717#if defined(HAVE__I64TOA) 718 return _i64toa(value, string, radix); 719#else 720 char *bufp = string; 721 722 if (value < 0) { 723 *bufp++ = '-'; 724 SDL_ulltoa(-value, bufp, radix); 725 } else { 726 SDL_ulltoa(value, bufp, radix); 727 } 728 729 return string; 730#endif /* HAVE__I64TOA */ 731} 732 733char * 734SDL_ulltoa(Uint64 value, char *string, int radix) 735{ 736#if defined(HAVE__UI64TOA) 737 return _ui64toa(value, string, radix); 738#else 739 char *bufp = string; 740 741 if (value) { 742 while (value > 0) { 743 *bufp++ = ntoa_table[value % radix]; 744 value /= radix; 745 } 746 } else { 747 *bufp++ = '0'; 748 } 749 *bufp = '\0'; 750 751 /* The numbers went into the string backwards. :) */ 752 SDL_strrev(string); 753 754 return string; 755#endif /* HAVE__UI64TOA */ 756} 757 758int SDL_atoi(const char *string) 759{ 760#ifdef HAVE_ATOI 761 return atoi(string); 762#else 763 return SDL_strtol(string, NULL, 0); 764#endif /* HAVE_ATOI */ 765} 766 767double SDL_atof(const char *string) 768{ 769#ifdef HAVE_ATOF 770 return (double) atof(string); 771#else 772 return SDL_strtod(string, NULL); 773#endif /* HAVE_ATOF */ 774} 775 776long 777SDL_strtol(const char *string, char **endp, int base) 778{ 779#if defined(HAVE_STRTOL) 780 return strtol(string, endp, base); 781#else 782 size_t len; 783 long value; 784 785 if (!base) { 786 if ((SDL_strlen(string) > 2) && (SDL_strncmp(string, "0x", 2) == 0)) { 787 base = 16; 788 } else { 789 base = 10; 790 } 791 } 792 793 len = SDL_ScanLong(string, base, &value); 794 if (endp) { 795 *endp = (char *) string + len; 796 } 797 return value; 798#endif /* HAVE_STRTOL */ 799} 800 801unsigned long 802SDL_strtoul(const char *string, char **endp, int base) 803{ 804#if defined(HAVE_STRTOUL) 805 return strtoul(string, endp, base); 806#else 807 size_t len; 808 unsigned long value; 809 810 if (!base) { 811 if ((SDL_strlen(string) > 2) && (SDL_strncmp(string, "0x", 2) == 0)) { 812 base = 16; 813 } else { 814 base = 10; 815 } 816 } 817 818 len = SDL_ScanUnsignedLong(string, base, &value); 819 if (endp) { 820 *endp = (char *) string + len; 821 } 822 return value; 823#endif /* HAVE_STRTOUL */ 824} 825 826Sint64 827SDL_strtoll(const char *string, char **endp, int base) 828{ 829#if defined(HAVE_STRTOLL) 830 return strtoll(string, endp, base); 831#else 832 size_t len; 833 Sint64 value; 834 835 if (!base) { 836 if ((SDL_strlen(string) > 2) && (SDL_strncmp(string, "0x", 2) == 0)) { 837 base = 16; 838 } else { 839 base = 10; 840 } 841 } 842 843 len = SDL_ScanLongLong(string, base, &value); 844 if (endp) { 845 *endp = (char *) string + len; 846 } 847 return value; 848#endif /* HAVE_STRTOLL */ 849} 850 851Uint64 852SDL_strtoull(const char *string, char **endp, int base) 853{ 854#if defined(HAVE_STRTOULL) 855 return strtoull(string, endp, base); 856#else 857 size_t len; 858 Uint64 value; 859 860 if (!base) { 861 if ((SDL_strlen(string) > 2) && (SDL_strncmp(string, "0x", 2) == 0)) { 862 base = 16; 863 } else { 864 base = 10; 865 } 866 } 867 868 len = SDL_ScanUnsignedLongLong(string, base, &value); 869 if (endp) { 870 *endp = (char *) string + len; 871 } 872 return value; 873#endif /* HAVE_STRTOULL */ 874} 875 876double 877SDL_strtod(const char *string, char **endp) 878{ 879#if defined(HAVE_STRTOD) 880 return strtod(string, endp); 881#else 882 size_t len; 883 double value; 884 885 len = SDL_ScanFloat(string, &value); 886 if (endp) { 887 *endp = (char *) string + len; 888 } 889 return value; 890#endif /* HAVE_STRTOD */ 891} 892 893int 894SDL_strcmp(const char *str1, const char *str2) 895{ 896#if defined(HAVE_STRCMP) 897 return strcmp(str1, str2); 898#else 899 while (*str1 && *str2) { 900 if (*str1 != *str2) 901 break; 902 ++str1; 903 ++str2; 904 } 905 return (int) ((unsigned char) *str1 - (unsigned char) *str2); 906#endif /* HAVE_STRCMP */ 907} 908 909int 910SDL_strncmp(const char *str1, const char *str2, size_t maxlen) 911{ 912#if defined(HAVE_STRNCMP) 913 return strncmp(str1, str2, maxlen); 914#else 915 while (*str1 && *str2 && maxlen) { 916 if (*str1 != *str2) 917 break; 918 ++str1; 919 ++str2; 920 --maxlen; 921 } 922 if (!maxlen) { 923 return 0; 924 } 925 return (int) ((unsigned char) *str1 - (unsigned char) *str2); 926#endif /* HAVE_STRNCMP */ 927} 928 929int 930SDL_strcasecmp(const char *str1, const char *str2) 931{ 932#ifdef HAVE_STRCASECMP 933 return strcasecmp(str1, str2); 934#elif defined(HAVE__STRICMP) 935 return _stricmp(str1, str2); 936#else 937 char a = 0; 938 char b = 0; 939 while (*str1 && *str2) { 940 a = SDL_toupper((unsigned char) *str1); 941 b = SDL_toupper((unsigned char) *str2); 942 if (a != b) 943 break; 944 ++str1; 945 ++str2; 946 } 947 a = SDL_toupper(*str1); 948 b = SDL_toupper(*str2); 949 return (int) ((unsigned char) a - (unsigned char) b); 950#endif /* HAVE_STRCASECMP */ 951} 952 953int 954SDL_strncasecmp(const char *str1, const char *str2, size_t maxlen) 955{ 956#ifdef HAVE_STRNCASECMP 957 return strncasecmp(str1, str2, maxlen); 958#elif defined(HAVE__STRNICMP) 959 return _strnicmp(str1, str2, maxlen); 960#else 961 char a = 0; 962 char b = 0; 963 while (*str1 && *str2 && maxlen) { 964 a = SDL_tolower((unsigned char) *str1); 965 b = SDL_tolower((unsigned char) *str2); 966 if (a != b) 967 break; 968 ++str1; 969 ++str2; 970 --maxlen; 971 } 972 if (maxlen == 0) { 973 return 0; 974 } else { 975 a = SDL_tolower((unsigned char) *str1); 976 b = SDL_tolower((unsigned char) *str2); 977 return (int) ((unsigned char) a - (unsigned char) b); 978 } 979#endif /* HAVE_STRNCASECMP */ 980} 981 982int 983SDL_sscanf(const char *text, SDL_SCANF_FORMAT_STRING const char *fmt, ...) 984{ 985 int rc; 986 va_list ap; 987 va_start(ap, fmt); 988 rc = SDL_vsscanf(text, fmt, ap); 989 va_end(ap); 990 return rc; 991} 992 993#ifdef HAVE_VSSCANF 994int 995SDL_vsscanf(const char *text, const char *fmt, va_list ap) 996{ 997 return vsscanf(text, fmt, ap); 998} 999#else 1000int 1001SDL_vsscanf(const char *text, const char *fmt, va_list ap) 1002{ 1003 int retval = 0; 1004 1005 while (*fmt) { 1006 if (*fmt == ' ') { 1007 while (SDL_isspace((unsigned char) *text)) { 1008 ++text; 1009 } 1010 ++fmt; 1011 continue; 1012 } 1013 if (*fmt == '%') { 1014 SDL_bool done = SDL_FALSE; 1015 long count = 0; 1016 int radix = 10; 1017 enum 1018 { 1019 DO_SHORT, 1020 DO_INT, 1021 DO_LONG, 1022 DO_LONGLONG 1023 } inttype = DO_INT; 1024 SDL_bool suppress = SDL_FALSE; 1025 1026 ++fmt; 1027 if (*fmt == '%') { 1028 if (*text == '%') { 1029 ++text; 1030 ++fmt; 1031 continue; 1032 } 1033 break; 1034 } 1035 if (*fmt == '*') { 1036 suppress = SDL_TRUE; 1037 ++fmt; 1038 } 1039 fmt += SDL_ScanLong(fmt, 10, &count); 1040 1041 if (*fmt == 'c') { 1042 if (!count) { 1043 count = 1; 1044 } 1045 if (suppress) { 1046 while (count--) { 1047 ++text; 1048 } 1049 } else { 1050 char *valuep = va_arg(ap, char *); 1051 while (count--) { 1052 *valuep++ = *text++; 1053 } 1054 ++retval; 1055 } 1056 continue; 1057 } 1058 1059 while (SDL_isspace((unsigned char) *text)) { 1060 ++text; 1061 } 1062 1063 /* FIXME: implement more of the format specifiers */ 1064 while (!done) { 1065 switch (*fmt) { 1066 case '*': 1067 suppress = SDL_TRUE; 1068 break; 1069 case 'h': 1070 if (inttype > DO_SHORT) { 1071 ++inttype; 1072 } 1073 break; 1074 case 'l': 1075 if (inttype < DO_LONGLONG) { 1076 ++inttype; 1077 } 1078 break; 1079 case 'I': 1080 if (SDL_strncmp(fmt, "I64", 3) == 0) { 1081 fmt += 2; 1082 inttype = DO_LONGLONG; 1083 } 1084 break; 1085 case 'i': 1086 { 1087 int index = 0; 1088 if (text[index] == '-') { 1089 ++index; 1090 } 1091 if (text[index] == '0') { 1092 if (SDL_tolower((unsigned char) text[index + 1]) == 'x') { 1093 radix = 16; 1094 } else { 1095 radix = 8; 1096 } 1097 } 1098 } 1099 /* Fall through to %d handling */ 1100 case 'd': 1101 if (inttype == DO_LONGLONG) { 1102 Sint64 value; 1103 text += SDL_ScanLongLong(text, radix, &value); 1104 if (!suppress) { 1105 Sint64 *valuep = va_arg(ap, Sint64 *); 1106 *valuep = value; 1107 ++retval; 1108 } 1109 } else { 1110 long value; 1111 text += SDL_ScanLong(text, radix, &value); 1112 if (!suppress) { 1113 switch (inttype) { 1114 case DO_SHORT: 1115 { 1116 short *valuep = va_arg(ap, short *); 1117 *valuep = (short) value; 1118 } 1119 break; 1120 case DO_INT: 1121 { 1122 int *valuep = va_arg(ap, int *); 1123 *valuep = (int) value; 1124 } 1125 break; 1126 case DO_LONG: 1127 { 1128 long *valuep = va_arg(ap, long *); 1129 *valuep = value; 1130 } 1131 break; 1132 case DO_LONGLONG: 1133 /* Handled above */ 1134 break; 1135 } 1136 ++retval; 1137 } 1138 } 1139 done = SDL_TRUE; 1140 break; 1141 case 'o': 1142 if (radix == 10) { 1143 radix = 8; 1144 } 1145 /* Fall through to unsigned handling */ 1146 case 'x': 1147 case 'X': 1148 if (radix == 10) { 1149 radix = 16; 1150 } 1151 /* Fall through to unsigned handling */ 1152 case 'u': 1153 if (inttype == DO_LONGLONG) { 1154 Uint64 value; 1155 text += SDL_ScanUnsignedLongLong(text, radix, &value); 1156 if (!suppress) { 1157 Uint64 *valuep = va_arg(ap, Uint64 *); 1158 *valuep = value; 1159 ++retval; 1160 } 1161 } else { 1162 unsigned long value; 1163 text += SDL_ScanUnsignedLong(text, radix, &value); 1164 if (!suppress) { 1165 switch (inttype) { 1166 case DO_SHORT: 1167 { 1168 short *valuep = va_arg(ap, short *); 1169 *valuep = (short) value; 1170 } 1171 break; 1172 case DO_INT: 1173 { 1174 int *valuep = va_arg(ap, int *); 1175 *valuep = (int) value; 1176 } 1177 break; 1178 case DO_LONG: 1179 { 1180 long *valuep = va_arg(ap, long *); 1181 *valuep = value; 1182 } 1183 break; 1184 case DO_LONGLONG: 1185 /* Handled above */ 1186 break; 1187 } 1188 ++retval; 1189 } 1190 } 1191 done = SDL_TRUE; 1192 break; 1193 case 'p': 1194 { 1195 uintptr_t value; 1196 text += SDL_ScanUintPtrT(text, 16, &value); 1197 if (!suppress) { 1198 void **valuep = va_arg(ap, void **); 1199 *valuep = (void *) value; 1200 ++retval; 1201 } 1202 } 1203 done = SDL_TRUE; 1204 break; 1205 case 'f': 1206 { 1207 double value; 1208 text += SDL_ScanFloat(text, &value); 1209 if (!suppress) { 1210 float *valuep = va_arg(ap, float *); 1211 *valuep = (float) value; 1212 ++retval; 1213 } 1214 } 1215 done = SDL_TRUE; 1216 break; 1217 case 's': 1218 if (suppress) { 1219 while (!SDL_isspace((unsigned char) *text)) { 1220 ++text; 1221 if (count) { 1222 if (--count == 0) { 1223 break; 1224 } 1225 } 1226 } 1227 } else { 1228 char *valuep = va_arg(ap, char *); 1229 while (!SDL_isspace((unsigned char) *text)) { 1230 *valuep++ = *text++; 1231 if (count) { 1232 if (--count == 0) { 1233 break; 1234 } 1235 } 1236 } 1237 *valuep = '\0'; 1238 ++retval; 1239 } 1240 done = SDL_TRUE; 1241 break; 1242 default: 1243 done = SDL_TRUE; 1244 break; 1245 } 1246 ++fmt; 1247 } 1248 continue; 1249 } 1250 if (*text == *fmt) { 1251 ++text; 1252 ++fmt; 1253 continue; 1254 } 1255 /* Text didn't match format specifier */ 1256 break; 1257 } 1258 1259 return retval; 1260} 1261#endif /* HAVE_VSSCANF */ 1262 1263int 1264SDL_snprintf(SDL_OUT_Z_CAP(maxlen) char *text, size_t maxlen, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) 1265{ 1266 va_list ap; 1267 int retval; 1268 1269 va_start(ap, fmt); 1270 retval = SDL_vsnprintf(text, maxlen, fmt, ap); 1271 va_end(ap); 1272 1273 return retval; 1274} 1275 1276#ifdef HAVE_VSNPRINTF 1277int SDL_vsnprintf(SDL_OUT_Z_CAP(maxlen) char *text, size_t maxlen, const char *fmt, va_list ap) 1278{ 1279 if (!fmt) { 1280 fmt = ""; 1281 } 1282 return vsnprintf(text, maxlen, fmt, ap); 1283} 1284#else 1285 /* FIXME: implement more of the format specifiers */ 1286typedef enum 1287{ 1288 SDL_CASE_NOCHANGE, 1289 SDL_CASE_LOWER, 1290 SDL_CASE_UPPER 1291} SDL_letter_case; 1292 1293typedef struct 1294{ 1295 SDL_bool left_justify; 1296 SDL_bool force_sign; 1297 SDL_bool force_type; 1298 SDL_bool pad_zeroes; 1299 SDL_letter_case force_case; 1300 int width; 1301 int radix; 1302 int precision; 1303} SDL_FormatInfo; 1304 1305static size_t 1306SDL_PrintString(char *text, size_t maxlen, SDL_FormatInfo *info, const char *string) 1307{ 1308 size_t length = 0; 1309 1310 if (info && info->width && (size_t)info->width > SDL_strlen(string)) { 1311 char fill = info->pad_zeroes ? '0' : ' '; 1312 size_t width = info->width - SDL_strlen(string); 1313 while (width-- > 0 && maxlen > 0) { 1314 *text++ = fill; 1315 ++length; 1316 --maxlen; 1317 } 1318 } 1319 1320 length += SDL_strlcpy(text, string, maxlen); 1321 1322 if (info) { 1323 if (info->force_case == SDL_CASE_LOWER) { 1324 SDL_strlwr(text); 1325 } else if (info->force_case == SDL_CASE_UPPER) { 1326 SDL_strupr(text); 1327 } 1328 } 1329 return length; 1330} 1331 1332static size_t 1333SDL_PrintLong(char *text, size_t maxlen, SDL_FormatInfo *info, long value) 1334{ 1335 char num[130]; 1336 1337 SDL_ltoa(value, num, info ? info->radix : 10); 1338 return SDL_PrintString(text, maxlen, info, num); 1339} 1340 1341static size_t 1342SDL_PrintUnsignedLong(char *text, size_t maxlen, SDL_FormatInfo *info, unsigned long value) 1343{ 1344 char num[130]; 1345 1346 SDL_ultoa(value, num, info ? info->radix : 10); 1347 return SDL_PrintString(text, maxlen, info, num); 1348} 1349 1350static size_t 1351SDL_PrintLongLong(char *text, size_t maxlen, SDL_FormatInfo *info, Sint64 value) 1352{ 1353 char num[130]; 1354 1355 SDL_lltoa(value, num, info ? info->radix : 10); 1356 return SDL_PrintString(text, maxlen, info, num); 1357} 1358 1359static size_t 1360SDL_PrintUnsignedLongLong(char *text, size_t maxlen, SDL_FormatInfo *info, Uint64 value) 1361{ 1362 char num[130]; 1363 1364 SDL_ulltoa(value, num, info ? info->radix : 10); 1365 return SDL_PrintString(text, maxlen, info, num); 1366} 1367 1368static size_t 1369SDL_PrintFloat(char *text, size_t maxlen, SDL_FormatInfo *info, double arg) 1370{ 1371 int width; 1372 size_t len; 1373 size_t left = maxlen; 1374 char *textstart = text; 1375 1376 if (arg) { 1377 /* This isn't especially accurate, but hey, it's easy. :) */ 1378 unsigned long value; 1379 1380 if (arg < 0) { 1381 if (left > 1) { 1382 *text = '-'; 1383 --left; 1384 } 1385 ++text; 1386 arg = -arg; 1387 } else if (info->force_sign) { 1388 if (left > 1) { 1389 *text = '+'; 1390 --left; 1391 } 1392 ++text; 1393 } 1394 value = (unsigned long) arg; 1395 len = SDL_PrintUnsignedLong(text, left, NULL, value); 1396 text += len; 1397 if (len >= left) { 1398 left = SDL_min(left, 1); 1399 } else { 1400 left -= len; 1401 } 1402 arg -= value; 1403 if (info->precision < 0) { 1404 info->precision = 6; 1405 } 1406 if (info->force_type || info->precision > 0) { 1407 int mult = 10; 1408 if (left > 1) { 1409 *text = '.'; 1410 --left; 1411 } 1412 ++text; 1413 while (info->precision-- > 0) { 1414 value = (unsigned long) (arg * mult); 1415 len = SDL_PrintUnsignedLong(text, left, NULL, value); 1416 text += len; 1417 if (len >= left) { 1418 left = SDL_min(left, 1); 1419 } else { 1420 left -= len; 1421 } 1422 arg -= (double) value / mult; 1423 mult *= 10; 1424 } 1425 } 1426 } else { 1427 if (left > 1) { 1428 *text = '0'; 1429 --left; 1430 } 1431 ++text; 1432 if (info->force_type) { 1433 if (left > 1) { 1434 *text = '.'; 1435 --left; 1436 } 1437 ++text; 1438 } 1439 } 1440 1441 width = info->width - (int)(text - textstart); 1442 if (width > 0) { 1443 char fill = info->pad_zeroes ? '0' : ' '; 1444 char *end = text+left-1; 1445 len = (text - textstart); 1446 for (len = (text - textstart); len--; ) { 1447 if ((textstart+len+width) < end) { 1448 *(textstart+len+width) = *(textstart+len); 1449 } 1450 } 1451 len = (size_t)width; 1452 text += len; 1453 if (len >= left) { 1454 left = SDL_min(left, 1); 1455 } else { 1456 left -= len; 1457 } 1458 while (len--) { 1459 if (textstart+len < end) { 1460 textstart[len] = fill; 1461 } 1462 } 1463 } 1464 1465 return (text - textstart); 1466} 1467 1468int 1469SDL_vsnprintf(SDL_OUT_Z_CAP(maxlen) char *text, size_t maxlen, const char *fmt, va_list ap) 1470{ 1471 size_t left = maxlen; 1472 char *textstart = text; 1473 1474 if (!fmt) { 1475 fmt = ""; 1476 } 1477 while (*fmt) { 1478 if (*fmt == '%') { 1479 SDL_bool done = SDL_FALSE; 1480 size_t len = 0; 1481 SDL_bool check_flag; 1482 SDL_FormatInfo info; 1483 enum 1484 { 1485 DO_INT, 1486 DO_LONG, 1487 DO_LONGLONG 1488 } inttype = DO_INT; 1489 1490 SDL_zero(info); 1491 info.radix = 10; 1492 info.precision = -1; 1493 1494 check_flag = SDL_TRUE; 1495 while (check_flag) { 1496 ++fmt; 1497 switch (*fmt) { 1498 case '-': 1499 info.left_justify = SDL_TRUE; 1500 break; 1501 case '+': 1502 info.force_sign = SDL_TRUE; 1503 break; 1504 case '#': 1505 info.force_type = SDL_TRUE; 1506 break; 1507 case '0': 1508 info.pad_zeroes = SDL_TRUE; 1509 break; 1510 default: 1511 check_flag = SDL_FALSE; 1512 break; 1513 } 1514 } 1515 1516 if (*fmt >= '0' && *fmt <= '9') { 1517 info.width = SDL_strtol(fmt, (char **)&fmt, 0); 1518 } 1519 1520 if (*fmt == '.') { 1521 ++fmt; 1522 if (*fmt >= '0' && *fmt <= '9') { 1523 info.precision = SDL_strtol(fmt, (char **)&fmt, 0); 1524 } else { 1525 info.precision = 0; 1526 } 1527 } 1528 1529 while (!done) { 1530 switch (*fmt) { 1531 case '%': 1532 if (left > 1) { 1533 *text = '%'; 1534 } 1535 len = 1; 1536 done = SDL_TRUE; 1537 break; 1538 case 'c': 1539 /* char is promoted to int when passed through (...) */ 1540 if (left > 1) { 1541 *text = (char) va_arg(ap, int); 1542 } 1543 len = 1; 1544 done = SDL_TRUE; 1545 break; 1546 case 'h': 1547 /* short is promoted to int when passed through (...) */ 1548 break; 1549 case 'l': 1550 if (inttype < DO_LONGLONG) { 1551 ++inttype; 1552 } 1553 break; 1554 case 'I': 1555 if (SDL_strncmp(fmt, "I64", 3) == 0) { 1556 fmt += 2; 1557 inttype = DO_LONGLONG; 1558 } 1559 break; 1560 case 'i': 1561 case 'd': 1562 switch (inttype) { 1563 case DO_INT: 1564 len = SDL_PrintLong(text, left, &info, 1565 (long) va_arg(ap, int)); 1566 break; 1567 case DO_LONG: 1568 len = SDL_PrintLong(text, left, &info, 1569 va_arg(ap, long)); 1570 break; 1571 case DO_LONGLONG: 1572 len = SDL_PrintLongLong(text, left, &info, 1573 va_arg(ap, Sint64)); 1574 break; 1575 } 1576 done = SDL_TRUE; 1577 break; 1578 case 'p': 1579 case 'x': 1580 info.force_case = SDL_CASE_LOWER; 1581 /* Fall through to 'X' handling */ 1582 case 'X': 1583 if (info.force_case == SDL_CASE_NOCHANGE) { 1584 info.force_case = SDL_CASE_UPPER; 1585 } 1586 if (info.radix == 10) { 1587 info.radix = 16; 1588 } 1589 if (*fmt == 'p') { 1590 inttype = DO_LONG; 1591 } 1592 /* Fall through to unsigned handling */ 1593 case 'o': 1594 if (info.radix == 10) { 1595 info.radix = 8; 1596 } 1597 /* Fall through to unsigned handling */ 1598 case 'u': 1599 info.pad_zeroes = SDL_TRUE; 1600 switch (inttype) { 1601 case DO_INT: 1602 len = SDL_PrintUnsignedLong(text, left, &info, 1603 (unsigned long) 1604 va_arg(ap, unsigned int)); 1605 break; 1606 case DO_LONG: 1607 len = SDL_PrintUnsignedLong(text, left, &info, 1608 va_arg(ap, unsigned long)); 1609 break; 1610 case DO_LONGLONG: 1611 len = SDL_PrintUnsignedLongLong(text, left, &info, 1612 va_arg(ap, Uint64)); 1613 break; 1614 } 1615 done = SDL_TRUE; 1616 break; 1617 case 'f': 1618 len = SDL_PrintFloat(text, left, &info, va_arg(ap, double)); 1619 done = SDL_TRUE; 1620 break; 1621 case 's': 1622 len = SDL_PrintString(text, left, &info, va_arg(ap, char *)); 1623 done = SDL_TRUE; 1624 break; 1625 default: 1626 done = SDL_TRUE; 1627 break; 1628 } 1629 ++fmt; 1630 } 1631 text += len; 1632 if (len >= left) { 1633 left = SDL_min(left, 1); 1634 } else { 1635 left -= len; 1636 } 1637 } else { 1638 if (left > 1) { 1639 *text = *fmt; 1640 --left; 1641 } 1642 ++fmt; 1643 ++text; 1644 } 1645 } 1646 if (left > 0) { 1647 *text = '\0'; 1648 } 1649 return (int)(text - textstart); 1650} 1651#endif /* HAVE_VSNPRINTF */ 1652 1653/* vi: set ts=4 sw=4 expandtab: */