mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 19:37:35 +00:00
LibC+AK: Implement all sorts of wprintf variants
This commit is contained in:
parent
db7a6d6e74
commit
f0709c7a24
6 changed files with 93 additions and 37 deletions
|
@ -19,8 +19,8 @@ extern "C" size_t strlen(const char*);
|
||||||
|
|
||||||
namespace PrintfImplementation {
|
namespace PrintfImplementation {
|
||||||
|
|
||||||
template<typename PutChFunc, typename T>
|
template<typename PutChFunc, typename T, typename CharType>
|
||||||
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)
|
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;
|
int ret = 0;
|
||||||
|
|
||||||
|
@ -76,8 +76,8 @@ ALWAYS_INLINE int print_hex(PutChFunc putch, char*& bufptr, T number, bool upper
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename PutChFunc>
|
template<typename PutChFunc, typename CharType>
|
||||||
ALWAYS_INLINE int print_number(PutChFunc putch, char*& bufptr, u32 number, bool left_pad, bool zero_pad, u32 field_width)
|
ALWAYS_INLINE int print_number(PutChFunc putch, CharType*& bufptr, u32 number, bool left_pad, bool zero_pad, u32 field_width)
|
||||||
{
|
{
|
||||||
u32 divisor = 1000000000;
|
u32 divisor = 1000000000;
|
||||||
char ch;
|
char ch;
|
||||||
|
@ -117,8 +117,8 @@ ALWAYS_INLINE int print_number(PutChFunc putch, char*& bufptr, u32 number, bool
|
||||||
return field_width;
|
return field_width;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename PutChFunc>
|
template<typename PutChFunc, typename CharType>
|
||||||
ALWAYS_INLINE int print_u64(PutChFunc putch, char*& bufptr, u64 number, bool left_pad, bool zero_pad, u32 field_width)
|
ALWAYS_INLINE int print_u64(PutChFunc putch, CharType*& bufptr, u64 number, bool left_pad, bool zero_pad, u32 field_width)
|
||||||
{
|
{
|
||||||
u64 divisor = 10000000000000000000LLU;
|
u64 divisor = 10000000000000000000LLU;
|
||||||
char ch;
|
char ch;
|
||||||
|
@ -158,8 +158,8 @@ ALWAYS_INLINE int print_u64(PutChFunc putch, char*& bufptr, u64 number, bool lef
|
||||||
return field_width;
|
return field_width;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename PutChFunc>
|
template<typename PutChFunc, typename CharType>
|
||||||
ALWAYS_INLINE int print_double(PutChFunc putch, char*& bufptr, double number, bool left_pad, bool zero_pad, u32 field_width, u32 fraction_length)
|
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;
|
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);
|
return length + print_u64(putch, bufptr, (i64)fraction, false, true, fraction_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename PutChFunc>
|
template<typename PutChFunc, typename CharType>
|
||||||
ALWAYS_INLINE int print_i64(PutChFunc putch, char*& bufptr, i64 number, bool left_pad, bool zero_pad, u32 field_width)
|
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'.
|
// FIXME: This won't work if there is padding. ' -17' becomes '- 17'.
|
||||||
if (number < 0) {
|
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);
|
return print_u64(putch, bufptr, number, left_pad, zero_pad, field_width);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename PutChFunc>
|
template<typename PutChFunc, typename CharType>
|
||||||
ALWAYS_INLINE int print_octal_number(PutChFunc putch, char*& bufptr, u32 number, bool left_pad, bool zero_pad, u32 field_width)
|
ALWAYS_INLINE int print_octal_number(PutChFunc putch, CharType*& bufptr, u32 number, bool left_pad, bool zero_pad, u32 field_width)
|
||||||
{
|
{
|
||||||
u32 divisor = 134217728;
|
u32 divisor = 134217728;
|
||||||
char ch;
|
char ch;
|
||||||
|
@ -232,8 +232,8 @@ ALWAYS_INLINE int print_octal_number(PutChFunc putch, char*& bufptr, u32 number,
|
||||||
return field_width;
|
return field_width;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename PutChFunc>
|
template<typename PutChFunc, typename CharType>
|
||||||
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)
|
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)
|
if (has_fraction)
|
||||||
len = min(len, fraction_length);
|
len = min(len, fraction_length);
|
||||||
|
@ -260,8 +260,8 @@ ALWAYS_INLINE int print_string(PutChFunc putch, char*& bufptr, const char* str,
|
||||||
return field_width;
|
return field_width;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename PutChFunc>
|
template<typename PutChFunc, typename CharType>
|
||||||
ALWAYS_INLINE int print_signed_number(PutChFunc putch, char*& bufptr, int number, bool left_pad, bool zero_pad, u32 field_width, bool always_sign)
|
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) {
|
if (number < 0) {
|
||||||
putch(bufptr, '-');
|
putch(bufptr, '-');
|
||||||
|
@ -285,9 +285,9 @@ struct ModifierState {
|
||||||
bool always_sign { false };
|
bool always_sign { false };
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename PutChFunc, typename ArgumentListRefT, template<typename T, typename U = ArgumentListRefT> typename NextArgument>
|
template<typename PutChFunc, typename ArgumentListRefT, template<typename T, typename U = ArgumentListRefT> typename NextArgument, typename CharType = char>
|
||||||
struct PrintfImpl {
|
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_bufptr(bufptr)
|
||||||
, m_nwritten(nwritten)
|
, m_nwritten(nwritten)
|
||||||
, m_putch(putch)
|
, m_putch(putch)
|
||||||
|
@ -376,14 +376,14 @@ struct PrintfImpl {
|
||||||
char c = NextArgument<int>()(ap);
|
char c = NextArgument<int>()(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);
|
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);
|
dbgln("printf_internal: Unimplemented format specifier {} (fmt: {})", format_op, fmt);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
char*& m_bufptr;
|
CharType*& m_bufptr;
|
||||||
const int& m_nwritten;
|
const int& m_nwritten;
|
||||||
PutChFunc& m_putch;
|
PutChFunc& m_putch;
|
||||||
};
|
};
|
||||||
|
@ -401,15 +401,15 @@ struct VaArgNextArgument {
|
||||||
ret += impl.format_##c(state, ap); \
|
ret += impl.format_##c(state, ap); \
|
||||||
break;
|
break;
|
||||||
|
|
||||||
template<typename PutChFunc, template<typename T, typename U, template<typename X, typename Y> typename V> typename Impl = PrintfImpl, typename ArgumentListT = va_list, template<typename T, typename V = decltype(declval<ArgumentListT&>())> typename NextArgument = VaArgNextArgument>
|
template<typename PutChFunc, template<typename T, typename U, template<typename X, typename Y> typename V, typename C = char> typename Impl = PrintfImpl, typename ArgumentListT = va_list, template<typename T, typename V = decltype(declval<ArgumentListT&>())> typename NextArgument = VaArgNextArgument, typename CharType = char>
|
||||||
ALWAYS_INLINE int printf_internal(PutChFunc putch, char* buffer, const char*& fmt, ArgumentListT ap)
|
ALWAYS_INLINE int printf_internal(PutChFunc putch, IdentityType<CharType>* buffer, const CharType*& fmt, ArgumentListT ap)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
char* bufptr = buffer;
|
CharType* bufptr = buffer;
|
||||||
|
|
||||||
Impl<PutChFunc, ArgumentListT&, NextArgument> impl { putch, bufptr, ret };
|
Impl<PutChFunc, ArgumentListT&, NextArgument, CharType> impl { putch, bufptr, ret };
|
||||||
|
|
||||||
for (const char* p = fmt; *p; ++p) {
|
for (const CharType* p = fmt; *p; ++p) {
|
||||||
ModifierState state;
|
ModifierState state;
|
||||||
if (*p == '%' && *(p + 1)) {
|
if (*p == '%' && *(p + 1)) {
|
||||||
one_more:
|
one_more:
|
||||||
|
|
|
@ -19,8 +19,8 @@ struct SingleEntryListNext {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename PutChFunc, typename ArgumentListRefT, template<typename T, typename U = ArgumentListRefT> typename NextArgument>
|
template<typename PutChFunc, typename ArgumentListRefT, template<typename T, typename U = ArgumentListRefT> typename NextArgument, typename CharType>
|
||||||
struct PrintfImpl : public PrintfImplementation::PrintfImpl<PutChFunc, ArgumentListRefT, NextArgument> {
|
struct PrintfImpl : public PrintfImplementation::PrintfImpl<PutChFunc, ArgumentListRefT, NextArgument, CharType> {
|
||||||
ALWAYS_INLINE PrintfImpl(PutChFunc& putch, char*& bufptr, const int& nwritten)
|
ALWAYS_INLINE PrintfImpl(PutChFunc& putch, char*& bufptr, const int& nwritten)
|
||||||
: PrintfImplementation::PrintfImpl<PutChFunc, ArgumentListRefT, NextArgument>(putch, bufptr, nwritten)
|
: PrintfImplementation::PrintfImpl<PutChFunc, ArgumentListRefT, NextArgument>(putch, bufptr, nwritten)
|
||||||
{
|
{
|
||||||
|
|
|
@ -479,12 +479,6 @@ long double wcstold(wchar_t const*, wchar_t**)
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
|
|
||||||
int swprintf(wchar_t*, size_t, wchar_t const*, ...)
|
|
||||||
{
|
|
||||||
dbgln("TODO: Implement swprintf()");
|
|
||||||
TODO();
|
|
||||||
}
|
|
||||||
|
|
||||||
int wcwidth(wchar_t wc)
|
int wcwidth(wchar_t wc)
|
||||||
{
|
{
|
||||||
if (wc == L'\0')
|
if (wc == L'\0')
|
||||||
|
|
|
@ -61,7 +61,6 @@ unsigned long long wcstoull(const wchar_t*, wchar_t**, int);
|
||||||
float wcstof(const wchar_t*, wchar_t**);
|
float wcstof(const wchar_t*, wchar_t**);
|
||||||
double wcstod(const wchar_t*, wchar_t**);
|
double wcstod(const wchar_t*, wchar_t**);
|
||||||
long double wcstold(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);
|
int wcwidth(wchar_t);
|
||||||
size_t wcsrtombs(char*, const wchar_t**, size_t, mbstate_t*);
|
size_t wcsrtombs(char*, const wchar_t**, size_t, mbstate_t*);
|
||||||
size_t mbsrtowcs(wchar_t*, const char**, 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 fputws(const wchar_t* __restrict ws, FILE* __restrict stream);
|
||||||
int fwide(FILE* stream, int mode);
|
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
|
__END_DECLS
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include <AK/Assertions.h>
|
#include <AK/Assertions.h>
|
||||||
#include <AK/BitCast.h>
|
#include <AK/BitCast.h>
|
||||||
|
#include <AK/PrintfImplementation.h>
|
||||||
#include <AK/StringBuilder.h>
|
#include <AK/StringBuilder.h>
|
||||||
#include <AK/Types.h>
|
#include <AK/Types.h>
|
||||||
#include <bits/stdio_file_implementation.h>
|
#include <bits/stdio_file_implementation.h>
|
||||||
|
@ -118,4 +119,59 @@ int fputws(wchar_t const* __restrict ws, FILE* __restrict stream)
|
||||||
}
|
}
|
||||||
return size;
|
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<wchar_t const*>(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<wchar_t const*>(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<int>(length_so_far);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,8 +20,8 @@
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename PutChFunc, typename ArgumentListRefT, template<typename T, typename U = ArgumentListRefT> typename NextArgument>
|
template<typename PutChFunc, typename ArgumentListRefT, template<typename T, typename U = ArgumentListRefT> typename NextArgument, typename CharType>
|
||||||
struct PrintfImpl : public PrintfImplementation::PrintfImpl<PutChFunc, ArgumentListRefT, NextArgument> {
|
requires(IsSame<CharType, char>) struct PrintfImpl : public PrintfImplementation::PrintfImpl<PutChFunc, ArgumentListRefT, NextArgument, CharType> {
|
||||||
ALWAYS_INLINE PrintfImpl(PutChFunc& putch, char*& bufptr, const int& nwritten)
|
ALWAYS_INLINE PrintfImpl(PutChFunc& putch, char*& bufptr, const int& nwritten)
|
||||||
: PrintfImplementation::PrintfImpl<PutChFunc, ArgumentListRefT, NextArgument>(putch, bufptr, nwritten)
|
: PrintfImplementation::PrintfImpl<PutChFunc, ArgumentListRefT, NextArgument>(putch, bufptr, nwritten)
|
||||||
{
|
{
|
||||||
|
@ -273,7 +273,7 @@ int main(int argc, char** argv)
|
||||||
auto previous_argc = 0;
|
auto previous_argc = 0;
|
||||||
do {
|
do {
|
||||||
previous_argc = argc;
|
previous_argc = argc;
|
||||||
PrintfImplementation::printf_internal<decltype(putch), PrintfImpl, ArgvWithCount, ArgvNextArgument>(putch, nullptr, format_string, arg);
|
PrintfImplementation::printf_internal<decltype(putch), PrintfImpl, ArgvWithCount, ArgvNextArgument, char>(putch, nullptr, format_string, arg);
|
||||||
} while (argc && previous_argc != argc);
|
} while (argc && previous_argc != argc);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue