src/stdlib/SDL_string.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 21 Sep 2009 08:58:51 +0000
branchSDL-1.2
changeset 4214 4250beeb5ad1
parent 4159 a1b03ba2fcd0
child 6137 4720145f848b
permissions -rw-r--r--
Oh yeah, we have GLX support too.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2009 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((unsigned char) *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((unsigned char) *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((unsigned char) *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((unsigned char) *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((unsigned char) *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((unsigned char) *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-1;
   293     dstp += len-1;
   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((unsigned char) *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((unsigned char) *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     if ( !base ) {
   515         if ( (SDL_strlen(string) > 2) && (SDL_strncmp(string, "0x", 2) == 0) ) {
   516             base = 16;
   517         } else {
   518             base = 10;
   519         }
   520     }
   521 
   522     len = SDL_ScanLong(string, base, &value);
   523     if ( endp ) {
   524         *endp = (char *)string + len;
   525     }
   526     return value;
   527 }
   528 #endif
   529 
   530 #ifndef HAVE_STRTOUL
   531 unsigned long SDL_strtoul(const char *string, char **endp, int base)
   532 {
   533     size_t len;
   534     unsigned long value;
   535 
   536     if ( !base ) {
   537         if ( (SDL_strlen(string) > 2) && (SDL_strncmp(string, "0x", 2) == 0) ) {
   538             base = 16;
   539         } else {
   540             base = 10;
   541         }
   542     }
   543 
   544     len = SDL_ScanUnsignedLong(string, base, &value);
   545     if ( endp ) {
   546         *endp = (char *)string + len;
   547     }
   548     return value;
   549 }
   550 #endif
   551 
   552 #ifdef SDL_HAS_64BIT_TYPE
   553 
   554 #ifndef HAVE__I64TOA
   555 char *SDL_lltoa(Sint64 value, char *string, int radix)
   556 {
   557     char *bufp = string;
   558 
   559     if ( value < 0 ) {
   560         *bufp++ = '-';
   561         value = -value;
   562     }
   563     if ( value ) {
   564         while ( value > 0 ) {
   565             *bufp++ = ntoa_table[value % radix];
   566             value /= radix;
   567         }
   568     } else {
   569         *bufp++ = '0';
   570     }
   571     *bufp = '\0';
   572 
   573     /* The numbers went into the string backwards. :) */
   574     if ( *string == '-' ) {
   575         SDL_strrev(string+1);
   576     } else {
   577         SDL_strrev(string);
   578     }
   579 
   580     return string;
   581 }
   582 #endif
   583 
   584 #ifndef HAVE__UI64TOA
   585 char *SDL_ulltoa(Uint64 value, char *string, int radix)
   586 {
   587     char *bufp = string;
   588 
   589     if ( value ) {
   590         while ( value > 0 ) {
   591             *bufp++ = ntoa_table[value % radix];
   592             value /= radix;
   593         }
   594     } else {
   595         *bufp++ = '0';
   596     }
   597     *bufp = '\0';
   598 
   599     /* The numbers went into the string backwards. :) */
   600     SDL_strrev(string);
   601 
   602     return string;
   603 }
   604 #endif
   605 
   606 #ifndef HAVE_STRTOLL
   607 Sint64 SDL_strtoll(const char *string, char **endp, int base)
   608 {
   609     size_t len;
   610     Sint64 value;
   611 
   612     if ( !base ) {
   613         if ( (SDL_strlen(string) > 2) && (SDL_strncmp(string, "0x", 2) == 0) ) {
   614             base = 16;
   615         } else {
   616             base = 10;
   617         }
   618     }
   619 
   620     len = SDL_ScanLongLong(string, base, &value);
   621     if ( endp ) {
   622         *endp = (char *)string + len;
   623     }
   624     return value;
   625 }
   626 #endif
   627 
   628 #ifndef HAVE_STRTOULL
   629 Uint64 SDL_strtoull(const char *string, char **endp, int base)
   630 {
   631     size_t len;
   632     Uint64 value;
   633 
   634     if ( !base ) {
   635         if ( (SDL_strlen(string) > 2) && (SDL_strncmp(string, "0x", 2) == 0) ) {
   636             base = 16;
   637         } else {
   638             base = 10;
   639         }
   640     }
   641 
   642     len = SDL_ScanUnsignedLongLong(string, base, &value);
   643     if ( endp ) {
   644         *endp = (char *)string + len;
   645     }
   646     return value;
   647 }
   648 #endif
   649 
   650 #endif /* SDL_HAS_64BIT_TYPE */
   651 
   652 #ifndef HAVE_STRTOD
   653 double SDL_strtod(const char *string, char **endp)
   654 {
   655     size_t len;
   656     double value;
   657 
   658     len = SDL_ScanFloat(string, &value);
   659     if ( endp ) {
   660         *endp = (char *)string + len;
   661     }
   662     return value;
   663 }
   664 #endif
   665 
   666 #ifndef HAVE_STRCMP
   667 int SDL_strcmp(const char *str1, const char *str2)
   668 {
   669     while (*str1 && *str2) {
   670         if ( *str1 != *str2 )
   671             break;
   672         ++str1;
   673         ++str2;
   674     }
   675     return (int)((unsigned char)*str1 - (unsigned char)*str2);
   676 }
   677 #endif
   678 
   679 #ifndef HAVE_STRNCMP
   680 int SDL_strncmp(const char *str1, const char *str2, size_t maxlen)
   681 {
   682     while ( *str1 && *str2 && maxlen ) {
   683         if ( *str1 != *str2 )
   684             break;
   685         ++str1;
   686         ++str2;
   687         --maxlen;
   688     }
   689     if ( ! maxlen ) {
   690         return 0;
   691     }
   692     return (int)((unsigned char)*str1 - (unsigned char)*str2);
   693 }
   694 #endif
   695 
   696 #if !defined(HAVE_STRCASECMP) && !defined(HAVE__STRICMP)
   697 int SDL_strcasecmp(const char *str1, const char *str2)
   698 {
   699     char a = 0;
   700     char b = 0;
   701     while ( *str1 && *str2 ) {
   702         a = SDL_tolower((unsigned char) *str1);
   703         b = SDL_tolower((unsigned char) *str2);
   704         if ( a != b )
   705             break;
   706         ++str1;
   707         ++str2;
   708     }
   709     return (int)((unsigned char)a - (unsigned char)b);
   710 }
   711 #endif
   712 
   713 #if !defined(HAVE_STRNCASECMP) && !defined(HAVE__STRNICMP)
   714 int SDL_strncasecmp(const char *str1, const char *str2, size_t maxlen)
   715 {
   716     char a = 0;
   717     char b = 0;
   718     while ( *str1 && *str2 && maxlen ) {
   719         a = SDL_tolower((unsigned char) *str1);
   720         b = SDL_tolower((unsigned char) *str2);
   721         if ( a != b )
   722             break;
   723         ++str1;
   724         ++str2;
   725         --maxlen;
   726     }
   727     return (int)((unsigned char)a - (unsigned char)b);
   728 }
   729 #endif
   730 
   731 #ifndef HAVE_SSCANF
   732 int SDL_sscanf(const char *text, const char *fmt, ...)
   733 {
   734     va_list ap;
   735     int retval = 0;
   736 
   737     va_start(ap, fmt);
   738     while ( *fmt ) {
   739         if ( *fmt == ' ' ) {
   740             while ( SDL_isspace((unsigned char) *text) ) {
   741                 ++text;
   742             }
   743             ++fmt;
   744             continue;
   745         }
   746         if ( *fmt == '%' ) {
   747             SDL_bool done = SDL_FALSE;
   748             long count = 0;
   749             int radix = 10;
   750             enum {
   751                 DO_SHORT,
   752                 DO_INT,
   753                 DO_LONG,
   754                 DO_LONGLONG
   755             } inttype = DO_INT;
   756             SDL_bool suppress = SDL_FALSE;
   757 
   758             ++fmt;
   759             if ( *fmt == '%' ) {
   760                 if ( *text == '%' ) {
   761                     ++text;
   762                     ++fmt;
   763                     continue;
   764                 }
   765                 break;
   766             }
   767             if ( *fmt == '*' ) {
   768                 suppress = SDL_TRUE;
   769                 ++fmt;
   770             }
   771             fmt += SDL_ScanLong(fmt, 10, &count);
   772 
   773             if ( *fmt == 'c' ) {
   774                 if ( ! count ) {
   775                     count = 1;
   776                 }
   777                 if ( suppress ) {
   778                     while ( count-- ) {
   779                         ++text;
   780                     }
   781                 } else {
   782                     char *valuep = va_arg(ap, char*);
   783                     while ( count-- ) {
   784                         *valuep++ = *text++;
   785                     }
   786                     ++retval;
   787                 }
   788                 continue;
   789             }
   790 
   791             while ( SDL_isspace((unsigned char) *text) ) {
   792                 ++text;
   793             }
   794 
   795             /* FIXME: implement more of the format specifiers */
   796             while (!done) {
   797                 switch(*fmt) {
   798                     case '*':
   799                         suppress = SDL_TRUE;
   800                         break;
   801                     case 'h':
   802                         if ( inttype > DO_SHORT ) {
   803                             ++inttype;
   804                         }
   805                         break;
   806                     case 'l':
   807                         if ( inttype < DO_LONGLONG ) {
   808                             ++inttype;
   809                         }
   810                         break;
   811                     case 'I':
   812                         if ( SDL_strncmp(fmt, "I64", 3) == 0 ) {
   813                             fmt += 2;
   814                             inttype = DO_LONGLONG;
   815                         }
   816                         break;
   817                     case 'i':
   818                         {
   819                             int index = 0;
   820                             if ( text[index] == '-' ) {
   821                                 ++index;
   822                             }
   823                             if ( text[index] == '0' ) {
   824                                 if ( SDL_tolower((unsigned char) text[index+1]) == 'x' ) {
   825                                     radix = 16;
   826                                 } else {
   827                                     radix = 8;
   828                                 }
   829                             }
   830                         }
   831                         /* Fall through to %d handling */
   832                     case 'd':
   833 #ifdef SDL_HAS_64BIT_TYPE
   834                         if ( inttype == DO_LONGLONG ) {
   835                             Sint64 value;
   836                             text += SDL_ScanLongLong(text, radix, &value);
   837                             if ( ! suppress ) {
   838                                 Sint64 *valuep = va_arg(ap, Sint64*);
   839                                 *valuep = value;
   840                                 ++retval;
   841                             }
   842                         }
   843                         else
   844 #endif /* SDL_HAS_64BIT_TYPE */
   845                         {
   846                             long value;
   847                             text += SDL_ScanLong(text, radix, &value);
   848                             if ( ! suppress ) {
   849                                 switch (inttype) {
   850                                     case DO_SHORT:
   851                                         { short* valuep = va_arg(ap, short*);
   852                                             *valuep = (short)value;
   853                                         }
   854                                         break;
   855                                     case DO_INT:
   856                                         { int* valuep = va_arg(ap, int*);
   857                                             *valuep = (int)value;
   858                                         }
   859                                         break;
   860                                     case DO_LONG:
   861                                         { long* valuep = va_arg(ap, long*);
   862                                             *valuep = value;
   863                                         }
   864                                         break;
   865                                     case DO_LONGLONG:
   866                                         /* Handled above */
   867                                         break;
   868                                 }
   869                                 ++retval;
   870                             }
   871                         }
   872                         done = SDL_TRUE;
   873                         break;
   874                     case 'o':
   875                         if ( radix == 10 ) {
   876                             radix = 8;
   877                         }
   878                         /* Fall through to unsigned handling */
   879                     case 'x':
   880                     case 'X':
   881                         if ( radix == 10 ) {
   882                             radix = 16;
   883                         }
   884                         /* Fall through to unsigned handling */
   885                     case 'u':
   886 #ifdef SDL_HAS_64BIT_TYPE
   887                         if ( inttype == DO_LONGLONG ) {
   888                             Uint64 value;
   889                             text += SDL_ScanUnsignedLongLong(text, radix, &value);
   890                             if ( ! suppress ) {
   891                                 Uint64 *valuep = va_arg(ap, Uint64*);
   892                                 *valuep = value;
   893                                 ++retval;
   894                             }
   895                         }
   896                         else
   897 #endif /* SDL_HAS_64BIT_TYPE */
   898                         {
   899                             unsigned long value;
   900                             text += SDL_ScanUnsignedLong(text, radix, &value);
   901                             if ( ! suppress ) {
   902                                 switch (inttype) {
   903                                     case DO_SHORT:
   904                                         { short* valuep = va_arg(ap, short*);
   905                                             *valuep = (short)value;
   906                                         }
   907                                         break;
   908                                     case DO_INT:
   909                                         { int* valuep = va_arg(ap, int*);
   910                                             *valuep = (int)value;
   911                                         }
   912                                         break;
   913                                     case DO_LONG:
   914                                         { long* valuep = va_arg(ap, long*);
   915                                             *valuep = value;
   916                                         }
   917                                         break;
   918                                     case DO_LONGLONG:
   919                                         /* Handled above */
   920                                         break;
   921                                 }
   922                                 ++retval;
   923                             }
   924                         }
   925                         done = SDL_TRUE;
   926                         break;
   927                     case 'p':
   928                         {
   929                             uintptr_t value;
   930                             text += SDL_ScanUintPtrT(text, 16, &value);
   931                             if ( ! suppress ) {
   932                                 void** valuep = va_arg(ap, void**);
   933                                 *valuep = (void*)value;
   934                                 ++retval;
   935                             }
   936                         }
   937                         done = SDL_TRUE;
   938                         break;
   939                     case 'f':
   940                         {
   941                             double value;
   942                             text += SDL_ScanFloat(text, &value);
   943                             if ( ! suppress ) {
   944                                 float* valuep = va_arg(ap, float*);
   945                                 *valuep = (float)value;
   946                                 ++retval;
   947                             }
   948                         }
   949                         done = SDL_TRUE;
   950                         break;
   951                     case 's':
   952                         if ( suppress ) {
   953                             while ( !SDL_isspace((unsigned char) *text) ) {
   954                                 ++text;
   955                                 if ( count ) {
   956                                     if ( --count == 0 ) {
   957                                         break;
   958                                     }
   959                                 }
   960                             }
   961                         } else {
   962                             char *valuep = va_arg(ap, char*);
   963                             while ( !SDL_isspace((unsigned char) *text) ) {
   964                                 *valuep++ = *text++;
   965                                 if ( count ) {
   966                                     if ( --count == 0 ) {
   967                                         break;
   968                                     }
   969                                 }
   970                             }
   971                             *valuep = '\0';
   972                             ++retval;
   973                         }
   974                         done = SDL_TRUE;
   975                         break;
   976                     default:
   977                         done = SDL_TRUE;
   978                         break;
   979                 }
   980                 ++fmt;
   981             }
   982             continue;
   983         }
   984         if ( *text == *fmt ) {
   985             ++text;
   986             ++fmt;
   987             continue;
   988         }
   989         /* Text didn't match format specifier */
   990         break;
   991     }
   992     va_end(ap);
   993 
   994     return retval;
   995 }
   996 #endif
   997 
   998 #ifndef HAVE_SNPRINTF
   999 int SDL_snprintf(char *text, size_t maxlen, const char *fmt, ...)
  1000 {
  1001     va_list ap;
  1002     int retval;
  1003 
  1004     va_start(ap, fmt);
  1005     retval = SDL_vsnprintf(text, maxlen, fmt, ap);
  1006     va_end(ap);
  1007 
  1008     return retval;
  1009 }
  1010 #endif
  1011 
  1012 #ifndef HAVE_VSNPRINTF
  1013 static size_t SDL_PrintLong(char *text, long value, int radix, size_t maxlen)
  1014 {
  1015     char num[130];
  1016     size_t size;
  1017 
  1018     SDL_ltoa(value, num, radix);
  1019     size = SDL_strlen(num);
  1020     if ( size >= maxlen ) {
  1021         size = maxlen-1;
  1022     }
  1023     SDL_strlcpy(text, num, size+1);
  1024 
  1025     return size;
  1026 }
  1027 static size_t SDL_PrintUnsignedLong(char *text, unsigned long value, int radix, size_t maxlen)
  1028 {
  1029     char num[130];
  1030     size_t size;
  1031 
  1032     SDL_ultoa(value, num, radix);
  1033     size = SDL_strlen(num);
  1034     if ( size >= maxlen ) {
  1035         size = maxlen-1;
  1036     }
  1037     SDL_strlcpy(text, num, size+1);
  1038 
  1039     return size;
  1040 }
  1041 #ifdef SDL_HAS_64BIT_TYPE
  1042 static size_t SDL_PrintLongLong(char *text, Sint64 value, int radix, size_t maxlen)
  1043 {
  1044     char num[130];
  1045     size_t size;
  1046 
  1047     SDL_lltoa(value, num, radix);
  1048     size = SDL_strlen(num);
  1049     if ( size >= maxlen ) {
  1050         size = maxlen-1;
  1051     }
  1052     SDL_strlcpy(text, num, size+1);
  1053 
  1054     return size;
  1055 }
  1056 static size_t SDL_PrintUnsignedLongLong(char *text, Uint64 value, int radix, size_t maxlen)
  1057 {
  1058     char num[130];
  1059     size_t size;
  1060 
  1061     SDL_ulltoa(value, num, radix);
  1062     size = SDL_strlen(num);
  1063     if ( size >= maxlen ) {
  1064         size = maxlen-1;
  1065     }
  1066     SDL_strlcpy(text, num, size+1);
  1067 
  1068     return size;
  1069 }
  1070 #endif /* SDL_HAS_64BIT_TYPE */
  1071 static size_t SDL_PrintFloat(char *text, double arg, size_t maxlen)
  1072 {
  1073     char *textstart = text;
  1074     if ( arg ) {
  1075         /* This isn't especially accurate, but hey, it's easy. :) */
  1076         const double precision = 0.00000001;
  1077         size_t len;
  1078         unsigned long value;
  1079 
  1080         if ( arg < 0 ) {
  1081             *text++ = '-';
  1082             --maxlen;
  1083             arg = -arg;
  1084         }
  1085         value = (unsigned long)arg;
  1086         len = SDL_PrintUnsignedLong(text, value, 10, maxlen);
  1087         text += len;
  1088         maxlen -= len;
  1089         arg -= value;
  1090         if ( arg > precision && maxlen ) {
  1091             int mult = 10;
  1092             *text++ = '.';
  1093             while ( (arg > precision) && maxlen ) {
  1094                 value = (unsigned long)(arg * mult);
  1095                 len = SDL_PrintUnsignedLong(text, value, 10, maxlen);
  1096                 text += len;
  1097                 maxlen -= len;
  1098                 arg -= (double)value / mult;
  1099                 mult *= 10;
  1100             }
  1101         }
  1102     } else {
  1103         *text++ = '0';
  1104     }
  1105     return (text - textstart);
  1106 }
  1107 static size_t SDL_PrintString(char *text, const char *string, size_t maxlen)
  1108 {
  1109     char *textstart = text;
  1110     while ( *string && maxlen-- ) {
  1111         *text++ = *string++;
  1112     }
  1113     return (text - textstart);
  1114 }
  1115 int SDL_vsnprintf(char *text, size_t maxlen, const char *fmt, va_list ap)
  1116 {
  1117     char *textstart = text;
  1118     if ( maxlen <= 0 ) {
  1119         return 0;
  1120     }
  1121     --maxlen; /* For the trailing '\0' */
  1122     while ( *fmt && maxlen ) {
  1123         if ( *fmt == '%' ) {
  1124             SDL_bool done = SDL_FALSE;
  1125             size_t len = 0;
  1126             SDL_bool do_lowercase = SDL_FALSE;
  1127             int radix = 10;
  1128             enum {
  1129                 DO_INT,
  1130                 DO_LONG,
  1131                 DO_LONGLONG
  1132             } inttype = DO_INT;
  1133 
  1134             ++fmt;
  1135             /* FIXME: implement more of the format specifiers */
  1136             while ( *fmt == '.' || (*fmt >= '0' && *fmt <= '9') ) {
  1137                 ++fmt;
  1138             }
  1139             while (!done) {
  1140                 switch(*fmt) {
  1141                     case '%':
  1142                         *text = '%';
  1143                         len = 1;
  1144                         done = SDL_TRUE;
  1145                         break;
  1146                     case 'c':
  1147                         /* char is promoted to int when passed through (...) */
  1148                         *text = (char)va_arg(ap, int);
  1149                         len = 1;
  1150                         done = SDL_TRUE;
  1151                         break;
  1152                     case 'h':
  1153                         /* short is promoted to int when passed through (...) */
  1154                         break;
  1155                     case 'l':
  1156                         if ( inttype < DO_LONGLONG ) {
  1157                             ++inttype;
  1158                         }
  1159                         break;
  1160                     case 'I':
  1161                         if ( SDL_strncmp(fmt, "I64", 3) == 0 ) {
  1162                             fmt += 2;
  1163                             inttype = DO_LONGLONG;
  1164                         }
  1165                         break;
  1166                     case 'i':
  1167                     case 'd':
  1168                         switch (inttype) {
  1169                             case DO_INT:
  1170                                 len = SDL_PrintLong(text, (long)va_arg(ap, int), radix, maxlen);
  1171                                 break;
  1172                             case DO_LONG:
  1173                                 len = SDL_PrintLong(text, va_arg(ap, long), radix, maxlen);
  1174                                 break;
  1175                             case DO_LONGLONG:
  1176 #ifdef SDL_HAS_64BIT_TYPE
  1177                                 len = SDL_PrintLongLong(text, va_arg(ap, Sint64), radix, maxlen);
  1178 #else
  1179                                 len = SDL_PrintLong(text, va_arg(ap, long), radix, maxlen);
  1180 #endif
  1181                                 break;
  1182                         }
  1183                         done = SDL_TRUE;
  1184                         break;
  1185                     case 'p':
  1186                     case 'x':
  1187                         do_lowercase = SDL_TRUE;
  1188                         /* Fall through to 'X' handling */
  1189                     case 'X':
  1190                         if ( radix == 10 ) {
  1191                             radix = 16;
  1192                         }
  1193                         if ( *fmt == 'p' ) {
  1194                             inttype = DO_LONG;
  1195                         }
  1196                         /* Fall through to unsigned handling */
  1197                     case 'o':
  1198                         if ( radix == 10 ) {
  1199                             radix = 8;
  1200                         }
  1201                         /* Fall through to unsigned handling */
  1202                     case 'u':
  1203                         switch (inttype) {
  1204                             case DO_INT:
  1205                                 len = SDL_PrintUnsignedLong(text, (unsigned long)va_arg(ap, unsigned int), radix, maxlen);
  1206                                 break;
  1207                             case DO_LONG:
  1208                                 len = SDL_PrintUnsignedLong(text, va_arg(ap, unsigned long), radix, maxlen);
  1209                                 break;
  1210                             case DO_LONGLONG:
  1211 #ifdef SDL_HAS_64BIT_TYPE
  1212                                 len = SDL_PrintUnsignedLongLong(text, va_arg(ap, Uint64), radix, maxlen);
  1213 #else
  1214                                 len = SDL_PrintUnsignedLong(text, va_arg(ap, unsigned long), radix, maxlen);
  1215 #endif
  1216                                 break;
  1217                         }
  1218                         if ( do_lowercase ) {
  1219                             SDL_strlwr(text);
  1220                         }
  1221                         done = SDL_TRUE;
  1222                         break;
  1223                     case 'f':
  1224                         len = SDL_PrintFloat(text, va_arg(ap, double), maxlen);
  1225                         done = SDL_TRUE;
  1226                         break;
  1227                     case 's':
  1228                         len = SDL_PrintString(text, va_arg(ap, char*), maxlen);
  1229                         done = SDL_TRUE;
  1230                         break;
  1231                     default:
  1232                         done = SDL_TRUE;
  1233                         break;
  1234                 }
  1235                 ++fmt;
  1236             }
  1237             text += len;
  1238             maxlen -= len;
  1239         } else {
  1240             *text++ = *fmt++;
  1241             --maxlen;
  1242         }
  1243     }
  1244     *text = '\0';
  1245 
  1246     return (text - textstart);
  1247 }
  1248 #endif