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