summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnotherTest <ali.mpfard@gmail.com>2021-02-16 12:50:48 +0330
committerAndreas Kling <kling@serenityos.org>2021-02-16 10:38:52 +0100
commite438dd3c9b406ba36fbd98c25514b4a335f21b41 (patch)
tree9f6edab1ad3b69485509055b1c23bdc69ec2b275
parent2323b6fb74d1cc7761a7bb294cf2a52080ccd57e (diff)
downloadserenity-e438dd3c9b406ba36fbd98c25514b4a335f21b41.zip
LibC: Teach scanf how to read "%lu" and "%llu" (unsigned long{, long})
This makes the gcc port work again.
-rw-r--r--Userland/Libraries/LibC/scanf.cpp38
-rw-r--r--Userland/Tests/LibC/scanf.cpp5
2 files changed, 43 insertions, 0 deletions
diff --git a/Userland/Libraries/LibC/scanf.cpp b/Userland/Libraries/LibC/scanf.cpp
index e1b30f6f69..bb51aad92d 100644
--- a/Userland/Libraries/LibC/scanf.cpp
+++ b/Userland/Libraries/LibC/scanf.cpp
@@ -164,6 +164,40 @@ struct read_element_concrete<unsigned, ApT, kind> {
};
template<typename ApT, ReadKind kind>
+struct read_element_concrete<unsigned long long, ApT, kind> {
+ bool operator()(GenericLexer& lexer, va_list* ap)
+ {
+ lexer.ignore_while(isspace);
+
+ auto* ptr = va_arg(*ap, ApT*);
+ unsigned long long value = 0;
+ char* endptr = nullptr;
+ auto nptr = lexer.remaining().characters_without_null_termination();
+ if constexpr (kind == ReadKind::Normal)
+ value = strtoull(nptr, &endptr, 10);
+ if constexpr (kind == ReadKind::Octal)
+ value = strtoull(nptr, &endptr, 8);
+ if constexpr (kind == ReadKind::Hex)
+ value = strtoull(nptr, &endptr, 16);
+ if constexpr (kind == ReadKind::Infer)
+ value = strtoull(nptr, &endptr, 0);
+
+ if (!endptr)
+ return false;
+
+ if (endptr == nptr)
+ return false;
+
+ auto diff = endptr - nptr;
+ ASSERT(diff > 0);
+ lexer.ignore((size_t)diff);
+
+ *ptr = value;
+ return true;
+ }
+};
+
+template<typename ApT, ReadKind kind>
struct read_element_concrete<float, ApT, kind> {
bool operator()(GenericLexer& lexer, va_list* ap)
{
@@ -211,12 +245,16 @@ struct read_element {
case Long:
if constexpr (IsSame<T, int>::value)
return read_element_concrete<T, long, kind> {}(input_lexer, ap);
+ if constexpr (IsSame<T, unsigned>::value)
+ return read_element_concrete<T, unsigned, kind> {}(input_lexer, ap);
if constexpr (IsSame<T, float>::value)
return read_element_concrete<T, double, kind> {}(input_lexer, ap);
return false;
case LongLong:
if constexpr (IsSame<T, int>::value)
return read_element_concrete<T, long long, kind> {}(input_lexer, ap);
+ if constexpr (IsSame<T, unsigned>::value)
+ return read_element_concrete<T, unsigned long long, kind> {}(input_lexer, ap);
if constexpr (IsSame<T, float>::value)
return read_element_concrete<T, double, kind> {}(input_lexer, ap);
return false;
diff --git a/Userland/Tests/LibC/scanf.cpp b/Userland/Tests/LibC/scanf.cpp
index 4da0d92856..da358ddac2 100644
--- a/Userland/Tests/LibC/scanf.cpp
+++ b/Userland/Tests/LibC/scanf.cpp
@@ -31,6 +31,7 @@
typedef long double longdouble;
typedef long long longlong;
+typedef unsigned long unsignedlong;
typedef char charstar[32];
template<typename T>
@@ -143,6 +144,7 @@ DECL_WITH_TYPE(longlong);
DECL_WITH_TYPE(float);
DECL_WITH_TYPE(double);
DECL_WITH_TYPE(longdouble);
+DECL_WITH_TYPE(unsignedlong);
#undef DECL_WITH_TYPE
@@ -179,6 +181,9 @@ const TestSuite test_suites[] {
{ "%u.%u.%u", "3.19", 2, 3, { unsignedarg0, unsignedarg1, unsignedarg2 }, { to_value_t(3u), to_value_t(19u) } },
// Failing test case from previous impl:
{ "SSH-%d.%d-%[^\n]\n", "SSH-2.0-OpenSSH_8.2p1 Ubuntu-4ubuntu0.1\n", 3, 3, { intarg0, intarg1, charstararg0 }, { to_value_t(2), to_value_t(0), str_to_value_t("OpenSSH_8.2p1 Ubuntu-4ubuntu0.1") } },
+ // GCC failure tests
+ { "%d.%d.%d", "10.2.0", 3, 3, { intarg0, intarg1, intarg2 }, { to_value_t(10), to_value_t(2), to_value_t(0) } },
+ { "%lu", "3054 ", 1, 1, { unsignedlongarg0 }, { to_value_t(3054ul) } },
};
bool g_any_failed = false;