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