src/stdlib/SDL_string.c
author Ryan C. Gordon
Mon, 04 Jun 2007 11:45:10 +0000
changeset 2114 4794e6f90feb
parent 2092 8e761d6af583
child 2120 2c835d58faad
permissions -rw-r--r--
Merged r3047:3048 from branches/SDL-1.2: SDL_revcpy() off-by-one fix.
     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((unsigned char) *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((unsigned char) *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((unsigned char) *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((unsigned char) *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((unsigned char) *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((unsigned char) *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-1;
   302     dstp += len-1;
   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((unsigned char) *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((unsigned char) *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((unsigned char) *str1);
   747         b = SDL_tolower((unsigned char) *str2);
   748         if (a != b)
   749             break;
   750         ++str1;
   751         ++str2;
   752     }
   753     a = SDL_tolower(*str1);
   754     b = SDL_tolower(*str2);
   755     return (int) ((unsigned char) a - (unsigned char) b);
   756 }
   757 #endif
   758 
   759 #if !defined(HAVE_STRNCASECMP) && !defined(HAVE__STRNICMP)
   760 int
   761 SDL_strncasecmp(const char *str1, const char *str2, size_t maxlen)
   762 {
   763     char a = 0;
   764     char b = 0;
   765     while (*str1 && *str2 && maxlen) {
   766         a = SDL_tolower((unsigned char) *str1);
   767         b = SDL_tolower((unsigned char) *str2);
   768         if (a != b)
   769             break;
   770         ++str1;
   771         ++str2;
   772         --maxlen;
   773     }
   774     a = SDL_tolower(*str1);
   775     b = SDL_tolower(*str2);
   776     return (int) ((unsigned char) a - (unsigned char) b);
   777 }
   778 #endif
   779 
   780 #ifndef HAVE_SSCANF
   781 int
   782 SDL_sscanf(const char *text, const char *fmt, ...)
   783 {
   784     va_list ap;
   785     int retval = 0;
   786 
   787     va_start(ap, fmt);
   788     while (*fmt) {
   789         if (*fmt == ' ') {
   790             while (SDL_isspace((unsigned char) *text)) {
   791                 ++text;
   792             }
   793             ++fmt;
   794             continue;
   795         }
   796         if (*fmt == '%') {
   797             SDL_bool done = SDL_FALSE;
   798             long count = 0;
   799             int radix = 10;
   800             enum
   801             {
   802                 DO_SHORT,
   803                 DO_INT,
   804                 DO_LONG,
   805                 DO_LONGLONG
   806             } inttype = DO_INT;
   807             SDL_bool suppress = SDL_FALSE;
   808 
   809             ++fmt;
   810             if (*fmt == '%') {
   811                 if (*text == '%') {
   812                     ++text;
   813                     ++fmt;
   814                     continue;
   815                 }
   816                 break;
   817             }
   818             if (*fmt == '*') {
   819                 suppress = SDL_TRUE;
   820                 ++fmt;
   821             }
   822             fmt += SDL_ScanLong(fmt, 10, &count);
   823 
   824             if (*fmt == 'c') {
   825                 if (!count) {
   826                     count = 1;
   827                 }
   828                 if (suppress) {
   829                     while (count--) {
   830                         ++text;
   831                     }
   832                 } else {
   833                     char *valuep = va_arg(ap, char *);
   834                     while (count--) {
   835                         *valuep++ = *text++;
   836                     }
   837                     ++retval;
   838                 }
   839                 continue;
   840             }
   841 
   842             while (SDL_isspace((unsigned char) *text)) {
   843                 ++text;
   844             }
   845 
   846             /* FIXME: implement more of the format specifiers */
   847             while (!done) {
   848                 switch (*fmt) {
   849                 case '*':
   850                     suppress = SDL_TRUE;
   851                     break;
   852                 case 'h':
   853                     if (inttype > DO_SHORT) {
   854                         ++inttype;
   855                     }
   856                     break;
   857                 case 'l':
   858                     if (inttype < DO_LONGLONG) {
   859                         ++inttype;
   860                     }
   861                     break;
   862                 case 'I':
   863                     if (SDL_strncmp(fmt, "I64", 3) == 0) {
   864                         fmt += 2;
   865                         inttype = DO_LONGLONG;
   866                     }
   867                     break;
   868                 case 'i':
   869                     {
   870                         int index = 0;
   871                         if (text[index] == '-') {
   872                             ++index;
   873                         }
   874                         if (text[index] == '0') {
   875                             if (SDL_tolower((unsigned char) text[index + 1]) == 'x') {
   876                                 radix = 16;
   877                             } else {
   878                                 radix = 8;
   879                             }
   880                         }
   881                     }
   882                     /* Fall through to %d handling */
   883                 case 'd':
   884 #ifdef SDL_HAS_64BIT_TYPE
   885                     if (inttype == DO_LONGLONG) {
   886                         Sint64 value;
   887                         text += SDL_ScanLongLong(text, radix, &value);
   888                         if (!suppress) {
   889                             Sint64 *valuep = va_arg(ap, Sint64 *);
   890                             *valuep = value;
   891                             ++retval;
   892                         }
   893                     } else
   894 #endif /* SDL_HAS_64BIT_TYPE */
   895                     {
   896                         long value;
   897                         text += SDL_ScanLong(text, radix, &value);
   898                         if (!suppress) {
   899                             switch (inttype) {
   900                             case DO_SHORT:
   901                                 {
   902                                     short *valuep = va_arg(ap, short *);
   903                                     *valuep = (short) value;
   904                                 }
   905                                 break;
   906                             case DO_INT:
   907                                 {
   908                                     int *valuep = va_arg(ap, int *);
   909                                     *valuep = (int) value;
   910                                 }
   911                                 break;
   912                             case DO_LONG:
   913                                 {
   914                                     long *valuep = va_arg(ap, long *);
   915                                     *valuep = value;
   916                                 }
   917                                 break;
   918                             case DO_LONGLONG:
   919                                 /* Handled above */
   920                                 break;
   921                             }
   922                             ++retval;
   923                         }
   924                     }
   925                     done = SDL_TRUE;
   926                     break;
   927                 case 'o':
   928                     if (radix == 10) {
   929                         radix = 8;
   930                     }
   931                     /* Fall through to unsigned handling */
   932                 case 'x':
   933                 case 'X':
   934                     if (radix == 10) {
   935                         radix = 16;
   936                     }
   937                     /* Fall through to unsigned handling */
   938                 case 'u':
   939 #ifdef SDL_HAS_64BIT_TYPE
   940                     if (inttype == DO_LONGLONG) {
   941                         Uint64 value;
   942                         text += SDL_ScanUnsignedLongLong(text, radix, &value);
   943                         if (!suppress) {
   944                             Uint64 *valuep = va_arg(ap, Uint64 *);
   945                             *valuep = value;
   946                             ++retval;
   947                         }
   948                     } else
   949 #endif /* SDL_HAS_64BIT_TYPE */
   950                     {
   951                         unsigned long value;
   952                         text += SDL_ScanUnsignedLong(text, radix, &value);
   953                         if (!suppress) {
   954                             switch (inttype) {
   955                             case DO_SHORT:
   956                                 {
   957                                     short *valuep = va_arg(ap, short *);
   958                                     *valuep = (short) value;
   959                                 }
   960                                 break;
   961                             case DO_INT:
   962                                 {
   963                                     int *valuep = va_arg(ap, int *);
   964                                     *valuep = (int) value;
   965                                 }
   966                                 break;
   967                             case DO_LONG:
   968                                 {
   969                                     long *valuep = va_arg(ap, long *);
   970                                     *valuep = value;
   971                                 }
   972                                 break;
   973                             case DO_LONGLONG:
   974                                 /* Handled above */
   975                                 break;
   976                             }
   977                             ++retval;
   978                         }
   979                     }
   980                     done = SDL_TRUE;
   981                     break;
   982                 case 'p':
   983                     {
   984                         uintptr_t value;
   985                         text += SDL_ScanUintPtrT(text, 16, &value);
   986                         if (!suppress) {
   987                             void **valuep = va_arg(ap, void **);
   988                             *valuep = (void *) value;
   989                             ++retval;
   990                         }
   991                     }
   992                     done = SDL_TRUE;
   993                     break;
   994                 case 'f':
   995                     {
   996                         double value;
   997                         text += SDL_ScanFloat(text, &value);
   998                         if (!suppress) {
   999                             float *valuep = va_arg(ap, float *);
  1000                             *valuep = (float) value;
  1001                             ++retval;
  1002                         }
  1003                     }
  1004                     done = SDL_TRUE;
  1005                     break;
  1006                 case 's':
  1007                     if (suppress) {
  1008                         while (!SDL_isspace((unsigned char) *text)) {
  1009                             ++text;
  1010                             if (count) {
  1011                                 if (--count == 0) {
  1012                                     break;
  1013                                 }
  1014                             }
  1015                         }
  1016                     } else {
  1017                         char *valuep = va_arg(ap, char *);
  1018                         while (!SDL_isspace((unsigned char) *text)) {
  1019                             *valuep++ = *text++;
  1020                             if (count) {
  1021                                 if (--count == 0) {
  1022                                     break;
  1023                                 }
  1024                             }
  1025                         }
  1026                         *valuep = '\0';
  1027                         ++retval;
  1028                     }
  1029                     done = SDL_TRUE;
  1030                     break;
  1031                 default:
  1032                     done = SDL_TRUE;
  1033                     break;
  1034                 }
  1035                 ++fmt;
  1036             }
  1037             continue;
  1038         }
  1039         if (*text == *fmt) {
  1040             ++text;
  1041             ++fmt;
  1042             continue;
  1043         }
  1044         /* Text didn't match format specifier */
  1045         break;
  1046     }
  1047     va_end(ap);
  1048 
  1049     return retval;
  1050 }
  1051 #endif
  1052 
  1053 #ifndef HAVE_SNPRINTF
  1054 int
  1055 SDL_snprintf(char *text, size_t maxlen, const char *fmt, ...)
  1056 {
  1057     va_list ap;
  1058     int retval;
  1059 
  1060     va_start(ap, fmt);
  1061     retval = SDL_vsnprintf(text, maxlen, fmt, ap);
  1062     va_end(ap);
  1063 
  1064     return retval;
  1065 }
  1066 #endif
  1067 
  1068 #ifndef HAVE_VSNPRINTF
  1069 static size_t
  1070 SDL_PrintLong(char *text, long value, int radix, size_t maxlen)
  1071 {
  1072     char num[130];
  1073     size_t size;
  1074 
  1075     SDL_ltoa(value, num, radix);
  1076     size = SDL_strlen(num);
  1077     if (size >= maxlen) {
  1078         size = maxlen - 1;
  1079     }
  1080     SDL_strlcpy(text, num, size + 1);
  1081 
  1082     return size;
  1083 }
  1084 
  1085 static size_t
  1086 SDL_PrintUnsignedLong(char *text, unsigned long value, int radix,
  1087                       size_t maxlen)
  1088 {
  1089     char num[130];
  1090     size_t size;
  1091 
  1092     SDL_ultoa(value, num, radix);
  1093     size = SDL_strlen(num);
  1094     if (size >= maxlen) {
  1095         size = maxlen - 1;
  1096     }
  1097     SDL_strlcpy(text, num, size + 1);
  1098 
  1099     return size;
  1100 }
  1101 
  1102 #ifdef SDL_HAS_64BIT_TYPE
  1103 static size_t
  1104 SDL_PrintLongLong(char *text, Sint64 value, int radix, size_t maxlen)
  1105 {
  1106     char num[130];
  1107     size_t size;
  1108 
  1109     SDL_lltoa(value, num, radix);
  1110     size = SDL_strlen(num);
  1111     if (size >= maxlen) {
  1112         size = maxlen - 1;
  1113     }
  1114     SDL_strlcpy(text, num, size + 1);
  1115 
  1116     return size;
  1117 }
  1118 
  1119 static size_t
  1120 SDL_PrintUnsignedLongLong(char *text, Uint64 value, int radix, size_t maxlen)
  1121 {
  1122     char num[130];
  1123     size_t size;
  1124 
  1125     SDL_ulltoa(value, num, radix);
  1126     size = SDL_strlen(num);
  1127     if (size >= maxlen) {
  1128         size = maxlen - 1;
  1129     }
  1130     SDL_strlcpy(text, num, size + 1);
  1131 
  1132     return size;
  1133 }
  1134 #endif /* SDL_HAS_64BIT_TYPE */
  1135 static size_t
  1136 SDL_PrintFloat(char *text, double arg, size_t maxlen)
  1137 {
  1138     char *textstart = text;
  1139     if (arg) {
  1140         /* This isn't especially accurate, but hey, it's easy. :) */
  1141         const double precision = 0.00000001;
  1142         size_t len;
  1143         unsigned long value;
  1144 
  1145         if (arg < 0) {
  1146             *text++ = '-';
  1147             --maxlen;
  1148             arg = -arg;
  1149         }
  1150         value = (unsigned long) arg;
  1151         len = SDL_PrintUnsignedLong(text, value, 10, maxlen);
  1152         text += len;
  1153         maxlen -= len;
  1154         arg -= value;
  1155         if (arg > precision && maxlen) {
  1156             int mult = 10;
  1157             *text++ = '.';
  1158             while ((arg > precision) && maxlen) {
  1159                 value = (unsigned long) (arg * mult);
  1160                 len = SDL_PrintUnsignedLong(text, value, 10, maxlen);
  1161                 text += len;
  1162                 maxlen -= len;
  1163                 arg -= (double) value / mult;
  1164                 mult *= 10;
  1165             }
  1166         }
  1167     } else {
  1168         *text++ = '0';
  1169     }
  1170     return (text - textstart);
  1171 }
  1172 
  1173 static size_t
  1174 SDL_PrintString(char *text, const char *string, size_t maxlen)
  1175 {
  1176     char *textstart = text;
  1177     while (*string && maxlen--) {
  1178         *text++ = *string++;
  1179     }
  1180     return (text - textstart);
  1181 }
  1182 
  1183 int
  1184 SDL_vsnprintf(char *text, size_t maxlen, const char *fmt, va_list ap)
  1185 {
  1186     char *textstart = text;
  1187     if (maxlen <= 0) {
  1188         return 0;
  1189     }
  1190     --maxlen;                   /* For the trailing '\0' */
  1191     while (*fmt && maxlen) {
  1192         if (*fmt == '%') {
  1193             SDL_bool done = SDL_FALSE;
  1194             size_t len = 0;
  1195             SDL_bool do_lowercase = SDL_FALSE;
  1196             int radix = 10;
  1197             enum
  1198             {
  1199                 DO_INT,
  1200                 DO_LONG,
  1201                 DO_LONGLONG
  1202             } inttype = DO_INT;
  1203 
  1204             ++fmt;
  1205             /* FIXME: implement more of the format specifiers */
  1206             while (*fmt == '.' || (*fmt >= '0' && *fmt <= '9')) {
  1207                 ++fmt;
  1208             }
  1209             while (!done) {
  1210                 switch (*fmt) {
  1211                 case '%':
  1212                     *text = '%';
  1213                     len = 1;
  1214                     done = SDL_TRUE;
  1215                     break;
  1216                 case 'c':
  1217                     /* char is promoted to int when passed through (...) */
  1218                     *text = (char) va_arg(ap, int);
  1219                     len = 1;
  1220                     done = SDL_TRUE;
  1221                     break;
  1222                 case 'h':
  1223                     /* short is promoted to int when passed through (...) */
  1224                     break;
  1225                 case 'l':
  1226                     if (inttype < DO_LONGLONG) {
  1227                         ++inttype;
  1228                     }
  1229                     break;
  1230                 case 'I':
  1231                     if (SDL_strncmp(fmt, "I64", 3) == 0) {
  1232                         fmt += 2;
  1233                         inttype = DO_LONGLONG;
  1234                     }
  1235                     break;
  1236                 case 'i':
  1237                 case 'd':
  1238                     switch (inttype) {
  1239                     case DO_INT:
  1240                         len =
  1241                             SDL_PrintLong(text,
  1242                                           (long) va_arg(ap, int),
  1243                                           radix, maxlen);
  1244                         break;
  1245                     case DO_LONG:
  1246                         len =
  1247                             SDL_PrintLong(text, va_arg(ap, long),
  1248                                           radix, maxlen);
  1249                         break;
  1250                     case DO_LONGLONG:
  1251 #ifdef SDL_HAS_64BIT_TYPE
  1252                         len =
  1253                             SDL_PrintLongLong(text,
  1254                                               va_arg(ap, Sint64),
  1255                                               radix, maxlen);
  1256 #else
  1257                         len =
  1258                             SDL_PrintLong(text, va_arg(ap, long),
  1259                                           radix, maxlen);
  1260 #endif
  1261                         break;
  1262                     }
  1263                     done = SDL_TRUE;
  1264                     break;
  1265                 case 'p':
  1266                 case 'x':
  1267                     do_lowercase = SDL_TRUE;
  1268                     /* Fall through to 'X' handling */
  1269                 case 'X':
  1270                     if (radix == 10) {
  1271                         radix = 16;
  1272                     }
  1273                     if (*fmt == 'p') {
  1274                         inttype = DO_LONG;
  1275                     }
  1276                     /* Fall through to unsigned handling */
  1277                 case 'o':
  1278                     if (radix == 10) {
  1279                         radix = 8;
  1280                     }
  1281                     /* Fall through to unsigned handling */
  1282                 case 'u':
  1283                     switch (inttype) {
  1284                     case DO_INT:
  1285                         len = SDL_PrintUnsignedLong(text, (unsigned long)
  1286                                                     va_arg(ap,
  1287                                                            unsigned
  1288                                                            int),
  1289                                                     radix, maxlen);
  1290                         break;
  1291                     case DO_LONG:
  1292                         len =
  1293                             SDL_PrintUnsignedLong(text,
  1294                                                   va_arg(ap,
  1295                                                          unsigned
  1296                                                          long),
  1297                                                   radix, maxlen);
  1298                         break;
  1299                     case DO_LONGLONG:
  1300 #ifdef SDL_HAS_64BIT_TYPE
  1301                         len =
  1302                             SDL_PrintUnsignedLongLong(text,
  1303                                                       va_arg(ap,
  1304                                                              Uint64),
  1305                                                       radix, maxlen);
  1306 #else
  1307                         len =
  1308                             SDL_PrintUnsignedLong(text,
  1309                                                   va_arg(ap,
  1310                                                          unsigned
  1311                                                          long),
  1312                                                   radix, maxlen);
  1313 #endif
  1314                         break;
  1315                     }
  1316                     if (do_lowercase) {
  1317                         SDL_strlwr(text);
  1318                     }
  1319                     done = SDL_TRUE;
  1320                     break;
  1321                 case 'f':
  1322                     len = SDL_PrintFloat(text, va_arg(ap, double), maxlen);
  1323                     done = SDL_TRUE;
  1324                     break;
  1325                 case 's':
  1326                     len = SDL_PrintString(text, va_arg(ap, char *), maxlen);
  1327                     done = SDL_TRUE;
  1328                     break;
  1329                 default:
  1330                     done = SDL_TRUE;
  1331                     break;
  1332                 }
  1333                 ++fmt;
  1334             }
  1335             text += len;
  1336             maxlen -= len;
  1337         } else {
  1338             *text++ = *fmt++;
  1339             --maxlen;
  1340         }
  1341     }
  1342     *text = '\0';
  1343 
  1344     return (text - textstart);
  1345 }
  1346 #endif
  1347 /* vi: set ts=4 sw=4 expandtab: */