From 30f41c02aec763d32e62351452da9ef582bc3472 Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Fri, 6 Mar 2026 13:30:59 -0800 Subject: Move contrib libraries to contrib repo --- contrib/SDL-3.2.8/src/stdlib/SDL_string.c | 2515 ----------------------------- 1 file changed, 2515 deletions(-) delete mode 100644 contrib/SDL-3.2.8/src/stdlib/SDL_string.c (limited to 'contrib/SDL-3.2.8/src/stdlib/SDL_string.c') diff --git a/contrib/SDL-3.2.8/src/stdlib/SDL_string.c b/contrib/SDL-3.2.8/src/stdlib/SDL_string.c deleted file mode 100644 index 007719e..0000000 --- a/contrib/SDL-3.2.8/src/stdlib/SDL_string.c +++ /dev/null @@ -1,2515 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "SDL_internal.h" - -// This file contains portable string manipulation functions for SDL - -#include "SDL_vacopy.h" - -#ifdef SDL_PLATFORM_VITA -#include -#endif - -#include "SDL_sysstdlib.h" - -#include "SDL_casefolding.h" - -#if defined(__SIZEOF_WCHAR_T__) -#define SDL_SIZEOF_WCHAR_T __SIZEOF_WCHAR_T__ -#elif defined(SDL_PLATFORM_WINDOWS) -#define SDL_SIZEOF_WCHAR_T 2 -#else // assume everything else is UTF-32 (add more tests if compiler-assert fails below!) -#define SDL_SIZEOF_WCHAR_T 4 -#endif -SDL_COMPILE_TIME_ASSERT(sizeof_wchar_t, sizeof(wchar_t) == SDL_SIZEOF_WCHAR_T); - - -char *SDL_UCS4ToUTF8(Uint32 codepoint, char *dst) -{ - if (!dst) { - return NULL; // I guess...? - } else if (codepoint > 0x10FFFF) { // Outside the range of Unicode codepoints (also, larger than can be encoded in 4 bytes of UTF-8!). - codepoint = SDL_INVALID_UNICODE_CODEPOINT; - } else if ((codepoint >= 0xD800) && (codepoint <= 0xDFFF)) { // UTF-16 surrogate values are illegal in UTF-8. - codepoint = SDL_INVALID_UNICODE_CODEPOINT; - } - - Uint8 *p = (Uint8 *)dst; - if (codepoint <= 0x7F) { - *p = (Uint8)codepoint; - ++dst; - } else if (codepoint <= 0x7FF) { - p[0] = 0xC0 | (Uint8)((codepoint >> 6) & 0x1F); - p[1] = 0x80 | (Uint8)(codepoint & 0x3F); - dst += 2; - } else if (codepoint <= 0xFFFF) { - p[0] = 0xE0 | (Uint8)((codepoint >> 12) & 0x0F); - p[1] = 0x80 | (Uint8)((codepoint >> 6) & 0x3F); - p[2] = 0x80 | (Uint8)(codepoint & 0x3F); - dst += 3; - } else { - SDL_assert(codepoint <= 0x10FFFF); - p[0] = 0xF0 | (Uint8)((codepoint >> 18) & 0x07); - p[1] = 0x80 | (Uint8)((codepoint >> 12) & 0x3F); - p[2] = 0x80 | (Uint8)((codepoint >> 6) & 0x3F); - p[3] = 0x80 | (Uint8)(codepoint & 0x3F); - dst += 4; - } - - return dst; -} - - -// this expects `from` and `to` to be UTF-32 encoding! -int SDL_CaseFoldUnicode(Uint32 from, Uint32 *to) -{ - // !!! FIXME: since the hashtable is static, maybe we should binary - // !!! FIXME: search it instead of walking the whole bucket. - - if (from < 128) { // low-ASCII, easy! - if ((from >= 'A') && (from <= 'Z')) { - *to = 'a' + (from - 'A'); - return 1; - } - } else if (from <= 0xFFFF) { // the Basic Multilingual Plane. - const Uint8 hash = ((from ^ (from >> 8)) & 0xFF); - const Uint16 from16 = (Uint16) from; - - // see if it maps to a single char (most common)... - { - const CaseFoldHashBucket1_16 *bucket = &case_fold_hash1_16[hash]; - const int count = (int) bucket->count; - for (int i = 0; i < count; i++) { - const CaseFoldMapping1_16 *mapping = &bucket->list[i]; - if (mapping->from == from16) { - *to = mapping->to0; - return 1; - } - } - } - - // see if it folds down to two chars... - { - const CaseFoldHashBucket2_16 *bucket = &case_fold_hash2_16[hash & 15]; - const int count = (int) bucket->count; - for (int i = 0; i < count; i++) { - const CaseFoldMapping2_16 *mapping = &bucket->list[i]; - if (mapping->from == from16) { - to[0] = mapping->to0; - to[1] = mapping->to1; - return 2; - } - } - } - - // okay, maybe it's _three_ characters! - { - const CaseFoldHashBucket3_16 *bucket = &case_fold_hash3_16[hash & 3]; - const int count = (int) bucket->count; - for (int i = 0; i < count; i++) { - const CaseFoldMapping3_16 *mapping = &bucket->list[i]; - if (mapping->from == from16) { - to[0] = mapping->to0; - to[1] = mapping->to1; - to[2] = mapping->to2; - return 3; - } - } - } - - } else { // codepoint that doesn't fit in 16 bits. - const Uint8 hash = ((from ^ (from >> 8)) & 0xFF); - const CaseFoldHashBucket1_32 *bucket = &case_fold_hash1_32[hash & 15]; - const int count = (int) bucket->count; - for (int i = 0; i < count; i++) { - const CaseFoldMapping1_32 *mapping = &bucket->list[i]; - if (mapping->from == from) { - *to = mapping->to0; - return 1; - } - } - } - - // Not found...there's no folding needed for this codepoint. - *to = from; - return 1; -} - -#define UNICODE_STRCASECMP(bits, slen1, slen2, update_slen1, update_slen2) \ - Uint32 folded1[3], folded2[3]; \ - int head1 = 0, tail1 = 0, head2 = 0, tail2 = 0; \ - while (true) { \ - Uint32 cp1, cp2; \ - if (head1 != tail1) { \ - cp1 = folded1[tail1++]; \ - } else { \ - const Uint##bits *str1start = (const Uint##bits *) str1; \ - head1 = SDL_CaseFoldUnicode(StepUTF##bits(&str1, slen1), folded1); \ - update_slen1; \ - cp1 = folded1[0]; \ - tail1 = 1; \ - } \ - if (head2 != tail2) { \ - cp2 = folded2[tail2++]; \ - } else { \ - const Uint##bits *str2start = (const Uint##bits *) str2; \ - head2 = SDL_CaseFoldUnicode(StepUTF##bits(&str2, slen2), folded2); \ - update_slen2; \ - cp2 = folded2[0]; \ - tail2 = 1; \ - } \ - if (cp1 < cp2) { \ - return -1; \ - } else if (cp1 > cp2) { \ - return 1; \ - } else if (cp1 == 0) { \ - break; /* complete match. */ \ - } \ - } \ - return 0 - - -static Uint32 StepUTF8(const char **_str, const size_t slen) -{ - /* - * From rfc3629, the UTF-8 spec: - * https://www.ietf.org/rfc/rfc3629.txt - * - * Char. number range | UTF-8 octet sequence - * (hexadecimal) | (binary) - * --------------------+--------------------------------------------- - * 0000 0000-0000 007F | 0xxxxxxx - * 0000 0080-0000 07FF | 110xxxxx 10xxxxxx - * 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx - * 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - */ - - const Uint8 *str = (const Uint8 *) *_str; - const Uint32 octet = (Uint32) (slen ? *str : 0); - - if (octet == 0) { // null terminator, end of string. - return 0; // don't advance `*_str`. - } else if ((octet & 0x80) == 0) { // 0xxxxxxx: one byte codepoint. - (*_str)++; - return octet; - } else if (((octet & 0xE0) == 0xC0) && (slen >= 2)) { // 110xxxxx 10xxxxxx: two byte codepoint. - const Uint8 str1 = str[1]; - if ((str1 & 0xC0) == 0x80) { // If trailing bytes aren't 10xxxxxx, sequence is bogus. - const Uint32 result = ((octet & 0x1F) << 6) | (str1 & 0x3F); - if (result >= 0x0080) { // rfc3629 says you can't use overlong sequences for smaller values. - *_str += 2; - return result; - } - } - } else if (((octet & 0xF0) == 0xE0) && (slen >= 3)) { // 1110xxxx 10xxxxxx 10xxxxxx: three byte codepoint. - const Uint8 str1 = str[1]; - const Uint8 str2 = str[2]; - if (((str1 & 0xC0) == 0x80) && ((str2 & 0xC0) == 0x80)) { // If trailing bytes aren't 10xxxxxx, sequence is bogus. - const Uint32 octet2 = ((Uint32) (str1 & 0x3F)) << 6; - const Uint32 octet3 = ((Uint32) (str2 & 0x3F)); - const Uint32 result = ((octet & 0x0F) << 12) | octet2 | octet3; - if (result >= 0x800) { // rfc3629 says you can't use overlong sequences for smaller values. - if ((result < 0xD800) || (result > 0xDFFF)) { // UTF-16 surrogate values are illegal in UTF-8. - *_str += 3; - return result; - } - } - } - } else if (((octet & 0xF8) == 0xF0) && (slen >= 4)) { // 11110xxxx 10xxxxxx 10xxxxxx 10xxxxxx: four byte codepoint. - const Uint8 str1 = str[1]; - const Uint8 str2 = str[2]; - const Uint8 str3 = str[3]; - if (((str1 & 0xC0) == 0x80) && ((str2 & 0xC0) == 0x80) && ((str3 & 0xC0) == 0x80)) { // If trailing bytes aren't 10xxxxxx, sequence is bogus. - const Uint32 octet2 = ((Uint32) (str1 & 0x1F)) << 12; - const Uint32 octet3 = ((Uint32) (str2 & 0x3F)) << 6; - const Uint32 octet4 = ((Uint32) (str3 & 0x3F)); - const Uint32 result = ((octet & 0x07) << 18) | octet2 | octet3 | octet4; - if (result >= 0x10000) { // rfc3629 says you can't use overlong sequences for smaller values. - *_str += 4; - return result; - } - } - } - - // bogus byte, skip ahead, return a REPLACEMENT CHARACTER. - (*_str)++; - return SDL_INVALID_UNICODE_CODEPOINT; -} - -Uint32 SDL_StepUTF8(const char **pstr, size_t *pslen) -{ - if (!pslen) { - return StepUTF8(pstr, 4); // 4 == max codepoint size. - } - const char *origstr = *pstr; - const Uint32 result = StepUTF8(pstr, *pslen); - *pslen -= (size_t) (*pstr - origstr); - return result; -} - -Uint32 SDL_StepBackUTF8(const char *start, const char **pstr) -{ - if (!pstr || *pstr <= start) { - return 0; - } - - // Step back over the previous UTF-8 character - const char *str = *pstr; - do { - if (str == start) { - break; - } - --str; - } while ((*str & 0xC0) == 0x80); - - size_t length = (*pstr - str); - *pstr = str; - return StepUTF8(&str, length); -} - -#if (SDL_SIZEOF_WCHAR_T == 2) -static Uint32 StepUTF16(const Uint16 **_str, const size_t slen) -{ - const Uint16 *str = *_str; - Uint32 cp = (Uint32) *(str++); - if (cp == 0) { - return 0; // don't advance string pointer. - } else if ((cp >= 0xDC00) && (cp <= 0xDFFF)) { - cp = SDL_INVALID_UNICODE_CODEPOINT; // Orphaned second half of surrogate pair - } else if ((cp >= 0xD800) && (cp <= 0xDBFF)) { // start of surrogate pair! - const Uint32 pair = (Uint32) *str; - if ((pair == 0) || ((pair < 0xDC00) || (pair > 0xDFFF))) { - cp = SDL_INVALID_UNICODE_CODEPOINT; - } else { - str++; // eat the other surrogate. - cp = 0x10000 + (((cp - 0xD800) << 10) | (pair - 0xDC00)); - } - } - - *_str = str; - return (cp > 0x10FFFF) ? SDL_INVALID_UNICODE_CODEPOINT : cp; -} -#elif (SDL_SIZEOF_WCHAR_T == 4) -static Uint32 StepUTF32(const Uint32 **_str, const size_t slen) -{ - if (!slen) { - return 0; - } - - const Uint32 *str = *_str; - const Uint32 cp = *str; - if (cp == 0) { - return 0; // don't advance string pointer. - } - - (*_str)++; - return (cp > 0x10FFFF) ? SDL_INVALID_UNICODE_CODEPOINT : cp; -} -#endif - -#define UTF8_IsLeadByte(c) ((c) >= 0xC0 && (c) <= 0xF4) -#define UTF8_IsTrailingByte(c) ((c) >= 0x80 && (c) <= 0xBF) - -static size_t UTF8_GetTrailingBytes(unsigned char c) -{ - if (c >= 0xC0 && c <= 0xDF) { - return 1; - } else if (c >= 0xE0 && c <= 0xEF) { - return 2; - } else if (c >= 0xF0 && c <= 0xF4) { - return 3; - } - - return 0; -} - -#if !defined(HAVE_VSSCANF) || !defined(HAVE_STRTOL) || !defined(HAVE_STRTOUL) || !defined(HAVE_STRTOLL) || !defined(HAVE_STRTOULL) || !defined(HAVE_STRTOD) -/** - * Parses an unsigned long long and returns the unsigned value and sign bit. - * - * Positive values are clamped to ULLONG_MAX. - * The result `value == 0 && negative` indicates negative overflow - * and might need to be handled differently depending on whether a - * signed or unsigned integer is being parsed. - */ -static size_t SDL_ScanUnsignedLongLongInternal(const char *text, int count, int radix, unsigned long long *valuep, bool *negativep) -{ - const unsigned long long ullong_max = ~0ULL; - - const char *text_start = text; - const char *number_start = text_start; - unsigned long long value = 0; - bool negative = false; - bool overflow = false; - - if (radix == 0 || (radix >= 2 && radix <= 36)) { - while (SDL_isspace(*text)) { - ++text; - } - if (*text == '-' || *text == '+') { - negative = *text == '-'; - ++text; - } - if ((radix == 0 || radix == 16) && *text == '0' && text[1] != '\0') { - ++text; - if (*text == 'x' || *text == 'X') { - radix = 16; - ++text; - } else if (radix == 0) { - radix = 8; - } - } else if (radix == 0) { - radix = 10; - } - number_start = text; - do { - unsigned long long digit; - if (*text >= '0' && *text <= '9') { - digit = *text - '0'; - } else if (radix > 10) { - if (*text >= 'A' && *text < 'A' + (radix - 10)) { - digit = 10 + (*text - 'A'); - } else if (*text >= 'a' && *text < 'a' + (radix - 10)) { - digit = 10 + (*text - 'a'); - } else { - break; - } - } else { - break; - } - if (value != 0 && radix > ullong_max / value) { - overflow = true; - } else { - value *= radix; - if (digit > ullong_max - value) { - overflow = true; - } else { - value += digit; - } - } - ++text; - } while (count == 0 || (text - text_start) != count); - } - if (text == number_start) { - if (radix == 16 && text > text_start && (*(text - 1) == 'x' || *(text - 1) == 'X')) { - // the string was "0x"; consume the '0' but not the 'x' - --text; - } else { - // no number was parsed, and thus no characters were consumed - text = text_start; - } - } - if (overflow) { - if (negative) { - value = 0; - } else { - value = ullong_max; - } - } else if (value == 0) { - negative = false; - } - *valuep = value; - *negativep = negative; - return text - text_start; -} -#endif - -#ifndef HAVE_WCSTOL -// SDL_ScanUnsignedLongLongInternalW assumes that wchar_t can be converted to int without truncating bits -SDL_COMPILE_TIME_ASSERT(wchar_t_int, sizeof(wchar_t) <= sizeof(int)); - -/** - * Parses an unsigned long long and returns the unsigned value and sign bit. - * - * Positive values are clamped to ULLONG_MAX. - * The result `value == 0 && negative` indicates negative overflow - * and might need to be handled differently depending on whether a - * signed or unsigned integer is being parsed. - */ -static size_t SDL_ScanUnsignedLongLongInternalW(const wchar_t *text, int count, int radix, unsigned long long *valuep, bool *negativep) -{ - const unsigned long long ullong_max = ~0ULL; - - const wchar_t *text_start = text; - const wchar_t *number_start = text_start; - unsigned long long value = 0; - bool negative = false; - bool overflow = false; - - if (radix == 0 || (radix >= 2 && radix <= 36)) { - while (SDL_isspace(*text)) { - ++text; - } - if (*text == '-' || *text == '+') { - negative = *text == '-'; - ++text; - } - if ((radix == 0 || radix == 16) && *text == '0') { - ++text; - if (*text == 'x' || *text == 'X') { - radix = 16; - ++text; - } else if (radix == 0) { - radix = 8; - } - } else if (radix == 0) { - radix = 10; - } - number_start = text; - do { - unsigned long long digit; - if (*text >= '0' && *text <= '9') { - digit = *text - '0'; - } else if (radix > 10) { - if (*text >= 'A' && *text < 'A' + (radix - 10)) { - digit = 10 + (*text - 'A'); - } else if (*text >= 'a' && *text < 'a' + (radix - 10)) { - digit = 10 + (*text - 'a'); - } else { - break; - } - } else { - break; - } - if (value != 0 && radix > ullong_max / value) { - overflow = true; - } else { - value *= radix; - if (digit > ullong_max - value) { - overflow = true; - } else { - value += digit; - } - } - ++text; - } while (count == 0 || (text - text_start) != count); - } - if (text == number_start) { - if (radix == 16 && text > text_start && (*(text - 1) == 'x' || *(text - 1) == 'X')) { - // the string was "0x"; consume the '0' but not the 'x' - --text; - } else { - // no number was parsed, and thus no characters were consumed - text = text_start; - } - } - if (overflow) { - if (negative) { - value = 0; - } else { - value = ullong_max; - } - } else if (value == 0) { - negative = false; - } - *valuep = value; - *negativep = negative; - return text - text_start; -} -#endif - -#if !defined(HAVE_VSSCANF) || !defined(HAVE_STRTOL) -static size_t SDL_ScanLong(const char *text, int count, int radix, long *valuep) -{ - const unsigned long long_max = (~0UL) >> 1; - unsigned long long value; - bool negative; - size_t len = SDL_ScanUnsignedLongLongInternal(text, count, radix, &value, &negative); - if (negative) { - const unsigned long abs_long_min = long_max + 1; - if (value == 0 || value > abs_long_min) { - value = 0ULL - abs_long_min; - } else { - value = 0ULL - value; - } - } else if (value > long_max) { - value = long_max; - } - *valuep = (long)value; - return len; -} -#endif - -#ifndef HAVE_WCSTOL -static size_t SDL_ScanLongW(const wchar_t *text, int count, int radix, long *valuep) -{ - const unsigned long long_max = (~0UL) >> 1; - unsigned long long value; - bool negative; - size_t len = SDL_ScanUnsignedLongLongInternalW(text, count, radix, &value, &negative); - if (negative) { - const unsigned long abs_long_min = long_max + 1; - if (value == 0 || value > abs_long_min) { - value = 0ULL - abs_long_min; - } else { - value = 0ULL - value; - } - } else if (value > long_max) { - value = long_max; - } - *valuep = (long)value; - return len; -} -#endif - -#if !defined(HAVE_VSSCANF) || !defined(HAVE_STRTOUL) -static size_t SDL_ScanUnsignedLong(const char *text, int count, int radix, unsigned long *valuep) -{ - const unsigned long ulong_max = ~0UL; - unsigned long long value; - bool negative; - size_t len = SDL_ScanUnsignedLongLongInternal(text, count, radix, &value, &negative); - if (negative) { - if (value == 0 || value > ulong_max) { - value = ulong_max; - } else if (value == ulong_max) { - value = 1; - } else { - value = 0ULL - value; - } - } else if (value > ulong_max) { - value = ulong_max; - } - *valuep = (unsigned long)value; - return len; -} -#endif - -#ifndef HAVE_VSSCANF -static size_t SDL_ScanUintPtrT(const char *text, uintptr_t *valuep) -{ - const uintptr_t uintptr_max = ~(uintptr_t)0; - unsigned long long value; - bool negative; - size_t len = SDL_ScanUnsignedLongLongInternal(text, 0, 16, &value, &negative); - if (negative) { - if (value == 0 || value > uintptr_max) { - value = uintptr_max; - } else if (value == uintptr_max) { - value = 1; - } else { - value = 0ULL - value; - } - } else if (value > uintptr_max) { - value = uintptr_max; - } - *valuep = (uintptr_t)value; - return len; -} -#endif - -#if !defined(HAVE_VSSCANF) || !defined(HAVE_STRTOLL) -static size_t SDL_ScanLongLong(const char *text, int count, int radix, long long *valuep) -{ - const unsigned long long llong_max = (~0ULL) >> 1; - unsigned long long value; - bool negative; - size_t len = SDL_ScanUnsignedLongLongInternal(text, count, radix, &value, &negative); - if (negative) { - const unsigned long long abs_llong_min = llong_max + 1; - if (value == 0 || value > abs_llong_min) { - value = 0ULL - abs_llong_min; - } else { - value = 0ULL - value; - } - } else if (value > llong_max) { - value = llong_max; - } - *valuep = value; - return len; -} -#endif - -#if !defined(HAVE_VSSCANF) || !defined(HAVE_STRTOULL) || !defined(HAVE_STRTOD) -static size_t SDL_ScanUnsignedLongLong(const char *text, int count, int radix, unsigned long long *valuep) -{ - const unsigned long long ullong_max = ~0ULL; - bool negative; - size_t len = SDL_ScanUnsignedLongLongInternal(text, count, radix, valuep, &negative); - if (negative) { - if (*valuep == 0) { - *valuep = ullong_max; - } else { - *valuep = 0ULL - *valuep; - } - } - return len; -} -#endif - -#if !defined(HAVE_VSSCANF) || !defined(HAVE_STRTOD) -static size_t SDL_ScanFloat(const char *text, double *valuep) -{ - const char *text_start = text; - const char *number_start = text_start; - double value = 0.0; - bool negative = false; - - while (SDL_isspace(*text)) { - ++text; - } - if (*text == '-' || *text == '+') { - negative = *text == '-'; - ++text; - } - number_start = text; - if (SDL_isdigit(*text)) { - value += SDL_strtoull(text, (char **)(&text), 10); - if (*text == '.') { - double denom = 10; - ++text; - while (SDL_isdigit(*text)) { - value += (double)(*text - '0') / denom; - denom *= 10; - ++text; - } - } - } - if (text == number_start) { - // no number was parsed, and thus no characters were consumed - text = text_start; - } else if (negative) { - value = -value; - } - *valuep = value; - return text - text_start; -} -#endif - -int SDL_memcmp(const void *s1, const void *s2, size_t len) -{ -#ifdef SDL_PLATFORM_VITA - /* - Using memcmp on NULL is UB per POSIX / C99 7.21.1/2. - But, both linux and bsd allow that, with an exception: - zero length strings are always identical, so NULLs are never dereferenced. - sceClibMemcmp on PSVita doesn't allow that, so we check ourselves. - */ - if (len == 0) { - return 0; - } - return sceClibMemcmp(s1, s2, len); -#elif defined(HAVE_MEMCMP) - return memcmp(s1, s2, len); -#else - char *s1p = (char *)s1; - char *s2p = (char *)s2; - while (len--) { - if (*s1p != *s2p) { - return *s1p - *s2p; - } - ++s1p; - ++s2p; - } - return 0; -#endif // HAVE_MEMCMP -} - -size_t SDL_strlen(const char *string) -{ -#ifdef HAVE_STRLEN - return strlen(string); -#else - size_t len = 0; - while (*string++) { - ++len; - } - return len; -#endif // HAVE_STRLEN -} - -size_t SDL_strnlen(const char *string, size_t maxlen) -{ -#ifdef HAVE_STRNLEN - return strnlen(string, maxlen); -#else - size_t len = 0; - while (len < maxlen && *string++) { - ++len; - } - return len; -#endif // HAVE_STRNLEN -} - -size_t SDL_wcslen(const wchar_t *string) -{ -#ifdef HAVE_WCSLEN - return wcslen(string); -#else - size_t len = 0; - while (*string++) { - ++len; - } - return len; -#endif // HAVE_WCSLEN -} - -size_t SDL_wcsnlen(const wchar_t *string, size_t maxlen) -{ -#ifdef HAVE_WCSNLEN - return wcsnlen(string, maxlen); -#else - size_t len = 0; - while (len < maxlen && *string++) { - ++len; - } - return len; -#endif // HAVE_WCSNLEN -} - -size_t SDL_wcslcpy(SDL_OUT_Z_CAP(maxlen) wchar_t *dst, const wchar_t *src, size_t maxlen) -{ -#ifdef HAVE_WCSLCPY - return wcslcpy(dst, src, maxlen); -#else - size_t srclen = SDL_wcslen(src); - if (maxlen > 0) { - size_t len = SDL_min(srclen, maxlen - 1); - SDL_memcpy(dst, src, len * sizeof(wchar_t)); - dst[len] = '\0'; - } - return srclen; -#endif // HAVE_WCSLCPY -} - -size_t SDL_wcslcat(SDL_INOUT_Z_CAP(maxlen) wchar_t *dst, const wchar_t *src, size_t maxlen) -{ -#ifdef HAVE_WCSLCAT - return wcslcat(dst, src, maxlen); -#else - size_t dstlen = SDL_wcslen(dst); - size_t srclen = SDL_wcslen(src); - if (dstlen < maxlen) { - SDL_wcslcpy(dst + dstlen, src, maxlen - dstlen); - } - return dstlen + srclen; -#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_wcsnstr(const wchar_t *haystack, const wchar_t *needle, size_t maxlen) -{ - size_t length = SDL_wcslen(needle); - if (length == 0) { - return (wchar_t *)haystack; - } - while (maxlen >= length && *haystack) { - if (maxlen >= length && SDL_wcsncmp(haystack, needle, length) == 0) { - return (wchar_t *)haystack; - } - ++haystack; - --maxlen; - } - return NULL; -} - -wchar_t *SDL_wcsstr(const wchar_t *haystack, const wchar_t *needle) -{ -#ifdef HAVE_WCSSTR - return SDL_const_cast(wchar_t *, wcsstr(haystack, needle)); -#else - return SDL_wcsnstr(haystack, needle, SDL_wcslen(haystack)); -#endif // HAVE_WCSSTR -} - -int SDL_wcscmp(const wchar_t *str1, const wchar_t *str2) -{ -#ifdef HAVE_WCSCMP - return wcscmp(str1, str2); -#else - while (*str1 && *str2) { - if (*str1 != *str2) { - break; - } - ++str1; - ++str2; - } - return *str1 - *str2; -#endif // HAVE_WCSCMP -} - -int SDL_wcsncmp(const wchar_t *str1, const wchar_t *str2, size_t maxlen) -{ -#ifdef HAVE_WCSNCMP - return wcsncmp(str1, str2, maxlen); -#else - while (*str1 && *str2 && maxlen) { - if (*str1 != *str2) { - break; - } - ++str1; - ++str2; - --maxlen; - } - if (!maxlen) { - return 0; - } - return *str1 - *str2; - -#endif // HAVE_WCSNCMP -} - -int SDL_wcscasecmp(const wchar_t *wstr1, const wchar_t *wstr2) -{ -#if (SDL_SIZEOF_WCHAR_T == 2) - const Uint16 *str1 = (const Uint16 *) wstr1; - const Uint16 *str2 = (const Uint16 *) wstr2; - UNICODE_STRCASECMP(16, 2, 2, (void) str1start, (void) str2start); // always NULL-terminated, no need to adjust lengths. -#elif (SDL_SIZEOF_WCHAR_T == 4) - const Uint32 *str1 = (const Uint32 *) wstr1; - const Uint32 *str2 = (const Uint32 *) wstr2; - UNICODE_STRCASECMP(32, 1, 1, (void) str1start, (void) str2start); // always NULL-terminated, no need to adjust lengths. -#else - #error Unexpected wchar_t size - return -1; -#endif -} - -int SDL_wcsncasecmp(const wchar_t *wstr1, const wchar_t *wstr2, size_t maxlen) -{ - size_t slen1 = maxlen; - size_t slen2 = maxlen; - -#if (SDL_SIZEOF_WCHAR_T == 2) - const Uint16 *str1 = (const Uint16 *) wstr1; - const Uint16 *str2 = (const Uint16 *) wstr2; - UNICODE_STRCASECMP(16, slen1, slen2, slen1 -= (size_t) (str1 - str1start), slen2 -= (size_t) (str2 - str2start)); -#elif (SDL_SIZEOF_WCHAR_T == 4) - const Uint32 *str1 = (const Uint32 *) wstr1; - const Uint32 *str2 = (const Uint32 *) wstr2; - UNICODE_STRCASECMP(32, slen1, slen2, slen1 -= (size_t) (str1 - str1start), slen2 -= (size_t) (str2 - str2start)); -#else - #error Unexpected wchar_t size - return -1; -#endif -} - -long SDL_wcstol(const wchar_t *string, wchar_t **endp, int base) -{ -#ifdef HAVE_WCSTOL - return wcstol(string, endp, base); -#else - long value = 0; - size_t len = SDL_ScanLongW(string, 0, base, &value); - if (endp) { - *endp = (wchar_t *)string + len; - } - return value; -#endif // HAVE_WCSTOL -} - -size_t SDL_strlcpy(SDL_OUT_Z_CAP(maxlen) char *dst, const char *src, size_t maxlen) -{ -#ifdef HAVE_STRLCPY - return strlcpy(dst, src, maxlen); -#else - size_t srclen = SDL_strlen(src); - if (maxlen > 0) { - size_t len = SDL_min(srclen, maxlen - 1); - SDL_memcpy(dst, src, len); - dst[len] = '\0'; - } - return srclen; -#endif // HAVE_STRLCPY -} - -size_t SDL_utf8strlcpy(SDL_OUT_Z_CAP(dst_bytes) char *dst, const char *src, size_t dst_bytes) -{ - size_t bytes = 0; - - if (dst_bytes > 0) { - size_t src_bytes = SDL_strlen(src); - size_t i = 0; - size_t trailing_bytes = 0; - - bytes = SDL_min(src_bytes, dst_bytes - 1); - if (bytes) { - unsigned char c = (unsigned char)src[bytes - 1]; - if (UTF8_IsLeadByte(c)) { - --bytes; - } else if (UTF8_IsTrailingByte(c)) { - for (i = bytes - 1; i != 0; --i) { - c = (unsigned char)src[i]; - trailing_bytes = UTF8_GetTrailingBytes(c); - if (trailing_bytes) { - if ((bytes - i) != (trailing_bytes + 1)) { - bytes = i; - } - - break; - } - } - } - SDL_memcpy(dst, src, bytes); - } - dst[bytes] = '\0'; - } - - return bytes; -} - -size_t SDL_utf8strlen(const char *str) -{ - size_t result = 0; - while (SDL_StepUTF8(&str, NULL)) { - result++; - } - return result; -} - -size_t SDL_utf8strnlen(const char *str, size_t bytes) -{ - size_t result = 0; - while (SDL_StepUTF8(&str, &bytes)) { - result++; - } - return result; -} - -size_t SDL_strlcat(SDL_INOUT_Z_CAP(maxlen) char *dst, const char *src, size_t maxlen) -{ -#ifdef HAVE_STRLCAT - return strlcat(dst, src, maxlen); -#else - size_t dstlen = SDL_strlen(dst); - size_t srclen = SDL_strlen(src); - if (dstlen < maxlen) { - SDL_strlcpy(dst + dstlen, src, maxlen - dstlen); - } - return dstlen + srclen; -#endif // HAVE_STRLCAT -} - -char *SDL_strdup(const char *string) -{ - size_t len = SDL_strlen(string) + 1; - char *newstr = (char *)SDL_malloc(len); - if (newstr) { - SDL_memcpy(newstr, string, len); - } - return newstr; -} - -char *SDL_strndup(const char *string, size_t maxlen) -{ - size_t len = SDL_strnlen(string, maxlen); - char *newstr = (char *)SDL_malloc(len + 1); - if (newstr) { - SDL_memcpy(newstr, string, len); - newstr[len] = '\0'; - } - return newstr; -} - -char *SDL_strrev(char *string) -{ -#ifdef HAVE__STRREV - return _strrev(string); -#else - size_t len = SDL_strlen(string); - char *a = &string[0]; - char *b = &string[len - 1]; - len /= 2; - while (len--) { - const char c = *a; // NOLINT(clang-analyzer-core.uninitialized.Assign) - *a++ = *b; - *b-- = c; - } - return string; -#endif // HAVE__STRREV -} - -char *SDL_strupr(char *string) -{ - char *bufp = string; - while (*bufp) { - *bufp = (char)SDL_toupper((unsigned char)*bufp); - ++bufp; - } - return string; -} - -char *SDL_strlwr(char *string) -{ - char *bufp = string; - while (*bufp) { - *bufp = (char)SDL_tolower((unsigned char)*bufp); - ++bufp; - } - return string; -} - -char *SDL_strchr(const char *string, int c) -{ -#ifdef HAVE_STRCHR - return SDL_const_cast(char *, strchr(string, c)); -#elif defined(HAVE_INDEX) - return SDL_const_cast(char *, index(string, c)); -#else - while (*string) { - if (*string == c) { - return (char *)string; - } - ++string; - } - if (c == '\0') { - return (char *)string; - } - return NULL; -#endif // HAVE_STRCHR -} - -char *SDL_strrchr(const char *string, int c) -{ -#ifdef HAVE_STRRCHR - return SDL_const_cast(char *, strrchr(string, c)); -#elif defined(HAVE_RINDEX) - return SDL_const_cast(char *, rindex(string, c)); -#else - const char *bufp = string + SDL_strlen(string); - while (bufp >= string) { - if (*bufp == c) { - return (char *)bufp; - } - --bufp; - } - return NULL; -#endif // HAVE_STRRCHR -} - -char *SDL_strnstr(const char *haystack, const char *needle, size_t maxlen) -{ -#ifdef HAVE_STRNSTR - return SDL_const_cast(char *, strnstr(haystack, needle, maxlen)); -#else - size_t length = SDL_strlen(needle); - if (length == 0) { - return (char *)haystack; - } - while (maxlen >= length && *haystack) { - if (SDL_strncmp(haystack, needle, length) == 0) { - return (char *)haystack; - } - ++haystack; - --maxlen; - } - return NULL; -#endif // HAVE_STRSTR -} - -char *SDL_strstr(const char *haystack, const char *needle) -{ -#ifdef HAVE_STRSTR - return SDL_const_cast(char *, strstr(haystack, needle)); -#else - return SDL_strnstr(haystack, needle, SDL_strlen(haystack)); -#endif // HAVE_STRSTR -} - -char *SDL_strcasestr(const char *haystack, const char *needle) -{ - const size_t length = SDL_strlen(needle); - do { - if (SDL_strncasecmp(haystack, needle, length) == 0) { - return (char *)haystack; - } - } while (SDL_StepUTF8(&haystack, NULL)); // move ahead by a full codepoint at a time, regardless of bytes. - - return NULL; -} - -#if !defined(HAVE__LTOA) || !defined(HAVE__I64TOA) || \ - !defined(HAVE__ULTOA) || !defined(HAVE__UI64TOA) -static const char ntoa_table[] = { - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', - 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', - 'U', 'V', 'W', 'X', 'Y', 'Z' -}; -#endif // ntoa() conversion table - -char *SDL_itoa(int value, char *string, int radix) -{ -#ifdef HAVE_ITOA - return itoa(value, string, radix); -#else - return SDL_ltoa((long)value, string, radix); -#endif // HAVE_ITOA -} - -char *SDL_uitoa(unsigned int value, char *string, int radix) -{ -#ifdef HAVE__UITOA - return _uitoa(value, string, radix); -#else - return SDL_ultoa((unsigned long)value, string, radix); -#endif // HAVE__UITOA -} - -char *SDL_ltoa(long value, char *string, int radix) -{ -#ifdef HAVE__LTOA - return _ltoa(value, string, radix); -#else - char *bufp = string; - - if (value < 0) { - *bufp++ = '-'; - SDL_ultoa(-value, bufp, radix); - } else { - SDL_ultoa(value, bufp, radix); - } - - return string; -#endif // HAVE__LTOA -} - -char *SDL_ultoa(unsigned long value, char *string, int radix) -{ -#ifdef HAVE__ULTOA - return _ultoa(value, string, radix); -#else - char *bufp = string; - - if (value) { - while (value > 0) { - *bufp++ = ntoa_table[value % radix]; - value /= radix; - } - } else { - *bufp++ = '0'; - } - *bufp = '\0'; - - // The numbers went into the string backwards. :) - SDL_strrev(string); - - return string; -#endif // HAVE__ULTOA -} - -char *SDL_lltoa(long long value, char *string, int radix) -{ -#ifdef HAVE__I64TOA - return _i64toa(value, string, radix); -#else - char *bufp = string; - - if (value < 0) { - *bufp++ = '-'; - SDL_ulltoa(-value, bufp, radix); - } else { - SDL_ulltoa(value, bufp, radix); - } - - return string; -#endif // HAVE__I64TOA -} - -char *SDL_ulltoa(unsigned long long value, char *string, int radix) -{ -#ifdef HAVE__UI64TOA - return _ui64toa(value, string, radix); -#else - char *bufp = string; - - if (value) { - while (value > 0) { - *bufp++ = ntoa_table[value % radix]; - value /= radix; - } - } else { - *bufp++ = '0'; - } - *bufp = '\0'; - - // The numbers went into the string backwards. :) - SDL_strrev(string); - - return string; -#endif // HAVE__UI64TOA -} - -int SDL_atoi(const char *string) -{ -#ifdef HAVE_ATOI - return atoi(string); -#else - return SDL_strtol(string, NULL, 10); -#endif // HAVE_ATOI -} - -double SDL_atof(const char *string) -{ -#ifdef HAVE_ATOF - return atof(string); -#else - return SDL_strtod(string, NULL); -#endif // HAVE_ATOF -} - -long SDL_strtol(const char *string, char **endp, int base) -{ -#ifdef HAVE_STRTOL - return strtol(string, endp, base); -#else - long value = 0; - size_t len = SDL_ScanLong(string, 0, base, &value); - if (endp) { - *endp = (char *)string + len; - } - return value; -#endif // HAVE_STRTOL -} - -unsigned long SDL_strtoul(const char *string, char **endp, int base) -{ -#ifdef HAVE_STRTOUL - return strtoul(string, endp, base); -#else - unsigned long value = 0; - size_t len = SDL_ScanUnsignedLong(string, 0, base, &value); - if (endp) { - *endp = (char *)string + len; - } - return value; -#endif // HAVE_STRTOUL -} - -long long SDL_strtoll(const char *string, char **endp, int base) -{ -#ifdef HAVE_STRTOLL - return strtoll(string, endp, base); -#else - long long value = 0; - size_t len = SDL_ScanLongLong(string, 0, base, &value); - if (endp) { - *endp = (char *)string + len; - } - return value; -#endif // HAVE_STRTOLL -} - -unsigned long long SDL_strtoull(const char *string, char **endp, int base) -{ -#ifdef HAVE_STRTOULL - return strtoull(string, endp, base); -#else - unsigned long long value = 0; - size_t len = SDL_ScanUnsignedLongLong(string, 0, base, &value); - if (endp) { - *endp = (char *)string + len; - } - return value; -#endif // HAVE_STRTOULL -} - -double SDL_strtod(const char *string, char **endp) -{ -#ifdef HAVE_STRTOD - return strtod(string, endp); -#else - double value; - size_t len = SDL_ScanFloat(string, &value); - if (endp) { - *endp = (char *)string + len; - } - return value; -#endif // HAVE_STRTOD -} - -int SDL_strcmp(const char *str1, const char *str2) -{ -#ifdef HAVE_STRCMP - return strcmp(str1, str2); -#else - int result; - - while (1) { - result = ((unsigned char)*str1 - (unsigned char)*str2); - if (result != 0 || (*str1 == '\0' /* && *str2 == '\0'*/)) { - break; - } - ++str1; - ++str2; - } - return result; -#endif // HAVE_STRCMP -} - -int SDL_strncmp(const char *str1, const char *str2, size_t maxlen) -{ -#ifdef HAVE_STRNCMP - return strncmp(str1, str2, maxlen); -#else - int result = 0; - - while (maxlen) { - result = (int)(unsigned char)*str1 - (unsigned char)*str2; - if (result != 0 || *str1 == '\0' /* && *str2 == '\0'*/) { - break; - } - ++str1; - ++str2; - --maxlen; - } - return result; -#endif // HAVE_STRNCMP -} - -int SDL_strcasecmp(const char *str1, const char *str2) -{ - UNICODE_STRCASECMP(8, 4, 4, (void) str1start, (void) str2start); // always NULL-terminated, no need to adjust lengths. -} - -int SDL_strncasecmp(const char *str1, const char *str2, size_t maxlen) -{ - size_t slen1 = maxlen; - size_t slen2 = maxlen; - UNICODE_STRCASECMP(8, slen1, slen2, slen1 -= (size_t) (str1 - ((const char *) str1start)), slen2 -= (size_t) (str2 - ((const char *) str2start))); -} - -int SDL_sscanf(const char *text, SDL_SCANF_FORMAT_STRING const char *fmt, ...) -{ - int rc; - va_list ap; - va_start(ap, fmt); - rc = SDL_vsscanf(text, fmt, ap); - va_end(ap); - return rc; -} - -#ifdef HAVE_VSSCANF -int SDL_vsscanf(const char *text, const char *fmt, va_list ap) -{ - return vsscanf(text, fmt, ap); -} -#else -static bool CharacterMatchesSet(char c, const char *set, size_t set_len) -{ - bool invert = false; - bool result = false; - - if (*set == '^') { - invert = true; - ++set; - --set_len; - } - while (set_len > 0 && !result) { - if (set_len >= 3 && set[1] == '-') { - char low_char = SDL_min(set[0], set[2]); - char high_char = SDL_max(set[0], set[2]); - if (c >= low_char && c <= high_char) { - result = true; - } - set += 3; - set_len -= 3; - } else { - if (c == *set) { - result = true; - } - ++set; - --set_len; - } - } - if (invert) { - result = !result; - } - return result; -} - -// NOLINTNEXTLINE(readability-non-const-parameter) -int SDL_vsscanf(const char *text, SDL_SCANF_FORMAT_STRING const char *fmt, va_list ap) -{ - const char *start = text; - int result = 0; - - if (!text || !*text) { - return -1; - } - - while (*fmt) { - if (*fmt == ' ') { - while (SDL_isspace((unsigned char)*text)) { - ++text; - } - ++fmt; - continue; - } - if (*fmt == '%') { - bool done = false; - long count = 0; - int radix = 10; - enum - { - DO_SHORT, - DO_INT, - DO_LONG, - DO_LONGLONG, - DO_SIZE_T - } inttype = DO_INT; - size_t advance; - bool suppress = false; - - ++fmt; - if (*fmt == '%') { - if (*text == '%') { - ++text; - ++fmt; - continue; - } - break; - } - if (*fmt == '*') { - suppress = true; - ++fmt; - } - fmt += SDL_ScanLong(fmt, 0, 10, &count); - - if (*fmt == 'c') { - if (!count) { - count = 1; - } - if (suppress) { - while (count--) { - ++text; - } - } else { - char *valuep = va_arg(ap, char *); - while (count--) { - *valuep++ = *text++; - } - ++result; - } - continue; - } - - while (SDL_isspace((unsigned char)*text)) { - ++text; - } - - // FIXME: implement more of the format specifiers - while (!done) { - switch (*fmt) { - case '*': - suppress = true; - break; - case 'h': - if (inttype == DO_INT) { - inttype = DO_SHORT; - } else if (inttype > DO_SHORT) { - ++inttype; - } - break; - case 'l': - if (inttype < DO_LONGLONG) { - ++inttype; - } - break; - case 'I': - if (SDL_strncmp(fmt, "I64", 3) == 0) { - fmt += 2; - inttype = DO_LONGLONG; - } - break; - case 'z': - inttype = DO_SIZE_T; - break; - case 'i': - { - int index = 0; - if (text[index] == '-') { - ++index; - } - if (text[index] == '0') { - if (SDL_tolower((unsigned char)text[index + 1]) == 'x') { - radix = 16; - } else { - radix = 8; - } - } - } - SDL_FALLTHROUGH; - case 'd': - if (inttype == DO_LONGLONG) { - long long value = 0; - advance = SDL_ScanLongLong(text, count, radix, &value); - text += advance; - if (advance && !suppress) { - Sint64 *valuep = va_arg(ap, Sint64 *); - *valuep = value; - ++result; - } - } else if (inttype == DO_SIZE_T) { - long long value = 0; - advance = SDL_ScanLongLong(text, count, radix, &value); - text += advance; - if (advance && !suppress) { - size_t *valuep = va_arg(ap, size_t *); - *valuep = (size_t)value; - ++result; - } - } else { - long value = 0; - advance = SDL_ScanLong(text, count, radix, &value); - text += advance; - if (advance && !suppress) { - switch (inttype) { - case DO_SHORT: - { - short *valuep = va_arg(ap, short *); - *valuep = (short)value; - } break; - case DO_INT: - { - int *valuep = va_arg(ap, int *); - *valuep = (int)value; - } break; - case DO_LONG: - { - long *valuep = va_arg(ap, long *); - *valuep = value; - } break; - case DO_LONGLONG: - case DO_SIZE_T: - // Handled above - break; - } - ++result; - } - } - done = true; - break; - case 'o': - if (radix == 10) { - radix = 8; - } - SDL_FALLTHROUGH; - case 'x': - case 'X': - if (radix == 10) { - radix = 16; - } - SDL_FALLTHROUGH; - case 'u': - if (inttype == DO_LONGLONG) { - unsigned long long value = 0; - advance = SDL_ScanUnsignedLongLong(text, count, radix, &value); - text += advance; - if (advance && !suppress) { - Uint64 *valuep = va_arg(ap, Uint64 *); - *valuep = value; - ++result; - } - } else if (inttype == DO_SIZE_T) { - unsigned long long value = 0; - advance = SDL_ScanUnsignedLongLong(text, count, radix, &value); - text += advance; - if (advance && !suppress) { - size_t *valuep = va_arg(ap, size_t *); - *valuep = (size_t)value; - ++result; - } - } else { - unsigned long value = 0; - advance = SDL_ScanUnsignedLong(text, count, radix, &value); - text += advance; - if (advance && !suppress) { - switch (inttype) { - case DO_SHORT: - { - short *valuep = va_arg(ap, short *); - *valuep = (short)value; - } break; - case DO_INT: - { - int *valuep = va_arg(ap, int *); - *valuep = (int)value; - } break; - case DO_LONG: - { - long *valuep = va_arg(ap, long *); - *valuep = value; - } break; - case DO_LONGLONG: - case DO_SIZE_T: - // Handled above - break; - } - ++result; - } - } - done = true; - break; - case 'p': - { - uintptr_t value = 0; - advance = SDL_ScanUintPtrT(text, &value); - text += advance; - if (advance && !suppress) { - void **valuep = va_arg(ap, void **); - *valuep = (void *)value; - ++result; - } - } - done = true; - break; - case 'f': - { - double value = 0.0; - advance = SDL_ScanFloat(text, &value); - text += advance; - if (advance && !suppress) { - float *valuep = va_arg(ap, float *); - *valuep = (float)value; - ++result; - } - } - done = true; - break; - case 's': - if (suppress) { - while (!SDL_isspace((unsigned char)*text)) { - ++text; - if (count) { - if (--count == 0) { - break; - } - } - } - } else { - char *valuep = va_arg(ap, char *); - while (!SDL_isspace((unsigned char)*text)) { - *valuep++ = *text++; - if (count) { - if (--count == 0) { - break; - } - } - } - *valuep = '\0'; - ++result; - } - done = true; - break; - case 'n': - switch (inttype) { - case DO_SHORT: - { - short *valuep = va_arg(ap, short *); - *valuep = (short)(text - start); - } break; - case DO_INT: - { - int *valuep = va_arg(ap, int *); - *valuep = (int)(text - start); - } break; - case DO_LONG: - { - long *valuep = va_arg(ap, long *); - *valuep = (long)(text - start); - } break; - case DO_LONGLONG: - { - long long *valuep = va_arg(ap, long long *); - *valuep = (long long)(text - start); - } break; - case DO_SIZE_T: - { - size_t *valuep = va_arg(ap, size_t *); - *valuep = (size_t)(text - start); - } break; - } - done = true; - break; - case '[': - { - const char *set = fmt + 1; - while (*fmt && *fmt != ']') { - ++fmt; - } - if (*fmt) { - size_t set_len = (fmt - set); - if (suppress) { - while (CharacterMatchesSet(*text, set, set_len)) { - ++text; - if (count) { - if (--count == 0) { - break; - } - } - } - } else { - bool had_match = false; - char *valuep = va_arg(ap, char *); - while (CharacterMatchesSet(*text, set, set_len)) { - had_match = true; - *valuep++ = *text++; - if (count) { - if (--count == 0) { - break; - } - } - } - *valuep = '\0'; - if (had_match) { - ++result; - } - } - } - } - done = true; - break; - default: - done = true; - break; - } - ++fmt; - } - continue; - } - if (*text == *fmt) { - ++text; - ++fmt; - continue; - } - // Text didn't match format specifier - break; - } - - return result; -} -#endif // HAVE_VSSCANF - -int SDL_snprintf(SDL_OUT_Z_CAP(maxlen) char *text, size_t maxlen, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) -{ - va_list ap; - int result; - - va_start(ap, fmt); - result = SDL_vsnprintf(text, maxlen, fmt, ap); - va_end(ap); - - return result; -} - -int SDL_swprintf(SDL_OUT_Z_CAP(maxlen) wchar_t *text, size_t maxlen, SDL_PRINTF_FORMAT_STRING const wchar_t *fmt, ...) -{ - va_list ap; - int result; - - va_start(ap, fmt); - result = SDL_vswprintf(text, maxlen, fmt, ap); - va_end(ap); - - return result; -} - -#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 result; - if (!fmt) { - fmt = ""; - } - result = _vsnprintf(text, maxlen, fmt, ap); - if (maxlen > 0) { - text[maxlen - 1] = '\0'; - } - if (result < 0) { - result = (int)maxlen; - } - return result; -} -#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) { - fmt = ""; - } - return vsnprintf(text, maxlen, fmt, ap); -} -#else -#define TEXT_AND_LEN_ARGS (length < maxlen) ? &text[length] : NULL, (length < maxlen) ? (maxlen - length) : 0 - -// FIXME: implement more of the format specifiers -typedef enum -{ - SDL_CASE_NOCHANGE, - SDL_CASE_LOWER, - SDL_CASE_UPPER -} SDL_letter_case; - -typedef struct -{ - bool left_justify; - bool force_sign; - bool force_type; // for now: used only by float printer, ignored otherwise. - bool pad_zeroes; - SDL_letter_case force_case; - int width; - int radix; - int precision; -} SDL_FormatInfo; - -static size_t SDL_PrintString(char *text, size_t maxlen, SDL_FormatInfo *info, const char *string) -{ - const char fill = (info && info->pad_zeroes) ? '0' : ' '; - size_t width = 0; - size_t filllen = 0; - size_t length = 0; - size_t slen, sz; - - if (!string) { - string = "(null)"; - } - - sz = SDL_strlen(string); - if (info && info->width > 0 && (size_t)info->width > sz) { - width = info->width - sz; - if (info->precision >= 0 && (size_t)info->precision < sz) { - width += sz - (size_t)info->precision; - } - - filllen = SDL_min(width, maxlen); - if (!info->left_justify) { - SDL_memset(text, fill, filllen); - text += filllen; - maxlen -= filllen; - length += width; - filllen = 0; - } - } - - SDL_strlcpy(text, string, maxlen); - length += sz; - - if (filllen > 0) { - SDL_memset(text + sz, fill, filllen); - length += width; - } - - 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 (maxlen > 1) { - if (info->force_case == SDL_CASE_LOWER) { - SDL_strlwr(text); - } else if (info->force_case == SDL_CASE_UPPER) { - SDL_strupr(text); - } - } - } - return length; -} - -static size_t SDL_PrintStringW(char *text, size_t maxlen, SDL_FormatInfo *info, const wchar_t *wide_string) -{ - size_t length = 0; - if (wide_string) { - char *string = SDL_iconv_string("UTF-8", "WCHAR_T", (char *)(wide_string), (SDL_wcslen(wide_string) + 1) * sizeof(*wide_string)); - length = SDL_PrintString(TEXT_AND_LEN_ARGS, info, string); - SDL_free(string); - } else { - length = SDL_PrintString(TEXT_AND_LEN_ARGS, info, NULL); - } - 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], *p = num; - - if (info->force_sign && value >= 0L) { - *p++ = '+'; - } - - SDL_ltoa(value, p, info ? info->radix : 10); - SDL_IntPrecisionAdjust(num, sizeof(num), info); - return SDL_PrintString(text, maxlen, info, num); -} - -static size_t SDL_PrintUnsignedLong(char *text, size_t maxlen, SDL_FormatInfo *info, unsigned long value) -{ - char num[130]; - - SDL_ultoa(value, num, info ? info->radix : 10); - SDL_IntPrecisionAdjust(num, sizeof(num), info); - return SDL_PrintString(text, maxlen, info, num); -} - -static size_t SDL_PrintLongLong(char *text, size_t maxlen, SDL_FormatInfo *info, long long value) -{ - char num[130], *p = num; - - if (info->force_sign && value >= (Sint64)0) { - *p++ = '+'; - } - - SDL_lltoa(value, p, info ? info->radix : 10); - SDL_IntPrecisionAdjust(num, sizeof(num), info); - return SDL_PrintString(text, maxlen, info, num); -} - -static size_t SDL_PrintUnsignedLongLong(char *text, size_t maxlen, SDL_FormatInfo *info, unsigned long long value) -{ - char num[130]; - - SDL_ulltoa(value, num, info ? info->radix : 10); - SDL_IntPrecisionAdjust(num, sizeof(num), info); - return SDL_PrintString(text, maxlen, info, num); -} - -static size_t SDL_PrintFloat(char *text, size_t maxlen, SDL_FormatInfo *info, double arg, bool g) -{ - char num[327]; - size_t length = 0; - size_t integer_length; - int precision = info->precision; - - // This isn't especially accurate, but hey, it's easy. :) - unsigned long long value; - - if (arg < 0.0 || (arg == 0.0 && 1.0 / arg < 0.0)) { // additional check for signed zero - num[length++] = '-'; - arg = -arg; - } else if (info->force_sign) { - num[length++] = '+'; - } - value = (unsigned long long)arg; - integer_length = SDL_PrintUnsignedLongLong(&num[length], sizeof(num) - length, NULL, value); - length += integer_length; - arg -= value; - if (precision < 0) { - precision = 6; - } - if (g) { - // The precision includes the integer portion - precision -= SDL_min((int)integer_length, precision); - } - if (info->force_type || precision > 0) { - const char decimal_separator = '.'; - double integer_value; - - SDL_assert(length < sizeof(num)); - num[length++] = decimal_separator; - while (precision > 1) { - arg *= 10.0; - arg = SDL_modf(arg, &integer_value); - SDL_assert(length < sizeof(num)); - num[length++] = '0' + (char)integer_value; - --precision; - } - if (precision == 1) { - arg *= 10.0; - integer_value = SDL_round(arg); - if (integer_value == 10.0) { - // Carry the one... - size_t i; - - for (i = length; i--; ) { - if (num[i] == decimal_separator) { - continue; - } - if (num[i] == '9') { - num[i] = '0'; - if (i == 0 || num[i - 1] == '-' || num[i - 1] == '+') { - SDL_memmove(&num[i+1], &num[i], length - i); - num[i] = '1'; - ++length; - break; - } - } else { - ++num[i]; - break; - } - } - SDL_assert(length < sizeof(num)); - num[length++] = '0'; - } else { - SDL_assert(length < sizeof(num)); - num[length++] = '0' + (char)integer_value; - } - } - - if (g) { - // Trim trailing zeroes and decimal separator - size_t i; - - for (i = length - 1; num[i] != decimal_separator; --i) { - if (num[i] == '0') { - --length; - } else { - break; - } - } - if (num[i] == decimal_separator) { - --length; - } - } - } - num[length] = '\0'; - - info->precision = -1; - length = SDL_PrintString(text, maxlen, info, num); - - if (info->width > 0 && (size_t)info->width > length) { - const char fill = info->pad_zeroes ? '0' : ' '; - size_t width = info->width - length; - size_t filllen, movelen; - - filllen = SDL_min(width, maxlen); - movelen = SDL_min(length, (maxlen - filllen)); - SDL_memmove(&text[filllen], text, movelen); - SDL_memset(text, fill, filllen); - length += width; - } - return length; -} - -static size_t SDL_PrintPointer(char *text, size_t maxlen, SDL_FormatInfo *info, const void *value) -{ - char num[130]; - size_t length; - - if (!value) { - return SDL_PrintString(text, maxlen, info, NULL); - } - - SDL_ulltoa((unsigned long long)(uintptr_t)value, num, 16); - length = SDL_PrintString(text, maxlen, info, "0x"); - return length + SDL_PrintString(TEXT_AND_LEN_ARGS, info, num); -} - -// NOLINTNEXTLINE(readability-non-const-parameter) -int SDL_vsnprintf(SDL_OUT_Z_CAP(maxlen) char *text, size_t maxlen, SDL_PRINTF_FORMAT_STRING const char *fmt, va_list ap) -{ - size_t length = 0; - - if (!text) { - maxlen = 0; - } - if (!fmt) { - fmt = ""; - } - while (*fmt) { - if (*fmt == '%') { - bool done = false; - bool check_flag; - SDL_FormatInfo info; - enum - { - DO_INT, - DO_LONG, - DO_LONGLONG, - DO_SIZE_T - } inttype = DO_INT; - - SDL_zero(info); - info.radix = 10; - info.precision = -1; - - check_flag = true; - while (check_flag) { - ++fmt; - switch (*fmt) { - case '-': - info.left_justify = true; - break; - case '+': - info.force_sign = true; - break; - case '#': - info.force_type = true; - break; - case '0': - info.pad_zeroes = true; - break; - default: - check_flag = false; - break; - } - } - - 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; - } - } - - while (!done) { - switch (*fmt) { - case '%': - if (length < maxlen) { - text[length] = '%'; - } - ++length; - done = true; - break; - case 'c': - // char is promoted to int when passed through (...) - if (length < maxlen) { - text[length] = (char)va_arg(ap, int); - } - ++length; - done = true; - break; - case 'h': - // short is promoted to int when passed through (...) - break; - case 'l': - if (inttype < DO_LONGLONG) { - ++inttype; - } - break; - case 'I': - if (SDL_strncmp(fmt, "I64", 3) == 0) { - fmt += 2; - inttype = DO_LONGLONG; - } - break; - case 'z': - inttype = DO_SIZE_T; - break; - case 'i': - case 'd': - if (info.precision >= 0) { - info.pad_zeroes = false; - } - switch (inttype) { - case DO_INT: - length += SDL_PrintLong(TEXT_AND_LEN_ARGS, &info, - (long)va_arg(ap, int)); - break; - case DO_LONG: - length += SDL_PrintLong(TEXT_AND_LEN_ARGS, &info, - va_arg(ap, long)); - break; - case DO_LONGLONG: - length += SDL_PrintLongLong(TEXT_AND_LEN_ARGS, &info, - va_arg(ap, long long)); - break; - case DO_SIZE_T: - length += SDL_PrintLongLong(TEXT_AND_LEN_ARGS, &info, - va_arg(ap, size_t)); - break; - } - done = true; - break; - case 'p': - info.force_case = SDL_CASE_LOWER; - length += SDL_PrintPointer(TEXT_AND_LEN_ARGS, &info, va_arg(ap, void *)); - done = true; - break; - case 'x': - info.force_case = SDL_CASE_LOWER; - SDL_FALLTHROUGH; - case 'X': - if (info.force_case == SDL_CASE_NOCHANGE) { - info.force_case = SDL_CASE_UPPER; - } - if (info.radix == 10) { - info.radix = 16; - } - SDL_FALLTHROUGH; - case 'o': - if (info.radix == 10) { - info.radix = 8; - } - SDL_FALLTHROUGH; - case 'u': - info.force_sign = false; - if (info.precision >= 0) { - info.pad_zeroes = false; - } - switch (inttype) { - case DO_INT: - length += SDL_PrintUnsignedLong(TEXT_AND_LEN_ARGS, &info, - va_arg(ap, unsigned int)); - break; - case DO_LONG: - length += SDL_PrintUnsignedLong(TEXT_AND_LEN_ARGS, &info, - va_arg(ap, unsigned long)); - break; - case DO_LONGLONG: - length += SDL_PrintUnsignedLongLong(TEXT_AND_LEN_ARGS, &info, - va_arg(ap, unsigned long long)); - break; - case DO_SIZE_T: - length += SDL_PrintUnsignedLongLong(TEXT_AND_LEN_ARGS, &info, - va_arg(ap, size_t)); - break; - } - done = true; - break; - case 'f': - length += SDL_PrintFloat(TEXT_AND_LEN_ARGS, &info, va_arg(ap, double), false); - done = true; - break; - case 'g': - length += SDL_PrintFloat(TEXT_AND_LEN_ARGS, &info, va_arg(ap, double), true); - done = true; - break; - case 'S': - info.pad_zeroes = false; - length += SDL_PrintStringW(TEXT_AND_LEN_ARGS, &info, va_arg(ap, wchar_t *)); - done = true; - break; - case 's': - info.pad_zeroes = false; - if (inttype > DO_INT) { - length += SDL_PrintStringW(TEXT_AND_LEN_ARGS, &info, va_arg(ap, wchar_t *)); - } else { - length += SDL_PrintString(TEXT_AND_LEN_ARGS, &info, va_arg(ap, char *)); - } - done = true; - break; - default: - done = true; - break; - } - ++fmt; - } - } else { - if (length < maxlen) { - text[length] = *fmt; - } - ++fmt; - ++length; - } - } - if (length < maxlen) { - text[length] = '\0'; - } else if (maxlen > 0) { - text[maxlen - 1] = '\0'; - } - return (int)length; -} - -#undef TEXT_AND_LEN_ARGS -#endif // HAVE_VSNPRINTF - -int SDL_vswprintf(SDL_OUT_Z_CAP(maxlen) wchar_t *text, size_t maxlen, const wchar_t *fmt, va_list ap) -{ - char *fmt_utf8 = NULL; - if (fmt) { - fmt_utf8 = SDL_iconv_string("UTF-8", "WCHAR_T", (const char *)fmt, (SDL_wcslen(fmt) + 1) * sizeof(wchar_t)); - if (!fmt_utf8) { - return -1; - } - } - - char tinybuf[64]; // for really small strings, calculate it once. - - // generate the text to find the final text length - va_list aq; - va_copy(aq, ap); - const int utf8len = SDL_vsnprintf(tinybuf, sizeof (tinybuf), fmt_utf8, aq); - va_end(aq); - - if (utf8len < 0) { - SDL_free(fmt_utf8); - return -1; - } - - bool isstack = false; - char *smallbuf = NULL; - char *utf8buf; - int result; - - if (utf8len < sizeof (tinybuf)) { // whole thing fit in the stack buffer, just use that copy. - utf8buf = tinybuf; - } else { // didn't fit in the stack buffer, allocate the needed space and run it again. - utf8buf = smallbuf = SDL_small_alloc(char, utf8len + 1, &isstack); - if (!smallbuf) { - SDL_free(fmt_utf8); - return -1; // oh well. - } - const int utf8len2 = SDL_vsnprintf(smallbuf, utf8len + 1, fmt_utf8, ap); - if (utf8len2 > utf8len) { - SDL_free(fmt_utf8); - return SDL_SetError("Formatted output changed between two runs"); // race condition on the parameters, and we no longer have room...yikes. - } - } - - SDL_free(fmt_utf8); - - wchar_t *wbuf = (wchar_t *)SDL_iconv_string("WCHAR_T", "UTF-8", utf8buf, utf8len + 1); - if (wbuf) { - if (text) { - SDL_wcslcpy(text, wbuf, maxlen); - } - result = (int)SDL_wcslen(wbuf); - SDL_free(wbuf); - } else { - result = -1; - } - - if (smallbuf != NULL) { - SDL_small_free(smallbuf, isstack); - } - - return result; -} - -int SDL_asprintf(char **strp, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) -{ - va_list ap; - int result; - - va_start(ap, fmt); - result = SDL_vasprintf(strp, fmt, ap); - va_end(ap); - - return result; -} - -int SDL_vasprintf(char **strp, SDL_PRINTF_FORMAT_STRING const char *fmt, va_list ap) -{ - int result; - int size = 100; // Guess we need no more than 100 bytes - char *p, *np; - va_list aq; - - *strp = NULL; - - p = (char *)SDL_malloc(size); - if (!p) { - return -1; - } - - while (1) { - // Try to print in the allocated space - va_copy(aq, ap); - result = SDL_vsnprintf(p, size, fmt, aq); - va_end(aq); - - // Check error code - if (result < 0) { - SDL_free(p); - return result; - } - - // If that worked, return the string - if (result < size) { - *strp = p; - return result; - } - - // Else try again with more space - size = result + 1; // Precisely what is needed - - np = (char *)SDL_realloc(p, size); - if (!np) { - SDL_free(p); - return -1; - } else { - p = np; - } - } -} - -char * SDL_strpbrk(const char *str, const char *breakset) -{ -#ifdef HAVE_STRPBRK - return strpbrk(str, breakset); -#else - - for (; *str; str++) { - const char *b; - - for (b = breakset; *b; b++) { - if (*str == *b) { - return (char *) str; - } - } - } - return NULL; -#endif -} -- cgit v1.2.3