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