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