2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2009 Sam Lantinga
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.
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.
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
22 #include "SDL_config.h"
24 /* This file contains portable string manipulation functions for SDL */
26 #include "SDL_stdinc.h"
29 #define SDL_isupperhex(X) (((X) >= 'A') && ((X) <= 'F'))
30 #define SDL_islowerhex(X) (((X) >= 'a') && ((X) <= 'f'))
32 #if !defined(HAVE_SSCANF) || !defined(HAVE_STRTOL)
33 static size_t SDL_ScanLong(const char *text, int radix, long *valuep)
35 const char *textstart = text;
37 SDL_bool negative = SDL_FALSE;
43 if ( radix == 16 && SDL_strncmp(text, "0x", 2) == 0 ) {
48 if ( SDL_isdigit((unsigned char) *text) ) {
50 } else if ( radix == 16 && SDL_isupperhex(*text) ) {
51 v = 10 + (*text - 'A');
52 } else if ( radix == 16 && SDL_islowerhex(*text) ) {
53 v = 10 + (*text - 'a');
62 if ( negative && value ) {
68 return (text - textstart);
72 #if !defined(HAVE_SSCANF) || !defined(HAVE_STRTOUL) || !defined(HAVE_STRTOD)
73 static size_t SDL_ScanUnsignedLong(const char *text, int radix, unsigned long *valuep)
75 const char *textstart = text;
76 unsigned long value = 0;
78 if ( radix == 16 && SDL_strncmp(text, "0x", 2) == 0 ) {
83 if ( SDL_isdigit((unsigned char) *text) ) {
85 } else if ( radix == 16 && SDL_isupperhex(*text) ) {
86 v = 10 + (*text - 'A');
87 } else if ( radix == 16 && SDL_islowerhex(*text) ) {
88 v = 10 + (*text - 'a');
99 return (text - textstart);
104 static size_t SDL_ScanUintPtrT(const char *text, int radix, uintptr_t *valuep)
106 const char *textstart = text;
109 if ( radix == 16 && SDL_strncmp(text, "0x", 2) == 0 ) {
114 if ( SDL_isdigit((unsigned char) *text) ) {
116 } else if ( radix == 16 && SDL_isupperhex(*text) ) {
117 v = 10 + (*text - 'A');
118 } else if ( radix == 16 && SDL_islowerhex(*text) ) {
119 v = 10 + (*text - 'a');
130 return (text - textstart);
134 #ifdef SDL_HAS_64BIT_TYPE
135 #if !defined(HAVE_SSCANF) || !defined(HAVE_STRTOLL)
136 static size_t SDL_ScanLongLong(const char *text, int radix, Sint64 *valuep)
138 const char *textstart = text;
140 SDL_bool negative = SDL_FALSE;
142 if ( *text == '-' ) {
146 if ( radix == 16 && SDL_strncmp(text, "0x", 2) == 0 ) {
151 if ( SDL_isdigit((unsigned char) *text) ) {
153 } else if ( radix == 16 && SDL_isupperhex(*text) ) {
154 v = 10 + (*text - 'A');
155 } else if ( radix == 16 && SDL_islowerhex(*text) ) {
156 v = 10 + (*text - 'a');
165 if ( negative && value ) {
171 return (text - textstart);
175 #if !defined(HAVE_SSCANF) || !defined(HAVE_STRTOULL)
176 static size_t SDL_ScanUnsignedLongLong(const char *text, int radix, Uint64 *valuep)
178 const char *textstart = text;
181 if ( radix == 16 && SDL_strncmp(text, "0x", 2) == 0 ) {
186 if ( SDL_isdigit((unsigned char) *text) ) {
188 } else if ( radix == 16 && SDL_isupperhex(*text) ) {
189 v = 10 + (*text - 'A');
190 } else if ( radix == 16 && SDL_islowerhex(*text) ) {
191 v = 10 + (*text - 'a');
202 return (text - textstart);
205 #endif /* SDL_HAS_64BIT_TYPE */
207 #if !defined(HAVE_SSCANF) || !defined(HAVE_STRTOD)
208 static size_t SDL_ScanFloat(const char *text, double *valuep)
210 const char *textstart = text;
211 unsigned long lvalue = 0;
213 SDL_bool negative = SDL_FALSE;
215 if ( *text == '-' ) {
219 text += SDL_ScanUnsignedLong(text, 10, &lvalue);
221 if ( *text == '.' ) {
224 while ( SDL_isdigit((unsigned char) *text) ) {
225 lvalue = *text - '0';
226 value += (double)lvalue / mult;
232 if ( negative && value ) {
238 return (text - textstart);
243 void *SDL_memset(void *dst, int c, size_t len)
245 size_t left = (len % 4);
248 Uint32 *dstp = (Uint32 *)dst;
250 for (i = 0; i < 4; ++i) {
260 Uint8 value = (Uint8)c;
261 Uint8 *dstp = (Uint8 *)dst;
276 void *SDL_memcpy(void *dst, const void *src, size_t len)
278 char *srcp = (char *)src;
279 char *dstp = (char *)dst;
288 void *SDL_revcpy(void *dst, const void *src, size_t len)
290 char *srcp = (char *)src;
291 char *dstp = (char *)dst;
302 int SDL_memcmp(const void *s1, const void *s2, size_t len)
304 char *s1p = (char *)s1;
305 char *s2p = (char *)s2;
307 if ( *s1p != *s2p ) {
308 return (*s1p - *s2p);
318 size_t SDL_strlen(const char *string)
321 while ( *string++ ) {
329 size_t SDL_strlcpy(char *dst, const char *src, size_t maxlen)
331 size_t srclen = SDL_strlen(src);
333 size_t len = SDL_min(srclen, maxlen-1);
334 SDL_memcpy(dst, src, len);
342 size_t SDL_strlcat(char *dst, const char *src, size_t maxlen)
344 size_t dstlen = SDL_strlen(dst);
345 size_t srclen = SDL_strlen(src);
346 if ( dstlen < maxlen ) {
347 SDL_strlcpy(dst+dstlen, src, maxlen-dstlen);
349 return dstlen+srclen;
354 char *SDL_strdup(const char *string)
356 size_t len = SDL_strlen(string)+1;
357 char *newstr = SDL_malloc(len);
359 SDL_strlcpy(newstr, string, len);
366 char *SDL_strrev(char *string)
368 size_t len = SDL_strlen(string);
369 char *a = &string[0];
370 char *b = &string[len-1];
382 char *SDL_strupr(char *string)
386 *bufp = SDL_toupper((unsigned char) *bufp);
394 char *SDL_strlwr(char *string)
398 *bufp = SDL_tolower((unsigned char) *bufp);
406 char *SDL_strchr(const char *string, int c)
409 if ( *string == c ) {
410 return (char *)string;
419 char *SDL_strrchr(const char *string, int c)
421 const char *bufp = string + SDL_strlen(string) - 1;
422 while ( bufp >= string ) {
433 char *SDL_strstr(const char *haystack, const char *needle)
435 size_t length = SDL_strlen(needle);
436 while ( *haystack ) {
437 if ( SDL_strncmp(haystack, needle, length) == 0 ) {
438 return (char *)haystack;
446 #if !defined(HAVE__LTOA) || !defined(HAVE__I64TOA) || \
447 !defined(HAVE__ULTOA) || !defined(HAVE__UI64TOA)
448 static const char ntoa_table[] = {
449 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
450 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
451 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
452 'U', 'V', 'W', 'X', 'Y', 'Z'
454 #endif /* ntoa() conversion table */
457 char *SDL_ltoa(long value, char *string, int radix)
466 while ( value > 0 ) {
467 *bufp++ = ntoa_table[value % radix];
475 /* The numbers went into the string backwards. :) */
476 if ( *string == '-' ) {
477 SDL_strrev(string+1);
487 char *SDL_ultoa(unsigned long value, char *string, int radix)
492 while ( value > 0 ) {
493 *bufp++ = ntoa_table[value % radix];
501 /* The numbers went into the string backwards. :) */
509 long SDL_strtol(const char *string, char **endp, int base)
515 if ( (SDL_strlen(string) > 2) && (SDL_strncmp(string, "0x", 2) == 0) ) {
522 len = SDL_ScanLong(string, base, &value);
524 *endp = (char *)string + len;
531 unsigned long SDL_strtoul(const char *string, char **endp, int base)
537 if ( (SDL_strlen(string) > 2) && (SDL_strncmp(string, "0x", 2) == 0) ) {
544 len = SDL_ScanUnsignedLong(string, base, &value);
546 *endp = (char *)string + len;
552 #ifdef SDL_HAS_64BIT_TYPE
555 char *SDL_lltoa(Sint64 value, char *string, int radix)
564 while ( value > 0 ) {
565 *bufp++ = ntoa_table[value % radix];
573 /* The numbers went into the string backwards. :) */
574 if ( *string == '-' ) {
575 SDL_strrev(string+1);
584 #ifndef HAVE__UI64TOA
585 char *SDL_ulltoa(Uint64 value, char *string, int radix)
590 while ( value > 0 ) {
591 *bufp++ = ntoa_table[value % radix];
599 /* The numbers went into the string backwards. :) */
607 Sint64 SDL_strtoll(const char *string, char **endp, int base)
613 if ( (SDL_strlen(string) > 2) && (SDL_strncmp(string, "0x", 2) == 0) ) {
620 len = SDL_ScanLongLong(string, base, &value);
622 *endp = (char *)string + len;
628 #ifndef HAVE_STRTOULL
629 Uint64 SDL_strtoull(const char *string, char **endp, int base)
635 if ( (SDL_strlen(string) > 2) && (SDL_strncmp(string, "0x", 2) == 0) ) {
642 len = SDL_ScanUnsignedLongLong(string, base, &value);
644 *endp = (char *)string + len;
650 #endif /* SDL_HAS_64BIT_TYPE */
653 double SDL_strtod(const char *string, char **endp)
658 len = SDL_ScanFloat(string, &value);
660 *endp = (char *)string + len;
667 int SDL_strcmp(const char *str1, const char *str2)
669 while (*str1 && *str2) {
670 if ( *str1 != *str2 )
675 return (int)((unsigned char)*str1 - (unsigned char)*str2);
680 int SDL_strncmp(const char *str1, const char *str2, size_t maxlen)
682 while ( *str1 && *str2 && maxlen ) {
683 if ( *str1 != *str2 )
692 return (int)((unsigned char)*str1 - (unsigned char)*str2);
696 #if !defined(HAVE_STRCASECMP) && !defined(HAVE__STRICMP)
697 int SDL_strcasecmp(const char *str1, const char *str2)
701 while ( *str1 && *str2 ) {
702 a = SDL_tolower((unsigned char) *str1);
703 b = SDL_tolower((unsigned char) *str2);
709 return (int)((unsigned char)a - (unsigned char)b);
713 #if !defined(HAVE_STRNCASECMP) && !defined(HAVE__STRNICMP)
714 int SDL_strncasecmp(const char *str1, const char *str2, size_t maxlen)
718 while ( *str1 && *str2 && maxlen ) {
719 a = SDL_tolower((unsigned char) *str1);
720 b = SDL_tolower((unsigned char) *str2);
727 return (int)((unsigned char)a - (unsigned char)b);
732 int SDL_sscanf(const char *text, const char *fmt, ...)
740 while ( SDL_isspace((unsigned char) *text) ) {
747 SDL_bool done = SDL_FALSE;
756 SDL_bool suppress = SDL_FALSE;
760 if ( *text == '%' ) {
771 fmt += SDL_ScanLong(fmt, 10, &count);
782 char *valuep = va_arg(ap, char*);
791 while ( SDL_isspace((unsigned char) *text) ) {
795 /* FIXME: implement more of the format specifiers */
802 if ( inttype > DO_SHORT ) {
807 if ( inttype < DO_LONGLONG ) {
812 if ( SDL_strncmp(fmt, "I64", 3) == 0 ) {
814 inttype = DO_LONGLONG;
820 if ( text[index] == '-' ) {
823 if ( text[index] == '0' ) {
824 if ( SDL_tolower((unsigned char) text[index+1]) == 'x' ) {
831 /* Fall through to %d handling */
833 #ifdef SDL_HAS_64BIT_TYPE
834 if ( inttype == DO_LONGLONG ) {
836 text += SDL_ScanLongLong(text, radix, &value);
838 Sint64 *valuep = va_arg(ap, Sint64*);
844 #endif /* SDL_HAS_64BIT_TYPE */
847 text += SDL_ScanLong(text, radix, &value);
851 { short* valuep = va_arg(ap, short*);
852 *valuep = (short)value;
856 { int* valuep = va_arg(ap, int*);
857 *valuep = (int)value;
861 { long* valuep = va_arg(ap, long*);
878 /* Fall through to unsigned handling */
884 /* Fall through to unsigned handling */
886 #ifdef SDL_HAS_64BIT_TYPE
887 if ( inttype == DO_LONGLONG ) {
889 text += SDL_ScanUnsignedLongLong(text, radix, &value);
891 Uint64 *valuep = va_arg(ap, Uint64*);
897 #endif /* SDL_HAS_64BIT_TYPE */
900 text += SDL_ScanUnsignedLong(text, radix, &value);
904 { short* valuep = va_arg(ap, short*);
905 *valuep = (short)value;
909 { int* valuep = va_arg(ap, int*);
910 *valuep = (int)value;
914 { long* valuep = va_arg(ap, long*);
930 text += SDL_ScanUintPtrT(text, 16, &value);
932 void** valuep = va_arg(ap, void**);
933 *valuep = (void*)value;
942 text += SDL_ScanFloat(text, &value);
944 float* valuep = va_arg(ap, float*);
945 *valuep = (float)value;
953 while ( !SDL_isspace((unsigned char) *text) ) {
956 if ( --count == 0 ) {
962 char *valuep = va_arg(ap, char*);
963 while ( !SDL_isspace((unsigned char) *text) ) {
966 if ( --count == 0 ) {
984 if ( *text == *fmt ) {
989 /* Text didn't match format specifier */
998 #ifndef HAVE_SNPRINTF
999 int SDL_snprintf(char *text, size_t maxlen, const char *fmt, ...)
1005 retval = SDL_vsnprintf(text, maxlen, fmt, ap);
1012 #ifndef HAVE_VSNPRINTF
1013 static size_t SDL_PrintLong(char *text, long value, int radix, size_t maxlen)
1018 SDL_ltoa(value, num, radix);
1019 size = SDL_strlen(num);
1020 if ( size >= maxlen ) {
1023 SDL_strlcpy(text, num, size+1);
1027 static size_t SDL_PrintUnsignedLong(char *text, unsigned long value, int radix, size_t maxlen)
1032 SDL_ultoa(value, num, radix);
1033 size = SDL_strlen(num);
1034 if ( size >= maxlen ) {
1037 SDL_strlcpy(text, num, size+1);
1041 #ifdef SDL_HAS_64BIT_TYPE
1042 static size_t SDL_PrintLongLong(char *text, Sint64 value, int radix, size_t maxlen)
1047 SDL_lltoa(value, num, radix);
1048 size = SDL_strlen(num);
1049 if ( size >= maxlen ) {
1052 SDL_strlcpy(text, num, size+1);
1056 static size_t SDL_PrintUnsignedLongLong(char *text, Uint64 value, int radix, size_t maxlen)
1061 SDL_ulltoa(value, num, radix);
1062 size = SDL_strlen(num);
1063 if ( size >= maxlen ) {
1066 SDL_strlcpy(text, num, size+1);
1070 #endif /* SDL_HAS_64BIT_TYPE */
1071 static size_t SDL_PrintFloat(char *text, double arg, size_t maxlen)
1073 char *textstart = text;
1075 /* This isn't especially accurate, but hey, it's easy. :) */
1076 const double precision = 0.00000001;
1078 unsigned long value;
1085 value = (unsigned long)arg;
1086 len = SDL_PrintUnsignedLong(text, value, 10, maxlen);
1090 if ( arg > precision && maxlen ) {
1093 while ( (arg > precision) && maxlen ) {
1094 value = (unsigned long)(arg * mult);
1095 len = SDL_PrintUnsignedLong(text, value, 10, maxlen);
1098 arg -= (double)value / mult;
1105 return (text - textstart);
1107 static size_t SDL_PrintString(char *text, const char *string, size_t maxlen)
1109 char *textstart = text;
1110 while ( *string && maxlen-- ) {
1111 *text++ = *string++;
1113 return (text - textstart);
1115 int SDL_vsnprintf(char *text, size_t maxlen, const char *fmt, va_list ap)
1117 char *textstart = text;
1118 if ( maxlen <= 0 ) {
1121 --maxlen; /* For the trailing '\0' */
1122 while ( *fmt && maxlen ) {
1123 if ( *fmt == '%' ) {
1124 SDL_bool done = SDL_FALSE;
1126 SDL_bool do_lowercase = SDL_FALSE;
1135 /* FIXME: implement more of the format specifiers */
1136 while ( *fmt == '.' || (*fmt >= '0' && *fmt <= '9') ) {
1147 /* char is promoted to int when passed through (...) */
1148 *text = (char)va_arg(ap, int);
1153 /* short is promoted to int when passed through (...) */
1156 if ( inttype < DO_LONGLONG ) {
1161 if ( SDL_strncmp(fmt, "I64", 3) == 0 ) {
1163 inttype = DO_LONGLONG;
1170 len = SDL_PrintLong(text, (long)va_arg(ap, int), radix, maxlen);
1173 len = SDL_PrintLong(text, va_arg(ap, long), radix, maxlen);
1176 #ifdef SDL_HAS_64BIT_TYPE
1177 len = SDL_PrintLongLong(text, va_arg(ap, Sint64), radix, maxlen);
1179 len = SDL_PrintLong(text, va_arg(ap, long), radix, maxlen);
1187 do_lowercase = SDL_TRUE;
1188 /* Fall through to 'X' handling */
1190 if ( radix == 10 ) {
1193 if ( *fmt == 'p' ) {
1196 /* Fall through to unsigned handling */
1198 if ( radix == 10 ) {
1201 /* Fall through to unsigned handling */
1205 len = SDL_PrintUnsignedLong(text, (unsigned long)va_arg(ap, unsigned int), radix, maxlen);
1208 len = SDL_PrintUnsignedLong(text, va_arg(ap, unsigned long), radix, maxlen);
1211 #ifdef SDL_HAS_64BIT_TYPE
1212 len = SDL_PrintUnsignedLongLong(text, va_arg(ap, Uint64), radix, maxlen);
1214 len = SDL_PrintUnsignedLong(text, va_arg(ap, unsigned long), radix, maxlen);
1218 if ( do_lowercase ) {
1224 len = SDL_PrintFloat(text, va_arg(ap, double), maxlen);
1228 len = SDL_PrintString(text, va_arg(ap, char*), maxlen);
1246 return (text - textstart);