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:
parent
f7c9cd06ac
commit
81daca5dd7
1 changed files with 42 additions and 26 deletions
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue