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