diff options
author | AnotherTest <ali.mpfard@gmail.com> | 2021-02-16 12:50:48 +0330 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-02-16 10:38:52 +0100 |
commit | e438dd3c9b406ba36fbd98c25514b4a335f21b41 (patch) | |
tree | 9f6edab1ad3b69485509055b1c23bdc69ec2b275 | |
parent | 2323b6fb74d1cc7761a7bb294cf2a52080ccd57e (diff) | |
download | serenity-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.cpp | 38 | ||||
-rw-r--r-- | Userland/Tests/LibC/scanf.cpp | 5 |
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; |