From 45839988174ece2038ae9535012f58cc2678b352 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 27 Sep 2014 13:34:48 +0800 Subject: [PATCH] Random work on C++11 printf --- .../Libraries/libc++_extras.so_src/Makefile | 7 +- .../libc++_extras.so_src/TEST_cprintf.cpp | 16 +- .../include_exp/cxxextras_printf | 178 +++++++++++++++++- 3 files changed, 182 insertions(+), 19 deletions(-) diff --git a/Usermode/Libraries/libc++_extras.so_src/Makefile b/Usermode/Libraries/libc++_extras.so_src/Makefile index a27ba3be..f129b612 100644 --- a/Usermode/Libraries/libc++_extras.so_src/Makefile +++ b/Usermode/Libraries/libc++_extras.so_src/Makefile @@ -12,9 +12,8 @@ LIBS += -lc++ include ../Makefile.tpl -EXP_%.txt: TEST_%.native - ./$< > $@ - rm $< - %.native: %.cpp $(NCXX) $< -o $@ -Wall -std=c++11 -I include_exp/ + +TEST_cprintf.native: include_exp/cxxextras_printf + diff --git a/Usermode/Libraries/libc++_extras.so_src/TEST_cprintf.cpp b/Usermode/Libraries/libc++_extras.so_src/TEST_cprintf.cpp index c99d1a7b..b77b0040 100644 --- a/Usermode/Libraries/libc++_extras.so_src/TEST_cprintf.cpp +++ b/Usermode/Libraries/libc++_extras.so_src/TEST_cprintf.cpp @@ -14,15 +14,15 @@ void my_puts(const char *str, size_t len) int main() { printf("Success\n"); - ::cxxextras::cprintf(my_puts, "%s %i %+#-010x\n", "hello_world", 1337, 0x1234565); + cprintf(my_puts, "%s %i %+#-010x\n", "hello_world", 1337, 0x1234565); - printf("Too Few\n"); - ASSERT_EXCEPTION( ::cxxextras::cprintf(my_puts, "%s %i %+#-010x\n"), ::cxxextras::cprintf_toofewargs ); - printf("Too Many\n"); - ASSERT_EXCEPTION( ::cxxextras::cprintf(my_puts, "%s\n", "tst", 12345), ::cxxextras::cprintf_toomanyargs ); - - printf("Bad Format\n"); - ASSERT_EXCEPTION( ::cxxextras::cprintf(my_puts, "%-\n"), ::cxxextras::cprintf_badformat ); + //printf("Too Few\n"); + //ASSERT_EXCEPTION( ::cxxextras::cprintf(my_puts, "%s %i %+#-010x\n"), ::cxxextras::cprintf_toofewargs ); + //printf("Too Many\n"); + //ASSERT_EXCEPTION( ::cxxextras::cprintf(my_puts, "%s\n", "tst", 12345), ::cxxextras::cprintf_toomanyargs ); + // + //printf("Bad Format\n"); + //ASSERT_EXCEPTION( ::cxxextras::cprintf(my_puts, "%-\n"), ::cxxextras::cprintf_badformat ); return 0; } diff --git a/Usermode/Libraries/libc++_extras.so_src/include_exp/cxxextras_printf b/Usermode/Libraries/libc++_extras.so_src/include_exp/cxxextras_printf index d9e2722d..7d05e219 100644 --- a/Usermode/Libraries/libc++_extras.so_src/include_exp/cxxextras_printf +++ b/Usermode/Libraries/libc++_extras.so_src/include_exp/cxxextras_printf @@ -89,7 +89,7 @@ struct PrintfFlags struct FHexU {}; constexpr PrintfFlags(PrintfFlags x, FHexU _): width(x.width), precision(x.precision), flags(x.flags | 0x800) {} - PrintfFlags(): + constexpr PrintfFlags(): width(0), precision(0), flags(0) { } @@ -120,7 +120,11 @@ constexpr unsigned todigit(const char ch) { typedef ::std::function cprintf_cb; template size_t cprintf_val(cprintf_cb puts, const _bits::PrintfFlags &fmt, Arg arg); +template constexpr bool cprintf_val_chk(const _bits::PrintfFlags fmt, Arg arg); +constexpr bool cprintf_val_chk(const _bits::PrintfFlags fmt, const char* arg) { + return true; +} size_t cprintf_val(cprintf_cb puts, const _bits::PrintfFlags& fmt, const char* arg) { unsigned int len; for(len = 0; arg[len]; len ++) @@ -128,6 +132,9 @@ size_t cprintf_val(cprintf_cb puts, const _bits::PrintfFlags& fmt, const char* a puts(arg, len); return len; } +constexpr bool cprintf_val_chk(const _bits::PrintfFlags& fmt, int arg) { + return true; +} size_t cprintf_val(cprintf_cb puts, const _bits::PrintfFlags& fmt, int arg) { size_t len = ::std::snprintf(nullptr, 0, "%i", arg); char buf[len+1]; @@ -135,6 +142,9 @@ size_t cprintf_val(cprintf_cb puts, const _bits::PrintfFlags& fmt, int arg) { puts(buf, len); return len; } +constexpr bool cprintf_val_chk(const _bits::PrintfFlags& fmt, unsigned int arg) { + return true; +} size_t cprintf_val(cprintf_cb puts, const _bits::PrintfFlags& fmt, unsigned int arg) { size_t len = ::std::snprintf(nullptr, 0, "%u", arg); char buf[len+1]; @@ -147,6 +157,158 @@ namespace _bits { namespace _printf { + template + class _str + { + const char m_buf[N]; + unsigned m_ofs; + public: + constexpr _str(const char buf[N]): + m_buf(buf), + m_ofs(0) + { + } + constexpr _str(const char buf[N], unsigned ofs): + m_buf(buf), + m_ofs(ofs) + { + } + constexpr _str operator+(const unsigned o) { + return _str(m_buf, m_ofs+o); + } + constexpr char operator*() { + return m_buf[m_ofs]; + } + }; + + template + constexpr bool val(const char* fmt, Args... args); + + template + constexpr bool val_fmt_done(const char * fmt, PrintfFlags item, Fmt fmtcode) + { + return false ? false : throw "Too few arguments"; + } + template + constexpr bool val_fmt_done(const char* fmt, PrintfFlags item, Fmt fmtcode, Arg arg, Args... args) + { + return cprintf_val_chk(item, arg) && val(fmt+1, args...); + } + // --- Format code + template + constexpr bool val_fmt_fmt(const char * fmt, PrintfFlags item, Args... args) + { + return *fmt == '\0' ? throw "ERROR: NUL byte in format specifier" + : *fmt == '?' ? val_fmt_done(fmt, item, PrintfFlags::FAuto(), args...) + : *fmt == 's' ? val_fmt_done(fmt, item, PrintfFlags::FString(),args...) + : *fmt == 'B' ? val_fmt_done(fmt, item, PrintfFlags::FBool(), args...) + : *fmt == 'b' ? val_fmt_done(fmt, item, PrintfFlags::FBinary(),args...) + : *fmt == 'o' ? val_fmt_done(fmt, item, PrintfFlags::FOct(), args...) + : *fmt == 'i' ? val_fmt_done(fmt, item, PrintfFlags::FSDec(), args...) + : *fmt == 'u' ? val_fmt_done(fmt, item, PrintfFlags::FUDec(), args...) + : *fmt == 'x' ? val_fmt_done(fmt, item, PrintfFlags::FHexL(), args...) + : *fmt == 'X' ? val_fmt_done(fmt, item, PrintfFlags::FHexU(), args...) + : throw cprintf_badformat("Unknown character in format string"); + } + // --- Size modifier (not implemented, not needed?) + template + constexpr bool val_fmt_size(const char * fmt, PrintfFlags item, Args... args) + { + // TODO: Size characters? + return val_fmt_fmt(fmt, item, args...); + } + // --- Precision + template + constexpr bool val_fmt_prec_val(const char * fmt, unsigned int value, PrintfFlags item, Args... args) + { + return _bits::isdigit_s(*fmt) ? val_fmt_prec_val(fmt+1, value*10+_bits::todigit(*fmt), item, args...) + : val_fmt_size(fmt, PrintfFlags(item, PrintfFlags::ArgPrec(), value), args...); + } + template + constexpr bool val_fmt_prec_arg(const char *fmt, PrintfFlags item, unsigned int size, Args... args) + { + return val_fmt_prec_opt(fmt, PrintfFlags(item, PrintfFlags::ArgPrec(), size), args...); + } + template + constexpr bool val_fmt_prec_arg(const char *fmt, PrintfFlags item, Arg size, Args... args) + { + //static_assert(false, "Invalid type for precision modifier, must be 'unsigned int'"); + return false ? false : throw "Invalid type for precision modifier, must be 'unsigned int'"; + } + constexpr bool val_fmt_prec_arg(const char *fmt, PrintfFlags item) + { + //static_assert(false, "Too few arguments when getting precision modifier"); + return false ? false : throw "Too few arguments when getting precision modifier"; + } + template + constexpr bool val_fmt_prec(const char * fmt, PrintfFlags item, Args... args) + { + return _bits::isdigit_s(*fmt) ? val_fmt_prec_val(fmt+1, _bits::todigit(*fmt), item, args...) + : *fmt == '*' ? val_fmt_prec_arg(fmt+1, item, args...) + : val_fmt_size(fmt, item, args...); + } + template + constexpr bool val_fmt_prec_opt(const char * fmt, PrintfFlags item, Args... args) + { + return *fmt == '.' ? val_fmt_prec(fmt+1, item, args...) + : val_fmt_size(fmt, item, args...); + } + // --- Field Width --- + template + constexpr bool val_fmt_width_val(const char* fmt, unsigned int size, PrintfFlags item, Args... args) + { + return _bits::isdigit_s(*fmt) ? val_fmt_width_val(fmt+1, size*10+_bits::todigit(*fmt), item, args...) + : val_fmt_prec_opt(fmt, PrintfFlags(item, PrintfFlags::ArgWidth(), size), args...); + } + template + constexpr bool val_fmt_width_arg(const char *fmt, PrintfFlags item, unsigned int size, Args... args) + { + return val_fmt_prec_opt(fmt, PrintfFlags(item, PrintfFlags::ArgWidth(), size), args...); + } + template + constexpr bool val_fmt_width_arg(const char *fmt, PrintfFlags item, Arg size, Args... args) + { + //static_assert(false, "Invalid type for width modifier, must be 'unsigned int'"); + return false ? false : throw "Invalid type for width modifier, must be 'unsigned int'"; + } + constexpr bool val_fmt_width_arg(const char *fmt, PrintfFlags item) + { + //static_assert(false, "Too few arguments when reading width for width modifier"); + return false ? false : throw "Too few arguments when reading width for width modifier"; + } + template + constexpr bool val_fmt_width(const char * fmt, PrintfFlags item, Args... args) + { + return _bits::isdigit_s(*fmt) ? val_fmt_width_val(fmt+1, _bits::todigit(*fmt), item, args...) + : *fmt == '*' ? val_fmt_width_arg(fmt+1, item, args...) + : val_fmt_prec_opt(fmt, item, args...); + } + // --- Flags + template + constexpr bool val_fmt_flags(const char * fmt, PrintfFlags item, Args... args) + { + return + *fmt == '-' ? val_fmt_flags(fmt+1, PrintfFlags(item, PrintfFlags::Left()) , args...) + : *fmt == '+' ? val_fmt_flags(fmt+1, PrintfFlags(item, PrintfFlags::Sign()) , args...) + : *fmt == ' ' ? val_fmt_flags(fmt+1, PrintfFlags(item, PrintfFlags::Space()), args...) + : *fmt == '#' ? val_fmt_flags(fmt+1, PrintfFlags(item, PrintfFlags::Alt()) , args...) + : *fmt == '0' ? val_fmt_flags(fmt+1, PrintfFlags(item, PrintfFlags::Zero()) , args...) + : val_fmt_width(fmt, item, args...); + } + // --- Literal '%' + template + constexpr bool val_fmt_start(const char* fmt, Args... args) + { + return *fmt == '%' ? val(fmt+1, args...) : val_fmt_flags(fmt, PrintfFlags(), args...); + } + template + constexpr bool val(const char* fmt, Args... args) + { + return *fmt == '\0' ? true + : *fmt == '%' ? val_fmt_start(fmt+1, args...) + : val(fmt+1, args...); + } + size_t run(cprintf_cb puts, const char *fmt); template size_t run(cprintf_cb puts, const char * fmt, Args... args); @@ -294,12 +456,14 @@ namespace _printf }; // namespace _bits -template -size_t cprintf(cprintf_cb puts, const char *fmt, Args... args) -{ - _bits::_printf::run(nullptr, fmt, args...); - return _bits::_printf::run(puts, fmt, args...); -} +#define cprintf(puts, fmt, ...) static_assert(::cxxextras::_bits::_printf::val(fmt, __VA_ARGS__),"");::cxxextras::_bits::_printf::run(puts, fmt, __VA_ARGS__) + +//template +//size_t cprintf(cprintf_cb puts, const char *fmt, Args... args) +//{ +// _bits::_printf::run(nullptr, fmt, args...); +// return _bits::_printf::run(puts, fmt, args...); +//} }; -- 2.20.1