1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 06:27:45 +00:00

LibC: Implement assignment suppression for vsscanf

The vsscanf library function lets the user skip assigning
parsed values to the arguments, e.g. with %*c - even though
a character is scanned it is not assigned to one of the
arguments.

The figlet port uses this. With this patch the port is actually
usable.
This commit is contained in:
Gunnar Beutner 2021-04-17 21:44:08 +02:00 committed by Andreas Kling
parent f7c9cd06ac
commit 81daca5dd7

View file

@ -84,7 +84,7 @@ struct ReadElementConcrete<int, ApT, kind> {
{
lexer.ignore_while(isspace);
auto* ptr = va_arg(*ap, ApT*);
auto* ptr = ap ? va_arg(*ap, ApT*) : nullptr;
long value = 0;
char* endptr = nullptr;
auto nptr = lexer.remaining().characters_without_null_termination();
@ -107,6 +107,7 @@ struct ReadElementConcrete<int, ApT, kind> {
VERIFY(diff > 0);
lexer.ignore((size_t)diff);
if (ptr)
*ptr = value;
return true;
}
@ -118,12 +119,13 @@ struct ReadElementConcrete<char, ApT, kind> {
{
static_assert(kind == ReadKind::Normal, "Can't read a non-normal character");
auto* ptr = va_arg(*ap, ApT*);
auto* ptr = ap ? va_arg(*ap, ApT*) : nullptr;
if (lexer.is_eof())
return false;
auto ch = lexer.consume();
if (ptr)
*ptr = ch;
return true;
}
@ -135,7 +137,7 @@ struct ReadElementConcrete<unsigned, ApT, kind> {
{
lexer.ignore_while(isspace);
auto* ptr = va_arg(*ap, ApT*);
auto* ptr = ap ? va_arg(*ap, ApT*) : nullptr;
unsigned long value = 0;
char* endptr = nullptr;
auto nptr = lexer.remaining().characters_without_null_termination();
@ -158,6 +160,7 @@ struct ReadElementConcrete<unsigned, ApT, kind> {
VERIFY(diff > 0);
lexer.ignore((size_t)diff);
if (ptr)
*ptr = value;
return true;
}
@ -169,7 +172,7 @@ struct ReadElementConcrete<long long, ApT, kind> {
{
lexer.ignore_while(isspace);
auto* ptr = va_arg(*ap, ApT*);
auto* ptr = ap ? va_arg(*ap, ApT*) : nullptr;
long long value = 0;
char* endptr = nullptr;
auto nptr = lexer.remaining().characters_without_null_termination();
@ -192,6 +195,7 @@ struct ReadElementConcrete<long long, ApT, kind> {
VERIFY(diff > 0);
lexer.ignore((size_t)diff);
if (ptr)
*ptr = value;
return true;
}
@ -203,7 +207,7 @@ struct ReadElementConcrete<unsigned long long, ApT, kind> {
{
lexer.ignore_while(isspace);
auto* ptr = va_arg(*ap, ApT*);
auto* ptr = ap ? va_arg(*ap, ApT*) : nullptr;
unsigned long long value = 0;
char* endptr = nullptr;
auto nptr = lexer.remaining().characters_without_null_termination();
@ -226,6 +230,7 @@ struct ReadElementConcrete<unsigned long long, ApT, kind> {
VERIFY(diff > 0);
lexer.ignore((size_t)diff);
if (ptr)
*ptr = value;
return true;
}
@ -237,7 +242,7 @@ struct ReadElementConcrete<float, ApT, kind> {
{
lexer.ignore_while(isspace);
auto* ptr = va_arg(*ap, ApT*);
auto* ptr = ap ? va_arg(*ap, ApT*) : nullptr;
double value = 0;
char* endptr = nullptr;
@ -257,6 +262,7 @@ struct ReadElementConcrete<float, ApT, kind> {
VERIFY(diff > 0);
lexer.ignore((size_t)diff);
if (ptr)
*ptr = value;
return true;
}
@ -322,7 +328,7 @@ struct ReadElement<char*, ReadKind::Normal> {
if (was_null)
input_lexer.ignore_while(isspace);
auto* ptr = va_arg(*ap, char*);
auto* ptr = ap ? va_arg(*ap, char*) : nullptr;
auto str = input_lexer.consume_while([this](auto c) { return this->matches(c); });
if (str.is_empty())
return false;
@ -353,7 +359,7 @@ struct ReadElement<void*, ReadKind::Normal> {
input_lexer.ignore_while(isspace);
auto* ptr = va_arg(*ap, void**);
auto* ptr = ap ? va_arg(*ap, void**) : nullptr;
auto str = input_lexer.consume_while([this](auto c) { return this->should_consume(c); });
if (count != 8) {
@ -418,6 +424,12 @@ extern "C" int vsscanf(const char* input, const char* format, va_list ap)
format_lexer.ignore(); // '%'
bool suppress_assignment = false;
if (format_lexer.next_is('*')) {
suppress_assignment = true;
format_lexer.ignore();
}
// Parse width specification
[[maybe_unused]] int width_specifier = 0;
if (format_lexer.next_is(isdigit)) {
@ -545,6 +557,8 @@ extern "C" int vsscanf(const char* input, const char* format, va_list ap)
}
}
auto* ap_or_null = !suppress_assignment ? (va_list*)&ap : nullptr;
// Now try to read.
switch (conversion_specifier) {
case Invalid:
@ -554,68 +568,70 @@ extern "C" int vsscanf(const char* input, const char* format, va_list ap)
dbgln("Invalid conversion specifier {} in scanf!", (int)conversion_specifier);
VERIFY_NOT_REACHED();
case Decimal:
if (!ReadElement<int, ReadKind::Normal> {}(length_modifier, input_lexer, (va_list*)&ap))
if (!ReadElement<int, ReadKind::Normal> {}(length_modifier, input_lexer, ap_or_null))
format_lexer.consume_all();
else
++elements_matched;
break;
case Integer:
if (!ReadElement<int, ReadKind::Infer> {}(length_modifier, input_lexer, (va_list*)&ap))
if (!ReadElement<int, ReadKind::Infer> {}(length_modifier, input_lexer, ap_or_null))
format_lexer.consume_all();
else
++elements_matched;
break;
case Octal:
if (!ReadElement<unsigned, ReadKind::Octal> {}(length_modifier, input_lexer, (va_list*)&ap))
if (!ReadElement<unsigned, ReadKind::Octal> {}(length_modifier, input_lexer, ap_or_null))
format_lexer.consume_all();
else
++elements_matched;
break;
case Unsigned:
if (!ReadElement<unsigned, ReadKind::Normal> {}(length_modifier, input_lexer, (va_list*)&ap))
if (!ReadElement<unsigned, ReadKind::Normal> {}(length_modifier, input_lexer, ap_or_null))
format_lexer.consume_all();
else
++elements_matched;
break;
case Hex:
if (!ReadElement<unsigned, ReadKind::Hex> {}(length_modifier, input_lexer, (va_list*)&ap))
if (!ReadElement<unsigned, ReadKind::Hex> {}(length_modifier, input_lexer, ap_or_null))
format_lexer.consume_all();
else
++elements_matched;
break;
case Floating:
if (!ReadElement<float, ReadKind::Normal> {}(length_modifier, input_lexer, (va_list*)&ap))
if (!ReadElement<float, ReadKind::Normal> {}(length_modifier, input_lexer, ap_or_null))
format_lexer.consume_all();
else
++elements_matched;
break;
case String:
if (!ReadElement<char*, ReadKind::Normal> {}(length_modifier, input_lexer, (va_list*)&ap))
if (!ReadElement<char*, ReadKind::Normal> {}(length_modifier, input_lexer, ap_or_null))
format_lexer.consume_all();
else
++elements_matched;
break;
case UseScanList:
if (!ReadElement<char*, ReadKind::Normal> { scanlist, invert_scanlist }(length_modifier, input_lexer, (va_list*)&ap))
if (!ReadElement<char*, ReadKind::Normal> { scanlist, invert_scanlist }(length_modifier, input_lexer, ap_or_null))
format_lexer.consume_all();
else
++elements_matched;
break;
case Character:
if (!ReadElement<char, ReadKind::Normal> {}(length_modifier, input_lexer, (va_list*)&ap))
if (!ReadElement<char, ReadKind::Normal> {}(length_modifier, input_lexer, ap_or_null))
format_lexer.consume_all();
else
++elements_matched;
break;
case Pointer:
if (!ReadElement<void*, ReadKind::Normal> {}(length_modifier, input_lexer, (va_list*)&ap))
if (!ReadElement<void*, ReadKind::Normal> {}(length_modifier, input_lexer, ap_or_null))
format_lexer.consume_all();
else
++elements_matched;
break;
case OutputNumberOfBytes: {
if (!suppress_assignment) {
auto* ptr = va_arg(ap, int*);
*ptr = input_lexer.tell();
}
++elements_matched;
break;
}