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