1 /*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20 */
21
22 #if defined(__clang_analyzer__) && !defined(SDL_DISABLE_ANALYZE_MACROS)
23 #define SDL_DISABLE_ANALYZE_MACROS 1
24 #endif
25
26 #ifndef _GNU_SOURCE
27 #define _GNU_SOURCE 1
28 #endif
29
30 #include "../SDL_internal.h"
31
32 /* This file contains portable string manipulation functions for SDL */
33
34 #include "SDL_stdinc.h"
35
36
37 #define SDL_isupperhex(X) (((X) >= 'A') && ((X) <= 'F'))
38 #define SDL_islowerhex(X) (((X) >= 'a') && ((X) <= 'f'))
39
40 #define UTF8_IsLeadByte(c) ((c) >= 0xC0 && (c) <= 0xF4)
41 #define UTF8_IsTrailingByte(c) ((c) >= 0x80 && (c) <= 0xBF)
42
UTF8_TrailingBytes(unsigned char c)43 static int UTF8_TrailingBytes(unsigned char c)
44 {
45 if (c >= 0xC0 && c <= 0xDF)
46 return 1;
47 else if (c >= 0xE0 && c <= 0xEF)
48 return 2;
49 else if (c >= 0xF0 && c <= 0xF4)
50 return 3;
51 else
52 return 0;
53 }
54
55 #if !defined(HAVE_VSSCANF) || !defined(HAVE_STRTOL)
56 static size_t
SDL_ScanLong(const char * text,int radix,long * valuep)57 SDL_ScanLong(const char *text, int radix, long *valuep)
58 {
59 const char *textstart = text;
60 long value = 0;
61 SDL_bool negative = SDL_FALSE;
62
63 if (*text == '-') {
64 negative = SDL_TRUE;
65 ++text;
66 }
67 if (radix == 16 && SDL_strncmp(text, "0x", 2) == 0) {
68 text += 2;
69 }
70 for (;;) {
71 int v;
72 if (SDL_isdigit((unsigned char) *text)) {
73 v = *text - '0';
74 } else if (radix == 16 && SDL_isupperhex(*text)) {
75 v = 10 + (*text - 'A');
76 } else if (radix == 16 && SDL_islowerhex(*text)) {
77 v = 10 + (*text - 'a');
78 } else {
79 break;
80 }
81 value *= radix;
82 value += v;
83 ++text;
84 }
85 if (valuep) {
86 if (negative && value) {
87 *valuep = -value;
88 } else {
89 *valuep = value;
90 }
91 }
92 return (text - textstart);
93 }
94 #endif
95
96 #if !defined(HAVE_VSSCANF) || !defined(HAVE_STRTOUL) || !defined(HAVE_STRTOD)
97 static size_t
SDL_ScanUnsignedLong(const char * text,int radix,unsigned long * valuep)98 SDL_ScanUnsignedLong(const char *text, int radix, unsigned long *valuep)
99 {
100 const char *textstart = text;
101 unsigned long value = 0;
102
103 if (radix == 16 && SDL_strncmp(text, "0x", 2) == 0) {
104 text += 2;
105 }
106 for (;;) {
107 int v;
108 if (SDL_isdigit((unsigned char) *text)) {
109 v = *text - '0';
110 } else if (radix == 16 && SDL_isupperhex(*text)) {
111 v = 10 + (*text - 'A');
112 } else if (radix == 16 && SDL_islowerhex(*text)) {
113 v = 10 + (*text - 'a');
114 } else {
115 break;
116 }
117 value *= radix;
118 value += v;
119 ++text;
120 }
121 if (valuep) {
122 *valuep = value;
123 }
124 return (text - textstart);
125 }
126 #endif
127
128 #ifndef HAVE_VSSCANF
129 static size_t
SDL_ScanUintPtrT(const char * text,int radix,uintptr_t * valuep)130 SDL_ScanUintPtrT(const char *text, int radix, uintptr_t * valuep)
131 {
132 const char *textstart = text;
133 uintptr_t value = 0;
134
135 if (radix == 16 && SDL_strncmp(text, "0x", 2) == 0) {
136 text += 2;
137 }
138 for (;;) {
139 int v;
140 if (SDL_isdigit((unsigned char) *text)) {
141 v = *text - '0';
142 } else if (radix == 16 && SDL_isupperhex(*text)) {
143 v = 10 + (*text - 'A');
144 } else if (radix == 16 && SDL_islowerhex(*text)) {
145 v = 10 + (*text - 'a');
146 } else {
147 break;
148 }
149 value *= radix;
150 value += v;
151 ++text;
152 }
153 if (valuep) {
154 *valuep = value;
155 }
156 return (text - textstart);
157 }
158 #endif
159
160 #if !defined(HAVE_VSSCANF) || !defined(HAVE_STRTOLL)
161 static size_t
SDL_ScanLongLong(const char * text,int radix,Sint64 * valuep)162 SDL_ScanLongLong(const char *text, int radix, Sint64 * valuep)
163 {
164 const char *textstart = text;
165 Sint64 value = 0;
166 SDL_bool negative = SDL_FALSE;
167
168 if (*text == '-') {
169 negative = SDL_TRUE;
170 ++text;
171 }
172 if (radix == 16 && SDL_strncmp(text, "0x", 2) == 0) {
173 text += 2;
174 }
175 for (;;) {
176 int v;
177 if (SDL_isdigit((unsigned char) *text)) {
178 v = *text - '0';
179 } else if (radix == 16 && SDL_isupperhex(*text)) {
180 v = 10 + (*text - 'A');
181 } else if (radix == 16 && SDL_islowerhex(*text)) {
182 v = 10 + (*text - 'a');
183 } else {
184 break;
185 }
186 value *= radix;
187 value += v;
188 ++text;
189 }
190 if (valuep) {
191 if (negative && value) {
192 *valuep = -value;
193 } else {
194 *valuep = value;
195 }
196 }
197 return (text - textstart);
198 }
199 #endif
200
201 #if !defined(HAVE_VSSCANF) || !defined(HAVE_STRTOULL)
202 static size_t
SDL_ScanUnsignedLongLong(const char * text,int radix,Uint64 * valuep)203 SDL_ScanUnsignedLongLong(const char *text, int radix, Uint64 * valuep)
204 {
205 const char *textstart = text;
206 Uint64 value = 0;
207
208 if (radix == 16 && SDL_strncmp(text, "0x", 2) == 0) {
209 text += 2;
210 }
211 for (;;) {
212 int v;
213 if (SDL_isdigit((unsigned char) *text)) {
214 v = *text - '0';
215 } else if (radix == 16 && SDL_isupperhex(*text)) {
216 v = 10 + (*text - 'A');
217 } else if (radix == 16 && SDL_islowerhex(*text)) {
218 v = 10 + (*text - 'a');
219 } else {
220 break;
221 }
222 value *= radix;
223 value += v;
224 ++text;
225 }
226 if (valuep) {
227 *valuep = value;
228 }
229 return (text - textstart);
230 }
231 #endif
232
233 #if !defined(HAVE_VSSCANF) || !defined(HAVE_STRTOD)
234 static size_t
SDL_ScanFloat(const char * text,double * valuep)235 SDL_ScanFloat(const char *text, double *valuep)
236 {
237 const char *textstart = text;
238 unsigned long lvalue = 0;
239 double value = 0.0;
240 SDL_bool negative = SDL_FALSE;
241
242 if (*text == '-') {
243 negative = SDL_TRUE;
244 ++text;
245 }
246 text += SDL_ScanUnsignedLong(text, 10, &lvalue);
247 value += lvalue;
248 if (*text == '.') {
249 int mult = 10;
250 ++text;
251 while (SDL_isdigit((unsigned char) *text)) {
252 lvalue = *text - '0';
253 value += (double) lvalue / mult;
254 mult *= 10;
255 ++text;
256 }
257 }
258 if (valuep) {
259 if (negative && value) {
260 *valuep = -value;
261 } else {
262 *valuep = value;
263 }
264 }
265 return (text - textstart);
266 }
267 #endif
268
269 void *
SDL_memset(SDL_OUT_BYTECAP (len)void * dst,int c,size_t len)270 SDL_memset(SDL_OUT_BYTECAP(len) void *dst, int c, size_t len)
271 {
272 #if defined(HAVE_MEMSET)
273 return memset(dst, c, len);
274 #else
275 size_t left;
276 Uint32 *dstp4;
277 Uint8 *dstp1 = (Uint8 *) dst;
278 Uint32 value4 = (c | (c << 8) | (c << 16) | (c << 24));
279 Uint8 value1 = (Uint8) c;
280
281 /* The destination pointer needs to be aligned on a 4-byte boundary to
282 * execute a 32-bit set. Set first bytes manually if needed until it is
283 * aligned. */
284 while ((intptr_t)dstp1 & 0x3) {
285 if (len--) {
286 *dstp1++ = value1;
287 } else {
288 return dst;
289 }
290 }
291
292 dstp4 = (Uint32 *) dstp1;
293 left = (len % 4);
294 len /= 4;
295 while (len--) {
296 *dstp4++ = value4;
297 }
298
299 dstp1 = (Uint8 *) dstp4;
300 switch (left) {
301 case 3:
302 *dstp1++ = value1;
303 case 2:
304 *dstp1++ = value1;
305 case 1:
306 *dstp1++ = value1;
307 }
308
309 return dst;
310 #endif /* HAVE_MEMSET */
311 }
312
313 void *
SDL_memcpy(SDL_OUT_BYTECAP (len)void * dst,SDL_IN_BYTECAP (len)const void * src,size_t len)314 SDL_memcpy(SDL_OUT_BYTECAP(len) void *dst, SDL_IN_BYTECAP(len) const void *src, size_t len)
315 {
316 #ifdef __GNUC__
317 /* Presumably this is well tuned for speed.
318 On my machine this is twice as fast as the C code below.
319 */
320 return __builtin_memcpy(dst, src, len);
321 #elif defined(HAVE_MEMCPY)
322 return memcpy(dst, src, len);
323 #elif defined(HAVE_BCOPY)
324 bcopy(src, dst, len);
325 return dst;
326 #else
327 /* GCC 4.9.0 with -O3 will generate movaps instructions with the loop
328 using Uint32* pointers, so we need to make sure the pointers are
329 aligned before we loop using them.
330 */
331 if (((intptr_t)src & 0x3) || ((intptr_t)dst & 0x3)) {
332 /* Do an unaligned byte copy */
333 Uint8 *srcp1 = (Uint8 *)src;
334 Uint8 *dstp1 = (Uint8 *)dst;
335
336 while (len--) {
337 *dstp1++ = *srcp1++;
338 }
339 } else {
340 size_t left = (len % 4);
341 Uint32 *srcp4, *dstp4;
342 Uint8 *srcp1, *dstp1;
343
344 srcp4 = (Uint32 *) src;
345 dstp4 = (Uint32 *) dst;
346 len /= 4;
347 while (len--) {
348 *dstp4++ = *srcp4++;
349 }
350
351 srcp1 = (Uint8 *) srcp4;
352 dstp1 = (Uint8 *) dstp4;
353 switch (left) {
354 case 3:
355 *dstp1++ = *srcp1++;
356 case 2:
357 *dstp1++ = *srcp1++;
358 case 1:
359 *dstp1++ = *srcp1++;
360 }
361 }
362 return dst;
363 #endif /* __GNUC__ */
364 }
365
366 void *
SDL_memmove(SDL_OUT_BYTECAP (len)void * dst,SDL_IN_BYTECAP (len)const void * src,size_t len)367 SDL_memmove(SDL_OUT_BYTECAP(len) void *dst, SDL_IN_BYTECAP(len) const void *src, size_t len)
368 {
369 #if defined(HAVE_MEMMOVE)
370 return memmove(dst, src, len);
371 #else
372 char *srcp = (char *) src;
373 char *dstp = (char *) dst;
374
375 if (src < dst) {
376 srcp += len - 1;
377 dstp += len - 1;
378 while (len--) {
379 *dstp-- = *srcp--;
380 }
381 } else {
382 while (len--) {
383 *dstp++ = *srcp++;
384 }
385 }
386 return dst;
387 #endif /* HAVE_MEMMOVE */
388 }
389
390 int
SDL_memcmp(const void * s1,const void * s2,size_t len)391 SDL_memcmp(const void *s1, const void *s2, size_t len)
392 {
393 #if defined(HAVE_MEMCMP)
394 return memcmp(s1, s2, len);
395 #else
396 char *s1p = (char *) s1;
397 char *s2p = (char *) s2;
398 while (len--) {
399 if (*s1p != *s2p) {
400 return (*s1p - *s2p);
401 }
402 ++s1p;
403 ++s2p;
404 }
405 return 0;
406 #endif /* HAVE_MEMCMP */
407 }
408
409 size_t
SDL_strlen(const char * string)410 SDL_strlen(const char *string)
411 {
412 #if defined(HAVE_STRLEN)
413 return strlen(string);
414 #else
415 size_t len = 0;
416 while (*string++) {
417 ++len;
418 }
419 return len;
420 #endif /* HAVE_STRLEN */
421 }
422
423 size_t
SDL_wcslen(const wchar_t * string)424 SDL_wcslen(const wchar_t * string)
425 {
426 #if defined(HAVE_WCSLEN)
427 return wcslen(string);
428 #else
429 size_t len = 0;
430 while (*string++) {
431 ++len;
432 }
433 return len;
434 #endif /* HAVE_WCSLEN */
435 }
436
437 size_t
SDL_wcslcpy(SDL_OUT_Z_CAP (maxlen)wchar_t * dst,const wchar_t * src,size_t maxlen)438 SDL_wcslcpy(SDL_OUT_Z_CAP(maxlen) wchar_t *dst, const wchar_t *src, size_t maxlen)
439 {
440 #if defined(HAVE_WCSLCPY)
441 return wcslcpy(dst, src, maxlen);
442 #else
443 size_t srclen = SDL_wcslen(src);
444 if (maxlen > 0) {
445 size_t len = SDL_min(srclen, maxlen - 1);
446 SDL_memcpy(dst, src, len * sizeof(wchar_t));
447 dst[len] = '\0';
448 }
449 return srclen;
450 #endif /* HAVE_WCSLCPY */
451 }
452
453 size_t
SDL_wcslcat(SDL_INOUT_Z_CAP (maxlen)wchar_t * dst,const wchar_t * src,size_t maxlen)454 SDL_wcslcat(SDL_INOUT_Z_CAP(maxlen) wchar_t *dst, const wchar_t *src, size_t maxlen)
455 {
456 #if defined(HAVE_WCSLCAT)
457 return wcslcat(dst, src, maxlen);
458 #else
459 size_t dstlen = SDL_wcslen(dst);
460 size_t srclen = SDL_wcslen(src);
461 if (dstlen < maxlen) {
462 SDL_wcslcpy(dst + dstlen, src, maxlen - dstlen);
463 }
464 return dstlen + srclen;
465 #endif /* HAVE_WCSLCAT */
466 }
467
468 size_t
SDL_strlcpy(SDL_OUT_Z_CAP (maxlen)char * dst,const char * src,size_t maxlen)469 SDL_strlcpy(SDL_OUT_Z_CAP(maxlen) char *dst, const char *src, size_t maxlen)
470 {
471 #if defined(HAVE_STRLCPY)
472 return strlcpy(dst, src, maxlen);
473 #else
474 size_t srclen = SDL_strlen(src);
475 if (maxlen > 0) {
476 size_t len = SDL_min(srclen, maxlen - 1);
477 SDL_memcpy(dst, src, len);
478 dst[len] = '\0';
479 }
480 return srclen;
481 #endif /* HAVE_STRLCPY */
482 }
483
SDL_utf8strlcpy(SDL_OUT_Z_CAP (dst_bytes)char * dst,const char * src,size_t dst_bytes)484 size_t SDL_utf8strlcpy(SDL_OUT_Z_CAP(dst_bytes) char *dst, const char *src, size_t dst_bytes)
485 {
486 size_t src_bytes = SDL_strlen(src);
487 size_t bytes = SDL_min(src_bytes, dst_bytes - 1);
488 size_t i = 0;
489 char trailing_bytes = 0;
490 if (bytes)
491 {
492 unsigned char c = (unsigned char)src[bytes - 1];
493 if (UTF8_IsLeadByte(c))
494 --bytes;
495 else if (UTF8_IsTrailingByte(c))
496 {
497 for (i = bytes - 1; i != 0; --i)
498 {
499 c = (unsigned char)src[i];
500 trailing_bytes = UTF8_TrailingBytes(c);
501 if (trailing_bytes)
502 {
503 if (bytes - i != trailing_bytes + 1)
504 bytes = i;
505
506 break;
507 }
508 }
509 }
510 SDL_memcpy(dst, src, bytes);
511 }
512 dst[bytes] = '\0';
513 return bytes;
514 }
515
516 size_t
SDL_strlcat(SDL_INOUT_Z_CAP (maxlen)char * dst,const char * src,size_t maxlen)517 SDL_strlcat(SDL_INOUT_Z_CAP(maxlen) char *dst, const char *src, size_t maxlen)
518 {
519 #if defined(HAVE_STRLCAT)
520 return strlcat(dst, src, maxlen);
521 #else
522 size_t dstlen = SDL_strlen(dst);
523 size_t srclen = SDL_strlen(src);
524 if (dstlen < maxlen) {
525 SDL_strlcpy(dst + dstlen, src, maxlen - dstlen);
526 }
527 return dstlen + srclen;
528 #endif /* HAVE_STRLCAT */
529 }
530
531 char *
SDL_strdup(const char * string)532 SDL_strdup(const char *string)
533 {
534 #if defined(HAVE_STRDUP)
535 return strdup(string);
536 #else
537 size_t len = SDL_strlen(string) + 1;
538 char *newstr = SDL_malloc(len);
539 if (newstr) {
540 SDL_strlcpy(newstr, string, len);
541 }
542 return newstr;
543 #endif /* HAVE_STRDUP */
544 }
545
546 char *
SDL_strrev(char * string)547 SDL_strrev(char *string)
548 {
549 #if defined(HAVE__STRREV)
550 return _strrev(string);
551 #else
552 size_t len = SDL_strlen(string);
553 char *a = &string[0];
554 char *b = &string[len - 1];
555 len /= 2;
556 while (len--) {
557 char c = *a;
558 *a++ = *b;
559 *b-- = c;
560 }
561 return string;
562 #endif /* HAVE__STRREV */
563 }
564
565 char *
SDL_strupr(char * string)566 SDL_strupr(char *string)
567 {
568 #if defined(HAVE__STRUPR)
569 return _strupr(string);
570 #else
571 char *bufp = string;
572 while (*bufp) {
573 *bufp = SDL_toupper((unsigned char) *bufp);
574 ++bufp;
575 }
576 return string;
577 #endif /* HAVE__STRUPR */
578 }
579
580 char *
SDL_strlwr(char * string)581 SDL_strlwr(char *string)
582 {
583 #if defined(HAVE__STRLWR)
584 return _strlwr(string);
585 #else
586 char *bufp = string;
587 while (*bufp) {
588 *bufp = SDL_tolower((unsigned char) *bufp);
589 ++bufp;
590 }
591 return string;
592 #endif /* HAVE__STRLWR */
593 }
594
595 char *
SDL_strchr(const char * string,int c)596 SDL_strchr(const char *string, int c)
597 {
598 #ifdef HAVE_STRCHR
599 return SDL_const_cast(char*,strchr(string, c));
600 #elif defined(HAVE_INDEX)
601 return SDL_const_cast(char*,index(string, c));
602 #else
603 while (*string) {
604 if (*string == c) {
605 return (char *) string;
606 }
607 ++string;
608 }
609 return NULL;
610 #endif /* HAVE_STRCHR */
611 }
612
613 char *
SDL_strrchr(const char * string,int c)614 SDL_strrchr(const char *string, int c)
615 {
616 #ifdef HAVE_STRRCHR
617 return SDL_const_cast(char*,strrchr(string, c));
618 #elif defined(HAVE_RINDEX)
619 return SDL_const_cast(char*,rindex(string, c));
620 #else
621 const char *bufp = string + SDL_strlen(string) - 1;
622 while (bufp >= string) {
623 if (*bufp == c) {
624 return (char *) bufp;
625 }
626 --bufp;
627 }
628 return NULL;
629 #endif /* HAVE_STRRCHR */
630 }
631
632 char *
SDL_strstr(const char * haystack,const char * needle)633 SDL_strstr(const char *haystack, const char *needle)
634 {
635 #if defined(HAVE_STRSTR)
636 return SDL_const_cast(char*,strstr(haystack, needle));
637 #else
638 size_t length = SDL_strlen(needle);
639 while (*haystack) {
640 if (SDL_strncmp(haystack, needle, length) == 0) {
641 return (char *) haystack;
642 }
643 ++haystack;
644 }
645 return NULL;
646 #endif /* HAVE_STRSTR */
647 }
648
649 #if !defined(HAVE__LTOA) || !defined(HAVE__I64TOA) || \
650 !defined(HAVE__ULTOA) || !defined(HAVE__UI64TOA)
651 static const char ntoa_table[] = {
652 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
653 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
654 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
655 'U', 'V', 'W', 'X', 'Y', 'Z'
656 };
657 #endif /* ntoa() conversion table */
658
659 char *
SDL_itoa(int value,char * string,int radix)660 SDL_itoa(int value, char *string, int radix)
661 {
662 #ifdef HAVE_ITOA
663 return itoa(value, string, radix);
664 #else
665 return SDL_ltoa((long)value, string, radix);
666 #endif /* HAVE_ITOA */
667 }
668
669 char *
SDL_uitoa(unsigned int value,char * string,int radix)670 SDL_uitoa(unsigned int value, char *string, int radix)
671 {
672 #ifdef HAVE__UITOA
673 return _uitoa(value, string, radix);
674 #else
675 return SDL_ultoa((unsigned long)value, string, radix);
676 #endif /* HAVE__UITOA */
677 }
678
679 char *
SDL_ltoa(long value,char * string,int radix)680 SDL_ltoa(long value, char *string, int radix)
681 {
682 #if defined(HAVE__LTOA)
683 return _ltoa(value, string, radix);
684 #else
685 char *bufp = string;
686
687 if (value < 0) {
688 *bufp++ = '-';
689 SDL_ultoa(-value, bufp, radix);
690 } else {
691 SDL_ultoa(value, bufp, radix);
692 }
693
694 return string;
695 #endif /* HAVE__LTOA */
696 }
697
698 char *
SDL_ultoa(unsigned long value,char * string,int radix)699 SDL_ultoa(unsigned long value, char *string, int radix)
700 {
701 #if defined(HAVE__ULTOA)
702 return _ultoa(value, string, radix);
703 #else
704 char *bufp = string;
705
706 if (value) {
707 while (value > 0) {
708 *bufp++ = ntoa_table[value % radix];
709 value /= radix;
710 }
711 } else {
712 *bufp++ = '0';
713 }
714 *bufp = '\0';
715
716 /* The numbers went into the string backwards. :) */
717 SDL_strrev(string);
718
719 return string;
720 #endif /* HAVE__ULTOA */
721 }
722
723 char *
SDL_lltoa(Sint64 value,char * string,int radix)724 SDL_lltoa(Sint64 value, char *string, int radix)
725 {
726 #if defined(HAVE__I64TOA)
727 return _i64toa(value, string, radix);
728 #else
729 char *bufp = string;
730
731 if (value < 0) {
732 *bufp++ = '-';
733 SDL_ulltoa(-value, bufp, radix);
734 } else {
735 SDL_ulltoa(value, bufp, radix);
736 }
737
738 return string;
739 #endif /* HAVE__I64TOA */
740 }
741
742 char *
SDL_ulltoa(Uint64 value,char * string,int radix)743 SDL_ulltoa(Uint64 value, char *string, int radix)
744 {
745 #if defined(HAVE__UI64TOA)
746 return _ui64toa(value, string, radix);
747 #else
748 char *bufp = string;
749
750 if (value) {
751 while (value > 0) {
752 *bufp++ = ntoa_table[value % radix];
753 value /= radix;
754 }
755 } else {
756 *bufp++ = '0';
757 }
758 *bufp = '\0';
759
760 /* The numbers went into the string backwards. :) */
761 SDL_strrev(string);
762
763 return string;
764 #endif /* HAVE__UI64TOA */
765 }
766
SDL_atoi(const char * string)767 int SDL_atoi(const char *string)
768 {
769 #ifdef HAVE_ATOI
770 return atoi(string);
771 #else
772 return SDL_strtol(string, NULL, 0);
773 #endif /* HAVE_ATOI */
774 }
775
SDL_atof(const char * string)776 double SDL_atof(const char *string)
777 {
778 #ifdef HAVE_ATOF
779 return (double) atof(string);
780 #else
781 return SDL_strtod(string, NULL);
782 #endif /* HAVE_ATOF */
783 }
784
785 long
SDL_strtol(const char * string,char ** endp,int base)786 SDL_strtol(const char *string, char **endp, int base)
787 {
788 #if defined(HAVE_STRTOL)
789 return strtol(string, endp, base);
790 #else
791 size_t len;
792 long value;
793
794 if (!base) {
795 if ((SDL_strlen(string) > 2) && (SDL_strncmp(string, "0x", 2) == 0)) {
796 base = 16;
797 } else {
798 base = 10;
799 }
800 }
801
802 len = SDL_ScanLong(string, base, &value);
803 if (endp) {
804 *endp = (char *) string + len;
805 }
806 return value;
807 #endif /* HAVE_STRTOL */
808 }
809
810 unsigned long
SDL_strtoul(const char * string,char ** endp,int base)811 SDL_strtoul(const char *string, char **endp, int base)
812 {
813 #if defined(HAVE_STRTOUL)
814 return strtoul(string, endp, base);
815 #else
816 size_t len;
817 unsigned long value;
818
819 if (!base) {
820 if ((SDL_strlen(string) > 2) && (SDL_strncmp(string, "0x", 2) == 0)) {
821 base = 16;
822 } else {
823 base = 10;
824 }
825 }
826
827 len = SDL_ScanUnsignedLong(string, base, &value);
828 if (endp) {
829 *endp = (char *) string + len;
830 }
831 return value;
832 #endif /* HAVE_STRTOUL */
833 }
834
835 Sint64
SDL_strtoll(const char * string,char ** endp,int base)836 SDL_strtoll(const char *string, char **endp, int base)
837 {
838 #if defined(HAVE_STRTOLL)
839 return strtoll(string, endp, base);
840 #else
841 size_t len;
842 Sint64 value;
843
844 if (!base) {
845 if ((SDL_strlen(string) > 2) && (SDL_strncmp(string, "0x", 2) == 0)) {
846 base = 16;
847 } else {
848 base = 10;
849 }
850 }
851
852 len = SDL_ScanLongLong(string, base, &value);
853 if (endp) {
854 *endp = (char *) string + len;
855 }
856 return value;
857 #endif /* HAVE_STRTOLL */
858 }
859
860 Uint64
SDL_strtoull(const char * string,char ** endp,int base)861 SDL_strtoull(const char *string, char **endp, int base)
862 {
863 #if defined(HAVE_STRTOULL)
864 return strtoull(string, endp, base);
865 #else
866 size_t len;
867 Uint64 value;
868
869 if (!base) {
870 if ((SDL_strlen(string) > 2) && (SDL_strncmp(string, "0x", 2) == 0)) {
871 base = 16;
872 } else {
873 base = 10;
874 }
875 }
876
877 len = SDL_ScanUnsignedLongLong(string, base, &value);
878 if (endp) {
879 *endp = (char *) string + len;
880 }
881 return value;
882 #endif /* HAVE_STRTOULL */
883 }
884
885 double
SDL_strtod(const char * string,char ** endp)886 SDL_strtod(const char *string, char **endp)
887 {
888 #if defined(HAVE_STRTOD)
889 return strtod(string, endp);
890 #else
891 size_t len;
892 double value;
893
894 len = SDL_ScanFloat(string, &value);
895 if (endp) {
896 *endp = (char *) string + len;
897 }
898 return value;
899 #endif /* HAVE_STRTOD */
900 }
901
902 int
SDL_strcmp(const char * str1,const char * str2)903 SDL_strcmp(const char *str1, const char *str2)
904 {
905 #if defined(HAVE_STRCMP)
906 return strcmp(str1, str2);
907 #else
908 while (*str1 && *str2) {
909 if (*str1 != *str2)
910 break;
911 ++str1;
912 ++str2;
913 }
914 return (int) ((unsigned char) *str1 - (unsigned char) *str2);
915 #endif /* HAVE_STRCMP */
916 }
917
918 int
SDL_strncmp(const char * str1,const char * str2,size_t maxlen)919 SDL_strncmp(const char *str1, const char *str2, size_t maxlen)
920 {
921 #if defined(HAVE_STRNCMP)
922 return strncmp(str1, str2, maxlen);
923 #else
924 while (*str1 && *str2 && maxlen) {
925 if (*str1 != *str2)
926 break;
927 ++str1;
928 ++str2;
929 --maxlen;
930 }
931 if (!maxlen) {
932 return 0;
933 }
934 return (int) ((unsigned char) *str1 - (unsigned char) *str2);
935 #endif /* HAVE_STRNCMP */
936 }
937
938 int
SDL_strcasecmp(const char * str1,const char * str2)939 SDL_strcasecmp(const char *str1, const char *str2)
940 {
941 #ifdef HAVE_STRCASECMP
942 return strcasecmp(str1, str2);
943 #elif defined(HAVE__STRICMP)
944 return _stricmp(str1, str2);
945 #else
946 char a = 0;
947 char b = 0;
948 while (*str1 && *str2) {
949 a = SDL_toupper((unsigned char) *str1);
950 b = SDL_toupper((unsigned char) *str2);
951 if (a != b)
952 break;
953 ++str1;
954 ++str2;
955 }
956 a = SDL_toupper(*str1);
957 b = SDL_toupper(*str2);
958 return (int) ((unsigned char) a - (unsigned char) b);
959 #endif /* HAVE_STRCASECMP */
960 }
961
962 int
SDL_strncasecmp(const char * str1,const char * str2,size_t maxlen)963 SDL_strncasecmp(const char *str1, const char *str2, size_t maxlen)
964 {
965 #ifdef HAVE_STRNCASECMP
966 return strncasecmp(str1, str2, maxlen);
967 #elif defined(HAVE__STRNICMP)
968 return _strnicmp(str1, str2, maxlen);
969 #else
970 char a = 0;
971 char b = 0;
972 while (*str1 && *str2 && maxlen) {
973 a = SDL_tolower((unsigned char) *str1);
974 b = SDL_tolower((unsigned char) *str2);
975 if (a != b)
976 break;
977 ++str1;
978 ++str2;
979 --maxlen;
980 }
981 if (maxlen == 0) {
982 return 0;
983 } else {
984 a = SDL_tolower((unsigned char) *str1);
985 b = SDL_tolower((unsigned char) *str2);
986 return (int) ((unsigned char) a - (unsigned char) b);
987 }
988 #endif /* HAVE_STRNCASECMP */
989 }
990
991 int
SDL_sscanf(const char * text,SDL_SCANF_FORMAT_STRING const char * fmt,...)992 SDL_sscanf(const char *text, SDL_SCANF_FORMAT_STRING const char *fmt, ...)
993 {
994 int rc;
995 va_list ap;
996 va_start(ap, fmt);
997 rc = SDL_vsscanf(text, fmt, ap);
998 va_end(ap);
999 return rc;
1000 }
1001
1002 #ifdef HAVE_VSSCANF
1003 int
SDL_vsscanf(const char * text,const char * fmt,va_list ap)1004 SDL_vsscanf(const char *text, const char *fmt, va_list ap)
1005 {
1006 return vsscanf(text, fmt, ap);
1007 }
1008 #else
1009 int
SDL_vsscanf(const char * text,const char * fmt,va_list ap)1010 SDL_vsscanf(const char *text, const char *fmt, va_list ap)
1011 {
1012 int retval = 0;
1013
1014 while (*fmt) {
1015 if (*fmt == ' ') {
1016 while (SDL_isspace((unsigned char) *text)) {
1017 ++text;
1018 }
1019 ++fmt;
1020 continue;
1021 }
1022 if (*fmt == '%') {
1023 SDL_bool done = SDL_FALSE;
1024 long count = 0;
1025 int radix = 10;
1026 enum
1027 {
1028 DO_SHORT,
1029 DO_INT,
1030 DO_LONG,
1031 DO_LONGLONG
1032 } inttype = DO_INT;
1033 SDL_bool suppress = SDL_FALSE;
1034
1035 ++fmt;
1036 if (*fmt == '%') {
1037 if (*text == '%') {
1038 ++text;
1039 ++fmt;
1040 continue;
1041 }
1042 break;
1043 }
1044 if (*fmt == '*') {
1045 suppress = SDL_TRUE;
1046 ++fmt;
1047 }
1048 fmt += SDL_ScanLong(fmt, 10, &count);
1049
1050 if (*fmt == 'c') {
1051 if (!count) {
1052 count = 1;
1053 }
1054 if (suppress) {
1055 while (count--) {
1056 ++text;
1057 }
1058 } else {
1059 char *valuep = va_arg(ap, char *);
1060 while (count--) {
1061 *valuep++ = *text++;
1062 }
1063 ++retval;
1064 }
1065 continue;
1066 }
1067
1068 while (SDL_isspace((unsigned char) *text)) {
1069 ++text;
1070 }
1071
1072 /* FIXME: implement more of the format specifiers */
1073 while (!done) {
1074 switch (*fmt) {
1075 case '*':
1076 suppress = SDL_TRUE;
1077 break;
1078 case 'h':
1079 if (inttype > DO_SHORT) {
1080 ++inttype;
1081 }
1082 break;
1083 case 'l':
1084 if (inttype < DO_LONGLONG) {
1085 ++inttype;
1086 }
1087 break;
1088 case 'I':
1089 if (SDL_strncmp(fmt, "I64", 3) == 0) {
1090 fmt += 2;
1091 inttype = DO_LONGLONG;
1092 }
1093 break;
1094 case 'i':
1095 {
1096 int index = 0;
1097 if (text[index] == '-') {
1098 ++index;
1099 }
1100 if (text[index] == '0') {
1101 if (SDL_tolower((unsigned char) text[index + 1]) == 'x') {
1102 radix = 16;
1103 } else {
1104 radix = 8;
1105 }
1106 }
1107 }
1108 /* Fall through to %d handling */
1109 case 'd':
1110 if (inttype == DO_LONGLONG) {
1111 Sint64 value;
1112 text += SDL_ScanLongLong(text, radix, &value);
1113 if (!suppress) {
1114 Sint64 *valuep = va_arg(ap, Sint64 *);
1115 *valuep = value;
1116 ++retval;
1117 }
1118 } else {
1119 long value;
1120 text += SDL_ScanLong(text, radix, &value);
1121 if (!suppress) {
1122 switch (inttype) {
1123 case DO_SHORT:
1124 {
1125 short *valuep = va_arg(ap, short *);
1126 *valuep = (short) value;
1127 }
1128 break;
1129 case DO_INT:
1130 {
1131 int *valuep = va_arg(ap, int *);
1132 *valuep = (int) value;
1133 }
1134 break;
1135 case DO_LONG:
1136 {
1137 long *valuep = va_arg(ap, long *);
1138 *valuep = value;
1139 }
1140 break;
1141 case DO_LONGLONG:
1142 /* Handled above */
1143 break;
1144 }
1145 ++retval;
1146 }
1147 }
1148 done = SDL_TRUE;
1149 break;
1150 case 'o':
1151 if (radix == 10) {
1152 radix = 8;
1153 }
1154 /* Fall through to unsigned handling */
1155 case 'x':
1156 case 'X':
1157 if (radix == 10) {
1158 radix = 16;
1159 }
1160 /* Fall through to unsigned handling */
1161 case 'u':
1162 if (inttype == DO_LONGLONG) {
1163 Uint64 value;
1164 text += SDL_ScanUnsignedLongLong(text, radix, &value);
1165 if (!suppress) {
1166 Uint64 *valuep = va_arg(ap, Uint64 *);
1167 *valuep = value;
1168 ++retval;
1169 }
1170 } else {
1171 unsigned long value;
1172 text += SDL_ScanUnsignedLong(text, radix, &value);
1173 if (!suppress) {
1174 switch (inttype) {
1175 case DO_SHORT:
1176 {
1177 short *valuep = va_arg(ap, short *);
1178 *valuep = (short) value;
1179 }
1180 break;
1181 case DO_INT:
1182 {
1183 int *valuep = va_arg(ap, int *);
1184 *valuep = (int) value;
1185 }
1186 break;
1187 case DO_LONG:
1188 {
1189 long *valuep = va_arg(ap, long *);
1190 *valuep = value;
1191 }
1192 break;
1193 case DO_LONGLONG:
1194 /* Handled above */
1195 break;
1196 }
1197 ++retval;
1198 }
1199 }
1200 done = SDL_TRUE;
1201 break;
1202 case 'p':
1203 {
1204 uintptr_t value;
1205 text += SDL_ScanUintPtrT(text, 16, &value);
1206 if (!suppress) {
1207 void **valuep = va_arg(ap, void **);
1208 *valuep = (void *) value;
1209 ++retval;
1210 }
1211 }
1212 done = SDL_TRUE;
1213 break;
1214 case 'f':
1215 {
1216 double value;
1217 text += SDL_ScanFloat(text, &value);
1218 if (!suppress) {
1219 float *valuep = va_arg(ap, float *);
1220 *valuep = (float) value;
1221 ++retval;
1222 }
1223 }
1224 done = SDL_TRUE;
1225 break;
1226 case 's':
1227 if (suppress) {
1228 while (!SDL_isspace((unsigned char) *text)) {
1229 ++text;
1230 if (count) {
1231 if (--count == 0) {
1232 break;
1233 }
1234 }
1235 }
1236 } else {
1237 char *valuep = va_arg(ap, char *);
1238 while (!SDL_isspace((unsigned char) *text)) {
1239 *valuep++ = *text++;
1240 if (count) {
1241 if (--count == 0) {
1242 break;
1243 }
1244 }
1245 }
1246 *valuep = '\0';
1247 ++retval;
1248 }
1249 done = SDL_TRUE;
1250 break;
1251 default:
1252 done = SDL_TRUE;
1253 break;
1254 }
1255 ++fmt;
1256 }
1257 continue;
1258 }
1259 if (*text == *fmt) {
1260 ++text;
1261 ++fmt;
1262 continue;
1263 }
1264 /* Text didn't match format specifier */
1265 break;
1266 }
1267
1268 return retval;
1269 }
1270 #endif /* HAVE_VSSCANF */
1271
1272 int
SDL_snprintf(SDL_OUT_Z_CAP (maxlen)char * text,size_t maxlen,SDL_PRINTF_FORMAT_STRING const char * fmt,...)1273 SDL_snprintf(SDL_OUT_Z_CAP(maxlen) char *text, size_t maxlen, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
1274 {
1275 va_list ap;
1276 int retval;
1277
1278 va_start(ap, fmt);
1279 retval = SDL_vsnprintf(text, maxlen, fmt, ap);
1280 va_end(ap);
1281
1282 return retval;
1283 }
1284
1285 #ifdef HAVE_VSNPRINTF
SDL_vsnprintf(SDL_OUT_Z_CAP (maxlen)char * text,size_t maxlen,const char * fmt,va_list ap)1286 int SDL_vsnprintf(SDL_OUT_Z_CAP(maxlen) char *text, size_t maxlen, const char *fmt, va_list ap)
1287 {
1288 if (!fmt) {
1289 fmt = "";
1290 }
1291 return vsnprintf(text, maxlen, fmt, ap);
1292 }
1293 #else
1294 /* FIXME: implement more of the format specifiers */
1295 typedef enum
1296 {
1297 SDL_CASE_NOCHANGE,
1298 SDL_CASE_LOWER,
1299 SDL_CASE_UPPER
1300 } SDL_letter_case;
1301
1302 typedef struct
1303 {
1304 SDL_bool left_justify;
1305 SDL_bool force_sign;
1306 SDL_bool force_type;
1307 SDL_bool pad_zeroes;
1308 SDL_letter_case force_case;
1309 int width;
1310 int radix;
1311 int precision;
1312 } SDL_FormatInfo;
1313
1314 static size_t
SDL_PrintString(char * text,size_t maxlen,SDL_FormatInfo * info,const char * string)1315 SDL_PrintString(char *text, size_t maxlen, SDL_FormatInfo *info, const char *string)
1316 {
1317 size_t length = 0;
1318 size_t slen;
1319
1320 if (info && info->width && (size_t)info->width > SDL_strlen(string)) {
1321 char fill = info->pad_zeroes ? '0' : ' ';
1322 size_t width = info->width - SDL_strlen(string);
1323 while (width-- > 0 && maxlen > 0) {
1324 *text++ = fill;
1325 ++length;
1326 --maxlen;
1327 }
1328 }
1329
1330 slen = SDL_strlcpy(text, string, maxlen);
1331 length += SDL_min(slen, maxlen);
1332
1333 if (info) {
1334 if (info->force_case == SDL_CASE_LOWER) {
1335 SDL_strlwr(text);
1336 } else if (info->force_case == SDL_CASE_UPPER) {
1337 SDL_strupr(text);
1338 }
1339 }
1340 return length;
1341 }
1342
1343 static size_t
SDL_PrintLong(char * text,size_t maxlen,SDL_FormatInfo * info,long value)1344 SDL_PrintLong(char *text, size_t maxlen, SDL_FormatInfo *info, long value)
1345 {
1346 char num[130];
1347
1348 SDL_ltoa(value, num, info ? info->radix : 10);
1349 return SDL_PrintString(text, maxlen, info, num);
1350 }
1351
1352 static size_t
SDL_PrintUnsignedLong(char * text,size_t maxlen,SDL_FormatInfo * info,unsigned long value)1353 SDL_PrintUnsignedLong(char *text, size_t maxlen, SDL_FormatInfo *info, unsigned long value)
1354 {
1355 char num[130];
1356
1357 SDL_ultoa(value, num, info ? info->radix : 10);
1358 return SDL_PrintString(text, maxlen, info, num);
1359 }
1360
1361 static size_t
SDL_PrintLongLong(char * text,size_t maxlen,SDL_FormatInfo * info,Sint64 value)1362 SDL_PrintLongLong(char *text, size_t maxlen, SDL_FormatInfo *info, Sint64 value)
1363 {
1364 char num[130];
1365
1366 SDL_lltoa(value, num, info ? info->radix : 10);
1367 return SDL_PrintString(text, maxlen, info, num);
1368 }
1369
1370 static size_t
SDL_PrintUnsignedLongLong(char * text,size_t maxlen,SDL_FormatInfo * info,Uint64 value)1371 SDL_PrintUnsignedLongLong(char *text, size_t maxlen, SDL_FormatInfo *info, Uint64 value)
1372 {
1373 char num[130];
1374
1375 SDL_ulltoa(value, num, info ? info->radix : 10);
1376 return SDL_PrintString(text, maxlen, info, num);
1377 }
1378
1379 static size_t
SDL_PrintFloat(char * text,size_t maxlen,SDL_FormatInfo * info,double arg)1380 SDL_PrintFloat(char *text, size_t maxlen, SDL_FormatInfo *info, double arg)
1381 {
1382 int width;
1383 size_t len;
1384 size_t left = maxlen;
1385 char *textstart = text;
1386
1387 if (arg) {
1388 /* This isn't especially accurate, but hey, it's easy. :) */
1389 unsigned long value;
1390
1391 if (arg < 0) {
1392 if (left > 1) {
1393 *text = '-';
1394 --left;
1395 }
1396 ++text;
1397 arg = -arg;
1398 } else if (info->force_sign) {
1399 if (left > 1) {
1400 *text = '+';
1401 --left;
1402 }
1403 ++text;
1404 }
1405 value = (unsigned long) arg;
1406 len = SDL_PrintUnsignedLong(text, left, NULL, value);
1407 if (len >= left) {
1408 text += (left > 1) ? left - 1 : 0;
1409 left = SDL_min(left, 1);
1410 } else {
1411 text += len;
1412 left -= len;
1413 }
1414 arg -= value;
1415 if (info->precision < 0) {
1416 info->precision = 6;
1417 }
1418 if (info->force_type || info->precision > 0) {
1419 int mult = 10;
1420 if (left > 1) {
1421 *text = '.';
1422 --left;
1423 }
1424 ++text;
1425 while (info->precision-- > 0) {
1426 value = (unsigned long) (arg * mult);
1427 len = SDL_PrintUnsignedLong(text, left, NULL, value);
1428 if (len >= left) {
1429 text += (left > 1) ? left - 1 : 0;
1430 left = SDL_min(left, 1);
1431 } else {
1432 text += len;
1433 left -= len;
1434 }
1435 arg -= (double) value / mult;
1436 mult *= 10;
1437 }
1438 }
1439 } else {
1440 if (left > 1) {
1441 *text = '0';
1442 --left;
1443 }
1444 ++text;
1445 if (info->force_type) {
1446 if (left > 1) {
1447 *text = '.';
1448 --left;
1449 }
1450 ++text;
1451 }
1452 }
1453
1454 width = info->width - (int)(text - textstart);
1455 if (width > 0) {
1456 char fill = info->pad_zeroes ? '0' : ' ';
1457 char *end = text+left-1;
1458 len = (text - textstart);
1459 for (len = (text - textstart); len--; ) {
1460 if ((textstart+len+width) < end) {
1461 *(textstart+len+width) = *(textstart+len);
1462 }
1463 }
1464 len = (size_t)width;
1465 if (len >= left) {
1466 text += (left > 1) ? left - 1 : 0;
1467 left = SDL_min(left, 1);
1468 } else {
1469 text += len;
1470 left -= len;
1471 }
1472 while (len--) {
1473 if (textstart+len < end) {
1474 textstart[len] = fill;
1475 }
1476 }
1477 }
1478
1479 return (text - textstart);
1480 }
1481
1482 int
SDL_vsnprintf(SDL_OUT_Z_CAP (maxlen)char * text,size_t maxlen,const char * fmt,va_list ap)1483 SDL_vsnprintf(SDL_OUT_Z_CAP(maxlen) char *text, size_t maxlen, const char *fmt, va_list ap)
1484 {
1485 size_t left = maxlen;
1486 char *textstart = text;
1487
1488 if (!fmt) {
1489 fmt = "";
1490 }
1491 while (*fmt) {
1492 if (*fmt == '%') {
1493 SDL_bool done = SDL_FALSE;
1494 size_t len = 0;
1495 SDL_bool check_flag;
1496 SDL_FormatInfo info;
1497 enum
1498 {
1499 DO_INT,
1500 DO_LONG,
1501 DO_LONGLONG
1502 } inttype = DO_INT;
1503
1504 SDL_zero(info);
1505 info.radix = 10;
1506 info.precision = -1;
1507
1508 check_flag = SDL_TRUE;
1509 while (check_flag) {
1510 ++fmt;
1511 switch (*fmt) {
1512 case '-':
1513 info.left_justify = SDL_TRUE;
1514 break;
1515 case '+':
1516 info.force_sign = SDL_TRUE;
1517 break;
1518 case '#':
1519 info.force_type = SDL_TRUE;
1520 break;
1521 case '0':
1522 info.pad_zeroes = SDL_TRUE;
1523 break;
1524 default:
1525 check_flag = SDL_FALSE;
1526 break;
1527 }
1528 }
1529
1530 if (*fmt >= '0' && *fmt <= '9') {
1531 info.width = SDL_strtol(fmt, (char **)&fmt, 0);
1532 }
1533
1534 if (*fmt == '.') {
1535 ++fmt;
1536 if (*fmt >= '0' && *fmt <= '9') {
1537 info.precision = SDL_strtol(fmt, (char **)&fmt, 0);
1538 } else {
1539 info.precision = 0;
1540 }
1541 }
1542
1543 while (!done) {
1544 switch (*fmt) {
1545 case '%':
1546 if (left > 1) {
1547 *text = '%';
1548 }
1549 len = 1;
1550 done = SDL_TRUE;
1551 break;
1552 case 'c':
1553 /* char is promoted to int when passed through (...) */
1554 if (left > 1) {
1555 *text = (char) va_arg(ap, int);
1556 }
1557 len = 1;
1558 done = SDL_TRUE;
1559 break;
1560 case 'h':
1561 /* short is promoted to int when passed through (...) */
1562 break;
1563 case 'l':
1564 if (inttype < DO_LONGLONG) {
1565 ++inttype;
1566 }
1567 break;
1568 case 'I':
1569 if (SDL_strncmp(fmt, "I64", 3) == 0) {
1570 fmt += 2;
1571 inttype = DO_LONGLONG;
1572 }
1573 break;
1574 case 'i':
1575 case 'd':
1576 switch (inttype) {
1577 case DO_INT:
1578 len = SDL_PrintLong(text, left, &info,
1579 (long) va_arg(ap, int));
1580 break;
1581 case DO_LONG:
1582 len = SDL_PrintLong(text, left, &info,
1583 va_arg(ap, long));
1584 break;
1585 case DO_LONGLONG:
1586 len = SDL_PrintLongLong(text, left, &info,
1587 va_arg(ap, Sint64));
1588 break;
1589 }
1590 done = SDL_TRUE;
1591 break;
1592 case 'p':
1593 case 'x':
1594 info.force_case = SDL_CASE_LOWER;
1595 /* Fall through to 'X' handling */
1596 case 'X':
1597 if (info.force_case == SDL_CASE_NOCHANGE) {
1598 info.force_case = SDL_CASE_UPPER;
1599 }
1600 if (info.radix == 10) {
1601 info.radix = 16;
1602 }
1603 if (*fmt == 'p') {
1604 inttype = DO_LONG;
1605 }
1606 /* Fall through to unsigned handling */
1607 case 'o':
1608 if (info.radix == 10) {
1609 info.radix = 8;
1610 }
1611 /* Fall through to unsigned handling */
1612 case 'u':
1613 info.pad_zeroes = SDL_TRUE;
1614 switch (inttype) {
1615 case DO_INT:
1616 len = SDL_PrintUnsignedLong(text, left, &info,
1617 (unsigned long)
1618 va_arg(ap, unsigned int));
1619 break;
1620 case DO_LONG:
1621 len = SDL_PrintUnsignedLong(text, left, &info,
1622 va_arg(ap, unsigned long));
1623 break;
1624 case DO_LONGLONG:
1625 len = SDL_PrintUnsignedLongLong(text, left, &info,
1626 va_arg(ap, Uint64));
1627 break;
1628 }
1629 done = SDL_TRUE;
1630 break;
1631 case 'f':
1632 len = SDL_PrintFloat(text, left, &info, va_arg(ap, double));
1633 done = SDL_TRUE;
1634 break;
1635 case 's':
1636 len = SDL_PrintString(text, left, &info, va_arg(ap, char *));
1637 done = SDL_TRUE;
1638 break;
1639 default:
1640 done = SDL_TRUE;
1641 break;
1642 }
1643 ++fmt;
1644 }
1645 if (len >= left) {
1646 text += (left > 1) ? left - 1 : 0;
1647 left = SDL_min(left, 1);
1648 } else {
1649 text += len;
1650 left -= len;
1651 }
1652 } else {
1653 if (left > 1) {
1654 *text = *fmt;
1655 --left;
1656 }
1657 ++fmt;
1658 ++text;
1659 }
1660 }
1661 if (left > 0) {
1662 *text = '\0';
1663 }
1664 return (int)(text - textstart);
1665 }
1666 #endif /* HAVE_VSNPRINTF */
1667
1668 /* vi: set ts=4 sw=4 expandtab: */
1669