diff options
-rw-r--r-- | AK/PrintfImplementation.h | 16 | ||||
-rw-r--r-- | Tests/AK/CMakeLists.txt | 1 | ||||
-rw-r--r-- | Tests/AK/TestPrint.cpp | 58 | ||||
-rw-r--r-- | Userland/Utilities/printf.cpp | 11 |
4 files changed, 84 insertions, 2 deletions
diff --git a/AK/PrintfImplementation.h b/AK/PrintfImplementation.h index 44cbc62ba3..51b46b4b47 100644 --- a/AK/PrintfImplementation.h +++ b/AK/PrintfImplementation.h @@ -11,6 +11,7 @@ #include <AK/Types.h> #include <math.h> #include <stdarg.h> +#include <wchar.h> #ifdef __serenity__ extern "C" size_t strlen(const char*); @@ -277,8 +278,8 @@ ALWAYS_INLINE int print_octal_number(PutChFunc putch, CharType*& bufptr, u64 num return field_width; } -template<typename PutChFunc, typename CharType> -ALWAYS_INLINE int print_string(PutChFunc putch, CharType*& bufptr, const char* str, size_t len, bool left_pad, size_t field_width, bool dot, size_t precision, bool has_fraction) +template<typename PutChFunc, typename T, typename CharType> +ALWAYS_INLINE int print_string(PutChFunc putch, CharType*& bufptr, T str, size_t len, bool left_pad, size_t field_width, bool dot, size_t precision, bool has_fraction) { if (has_fraction) len = min(len, precision); @@ -339,6 +340,17 @@ struct PrintfImpl { ALWAYS_INLINE int format_s(const ModifierState& state, ArgumentListRefT ap) const { + // FIXME: Narrow characters should be converted to wide characters on the fly and vice versa. + // https://pubs.opengroup.org/onlinepubs/9699919799/functions/printf.html + // https://pubs.opengroup.org/onlinepubs/9699919799/functions/wprintf.html +#ifndef KERNEL + if (state.long_qualifiers) { + const wchar_t* sp = NextArgument<const wchar_t*>()(ap); + if (!sp) + sp = L"(null)"; + return print_string(m_putch, m_bufptr, sp, wcslen(sp), state.left_pad, state.field_width, state.dot, state.precision, state.has_precision); + } +#endif const char* sp = NextArgument<const char*>()(ap); if (!sp) sp = "(null)"; diff --git a/Tests/AK/CMakeLists.txt b/Tests/AK/CMakeLists.txt index fac063f6fd..38b066fcbe 100644 --- a/Tests/AK/CMakeLists.txt +++ b/Tests/AK/CMakeLists.txt @@ -48,6 +48,7 @@ set(AK_TEST_SOURCES TestNonnullRefPtr.cpp TestNumberFormat.cpp TestOptional.cpp + TestPrint.cpp TestQueue.cpp TestQuickSort.cpp TestRedBlackTree.cpp diff --git a/Tests/AK/TestPrint.cpp b/Tests/AK/TestPrint.cpp new file mode 100644 index 0000000000..780415cce0 --- /dev/null +++ b/Tests/AK/TestPrint.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2022, the SerenityOS developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <LibTest/TestCase.h> +#include <wchar.h> + +TEST_CASE(swprint_no_format) +{ + wchar_t buffer[256]; + size_t len = swprintf(buffer, 64, L"Well, hello friends!"); + + VERIFY(wcscmp(buffer, L"Well, hello friends!") == 0); + VERIFY(wcscmp(buffer, L"Well, hello friends") != 0); + VERIFY(wcslen(buffer) == len); +} + +TEST_CASE(swprint_single_wchar_argument) +{ + wchar_t buffer[256]; + size_t len = swprintf(buffer, 64, L"Well, %ls friends!", L"hello"); + + VERIFY(wcscmp(buffer, L"Well, hello friends!") == 0); + VERIFY(wcscmp(buffer, L"Well, hello friends") != 0); + VERIFY(wcslen(buffer) == len); +} + +TEST_CASE(swprint_single_char_argument) +{ + wchar_t buffer[256]; + size_t len = swprintf(buffer, 64, L"Well, %s friends!", "hello"); + + VERIFY(wcscmp(buffer, L"Well, hello friends!") == 0); + VERIFY(wcscmp(buffer, L"Well, hello friends") != 0); + VERIFY(wcslen(buffer) == len); +} + +TEST_CASE(swprint_single_narrow_char_argument) +{ + wchar_t buffer[256]; + size_t len = swprintf(buffer, 64, L"Well, %hs friends!", "hello"); + + VERIFY(wcscmp(buffer, L"Well, hello friends!") == 0); + VERIFY(wcscmp(buffer, L"Well, hello friends") != 0); + VERIFY(wcslen(buffer) == len); +} + +TEST_CASE(swprint_mixed_arguments) +{ + wchar_t buffer[256]; + size_t len = swprintf(buffer, 64, L"Well, %ls friends! %hs is less then %s.", L"hello", "10", "20"); + + VERIFY(wcscmp(buffer, L"Well, hello friends! 10 is less then 20.") == 0); + VERIFY(wcscmp(buffer, L"Well, hello friends! 10 is less then 2.") != 0); + VERIFY(wcslen(buffer) == len); +} diff --git a/Userland/Utilities/printf.cpp b/Userland/Utilities/printf.cpp index 36099d4e7d..fe7a9b7f27 100644 --- a/Userland/Utilities/printf.cpp +++ b/Userland/Utilities/printf.cpp @@ -119,6 +119,17 @@ struct ArgvNextArgument<const char*, V> { }; template<typename V> +struct ArgvNextArgument<const wchar_t*, V> { + ALWAYS_INLINE const wchar_t* operator()(V arg) const + { + if (arg.argc == 0) + return L""; + + return L""; + } +}; + +template<typename V> struct ArgvNextArgument<int, V> { ALWAYS_INLINE int operator()(V arg) const { |