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