summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AK/PrintfImplementation.h16
-rw-r--r--Tests/AK/CMakeLists.txt1
-rw-r--r--Tests/AK/TestPrint.cpp58
-rw-r--r--Userland/Utilities/printf.cpp11
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
{