diff --git a/AK/PrintfImplementation.h b/AK/PrintfImplementation.h index 38b5fcf360..2d6d5fbce1 100644 --- a/AK/PrintfImplementation.h +++ b/AK/PrintfImplementation.h @@ -19,8 +19,8 @@ extern "C" size_t strlen(const char*); namespace PrintfImplementation { -template -ALWAYS_INLINE int print_hex(PutChFunc putch, char*& bufptr, T number, bool upper_case, bool alternate_form, bool left_pad, bool zero_pad, u8 field_width) +template +ALWAYS_INLINE int print_hex(PutChFunc putch, CharType*& bufptr, T number, bool upper_case, bool alternate_form, bool left_pad, bool zero_pad, u8 field_width) { int ret = 0; @@ -76,8 +76,8 @@ ALWAYS_INLINE int print_hex(PutChFunc putch, char*& bufptr, T number, bool upper return ret; } -template -ALWAYS_INLINE int print_number(PutChFunc putch, char*& bufptr, u32 number, bool left_pad, bool zero_pad, u32 field_width) +template +ALWAYS_INLINE int print_number(PutChFunc putch, CharType*& bufptr, u32 number, bool left_pad, bool zero_pad, u32 field_width) { u32 divisor = 1000000000; char ch; @@ -117,8 +117,8 @@ ALWAYS_INLINE int print_number(PutChFunc putch, char*& bufptr, u32 number, bool return field_width; } -template -ALWAYS_INLINE int print_u64(PutChFunc putch, char*& bufptr, u64 number, bool left_pad, bool zero_pad, u32 field_width) +template +ALWAYS_INLINE int print_u64(PutChFunc putch, CharType*& bufptr, u64 number, bool left_pad, bool zero_pad, u32 field_width) { u64 divisor = 10000000000000000000LLU; char ch; @@ -158,8 +158,8 @@ ALWAYS_INLINE int print_u64(PutChFunc putch, char*& bufptr, u64 number, bool lef return field_width; } -template -ALWAYS_INLINE int print_double(PutChFunc putch, char*& bufptr, double number, bool left_pad, bool zero_pad, u32 field_width, u32 fraction_length) +template +ALWAYS_INLINE int print_double(PutChFunc putch, CharType*& bufptr, double number, bool left_pad, bool zero_pad, u32 field_width, u32 fraction_length) { int length = 0; @@ -180,8 +180,8 @@ ALWAYS_INLINE int print_double(PutChFunc putch, char*& bufptr, double number, bo return length + print_u64(putch, bufptr, (i64)fraction, false, true, fraction_length); } -template -ALWAYS_INLINE int print_i64(PutChFunc putch, char*& bufptr, i64 number, bool left_pad, bool zero_pad, u32 field_width) +template +ALWAYS_INLINE int print_i64(PutChFunc putch, CharType*& bufptr, i64 number, bool left_pad, bool zero_pad, u32 field_width) { // FIXME: This won't work if there is padding. ' -17' becomes '- 17'. if (number < 0) { @@ -191,8 +191,8 @@ ALWAYS_INLINE int print_i64(PutChFunc putch, char*& bufptr, i64 number, bool lef return print_u64(putch, bufptr, number, left_pad, zero_pad, field_width); } -template -ALWAYS_INLINE int print_octal_number(PutChFunc putch, char*& bufptr, u32 number, bool left_pad, bool zero_pad, u32 field_width) +template +ALWAYS_INLINE int print_octal_number(PutChFunc putch, CharType*& bufptr, u32 number, bool left_pad, bool zero_pad, u32 field_width) { u32 divisor = 134217728; char ch; @@ -232,8 +232,8 @@ ALWAYS_INLINE int print_octal_number(PutChFunc putch, char*& bufptr, u32 number, return field_width; } -template -ALWAYS_INLINE int print_string(PutChFunc putch, char*& bufptr, const char* str, size_t len, bool left_pad, size_t field_width, bool dot, size_t fraction_length, bool has_fraction) +template +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 fraction_length, bool has_fraction) { if (has_fraction) len = min(len, fraction_length); @@ -260,8 +260,8 @@ ALWAYS_INLINE int print_string(PutChFunc putch, char*& bufptr, const char* str, return field_width; } -template -ALWAYS_INLINE int print_signed_number(PutChFunc putch, char*& bufptr, int number, bool left_pad, bool zero_pad, u32 field_width, bool always_sign) +template +ALWAYS_INLINE int print_signed_number(PutChFunc putch, CharType*& bufptr, int number, bool left_pad, bool zero_pad, u32 field_width, bool always_sign) { if (number < 0) { putch(bufptr, '-'); @@ -285,9 +285,9 @@ struct ModifierState { bool always_sign { false }; }; -template typename NextArgument> +template typename NextArgument, typename CharType = char> struct PrintfImpl { - ALWAYS_INLINE PrintfImpl(PutChFunc& putch, char*& bufptr, const int& nwritten) + ALWAYS_INLINE PrintfImpl(PutChFunc& putch, CharType*& bufptr, const int& nwritten) : m_bufptr(bufptr) , m_nwritten(nwritten) , m_putch(putch) @@ -376,14 +376,14 @@ struct PrintfImpl { char c = NextArgument()(ap); return print_string(m_putch, m_bufptr, &c, 1, state.left_pad, state.field_width, state.dot, state.fraction_length, state.has_fraction_length); } - ALWAYS_INLINE int format_unrecognized(char format_op, const char* fmt, const ModifierState&, ArgumentListRefT) const + ALWAYS_INLINE int format_unrecognized(CharType format_op, const CharType* fmt, const ModifierState&, ArgumentListRefT) const { dbgln("printf_internal: Unimplemented format specifier {} (fmt: {})", format_op, fmt); return 0; } protected: - char*& m_bufptr; + CharType*& m_bufptr; const int& m_nwritten; PutChFunc& m_putch; }; @@ -401,15 +401,15 @@ struct VaArgNextArgument { ret += impl.format_##c(state, ap); \ break; -template typename V> typename Impl = PrintfImpl, typename ArgumentListT = va_list, template())> typename NextArgument = VaArgNextArgument> -ALWAYS_INLINE int printf_internal(PutChFunc putch, char* buffer, const char*& fmt, ArgumentListT ap) +template typename V, typename C = char> typename Impl = PrintfImpl, typename ArgumentListT = va_list, template())> typename NextArgument = VaArgNextArgument, typename CharType = char> +ALWAYS_INLINE int printf_internal(PutChFunc putch, IdentityType* buffer, const CharType*& fmt, ArgumentListT ap) { int ret = 0; - char* bufptr = buffer; + CharType* bufptr = buffer; - Impl impl { putch, bufptr, ret }; + Impl impl { putch, bufptr, ret }; - for (const char* p = fmt; *p; ++p) { + for (const CharType* p = fmt; *p; ++p) { ModifierState state; if (*p == '%' && *(p + 1)) { one_more: diff --git a/Userland/Applications/Spreadsheet/CellType/Format.cpp b/Userland/Applications/Spreadsheet/CellType/Format.cpp index bcdce48acf..f33d11e320 100644 --- a/Userland/Applications/Spreadsheet/CellType/Format.cpp +++ b/Userland/Applications/Spreadsheet/CellType/Format.cpp @@ -19,8 +19,8 @@ struct SingleEntryListNext { } }; -template typename NextArgument> -struct PrintfImpl : public PrintfImplementation::PrintfImpl { +template typename NextArgument, typename CharType> +struct PrintfImpl : public PrintfImplementation::PrintfImpl { ALWAYS_INLINE PrintfImpl(PutChFunc& putch, char*& bufptr, const int& nwritten) : PrintfImplementation::PrintfImpl(putch, bufptr, nwritten) { diff --git a/Userland/Libraries/LibC/wchar.cpp b/Userland/Libraries/LibC/wchar.cpp index 13c5081317..801b7d6d72 100644 --- a/Userland/Libraries/LibC/wchar.cpp +++ b/Userland/Libraries/LibC/wchar.cpp @@ -479,12 +479,6 @@ long double wcstold(wchar_t const*, wchar_t**) TODO(); } -int swprintf(wchar_t*, size_t, wchar_t const*, ...) -{ - dbgln("TODO: Implement swprintf()"); - TODO(); -} - int wcwidth(wchar_t wc) { if (wc == L'\0') diff --git a/Userland/Libraries/LibC/wchar.h b/Userland/Libraries/LibC/wchar.h index d17b432180..034009e3ba 100644 --- a/Userland/Libraries/LibC/wchar.h +++ b/Userland/Libraries/LibC/wchar.h @@ -61,7 +61,6 @@ unsigned long long wcstoull(const wchar_t*, wchar_t**, int); float wcstof(const wchar_t*, wchar_t**); double wcstod(const wchar_t*, wchar_t**); long double wcstold(const wchar_t*, wchar_t**); -int swprintf(wchar_t*, size_t, const wchar_t*, ...); int wcwidth(wchar_t); size_t wcsrtombs(char*, const wchar_t**, size_t, mbstate_t*); size_t mbsrtowcs(wchar_t*, const char**, size_t, mbstate_t*); @@ -81,4 +80,11 @@ wchar_t* fgetws(wchar_t* __restrict ws, int n, FILE* __restrict stream); int fputws(const wchar_t* __restrict ws, FILE* __restrict stream); int fwide(FILE* stream, int mode); +int wprintf(const wchar_t* __restrict format, ...); +int fwprintf(FILE* __restrict stream, const wchar_t* __restrict format, ...); +int swprintf(wchar_t* __restrict wcs, size_t maxlen, const wchar_t* __restrict format, ...); +int vwprintf(const wchar_t* __restrict format, va_list args); +int vfwprintf(FILE* __restrict stream, const wchar_t* __restrict format, va_list args); +int vswprintf(wchar_t* __restrict wcs, size_t maxlen, const wchar_t* __restrict format, va_list args); + __END_DECLS diff --git a/Userland/Libraries/LibC/wstdio.cpp b/Userland/Libraries/LibC/wstdio.cpp index 521551a208..d98fb71925 100644 --- a/Userland/Libraries/LibC/wstdio.cpp +++ b/Userland/Libraries/LibC/wstdio.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -118,4 +119,59 @@ int fputws(wchar_t const* __restrict ws, FILE* __restrict stream) } return size; } + +int wprintf(wchar_t const* __restrict format, ...) +{ + va_list ap; + va_start(ap, format); + auto rc = vfwprintf(stdout, format, ap); + va_end(ap); + return rc; +} + +int fwprintf(FILE* __restrict stream, wchar_t const* __restrict format, ...) +{ + va_list ap; + va_start(ap, format); + auto rc = vfwprintf(stream, format, ap); + va_end(ap); + return rc; +} + +int swprintf(wchar_t* __restrict wcs, size_t max_length, wchar_t const* __restrict format, ...) +{ + va_list ap; + va_start(ap, format); + auto rc = vswprintf(wcs, max_length, format, ap); + va_end(ap); + return rc; +} + +int vwprintf(wchar_t const* __restrict format, va_list args) +{ + return vfwprintf(stdout, format, args); +} + +int vfwprintf(FILE* __restrict stream, wchar_t const* __restrict format, va_list args) +{ + auto const* fmt = bit_cast(format); + return printf_internal([stream](wchar_t*&, wchar_t wc) { + putwc(wc, stream); + }, + nullptr, fmt, args); +} + +int vswprintf(wchar_t* __restrict wcs, size_t max_length, wchar_t const* __restrict format, va_list args) +{ + auto const* fmt = bit_cast(format); + size_t length_so_far = 0; + printf_internal([max_length, &length_so_far](wchar_t*& buffer, wchar_t wc) { + if (length_so_far > max_length) + return; + *buffer++ = wc; + ++length_so_far; + }, + wcs, fmt, args); + return static_cast(length_so_far); +} } diff --git a/Userland/Utilities/printf.cpp b/Userland/Utilities/printf.cpp index 576db3d5c8..1ea46d54b4 100644 --- a/Userland/Utilities/printf.cpp +++ b/Userland/Utilities/printf.cpp @@ -20,8 +20,8 @@ exit(1); } -template typename NextArgument> -struct PrintfImpl : public PrintfImplementation::PrintfImpl { +template typename NextArgument, typename CharType> +requires(IsSame) struct PrintfImpl : public PrintfImplementation::PrintfImpl { ALWAYS_INLINE PrintfImpl(PutChFunc& putch, char*& bufptr, const int& nwritten) : PrintfImplementation::PrintfImpl(putch, bufptr, nwritten) { @@ -273,7 +273,7 @@ int main(int argc, char** argv) auto previous_argc = 0; do { previous_argc = argc; - PrintfImplementation::printf_internal(putch, nullptr, format_string, arg); + PrintfImplementation::printf_internal(putch, nullptr, format_string, arg); } while (argc && previous_argc != argc); return 0;