src/stdlib/SDL_string.c
author Sam Lantinga
Mon, 13 Mar 2006 02:12:39 +0000
changeset 1512 845b1619c8f6
parent 1510 720f8bb49d7d
child 1659 14717b52abc0
permissions -rw-r--r--
Added _strnicmp support
     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 #if !defined(HAVE_STRCASECMP) && !defined(HAVE__STRICMP)
   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 #if !defined(HAVE_STRNCASECMP) && !defined(HAVE__STRNICMP)
   682 int SDL_strncasecmp(const char *str1, const char *str2, size_t maxlen)
   683 {
   684     char a = 0;
   685     char b = 0;
   686     while ( *str1 && *str2 && maxlen ) {
   687         a = SDL_tolower(*str1);
   688         b = SDL_tolower(*str2);
   689         if ( a != b )
   690             break;
   691         ++str1;
   692         ++str2;
   693         --maxlen;
   694     }
   695     return (int)((unsigned char)a - (unsigned char)b);
   696 }
   697 #endif
   698 
   699 #ifndef HAVE_SSCANF
   700 int SDL_sscanf(const char *text, const char *fmt, ...)
   701 {
   702     va_list ap;
   703     int retval = 0;
   704 
   705     va_start(ap, fmt);
   706     while ( *fmt ) {
   707         if ( *fmt == ' ' ) {
   708             while ( SDL_isspace(*text) ) {
   709                 ++text;
   710             }
   711             ++fmt;
   712             continue;
   713         }
   714         if ( *fmt == '%' ) {
   715             SDL_bool done = SDL_FALSE;
   716             long count = 0;
   717             int radix = 10;
   718             enum {
   719                 DO_SHORT,
   720                 DO_INT,
   721                 DO_LONG,
   722                 DO_LONGLONG
   723             } inttype = DO_INT;
   724             SDL_bool suppress = SDL_FALSE;
   725 
   726             ++fmt;
   727             if ( *fmt == '%' ) {
   728                 if ( *text == '%' ) {
   729                     ++text;
   730                     ++fmt;
   731                     continue;
   732                 }
   733                 break;
   734             }
   735             if ( *fmt == '*' ) {
   736                 suppress = SDL_TRUE;
   737                 ++fmt;
   738             }
   739             fmt += SDL_ScanLong(fmt, 10, &count);
   740 
   741             if ( *fmt == 'c' ) {
   742                 if ( ! count ) {
   743                     count = 1;
   744                 }
   745                 if ( suppress ) {
   746                     while ( count-- ) {
   747                         ++text;
   748                     }
   749                 } else {
   750                     char *valuep = va_arg(ap, char*);
   751                     while ( count-- ) {
   752                         *valuep++ = *text++;
   753                     }
   754                     ++retval;
   755                 }
   756                 continue;
   757             }
   758 
   759             while ( SDL_isspace(*text) ) {
   760                 ++text;
   761             }
   762 
   763             /* FIXME: implement more of the format specifiers */
   764             while (!done) {
   765                 switch(*fmt) {
   766                     case '*':
   767                         suppress = SDL_TRUE;
   768                         break;
   769                     case 'h':
   770                         if ( inttype > DO_SHORT ) {
   771                             ++inttype;
   772                         }
   773                         break;
   774                     case 'l':
   775                         if ( inttype < DO_LONGLONG ) {
   776                             ++inttype;
   777                         }
   778                         break;
   779                     case 'I':
   780                         if ( SDL_strncmp(fmt, "I64", 3) == 0 ) {
   781                             fmt += 2;
   782                             inttype = DO_LONGLONG;
   783                         }
   784                         break;
   785                     case 'i':
   786                         {
   787                             int index = 0;
   788                             if ( text[index] == '-' ) {
   789                                 ++index;
   790                             }
   791                             if ( text[index] == '0' ) {
   792                                 if ( SDL_tolower(text[index+1]) == 'x' ) {
   793                                     radix = 16;
   794                                 } else {
   795                                     radix = 8;
   796                                 }
   797                             }
   798                         }
   799                         /* Fall through to %d handling */
   800                     case 'd':
   801 #ifdef SDL_HAS_64BIT_TYPE
   802                         if ( inttype == DO_LONGLONG ) {
   803                             Sint64 value;
   804                             text += SDL_ScanLongLong(text, radix, &value);
   805                             if ( ! suppress ) {
   806                                 Sint64 *valuep = va_arg(ap, Sint64*);
   807                                 *valuep = value;
   808                                 ++retval;
   809                             }
   810                         }
   811                         else
   812 #endif /* SDL_HAS_64BIT_TYPE */
   813                         {
   814                             long value;
   815                             text += SDL_ScanLong(text, radix, &value);
   816                             if ( ! suppress ) {
   817                                 switch (inttype) {
   818                                     case DO_SHORT:
   819                                         { short* valuep = va_arg(ap, short*);
   820                                             *valuep = (short)value;
   821                                         }
   822                                         break;
   823                                     case DO_INT:
   824                                         { int* valuep = va_arg(ap, int*);
   825                                             *valuep = (int)value;
   826                                         }
   827                                         break;
   828                                     case DO_LONG:
   829                                         { long* valuep = va_arg(ap, long*);
   830                                             *valuep = value;
   831                                         }
   832                                         break;
   833                                     case DO_LONGLONG:
   834                                         /* Handled above */
   835                                         break;
   836                                 }
   837                                 ++retval;
   838                             }
   839                         }
   840                         done = SDL_TRUE;
   841                         break;
   842                     case 'o':
   843                         if ( radix == 10 ) {
   844                             radix = 8;
   845                         }
   846                         /* Fall through to unsigned handling */
   847                     case 'x':
   848                     case 'X':
   849                         if ( radix == 10 ) {
   850                             radix = 16;
   851                         }
   852                         /* Fall through to unsigned handling */
   853                     case 'u':
   854 #ifdef SDL_HAS_64BIT_TYPE
   855                         if ( inttype == DO_LONGLONG ) {
   856                             Uint64 value;
   857                             text += SDL_ScanUnsignedLongLong(text, radix, &value);
   858                             if ( ! suppress ) {
   859                                 Uint64 *valuep = va_arg(ap, Uint64*);
   860                                 *valuep = value;
   861                                 ++retval;
   862                             }
   863                         }
   864                         else
   865 #endif /* SDL_HAS_64BIT_TYPE */
   866                         {
   867                             unsigned long value;
   868                             text += SDL_ScanUnsignedLong(text, radix, &value);
   869                             if ( ! suppress ) {
   870                                 switch (inttype) {
   871                                     case DO_SHORT:
   872                                         { short* valuep = va_arg(ap, short*);
   873                                             *valuep = (short)value;
   874                                         }
   875                                         break;
   876                                     case DO_INT:
   877                                         { int* valuep = va_arg(ap, int*);
   878                                             *valuep = (int)value;
   879                                         }
   880                                         break;
   881                                     case DO_LONG:
   882                                         { long* valuep = va_arg(ap, long*);
   883                                             *valuep = value;
   884                                         }
   885                                         break;
   886                                     case DO_LONGLONG:
   887                                         /* Handled above */
   888                                         break;
   889                                 }
   890                                 ++retval;
   891                             }
   892                         }
   893                         done = SDL_TRUE;
   894                         break;
   895                     case 'p':
   896                         {
   897                             uintptr_t value;
   898                             text += SDL_ScanUintPtrT(text, 16, &value);
   899                             if ( ! suppress ) {
   900                                 void** valuep = va_arg(ap, void**);
   901                                 *valuep = (void*)value;
   902                                 ++retval;
   903                             }
   904                         }
   905                         done = SDL_TRUE;
   906                         break;
   907                     case 'f':
   908                         {
   909                             double value;
   910                             text += SDL_ScanFloat(text, &value);
   911                             if ( ! suppress ) {
   912                                 float* valuep = va_arg(ap, float*);
   913                                 *valuep = (float)value;
   914                                 ++retval;
   915                             }
   916                         }
   917                         done = SDL_TRUE;
   918                         break;
   919                     case 's':
   920                         if ( suppress ) {
   921                             while ( !SDL_isspace(*text) ) {
   922                                 ++text;
   923                                 if ( count ) {
   924                                     if ( --count == 0 ) {
   925                                         break;
   926                                     }
   927                                 }
   928                             }
   929                         } else {
   930                             char *valuep = va_arg(ap, char*);
   931                             while ( !SDL_isspace(*text) ) {
   932                                 *valuep++ = *text++;
   933                                 if ( count ) {
   934                                     if ( --count == 0 ) {
   935                                         break;
   936                                     }
   937                                 }
   938                             }
   939                             *valuep = '\0';
   940                             ++retval;
   941                         }
   942                         done = SDL_TRUE;
   943                         break;
   944                     default:
   945                         done = SDL_TRUE;
   946                         break;
   947                 }
   948                 ++fmt;
   949             }
   950             continue;
   951         }
   952         if ( *text == *fmt ) {
   953             ++text;
   954             ++fmt;
   955             continue;
   956         }
   957         /* Text didn't match format specifier */
   958         break;
   959     }
   960     va_end(ap);
   961 
   962     return retval;
   963 }
   964 #endif
   965 
   966 #ifndef HAVE_SNPRINTF
   967 int SDL_snprintf(char *text, size_t maxlen, const char *fmt, ...)
   968 {
   969     va_list ap;
   970     int retval;
   971 
   972     va_start(ap, fmt);
   973     retval = SDL_vsnprintf(text, maxlen, fmt, ap);
   974     va_end(ap);
   975 
   976     return retval;
   977 }
   978 #endif
   979 
   980 #ifndef HAVE_VSNPRINTF
   981 static size_t SDL_PrintLong(char *text, long value, int radix, size_t maxlen)
   982 {
   983     char num[130];
   984     size_t size;
   985 
   986     SDL_ltoa(value, num, radix);
   987     size = SDL_strlen(num);
   988     if ( size > maxlen ) {
   989         size = maxlen;
   990     }
   991     SDL_strlcpy(text, num, size);
   992 
   993     return size;
   994 }
   995 static size_t SDL_PrintUnsignedLong(char *text, unsigned long value, int radix, size_t maxlen)
   996 {
   997     char num[130];
   998     size_t size;
   999 
  1000     SDL_ultoa(value, num, radix);
  1001     size = SDL_strlen(num);
  1002     if ( size > maxlen ) {
  1003         size = maxlen;
  1004     }
  1005     SDL_strlcpy(text, num, size);
  1006 
  1007     return size;
  1008 }
  1009 #ifdef SDL_HAS_64BIT_TYPE
  1010 static size_t SDL_PrintLongLong(char *text, Sint64 value, int radix, size_t maxlen)
  1011 {
  1012     char num[130];
  1013     size_t size;
  1014 
  1015     SDL_lltoa(value, num, radix);
  1016     size = SDL_strlen(num);
  1017     if ( size > maxlen ) {
  1018         size = maxlen;
  1019     }
  1020     SDL_strlcpy(text, num, size);
  1021 
  1022     return size;
  1023 }
  1024 static size_t SDL_PrintUnsignedLongLong(char *text, Uint64 value, int radix, size_t maxlen)
  1025 {
  1026     char num[130];
  1027     size_t size;
  1028 
  1029     SDL_ulltoa(value, num, radix);
  1030     size = SDL_strlen(num);
  1031     if ( size > maxlen ) {
  1032         size = maxlen;
  1033     }
  1034     SDL_strlcpy(text, num, size);
  1035 
  1036     return size;
  1037 }
  1038 #endif /* SDL_HAS_64BIT_TYPE */
  1039 static size_t SDL_PrintFloat(char *text, double arg, size_t maxlen)
  1040 {
  1041     char *textstart = text;
  1042     if ( arg ) {
  1043         /* This isn't especially accurate, but hey, it's easy. :) */
  1044         const double precision = 0.00000001;
  1045         size_t len;
  1046         unsigned long value;
  1047 
  1048         if ( arg < 0 ) {
  1049             *text++ = '-';
  1050             --maxlen;
  1051             arg = -arg;
  1052         }
  1053         value = (unsigned long)arg;
  1054         len = SDL_PrintUnsignedLong(text, value, 10, maxlen);
  1055         text += len;
  1056         maxlen -= len;
  1057         arg -= value;
  1058         if ( arg > precision && maxlen ) {
  1059             int mult = 10;
  1060             *text++ = '.';
  1061             while ( (arg > precision) && maxlen ) {
  1062                 value = (unsigned long)(arg * mult);
  1063                 len = SDL_PrintUnsignedLong(text, value, 10, maxlen);
  1064                 text += len;
  1065                 maxlen -= len;
  1066                 arg -= (double)value / mult;
  1067                 mult *= 10;
  1068             }
  1069         }
  1070     } else {
  1071         *text++ = '0';
  1072     }
  1073     return (text - textstart);
  1074 }
  1075 static size_t SDL_PrintString(char *text, const char *string, size_t maxlen)
  1076 {
  1077     char *textstart = text;
  1078     while ( *string && maxlen-- ) {
  1079         *text++ = *string++;
  1080     }
  1081     return (text - textstart);
  1082 }
  1083 int SDL_vsnprintf(char *text, size_t maxlen, const char *fmt, va_list ap)
  1084 {
  1085     char *textstart = text;
  1086     if ( maxlen <= 0 ) {
  1087         return 0;
  1088     }
  1089     --maxlen; /* For the trailing '\0' */
  1090     while ( *fmt && maxlen ) {
  1091         if ( *fmt == '%' ) {
  1092             SDL_bool done = SDL_FALSE;
  1093             size_t len = 0;
  1094             SDL_bool do_lowercase = SDL_FALSE;
  1095             int radix = 10;
  1096             enum {
  1097                 DO_INT,
  1098                 DO_LONG,
  1099                 DO_LONGLONG
  1100             } inttype = DO_INT;
  1101 
  1102             ++fmt;
  1103             /* FIXME: implement more of the format specifiers */
  1104             while (!done) {
  1105                 switch(*fmt) {
  1106                     case '%':
  1107                         *text = '%';
  1108                         len = 1;
  1109                         done = SDL_TRUE;
  1110                         break;
  1111                     case 'c':
  1112                         /* char is promoted to int when passed through (...) */
  1113                         *text = (char)va_arg(ap, int);
  1114                         len = 1;
  1115                         done = SDL_TRUE;
  1116                         break;
  1117                     case 'h':
  1118                         /* short is promoted to int when passed through (...) */
  1119                         break;
  1120                     case 'l':
  1121                         if ( inttype < DO_LONGLONG ) {
  1122                             ++inttype;
  1123                         }
  1124                         break;
  1125                     case 'I':
  1126                         if ( SDL_strncmp(fmt, "I64", 3) == 0 ) {
  1127                             fmt += 2;
  1128                             inttype = DO_LONGLONG;
  1129                         }
  1130                         break;
  1131                     case 'i':
  1132                     case 'd':
  1133                         switch (inttype) {
  1134                             case DO_INT:
  1135                                 len = SDL_PrintLong(text, (long)va_arg(ap, int), radix, maxlen);
  1136                                 break;
  1137                             case DO_LONG:
  1138                                 len = SDL_PrintLong(text, va_arg(ap, long), radix, maxlen);
  1139                                 break;
  1140                             case DO_LONGLONG:
  1141 #ifdef SDL_HAS_64BIT_TYPE
  1142                                 len = SDL_PrintLongLong(text, va_arg(ap, Sint64), radix, maxlen);
  1143 #else
  1144                                 len = SDL_PrintLong(text, va_arg(ap, long), radix, maxlen);
  1145 #endif
  1146                                 break;
  1147                         }
  1148                         done = SDL_TRUE;
  1149                         break;
  1150                     case 'p':
  1151                     case 'x':
  1152                         do_lowercase = SDL_TRUE;
  1153                         /* Fall through to 'X' handling */
  1154                     case 'X':
  1155                         if ( radix == 10 ) {
  1156                             radix = 16;
  1157                         }
  1158                         if ( *fmt == 'p' ) {
  1159                             inttype = DO_LONG;
  1160                         }
  1161                         /* Fall through to unsigned handling */
  1162                     case 'o':
  1163                         if ( radix == 10 ) {
  1164                             radix = 8;
  1165                         }
  1166                         /* Fall through to unsigned handling */
  1167                     case 'u':
  1168                         switch (inttype) {
  1169                             case DO_INT:
  1170                                 len = SDL_PrintUnsignedLong(text, (unsigned long)va_arg(ap, unsigned int), radix, maxlen);
  1171                                 break;
  1172                             case DO_LONG:
  1173                                 len = SDL_PrintUnsignedLong(text, va_arg(ap, unsigned long), radix, maxlen);
  1174                                 break;
  1175                             case DO_LONGLONG:
  1176 #ifdef SDL_HAS_64BIT_TYPE
  1177                                 len = SDL_PrintUnsignedLongLong(text, va_arg(ap, Uint64), radix, maxlen);
  1178 #else
  1179                                 len = SDL_PrintUnsignedLong(text, va_arg(ap, unsigned long), radix, maxlen);
  1180 #endif
  1181                                 break;
  1182                         }
  1183                         if ( do_lowercase ) {
  1184                             SDL_strlwr(text);
  1185                         }
  1186                         done = SDL_TRUE;
  1187                         break;
  1188                     case 'f':
  1189                         len = SDL_PrintFloat(text, va_arg(ap, double), maxlen);
  1190                         done = SDL_TRUE;
  1191                         break;
  1192                     case 's':
  1193                         len = SDL_PrintString(text, va_arg(ap, char*), maxlen);
  1194                         done = SDL_TRUE;
  1195                         break;
  1196                     default:
  1197                         done = SDL_TRUE;
  1198                         break;
  1199                 }
  1200                 ++fmt;
  1201             }
  1202             text += len;
  1203             maxlen -= len;
  1204         } else {
  1205             *text++ = *fmt++;
  1206             --maxlen;
  1207         }
  1208     }
  1209     *text = '\0';
  1210 
  1211     return (text - textstart);
  1212 }
  1213 #endif