src/stdlib/SDL_string.c
author Sam Lantinga
Mon, 29 May 2006 04:04:35 +0000
branchSDL-1.3
changeset 1668 4da1ee79c9af
parent 1662 782fd950bd46
child 1693 504cb581ae1c
permissions -rw-r--r--
more tweaking indent options
     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_STRLCPY
   340 size_t
   341 SDL_strlcpy(char *dst, const char *src, size_t maxlen)
   342 {
   343     size_t srclen = SDL_strlen(src);
   344     if (maxlen > 0) {
   345         size_t len = SDL_min(srclen, maxlen - 1);
   346         SDL_memcpy(dst, src, len);
   347         dst[len] = '\0';
   348     }
   349     return srclen;
   350 }
   351 #endif
   352 
   353 #ifndef HAVE_STRLCAT
   354 size_t
   355 SDL_strlcat(char *dst, const char *src, size_t maxlen)
   356 {
   357     size_t dstlen = SDL_strlen(dst);
   358     size_t srclen = SDL_strlen(src);
   359     if (dstlen < maxlen) {
   360         SDL_strlcpy(dst + dstlen, src, maxlen - dstlen);
   361     }
   362     return dstlen + srclen;
   363 }
   364 #endif
   365 
   366 #ifndef HAVE_STRDUP
   367 char *
   368 SDL_strdup(const char *string)
   369 {
   370     size_t len = SDL_strlen(string) + 1;
   371     char *newstr = SDL_malloc(len);
   372     if (newstr) {
   373         SDL_strlcpy(newstr, string, len);
   374     }
   375     return newstr;
   376 }
   377 #endif
   378 
   379 #ifndef HAVE__STRREV
   380 char *
   381 SDL_strrev(char *string)
   382 {
   383     size_t len = SDL_strlen(string);
   384     char *a = &string[0];
   385     char *b = &string[len - 1];
   386     len /= 2;
   387     while (len--) {
   388         char c = *a;
   389         *a++ = *b;
   390         *b-- = c;
   391     }
   392     return string;
   393 }
   394 #endif
   395 
   396 #ifndef HAVE__STRUPR
   397 char *
   398 SDL_strupr(char *string)
   399 {
   400     char *bufp = string;
   401     while (*bufp) {
   402         *bufp = SDL_toupper(*bufp);
   403         ++bufp;
   404     }
   405     return string;
   406 }
   407 #endif
   408 
   409 #ifndef HAVE__STRLWR
   410 char *
   411 SDL_strlwr(char *string)
   412 {
   413     char *bufp = string;
   414     while (*bufp) {
   415         *bufp = SDL_tolower(*bufp);
   416         ++bufp;
   417     }
   418     return string;
   419 }
   420 #endif
   421 
   422 #ifndef HAVE_STRCHR
   423 char *
   424 SDL_strchr(const char *string, int c)
   425 {
   426     while (*string) {
   427         if (*string == c) {
   428             return (char *) string;
   429         }
   430         ++string;
   431     }
   432     return NULL;
   433 }
   434 #endif
   435 
   436 #ifndef HAVE_STRRCHR
   437 char *
   438 SDL_strrchr(const char *string, int c)
   439 {
   440     const char *bufp = string + SDL_strlen(string) - 1;
   441     while (bufp >= string) {
   442         if (*bufp == c) {
   443             return (char *) bufp;
   444         }
   445         --bufp;
   446     }
   447     return NULL;
   448 }
   449 #endif
   450 
   451 #ifndef HAVE_STRSTR
   452 char *
   453 SDL_strstr(const char *haystack, const char *needle)
   454 {
   455     size_t length = SDL_strlen(needle);
   456     while (*haystack) {
   457         if (SDL_strncmp(haystack, needle, length) == 0) {
   458             return (char *) haystack;
   459         }
   460         ++haystack;
   461     }
   462     return NULL;
   463 }
   464 #endif
   465 
   466 #if !defined(HAVE__LTOA)  || !defined(HAVE__I64TOA) || \
   467     !defined(HAVE__ULTOA) || !defined(HAVE__UI64TOA)
   468 static const char ntoa_table[] = {
   469     '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
   470     'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
   471     'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
   472     'U', 'V', 'W', 'X', 'Y', 'Z'
   473 };
   474 #endif /* ntoa() conversion table */
   475 
   476 #ifndef HAVE__LTOA
   477 char *
   478 SDL_ltoa(long value, char *string, int radix)
   479 {
   480     char *bufp = string;
   481 
   482     if (value < 0) {
   483         *bufp++ = '-';
   484         value = -value;
   485     }
   486     if (value) {
   487         while (value > 0) {
   488             *bufp++ = ntoa_table[value % radix];
   489             value /= radix;
   490         }
   491     } else {
   492         *bufp++ = '0';
   493     }
   494     *bufp = '\0';
   495 
   496     /* The numbers went into the string backwards. :) */
   497     if (*string == '-') {
   498         SDL_strrev(string + 1);
   499     } else {
   500         SDL_strrev(string);
   501     }
   502 
   503     return string;
   504 }
   505 #endif
   506 
   507 #ifndef HAVE__ULTOA
   508 char *
   509 SDL_ultoa(unsigned long value, char *string, int radix)
   510 {
   511     char *bufp = string;
   512 
   513     if (value) {
   514         while (value > 0) {
   515             *bufp++ = ntoa_table[value % radix];
   516             value /= radix;
   517         }
   518     } else {
   519         *bufp++ = '0';
   520     }
   521     *bufp = '\0';
   522 
   523     /* The numbers went into the string backwards. :) */
   524     SDL_strrev(string);
   525 
   526     return string;
   527 }
   528 #endif
   529 
   530 #ifndef HAVE_STRTOL
   531 long
   532 SDL_strtol(const char *string, char **endp, int base)
   533 {
   534     size_t len;
   535     long value;
   536 
   537     len = SDL_ScanLong(string, base ? base : 10, &value);
   538     if (endp) {
   539         *endp = (char *) string + len;
   540     }
   541     return value;
   542 }
   543 #endif
   544 
   545 #ifndef HAVE_STRTOUL
   546 unsigned long
   547 SDL_strtoul(const char *string, char **endp, int base)
   548 {
   549     size_t len;
   550     unsigned long value;
   551 
   552     len = SDL_ScanUnsignedLong(string, base ? base : 10, &value);
   553     if (endp) {
   554         *endp = (char *) string + len;
   555     }
   556     return value;
   557 }
   558 #endif
   559 
   560 #ifdef SDL_HAS_64BIT_TYPE
   561 
   562 #ifndef HAVE__I64TOA
   563 char *
   564 SDL_lltoa(Sint64 value, char *string, int radix)
   565 {
   566     char *bufp = string;
   567 
   568     if (value < 0) {
   569         *bufp++ = '-';
   570         value = -value;
   571     }
   572     if (value) {
   573         while (value > 0) {
   574             *bufp++ = ntoa_table[value % radix];
   575             value /= radix;
   576         }
   577     } else {
   578         *bufp++ = '0';
   579     }
   580     *bufp = '\0';
   581 
   582     /* The numbers went into the string backwards. :) */
   583     if (*string == '-') {
   584         SDL_strrev(string + 1);
   585     } else {
   586         SDL_strrev(string);
   587     }
   588 
   589     return string;
   590 }
   591 #endif
   592 
   593 #ifndef HAVE__UI64TOA
   594 char *
   595 SDL_ulltoa(Uint64 value, char *string, int radix)
   596 {
   597     char *bufp = string;
   598 
   599     if (value) {
   600         while (value > 0) {
   601             *bufp++ = ntoa_table[value % radix];
   602             value /= radix;
   603         }
   604     } else {
   605         *bufp++ = '0';
   606     }
   607     *bufp = '\0';
   608 
   609     /* The numbers went into the string backwards. :) */
   610     SDL_strrev(string);
   611 
   612     return string;
   613 }
   614 #endif
   615 
   616 #ifndef HAVE_STRTOLL
   617 Sint64
   618 SDL_strtoll(const char *string, char **endp, int base)
   619 {
   620     size_t len;
   621     Sint64 value;
   622 
   623     len = SDL_ScanLongLong(string, base ? base : 10, &value);
   624     if (endp) {
   625         *endp = (char *) string + len;
   626     }
   627     return value;
   628 }
   629 #endif
   630 
   631 #ifndef HAVE_STRTOULL
   632 Uint64
   633 SDL_strtoull(const char *string, char **endp, int base)
   634 {
   635     size_t len;
   636     Uint64 value;
   637 
   638     len = SDL_ScanUnsignedLongLong(string, base ? base : 10, &value);
   639     if (endp) {
   640         *endp = (char *) string + len;
   641     }
   642     return value;
   643 }
   644 #endif
   645 
   646 #endif /* SDL_HAS_64BIT_TYPE */
   647 
   648 #ifndef HAVE_STRTOD
   649 double
   650 SDL_strtod(const char *string, char **endp)
   651 {
   652     size_t len;
   653     double value;
   654 
   655     len = SDL_ScanFloat(string, &value);
   656     if (endp) {
   657         *endp = (char *) string + len;
   658     }
   659     return value;
   660 }
   661 #endif
   662 
   663 #ifndef HAVE_STRCMP
   664 int
   665 SDL_strcmp(const char *str1, const char *str2)
   666 {
   667     while (*str1 && *str2) {
   668         if (*str1 != *str2)
   669             break;
   670         ++str1;
   671         ++str2;
   672     }
   673     return (int) ((unsigned char) *str1 - (unsigned char) *str2);
   674 }
   675 #endif
   676 
   677 #ifndef HAVE_STRNCMP
   678 int
   679 SDL_strncmp(const char *str1, const char *str2, size_t maxlen)
   680 {
   681     while (*str1 && *str2 && maxlen) {
   682         if (*str1 != *str2)
   683             break;
   684         ++str1;
   685         ++str2;
   686         --maxlen;
   687     }
   688     if (!maxlen) {
   689         return 0;
   690     }
   691     return (int) ((unsigned char) *str1 - (unsigned char) *str2);
   692 }
   693 #endif
   694 
   695 #if !defined(HAVE_STRCASECMP) && !defined(HAVE__STRICMP)
   696 int
   697 SDL_strcasecmp(const char *str1, const char *str2)
   698 {
   699     char a = 0;
   700     char b = 0;
   701     while (*str1 && *str2) {
   702         a = SDL_tolower(*str1);
   703         b = SDL_tolower(*str2);
   704         if (a != b)
   705             break;
   706         ++str1;
   707         ++str2;
   708     }
   709     return (int) ((unsigned char) a - (unsigned char) b);
   710 }
   711 #endif
   712 
   713 #if !defined(HAVE_STRNCASECMP) && !defined(HAVE__STRNICMP)
   714 int
   715 SDL_strncasecmp(const char *str1, const char *str2, size_t maxlen)
   716 {
   717     char a = 0;
   718     char b = 0;
   719     while (*str1 && *str2 && maxlen) {
   720         a = SDL_tolower(*str1);
   721         b = SDL_tolower(*str2);
   722         if (a != b)
   723             break;
   724         ++str1;
   725         ++str2;
   726         --maxlen;
   727     }
   728     return (int) ((unsigned char) a - (unsigned char) b);
   729 }
   730 #endif
   731 
   732 #ifndef HAVE_SSCANF
   733 int
   734 SDL_sscanf(const char *text, const char *fmt, ...)
   735 {
   736     va_list ap;
   737     int retval = 0;
   738 
   739     va_start(ap, fmt);
   740     while (*fmt) {
   741         if (*fmt == ' ') {
   742             while (SDL_isspace(*text)) {
   743                 ++text;
   744             }
   745             ++fmt;
   746             continue;
   747         }
   748         if (*fmt == '%') {
   749             SDL_bool done = SDL_FALSE;
   750             long count = 0;
   751             int radix = 10;
   752             enum
   753             {
   754                 DO_SHORT,
   755                 DO_INT,
   756                 DO_LONG,
   757                 DO_LONGLONG
   758             } inttype = DO_INT;
   759             SDL_bool suppress = SDL_FALSE;
   760 
   761             ++fmt;
   762             if (*fmt == '%') {
   763                 if (*text == '%') {
   764                     ++text;
   765                     ++fmt;
   766                     continue;
   767                 }
   768                 break;
   769             }
   770             if (*fmt == '*') {
   771                 suppress = SDL_TRUE;
   772                 ++fmt;
   773             }
   774             fmt += SDL_ScanLong(fmt, 10, &count);
   775 
   776             if (*fmt == 'c') {
   777                 if (!count) {
   778                     count = 1;
   779                 }
   780                 if (suppress) {
   781                     while (count--) {
   782                         ++text;
   783                     }
   784                 } else {
   785                     char *valuep = va_arg(ap, char *);
   786                     while (count--) {
   787                         *valuep++ = *text++;
   788                     }
   789                     ++retval;
   790                 }
   791                 continue;
   792             }
   793 
   794             while (SDL_isspace(*text)) {
   795                 ++text;
   796             }
   797 
   798             /* FIXME: implement more of the format specifiers */
   799             while (!done) {
   800                 switch (*fmt) {
   801                 case '*':
   802                     suppress = SDL_TRUE;
   803                     break;
   804                 case 'h':
   805                     if (inttype > DO_SHORT) {
   806                         ++inttype;
   807                     }
   808                     break;
   809                 case 'l':
   810                     if (inttype < DO_LONGLONG) {
   811                         ++inttype;
   812                     }
   813                     break;
   814                 case 'I':
   815                     if (SDL_strncmp(fmt, "I64", 3) == 0) {
   816                         fmt += 2;
   817                         inttype = DO_LONGLONG;
   818                     }
   819                     break;
   820                 case 'i':
   821                     {
   822                         int index = 0;
   823                         if (text[index] == '-') {
   824                             ++index;
   825                         }
   826                         if (text[index] == '0') {
   827                             if (SDL_tolower(text[index + 1]) == 'x') {
   828                                 radix = 16;
   829                             } else {
   830                                 radix = 8;
   831                             }
   832                         }
   833                     }
   834                     /* Fall through to %d handling */
   835                 case 'd':
   836 #ifdef SDL_HAS_64BIT_TYPE
   837                     if (inttype == DO_LONGLONG) {
   838                         Sint64 value;
   839                         text += SDL_ScanLongLong(text, radix, &value);
   840                         if (!suppress) {
   841                             Sint64 *valuep = va_arg(ap, Sint64 *);
   842                             *valuep = value;
   843                             ++retval;
   844                         }
   845                     } else
   846 #endif /* SDL_HAS_64BIT_TYPE */
   847                     {
   848                         long value;
   849                         text += SDL_ScanLong(text, radix, &value);
   850                         if (!suppress) {
   851                             switch (inttype) {
   852                             case DO_SHORT:
   853                                 {
   854                                     short *valuep = va_arg(ap, short *);
   855                                     *valuep = (short) value;
   856                                 }
   857                                 break;
   858                             case DO_INT:
   859                                 {
   860                                     int *valuep = va_arg(ap, int *);
   861                                     *valuep = (int) value;
   862                                 }
   863                                 break;
   864                             case DO_LONG:
   865                                 {
   866                                     long *valuep = va_arg(ap, long *);
   867                                     *valuep = value;
   868                                 }
   869                                 break;
   870                             case DO_LONGLONG:
   871                                 /* Handled above */
   872                                 break;
   873                             }
   874                             ++retval;
   875                         }
   876                     }
   877                     done = SDL_TRUE;
   878                     break;
   879                 case 'o':
   880                     if (radix == 10) {
   881                         radix = 8;
   882                     }
   883                     /* Fall through to unsigned handling */
   884                 case 'x':
   885                 case 'X':
   886                     if (radix == 10) {
   887                         radix = 16;
   888                     }
   889                     /* Fall through to unsigned handling */
   890                 case 'u':
   891 #ifdef SDL_HAS_64BIT_TYPE
   892                     if (inttype == DO_LONGLONG) {
   893                         Uint64 value;
   894                         text += SDL_ScanUnsignedLongLong(text, radix, &value);
   895                         if (!suppress) {
   896                             Uint64 *valuep = va_arg(ap, Uint64 *);
   897                             *valuep = value;
   898                             ++retval;
   899                         }
   900                     } else
   901 #endif /* SDL_HAS_64BIT_TYPE */
   902                     {
   903                         unsigned long value;
   904                         text += SDL_ScanUnsignedLong(text, radix, &value);
   905                         if (!suppress) {
   906                             switch (inttype) {
   907                             case DO_SHORT:
   908                                 {
   909                                     short *valuep = va_arg(ap, short *);
   910                                     *valuep = (short) value;
   911                                 }
   912                                 break;
   913                             case DO_INT:
   914                                 {
   915                                     int *valuep = va_arg(ap, int *);
   916                                     *valuep = (int) value;
   917                                 }
   918                                 break;
   919                             case DO_LONG:
   920                                 {
   921                                     long *valuep = va_arg(ap, long *);
   922                                     *valuep = value;
   923                                 }
   924                                 break;
   925                             case DO_LONGLONG:
   926                                 /* Handled above */
   927                                 break;
   928                             }
   929                             ++retval;
   930                         }
   931                     }
   932                     done = SDL_TRUE;
   933                     break;
   934                 case 'p':
   935                     {
   936                         uintptr_t value;
   937                         text += SDL_ScanUintPtrT(text, 16, &value);
   938                         if (!suppress) {
   939                             void **valuep = va_arg(ap, void **);
   940                             *valuep = (void *) value;
   941                             ++retval;
   942                         }
   943                     }
   944                     done = SDL_TRUE;
   945                     break;
   946                 case 'f':
   947                     {
   948                         double value;
   949                         text += SDL_ScanFloat(text, &value);
   950                         if (!suppress) {
   951                             float *valuep = va_arg(ap, float *);
   952                             *valuep = (float) value;
   953                             ++retval;
   954                         }
   955                     }
   956                     done = SDL_TRUE;
   957                     break;
   958                 case 's':
   959                     if (suppress) {
   960                         while (!SDL_isspace(*text)) {
   961                             ++text;
   962                             if (count) {
   963                                 if (--count == 0) {
   964                                     break;
   965                                 }
   966                             }
   967                         }
   968                     } else {
   969                         char *valuep = va_arg(ap, char *);
   970                         while (!SDL_isspace(*text)) {
   971                             *valuep++ = *text++;
   972                             if (count) {
   973                                 if (--count == 0) {
   974                                     break;
   975                                 }
   976                             }
   977                         }
   978                         *valuep = '\0';
   979                         ++retval;
   980                     }
   981                     done = SDL_TRUE;
   982                     break;
   983                 default:
   984                     done = SDL_TRUE;
   985                     break;
   986                 }
   987                 ++fmt;
   988             }
   989             continue;
   990         }
   991         if (*text == *fmt) {
   992             ++text;
   993             ++fmt;
   994             continue;
   995         }
   996         /* Text didn't match format specifier */
   997         break;
   998     }
   999     va_end(ap);
  1000 
  1001     return retval;
  1002 }
  1003 #endif
  1004 
  1005 #ifndef HAVE_SNPRINTF
  1006 int
  1007 SDL_snprintf(char *text, size_t maxlen, const char *fmt, ...)
  1008 {
  1009     va_list ap;
  1010     int retval;
  1011 
  1012     va_start(ap, fmt);
  1013     retval = SDL_vsnprintf(text, maxlen, fmt, ap);
  1014     va_end(ap);
  1015 
  1016     return retval;
  1017 }
  1018 #endif
  1019 
  1020 #ifndef HAVE_VSNPRINTF
  1021 static size_t
  1022 SDL_PrintLong(char *text, long value, int radix, size_t maxlen)
  1023 {
  1024     char num[130];
  1025     size_t size;
  1026 
  1027     SDL_ltoa(value, num, radix);
  1028     size = SDL_strlen(num);
  1029     if (size >= maxlen) {
  1030         size = maxlen - 1;
  1031     }
  1032     SDL_strlcpy(text, num, size + 1);
  1033 
  1034     return size;
  1035 }
  1036 
  1037 static size_t
  1038 SDL_PrintUnsignedLong(char *text, unsigned long value, int radix,
  1039                       size_t maxlen)
  1040 {
  1041     char num[130];
  1042     size_t size;
  1043 
  1044     SDL_ultoa(value, num, radix);
  1045     size = SDL_strlen(num);
  1046     if (size >= maxlen) {
  1047         size = maxlen - 1;
  1048     }
  1049     SDL_strlcpy(text, num, size + 1);
  1050 
  1051     return size;
  1052 }
  1053 
  1054 #ifdef SDL_HAS_64BIT_TYPE
  1055 static size_t
  1056 SDL_PrintLongLong(char *text, Sint64 value, int radix, size_t maxlen)
  1057 {
  1058     char num[130];
  1059     size_t size;
  1060 
  1061     SDL_lltoa(value, num, radix);
  1062     size = SDL_strlen(num);
  1063     if (size >= maxlen) {
  1064         size = maxlen - 1;
  1065     }
  1066     SDL_strlcpy(text, num, size + 1);
  1067 
  1068     return size;
  1069 }
  1070 
  1071 static size_t
  1072 SDL_PrintUnsignedLongLong(char *text, Uint64 value, int radix, size_t maxlen)
  1073 {
  1074     char num[130];
  1075     size_t size;
  1076 
  1077     SDL_ulltoa(value, num, radix);
  1078     size = SDL_strlen(num);
  1079     if (size >= maxlen) {
  1080         size = maxlen - 1;
  1081     }
  1082     SDL_strlcpy(text, num, size + 1);
  1083 
  1084     return size;
  1085 }
  1086 #endif /* SDL_HAS_64BIT_TYPE */
  1087 static size_t
  1088 SDL_PrintFloat(char *text, double arg, size_t maxlen)
  1089 {
  1090     char *textstart = text;
  1091     if (arg) {
  1092         /* This isn't especially accurate, but hey, it's easy. :) */
  1093         const double precision = 0.00000001;
  1094         size_t len;
  1095         unsigned long value;
  1096 
  1097         if (arg < 0) {
  1098             *text++ = '-';
  1099             --maxlen;
  1100             arg = -arg;
  1101         }
  1102         value = (unsigned long) arg;
  1103         len = SDL_PrintUnsignedLong(text, value, 10, maxlen);
  1104         text += len;
  1105         maxlen -= len;
  1106         arg -= value;
  1107         if (arg > precision && maxlen) {
  1108             int mult = 10;
  1109             *text++ = '.';
  1110             while ((arg > precision) && maxlen) {
  1111                 value = (unsigned long) (arg * mult);
  1112                 len = SDL_PrintUnsignedLong(text, value, 10, maxlen);
  1113                 text += len;
  1114                 maxlen -= len;
  1115                 arg -= (double) value / mult;
  1116                 mult *= 10;
  1117             }
  1118         }
  1119     } else {
  1120         *text++ = '0';
  1121     }
  1122     return (text - textstart);
  1123 }
  1124 
  1125 static size_t
  1126 SDL_PrintString(char *text, const char *string, size_t maxlen)
  1127 {
  1128     char *textstart = text;
  1129     while (*string && maxlen--) {
  1130         *text++ = *string++;
  1131     }
  1132     return (text - textstart);
  1133 }
  1134 
  1135 int
  1136 SDL_vsnprintf(char *text, size_t maxlen, const char *fmt, va_list ap)
  1137 {
  1138     char *textstart = text;
  1139     if (maxlen <= 0) {
  1140         return 0;
  1141     }
  1142     --maxlen;                   /* For the trailing '\0' */
  1143     while (*fmt && maxlen) {
  1144         if (*fmt == '%') {
  1145             SDL_bool done = SDL_FALSE;
  1146             size_t len = 0;
  1147             SDL_bool do_lowercase = SDL_FALSE;
  1148             int radix = 10;
  1149             enum
  1150             {
  1151                 DO_INT,
  1152                 DO_LONG,
  1153                 DO_LONGLONG
  1154             } inttype = DO_INT;
  1155 
  1156             ++fmt;
  1157             /* FIXME: implement more of the format specifiers */
  1158             while (*fmt == '.' || (*fmt >= '0' && *fmt <= '9')) {
  1159                 ++fmt;
  1160             }
  1161             while (!done) {
  1162                 switch (*fmt) {
  1163                 case '%':
  1164                     *text = '%';
  1165                     len = 1;
  1166                     done = SDL_TRUE;
  1167                     break;
  1168                 case 'c':
  1169                     /* char is promoted to int when passed through (...) */
  1170                     *text = (char) va_arg(ap, int);
  1171                     len = 1;
  1172                     done = SDL_TRUE;
  1173                     break;
  1174                 case 'h':
  1175                     /* short is promoted to int when passed through (...) */
  1176                     break;
  1177                 case 'l':
  1178                     if (inttype < DO_LONGLONG) {
  1179                         ++inttype;
  1180                     }
  1181                     break;
  1182                 case 'I':
  1183                     if (SDL_strncmp(fmt, "I64", 3) == 0) {
  1184                         fmt += 2;
  1185                         inttype = DO_LONGLONG;
  1186                     }
  1187                     break;
  1188                 case 'i':
  1189                 case 'd':
  1190                     switch (inttype) {
  1191                     case DO_INT:
  1192                         len =
  1193                             SDL_PrintLong(text,
  1194                                           (long) va_arg(ap, int),
  1195                                           radix, maxlen);
  1196                         break;
  1197                     case DO_LONG:
  1198                         len =
  1199                             SDL_PrintLong(text, va_arg(ap, long),
  1200                                           radix, maxlen);
  1201                         break;
  1202                     case DO_LONGLONG:
  1203 #ifdef SDL_HAS_64BIT_TYPE
  1204                         len =
  1205                             SDL_PrintLongLong(text,
  1206                                               va_arg(ap, Sint64),
  1207                                               radix, maxlen);
  1208 #else
  1209                         len =
  1210                             SDL_PrintLong(text, va_arg(ap, long),
  1211                                           radix, maxlen);
  1212 #endif
  1213                         break;
  1214                     }
  1215                     done = SDL_TRUE;
  1216                     break;
  1217                 case 'p':
  1218                 case 'x':
  1219                     do_lowercase = SDL_TRUE;
  1220                     /* Fall through to 'X' handling */
  1221                 case 'X':
  1222                     if (radix == 10) {
  1223                         radix = 16;
  1224                     }
  1225                     if (*fmt == 'p') {
  1226                         inttype = DO_LONG;
  1227                     }
  1228                     /* Fall through to unsigned handling */
  1229                 case 'o':
  1230                     if (radix == 10) {
  1231                         radix = 8;
  1232                     }
  1233                     /* Fall through to unsigned handling */
  1234                 case 'u':
  1235                     switch (inttype) {
  1236                     case DO_INT:
  1237                         len = SDL_PrintUnsignedLong(text, (unsigned long)
  1238                                                     va_arg(ap,
  1239                                                            unsigned
  1240                                                            int),
  1241                                                     radix, maxlen);
  1242                         break;
  1243                     case DO_LONG:
  1244                         len =
  1245                             SDL_PrintUnsignedLong(text,
  1246                                                   va_arg(ap,
  1247                                                          unsigned
  1248                                                          long),
  1249                                                   radix, maxlen);
  1250                         break;
  1251                     case DO_LONGLONG:
  1252 #ifdef SDL_HAS_64BIT_TYPE
  1253                         len =
  1254                             SDL_PrintUnsignedLongLong(text,
  1255                                                       va_arg(ap,
  1256                                                              Uint64),
  1257                                                       radix, maxlen);
  1258 #else
  1259                         len =
  1260                             SDL_PrintUnsignedLong(text,
  1261                                                   va_arg(ap,
  1262                                                          unsigned
  1263                                                          long),
  1264                                                   radix, maxlen);
  1265 #endif
  1266                         break;
  1267                     }
  1268                     if (do_lowercase) {
  1269                         SDL_strlwr(text);
  1270                     }
  1271                     done = SDL_TRUE;
  1272                     break;
  1273                 case 'f':
  1274                     len = SDL_PrintFloat(text, va_arg(ap, double), maxlen);
  1275                     done = SDL_TRUE;
  1276                     break;
  1277                 case 's':
  1278                     len = SDL_PrintString(text, va_arg(ap, char *), maxlen);
  1279                     done = SDL_TRUE;
  1280                     break;
  1281                 default:
  1282                     done = SDL_TRUE;
  1283                     break;
  1284                 }
  1285                 ++fmt;
  1286             }
  1287             text += len;
  1288             maxlen -= len;
  1289         } else {
  1290             *text++ = *fmt++;
  1291             --maxlen;
  1292         }
  1293     }
  1294     *text = '\0';
  1295 
  1296     return (text - textstart);
  1297 }
  1298 #endif
  1299 /* vi: set ts=4 sw=4 expandtab: */