Home | History | Annotate | Download | only in stdlib
      1 /*
      2     SDL - Simple DirectMedia Layer
      3     Copyright (C) 1997-2012 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 (at) 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
   1249