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