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