src/stdlib/SDL_string.c
author Sam Lantinga
Sun, 28 May 2006 13:04:16 +0000
branchSDL-1.3
changeset 1662 782fd950bd46
parent 1659 14717b52abc0
child 1668 4da1ee79c9af
permissions -rw-r--r--
Revamp of the video system in progress - adding support for multiple displays, multiple windows, and a full video mode selection API.

WARNING: None of the video drivers have been updated for the new API yet! The API is still under design and very fluid.

The code is now run through a consistent indent format:
indent -i4 -nut -nsc -br -ce

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