src/stdlib/SDL_string.c
author Sam Lantinga
Sat, 19 Sep 2009 13:29:40 +0000
changeset 3280 00cace2d9080
parent 3253 5d7ef5970073
child 3697 f7b03b6838cb
permissions -rw-r--r--
Merged a cleaned up version of Jiang's code changes from Google Summer of Code 2009
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2009 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])
   876                                 == 'x') {
   877                                 radix = 16;
   878                             } else {
   879                                 radix = 8;
   880                             }
   881                         }
   882                     }
   883                     /* Fall through to %d handling */
   884                 case 'd':
   885 #ifdef SDL_HAS_64BIT_TYPE
   886                     if (inttype == DO_LONGLONG) {
   887                         Sint64 value;
   888                         text += SDL_ScanLongLong(text, radix, &value);
   889                         if (!suppress) {
   890                             Sint64 *valuep = va_arg(ap, Sint64 *);
   891                             *valuep = value;
   892                             ++retval;
   893                         }
   894                     } else
   895 #endif /* SDL_HAS_64BIT_TYPE */
   896                     {
   897                         long value;
   898                         text += SDL_ScanLong(text, radix, &value);
   899                         if (!suppress) {
   900                             switch (inttype) {
   901                             case DO_SHORT:
   902                                 {
   903                                     short *valuep = va_arg(ap, short *);
   904                                     *valuep = (short) value;
   905                                 }
   906                                 break;
   907                             case DO_INT:
   908                                 {
   909                                     int *valuep = va_arg(ap, int *);
   910                                     *valuep = (int) value;
   911                                 }
   912                                 break;
   913                             case DO_LONG:
   914                                 {
   915                                     long *valuep = va_arg(ap, long *);
   916                                     *valuep = value;
   917                                 }
   918                                 break;
   919                             case DO_LONGLONG:
   920                                 /* Handled above */
   921                                 break;
   922                             }
   923                             ++retval;
   924                         }
   925                     }
   926                     done = SDL_TRUE;
   927                     break;
   928                 case 'o':
   929                     if (radix == 10) {
   930                         radix = 8;
   931                     }
   932                     /* Fall through to unsigned handling */
   933                 case 'x':
   934                 case 'X':
   935                     if (radix == 10) {
   936                         radix = 16;
   937                     }
   938                     /* Fall through to unsigned handling */
   939                 case 'u':
   940 #ifdef SDL_HAS_64BIT_TYPE
   941                     if (inttype == DO_LONGLONG) {
   942                         Uint64 value;
   943                         text += SDL_ScanUnsignedLongLong(text, radix, &value);
   944                         if (!suppress) {
   945                             Uint64 *valuep = va_arg(ap, Uint64 *);
   946                             *valuep = value;
   947                             ++retval;
   948                         }
   949                     } else
   950 #endif /* SDL_HAS_64BIT_TYPE */
   951                     {
   952                         unsigned long value;
   953                         text += SDL_ScanUnsignedLong(text, radix, &value);
   954                         if (!suppress) {
   955                             switch (inttype) {
   956                             case DO_SHORT:
   957                                 {
   958                                     short *valuep = va_arg(ap, short *);
   959                                     *valuep = (short) value;
   960                                 }
   961                                 break;
   962                             case DO_INT:
   963                                 {
   964                                     int *valuep = va_arg(ap, int *);
   965                                     *valuep = (int) value;
   966                                 }
   967                                 break;
   968                             case DO_LONG:
   969                                 {
   970                                     long *valuep = va_arg(ap, long *);
   971                                     *valuep = value;
   972                                 }
   973                                 break;
   974                             case DO_LONGLONG:
   975                                 /* Handled above */
   976                                 break;
   977                             }
   978                             ++retval;
   979                         }
   980                     }
   981                     done = SDL_TRUE;
   982                     break;
   983                 case 'p':
   984                     {
   985                         uintptr_t value;
   986                         text += SDL_ScanUintPtrT(text, 16, &value);
   987                         if (!suppress) {
   988                             void **valuep = va_arg(ap, void **);
   989                             *valuep = (void *) value;
   990                             ++retval;
   991                         }
   992                     }
   993                     done = SDL_TRUE;
   994                     break;
   995                 case 'f':
   996                     {
   997                         double value;
   998                         text += SDL_ScanFloat(text, &value);
   999                         if (!suppress) {
  1000                             float *valuep = va_arg(ap, float *);
  1001                             *valuep = (float) value;
  1002                             ++retval;
  1003                         }
  1004                     }
  1005                     done = SDL_TRUE;
  1006                     break;
  1007                 case 's':
  1008                     if (suppress) {
  1009                         while (!SDL_isspace((unsigned char) *text)) {
  1010                             ++text;
  1011                             if (count) {
  1012                                 if (--count == 0) {
  1013                                     break;
  1014                                 }
  1015                             }
  1016                         }
  1017                     } else {
  1018                         char *valuep = va_arg(ap, char *);
  1019                         while (!SDL_isspace((unsigned char) *text)) {
  1020                             *valuep++ = *text++;
  1021                             if (count) {
  1022                                 if (--count == 0) {
  1023                                     break;
  1024                                 }
  1025                             }
  1026                         }
  1027                         *valuep = '\0';
  1028                         ++retval;
  1029                     }
  1030                     done = SDL_TRUE;
  1031                     break;
  1032                 default:
  1033                     done = SDL_TRUE;
  1034                     break;
  1035                 }
  1036                 ++fmt;
  1037             }
  1038             continue;
  1039         }
  1040         if (*text == *fmt) {
  1041             ++text;
  1042             ++fmt;
  1043             continue;
  1044         }
  1045         /* Text didn't match format specifier */
  1046         break;
  1047     }
  1048     va_end(ap);
  1049 
  1050     return retval;
  1051 }
  1052 #endif
  1053 
  1054 #ifndef HAVE_SNPRINTF
  1055 int
  1056 SDL_snprintf(char *text, size_t maxlen, const char *fmt, ...)
  1057 {
  1058     va_list ap;
  1059     int retval;
  1060 
  1061     va_start(ap, fmt);
  1062     retval = SDL_vsnprintf(text, maxlen, fmt, ap);
  1063     va_end(ap);
  1064 
  1065     return retval;
  1066 }
  1067 #endif
  1068 
  1069 #ifndef HAVE_VSNPRINTF
  1070 static size_t
  1071 SDL_PrintLong(char *text, long value, int radix, size_t maxlen)
  1072 {
  1073     char num[130];
  1074     size_t size;
  1075 
  1076     SDL_ltoa(value, num, radix);
  1077     size = SDL_strlen(num);
  1078     if (size >= maxlen) {
  1079         size = maxlen - 1;
  1080     }
  1081     SDL_strlcpy(text, num, size + 1);
  1082 
  1083     return size;
  1084 }
  1085 
  1086 static size_t
  1087 SDL_PrintUnsignedLong(char *text, unsigned long value, int radix,
  1088                       size_t maxlen)
  1089 {
  1090     char num[130];
  1091     size_t size;
  1092 
  1093     SDL_ultoa(value, num, radix);
  1094     size = SDL_strlen(num);
  1095     if (size >= maxlen) {
  1096         size = maxlen - 1;
  1097     }
  1098     SDL_strlcpy(text, num, size + 1);
  1099 
  1100     return size;
  1101 }
  1102 
  1103 #ifdef SDL_HAS_64BIT_TYPE
  1104 static size_t
  1105 SDL_PrintLongLong(char *text, Sint64 value, int radix, size_t maxlen)
  1106 {
  1107     char num[130];
  1108     size_t size;
  1109 
  1110     SDL_lltoa(value, num, radix);
  1111     size = SDL_strlen(num);
  1112     if (size >= maxlen) {
  1113         size = maxlen - 1;
  1114     }
  1115     SDL_strlcpy(text, num, size + 1);
  1116 
  1117     return size;
  1118 }
  1119 
  1120 static size_t
  1121 SDL_PrintUnsignedLongLong(char *text, Uint64 value, int radix, size_t maxlen)
  1122 {
  1123     char num[130];
  1124     size_t size;
  1125 
  1126     SDL_ulltoa(value, num, radix);
  1127     size = SDL_strlen(num);
  1128     if (size >= maxlen) {
  1129         size = maxlen - 1;
  1130     }
  1131     SDL_strlcpy(text, num, size + 1);
  1132 
  1133     return size;
  1134 }
  1135 #endif /* SDL_HAS_64BIT_TYPE */
  1136 static size_t
  1137 SDL_PrintFloat(char *text, double arg, size_t maxlen)
  1138 {
  1139     char *textstart = text;
  1140     if (arg) {
  1141         /* This isn't especially accurate, but hey, it's easy. :) */
  1142         const double precision = 0.00000001;
  1143         size_t len;
  1144         unsigned long value;
  1145 
  1146         if (arg < 0) {
  1147             *text++ = '-';
  1148             --maxlen;
  1149             arg = -arg;
  1150         }
  1151         value = (unsigned long) arg;
  1152         len = SDL_PrintUnsignedLong(text, value, 10, maxlen);
  1153         text += len;
  1154         maxlen -= len;
  1155         arg -= value;
  1156         if (arg > precision && maxlen) {
  1157             int mult = 10;
  1158             *text++ = '.';
  1159             while ((arg > precision) && maxlen) {
  1160                 value = (unsigned long) (arg * mult);
  1161                 len = SDL_PrintUnsignedLong(text, value, 10, maxlen);
  1162                 text += len;
  1163                 maxlen -= len;
  1164                 arg -= (double) value / mult;
  1165                 mult *= 10;
  1166             }
  1167         }
  1168     } else {
  1169         *text++ = '0';
  1170     }
  1171     return (text - textstart);
  1172 }
  1173 
  1174 static size_t
  1175 SDL_PrintString(char *text, const char *string, size_t maxlen)
  1176 {
  1177     char *textstart = text;
  1178     while (*string && maxlen--) {
  1179         *text++ = *string++;
  1180     }
  1181     return (text - textstart);
  1182 }
  1183 
  1184 int
  1185 SDL_vsnprintf(char *text, size_t maxlen, const char *fmt, va_list ap)
  1186 {
  1187     char *textstart = text;
  1188     if (maxlen <= 0) {
  1189         return 0;
  1190     }
  1191     --maxlen;                   /* For the trailing '\0' */
  1192     while (*fmt && maxlen) {
  1193         if (*fmt == '%') {
  1194             SDL_bool done = SDL_FALSE;
  1195             size_t len = 0;
  1196             SDL_bool do_lowercase = SDL_FALSE;
  1197             int radix = 10;
  1198             enum
  1199             {
  1200                 DO_INT,
  1201                 DO_LONG,
  1202                 DO_LONGLONG
  1203             } inttype = DO_INT;
  1204 
  1205             ++fmt;
  1206             /* FIXME: implement more of the format specifiers */
  1207             while (*fmt == '.' || (*fmt >= '0' && *fmt <= '9')) {
  1208                 ++fmt;
  1209             }
  1210             while (!done) {
  1211                 switch (*fmt) {
  1212                 case '%':
  1213                     *text = '%';
  1214                     len = 1;
  1215                     done = SDL_TRUE;
  1216                     break;
  1217                 case 'c':
  1218                     /* char is promoted to int when passed through (...) */
  1219                     *text = (char) va_arg(ap, int);
  1220                     len = 1;
  1221                     done = SDL_TRUE;
  1222                     break;
  1223                 case 'h':
  1224                     /* short is promoted to int when passed through (...) */
  1225                     break;
  1226                 case 'l':
  1227                     if (inttype < DO_LONGLONG) {
  1228                         ++inttype;
  1229                     }
  1230                     break;
  1231                 case 'I':
  1232                     if (SDL_strncmp(fmt, "I64", 3) == 0) {
  1233                         fmt += 2;
  1234                         inttype = DO_LONGLONG;
  1235                     }
  1236                     break;
  1237                 case 'i':
  1238                 case 'd':
  1239                     switch (inttype) {
  1240                     case DO_INT:
  1241                         len =
  1242                             SDL_PrintLong(text,
  1243                                           (long) va_arg(ap, int),
  1244                                           radix, maxlen);
  1245                         break;
  1246                     case DO_LONG:
  1247                         len =
  1248                             SDL_PrintLong(text, va_arg(ap, long),
  1249                                           radix, maxlen);
  1250                         break;
  1251                     case DO_LONGLONG:
  1252 #ifdef SDL_HAS_64BIT_TYPE
  1253                         len =
  1254                             SDL_PrintLongLong(text,
  1255                                               va_arg(ap, Sint64),
  1256                                               radix, maxlen);
  1257 #else
  1258                         len =
  1259                             SDL_PrintLong(text, va_arg(ap, long),
  1260                                           radix, maxlen);
  1261 #endif
  1262                         break;
  1263                     }
  1264                     done = SDL_TRUE;
  1265                     break;
  1266                 case 'p':
  1267                 case 'x':
  1268                     do_lowercase = SDL_TRUE;
  1269                     /* Fall through to 'X' handling */
  1270                 case 'X':
  1271                     if (radix == 10) {
  1272                         radix = 16;
  1273                     }
  1274                     if (*fmt == 'p') {
  1275                         inttype = DO_LONG;
  1276                     }
  1277                     /* Fall through to unsigned handling */
  1278                 case 'o':
  1279                     if (radix == 10) {
  1280                         radix = 8;
  1281                     }
  1282                     /* Fall through to unsigned handling */
  1283                 case 'u':
  1284                     switch (inttype) {
  1285                     case DO_INT:
  1286                         len = SDL_PrintUnsignedLong(text, (unsigned long)
  1287                                                     va_arg(ap,
  1288                                                            unsigned
  1289                                                            int),
  1290                                                     radix, maxlen);
  1291                         break;
  1292                     case DO_LONG:
  1293                         len =
  1294                             SDL_PrintUnsignedLong(text,
  1295                                                   va_arg(ap,
  1296                                                          unsigned
  1297                                                          long),
  1298                                                   radix, maxlen);
  1299                         break;
  1300                     case DO_LONGLONG:
  1301 #ifdef SDL_HAS_64BIT_TYPE
  1302                         len =
  1303                             SDL_PrintUnsignedLongLong(text,
  1304                                                       va_arg(ap,
  1305                                                              Uint64),
  1306                                                       radix, maxlen);
  1307 #else
  1308                         len =
  1309                             SDL_PrintUnsignedLong(text,
  1310                                                   va_arg(ap,
  1311                                                          unsigned
  1312                                                          long),
  1313                                                   radix, maxlen);
  1314 #endif
  1315                         break;
  1316                     }
  1317                     if (do_lowercase) {
  1318                         SDL_strlwr(text);
  1319                     }
  1320                     done = SDL_TRUE;
  1321                     break;
  1322                 case 'f':
  1323                     len = SDL_PrintFloat(text, va_arg(ap, double), maxlen);
  1324                     done = SDL_TRUE;
  1325                     break;
  1326                 case 's':
  1327                     len = SDL_PrintString(text, va_arg(ap, char *), maxlen);
  1328                     done = SDL_TRUE;
  1329                     break;
  1330                 default:
  1331                     done = SDL_TRUE;
  1332                     break;
  1333                 }
  1334                 ++fmt;
  1335             }
  1336             text += len;
  1337             maxlen -= len;
  1338         } else {
  1339             *text++ = *fmt++;
  1340             --maxlen;
  1341         }
  1342     }
  1343     *text = '\0';
  1344 
  1345     return (int)(text - textstart);
  1346 }
  1347 #endif
  1348 /* vi: set ts=4 sw=4 expandtab: */