Added support for "%[]" sscanf syntax

Fixes https://github.com/libsdl-org/SDL/issues/8423
This commit is contained in:
Sam Lantinga
2023-10-24 16:41:19 -07:00
parent 124a0050b6
commit 39a961ba41
2 changed files with 148 additions and 1 deletions

View File

@@ -1199,6 +1199,39 @@ int SDL_vsscanf(const char *text, const char *fmt, va_list ap)
return vsscanf(text, fmt, ap);
}
#else
static SDL_bool CharacterMatchesSet(char c, const char *set, size_t set_len)
{
SDL_bool invert = SDL_FALSE;
SDL_bool result = SDL_FALSE;
if (*set == '^') {
invert = SDL_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 = SDL_TRUE;
}
set += 3;
set_len -= 3;
} else {
if (c == *set) {
result = SDL_TRUE;
}
++set;
--set_len;
}
}
if (invert) {
result = result ? SDL_FALSE : SDL_TRUE;
}
return result;
}
/* NOLINTNEXTLINE(readability-non-const-parameter) */
int SDL_vsscanf(const char *text, const char *fmt, va_list ap)
{
@@ -1472,6 +1505,44 @@ int SDL_vsscanf(const char *text, const char *fmt, va_list ap)
}
done = SDL_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 {
SDL_bool had_match = SDL_FALSE;
char *valuep = va_arg(ap, char *);
while (CharacterMatchesSet(*text, set, set_len)) {
had_match = SDL_TRUE;
*valuep++ = *text++;
if (count) {
if (--count == 0) {
break;
}
}
}
*valuep = '\0';
if (had_match) {
++retval;
}
}
}
}
done = SDL_TRUE;
break;
default:
done = SDL_TRUE;
break;