SDL-1.2.14
[sdl_omap.git] / src / stdlib / SDL_string.c
CommitLineData
e14743d1 1/*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2009 Sam Lantinga
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19 Sam Lantinga
20 slouken@libsdl.org
21*/
22#include "SDL_config.h"
23
24/* This file contains portable string manipulation functions for SDL */
25
26#include "SDL_stdinc.h"
27
28
29#define SDL_isupperhex(X) (((X) >= 'A') && ((X) <= 'F'))
30#define SDL_islowerhex(X) (((X) >= 'a') && ((X) <= 'f'))
31
32#if !defined(HAVE_SSCANF) || !defined(HAVE_STRTOL)
33static size_t SDL_ScanLong(const char *text, int radix, long *valuep)
34{
35 const char *textstart = text;
36 long value = 0;
37 SDL_bool negative = SDL_FALSE;
38
39 if ( *text == '-' ) {
40 negative = SDL_TRUE;
41 ++text;
42 }
43 if ( radix == 16 && SDL_strncmp(text, "0x", 2) == 0 ) {
44 text += 2;
45 }
46 for ( ; ; ) {
47 int v;
48 if ( SDL_isdigit((unsigned char) *text) ) {
49 v = *text - '0';
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');
54 } else {
55 break;
56 }
57 value *= radix;
58 value += v;
59 ++text;
60 }
61 if ( valuep ) {
62 if ( negative && value ) {
63 *valuep = -value;
64 } else {
65 *valuep = value;
66 }
67 }
68 return (text - textstart);
69}
70#endif
71
72#if !defined(HAVE_SSCANF) || !defined(HAVE_STRTOUL) || !defined(HAVE_STRTOD)
73static size_t SDL_ScanUnsignedLong(const char *text, int radix, unsigned long *valuep)
74{
75 const char *textstart = text;
76 unsigned long value = 0;
77
78 if ( radix == 16 && SDL_strncmp(text, "0x", 2) == 0 ) {
79 text += 2;
80 }
81 for ( ; ; ) {
82 int v;
83 if ( SDL_isdigit((unsigned char) *text) ) {
84 v = *text - '0';
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');
89 } else {
90 break;
91 }
92 value *= radix;
93 value += v;
94 ++text;
95 }
96 if ( valuep ) {
97 *valuep = value;
98 }
99 return (text - textstart);
100}
101#endif
102
103#ifndef HAVE_SSCANF
104static size_t SDL_ScanUintPtrT(const char *text, int radix, uintptr_t *valuep)
105{
106 const char *textstart = text;
107 uintptr_t value = 0;
108
109 if ( radix == 16 && SDL_strncmp(text, "0x", 2) == 0 ) {
110 text += 2;
111 }
112 for ( ; ; ) {
113 int v;
114 if ( SDL_isdigit((unsigned char) *text) ) {
115 v = *text - '0';
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');
120 } else {
121 break;
122 }
123 value *= radix;
124 value += v;
125 ++text;
126 }
127 if ( valuep ) {
128 *valuep = value;
129 }
130 return (text - textstart);
131}
132#endif
133
134#ifdef SDL_HAS_64BIT_TYPE
135#if !defined(HAVE_SSCANF) || !defined(HAVE_STRTOLL)
136static size_t SDL_ScanLongLong(const char *text, int radix, Sint64 *valuep)
137{
138 const char *textstart = text;
139 Sint64 value = 0;
140 SDL_bool negative = SDL_FALSE;
141
142 if ( *text == '-' ) {
143 negative = SDL_TRUE;
144 ++text;
145 }
146 if ( radix == 16 && SDL_strncmp(text, "0x", 2) == 0 ) {
147 text += 2;
148 }
149 for ( ; ; ) {
150 int v;
151 if ( SDL_isdigit((unsigned char) *text) ) {
152 v = *text - '0';
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');
157 } else {
158 break;
159 }
160 value *= radix;
161 value += v;
162 ++text;
163 }
164 if ( valuep ) {
165 if ( negative && value ) {
166 *valuep = -value;
167 } else {
168 *valuep = value;
169 }
170 }
171 return (text - textstart);
172}
173#endif
174
175#if !defined(HAVE_SSCANF) || !defined(HAVE_STRTOULL)
176static size_t SDL_ScanUnsignedLongLong(const char *text, int radix, Uint64 *valuep)
177{
178 const char *textstart = text;
179 Uint64 value = 0;
180
181 if ( radix == 16 && SDL_strncmp(text, "0x", 2) == 0 ) {
182 text += 2;
183 }
184 for ( ; ; ) {
185 int v;
186 if ( SDL_isdigit((unsigned char) *text) ) {
187 v = *text - '0';
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');
192 } else {
193 break;
194 }
195 value *= radix;
196 value += v;
197 ++text;
198 }
199 if ( valuep ) {
200 *valuep = value;
201 }
202 return (text - textstart);
203}
204#endif
205#endif /* SDL_HAS_64BIT_TYPE */
206
207#if !defined(HAVE_SSCANF) || !defined(HAVE_STRTOD)
208static size_t SDL_ScanFloat(const char *text, double *valuep)
209{
210 const char *textstart = text;
211 unsigned long lvalue = 0;
212 double value = 0.0;
213 SDL_bool negative = SDL_FALSE;
214
215 if ( *text == '-' ) {
216 negative = SDL_TRUE;
217 ++text;
218 }
219 text += SDL_ScanUnsignedLong(text, 10, &lvalue);
220 value += lvalue;
221 if ( *text == '.' ) {
222 int mult = 10;
223 ++text;
224 while ( SDL_isdigit((unsigned char) *text) ) {
225 lvalue = *text - '0';
226 value += (double)lvalue / mult;
227 mult *= 10;
228 ++text;
229 }
230 }
231 if ( valuep ) {
232 if ( negative && value ) {
233 *valuep = -value;
234 } else {
235 *valuep = value;
236 }
237 }
238 return (text - textstart);
239}
240#endif
241
242#ifndef SDL_memset
243void *SDL_memset(void *dst, int c, size_t len)
244{
245 size_t left = (len % 4);
246 if ( len >= 4 ) {
247 Uint32 value = 0;
248 Uint32 *dstp = (Uint32 *)dst;
249 int i;
250 for (i = 0; i < 4; ++i) {
251 value <<= 8;
252 value |= c;
253 }
254 len /= 4;
255 while ( len-- ) {
256 *dstp++ = value;
257 }
258 }
259 if ( left > 0 ) {
260 Uint8 value = (Uint8)c;
261 Uint8 *dstp = (Uint8 *)dst;
262 switch(left) {
263 case 3:
264 *dstp++ = value;
265 case 2:
266 *dstp++ = value;
267 case 1:
268 *dstp++ = value;
269 }
270 }
271 return dst;
272}
273#endif
274
275#ifndef SDL_memcpy
276void *SDL_memcpy(void *dst, const void *src, size_t len)
277{
278 char *srcp = (char *)src;
279 char *dstp = (char *)dst;
280 while ( len-- ) {
281 *dstp++ = *srcp++;
282 }
283 return dst;
284}
285#endif
286
287#ifndef SDL_revcpy
288void *SDL_revcpy(void *dst, const void *src, size_t len)
289{
290 char *srcp = (char *)src;
291 char *dstp = (char *)dst;
292 srcp += len-1;
293 dstp += len-1;
294 while ( len-- ) {
295 *dstp-- = *srcp--;
296 }
297 return dst;
298}
299#endif
300
301#ifndef SDL_memcmp
302int SDL_memcmp(const void *s1, const void *s2, size_t len)
303{
304 char *s1p = (char *)s1;
305 char *s2p = (char *)s2;
306 while ( len-- ) {
307 if ( *s1p != *s2p ) {
308 return (*s1p - *s2p);
309 }
310 ++s1p;
311 ++s2p;
312 }
313 return 0;
314}
315#endif
316
317#ifndef HAVE_STRLEN
318size_t SDL_strlen(const char *string)
319{
320 size_t len = 0;
321 while ( *string++ ) {
322 ++len;
323 }
324 return len;
325}
326#endif
327
328#ifndef HAVE_STRLCPY
329size_t SDL_strlcpy(char *dst, const char *src, size_t maxlen)
330{
331 size_t srclen = SDL_strlen(src);
332 if ( maxlen > 0 ) {
333 size_t len = SDL_min(srclen, maxlen-1);
334 SDL_memcpy(dst, src, len);
335 dst[len] = '\0';
336 }
337 return srclen;
338}
339#endif
340
341#ifndef HAVE_STRLCAT
342size_t SDL_strlcat(char *dst, const char *src, size_t maxlen)
343{
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);
348 }
349 return dstlen+srclen;
350}
351#endif
352
353#ifndef HAVE_STRDUP
354char *SDL_strdup(const char *string)
355{
356 size_t len = SDL_strlen(string)+1;
357 char *newstr = SDL_malloc(len);
358 if ( newstr ) {
359 SDL_strlcpy(newstr, string, len);
360 }
361 return newstr;
362}
363#endif
364
365#ifndef HAVE__STRREV
366char *SDL_strrev(char *string)
367{
368 size_t len = SDL_strlen(string);
369 char *a = &string[0];
370 char *b = &string[len-1];
371 len /= 2;
372 while ( len-- ) {
373 char c = *a;
374 *a++ = *b;
375 *b-- = c;
376 }
377 return string;
378}
379#endif
380
381#ifndef HAVE__STRUPR
382char *SDL_strupr(char *string)
383{
384 char *bufp = string;
385 while ( *bufp ) {
386 *bufp = SDL_toupper((unsigned char) *bufp);
387 ++bufp;
388 }
389 return string;
390}
391#endif
392
393#ifndef HAVE__STRLWR
394char *SDL_strlwr(char *string)
395{
396 char *bufp = string;
397 while ( *bufp ) {
398 *bufp = SDL_tolower((unsigned char) *bufp);
399 ++bufp;
400 }
401 return string;
402}
403#endif
404
405#ifndef HAVE_STRCHR
406char *SDL_strchr(const char *string, int c)
407{
408 while ( *string ) {
409 if ( *string == c ) {
410 return (char *)string;
411 }
412 ++string;
413 }
414 return NULL;
415}
416#endif
417
418#ifndef HAVE_STRRCHR
419char *SDL_strrchr(const char *string, int c)
420{
421 const char *bufp = string + SDL_strlen(string) - 1;
422 while ( bufp >= string ) {
423 if ( *bufp == c ) {
424 return (char *)bufp;
425 }
426 --bufp;
427 }
428 return NULL;
429}
430#endif
431
432#ifndef HAVE_STRSTR
433char *SDL_strstr(const char *haystack, const char *needle)
434{
435 size_t length = SDL_strlen(needle);
436 while ( *haystack ) {
437 if ( SDL_strncmp(haystack, needle, length) == 0 ) {
438 return (char *)haystack;
439 }
440 ++haystack;
441 }
442 return NULL;
443}
444#endif
445
446#if !defined(HAVE__LTOA) || !defined(HAVE__I64TOA) || \
447 !defined(HAVE__ULTOA) || !defined(HAVE__UI64TOA)
448static 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'
453};
454#endif /* ntoa() conversion table */
455
456#ifndef HAVE__LTOA
457char *SDL_ltoa(long value, char *string, int radix)
458{
459 char *bufp = string;
460
461 if ( value < 0 ) {
462 *bufp++ = '-';
463 value = -value;
464 }
465 if ( value ) {
466 while ( value > 0 ) {
467 *bufp++ = ntoa_table[value % radix];
468 value /= radix;
469 }
470 } else {
471 *bufp++ = '0';
472 }
473 *bufp = '\0';
474
475 /* The numbers went into the string backwards. :) */
476 if ( *string == '-' ) {
477 SDL_strrev(string+1);
478 } else {
479 SDL_strrev(string);
480 }
481
482 return string;
483}
484#endif
485
486#ifndef HAVE__ULTOA
487char *SDL_ultoa(unsigned long value, char *string, int radix)
488{
489 char *bufp = string;
490
491 if ( value ) {
492 while ( value > 0 ) {
493 *bufp++ = ntoa_table[value % radix];
494 value /= radix;
495 }
496 } else {
497 *bufp++ = '0';
498 }
499 *bufp = '\0';
500
501 /* The numbers went into the string backwards. :) */
502 SDL_strrev(string);
503
504 return string;
505}
506#endif
507
508#ifndef HAVE_STRTOL
509long SDL_strtol(const char *string, char **endp, int base)
510{
511 size_t len;
512 long value;
513
514 if ( !base ) {
515 if ( (SDL_strlen(string) > 2) && (SDL_strncmp(string, "0x", 2) == 0) ) {
516 base = 16;
517 } else {
518 base = 10;
519 }
520 }
521
522 len = SDL_ScanLong(string, base, &value);
523 if ( endp ) {
524 *endp = (char *)string + len;
525 }
526 return value;
527}
528#endif
529
530#ifndef HAVE_STRTOUL
531unsigned long SDL_strtoul(const char *string, char **endp, int base)
532{
533 size_t len;
534 unsigned long value;
535
536 if ( !base ) {
537 if ( (SDL_strlen(string) > 2) && (SDL_strncmp(string, "0x", 2) == 0) ) {
538 base = 16;
539 } else {
540 base = 10;
541 }
542 }
543
544 len = SDL_ScanUnsignedLong(string, base, &value);
545 if ( endp ) {
546 *endp = (char *)string + len;
547 }
548 return value;
549}
550#endif
551
552#ifdef SDL_HAS_64BIT_TYPE
553
554#ifndef HAVE__I64TOA
555char *SDL_lltoa(Sint64 value, char *string, int radix)
556{
557 char *bufp = string;
558
559 if ( value < 0 ) {
560 *bufp++ = '-';
561 value = -value;
562 }
563 if ( value ) {
564 while ( value > 0 ) {
565 *bufp++ = ntoa_table[value % radix];
566 value /= radix;
567 }
568 } else {
569 *bufp++ = '0';
570 }
571 *bufp = '\0';
572
573 /* The numbers went into the string backwards. :) */
574 if ( *string == '-' ) {
575 SDL_strrev(string+1);
576 } else {
577 SDL_strrev(string);
578 }
579
580 return string;
581}
582#endif
583
584#ifndef HAVE__UI64TOA
585char *SDL_ulltoa(Uint64 value, char *string, int radix)
586{
587 char *bufp = string;
588
589 if ( value ) {
590 while ( value > 0 ) {
591 *bufp++ = ntoa_table[value % radix];
592 value /= radix;
593 }
594 } else {
595 *bufp++ = '0';
596 }
597 *bufp = '\0';
598
599 /* The numbers went into the string backwards. :) */
600 SDL_strrev(string);
601
602 return string;
603}
604#endif
605
606#ifndef HAVE_STRTOLL
607Sint64 SDL_strtoll(const char *string, char **endp, int base)
608{
609 size_t len;
610 Sint64 value;
611
612 if ( !base ) {
613 if ( (SDL_strlen(string) > 2) && (SDL_strncmp(string, "0x", 2) == 0) ) {
614 base = 16;
615 } else {
616 base = 10;
617 }
618 }
619
620 len = SDL_ScanLongLong(string, base, &value);
621 if ( endp ) {
622 *endp = (char *)string + len;
623 }
624 return value;
625}
626#endif
627
628#ifndef HAVE_STRTOULL
629Uint64 SDL_strtoull(const char *string, char **endp, int base)
630{
631 size_t len;
632 Uint64 value;
633
634 if ( !base ) {
635 if ( (SDL_strlen(string) > 2) && (SDL_strncmp(string, "0x", 2) == 0) ) {
636 base = 16;
637 } else {
638 base = 10;
639 }
640 }
641
642 len = SDL_ScanUnsignedLongLong(string, base, &value);
643 if ( endp ) {
644 *endp = (char *)string + len;
645 }
646 return value;
647}
648#endif
649
650#endif /* SDL_HAS_64BIT_TYPE */
651
652#ifndef HAVE_STRTOD
653double SDL_strtod(const char *string, char **endp)
654{
655 size_t len;
656 double value;
657
658 len = SDL_ScanFloat(string, &value);
659 if ( endp ) {
660 *endp = (char *)string + len;
661 }
662 return value;
663}
664#endif
665
666#ifndef HAVE_STRCMP
667int SDL_strcmp(const char *str1, const char *str2)
668{
669 while (*str1 && *str2) {
670 if ( *str1 != *str2 )
671 break;
672 ++str1;
673 ++str2;
674 }
675 return (int)((unsigned char)*str1 - (unsigned char)*str2);
676}
677#endif
678
679#ifndef HAVE_STRNCMP
680int SDL_strncmp(const char *str1, const char *str2, size_t maxlen)
681{
682 while ( *str1 && *str2 && maxlen ) {
683 if ( *str1 != *str2 )
684 break;
685 ++str1;
686 ++str2;
687 --maxlen;
688 }
689 if ( ! maxlen ) {
690 return 0;
691 }
692 return (int)((unsigned char)*str1 - (unsigned char)*str2);
693}
694#endif
695
696#if !defined(HAVE_STRCASECMP) && !defined(HAVE__STRICMP)
697int 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((unsigned char) *str1);
703 b = SDL_tolower((unsigned char) *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)
714int SDL_strncasecmp(const char *str1, const char *str2, size_t maxlen)
715{
716 char a = 0;
717 char b = 0;
718 while ( *str1 && *str2 && maxlen ) {
719 a = SDL_tolower((unsigned char) *str1);
720 b = SDL_tolower((unsigned char) *str2);
721 if ( a != b )
722 break;
723 ++str1;
724 ++str2;
725 --maxlen;
726 }
727 return (int)((unsigned char)a - (unsigned char)b);
728}
729#endif
730
731#ifndef HAVE_SSCANF
732int SDL_sscanf(const char *text, const char *fmt, ...)
733{
734 va_list ap;
735 int retval = 0;
736
737 va_start(ap, fmt);
738 while ( *fmt ) {
739 if ( *fmt == ' ' ) {
740 while ( SDL_isspace((unsigned char) *text) ) {
741 ++text;
742 }
743 ++fmt;
744 continue;
745 }
746 if ( *fmt == '%' ) {
747 SDL_bool done = SDL_FALSE;
748 long count = 0;
749 int radix = 10;
750 enum {
751 DO_SHORT,
752 DO_INT,
753 DO_LONG,
754 DO_LONGLONG
755 } inttype = DO_INT;
756 SDL_bool suppress = SDL_FALSE;
757
758 ++fmt;
759 if ( *fmt == '%' ) {
760 if ( *text == '%' ) {
761 ++text;
762 ++fmt;
763 continue;
764 }
765 break;
766 }
767 if ( *fmt == '*' ) {
768 suppress = SDL_TRUE;
769 ++fmt;
770 }
771 fmt += SDL_ScanLong(fmt, 10, &count);
772
773 if ( *fmt == 'c' ) {
774 if ( ! count ) {
775 count = 1;
776 }
777 if ( suppress ) {
778 while ( count-- ) {
779 ++text;
780 }
781 } else {
782 char *valuep = va_arg(ap, char*);
783 while ( count-- ) {
784 *valuep++ = *text++;
785 }
786 ++retval;
787 }
788 continue;
789 }
790
791 while ( SDL_isspace((unsigned char) *text) ) {
792 ++text;
793 }
794
795 /* FIXME: implement more of the format specifiers */
796 while (!done) {
797 switch(*fmt) {
798 case '*':
799 suppress = SDL_TRUE;
800 break;
801 case 'h':
802 if ( inttype > DO_SHORT ) {
803 ++inttype;
804 }
805 break;
806 case 'l':
807 if ( inttype < DO_LONGLONG ) {
808 ++inttype;
809 }
810 break;
811 case 'I':
812 if ( SDL_strncmp(fmt, "I64", 3) == 0 ) {
813 fmt += 2;
814 inttype = DO_LONGLONG;
815 }
816 break;
817 case 'i':
818 {
819 int index = 0;
820 if ( text[index] == '-' ) {
821 ++index;
822 }
823 if ( text[index] == '0' ) {
824 if ( SDL_tolower((unsigned char) text[index+1]) == 'x' ) {
825 radix = 16;
826 } else {
827 radix = 8;
828 }
829 }
830 }
831 /* Fall through to %d handling */
832 case 'd':
833#ifdef SDL_HAS_64BIT_TYPE
834 if ( inttype == DO_LONGLONG ) {
835 Sint64 value;
836 text += SDL_ScanLongLong(text, radix, &value);
837 if ( ! suppress ) {
838 Sint64 *valuep = va_arg(ap, Sint64*);
839 *valuep = value;
840 ++retval;
841 }
842 }
843 else
844#endif /* SDL_HAS_64BIT_TYPE */
845 {
846 long value;
847 text += SDL_ScanLong(text, radix, &value);
848 if ( ! suppress ) {
849 switch (inttype) {
850 case DO_SHORT:
851 { short* valuep = va_arg(ap, short*);
852 *valuep = (short)value;
853 }
854 break;
855 case DO_INT:
856 { int* valuep = va_arg(ap, int*);
857 *valuep = (int)value;
858 }
859 break;
860 case DO_LONG:
861 { long* valuep = va_arg(ap, long*);
862 *valuep = value;
863 }
864 break;
865 case DO_LONGLONG:
866 /* Handled above */
867 break;
868 }
869 ++retval;
870 }
871 }
872 done = SDL_TRUE;
873 break;
874 case 'o':
875 if ( radix == 10 ) {
876 radix = 8;
877 }
878 /* Fall through to unsigned handling */
879 case 'x':
880 case 'X':
881 if ( radix == 10 ) {
882 radix = 16;
883 }
884 /* Fall through to unsigned handling */
885 case 'u':
886#ifdef SDL_HAS_64BIT_TYPE
887 if ( inttype == DO_LONGLONG ) {
888 Uint64 value;
889 text += SDL_ScanUnsignedLongLong(text, radix, &value);
890 if ( ! suppress ) {
891 Uint64 *valuep = va_arg(ap, Uint64*);
892 *valuep = value;
893 ++retval;
894 }
895 }
896 else
897#endif /* SDL_HAS_64BIT_TYPE */
898 {
899 unsigned long value;
900 text += SDL_ScanUnsignedLong(text, radix, &value);
901 if ( ! suppress ) {
902 switch (inttype) {
903 case DO_SHORT:
904 { short* valuep = va_arg(ap, short*);
905 *valuep = (short)value;
906 }
907 break;
908 case DO_INT:
909 { int* valuep = va_arg(ap, int*);
910 *valuep = (int)value;
911 }
912 break;
913 case DO_LONG:
914 { long* valuep = va_arg(ap, long*);
915 *valuep = value;
916 }
917 break;
918 case DO_LONGLONG:
919 /* Handled above */
920 break;
921 }
922 ++retval;
923 }
924 }
925 done = SDL_TRUE;
926 break;
927 case 'p':
928 {
929 uintptr_t value;
930 text += SDL_ScanUintPtrT(text, 16, &value);
931 if ( ! suppress ) {
932 void** valuep = va_arg(ap, void**);
933 *valuep = (void*)value;
934 ++retval;
935 }
936 }
937 done = SDL_TRUE;
938 break;
939 case 'f':
940 {
941 double value;
942 text += SDL_ScanFloat(text, &value);
943 if ( ! suppress ) {
944 float* valuep = va_arg(ap, float*);
945 *valuep = (float)value;
946 ++retval;
947 }
948 }
949 done = SDL_TRUE;
950 break;
951 case 's':
952 if ( suppress ) {
953 while ( !SDL_isspace((unsigned char) *text) ) {
954 ++text;
955 if ( count ) {
956 if ( --count == 0 ) {
957 break;
958 }
959 }
960 }
961 } else {
962 char *valuep = va_arg(ap, char*);
963 while ( !SDL_isspace((unsigned char) *text) ) {
964 *valuep++ = *text++;
965 if ( count ) {
966 if ( --count == 0 ) {
967 break;
968 }
969 }
970 }
971 *valuep = '\0';
972 ++retval;
973 }
974 done = SDL_TRUE;
975 break;
976 default:
977 done = SDL_TRUE;
978 break;
979 }
980 ++fmt;
981 }
982 continue;
983 }
984 if ( *text == *fmt ) {
985 ++text;
986 ++fmt;
987 continue;
988 }
989 /* Text didn't match format specifier */
990 break;
991 }
992 va_end(ap);
993
994 return retval;
995}
996#endif
997
998#ifndef HAVE_SNPRINTF
999int SDL_snprintf(char *text, size_t maxlen, const char *fmt, ...)
1000{
1001 va_list ap;
1002 int retval;
1003
1004 va_start(ap, fmt);
1005 retval = SDL_vsnprintf(text, maxlen, fmt, ap);
1006 va_end(ap);
1007
1008 return retval;
1009}
1010#endif
1011
1012#ifndef HAVE_VSNPRINTF
1013static size_t SDL_PrintLong(char *text, long value, int radix, size_t maxlen)
1014{
1015 char num[130];
1016 size_t size;
1017
1018 SDL_ltoa(value, num, radix);
1019 size = SDL_strlen(num);
1020 if ( size >= maxlen ) {
1021 size = maxlen-1;
1022 }
1023 SDL_strlcpy(text, num, size+1);
1024
1025 return size;
1026}
1027static size_t SDL_PrintUnsignedLong(char *text, unsigned long value, int radix, size_t maxlen)
1028{
1029 char num[130];
1030 size_t size;
1031
1032 SDL_ultoa(value, num, radix);
1033 size = SDL_strlen(num);
1034 if ( size >= maxlen ) {
1035 size = maxlen-1;
1036 }
1037 SDL_strlcpy(text, num, size+1);
1038
1039 return size;
1040}
1041#ifdef SDL_HAS_64BIT_TYPE
1042static size_t SDL_PrintLongLong(char *text, Sint64 value, int radix, size_t maxlen)
1043{
1044 char num[130];
1045 size_t size;
1046
1047 SDL_lltoa(value, num, radix);
1048 size = SDL_strlen(num);
1049 if ( size >= maxlen ) {
1050 size = maxlen-1;
1051 }
1052 SDL_strlcpy(text, num, size+1);
1053
1054 return size;
1055}
1056static size_t SDL_PrintUnsignedLongLong(char *text, Uint64 value, int radix, size_t maxlen)
1057{
1058 char num[130];
1059 size_t size;
1060
1061 SDL_ulltoa(value, num, radix);
1062 size = SDL_strlen(num);
1063 if ( size >= maxlen ) {
1064 size = maxlen-1;
1065 }
1066 SDL_strlcpy(text, num, size+1);
1067
1068 return size;
1069}
1070#endif /* SDL_HAS_64BIT_TYPE */
1071static size_t SDL_PrintFloat(char *text, double arg, size_t maxlen)
1072{
1073 char *textstart = text;
1074 if ( arg ) {
1075 /* This isn't especially accurate, but hey, it's easy. :) */
1076 const double precision = 0.00000001;
1077 size_t len;
1078 unsigned long value;
1079
1080 if ( arg < 0 ) {
1081 *text++ = '-';
1082 --maxlen;
1083 arg = -arg;
1084 }
1085 value = (unsigned long)arg;
1086 len = SDL_PrintUnsignedLong(text, value, 10, maxlen);
1087 text += len;
1088 maxlen -= len;
1089 arg -= value;
1090 if ( arg > precision && maxlen ) {
1091 int mult = 10;
1092 *text++ = '.';
1093 while ( (arg > precision) && maxlen ) {
1094 value = (unsigned long)(arg * mult);
1095 len = SDL_PrintUnsignedLong(text, value, 10, maxlen);
1096 text += len;
1097 maxlen -= len;
1098 arg -= (double)value / mult;
1099 mult *= 10;
1100 }
1101 }
1102 } else {
1103 *text++ = '0';
1104 }
1105 return (text - textstart);
1106}
1107static size_t SDL_PrintString(char *text, const char *string, size_t maxlen)
1108{
1109 char *textstart = text;
1110 while ( *string && maxlen-- ) {
1111 *text++ = *string++;
1112 }
1113 return (text - textstart);
1114}
1115int SDL_vsnprintf(char *text, size_t maxlen, const char *fmt, va_list ap)
1116{
1117 char *textstart = text;
1118 if ( maxlen <= 0 ) {
1119 return 0;
1120 }
1121 --maxlen; /* For the trailing '\0' */
1122 while ( *fmt && maxlen ) {
1123 if ( *fmt == '%' ) {
1124 SDL_bool done = SDL_FALSE;
1125 size_t len = 0;
1126 SDL_bool do_lowercase = SDL_FALSE;
1127 int radix = 10;
1128 enum {
1129 DO_INT,
1130 DO_LONG,
1131 DO_LONGLONG
1132 } inttype = DO_INT;
1133
1134 ++fmt;
1135 /* FIXME: implement more of the format specifiers */
1136 while ( *fmt == '.' || (*fmt >= '0' && *fmt <= '9') ) {
1137 ++fmt;
1138 }
1139 while (!done) {
1140 switch(*fmt) {
1141 case '%':
1142 *text = '%';
1143 len = 1;
1144 done = SDL_TRUE;
1145 break;
1146 case 'c':
1147 /* char is promoted to int when passed through (...) */
1148 *text = (char)va_arg(ap, int);
1149 len = 1;
1150 done = SDL_TRUE;
1151 break;
1152 case 'h':
1153 /* short is promoted to int when passed through (...) */
1154 break;
1155 case 'l':
1156 if ( inttype < DO_LONGLONG ) {
1157 ++inttype;
1158 }
1159 break;
1160 case 'I':
1161 if ( SDL_strncmp(fmt, "I64", 3) == 0 ) {
1162 fmt += 2;
1163 inttype = DO_LONGLONG;
1164 }
1165 break;
1166 case 'i':
1167 case 'd':
1168 switch (inttype) {
1169 case DO_INT:
1170 len = SDL_PrintLong(text, (long)va_arg(ap, int), radix, maxlen);
1171 break;
1172 case DO_LONG:
1173 len = SDL_PrintLong(text, va_arg(ap, long), radix, maxlen);
1174 break;
1175 case DO_LONGLONG:
1176#ifdef SDL_HAS_64BIT_TYPE
1177 len = SDL_PrintLongLong(text, va_arg(ap, Sint64), radix, maxlen);
1178#else
1179 len = SDL_PrintLong(text, va_arg(ap, long), radix, maxlen);
1180#endif
1181 break;
1182 }
1183 done = SDL_TRUE;
1184 break;
1185 case 'p':
1186 case 'x':
1187 do_lowercase = SDL_TRUE;
1188 /* Fall through to 'X' handling */
1189 case 'X':
1190 if ( radix == 10 ) {
1191 radix = 16;
1192 }
1193 if ( *fmt == 'p' ) {
1194 inttype = DO_LONG;
1195 }
1196 /* Fall through to unsigned handling */
1197 case 'o':
1198 if ( radix == 10 ) {
1199 radix = 8;
1200 }
1201 /* Fall through to unsigned handling */
1202 case 'u':
1203 switch (inttype) {
1204 case DO_INT:
1205 len = SDL_PrintUnsignedLong(text, (unsigned long)va_arg(ap, unsigned int), radix, maxlen);
1206 break;
1207 case DO_LONG:
1208 len = SDL_PrintUnsignedLong(text, va_arg(ap, unsigned long), radix, maxlen);
1209 break;
1210 case DO_LONGLONG:
1211#ifdef SDL_HAS_64BIT_TYPE
1212 len = SDL_PrintUnsignedLongLong(text, va_arg(ap, Uint64), radix, maxlen);
1213#else
1214 len = SDL_PrintUnsignedLong(text, va_arg(ap, unsigned long), radix, maxlen);
1215#endif
1216 break;
1217 }
1218 if ( do_lowercase ) {
1219 SDL_strlwr(text);
1220 }
1221 done = SDL_TRUE;
1222 break;
1223 case 'f':
1224 len = SDL_PrintFloat(text, va_arg(ap, double), maxlen);
1225 done = SDL_TRUE;
1226 break;
1227 case 's':
1228 len = SDL_PrintString(text, va_arg(ap, char*), maxlen);
1229 done = SDL_TRUE;
1230 break;
1231 default:
1232 done = SDL_TRUE;
1233 break;
1234 }
1235 ++fmt;
1236 }
1237 text += len;
1238 maxlen -= len;
1239 } else {
1240 *text++ = *fmt++;
1241 --maxlen;
1242 }
1243 }
1244 *text = '\0';
1245
1246 return (text - textstart);
1247}
1248#endif