src/stdlib/SDL_string.c
author Sam Lantinga
Mon, 10 Jul 2006 21:04:37 +0000
changeset 1895 c121d94672cb
parent 1867 887c3600826b
child 1901 f1828a500391
permissions -rw-r--r--
SDL 1.2 is moving to a branch, and SDL 1.3 is becoming the head.
     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     if (!base) {
   538         if ((SDL_strlen(string) > 2) && (SDL_strncmp(string, "0x", 2) == 0)) {
   539             base = 16;
   540         } else {
   541             base = 10;
   542         }
   543     }
   544 
   545     len = SDL_ScanLong(string, base, &value);
   546     if (endp) {
   547         *endp = (char *) string + len;
   548     }
   549     return value;
   550 }
   551 #endif
   552 
   553 #ifndef HAVE_STRTOUL
   554 unsigned long
   555 SDL_strtoul(const char *string, char **endp, int base)
   556 {
   557     size_t len;
   558     unsigned long value;
   559 
   560     if (!base) {
   561         if ((SDL_strlen(string) > 2) && (SDL_strncmp(string, "0x", 2) == 0)) {
   562             base = 16;
   563         } else {
   564             base = 10;
   565         }
   566     }
   567 
   568     len = SDL_ScanUnsignedLong(string, base, &value);
   569     if (endp) {
   570         *endp = (char *) string + len;
   571     }
   572     return value;
   573 }
   574 #endif
   575 
   576 #ifdef SDL_HAS_64BIT_TYPE
   577 
   578 #ifndef HAVE__I64TOA
   579 char *
   580 SDL_lltoa(Sint64 value, char *string, int radix)
   581 {
   582     char *bufp = string;
   583 
   584     if (value < 0) {
   585         *bufp++ = '-';
   586         value = -value;
   587     }
   588     if (value) {
   589         while (value > 0) {
   590             *bufp++ = ntoa_table[value % radix];
   591             value /= radix;
   592         }
   593     } else {
   594         *bufp++ = '0';
   595     }
   596     *bufp = '\0';
   597 
   598     /* The numbers went into the string backwards. :) */
   599     if (*string == '-') {
   600         SDL_strrev(string + 1);
   601     } else {
   602         SDL_strrev(string);
   603     }
   604 
   605     return string;
   606 }
   607 #endif
   608 
   609 #ifndef HAVE__UI64TOA
   610 char *
   611 SDL_ulltoa(Uint64 value, char *string, int radix)
   612 {
   613     char *bufp = string;
   614 
   615     if (value) {
   616         while (value > 0) {
   617             *bufp++ = ntoa_table[value % radix];
   618             value /= radix;
   619         }
   620     } else {
   621         *bufp++ = '0';
   622     }
   623     *bufp = '\0';
   624 
   625     /* The numbers went into the string backwards. :) */
   626     SDL_strrev(string);
   627 
   628     return string;
   629 }
   630 #endif
   631 
   632 #ifndef HAVE_STRTOLL
   633 Sint64
   634 SDL_strtoll(const char *string, char **endp, int base)
   635 {
   636     size_t len;
   637     Sint64 value;
   638 
   639     if (!base) {
   640         if ((SDL_strlen(string) > 2) && (SDL_strncmp(string, "0x", 2) == 0)) {
   641             base = 16;
   642         } else {
   643             base = 10;
   644         }
   645     }
   646 
   647     len = SDL_ScanLongLong(string, base, &value);
   648     if (endp) {
   649         *endp = (char *) string + len;
   650     }
   651     return value;
   652 }
   653 #endif
   654 
   655 #ifndef HAVE_STRTOULL
   656 Uint64
   657 SDL_strtoull(const char *string, char **endp, int base)
   658 {
   659     size_t len;
   660     Uint64 value;
   661 
   662     if (!base) {
   663         if ((SDL_strlen(string) > 2) && (SDL_strncmp(string, "0x", 2) == 0)) {
   664             base = 16;
   665         } else {
   666             base = 10;
   667         }
   668     }
   669 
   670     len = SDL_ScanUnsignedLongLong(string, base, &value);
   671     if (endp) {
   672         *endp = (char *) string + len;
   673     }
   674     return value;
   675 }
   676 #endif
   677 
   678 #endif /* SDL_HAS_64BIT_TYPE */
   679 
   680 #ifndef HAVE_STRTOD
   681 double
   682 SDL_strtod(const char *string, char **endp)
   683 {
   684     size_t len;
   685     double value;
   686 
   687     len = SDL_ScanFloat(string, &value);
   688     if (endp) {
   689         *endp = (char *) string + len;
   690     }
   691     return value;
   692 }
   693 #endif
   694 
   695 #ifndef HAVE_STRCMP
   696 int
   697 SDL_strcmp(const char *str1, const char *str2)
   698 {
   699     while (*str1 && *str2) {
   700         if (*str1 != *str2)
   701             break;
   702         ++str1;
   703         ++str2;
   704     }
   705     return (int) ((unsigned char) *str1 - (unsigned char) *str2);
   706 }
   707 #endif
   708 
   709 #ifndef HAVE_STRNCMP
   710 int
   711 SDL_strncmp(const char *str1, const char *str2, size_t maxlen)
   712 {
   713     while (*str1 && *str2 && maxlen) {
   714         if (*str1 != *str2)
   715             break;
   716         ++str1;
   717         ++str2;
   718         --maxlen;
   719     }
   720     if (!maxlen) {
   721         return 0;
   722     }
   723     return (int) ((unsigned char) *str1 - (unsigned char) *str2);
   724 }
   725 #endif
   726 
   727 #if !defined(HAVE_STRCASECMP) && !defined(HAVE__STRICMP)
   728 int
   729 SDL_strcasecmp(const char *str1, const char *str2)
   730 {
   731     char a = 0;
   732     char b = 0;
   733     while (*str1 && *str2) {
   734         a = SDL_tolower(*str1);
   735         b = SDL_tolower(*str2);
   736         if (a != b)
   737             break;
   738         ++str1;
   739         ++str2;
   740     }
   741     return (int) ((unsigned char) a - (unsigned char) b);
   742 }
   743 #endif
   744 
   745 #if !defined(HAVE_STRNCASECMP) && !defined(HAVE__STRNICMP)
   746 int
   747 SDL_strncasecmp(const char *str1, const char *str2, size_t maxlen)
   748 {
   749     char a = 0;
   750     char b = 0;
   751     while (*str1 && *str2 && maxlen) {
   752         a = SDL_tolower(*str1);
   753         b = SDL_tolower(*str2);
   754         if (a != b)
   755             break;
   756         ++str1;
   757         ++str2;
   758         --maxlen;
   759     }
   760     return (int) ((unsigned char) a - (unsigned char) b);
   761 }
   762 #endif
   763 
   764 #ifndef HAVE_SSCANF
   765 int
   766 SDL_sscanf(const char *text, const char *fmt, ...)
   767 {
   768     va_list ap;
   769     int retval = 0;
   770 
   771     va_start(ap, fmt);
   772     while (*fmt) {
   773         if (*fmt == ' ') {
   774             while (SDL_isspace(*text)) {
   775                 ++text;
   776             }
   777             ++fmt;
   778             continue;
   779         }
   780         if (*fmt == '%') {
   781             SDL_bool done = SDL_FALSE;
   782             long count = 0;
   783             int radix = 10;
   784             enum
   785             {
   786                 DO_SHORT,
   787                 DO_INT,
   788                 DO_LONG,
   789                 DO_LONGLONG
   790             } inttype = DO_INT;
   791             SDL_bool suppress = SDL_FALSE;
   792 
   793             ++fmt;
   794             if (*fmt == '%') {
   795                 if (*text == '%') {
   796                     ++text;
   797                     ++fmt;
   798                     continue;
   799                 }
   800                 break;
   801             }
   802             if (*fmt == '*') {
   803                 suppress = SDL_TRUE;
   804                 ++fmt;
   805             }
   806             fmt += SDL_ScanLong(fmt, 10, &count);
   807 
   808             if (*fmt == 'c') {
   809                 if (!count) {
   810                     count = 1;
   811                 }
   812                 if (suppress) {
   813                     while (count--) {
   814                         ++text;
   815                     }
   816                 } else {
   817                     char *valuep = va_arg(ap, char *);
   818                     while (count--) {
   819                         *valuep++ = *text++;
   820                     }
   821                     ++retval;
   822                 }
   823                 continue;
   824             }
   825 
   826             while (SDL_isspace(*text)) {
   827                 ++text;
   828             }
   829 
   830             /* FIXME: implement more of the format specifiers */
   831             while (!done) {
   832                 switch (*fmt) {
   833                 case '*':
   834                     suppress = SDL_TRUE;
   835                     break;
   836                 case 'h':
   837                     if (inttype > DO_SHORT) {
   838                         ++inttype;
   839                     }
   840                     break;
   841                 case 'l':
   842                     if (inttype < DO_LONGLONG) {
   843                         ++inttype;
   844                     }
   845                     break;
   846                 case 'I':
   847                     if (SDL_strncmp(fmt, "I64", 3) == 0) {
   848                         fmt += 2;
   849                         inttype = DO_LONGLONG;
   850                     }
   851                     break;
   852                 case 'i':
   853                     {
   854                         int index = 0;
   855                         if (text[index] == '-') {
   856                             ++index;
   857                         }
   858                         if (text[index] == '0') {
   859                             if (SDL_tolower(text[index + 1]) == 'x') {
   860                                 radix = 16;
   861                             } else {
   862                                 radix = 8;
   863                             }
   864                         }
   865                     }
   866                     /* Fall through to %d handling */
   867                 case 'd':
   868 #ifdef SDL_HAS_64BIT_TYPE
   869                     if (inttype == DO_LONGLONG) {
   870                         Sint64 value;
   871                         text += SDL_ScanLongLong(text, radix, &value);
   872                         if (!suppress) {
   873                             Sint64 *valuep = va_arg(ap, Sint64 *);
   874                             *valuep = value;
   875                             ++retval;
   876                         }
   877                     } else
   878 #endif /* SDL_HAS_64BIT_TYPE */
   879                     {
   880                         long value;
   881                         text += SDL_ScanLong(text, radix, &value);
   882                         if (!suppress) {
   883                             switch (inttype) {
   884                             case DO_SHORT:
   885                                 {
   886                                     short *valuep = va_arg(ap, short *);
   887                                     *valuep = (short) value;
   888                                 }
   889                                 break;
   890                             case DO_INT:
   891                                 {
   892                                     int *valuep = va_arg(ap, int *);
   893                                     *valuep = (int) value;
   894                                 }
   895                                 break;
   896                             case DO_LONG:
   897                                 {
   898                                     long *valuep = va_arg(ap, long *);
   899                                     *valuep = value;
   900                                 }
   901                                 break;
   902                             case DO_LONGLONG:
   903                                 /* Handled above */
   904                                 break;
   905                             }
   906                             ++retval;
   907                         }
   908                     }
   909                     done = SDL_TRUE;
   910                     break;
   911                 case 'o':
   912                     if (radix == 10) {
   913                         radix = 8;
   914                     }
   915                     /* Fall through to unsigned handling */
   916                 case 'x':
   917                 case 'X':
   918                     if (radix == 10) {
   919                         radix = 16;
   920                     }
   921                     /* Fall through to unsigned handling */
   922                 case 'u':
   923 #ifdef SDL_HAS_64BIT_TYPE
   924                     if (inttype == DO_LONGLONG) {
   925                         Uint64 value;
   926                         text += SDL_ScanUnsignedLongLong(text, radix, &value);
   927                         if (!suppress) {
   928                             Uint64 *valuep = va_arg(ap, Uint64 *);
   929                             *valuep = value;
   930                             ++retval;
   931                         }
   932                     } else
   933 #endif /* SDL_HAS_64BIT_TYPE */
   934                     {
   935                         unsigned long value;
   936                         text += SDL_ScanUnsignedLong(text, radix, &value);
   937                         if (!suppress) {
   938                             switch (inttype) {
   939                             case DO_SHORT:
   940                                 {
   941                                     short *valuep = va_arg(ap, short *);
   942                                     *valuep = (short) value;
   943                                 }
   944                                 break;
   945                             case DO_INT:
   946                                 {
   947                                     int *valuep = va_arg(ap, int *);
   948                                     *valuep = (int) value;
   949                                 }
   950                                 break;
   951                             case DO_LONG:
   952                                 {
   953                                     long *valuep = va_arg(ap, long *);
   954                                     *valuep = value;
   955                                 }
   956                                 break;
   957                             case DO_LONGLONG:
   958                                 /* Handled above */
   959                                 break;
   960                             }
   961                             ++retval;
   962                         }
   963                     }
   964                     done = SDL_TRUE;
   965                     break;
   966                 case 'p':
   967                     {
   968                         uintptr_t value;
   969                         text += SDL_ScanUintPtrT(text, 16, &value);
   970                         if (!suppress) {
   971                             void **valuep = va_arg(ap, void **);
   972                             *valuep = (void *) value;
   973                             ++retval;
   974                         }
   975                     }
   976                     done = SDL_TRUE;
   977                     break;
   978                 case 'f':
   979                     {
   980                         double value;
   981                         text += SDL_ScanFloat(text, &value);
   982                         if (!suppress) {
   983                             float *valuep = va_arg(ap, float *);
   984                             *valuep = (float) value;
   985                             ++retval;
   986                         }
   987                     }
   988                     done = SDL_TRUE;
   989                     break;
   990                 case 's':
   991                     if (suppress) {
   992                         while (!SDL_isspace(*text)) {
   993                             ++text;
   994                             if (count) {
   995                                 if (--count == 0) {
   996                                     break;
   997                                 }
   998                             }
   999                         }
  1000                     } else {
  1001                         char *valuep = va_arg(ap, char *);
  1002                         while (!SDL_isspace(*text)) {
  1003                             *valuep++ = *text++;
  1004                             if (count) {
  1005                                 if (--count == 0) {
  1006                                     break;
  1007                                 }
  1008                             }
  1009                         }
  1010                         *valuep = '\0';
  1011                         ++retval;
  1012                     }
  1013                     done = SDL_TRUE;
  1014                     break;
  1015                 default:
  1016                     done = SDL_TRUE;
  1017                     break;
  1018                 }
  1019                 ++fmt;
  1020             }
  1021             continue;
  1022         }
  1023         if (*text == *fmt) {
  1024             ++text;
  1025             ++fmt;
  1026             continue;
  1027         }
  1028         /* Text didn't match format specifier */
  1029         break;
  1030     }
  1031     va_end(ap);
  1032 
  1033     return retval;
  1034 }
  1035 #endif
  1036 
  1037 #ifndef HAVE_SNPRINTF
  1038 int
  1039 SDL_snprintf(char *text, size_t maxlen, const char *fmt, ...)
  1040 {
  1041     va_list ap;
  1042     int retval;
  1043 
  1044     va_start(ap, fmt);
  1045     retval = SDL_vsnprintf(text, maxlen, fmt, ap);
  1046     va_end(ap);
  1047 
  1048     return retval;
  1049 }
  1050 #endif
  1051 
  1052 #ifndef HAVE_VSNPRINTF
  1053 static size_t
  1054 SDL_PrintLong(char *text, long value, int radix, size_t maxlen)
  1055 {
  1056     char num[130];
  1057     size_t size;
  1058 
  1059     SDL_ltoa(value, num, radix);
  1060     size = SDL_strlen(num);
  1061     if (size >= maxlen) {
  1062         size = maxlen - 1;
  1063     }
  1064     SDL_strlcpy(text, num, size + 1);
  1065 
  1066     return size;
  1067 }
  1068 
  1069 static size_t
  1070 SDL_PrintUnsignedLong(char *text, unsigned long value, int radix,
  1071                       size_t maxlen)
  1072 {
  1073     char num[130];
  1074     size_t size;
  1075 
  1076     SDL_ultoa(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 #ifdef SDL_HAS_64BIT_TYPE
  1087 static size_t
  1088 SDL_PrintLongLong(char *text, Sint64 value, int radix, size_t maxlen)
  1089 {
  1090     char num[130];
  1091     size_t size;
  1092 
  1093     SDL_lltoa(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 static size_t
  1104 SDL_PrintUnsignedLongLong(char *text, Uint64 value, int radix, size_t maxlen)
  1105 {
  1106     char num[130];
  1107     size_t size;
  1108 
  1109     SDL_ulltoa(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 #endif /* SDL_HAS_64BIT_TYPE */
  1119 static size_t
  1120 SDL_PrintFloat(char *text, double arg, size_t maxlen)
  1121 {
  1122     char *textstart = text;
  1123     if (arg) {
  1124         /* This isn't especially accurate, but hey, it's easy. :) */
  1125         const double precision = 0.00000001;
  1126         size_t len;
  1127         unsigned long value;
  1128 
  1129         if (arg < 0) {
  1130             *text++ = '-';
  1131             --maxlen;
  1132             arg = -arg;
  1133         }
  1134         value = (unsigned long) arg;
  1135         len = SDL_PrintUnsignedLong(text, value, 10, maxlen);
  1136         text += len;
  1137         maxlen -= len;
  1138         arg -= value;
  1139         if (arg > precision && maxlen) {
  1140             int mult = 10;
  1141             *text++ = '.';
  1142             while ((arg > precision) && maxlen) {
  1143                 value = (unsigned long) (arg * mult);
  1144                 len = SDL_PrintUnsignedLong(text, value, 10, maxlen);
  1145                 text += len;
  1146                 maxlen -= len;
  1147                 arg -= (double) value / mult;
  1148                 mult *= 10;
  1149             }
  1150         }
  1151     } else {
  1152         *text++ = '0';
  1153     }
  1154     return (text - textstart);
  1155 }
  1156 
  1157 static size_t
  1158 SDL_PrintString(char *text, const char *string, size_t maxlen)
  1159 {
  1160     char *textstart = text;
  1161     while (*string && maxlen--) {
  1162         *text++ = *string++;
  1163     }
  1164     return (text - textstart);
  1165 }
  1166 
  1167 int
  1168 SDL_vsnprintf(char *text, size_t maxlen, const char *fmt, va_list ap)
  1169 {
  1170     char *textstart = text;
  1171     if (maxlen <= 0) {
  1172         return 0;
  1173     }
  1174     --maxlen;                   /* For the trailing '\0' */
  1175     while (*fmt && maxlen) {
  1176         if (*fmt == '%') {
  1177             SDL_bool done = SDL_FALSE;
  1178             size_t len = 0;
  1179             SDL_bool do_lowercase = SDL_FALSE;
  1180             int radix = 10;
  1181             enum
  1182             {
  1183                 DO_INT,
  1184                 DO_LONG,
  1185                 DO_LONGLONG
  1186             } inttype = DO_INT;
  1187 
  1188             ++fmt;
  1189             /* FIXME: implement more of the format specifiers */
  1190             while (*fmt == '.' || (*fmt >= '0' && *fmt <= '9')) {
  1191                 ++fmt;
  1192             }
  1193             while (!done) {
  1194                 switch (*fmt) {
  1195                 case '%':
  1196                     *text = '%';
  1197                     len = 1;
  1198                     done = SDL_TRUE;
  1199                     break;
  1200                 case 'c':
  1201                     /* char is promoted to int when passed through (...) */
  1202                     *text = (char) va_arg(ap, int);
  1203                     len = 1;
  1204                     done = SDL_TRUE;
  1205                     break;
  1206                 case 'h':
  1207                     /* short is promoted to int when passed through (...) */
  1208                     break;
  1209                 case 'l':
  1210                     if (inttype < DO_LONGLONG) {
  1211                         ++inttype;
  1212                     }
  1213                     break;
  1214                 case 'I':
  1215                     if (SDL_strncmp(fmt, "I64", 3) == 0) {
  1216                         fmt += 2;
  1217                         inttype = DO_LONGLONG;
  1218                     }
  1219                     break;
  1220                 case 'i':
  1221                 case 'd':
  1222                     switch (inttype) {
  1223                     case DO_INT:
  1224                         len =
  1225                             SDL_PrintLong(text,
  1226                                           (long) va_arg(ap, int),
  1227                                           radix, maxlen);
  1228                         break;
  1229                     case DO_LONG:
  1230                         len =
  1231                             SDL_PrintLong(text, va_arg(ap, long),
  1232                                           radix, maxlen);
  1233                         break;
  1234                     case DO_LONGLONG:
  1235 #ifdef SDL_HAS_64BIT_TYPE
  1236                         len =
  1237                             SDL_PrintLongLong(text,
  1238                                               va_arg(ap, Sint64),
  1239                                               radix, maxlen);
  1240 #else
  1241                         len =
  1242                             SDL_PrintLong(text, va_arg(ap, long),
  1243                                           radix, maxlen);
  1244 #endif
  1245                         break;
  1246                     }
  1247                     done = SDL_TRUE;
  1248                     break;
  1249                 case 'p':
  1250                 case 'x':
  1251                     do_lowercase = SDL_TRUE;
  1252                     /* Fall through to 'X' handling */
  1253                 case 'X':
  1254                     if (radix == 10) {
  1255                         radix = 16;
  1256                     }
  1257                     if (*fmt == 'p') {
  1258                         inttype = DO_LONG;
  1259                     }
  1260                     /* Fall through to unsigned handling */
  1261                 case 'o':
  1262                     if (radix == 10) {
  1263                         radix = 8;
  1264                     }
  1265                     /* Fall through to unsigned handling */
  1266                 case 'u':
  1267                     switch (inttype) {
  1268                     case DO_INT:
  1269                         len = SDL_PrintUnsignedLong(text, (unsigned long)
  1270                                                     va_arg(ap,
  1271                                                            unsigned
  1272                                                            int),
  1273                                                     radix, maxlen);
  1274                         break;
  1275                     case DO_LONG:
  1276                         len =
  1277                             SDL_PrintUnsignedLong(text,
  1278                                                   va_arg(ap,
  1279                                                          unsigned
  1280                                                          long),
  1281                                                   radix, maxlen);
  1282                         break;
  1283                     case DO_LONGLONG:
  1284 #ifdef SDL_HAS_64BIT_TYPE
  1285                         len =
  1286                             SDL_PrintUnsignedLongLong(text,
  1287                                                       va_arg(ap,
  1288                                                              Uint64),
  1289                                                       radix, maxlen);
  1290 #else
  1291                         len =
  1292                             SDL_PrintUnsignedLong(text,
  1293                                                   va_arg(ap,
  1294                                                          unsigned
  1295                                                          long),
  1296                                                   radix, maxlen);
  1297 #endif
  1298                         break;
  1299                     }
  1300                     if (do_lowercase) {
  1301                         SDL_strlwr(text);
  1302                     }
  1303                     done = SDL_TRUE;
  1304                     break;
  1305                 case 'f':
  1306                     len = SDL_PrintFloat(text, va_arg(ap, double), maxlen);
  1307                     done = SDL_TRUE;
  1308                     break;
  1309                 case 's':
  1310                     len = SDL_PrintString(text, va_arg(ap, char *), maxlen);
  1311                     done = SDL_TRUE;
  1312                     break;
  1313                 default:
  1314                     done = SDL_TRUE;
  1315                     break;
  1316                 }
  1317                 ++fmt;
  1318             }
  1319             text += len;
  1320             maxlen -= len;
  1321         } else {
  1322             *text++ = *fmt++;
  1323             --maxlen;
  1324         }
  1325     }
  1326     *text = '\0';
  1327 
  1328     return (text - textstart);
  1329 }
  1330 #endif
  1331 /* vi: set ts=4 sw=4 expandtab: */