From ab44451578ec6e449bd78b8f99ee0333dba69e3c Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Mon, 24 Feb 2025 18:49:31 -0800 Subject: [PATCH] Added support for the "%n" sscanf format specifier (cherry picked from commit 69803253100111f870c068300d336edac19783b4) --- src/stdlib/SDL_string.c | 31 ++++++++++++++++++++++ test/testautomation_stdlib.c | 50 +++++++++++++++++++++--------------- 2 files changed, 61 insertions(+), 20 deletions(-) diff --git a/src/stdlib/SDL_string.c b/src/stdlib/SDL_string.c index 9af6977fe6..2ce22186e3 100644 --- a/src/stdlib/SDL_string.c +++ b/src/stdlib/SDL_string.c @@ -1113,6 +1113,7 @@ static SDL_bool CharacterMatchesSet(char c, const char *set, size_t set_len) /* NOLINTNEXTLINE(readability-non-const-parameter) */ int SDL_vsscanf(const char *text, const char *fmt, va_list ap) { + const char *start = text; int retval = 0; if (!text || !*text) { @@ -1383,6 +1384,36 @@ int SDL_vsscanf(const char *text, const char *fmt, va_list ap) } done = SDL_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 = SDL_TRUE; + break; case '[': { const char *set = fmt + 1; diff --git a/test/testautomation_stdlib.c b/test/testautomation_stdlib.c index 30abf0a7f7..e62069da4b 100644 --- a/test/testautomation_stdlib.c +++ b/test/testautomation_stdlib.c @@ -393,6 +393,7 @@ int stdlib_getsetenv(void *arg) #endif #define FMT_PRILLd "%lld" +#define FMT_PRILLdn "%lld%lln" #define FMT_PRILLu "%llu" /** @@ -403,11 +404,12 @@ int stdlib_sscanf(void *arg) { int output; int result; + int length; int expected_output; int expected_result; - short short_output, expected_short_output; - long long_output, expected_long_output; - long long long_long_output, expected_long_long_output; + short short_output, expected_short_output, short_length; + long long_output, expected_long_output, long_length; + long long long_long_output, expected_long_long_output, long_long_length; size_t size_output, expected_size_output; char text[128], text2[128]; @@ -426,43 +428,51 @@ int stdlib_sscanf(void *arg) SDLTest_AssertCheck(expected_result == result, "Check return value, expected: %i, got: %i", expected_result, result); output = 123; + length = 0; expected_output = 2; expected_result = 1; - result = SDL_sscanf("2", "%i", &output); - SDLTest_AssertPass("Call to SDL_sscanf(\"2\", \"%%i\", &output)"); + result = SDL_sscanf("2", "%i%n", &output, &length); + SDLTest_AssertPass("Call to SDL_sscanf(\"2\", \"%%i%%n\", &output, &length)"); SDLTest_AssertCheck(expected_output == output, "Check output, expected: %i, got: %i", expected_output, output); SDLTest_AssertCheck(expected_result == result, "Check return value, expected: %i, got: %i", expected_result, result); + SDLTest_AssertCheck(length == 1, "Check length, expected: 1, got: %i", length); output = 123; + length = 0; expected_output = 0xa; expected_result = 1; - result = SDL_sscanf("aa", "%1x", &output); - SDLTest_AssertPass("Call to SDL_sscanf(\"aa\", \"%%1x\", &output)"); + result = SDL_sscanf("aa", "%1x%n", &output, &length); + SDLTest_AssertPass("Call to SDL_sscanf(\"aa\", \"%%1x%%n\", &output, &length)"); SDLTest_AssertCheck(expected_output == output, "Check output, expected: %i, got: %i", expected_output, output); SDLTest_AssertCheck(expected_result == result, "Check return value, expected: %i, got: %i", expected_result, result); + SDLTest_AssertCheck(length == 1, "Check length, expected: 1, got: %i", length); -#define SIZED_TEST_CASE(type, var, format_specifier) \ +#define SIZED_TEST_CASE(type, var, printf_specifier, scanf_specifier) \ var##_output = 123; \ + var##_length = 0; \ expected_##var##_output = (type)(((unsigned type)(~0)) >> 1); \ expected_result = 1; \ - result = SDL_snprintf(text, sizeof(text), format_specifier, expected_##var##_output); \ - result = SDL_sscanf(text, format_specifier, &var##_output); \ - SDLTest_AssertPass("Call to SDL_sscanf(\"%s\", \"%s\", &output)", text, #format_specifier); \ - SDLTest_AssertCheck(expected_##var##_output == var##_output, "Check output, expected: " format_specifier ", got: " format_specifier, expected_##var##_output, var##_output); \ + result = SDL_snprintf(text, sizeof(text), printf_specifier, expected_##var##_output); \ + result = SDL_sscanf(text, scanf_specifier, &var##_output, &var##_length); \ + SDLTest_AssertPass("Call to SDL_sscanf(\"%s\", %s, &output, &length)", text, #scanf_specifier); \ + SDLTest_AssertCheck(expected_##var##_output == var##_output, "Check output, expected: " printf_specifier ", got: " printf_specifier, expected_##var##_output, var##_output); \ SDLTest_AssertCheck(expected_result == result, "Check return value, expected: %i, got: %i", expected_result, result); \ + SDLTest_AssertCheck(var##_length == (type)SDL_strlen(text), "Check length, expected: %i, got: %i", (int)SDL_strlen(text), (int)var##_length); \ \ var##_output = 123; \ + var##_length = 0; \ expected_##var##_output = ~(type)(((unsigned type)(~0)) >> 1); \ expected_result = 1; \ - result = SDL_snprintf(text, sizeof(text), format_specifier, expected_##var##_output); \ - result = SDL_sscanf(text, format_specifier, &var##_output); \ - SDLTest_AssertPass("Call to SDL_sscanf(\"%s\", \"%s\", &output)", text, #format_specifier); \ - SDLTest_AssertCheck(expected_##var##_output == var##_output, "Check output, expected: " format_specifier ", got: " format_specifier, expected_##var##_output, var##_output); \ - SDLTest_AssertCheck(expected_result == result, "Check return value, expected: %i, got: %i", expected_result, result); + result = SDL_snprintf(text, sizeof(text), printf_specifier, expected_##var##_output); \ + result = SDL_sscanf(text, scanf_specifier, &var##_output, &var##_length); \ + SDLTest_AssertPass("Call to SDL_sscanf(\"%s\", %s, &output, &length)", text, #scanf_specifier); \ + SDLTest_AssertCheck(expected_##var##_output == var##_output, "Check output, expected: " printf_specifier ", got: " printf_specifier, expected_##var##_output, var##_output); \ + SDLTest_AssertCheck(expected_result == result, "Check return value, expected: %i, got: %i", expected_result, result); \ + SDLTest_AssertCheck(var##_length == (type)SDL_strlen(text), "Check length, expected: %i, got: %i", (int)SDL_strlen(text), (int)var##_length); \ - SIZED_TEST_CASE(short, short, "%hd") - SIZED_TEST_CASE(long, long, "%ld") - SIZED_TEST_CASE(long long, long_long, "%lld") + SIZED_TEST_CASE(short, short, "%hd", "%hd%hn") + SIZED_TEST_CASE(long, long, "%ld", "%ld%ln") + SIZED_TEST_CASE(long long, long_long, FMT_PRILLd, FMT_PRILLdn) size_output = 123; expected_size_output = ~((size_t)0);