src/stdlib/SDL_string.c
author Ryan C. Gordon <icculus@icculus.org>
Mon, 29 May 2017 00:51:38 -0400
changeset 11052 0666dea591ab
parent 11049 6e24dc7c67c6
child 11227 10b07421903d
permissions -rw-r--r--
Fixed whitespace code style.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2017 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 #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 
    39 static 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)
    52 static size_t
    53 SDL_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) {
    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)
    93 static size_t
    94 SDL_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) {
   118         *valuep = value;
   119     }
   120     return (text - textstart);
   121 }
   122 #endif
   123 
   124 #ifndef HAVE_VSSCANF
   125 static size_t
   126 SDL_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) {
   150         *valuep = value;
   151     }
   152     return (text - textstart);
   153 }
   154 #endif
   155 
   156 #if !defined(HAVE_VSSCANF) || !defined(HAVE_STRTOLL)
   157 static size_t
   158 SDL_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) {
   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)
   198 static size_t
   199 SDL_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) {
   223         *valuep = value;
   224     }
   225     return (text - textstart);
   226 }
   227 #endif
   228 
   229 #if !defined(HAVE_VSSCANF) || !defined(HAVE_STRTOD)
   230 static size_t
   231 SDL_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) {
   255         if (negative && value) {
   256             *valuep = -value;
   257         } else {
   258             *valuep = value;
   259         }
   260     }
   261     return (text - textstart);
   262 }
   263 #endif
   264 
   265 void *
   266 SDL_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 
   309 void *
   310 SDL_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 
   362 void *
   363 SDL_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 
   386 int
   387 SDL_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 
   405 size_t
   406 SDL_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 
   419 size_t
   420 SDL_wcslen(const wchar_t * string)
   421 {
   422 #if defined(HAVE_WCSLEN)
   423     return wcslen(string);
   424 #else
   425     size_t len = 0;
   426     while (*string++) {
   427         ++len;
   428     }
   429     return len;
   430 #endif /* HAVE_WCSLEN */
   431 }
   432 
   433 size_t
   434 SDL_wcslcpy(SDL_OUT_Z_CAP(maxlen) wchar_t *dst, const wchar_t *src, size_t maxlen)
   435 {
   436 #if defined(HAVE_WCSLCPY)
   437     return wcslcpy(dst, src, maxlen);
   438 #else
   439     size_t srclen = SDL_wcslen(src);
   440     if (maxlen > 0) {
   441         size_t len = SDL_min(srclen, maxlen - 1);
   442         SDL_memcpy(dst, src, len * sizeof(wchar_t));
   443         dst[len] = '\0';
   444     }
   445     return srclen;
   446 #endif /* HAVE_WCSLCPY */
   447 }
   448 
   449 size_t
   450 SDL_wcslcat(SDL_INOUT_Z_CAP(maxlen) wchar_t *dst, const wchar_t *src, size_t maxlen)
   451 {
   452 #if defined(HAVE_WCSLCAT)
   453     return wcslcat(dst, src, maxlen);
   454 #else
   455     size_t dstlen = SDL_wcslen(dst);
   456     size_t srclen = SDL_wcslen(src);
   457     if (dstlen < maxlen) {
   458         SDL_wcslcpy(dst + dstlen, src, maxlen - dstlen);
   459     }
   460     return dstlen + srclen;
   461 #endif /* HAVE_WCSLCAT */
   462 }
   463 
   464 size_t
   465 SDL_strlcpy(SDL_OUT_Z_CAP(maxlen) char *dst, const char *src, size_t maxlen)
   466 {
   467 #if defined(HAVE_STRLCPY)
   468     return strlcpy(dst, src, maxlen);
   469 #else
   470     size_t srclen = SDL_strlen(src);
   471     if (maxlen > 0) {
   472         size_t len = SDL_min(srclen, maxlen - 1);
   473         SDL_memcpy(dst, src, len);
   474         dst[len] = '\0';
   475     }
   476     return srclen;
   477 #endif /* HAVE_STRLCPY */
   478 }
   479 
   480 size_t
   481 SDL_utf8strlcpy(SDL_OUT_Z_CAP(dst_bytes) char *dst, const char *src, size_t dst_bytes)
   482 {
   483     size_t src_bytes = SDL_strlen(src);
   484     size_t bytes = SDL_min(src_bytes, dst_bytes - 1);
   485     size_t i = 0;
   486     char trailing_bytes = 0;
   487     if (bytes)
   488     {
   489         unsigned char c = (unsigned char)src[bytes - 1];
   490         if (UTF8_IsLeadByte(c))
   491             --bytes;
   492         else if (UTF8_IsTrailingByte(c))
   493         {
   494             for (i = bytes - 1; i != 0; --i)
   495             {
   496                 c = (unsigned char)src[i];
   497                 trailing_bytes = UTF8_TrailingBytes(c);
   498                 if (trailing_bytes)
   499                 {
   500                     if (bytes - i != trailing_bytes + 1)
   501                         bytes = i;
   502 
   503                     break;
   504                 }
   505             }
   506         }
   507         SDL_memcpy(dst, src, bytes);
   508     }
   509     dst[bytes] = '\0';
   510     return bytes;
   511 }
   512 
   513 size_t
   514 SDL_utf8strlen(const char *str)
   515 {
   516     size_t retval = 0;
   517     const char *p = str;
   518     char ch;
   519 
   520     while ((ch = *(p++))) {
   521         /* if top two bits are 1 and 0, it's a continuation byte. */
   522         if ((ch & 0xc0) != 0x80) {
   523             retval++;
   524         }
   525     }
   526     
   527     return retval;
   528 }
   529 
   530 size_t
   531 SDL_strlcat(SDL_INOUT_Z_CAP(maxlen) char *dst, const char *src, size_t maxlen)
   532 {
   533 #if defined(HAVE_STRLCAT)
   534     return strlcat(dst, src, maxlen);
   535 #else
   536     size_t dstlen = SDL_strlen(dst);
   537     size_t srclen = SDL_strlen(src);
   538     if (dstlen < maxlen) {
   539         SDL_strlcpy(dst + dstlen, src, maxlen - dstlen);
   540     }
   541     return dstlen + srclen;
   542 #endif /* HAVE_STRLCAT */
   543 }
   544 
   545 char *
   546 SDL_strdup(const char *string)
   547 {
   548 #if defined(HAVE_STRDUP)
   549     return strdup(string);
   550 #else
   551     size_t len = SDL_strlen(string) + 1;
   552     char *newstr = SDL_malloc(len);
   553     if (newstr) {
   554         SDL_strlcpy(newstr, string, len);
   555     }
   556     return newstr;
   557 #endif /* HAVE_STRDUP */
   558 }
   559 
   560 char *
   561 SDL_strrev(char *string)
   562 {
   563 #if defined(HAVE__STRREV)
   564     return _strrev(string);
   565 #else
   566     size_t len = SDL_strlen(string);
   567     char *a = &string[0];
   568     char *b = &string[len - 1];
   569     len /= 2;
   570     while (len--) {
   571         char c = *a;
   572         *a++ = *b;
   573         *b-- = c;
   574     }
   575     return string;
   576 #endif /* HAVE__STRREV */
   577 }
   578 
   579 char *
   580 SDL_strupr(char *string)
   581 {
   582 #if defined(HAVE__STRUPR)
   583     return _strupr(string);
   584 #else
   585     char *bufp = string;
   586     while (*bufp) {
   587         *bufp = SDL_toupper((unsigned char) *bufp);
   588         ++bufp;
   589     }
   590     return string;
   591 #endif /* HAVE__STRUPR */
   592 }
   593 
   594 char *
   595 SDL_strlwr(char *string)
   596 {
   597 #if defined(HAVE__STRLWR)
   598     return _strlwr(string);
   599 #else
   600     char *bufp = string;
   601     while (*bufp) {
   602         *bufp = SDL_tolower((unsigned char) *bufp);
   603         ++bufp;
   604     }
   605     return string;
   606 #endif /* HAVE__STRLWR */
   607 }
   608 
   609 char *
   610 SDL_strchr(const char *string, int c)
   611 {
   612 #ifdef HAVE_STRCHR
   613     return SDL_const_cast(char*,strchr(string, c));
   614 #elif defined(HAVE_INDEX)
   615     return SDL_const_cast(char*,index(string, c));
   616 #else
   617     while (*string) {
   618         if (*string == c) {
   619             return (char *) string;
   620         }
   621         ++string;
   622     }
   623     return NULL;
   624 #endif /* HAVE_STRCHR */
   625 }
   626 
   627 char *
   628 SDL_strrchr(const char *string, int c)
   629 {
   630 #ifdef HAVE_STRRCHR
   631     return SDL_const_cast(char*,strrchr(string, c));
   632 #elif defined(HAVE_RINDEX)
   633     return SDL_const_cast(char*,rindex(string, c));
   634 #else
   635     const char *bufp = string + SDL_strlen(string) - 1;
   636     while (bufp >= string) {
   637         if (*bufp == c) {
   638             return (char *) bufp;
   639         }
   640         --bufp;
   641     }
   642     return NULL;
   643 #endif /* HAVE_STRRCHR */
   644 }
   645 
   646 char *
   647 SDL_strstr(const char *haystack, const char *needle)
   648 {
   649 #if defined(HAVE_STRSTR)
   650     return SDL_const_cast(char*,strstr(haystack, needle));
   651 #else
   652     size_t length = SDL_strlen(needle);
   653     while (*haystack) {
   654         if (SDL_strncmp(haystack, needle, length) == 0) {
   655             return (char *) haystack;
   656         }
   657         ++haystack;
   658     }
   659     return NULL;
   660 #endif /* HAVE_STRSTR */
   661 }
   662 
   663 #if !defined(HAVE__LTOA) || !defined(HAVE__I64TOA) || \
   664     !defined(HAVE__ULTOA) || !defined(HAVE__UI64TOA)
   665 static const char ntoa_table[] = {
   666     '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
   667     'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
   668     'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
   669     'U', 'V', 'W', 'X', 'Y', 'Z'
   670 };
   671 #endif /* ntoa() conversion table */
   672 
   673 char *
   674 SDL_itoa(int value, char *string, int radix)
   675 {
   676 #ifdef HAVE_ITOA
   677     return itoa(value, string, radix);
   678 #else
   679     return SDL_ltoa((long)value, string, radix);
   680 #endif /* HAVE_ITOA */
   681 }
   682 
   683 char *
   684 SDL_uitoa(unsigned int value, char *string, int radix)
   685 {
   686 #ifdef HAVE__UITOA
   687     return _uitoa(value, string, radix);
   688 #else
   689     return SDL_ultoa((unsigned long)value, string, radix);
   690 #endif /* HAVE__UITOA */
   691 }
   692 
   693 char *
   694 SDL_ltoa(long value, char *string, int radix)
   695 {
   696 #if defined(HAVE__LTOA)
   697     return _ltoa(value, string, radix);
   698 #else
   699     char *bufp = string;
   700 
   701     if (value < 0) {
   702         *bufp++ = '-';
   703         SDL_ultoa(-value, bufp, radix);
   704     } else {
   705         SDL_ultoa(value, bufp, radix);
   706     }
   707 
   708     return string;
   709 #endif /* HAVE__LTOA */
   710 }
   711 
   712 char *
   713 SDL_ultoa(unsigned long value, char *string, int radix)
   714 {
   715 #if defined(HAVE__ULTOA)
   716     return _ultoa(value, string, radix);
   717 #else
   718     char *bufp = string;
   719 
   720     if (value) {
   721         while (value > 0) {
   722             *bufp++ = ntoa_table[value % radix];
   723             value /= radix;
   724         }
   725     } else {
   726         *bufp++ = '0';
   727     }
   728     *bufp = '\0';
   729 
   730     /* The numbers went into the string backwards. :) */
   731     SDL_strrev(string);
   732 
   733     return string;
   734 #endif /* HAVE__ULTOA */
   735 }
   736 
   737 char *
   738 SDL_lltoa(Sint64 value, char *string, int radix)
   739 {
   740 #if defined(HAVE__I64TOA)
   741     return _i64toa(value, string, radix);
   742 #else
   743     char *bufp = string;
   744 
   745     if (value < 0) {
   746         *bufp++ = '-';
   747         SDL_ulltoa(-value, bufp, radix);
   748     } else {
   749         SDL_ulltoa(value, bufp, radix);
   750     }
   751 
   752     return string;
   753 #endif /* HAVE__I64TOA */
   754 }
   755 
   756 char *
   757 SDL_ulltoa(Uint64 value, char *string, int radix)
   758 {
   759 #if defined(HAVE__UI64TOA)
   760     return _ui64toa(value, string, radix);
   761 #else
   762     char *bufp = string;
   763 
   764     if (value) {
   765         while (value > 0) {
   766             *bufp++ = ntoa_table[value % radix];
   767             value /= radix;
   768         }
   769     } else {
   770         *bufp++ = '0';
   771     }
   772     *bufp = '\0';
   773 
   774     /* The numbers went into the string backwards. :) */
   775     SDL_strrev(string);
   776 
   777     return string;
   778 #endif /* HAVE__UI64TOA */
   779 }
   780 
   781 int SDL_atoi(const char *string)
   782 {
   783 #ifdef HAVE_ATOI
   784     return atoi(string);
   785 #else
   786     return SDL_strtol(string, NULL, 0);
   787 #endif /* HAVE_ATOI */
   788 }
   789 
   790 double SDL_atof(const char *string)
   791 {
   792 #ifdef HAVE_ATOF
   793     return (double) atof(string);
   794 #else
   795     return SDL_strtod(string, NULL);
   796 #endif /* HAVE_ATOF */
   797 }
   798 
   799 long
   800 SDL_strtol(const char *string, char **endp, int base)
   801 {
   802 #if defined(HAVE_STRTOL)
   803     return strtol(string, endp, base);
   804 #else
   805     size_t len;
   806     long value;
   807 
   808     if (!base) {
   809         if ((SDL_strlen(string) > 2) && (SDL_strncmp(string, "0x", 2) == 0)) {
   810             base = 16;
   811         } else {
   812             base = 10;
   813         }
   814     }
   815 
   816     len = SDL_ScanLong(string, base, &value);
   817     if (endp) {
   818         *endp = (char *) string + len;
   819     }
   820     return value;
   821 #endif /* HAVE_STRTOL */
   822 }
   823 
   824 unsigned long
   825 SDL_strtoul(const char *string, char **endp, int base)
   826 {
   827 #if defined(HAVE_STRTOUL)
   828     return strtoul(string, endp, base);
   829 #else
   830     size_t len;
   831     unsigned long value;
   832 
   833     if (!base) {
   834         if ((SDL_strlen(string) > 2) && (SDL_strncmp(string, "0x", 2) == 0)) {
   835             base = 16;
   836         } else {
   837             base = 10;
   838         }
   839     }
   840 
   841     len = SDL_ScanUnsignedLong(string, base, &value);
   842     if (endp) {
   843         *endp = (char *) string + len;
   844     }
   845     return value;
   846 #endif /* HAVE_STRTOUL */
   847 }
   848 
   849 Sint64
   850 SDL_strtoll(const char *string, char **endp, int base)
   851 {
   852 #if defined(HAVE_STRTOLL)
   853     return strtoll(string, endp, base);
   854 #else
   855     size_t len;
   856     Sint64 value;
   857 
   858     if (!base) {
   859         if ((SDL_strlen(string) > 2) && (SDL_strncmp(string, "0x", 2) == 0)) {
   860             base = 16;
   861         } else {
   862             base = 10;
   863         }
   864     }
   865 
   866     len = SDL_ScanLongLong(string, base, &value);
   867     if (endp) {
   868         *endp = (char *) string + len;
   869     }
   870     return value;
   871 #endif /* HAVE_STRTOLL */
   872 }
   873 
   874 Uint64
   875 SDL_strtoull(const char *string, char **endp, int base)
   876 {
   877 #if defined(HAVE_STRTOULL)
   878     return strtoull(string, endp, base);
   879 #else
   880     size_t len;
   881     Uint64 value;
   882 
   883     if (!base) {
   884         if ((SDL_strlen(string) > 2) && (SDL_strncmp(string, "0x", 2) == 0)) {
   885             base = 16;
   886         } else {
   887             base = 10;
   888         }
   889     }
   890 
   891     len = SDL_ScanUnsignedLongLong(string, base, &value);
   892     if (endp) {
   893         *endp = (char *) string + len;
   894     }
   895     return value;
   896 #endif /* HAVE_STRTOULL */
   897 }
   898 
   899 double
   900 SDL_strtod(const char *string, char **endp)
   901 {
   902 #if defined(HAVE_STRTOD)
   903     return strtod(string, endp);
   904 #else
   905     size_t len;
   906     double value;
   907 
   908     len = SDL_ScanFloat(string, &value);
   909     if (endp) {
   910         *endp = (char *) string + len;
   911     }
   912     return value;
   913 #endif /* HAVE_STRTOD */
   914 }
   915 
   916 int
   917 SDL_strcmp(const char *str1, const char *str2)
   918 {
   919 #if defined(HAVE_STRCMP)
   920     return strcmp(str1, str2);
   921 #else
   922     while (*str1 && *str2) {
   923         if (*str1 != *str2)
   924             break;
   925         ++str1;
   926         ++str2;
   927     }
   928     return (int) ((unsigned char) *str1 - (unsigned char) *str2);
   929 #endif /* HAVE_STRCMP */
   930 }
   931 
   932 int
   933 SDL_strncmp(const char *str1, const char *str2, size_t maxlen)
   934 {
   935 #if defined(HAVE_STRNCMP)
   936     return strncmp(str1, str2, maxlen);
   937 #else
   938     while (*str1 && *str2 && maxlen) {
   939         if (*str1 != *str2)
   940             break;
   941         ++str1;
   942         ++str2;
   943         --maxlen;
   944     }
   945     if (!maxlen) {
   946         return 0;
   947     }
   948     return (int) ((unsigned char) *str1 - (unsigned char) *str2);
   949 #endif /* HAVE_STRNCMP */
   950 }
   951 
   952 int
   953 SDL_strcasecmp(const char *str1, const char *str2)
   954 {
   955 #ifdef HAVE_STRCASECMP
   956     return strcasecmp(str1, str2);
   957 #elif defined(HAVE__STRICMP)
   958     return _stricmp(str1, str2);
   959 #else
   960     char a = 0;
   961     char b = 0;
   962     while (*str1 && *str2) {
   963         a = SDL_toupper((unsigned char) *str1);
   964         b = SDL_toupper((unsigned char) *str2);
   965         if (a != b)
   966             break;
   967         ++str1;
   968         ++str2;
   969     }
   970     a = SDL_toupper(*str1);
   971     b = SDL_toupper(*str2);
   972     return (int) ((unsigned char) a - (unsigned char) b);
   973 #endif /* HAVE_STRCASECMP */
   974 }
   975 
   976 int
   977 SDL_strncasecmp(const char *str1, const char *str2, size_t maxlen)
   978 {
   979 #ifdef HAVE_STRNCASECMP
   980     return strncasecmp(str1, str2, maxlen);
   981 #elif defined(HAVE__STRNICMP)
   982     return _strnicmp(str1, str2, maxlen);
   983 #else
   984     char a = 0;
   985     char b = 0;
   986     while (*str1 && *str2 && maxlen) {
   987         a = SDL_tolower((unsigned char) *str1);
   988         b = SDL_tolower((unsigned char) *str2);
   989         if (a != b)
   990             break;
   991         ++str1;
   992         ++str2;
   993         --maxlen;
   994     }
   995     if (maxlen == 0) {
   996         return 0;
   997     } else {
   998         a = SDL_tolower((unsigned char) *str1);
   999         b = SDL_tolower((unsigned char) *str2);
  1000         return (int) ((unsigned char) a - (unsigned char) b);
  1001     }
  1002 #endif /* HAVE_STRNCASECMP */
  1003 }
  1004 
  1005 int
  1006 SDL_sscanf(const char *text, SDL_SCANF_FORMAT_STRING const char *fmt, ...)
  1007 {
  1008     int rc;
  1009     va_list ap;
  1010     va_start(ap, fmt);
  1011     rc = SDL_vsscanf(text, fmt, ap);
  1012     va_end(ap);
  1013     return rc;
  1014 }
  1015 
  1016 #ifdef HAVE_VSSCANF
  1017 int
  1018 SDL_vsscanf(const char *text, const char *fmt, va_list ap)
  1019 {
  1020     return vsscanf(text, fmt, ap);
  1021 }
  1022 #else
  1023 int
  1024 SDL_vsscanf(const char *text, const char *fmt, va_list ap)
  1025 {
  1026     int retval = 0;
  1027 
  1028     while (*fmt) {
  1029         if (*fmt == ' ') {
  1030             while (SDL_isspace((unsigned char) *text)) {
  1031                 ++text;
  1032             }
  1033             ++fmt;
  1034             continue;
  1035         }
  1036         if (*fmt == '%') {
  1037             SDL_bool done = SDL_FALSE;
  1038             long count = 0;
  1039             int radix = 10;
  1040             enum
  1041             {
  1042                 DO_SHORT,
  1043                 DO_INT,
  1044                 DO_LONG,
  1045                 DO_LONGLONG
  1046             } inttype = DO_INT;
  1047             SDL_bool suppress = SDL_FALSE;
  1048 
  1049             ++fmt;
  1050             if (*fmt == '%') {
  1051                 if (*text == '%') {
  1052                     ++text;
  1053                     ++fmt;
  1054                     continue;
  1055                 }
  1056                 break;
  1057             }
  1058             if (*fmt == '*') {
  1059                 suppress = SDL_TRUE;
  1060                 ++fmt;
  1061             }
  1062             fmt += SDL_ScanLong(fmt, 10, &count);
  1063 
  1064             if (*fmt == 'c') {
  1065                 if (!count) {
  1066                     count = 1;
  1067                 }
  1068                 if (suppress) {
  1069                     while (count--) {
  1070                         ++text;
  1071                     }
  1072                 } else {
  1073                     char *valuep = va_arg(ap, char *);
  1074                     while (count--) {
  1075                         *valuep++ = *text++;
  1076                     }
  1077                     ++retval;
  1078                 }
  1079                 continue;
  1080             }
  1081 
  1082             while (SDL_isspace((unsigned char) *text)) {
  1083                 ++text;
  1084             }
  1085 
  1086             /* FIXME: implement more of the format specifiers */
  1087             while (!done) {
  1088                 switch (*fmt) {
  1089                 case '*':
  1090                     suppress = SDL_TRUE;
  1091                     break;
  1092                 case 'h':
  1093                     if (inttype > DO_SHORT) {
  1094                         ++inttype;
  1095                     }
  1096                     break;
  1097                 case 'l':
  1098                     if (inttype < DO_LONGLONG) {
  1099                         ++inttype;
  1100                     }
  1101                     break;
  1102                 case 'I':
  1103                     if (SDL_strncmp(fmt, "I64", 3) == 0) {
  1104                         fmt += 2;
  1105                         inttype = DO_LONGLONG;
  1106                     }
  1107                     break;
  1108                 case 'i':
  1109                     {
  1110                         int index = 0;
  1111                         if (text[index] == '-') {
  1112                             ++index;
  1113                         }
  1114                         if (text[index] == '0') {
  1115                             if (SDL_tolower((unsigned char) text[index + 1]) == 'x') {
  1116                                 radix = 16;
  1117                             } else {
  1118                                 radix = 8;
  1119                             }
  1120                         }
  1121                     }
  1122                     /* Fall through to %d handling */
  1123                 case 'd':
  1124                     if (inttype == DO_LONGLONG) {
  1125                         Sint64 value;
  1126                         text += SDL_ScanLongLong(text, radix, &value);
  1127                         if (!suppress) {
  1128                             Sint64 *valuep = va_arg(ap, Sint64 *);
  1129                             *valuep = value;
  1130                             ++retval;
  1131                         }
  1132                     } else {
  1133                         long value;
  1134                         text += SDL_ScanLong(text, radix, &value);
  1135                         if (!suppress) {
  1136                             switch (inttype) {
  1137                             case DO_SHORT:
  1138                                 {
  1139                                     short *valuep = va_arg(ap, short *);
  1140                                     *valuep = (short) value;
  1141                                 }
  1142                                 break;
  1143                             case DO_INT:
  1144                                 {
  1145                                     int *valuep = va_arg(ap, int *);
  1146                                     *valuep = (int) value;
  1147                                 }
  1148                                 break;
  1149                             case DO_LONG:
  1150                                 {
  1151                                     long *valuep = va_arg(ap, long *);
  1152                                     *valuep = value;
  1153                                 }
  1154                                 break;
  1155                             case DO_LONGLONG:
  1156                                 /* Handled above */
  1157                                 break;
  1158                             }
  1159                             ++retval;
  1160                         }
  1161                     }
  1162                     done = SDL_TRUE;
  1163                     break;
  1164                 case 'o':
  1165                     if (radix == 10) {
  1166                         radix = 8;
  1167                     }
  1168                     /* Fall through to unsigned handling */
  1169                 case 'x':
  1170                 case 'X':
  1171                     if (radix == 10) {
  1172                         radix = 16;
  1173                     }
  1174                     /* Fall through to unsigned handling */
  1175                 case 'u':
  1176                     if (inttype == DO_LONGLONG) {
  1177                         Uint64 value;
  1178                         text += SDL_ScanUnsignedLongLong(text, radix, &value);
  1179                         if (!suppress) {
  1180                             Uint64 *valuep = va_arg(ap, Uint64 *);
  1181                             *valuep = value;
  1182                             ++retval;
  1183                         }
  1184                     } else {
  1185                         unsigned long value;
  1186                         text += SDL_ScanUnsignedLong(text, radix, &value);
  1187                         if (!suppress) {
  1188                             switch (inttype) {
  1189                             case DO_SHORT:
  1190                                 {
  1191                                     short *valuep = va_arg(ap, short *);
  1192                                     *valuep = (short) value;
  1193                                 }
  1194                                 break;
  1195                             case DO_INT:
  1196                                 {
  1197                                     int *valuep = va_arg(ap, int *);
  1198                                     *valuep = (int) value;
  1199                                 }
  1200                                 break;
  1201                             case DO_LONG:
  1202                                 {
  1203                                     long *valuep = va_arg(ap, long *);
  1204                                     *valuep = value;
  1205                                 }
  1206                                 break;
  1207                             case DO_LONGLONG:
  1208                                 /* Handled above */
  1209                                 break;
  1210                             }
  1211                             ++retval;
  1212                         }
  1213                     }
  1214                     done = SDL_TRUE;
  1215                     break;
  1216                 case 'p':
  1217                     {
  1218                         uintptr_t value;
  1219                         text += SDL_ScanUintPtrT(text, 16, &value);
  1220                         if (!suppress) {
  1221                             void **valuep = va_arg(ap, void **);
  1222                             *valuep = (void *) value;
  1223                             ++retval;
  1224                         }
  1225                     }
  1226                     done = SDL_TRUE;
  1227                     break;
  1228                 case 'f':
  1229                     {
  1230                         double value;
  1231                         text += SDL_ScanFloat(text, &value);
  1232                         if (!suppress) {
  1233                             float *valuep = va_arg(ap, float *);
  1234                             *valuep = (float) value;
  1235                             ++retval;
  1236                         }
  1237                     }
  1238                     done = SDL_TRUE;
  1239                     break;
  1240                 case 's':
  1241                     if (suppress) {
  1242                         while (!SDL_isspace((unsigned char) *text)) {
  1243                             ++text;
  1244                             if (count) {
  1245                                 if (--count == 0) {
  1246                                     break;
  1247                                 }
  1248                             }
  1249                         }
  1250                     } else {
  1251                         char *valuep = va_arg(ap, char *);
  1252                         while (!SDL_isspace((unsigned char) *text)) {
  1253                             *valuep++ = *text++;
  1254                             if (count) {
  1255                                 if (--count == 0) {
  1256                                     break;
  1257                                 }
  1258                             }
  1259                         }
  1260                         *valuep = '\0';
  1261                         ++retval;
  1262                     }
  1263                     done = SDL_TRUE;
  1264                     break;
  1265                 default:
  1266                     done = SDL_TRUE;
  1267                     break;
  1268                 }
  1269                 ++fmt;
  1270             }
  1271             continue;
  1272         }
  1273         if (*text == *fmt) {
  1274             ++text;
  1275             ++fmt;
  1276             continue;
  1277         }
  1278         /* Text didn't match format specifier */
  1279         break;
  1280     }
  1281 
  1282     return retval;
  1283 }
  1284 #endif /* HAVE_VSSCANF */
  1285 
  1286 int
  1287 SDL_snprintf(SDL_OUT_Z_CAP(maxlen) char *text, size_t maxlen, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
  1288 {
  1289     va_list ap;
  1290     int retval;
  1291 
  1292     va_start(ap, fmt);
  1293     retval = SDL_vsnprintf(text, maxlen, fmt, ap);
  1294     va_end(ap);
  1295 
  1296     return retval;
  1297 }
  1298 
  1299 #ifdef HAVE_VSNPRINTF
  1300 int SDL_vsnprintf(SDL_OUT_Z_CAP(maxlen) char *text, size_t maxlen, const char *fmt, va_list ap)
  1301 {
  1302     if (!fmt) {
  1303         fmt = "";
  1304     }
  1305     return vsnprintf(text, maxlen, fmt, ap);
  1306 }
  1307 #else
  1308  /* FIXME: implement more of the format specifiers */
  1309 typedef enum
  1310 {
  1311     SDL_CASE_NOCHANGE,
  1312     SDL_CASE_LOWER,
  1313     SDL_CASE_UPPER
  1314 } SDL_letter_case;
  1315 
  1316 typedef struct
  1317 {
  1318     SDL_bool left_justify;
  1319     SDL_bool force_sign;
  1320     SDL_bool force_type;
  1321     SDL_bool pad_zeroes;
  1322     SDL_letter_case force_case;
  1323     int width;
  1324     int radix;
  1325     int precision;
  1326 } SDL_FormatInfo;
  1327 
  1328 static size_t
  1329 SDL_PrintString(char *text, size_t maxlen, SDL_FormatInfo *info, const char *string)
  1330 {
  1331     size_t length = 0;
  1332     size_t slen;
  1333 
  1334     if (string == NULL) {
  1335         string = "(null)";
  1336     }
  1337 
  1338     if (info && info->width && (size_t)info->width > SDL_strlen(string)) {
  1339         char fill = info->pad_zeroes ? '0' : ' ';
  1340         size_t width = info->width - SDL_strlen(string);
  1341         while (width-- > 0 && maxlen > 0) {
  1342             *text++ = fill;
  1343             ++length;
  1344             --maxlen;
  1345         }
  1346     }
  1347 
  1348     slen = SDL_strlcpy(text, string, maxlen);
  1349     length += SDL_min(slen, maxlen);
  1350 
  1351     if (info) {
  1352         if (info->force_case == SDL_CASE_LOWER) {
  1353             SDL_strlwr(text);
  1354         } else if (info->force_case == SDL_CASE_UPPER) {
  1355             SDL_strupr(text);
  1356         }
  1357     }
  1358     return length;
  1359 }
  1360 
  1361 static size_t
  1362 SDL_PrintLong(char *text, size_t maxlen, SDL_FormatInfo *info, long value)
  1363 {
  1364     char num[130];
  1365 
  1366     SDL_ltoa(value, num, info ? info->radix : 10);
  1367     return SDL_PrintString(text, maxlen, info, num);
  1368 }
  1369 
  1370 static size_t
  1371 SDL_PrintUnsignedLong(char *text, size_t maxlen, SDL_FormatInfo *info, unsigned long value)
  1372 {
  1373     char num[130];
  1374 
  1375     SDL_ultoa(value, num, info ? info->radix : 10);
  1376     return SDL_PrintString(text, maxlen, info, num);
  1377 }
  1378 
  1379 static size_t
  1380 SDL_PrintLongLong(char *text, size_t maxlen, SDL_FormatInfo *info, Sint64 value)
  1381 {
  1382     char num[130];
  1383 
  1384     SDL_lltoa(value, num, info ? info->radix : 10);
  1385     return SDL_PrintString(text, maxlen, info, num);
  1386 }
  1387 
  1388 static size_t
  1389 SDL_PrintUnsignedLongLong(char *text, size_t maxlen, SDL_FormatInfo *info, Uint64 value)
  1390 {
  1391     char num[130];
  1392 
  1393     SDL_ulltoa(value, num, info ? info->radix : 10);
  1394     return SDL_PrintString(text, maxlen, info, num);
  1395 }
  1396 
  1397 static size_t
  1398 SDL_PrintFloat(char *text, size_t maxlen, SDL_FormatInfo *info, double arg)
  1399 {
  1400     int width;
  1401     size_t len;
  1402     size_t left = maxlen;
  1403     char *textstart = text;
  1404 
  1405     if (arg) {
  1406         /* This isn't especially accurate, but hey, it's easy. :) */
  1407         unsigned long value;
  1408 
  1409         if (arg < 0) {
  1410             if (left > 1) {
  1411                 *text = '-';
  1412                 --left;
  1413             }
  1414             ++text;
  1415             arg = -arg;
  1416         } else if (info->force_sign) {
  1417             if (left > 1) {
  1418                 *text = '+';
  1419                 --left;
  1420             }
  1421             ++text;
  1422         }
  1423         value = (unsigned long) arg;
  1424         len = SDL_PrintUnsignedLong(text, left, NULL, value);
  1425         if (len >= left) {
  1426             text += (left > 1) ? left - 1 : 0;
  1427             left = SDL_min(left, 1);
  1428         } else {
  1429             text += len;
  1430             left -= len;
  1431         }
  1432         arg -= value;
  1433         if (info->precision < 0) {
  1434             info->precision = 6;
  1435         }
  1436         if (info->force_type || info->precision > 0) {
  1437             int mult = 10;
  1438             if (left > 1) {
  1439                 *text = '.';
  1440                 --left;
  1441             }
  1442             ++text;
  1443             while (info->precision-- > 0) {
  1444                 value = (unsigned long) (arg * mult);
  1445                 len = SDL_PrintUnsignedLong(text, left, NULL, value);
  1446                 if (len >= left) {
  1447                     text += (left > 1) ? left - 1 : 0;
  1448                     left = SDL_min(left, 1);
  1449                 } else {
  1450                     text += len;
  1451                     left -= len;
  1452                 }
  1453                 arg -= (double) value / mult;
  1454                 mult *= 10;
  1455             }
  1456         }
  1457     } else {
  1458         if (left > 1) {
  1459             *text = '0';
  1460             --left;
  1461         }
  1462         ++text;
  1463         if (info->force_type) {
  1464             if (left > 1) {
  1465                 *text = '.';
  1466                 --left;
  1467             }
  1468             ++text;
  1469         }
  1470     }
  1471 
  1472     width = info->width - (int)(text - textstart);
  1473     if (width > 0) {
  1474         char fill = info->pad_zeroes ? '0' : ' ';
  1475         char *end = text+left-1;
  1476         len = (text - textstart);
  1477         for (len = (text - textstart); len--; ) {
  1478             if ((textstart+len+width) < end) {
  1479                 *(textstart+len+width) = *(textstart+len);
  1480             }
  1481         }
  1482         len = (size_t)width;
  1483         if (len >= left) {
  1484             text += (left > 1) ? left - 1 : 0;
  1485             left = SDL_min(left, 1);
  1486         } else {
  1487             text += len;
  1488             left -= len;
  1489         }
  1490         while (len--) {
  1491             if (textstart+len < end) {
  1492                 textstart[len] = fill;
  1493             }
  1494         }
  1495     }
  1496 
  1497     return (text - textstart);
  1498 }
  1499 
  1500 int
  1501 SDL_vsnprintf(SDL_OUT_Z_CAP(maxlen) char *text, size_t maxlen, const char *fmt, va_list ap)
  1502 {
  1503     size_t left = maxlen;
  1504     char *textstart = text;
  1505 
  1506     if (!fmt) {
  1507         fmt = "";
  1508     }
  1509     while (*fmt && left > 1) {
  1510         if (*fmt == '%') {
  1511             SDL_bool done = SDL_FALSE;
  1512             size_t len = 0;
  1513             SDL_bool check_flag;
  1514             SDL_FormatInfo info;
  1515             enum
  1516             {
  1517                 DO_INT,
  1518                 DO_LONG,
  1519                 DO_LONGLONG
  1520             } inttype = DO_INT;
  1521 
  1522             SDL_zero(info);
  1523             info.radix = 10;
  1524             info.precision = -1;
  1525 
  1526             check_flag = SDL_TRUE;
  1527             while (check_flag) {
  1528                 ++fmt;
  1529                 switch (*fmt) {
  1530                 case '-':
  1531                     info.left_justify = SDL_TRUE;
  1532                     break;
  1533                 case '+':
  1534                     info.force_sign = SDL_TRUE;
  1535                     break;
  1536                 case '#':
  1537                     info.force_type = SDL_TRUE;
  1538                     break;
  1539                 case '0':
  1540                     info.pad_zeroes = SDL_TRUE;
  1541                     break;
  1542                 default:
  1543                     check_flag = SDL_FALSE;
  1544                     break;
  1545                 }
  1546             }
  1547 
  1548             if (*fmt >= '0' && *fmt <= '9') {
  1549                 info.width = SDL_strtol(fmt, (char **)&fmt, 0);
  1550             }
  1551 
  1552             if (*fmt == '.') {
  1553                 ++fmt;
  1554                 if (*fmt >= '0' && *fmt <= '9') {
  1555                     info.precision = SDL_strtol(fmt, (char **)&fmt, 0);
  1556                 } else {
  1557                     info.precision = 0;
  1558                 }
  1559             }
  1560 
  1561             while (!done) {
  1562                 switch (*fmt) {
  1563                 case '%':
  1564                     if (left > 1) {
  1565                         *text = '%';
  1566                     }
  1567                     len = 1;
  1568                     done = SDL_TRUE;
  1569                     break;
  1570                 case 'c':
  1571                     /* char is promoted to int when passed through (...) */
  1572                     if (left > 1) {
  1573                         *text = (char) va_arg(ap, int);
  1574                     }
  1575                     len = 1;
  1576                     done = SDL_TRUE;
  1577                     break;
  1578                 case 'h':
  1579                     /* short is promoted to int when passed through (...) */
  1580                     break;
  1581                 case 'l':
  1582                     if (inttype < DO_LONGLONG) {
  1583                         ++inttype;
  1584                     }
  1585                     break;
  1586                 case 'I':
  1587                     if (SDL_strncmp(fmt, "I64", 3) == 0) {
  1588                         fmt += 2;
  1589                         inttype = DO_LONGLONG;
  1590                     }
  1591                     break;
  1592                 case 'i':
  1593                 case 'd':
  1594                     switch (inttype) {
  1595                     case DO_INT:
  1596                         len = SDL_PrintLong(text, left, &info,
  1597                                             (long) va_arg(ap, int));
  1598                         break;
  1599                     case DO_LONG:
  1600                         len = SDL_PrintLong(text, left, &info,
  1601                                             va_arg(ap, long));
  1602                         break;
  1603                     case DO_LONGLONG:
  1604                         len = SDL_PrintLongLong(text, left, &info,
  1605                                                 va_arg(ap, Sint64));
  1606                         break;
  1607                     }
  1608                     done = SDL_TRUE;
  1609                     break;
  1610                 case 'p':
  1611                 case 'x':
  1612                     info.force_case = SDL_CASE_LOWER;
  1613                     /* Fall through to 'X' handling */
  1614                 case 'X':
  1615                     if (info.force_case == SDL_CASE_NOCHANGE) {
  1616                         info.force_case = SDL_CASE_UPPER;
  1617                     }
  1618                     if (info.radix == 10) {
  1619                         info.radix = 16;
  1620                     }
  1621                     if (*fmt == 'p') {
  1622                         inttype = DO_LONG;
  1623                     }
  1624                     /* Fall through to unsigned handling */
  1625                 case 'o':
  1626                     if (info.radix == 10) {
  1627                         info.radix = 8;
  1628                     }
  1629                     /* Fall through to unsigned handling */
  1630                 case 'u':
  1631                     info.pad_zeroes = SDL_TRUE;
  1632                     switch (inttype) {
  1633                     case DO_INT:
  1634                         len = SDL_PrintUnsignedLong(text, left, &info,
  1635                                                     (unsigned long)
  1636                                                     va_arg(ap, unsigned int));
  1637                         break;
  1638                     case DO_LONG:
  1639                         len = SDL_PrintUnsignedLong(text, left, &info,
  1640                                                     va_arg(ap, unsigned long));
  1641                         break;
  1642                     case DO_LONGLONG:
  1643                         len = SDL_PrintUnsignedLongLong(text, left, &info,
  1644                                                         va_arg(ap, Uint64));
  1645                         break;
  1646                     }
  1647                     done = SDL_TRUE;
  1648                     break;
  1649                 case 'f':
  1650                     len = SDL_PrintFloat(text, left, &info, va_arg(ap, double));
  1651                     done = SDL_TRUE;
  1652                     break;
  1653                 case 'S':
  1654                     {
  1655                         /* In practice this is used on Windows for WCHAR strings */
  1656                         wchar_t *wide_arg = va_arg(ap, wchar_t *);
  1657                         char *arg = SDL_iconv_string("UTF-8", "UTF-16LE", (char *)(wide_arg), (SDL_wcslen(wide_arg)+1)*sizeof(*wide_arg));
  1658                         len = SDL_PrintString(text, left, &info, arg);
  1659                         SDL_free(arg);
  1660                         done = SDL_TRUE;
  1661                     }
  1662                     break;
  1663                 case 's':
  1664                     len = SDL_PrintString(text, left, &info, va_arg(ap, char *));
  1665                     done = SDL_TRUE;
  1666                     break;
  1667                 default:
  1668                     done = SDL_TRUE;
  1669                     break;
  1670                 }
  1671                 ++fmt;
  1672             }
  1673             if (len >= left) {
  1674                 text += (left > 1) ? left - 1 : 0;
  1675                 left = SDL_min(left, 1);
  1676             } else {
  1677                 text += len;
  1678                 left -= len;
  1679             }
  1680         } else {
  1681             *text++ = *fmt++;
  1682             --left;
  1683         }
  1684     }
  1685     if (left > 0) {
  1686         *text = '\0';
  1687     }
  1688     return (int)(text - textstart);
  1689 }
  1690 #endif /* HAVE_VSNPRINTF */
  1691 
  1692 /* vi: set ts=4 sw=4 expandtab: */