| | |
| | | /* |
| | | Simple DirectMedia Layer |
| | | Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org> |
| | | Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org> |
| | | |
| | | This software is provided 'as-is', without any express or implied |
| | | warranty. In no event will the authors be held liable for any damages |
| | |
| | | misrepresented as being the original software. |
| | | 3. This notice may not be removed or altered from any source distribution. |
| | | */ |
| | | |
| | | #if defined(__clang_analyzer__) && !defined(SDL_DISABLE_ANALYZE_MACROS) |
| | | #if defined(__clang_analyzer__) |
| | | #define SDL_DISABLE_ANALYZE_MACROS 1 |
| | | #endif |
| | | |
| | |
| | | |
| | | #include "SDL_stdinc.h" |
| | | |
| | | |
| | | #if !defined(HAVE_VSSCANF) || !defined(HAVE_STRTOL) || !defined(HAVE_STRTOUL) || !defined(HAVE_STRTOLL) || !defined(HAVE_STRTOULL) || !defined(HAVE_STRTOD) |
| | | #define SDL_isupperhex(X) (((X) >= 'A') && ((X) <= 'F')) |
| | | #define SDL_islowerhex(X) (((X) >= 'a') && ((X) <= 'f')) |
| | | #endif |
| | | |
| | | #define UTF8_IsLeadByte(c) ((c) >= 0xC0 && (c) <= 0xF4) |
| | | #define UTF8_IsTrailingByte(c) ((c) >= 0x80 && (c) <= 0xBF) |
| | |
| | | value += v; |
| | | ++text; |
| | | } |
| | | if (valuep) { |
| | | if (valuep && text > textstart) { |
| | | if (negative && value) { |
| | | *valuep = -value; |
| | | } else { |
| | |
| | | value += v; |
| | | ++text; |
| | | } |
| | | if (valuep) { |
| | | if (valuep && text > textstart) { |
| | | *valuep = value; |
| | | } |
| | | return (text - textstart); |
| | |
| | | value += v; |
| | | ++text; |
| | | } |
| | | if (valuep) { |
| | | if (valuep && text > textstart) { |
| | | *valuep = value; |
| | | } |
| | | return (text - textstart); |
| | |
| | | value += v; |
| | | ++text; |
| | | } |
| | | if (valuep) { |
| | | if (valuep && text > textstart) { |
| | | if (negative && value) { |
| | | *valuep = -value; |
| | | } else { |
| | |
| | | value += v; |
| | | ++text; |
| | | } |
| | | if (valuep) { |
| | | if (valuep && text > textstart) { |
| | | *valuep = value; |
| | | } |
| | | return (text - textstart); |
| | |
| | | ++text; |
| | | } |
| | | } |
| | | if (valuep) { |
| | | if (valuep && text > textstart) { |
| | | if (negative && value) { |
| | | *valuep = -value; |
| | | } else { |
| | |
| | | size_t left; |
| | | Uint32 *dstp4; |
| | | Uint8 *dstp1 = (Uint8 *) dst; |
| | | Uint32 value4 = (c | (c << 8) | (c << 16) | (c << 24)); |
| | | Uint8 value1 = (Uint8) c; |
| | | Uint8 value1; |
| | | Uint32 value4; |
| | | |
| | | /* The value used in memset() is a byte, passed as an int */ |
| | | c &= 0xff; |
| | | |
| | | /* The destination pointer needs to be aligned on a 4-byte boundary to |
| | | * execute a 32-bit set. Set first bytes manually if needed until it is |
| | | * aligned. */ |
| | | value1 = (Uint8)c; |
| | | while ((intptr_t)dstp1 & 0x3) { |
| | | if (len--) { |
| | | *dstp1++ = value1; |
| | |
| | | } |
| | | } |
| | | |
| | | value4 = (c | (c << 8) | (c << 16) | (c << 24)); |
| | | dstp4 = (Uint32 *) dstp1; |
| | | left = (len % 4); |
| | | len /= 4; |
| | |
| | | #endif /* HAVE_WCSLCAT */ |
| | | } |
| | | |
| | | wchar_t * |
| | | SDL_wcsdup(const wchar_t *string) |
| | | { |
| | | size_t len = ((SDL_wcslen(string) + 1) * sizeof(wchar_t)); |
| | | wchar_t *newstr = (wchar_t *)SDL_malloc(len); |
| | | if (newstr) { |
| | | SDL_memcpy(newstr, string, len); |
| | | } |
| | | return newstr; |
| | | } |
| | | |
| | | wchar_t * |
| | | SDL_wcsstr(const wchar_t *haystack, const wchar_t *needle) |
| | | { |
| | | #if defined(HAVE_WCSSTR) |
| | | return SDL_const_cast(wchar_t*,wcsstr(haystack, needle)); |
| | | #else |
| | | size_t length = SDL_wcslen(needle); |
| | | while (*haystack) { |
| | | if (SDL_wcsncmp(haystack, needle, length) == 0) { |
| | | return (wchar_t *)haystack; |
| | | } |
| | | ++haystack; |
| | | } |
| | | return NULL; |
| | | #endif /* HAVE_WCSSTR */ |
| | | } |
| | | |
| | | int |
| | | SDL_wcscmp(const wchar_t *str1, const wchar_t *str2) |
| | | { |
| | | #if defined(HAVE_WCSCMP) |
| | | return wcscmp(str1, str2); |
| | | #else |
| | | while (*str1 && *str2) { |
| | | if (*str1 != *str2) |
| | | break; |
| | | ++str1; |
| | | ++str2; |
| | | } |
| | | return (int)(*str1 - *str2); |
| | | #endif /* HAVE_WCSCMP */ |
| | | } |
| | | |
| | | int |
| | | SDL_wcsncmp(const wchar_t *str1, const wchar_t *str2, size_t maxlen) |
| | | { |
| | | #if defined(HAVE_WCSNCMP) |
| | | return wcsncmp(str1, str2, maxlen); |
| | | #else |
| | | while (*str1 && *str2) { |
| | | if (*str1 != *str2) |
| | | break; |
| | | ++str1; |
| | | ++str2; |
| | | } |
| | | return (int)(*str1 - *str2); |
| | | #endif /* HAVE_WCSNCMP */ |
| | | } |
| | | |
| | | size_t |
| | | SDL_strlcpy(SDL_OUT_Z_CAP(maxlen) char *dst, const char *src, size_t maxlen) |
| | | { |
| | |
| | | #endif /* HAVE_STRLCPY */ |
| | | } |
| | | |
| | | size_t SDL_utf8strlcpy(SDL_OUT_Z_CAP(dst_bytes) char *dst, const char *src, size_t dst_bytes) |
| | | size_t |
| | | SDL_utf8strlcpy(SDL_OUT_Z_CAP(dst_bytes) char *dst, const char *src, size_t dst_bytes) |
| | | { |
| | | size_t src_bytes = SDL_strlen(src); |
| | | size_t bytes = SDL_min(src_bytes, dst_bytes - 1); |
| | |
| | | } |
| | | |
| | | size_t |
| | | SDL_utf8strlen(const char *str) |
| | | { |
| | | size_t retval = 0; |
| | | const char *p = str; |
| | | char ch; |
| | | |
| | | while ((ch = *(p++)) != 0) { |
| | | /* if top two bits are 1 and 0, it's a continuation byte. */ |
| | | if ((ch & 0xc0) != 0x80) { |
| | | retval++; |
| | | } |
| | | } |
| | | |
| | | return retval; |
| | | } |
| | | |
| | | size_t |
| | | SDL_strlcat(SDL_INOUT_Z_CAP(maxlen) char *dst, const char *src, size_t maxlen) |
| | | { |
| | | #if defined(HAVE_STRLCAT) |
| | |
| | | char * |
| | | SDL_strdup(const char *string) |
| | | { |
| | | #if defined(HAVE_STRDUP) |
| | | return strdup(string); |
| | | #else |
| | | size_t len = SDL_strlen(string) + 1; |
| | | char *newstr = SDL_malloc(len); |
| | | char *newstr = (char *)SDL_malloc(len); |
| | | if (newstr) { |
| | | SDL_strlcpy(newstr, string, len); |
| | | SDL_memcpy(newstr, string, len); |
| | | } |
| | | return newstr; |
| | | #endif /* HAVE_STRDUP */ |
| | | } |
| | | |
| | | char * |
| | |
| | | double SDL_atof(const char *string) |
| | | { |
| | | #ifdef HAVE_ATOF |
| | | return (double) atof(string); |
| | | return atof(string); |
| | | #else |
| | | return SDL_strtod(string, NULL); |
| | | #endif /* HAVE_ATOF */ |
| | |
| | | return strtol(string, endp, base); |
| | | #else |
| | | size_t len; |
| | | long value; |
| | | long value = 0; |
| | | |
| | | if (!base) { |
| | | if ((SDL_strlen(string) > 2) && (SDL_strncmp(string, "0x", 2) == 0)) { |
| | |
| | | return strtoul(string, endp, base); |
| | | #else |
| | | size_t len; |
| | | unsigned long value; |
| | | unsigned long value = 0; |
| | | |
| | | if (!base) { |
| | | if ((SDL_strlen(string) > 2) && (SDL_strncmp(string, "0x", 2) == 0)) { |
| | |
| | | return strtoll(string, endp, base); |
| | | #else |
| | | size_t len; |
| | | Sint64 value; |
| | | Sint64 value = 0; |
| | | |
| | | if (!base) { |
| | | if ((SDL_strlen(string) > 2) && (SDL_strncmp(string, "0x", 2) == 0)) { |
| | |
| | | return strtoull(string, endp, base); |
| | | #else |
| | | size_t len; |
| | | Uint64 value; |
| | | Uint64 value = 0; |
| | | |
| | | if (!base) { |
| | | if ((SDL_strlen(string) > 2) && (SDL_strncmp(string, "0x", 2) == 0)) { |
| | |
| | | return strtod(string, endp); |
| | | #else |
| | | size_t len; |
| | | double value; |
| | | double value = 0.0; |
| | | |
| | | len = SDL_ScanFloat(string, &value); |
| | | if (endp) { |
| | |
| | | ++str1; |
| | | ++str2; |
| | | } |
| | | return (int) ((unsigned char) *str1 - (unsigned char) *str2); |
| | | return (int)((unsigned char) *str1 - (unsigned char) *str2); |
| | | #endif /* HAVE_STRCMP */ |
| | | } |
| | | |
| | |
| | | { |
| | | int retval = 0; |
| | | |
| | | if (!text || !*text) { |
| | | return -1; |
| | | } |
| | | |
| | | while (*fmt) { |
| | | if (*fmt == ' ') { |
| | | while (SDL_isspace((unsigned char) *text)) { |
| | |
| | | DO_LONG, |
| | | DO_LONGLONG |
| | | } inttype = DO_INT; |
| | | size_t advance; |
| | | SDL_bool suppress = SDL_FALSE; |
| | | |
| | | ++fmt; |
| | |
| | | case 'd': |
| | | if (inttype == DO_LONGLONG) { |
| | | Sint64 value; |
| | | text += SDL_ScanLongLong(text, radix, &value); |
| | | if (!suppress) { |
| | | advance = SDL_ScanLongLong(text, radix, &value); |
| | | text += advance; |
| | | if (advance && !suppress) { |
| | | Sint64 *valuep = va_arg(ap, Sint64 *); |
| | | *valuep = value; |
| | | ++retval; |
| | | } |
| | | } else { |
| | | long value; |
| | | text += SDL_ScanLong(text, radix, &value); |
| | | if (!suppress) { |
| | | advance = SDL_ScanLong(text, radix, &value); |
| | | text += advance; |
| | | if (advance && !suppress) { |
| | | switch (inttype) { |
| | | case DO_SHORT: |
| | | { |
| | |
| | | /* Fall through to unsigned handling */ |
| | | case 'u': |
| | | if (inttype == DO_LONGLONG) { |
| | | Uint64 value; |
| | | text += SDL_ScanUnsignedLongLong(text, radix, &value); |
| | | if (!suppress) { |
| | | Uint64 value = 0; |
| | | advance = SDL_ScanUnsignedLongLong(text, radix, &value); |
| | | text += advance; |
| | | if (advance && !suppress) { |
| | | Uint64 *valuep = va_arg(ap, Uint64 *); |
| | | *valuep = value; |
| | | ++retval; |
| | | } |
| | | } else { |
| | | unsigned long value; |
| | | text += SDL_ScanUnsignedLong(text, radix, &value); |
| | | if (!suppress) { |
| | | unsigned long value = 0; |
| | | advance = SDL_ScanUnsignedLong(text, radix, &value); |
| | | text += advance; |
| | | if (advance && !suppress) { |
| | | switch (inttype) { |
| | | case DO_SHORT: |
| | | { |
| | |
| | | break; |
| | | case 'p': |
| | | { |
| | | uintptr_t value; |
| | | text += SDL_ScanUintPtrT(text, 16, &value); |
| | | if (!suppress) { |
| | | uintptr_t value = 0; |
| | | advance = SDL_ScanUintPtrT(text, 16, &value); |
| | | text += advance; |
| | | if (advance && !suppress) { |
| | | void **valuep = va_arg(ap, void **); |
| | | *valuep = (void *) value; |
| | | ++retval; |
| | |
| | | case 'f': |
| | | { |
| | | double value; |
| | | text += SDL_ScanFloat(text, &value); |
| | | if (!suppress) { |
| | | advance = SDL_ScanFloat(text, &value); |
| | | text += advance; |
| | | if (advance && !suppress) { |
| | | float *valuep = va_arg(ap, float *); |
| | | *valuep = (float) value; |
| | | ++retval; |
| | |
| | | return retval; |
| | | } |
| | | |
| | | #ifdef HAVE_VSNPRINTF |
| | | #if defined(HAVE_LIBC) && defined(__WATCOMC__) |
| | | /* _vsnprintf() doesn't ensure nul termination */ |
| | | int SDL_vsnprintf(SDL_OUT_Z_CAP(maxlen) char *text, size_t maxlen, const char *fmt, va_list ap) |
| | | { |
| | | int retval; |
| | | if (!fmt) fmt = ""; |
| | | retval = _vsnprintf(text, maxlen, fmt, ap); |
| | | if (maxlen > 0) text[maxlen-1] = '\0'; |
| | | if (retval < 0) retval = (int) maxlen; |
| | | return retval; |
| | | } |
| | | #elif defined(HAVE_VSNPRINTF) |
| | | int SDL_vsnprintf(SDL_OUT_Z_CAP(maxlen) char *text, size_t maxlen, const char *fmt, va_list ap) |
| | | { |
| | | if (!fmt) { |
| | |
| | | |
| | | typedef struct |
| | | { |
| | | SDL_bool left_justify; |
| | | SDL_bool left_justify; /* for now: ignored. */ |
| | | SDL_bool force_sign; |
| | | SDL_bool force_type; |
| | | SDL_bool force_type; /* for now: used only by float printer, ignored otherwise. */ |
| | | SDL_bool pad_zeroes; |
| | | SDL_letter_case force_case; |
| | | int width; |
| | |
| | | SDL_PrintString(char *text, size_t maxlen, SDL_FormatInfo *info, const char *string) |
| | | { |
| | | size_t length = 0; |
| | | size_t slen, sz; |
| | | |
| | | if (info && info->width && (size_t)info->width > SDL_strlen(string)) { |
| | | char fill = info->pad_zeroes ? '0' : ' '; |
| | | size_t width = info->width - SDL_strlen(string); |
| | | while (width-- > 0 && maxlen > 0) { |
| | | *text++ = fill; |
| | | ++length; |
| | | --maxlen; |
| | | } |
| | | if (string == NULL) { |
| | | string = "(null)"; |
| | | } |
| | | |
| | | length += SDL_strlcpy(text, string, maxlen); |
| | | sz = SDL_strlen(string); |
| | | if (info && info->width > 0 && (size_t)info->width > sz) { |
| | | const char fill = info->pad_zeroes ? '0' : ' '; |
| | | size_t width = info->width - sz; |
| | | size_t filllen; |
| | | |
| | | if (info->precision >= 0 && (size_t)info->precision < sz) |
| | | width += sz - (size_t)info->precision; |
| | | |
| | | filllen = SDL_min(width, maxlen); |
| | | SDL_memset(text, fill, filllen); |
| | | text += filllen; |
| | | length += filllen; |
| | | maxlen -= filllen; |
| | | } |
| | | |
| | | slen = SDL_strlcpy(text, string, maxlen); |
| | | length += SDL_min(slen, maxlen); |
| | | |
| | | if (info) { |
| | | if (info->precision >= 0 && (size_t)info->precision < sz) { |
| | | slen = (size_t)info->precision; |
| | | if (slen < maxlen) { |
| | | text[slen] = 0; |
| | | length -= (sz - slen); |
| | | } |
| | | } |
| | | if (info->force_case == SDL_CASE_LOWER) { |
| | | SDL_strlwr(text); |
| | | } else if (info->force_case == SDL_CASE_UPPER) { |
| | |
| | | return length; |
| | | } |
| | | |
| | | static void |
| | | SDL_IntPrecisionAdjust(char *num, size_t maxlen, SDL_FormatInfo *info) |
| | | {/* left-pad num with zeroes. */ |
| | | size_t sz, pad, have_sign; |
| | | |
| | | if (!info) |
| | | return; |
| | | |
| | | have_sign = 0; |
| | | if (*num == '-' || *num == '+') { |
| | | have_sign = 1; |
| | | ++num; |
| | | --maxlen; |
| | | } |
| | | sz = SDL_strlen(num); |
| | | if (info->precision > 0 && sz < (size_t)info->precision) { |
| | | pad = (size_t)info->precision - sz; |
| | | if (pad + sz + 1 <= maxlen) { /* otherwise ignore the precision */ |
| | | SDL_memmove(num + pad, num, sz + 1); |
| | | SDL_memset(num, '0', pad); |
| | | } |
| | | } |
| | | info->precision = -1;/* so that SDL_PrintString() doesn't make a mess. */ |
| | | |
| | | if (info->pad_zeroes && info->width > 0 && (size_t)info->width > sz + have_sign) { |
| | | /* handle here: spaces are added before the sign |
| | | but zeroes must be placed _after_ the sign. */ |
| | | /* sz hasn't changed: we ignore pad_zeroes if a precision is given. */ |
| | | pad = (size_t)info->width - sz - have_sign; |
| | | if (pad + sz + 1 <= maxlen) { |
| | | SDL_memmove(num + pad, num, sz + 1); |
| | | SDL_memset(num, '0', pad); |
| | | } |
| | | info->width = 0; /* so that SDL_PrintString() doesn't make a mess. */ |
| | | } |
| | | } |
| | | |
| | | static size_t |
| | | SDL_PrintLong(char *text, size_t maxlen, SDL_FormatInfo *info, long value) |
| | | { |
| | | char num[130]; |
| | | char num[130], *p = num; |
| | | |
| | | SDL_ltoa(value, num, info ? info->radix : 10); |
| | | if (info->force_sign && value >= 0L) { |
| | | *p++ = '+'; |
| | | } |
| | | |
| | | SDL_ltoa(value, p, info ? info->radix : 10); |
| | | SDL_IntPrecisionAdjust(num, maxlen, info); |
| | | return SDL_PrintString(text, maxlen, info, num); |
| | | } |
| | | |
| | |
| | | char num[130]; |
| | | |
| | | SDL_ultoa(value, num, info ? info->radix : 10); |
| | | SDL_IntPrecisionAdjust(num, maxlen, info); |
| | | return SDL_PrintString(text, maxlen, info, num); |
| | | } |
| | | |
| | | static size_t |
| | | SDL_PrintLongLong(char *text, size_t maxlen, SDL_FormatInfo *info, Sint64 value) |
| | | { |
| | | char num[130]; |
| | | char num[130], *p = num; |
| | | |
| | | SDL_lltoa(value, num, info ? info->radix : 10); |
| | | if (info->force_sign && value >= (Sint64)0) { |
| | | *p++ = '+'; |
| | | } |
| | | |
| | | SDL_lltoa(value, p, info ? info->radix : 10); |
| | | SDL_IntPrecisionAdjust(num, maxlen, info); |
| | | return SDL_PrintString(text, maxlen, info, num); |
| | | } |
| | | |
| | |
| | | char num[130]; |
| | | |
| | | SDL_ulltoa(value, num, info ? info->radix : 10); |
| | | SDL_IntPrecisionAdjust(num, maxlen, info); |
| | | return SDL_PrintString(text, maxlen, info, num); |
| | | } |
| | | |
| | |
| | | } |
| | | value = (unsigned long) arg; |
| | | len = SDL_PrintUnsignedLong(text, left, NULL, value); |
| | | text += len; |
| | | if (len >= left) { |
| | | text += (left > 1) ? left - 1 : 0; |
| | | left = SDL_min(left, 1); |
| | | } else { |
| | | text += len; |
| | | left -= len; |
| | | } |
| | | arg -= value; |
| | |
| | | while (info->precision-- > 0) { |
| | | value = (unsigned long) (arg * mult); |
| | | len = SDL_PrintUnsignedLong(text, left, NULL, value); |
| | | text += len; |
| | | if (len >= left) { |
| | | text += (left > 1) ? left - 1 : 0; |
| | | left = SDL_min(left, 1); |
| | | } else { |
| | | text += len; |
| | | left -= len; |
| | | } |
| | | arg -= (double) value / mult; |
| | |
| | | |
| | | width = info->width - (int)(text - textstart); |
| | | if (width > 0) { |
| | | char fill = info->pad_zeroes ? '0' : ' '; |
| | | const char fill = info->pad_zeroes ? '0' : ' '; |
| | | char *end = text+left-1; |
| | | len = (text - textstart); |
| | | for (len = (text - textstart); len--; ) { |
| | |
| | | } |
| | | } |
| | | len = (size_t)width; |
| | | text += len; |
| | | if (len >= left) { |
| | | text += (left > 1) ? left - 1 : 0; |
| | | left = SDL_min(left, 1); |
| | | } else { |
| | | text += len; |
| | | left -= len; |
| | | } |
| | | while (len--) { |
| | | if (textstart+len < end) { |
| | | textstart[len] = fill; |
| | | } |
| | | |
| | | if (end != textstart) { |
| | | const size_t filllen = SDL_min(len, ((size_t) (end - textstart)) - 1); |
| | | SDL_memset(textstart, fill, filllen); |
| | | } |
| | | } |
| | | |
| | |
| | | if (!fmt) { |
| | | fmt = ""; |
| | | } |
| | | while (*fmt) { |
| | | while (*fmt && left > 1) { |
| | | if (*fmt == '%') { |
| | | SDL_bool done = SDL_FALSE; |
| | | size_t len = 0; |
| | |
| | | if (*fmt >= '0' && *fmt <= '9') { |
| | | info.width = SDL_strtol(fmt, (char **)&fmt, 0); |
| | | } |
| | | else if (*fmt == '*') { |
| | | ++fmt; |
| | | info.width = va_arg(ap, int); |
| | | } |
| | | |
| | | if (*fmt == '.') { |
| | | ++fmt; |
| | | if (*fmt >= '0' && *fmt <= '9') { |
| | | info.precision = SDL_strtol(fmt, (char **)&fmt, 0); |
| | | } else if (*fmt == '*') { |
| | | ++fmt; |
| | | info.precision = va_arg(ap, int); |
| | | } else { |
| | | info.precision = 0; |
| | | } |
| | | if (info.precision < 0) { |
| | | info.precision = 0; |
| | | } |
| | | } |
| | |
| | | break; |
| | | case 'i': |
| | | case 'd': |
| | | if (info.precision >= 0) { |
| | | info.pad_zeroes = SDL_FALSE; |
| | | } |
| | | switch (inttype) { |
| | | case DO_INT: |
| | | len = SDL_PrintLong(text, left, &info, |
| | |
| | | } |
| | | /* Fall through to unsigned handling */ |
| | | case 'u': |
| | | info.pad_zeroes = SDL_TRUE; |
| | | info.force_sign = SDL_FALSE; |
| | | if (info.precision >= 0) { |
| | | info.pad_zeroes = SDL_FALSE; |
| | | } |
| | | switch (inttype) { |
| | | case DO_INT: |
| | | len = SDL_PrintUnsignedLong(text, left, &info, |
| | |
| | | len = SDL_PrintFloat(text, left, &info, va_arg(ap, double)); |
| | | done = SDL_TRUE; |
| | | break; |
| | | case 'S': |
| | | { |
| | | /* In practice this is used on Windows for WCHAR strings */ |
| | | wchar_t *wide_arg = va_arg(ap, wchar_t *); |
| | | char *arg = SDL_iconv_string("UTF-8", "UTF-16LE", (char *)(wide_arg), (SDL_wcslen(wide_arg)+1)*sizeof(*wide_arg)); |
| | | info.pad_zeroes = SDL_FALSE; |
| | | len = SDL_PrintString(text, left, &info, arg); |
| | | SDL_free(arg); |
| | | done = SDL_TRUE; |
| | | } |
| | | break; |
| | | case 's': |
| | | info.pad_zeroes = SDL_FALSE; |
| | | len = SDL_PrintString(text, left, &info, va_arg(ap, char *)); |
| | | done = SDL_TRUE; |
| | | break; |
| | |
| | | } |
| | | ++fmt; |
| | | } |
| | | text += len; |
| | | if (len >= left) { |
| | | text += (left > 1) ? left - 1 : 0; |
| | | left = SDL_min(left, 1); |
| | | } else { |
| | | text += len; |
| | | left -= len; |
| | | } |
| | | } else { |
| | | if (left > 1) { |
| | | *text = *fmt; |
| | | --left; |
| | | } |
| | | ++fmt; |
| | | ++text; |
| | | *text++ = *fmt++; |
| | | --left; |
| | | } |
| | | } |
| | | if (left > 0) { |