| | |
| | | /* |
| | | Simple DirectMedia Layer |
| | | Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org> |
| | | Copyright (C) 1997-2018 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 |
| | | |
| | | #ifndef _GNU_SOURCE |
| | | #define _GNU_SOURCE 1 |
| | | #endif |
| | | |
| | | #include "../SDL_internal.h" |
| | |
| | | |
| | | #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 { |
| | |
| | | #endif /* HAVE_WCSLCAT */ |
| | | } |
| | | |
| | | 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 */ |
| | | } |
| | | |
| | | 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++))) { |
| | | /* 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); |
| | | if (newstr) { |
| | | SDL_strlcpy(newstr, string, len); |
| | | SDL_memcpy(newstr, string, len); |
| | | } |
| | | return newstr; |
| | | #endif /* HAVE_STRDUP */ |
| | | } |
| | | |
| | | char * |
| | |
| | | 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; |
| | |
| | | { |
| | | size_t length = 0; |
| | | size_t slen; |
| | | |
| | | if (string == NULL) { |
| | | string = "(null)"; |
| | | } |
| | | |
| | | if (info && info->width && (size_t)info->width > SDL_strlen(string)) { |
| | | char fill = info->pad_zeroes ? '0' : ' '; |
| | |
| | | if (!fmt) { |
| | | fmt = ""; |
| | | } |
| | | while (*fmt) { |
| | | while (*fmt && left > 1) { |
| | | if (*fmt == '%') { |
| | | SDL_bool done = SDL_FALSE; |
| | | size_t len = 0; |
| | |
| | | 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)); |
| | | len = SDL_PrintString(text, left, &info, arg); |
| | | SDL_free(arg); |
| | | done = SDL_TRUE; |
| | | } |
| | | break; |
| | | case 's': |
| | | len = SDL_PrintString(text, left, &info, va_arg(ap, char *)); |
| | | done = SDL_TRUE; |
| | |
| | | left -= len; |
| | | } |
| | | } else { |
| | | if (left > 1) { |
| | | *text = *fmt; |
| | | --left; |
| | | } |
| | | ++fmt; |
| | | ++text; |
| | | *text++ = *fmt++; |
| | | --left; |
| | | } |
| | | } |
| | | if (left > 0) { |