diff --git a/include/fmt/compile.h b/include/fmt/compile.h index 71881535..9528b57d 100644 --- a/include/fmt/compile.h +++ b/include/fmt/compile.h @@ -606,6 +606,20 @@ size_t formatted_size(const S& format_str, const Args&... args) { return format_to(detail::counting_iterator(), format_str, args...).count(); } +template ::value)> +void print(std::FILE* f, const S& format_str, const Args&... args) { + memory_buffer buffer; + format_to(std::back_inserter(buffer), format_str, args...); + detail::print(f, {buffer.data(), buffer.size()}); +} + +template ::value)> +void print(const S& format_str, const Args&... args) { + print(stdout, format_str, args...); +} + #if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS inline namespace literals { template diff --git a/include/fmt/format-inl.h b/include/fmt/format-inl.h index 4be6c1c3..a3eaa361 100644 --- a/include/fmt/format-inl.h +++ b/include/fmt/format-inl.h @@ -2595,13 +2595,12 @@ extern "C" __declspec(dllimport) int __stdcall WriteConsoleW( // } // namespace detail #endif -FMT_FUNC void vprint(std::FILE* f, string_view format_str, format_args args) { - memory_buffer buffer; - detail::vformat_to(buffer, format_str, args); +namespace detail { +FMT_FUNC void print(std::FILE* f, string_view text) { #ifdef _WIN32 auto fd = _fileno(f); if (_isatty(fd)) { - detail::utf8_to_utf16 u16(string_view(buffer.data(), buffer.size())); + detail::utf8_to_utf16 u16(string_view(text.data(), text.size())); auto written = detail::dword(); if (detail::WriteConsoleW(reinterpret_cast(_get_osfhandle(fd)), u16.c_str(), static_cast(u16.size()), @@ -2612,7 +2611,14 @@ FMT_FUNC void vprint(std::FILE* f, string_view format_str, format_args args) { // redirected to NUL. } #endif - detail::fwrite_fully(buffer.data(), 1, buffer.size(), f); + detail::fwrite_fully(text.data(), 1, text.size(), f); +} +} // namespace detail + +FMT_FUNC void vprint(std::FILE* f, string_view format_str, format_args args) { + memory_buffer buffer; + detail::vformat_to(buffer, format_str, args); + detail::print(f, {buffer.data(), buffer.size()}); } #ifdef _WIN32 diff --git a/include/fmt/format.h b/include/fmt/format.h index 9f1178bd..4dc9e097 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -791,6 +791,10 @@ template struct is_contiguous> : std::true_type { }; +namespace detail { +FMT_API void print(std::FILE*, string_view); +} + /** A formatting error such as invalid format string. */ FMT_CLASS_API class FMT_API format_error : public std::runtime_error { diff --git a/test/compile-test.cc b/test/compile-test.cc index 71eddc92..58fd057d 100644 --- a/test/compile-test.cc +++ b/test/compile-test.cc @@ -11,6 +11,7 @@ #include "fmt/chrono.h" #include "gmock/gmock.h" +#include "gtest-extra.h" TEST(iterator_test, counting_iterator) { auto it = fmt::detail::counting_iterator(); @@ -241,6 +242,13 @@ FMT_END_NAMESPACE TEST(compile_test, to_string_and_formatter) { fmt::format(FMT_COMPILE("{}"), to_stringable()); } + +TEST(compile_test, print) { + EXPECT_WRITE(stdout, fmt::print(FMT_COMPILE("Don't {}!"), "panic"), + "Don't panic!"); + EXPECT_WRITE(stderr, fmt::print(stderr, FMT_COMPILE("Don't {}!"), "panic"), + "Don't panic!"); +} #endif #if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS