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