src/stdlib/SDL_string.c
author Sam Lantinga
Wed, 01 Mar 2006 09:43:47 +0000
changeset 1456 84de7511f79f
parent 1402 d910939febfa
child 1501 73dc5d39bbf8
permissions -rw-r--r--
Fixed a bunch of 64-bit compatibility problems
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2006 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 /* This file contains portable string manipulation functions for SDL */
    25 
    26 #include "SDL_stdinc.h"
    27 
    28 
    29 #define SDL_isupperhex(X)   (((X) >= 'A') && ((X) <= 'F'))
    30 #define SDL_islowerhex(X)   (((X) >= 'a') && ((X) <= 'f'))
    31 
    32 #if !defined(HAVE_SSCANF) || !defined(HAVE_STRTOL)
    33 static size_t SDL_ScanLong(const char *text, int radix, long *valuep)
    34 {
    35     const char *textstart = text;
    36     long value = 0;
    37     SDL_bool negative = SDL_FALSE;
    38 
    39     if ( *text == '-' ) {
    40         negative = SDL_TRUE;
    41         ++text;
    42     }
    43     if ( radix == 16 && SDL_strncmp(text, "0x", 2) == 0 ) {
    44         text += 2;
    45     }
    46     for ( ; ; ) {
    47         int v;
    48         if ( SDL_isdigit(*text) ) {
    49             v = *text - '0';
    50         } else if ( radix == 16 && SDL_isupperhex(*text) ) {
    51             v = 10 + (*text - 'A');
    52         } else if ( radix == 16 && SDL_islowerhex(*text) ) {
    53             v = 10 + (*text - 'a');
    54         } else {
    55             break;
    56         }
    57         value *= radix;
    58         value += v;
    59         ++text;
    60     }
    61     if ( valuep ) {
    62         if ( negative && value ) {
    63             *valuep = -value;
    64         } else {
    65             *valuep = value;
    66         }
    67     }
    68     return (text - textstart);
    69 }
    70 #endif
    71 
    72 #if !defined(HAVE_SSCANF) || !defined(HAVE_STRTOUL) || !defined(HAVE_STRTOD)
    73 static size_t SDL_ScanUnsignedLong(const char *text, int radix, unsigned long *valuep)
    74 {
    75     const char *textstart = text;
    76     unsigned long value = 0;
    77 
    78     if ( radix == 16 && SDL_strncmp(text, "0x", 2) == 0 ) {
    79         text += 2;
    80     }
    81     for ( ; ; ) {
    82         int v;
    83         if ( SDL_isdigit(*text) ) {
    84             v = *text - '0';
    85         } else if ( radix == 16 && SDL_isupperhex(*text) ) {
    86             v = 10 + (*text - 'A');
    87         } else if ( radix == 16 && SDL_islowerhex(*text) ) {
    88             v = 10 + (*text - 'a');
    89         } else {
    90             break;
    91         }
    92         value *= radix;
    93         value += v;
    94         ++text;
    95     }
    96     if ( valuep ) {
    97         *valuep = value;
    98     }
    99     return (text - textstart);
   100 }
   101 #endif
   102 
   103 #ifndef HAVE_SSCANF
   104 static size_t SDL_ScanUintPtrT(const char *text, int radix, uintptr_t *valuep)
   105 {
   106     const char *textstart = text;
   107     uintptr_t value = 0;
   108 
   109     if ( radix == 16 && SDL_strncmp(text, "0x", 2) == 0 ) {
   110         text += 2;
   111     }
   112     for ( ; ; ) {
   113         int v;
   114         if ( SDL_isdigit(*text) ) {
   115             v = *text - '0';
   116         } else if ( radix == 16 && SDL_isupperhex(*text) ) {
   117             v = 10 + (*text - 'A');
   118         } else if ( radix == 16 && SDL_islowerhex(*text) ) {
   119             v = 10 + (*text - 'a');
   120         } else {
   121             break;
   122         }
   123         value *= radix;
   124         value += v;
   125         ++text;
   126     }
   127     if ( valuep ) {
   128         *valuep = value;
   129     }
   130     return (text - textstart);
   131 }
   132 #endif
   133 
   134 #ifdef SDL_HAS_64BIT_TYPE
   135 #if !defined(HAVE_SSCANF) || !defined(HAVE_STRTOLL)
   136 static size_t SDL_ScanLongLong(const char *text, int radix, Sint64 *valuep)
   137 {
   138     const char *textstart = text;
   139     Sint64 value = 0;
   140     SDL_bool negative = SDL_FALSE;
   141 
   142     if ( *text == '-' ) {
   143         negative = SDL_TRUE;
   144         ++text;
   145     }
   146     if ( radix == 16 && SDL_strncmp(text, "0x", 2) == 0 ) {
   147         text += 2;
   148     }
   149     for ( ; ; ) {
   150         int v;
   151         if ( SDL_isdigit(*text) ) {
   152             v = *text - '0';
   153         } else if ( radix == 16 && SDL_isupperhex(*text) ) {
   154             v = 10 + (*text - 'A');
   155         } else if ( radix == 16 && SDL_islowerhex(*text) ) {
   156             v = 10 + (*text - 'a');
   157         } else {
   158             break;
   159         }
   160         value *= radix;
   161         value += v;
   162         ++text;
   163     }
   164     if ( valuep ) {
   165         if ( negative && value ) {
   166             *valuep = -value;
   167         } else {
   168             *valuep = value;
   169         }
   170     }
   171     return (text - textstart);
   172 }
   173 #endif
   174 
   175 #if !defined(HAVE_SSCANF) || !defined(HAVE_STRTOULL)
   176 static size_t SDL_ScanUnsignedLongLong(const char *text, int radix, Uint64 *valuep)
   177 {
   178     const char *textstart = text;
   179     Uint64 value = 0;
   180 
   181     if ( radix == 16 && SDL_strncmp(text, "0x", 2) == 0 ) {
   182         text += 2;
   183     }
   184     for ( ; ; ) {
   185         int v;
   186         if ( SDL_isdigit(*text) ) {
   187             v = *text - '0';
   188         } else if ( radix == 16 && SDL_isupperhex(*text) ) {
   189             v = 10 + (*text - 'A');
   190         } else if ( radix == 16 && SDL_islowerhex(*text) ) {
   191             v = 10 + (*text - 'a');
   192         } else {
   193             break;
   194         }
   195         value *= radix;
   196         value += v;
   197         ++text;
   198     }
   199     if ( valuep ) {
   200         *valuep = value;
   201     }
   202     return (text - textstart);
   203 }
   204 #endif
   205 #endif /* SDL_HAS_64BIT_TYPE */
   206 
   207 #if !defined(HAVE_SSCANF) || !defined(HAVE_STRTOD)
   208 static size_t SDL_ScanFloat(const char *text, double *valuep)
   209 {
   210     const char *textstart = text;
   211     unsigned long lvalue = 0;
   212     double value = 0.0;
   213     SDL_bool negative = SDL_FALSE;
   214 
   215     if ( *text == '-' ) {
   216         negative = SDL_TRUE;
   217         ++text;
   218     }
   219     text += SDL_ScanUnsignedLong(text, 10, &lvalue);
   220     value += lvalue;
   221     if ( *text == '.' ) {
   222         int mult = 10;
   223         ++text;
   224         while ( SDL_isdigit(*text) ) {
   225             lvalue = *text - '0';
   226             value += (double)lvalue / mult;
   227             mult *= 10;
   228             ++text;
   229         }
   230     }
   231     if ( valuep ) {
   232         if ( negative && value ) {
   233             *valuep = -value;
   234         } else {
   235             *valuep = value;
   236         }
   237     }
   238     return (text - textstart);
   239 }
   240 #endif
   241 
   242 #ifndef SDL_memset
   243 void *SDL_memset(void *dst, int c, size_t len)
   244 {
   245     size_t left = (len % 4);
   246     if ( len >= 4 ) {
   247         Uint32 value = 0;
   248         Uint32 *dstp = (Uint32 *)dst;
   249         int i;
   250         for (i = 0; i < 4; ++i) {
   251             value <<= 8;
   252             value |= c;
   253         }
   254         len /= 4;
   255         while ( len-- ) {
   256             *dstp++ = value;
   257         }
   258     }
   259     if ( left > 0 ) {
   260         Uint8 value = (Uint8)c;
   261         Uint8 *dstp = (Uint8 *)dst;
   262 	switch(left) {
   263 	case 3:
   264             *dstp++ = value;
   265 	case 2:
   266             *dstp++ = value;
   267 	case 1:
   268             *dstp++ = value;
   269         }
   270     }
   271     return dst;
   272 }
   273 #endif
   274 
   275 #ifndef SDL_memcpy
   276 void *SDL_memcpy(void *dst, const void *src, size_t len)
   277 {
   278     char *srcp = (char *)src;
   279     char *dstp = (char *)dst;
   280     while ( len-- ) {
   281         *dstp++ = *srcp++;
   282     }
   283     return dst;
   284 }
   285 #endif
   286 
   287 #ifndef SDL_revcpy
   288 void *SDL_revcpy(void *dst, const void *src, size_t len)
   289 {
   290     char *srcp = (char *)src;
   291     char *dstp = (char *)dst;
   292     srcp += len;
   293     dstp += len;
   294     while ( len-- ) {
   295         *dstp-- = *srcp--;
   296     }
   297     return dst;
   298 }
   299 #endif
   300 
   301 #ifndef SDL_memcmp
   302 int SDL_memcmp(const void *s1, const void *s2, size_t len)
   303 {
   304     char *s1p = (char *)s1;
   305     char *s2p = (char *)s2;
   306     while ( len-- ) {
   307         if ( *s1p != *s2p ) {
   308             return (*s1p - *s2p);
   309     }
   310     ++s1p;
   311     ++s2p;
   312     }
   313     return 0;
   314 }
   315 #endif
   316 
   317 #ifndef HAVE_STRLEN
   318 size_t SDL_strlen(const char *string)
   319 {
   320     size_t len = 0;
   321     while ( *string++ ) {
   322         ++len;
   323     }
   324     return len;
   325 }
   326 #endif
   327 
   328 #ifndef HAVE_STRLCPY
   329 size_t SDL_strlcpy(char *dst, const char *src, size_t maxlen)
   330 {
   331     size_t srclen = SDL_strlen(src);
   332     if ( maxlen > 0 ) {
   333         size_t len = SDL_min(srclen, maxlen-1);
   334         SDL_memcpy(dst, src, len);
   335         dst[len] = '\0';
   336     }
   337     return srclen;
   338 }
   339 #endif
   340 
   341 #ifndef HAVE_STRLCAT
   342 size_t SDL_strlcat(char *dst, const char *src, size_t maxlen)
   343 {
   344     size_t dstlen = SDL_strlen(dst);
   345     size_t srclen = SDL_strlen(src);
   346     if ( dstlen < maxlen ) {
   347         SDL_strlcpy(dst+dstlen, src, maxlen-dstlen);
   348     }
   349     return dstlen+srclen;
   350 }
   351 #endif
   352 
   353 #ifndef HAVE_STRDUP
   354 char *SDL_strdup(const char *string)
   355 {
   356     size_t len = SDL_strlen(string)+1;
   357     char *newstr = SDL_malloc(len);
   358     if ( newstr ) {
   359         SDL_strlcpy(newstr, string, len);
   360     }
   361     return newstr;
   362 }
   363 #endif
   364 
   365 #ifndef HAVE__STRREV
   366 char *SDL_strrev(char *string)
   367 {
   368     size_t len = SDL_strlen(string);
   369     char *a = &string[0];
   370     char *b = &string[len-1];
   371     len /= 2;
   372     while ( len-- ) {
   373         char c = *a;
   374         *a++ = *b;
   375         *b-- = c;
   376     }
   377     return string;
   378 }
   379 #endif
   380 
   381 #ifndef HAVE__STRUPR
   382 char *SDL_strupr(char *string)
   383 {
   384     char *bufp = string;
   385     while ( *bufp ) {
   386         *bufp = SDL_toupper(*bufp);
   387 	++bufp;
   388     }
   389     return string;
   390 }
   391 #endif
   392 
   393 #ifndef HAVE__STRLWR
   394 char *SDL_strlwr(char *string)
   395 {
   396     char *bufp = string;
   397     while ( *bufp ) {
   398         *bufp = SDL_tolower(*bufp);
   399 	++bufp;
   400     }
   401     return string;
   402 }
   403 #endif
   404 
   405 #ifndef HAVE_STRCHR
   406 char *SDL_strchr(const char *string, int c)
   407 {
   408     while ( *string ) {
   409         if ( *string == c ) {
   410             return (char *)string;
   411         }
   412 	++string;
   413     }
   414     return NULL;
   415 }
   416 #endif
   417 
   418 #ifndef HAVE_STRRCHR
   419 char *SDL_strrchr(const char *string, int c)
   420 {
   421     const char *bufp = string + SDL_strlen(string) - 1;
   422     while ( bufp >= string ) {
   423         if ( *bufp == c ) {
   424             return (char *)bufp;
   425         }
   426 	--bufp;
   427     }
   428     return NULL;
   429 }
   430 #endif
   431 
   432 #ifndef HAVE_STRSTR
   433 char *SDL_strstr(const char *haystack, const char *needle)
   434 {
   435     size_t length = SDL_strlen(needle);
   436     while ( *haystack ) {
   437         if ( SDL_strncmp(haystack, needle, length) == 0 ) {
   438             return (char *)haystack;
   439         }
   440 	++haystack;
   441     }
   442     return NULL;
   443 }
   444 #endif
   445 
   446 #if !defined(HAVE__LTOA)  || !defined(HAVE__I64TOA) || \
   447     !defined(HAVE__ULTOA) || !defined(HAVE__UI64TOA)
   448 static const char ntoa_table[] = {
   449     '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
   450     'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
   451     'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
   452     'U', 'V', 'W', 'X', 'Y', 'Z'
   453 };
   454 #endif /* ntoa() conversion table */
   455 
   456 #ifndef HAVE__LTOA
   457 char *SDL_ltoa(long value, char *string, int radix)
   458 {
   459     char *bufp = string;
   460 
   461     if ( value < 0 ) {
   462         *bufp++ = '-';
   463         value = -value;
   464     }
   465     if ( value ) {
   466         while ( value > 0 ) {
   467             *bufp++ = ntoa_table[value % radix];
   468             value /= radix;
   469         }
   470     } else {
   471         *bufp++ = '0';
   472     }
   473     *bufp = '\0';
   474 
   475     /* The numbers went into the string backwards. :) */
   476     if ( *string == '-' ) {
   477         SDL_strrev(string+1);
   478     } else {
   479         SDL_strrev(string);
   480     }
   481 
   482     return string;
   483 }
   484 #endif
   485 
   486 #ifndef HAVE__ULTOA
   487 char *SDL_ultoa(unsigned long value, char *string, int radix)
   488 {
   489     char *bufp = string;
   490 
   491     if ( value ) {
   492         while ( value > 0 ) {
   493             *bufp++ = ntoa_table[value % radix];
   494             value /= radix;
   495         }
   496     } else {
   497         *bufp++ = '0';
   498     }
   499     *bufp = '\0';
   500 
   501     /* The numbers went into the string backwards. :) */
   502     SDL_strrev(string);
   503 
   504     return string;
   505 }
   506 #endif
   507 
   508 #ifndef HAVE_STRTOL
   509 long SDL_strtol(const char *string, char **endp, int base)
   510 {
   511     size_t len;
   512     long value;
   513 
   514     len = SDL_ScanLong(string, base ? base : 10, &value);
   515     if ( endp ) {
   516         *endp = (char *)string + len;
   517     }
   518     return value;
   519 }
   520 #endif
   521 
   522 #ifndef HAVE_STRTOUL
   523 unsigned long SDL_strtoul(const char *string, char **endp, int base)
   524 {
   525     size_t len;
   526     unsigned long value;
   527 
   528     len = SDL_ScanUnsignedLong(string, base ? base : 10, &value);
   529     if ( endp ) {
   530         *endp = (char *)string + len;
   531     }
   532     return value;
   533 }
   534 #endif
   535 
   536 #ifdef SDL_HAS_64BIT_TYPE
   537 
   538 #ifndef HAVE__I64TOA
   539 char *SDL_lltoa(Sint64 value, char *string, int radix)
   540 {
   541     char *bufp = string;
   542 
   543     if ( value < 0 ) {
   544         *bufp++ = '-';
   545         value = -value;
   546     }
   547     if ( value ) {
   548         while ( value > 0 ) {
   549             *bufp++ = ntoa_table[value % radix];
   550             value /= radix;
   551         }
   552     } else {
   553         *bufp++ = '0';
   554     }
   555     *bufp = '\0';
   556 
   557     /* The numbers went into the string backwards. :) */
   558     if ( *string == '-' ) {
   559         SDL_strrev(string+1);
   560     } else {
   561         SDL_strrev(string);
   562     }
   563 
   564     return string;
   565 }
   566 #endif
   567 
   568 #ifndef HAVE__UI64TOA
   569 char *SDL_ulltoa(Uint64 value, char *string, int radix)
   570 {
   571     char *bufp = string;
   572 
   573     if ( value ) {
   574         while ( value > 0 ) {
   575             *bufp++ = ntoa_table[value % radix];
   576             value /= radix;
   577         }
   578     } else {
   579         *bufp++ = '0';
   580     }
   581     *bufp = '\0';
   582 
   583     /* The numbers went into the string backwards. :) */
   584     SDL_strrev(string);
   585 
   586     return string;
   587 }
   588 #endif
   589 
   590 #ifndef HAVE_STRTOLL
   591 Sint64 SDL_strtoll(const char *string, char **endp, int base)
   592 {
   593     size_t len;
   594     Sint64 value;
   595 
   596     len = SDL_ScanLongLong(string, base ? base : 10, &value);
   597     if ( endp ) {
   598         *endp = (char *)string + len;
   599     }
   600     return value;
   601 }
   602 #endif
   603 
   604 #ifndef HAVE_STRTOULL
   605 Uint64 SDL_strtoull(const char *string, char **endp, int base)
   606 {
   607     size_t len;
   608     Uint64 value;
   609 
   610     len = SDL_ScanUnsignedLongLong(string, base ? base : 10, &value);
   611     if ( endp ) {
   612         *endp = (char *)string + len;
   613     }
   614     return value;
   615 }
   616 #endif
   617 
   618 #endif /* SDL_HAS_64BIT_TYPE */
   619 
   620 #ifndef HAVE_STRTOD
   621 double SDL_strtod(const char *string, char **endp)
   622 {
   623     size_t len;
   624     double value;
   625 
   626     len = SDL_ScanFloat(string, &value);
   627     if ( endp ) {
   628         *endp = (char *)string + len;
   629     }
   630     return value;
   631 }
   632 #endif
   633 
   634 #ifndef HAVE_STRCMP
   635 int SDL_strcmp(const char *str1, const char *str2)
   636 {
   637     while (*str1 && *str2) {
   638         if ( *str1 != *str2 )
   639             break;
   640         ++str1;
   641         ++str2;
   642     }
   643     return (int)((unsigned char)*str1 - (unsigned char)*str2);
   644 }
   645 #endif
   646 
   647 #ifndef HAVE_STRNCMP
   648 int SDL_strncmp(const char *str1, const char *str2, size_t maxlen)
   649 {
   650     while ( *str1 && *str2 && maxlen ) {
   651         if ( *str1 != *str2 )
   652             break;
   653         ++str1;
   654         ++str2;
   655         --maxlen;
   656     }
   657     if ( ! maxlen ) {
   658         return 0;
   659     }
   660     return (int)((unsigned char)*str1 - (unsigned char)*str2);
   661 }
   662 #endif
   663 
   664 #ifndef HAVE_STRCASECMP
   665 int SDL_strcasecmp(const char *str1, const char *str2)
   666 {
   667     char a = 0;
   668     char b = 0;
   669     while (*str1 && *str2) {
   670         a = SDL_tolower(*str1);
   671         b = SDL_tolower(*str2);
   672         if ( a != b )
   673             break;
   674         ++str1;
   675         ++str2;
   676     }
   677     return (int)((unsigned char)a - (unsigned char)b);
   678 }
   679 #endif
   680 
   681 #ifndef HAVE_SSCANF
   682 int SDL_sscanf(const char *text, const char *fmt, ...)
   683 {
   684     va_list ap;
   685     int retval = 0;
   686 
   687     va_start(ap, fmt);
   688     while ( *fmt ) {
   689         if ( *fmt == ' ' ) {
   690             while ( SDL_isspace(*text) ) {
   691                 ++text;
   692             }
   693             ++fmt;
   694             continue;
   695         }
   696         if ( *fmt == '%' ) {
   697             SDL_bool done = SDL_FALSE;
   698             long count = 0;
   699             int radix = 10;
   700             enum {
   701                 DO_SHORT,
   702                 DO_INT,
   703                 DO_LONG,
   704                 DO_LONGLONG
   705             } inttype = DO_INT;
   706             SDL_bool suppress = SDL_FALSE;
   707 
   708             ++fmt;
   709             if ( *fmt == '%' ) {
   710                 if ( *text == '%' ) {
   711                     ++text;
   712                     ++fmt;
   713                     continue;
   714                 }
   715                 break;
   716             }
   717             if ( *fmt == '*' ) {
   718                 suppress = SDL_TRUE;
   719                 ++fmt;
   720             }
   721             fmt += SDL_ScanLong(fmt, 10, &count);
   722 
   723             if ( *fmt == 'c' ) {
   724                 if ( ! count ) {
   725                     count = 1;
   726                 }
   727                 if ( suppress ) {
   728                     while ( count-- ) {
   729                         ++text;
   730                     }
   731                 } else {
   732                     char *valuep = va_arg(ap, char*);
   733                     while ( count-- ) {
   734                         *valuep++ = *text++;
   735                     }
   736                     ++retval;
   737                 }
   738                 continue;
   739             }
   740 
   741             while ( SDL_isspace(*text) ) {
   742                 ++text;
   743             }
   744 
   745             /* FIXME: implement more of the format specifiers */
   746             while (!done) {
   747                 switch(*fmt) {
   748                     case '*':
   749                         suppress = SDL_TRUE;
   750                         break;
   751                     case 'h':
   752                         if ( inttype > DO_SHORT ) {
   753                             ++inttype;
   754                         }
   755                         break;
   756                     case 'l':
   757                         if ( inttype < DO_LONGLONG ) {
   758                             ++inttype;
   759                         }
   760                         break;
   761                     case 'I':
   762                         if ( SDL_strncmp(fmt, "I64", 3) == 0 ) {
   763                             fmt += 2;
   764                             inttype = DO_LONGLONG;
   765                         }
   766                         break;
   767                     case 'i':
   768                         {
   769                             int index = 0;
   770                             if ( text[index] == '-' ) {
   771                                 ++index;
   772                             }
   773                             if ( text[index] == '0' ) {
   774                                 if ( SDL_tolower(text[index+1]) == 'x' ) {
   775                                     radix = 16;
   776                                 } else {
   777                                     radix = 8;
   778                                 }
   779                             }
   780                         }
   781                         /* Fall through to %d handling */
   782                     case 'd':
   783 #ifdef SDL_HAS_64BIT_TYPE
   784                         if ( inttype == DO_LONGLONG ) {
   785                             Sint64 value;
   786                             text += SDL_ScanLongLong(text, radix, &value);
   787                             if ( ! suppress ) {
   788                                 Sint64 *valuep = va_arg(ap, Sint64*);
   789                                 *valuep = value;
   790                                 ++retval;
   791                             }
   792                         }
   793                         else
   794 #endif /* SDL_HAS_64BIT_TYPE */
   795                         {
   796                             long value;
   797                             text += SDL_ScanLong(text, radix, &value);
   798                             if ( ! suppress ) {
   799                                 switch (inttype) {
   800                                     case DO_SHORT:
   801                                         { short* valuep = va_arg(ap, short*);
   802                                             *valuep = (short)value;
   803                                         }
   804                                         break;
   805                                     case DO_INT:
   806                                         { int* valuep = va_arg(ap, int*);
   807                                             *valuep = (int)value;
   808                                         }
   809                                         break;
   810                                     case DO_LONG:
   811                                         { long* valuep = va_arg(ap, long*);
   812                                             *valuep = value;
   813                                         }
   814                                         break;
   815                                     case DO_LONGLONG:
   816                                         /* Handled above */
   817                                         break;
   818                                 }
   819                                 ++retval;
   820                             }
   821                         }
   822                         done = SDL_TRUE;
   823                         break;
   824                     case 'o':
   825                         if ( radix == 10 ) {
   826                             radix = 8;
   827                         }
   828                         /* Fall through to unsigned handling */
   829                     case 'x':
   830                     case 'X':
   831                         if ( radix == 10 ) {
   832                             radix = 16;
   833                         }
   834                         /* Fall through to unsigned handling */
   835                     case 'u':
   836 #ifdef SDL_HAS_64BIT_TYPE
   837                         if ( inttype == DO_LONGLONG ) {
   838                             Uint64 value;
   839                             text += SDL_ScanUnsignedLongLong(text, radix, &value);
   840                             if ( ! suppress ) {
   841                                 Uint64 *valuep = va_arg(ap, Uint64*);
   842                                 *valuep = value;
   843                                 ++retval;
   844                             }
   845                         }
   846                         else
   847 #endif /* SDL_HAS_64BIT_TYPE */
   848                         {
   849                             unsigned long value;
   850                             text += SDL_ScanUnsignedLong(text, radix, &value);
   851                             if ( ! suppress ) {
   852                                 switch (inttype) {
   853                                     case DO_SHORT:
   854                                         { short* valuep = va_arg(ap, short*);
   855                                             *valuep = (short)value;
   856                                         }
   857                                         break;
   858                                     case DO_INT:
   859                                         { int* valuep = va_arg(ap, int*);
   860                                             *valuep = (int)value;
   861                                         }
   862                                         break;
   863                                     case DO_LONG:
   864                                         { long* valuep = va_arg(ap, long*);
   865                                             *valuep = value;
   866                                         }
   867                                         break;
   868                                     case DO_LONGLONG:
   869                                         /* Handled above */
   870                                         break;
   871                                 }
   872                                 ++retval;
   873                             }
   874                         }
   875                         done = SDL_TRUE;
   876                         break;
   877                     case 'p':
   878                         {
   879                             uintptr_t value;
   880                             text += SDL_ScanUintPtrT(text, 16, &value);
   881                             if ( ! suppress ) {
   882                                 void** valuep = va_arg(ap, void**);
   883                                 *valuep = (void*)value;
   884                                 ++retval;
   885                             }
   886                         }
   887                         done = SDL_TRUE;
   888                         break;
   889                     case 'f':
   890                         {
   891                             double value;
   892                             text += SDL_ScanFloat(text, &value);
   893                             if ( ! suppress ) {
   894                                 float* valuep = va_arg(ap, float*);
   895                                 *valuep = (float)value;
   896                                 ++retval;
   897                             }
   898                         }
   899                         done = SDL_TRUE;
   900                         break;
   901                     case 's':
   902                         if ( suppress ) {
   903                             while ( !SDL_isspace(*text) ) {
   904                                 ++text;
   905                                 if ( count ) {
   906                                     if ( --count == 0 ) {
   907                                         break;
   908                                     }
   909                                 }
   910                             }
   911                         } else {
   912                             char *valuep = va_arg(ap, char*);
   913                             while ( !SDL_isspace(*text) ) {
   914                                 *valuep++ = *text++;
   915                                 if ( count ) {
   916                                     if ( --count == 0 ) {
   917                                         break;
   918                                     }
   919                                 }
   920                             }
   921                             *valuep = '\0';
   922                             ++retval;
   923                         }
   924                         done = SDL_TRUE;
   925                         break;
   926                     default:
   927                         done = SDL_TRUE;
   928                         break;
   929                 }
   930                 ++fmt;
   931             }
   932             continue;
   933         }
   934         if ( *text == *fmt ) {
   935             ++text;
   936             ++fmt;
   937             continue;
   938         }
   939         /* Text didn't match format specifier */
   940         break;
   941     }
   942     va_end(ap);
   943 
   944     return retval;
   945 }
   946 #endif
   947 
   948 #ifndef HAVE_SNPRINTF
   949 int SDL_snprintf(char *text, size_t maxlen, const char *fmt, ...)
   950 {
   951     va_list ap;
   952     int retval;
   953 
   954     va_start(ap, fmt);
   955     retval = SDL_vsnprintf(text, maxlen, fmt, ap);
   956     va_end(ap);
   957 
   958     return retval;
   959 }
   960 #endif
   961 
   962 #ifndef HAVE_VSNPRINTF
   963 static size_t SDL_PrintLong(char *text, long value, int radix, size_t maxlen)
   964 {
   965     char num[130];
   966     size_t size;
   967 
   968     SDL_ltoa(value, num, radix);
   969     size = SDL_strlen(num);
   970     if ( size > maxlen ) {
   971         size = maxlen;
   972     }
   973     SDL_strlcpy(text, num, size);
   974 
   975     return size;
   976 }
   977 static size_t SDL_PrintUnsignedLong(char *text, unsigned long value, int radix, size_t maxlen)
   978 {
   979     char num[130];
   980     size_t size;
   981 
   982     SDL_ultoa(value, num, radix);
   983     size = SDL_strlen(num);
   984     if ( size > maxlen ) {
   985         size = maxlen;
   986     }
   987     SDL_strlcpy(text, num, size);
   988 
   989     return size;
   990 }
   991 #ifdef SDL_HAS_64BIT_TYPE
   992 static size_t SDL_PrintLongLong(char *text, Sint64 value, int radix, size_t maxlen)
   993 {
   994     char num[130];
   995     size_t size;
   996 
   997     SDL_lltoa(value, num, radix);
   998     size = SDL_strlen(num);
   999     if ( size > maxlen ) {
  1000         size = maxlen;
  1001     }
  1002     SDL_strlcpy(text, num, size);
  1003 
  1004     return size;
  1005 }
  1006 static size_t SDL_PrintUnsignedLongLong(char *text, Uint64 value, int radix, size_t maxlen)
  1007 {
  1008     char num[130];
  1009     size_t size;
  1010 
  1011     SDL_ulltoa(value, num, radix);
  1012     size = SDL_strlen(num);
  1013     if ( size > maxlen ) {
  1014         size = maxlen;
  1015     }
  1016     SDL_strlcpy(text, num, size);
  1017 
  1018     return size;
  1019 }
  1020 #endif /* SDL_HAS_64BIT_TYPE */
  1021 static size_t SDL_PrintFloat(char *text, double arg, size_t maxlen)
  1022 {
  1023     char *textstart = text;
  1024     if ( arg ) {
  1025         /* This isn't especially accurate, but hey, it's easy. :) */
  1026         const double precision = 0.00000001;
  1027         size_t len;
  1028         unsigned long value;
  1029 
  1030         if ( arg < 0 ) {
  1031             *text++ = '-';
  1032             --maxlen;
  1033             arg = -arg;
  1034         }
  1035         value = (unsigned long)arg;
  1036         len = SDL_PrintUnsignedLong(text, value, 10, maxlen);
  1037         text += len;
  1038         maxlen -= len;
  1039         arg -= value;
  1040         if ( arg > precision && maxlen ) {
  1041             int mult = 10;
  1042             *text++ = '.';
  1043             while ( (arg > precision) && maxlen ) {
  1044                 value = (unsigned long)(arg * mult);
  1045                 len = SDL_PrintUnsignedLong(text, value, 10, maxlen);
  1046                 text += len;
  1047                 maxlen -= len;
  1048                 arg -= (double)value / mult;
  1049                 mult *= 10;
  1050             }
  1051         }
  1052     } else {
  1053         *text++ = '0';
  1054     }
  1055     return (text - textstart);
  1056 }
  1057 static size_t SDL_PrintString(char *text, const char *string, size_t maxlen)
  1058 {
  1059     char *textstart = text;
  1060     while ( *string && maxlen-- ) {
  1061         *text++ = *string++;
  1062     }
  1063     return (text - textstart);
  1064 }
  1065 int SDL_vsnprintf(char *text, size_t maxlen, const char *fmt, va_list ap)
  1066 {
  1067     char *textstart = text;
  1068     if ( maxlen <= 0 ) {
  1069         return 0;
  1070     }
  1071     --maxlen; /* For the trailing '\0' */
  1072     while ( *fmt && maxlen ) {
  1073         if ( *fmt == '%' ) {
  1074             SDL_bool done = SDL_FALSE;
  1075             size_t len = 0;
  1076             SDL_bool do_lowercase = SDL_FALSE;
  1077             int radix = 10;
  1078             enum {
  1079                 DO_INT,
  1080                 DO_LONG,
  1081                 DO_LONGLONG
  1082             } inttype = DO_INT;
  1083 
  1084             ++fmt;
  1085             /* FIXME: implement more of the format specifiers */
  1086             while (!done) {
  1087                 switch(*fmt) {
  1088                     case '%':
  1089                         *text = '%';
  1090                         len = 1;
  1091                         done = SDL_TRUE;
  1092                         break;
  1093                     case 'c':
  1094                         /* char is promoted to int when passed through (...) */
  1095                         *text = (char)va_arg(ap, int);
  1096                         len = 1;
  1097                         done = SDL_TRUE;
  1098                         break;
  1099                     case 'h':
  1100                         /* short is promoted to int when passed through (...) */
  1101                         break;
  1102                     case 'l':
  1103                         if ( inttype < DO_LONGLONG ) {
  1104                             ++inttype;
  1105                         }
  1106                         break;
  1107                     case 'I':
  1108                         if ( SDL_strncmp(fmt, "I64", 3) == 0 ) {
  1109                             fmt += 2;
  1110                             inttype = DO_LONGLONG;
  1111                         }
  1112                         break;
  1113                     case 'i':
  1114                     case 'd':
  1115                         switch (inttype) {
  1116                             case DO_INT:
  1117                                 len = SDL_PrintLong(text, (long)va_arg(ap, int), radix, maxlen);
  1118                                 break;
  1119                             case DO_LONG:
  1120                                 len = SDL_PrintLong(text, va_arg(ap, long), radix, maxlen);
  1121                                 break;
  1122                             case DO_LONGLONG:
  1123 #ifdef SDL_HAS_64BIT_TYPE
  1124                                 len = SDL_PrintLongLong(text, va_arg(ap, Sint64), radix, maxlen);
  1125 #else
  1126                                 len = SDL_PrintLong(text, va_arg(ap, long), radix, maxlen);
  1127 #endif
  1128                                 break;
  1129                         }
  1130                         done = SDL_TRUE;
  1131                         break;
  1132                     case 'p':
  1133                     case 'x':
  1134                         do_lowercase = SDL_TRUE;
  1135                         /* Fall through to 'X' handling */
  1136                     case 'X':
  1137                         if ( radix == 10 ) {
  1138                             radix = 16;
  1139                         }
  1140                         if ( *fmt == 'p' ) {
  1141                             inttype = DO_LONG;
  1142                         }
  1143                         /* Fall through to unsigned handling */
  1144                     case 'o':
  1145                         if ( radix == 10 ) {
  1146                             radix = 8;
  1147                         }
  1148                         /* Fall through to unsigned handling */
  1149                     case 'u':
  1150                         switch (inttype) {
  1151                             case DO_INT:
  1152                                 len = SDL_PrintUnsignedLong(text, (unsigned long)va_arg(ap, unsigned int), radix, maxlen);
  1153                                 break;
  1154                             case DO_LONG:
  1155                                 len = SDL_PrintUnsignedLong(text, va_arg(ap, unsigned long), radix, maxlen);
  1156                                 break;
  1157                             case DO_LONGLONG:
  1158 #ifdef SDL_HAS_64BIT_TYPE
  1159                                 len = SDL_PrintUnsignedLongLong(text, va_arg(ap, Uint64), radix, maxlen);
  1160 #else
  1161                                 len = SDL_PrintUnsignedLong(text, va_arg(ap, unsigned long), radix, maxlen);
  1162 #endif
  1163                                 break;
  1164                         }
  1165                         if ( do_lowercase ) {
  1166                             SDL_strlwr(text);
  1167                         }
  1168                         done = SDL_TRUE;
  1169                         break;
  1170                     case 'f':
  1171                         len = SDL_PrintFloat(text, va_arg(ap, double), maxlen);
  1172                         done = SDL_TRUE;
  1173                         break;
  1174                     case 's':
  1175                         len = SDL_PrintString(text, va_arg(ap, char*), maxlen);
  1176                         done = SDL_TRUE;
  1177                         break;
  1178                     default:
  1179                         done = SDL_TRUE;
  1180                         break;
  1181                 }
  1182                 ++fmt;
  1183             }
  1184             text += len;
  1185             maxlen -= len;
  1186         } else {
  1187             *text++ = *fmt++;
  1188             --maxlen;
  1189         }
  1190     }
  1191     *text = '\0';
  1192 
  1193     return (text - textstart);
  1194 }
  1195 #endif