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