1 // Formatting library for C++ - std::ostream support
2 //
3 // Copyright (c) 2012 - present, Victor Zverovich
4 // All rights reserved.
5 //
6 // For the license information refer to format.h.
7
8 #ifndef FMT_OSTREAM_H_
9 #define FMT_OSTREAM_H_
10
11 #ifndef FMT_MODULE
12 # include <fstream> // std::filebuf
13 #endif
14
15 #ifdef _WIN32
16 # ifdef __GLIBCXX__
17 # include <ext/stdio_filebuf.h>
18 # include <ext/stdio_sync_filebuf.h>
19 # endif
20 # include <io.h>
21 #endif
22
23 #include "chrono.h" // formatbuf
24
25 FMT_BEGIN_NAMESPACE
26 namespace detail {
27
28 // Generate a unique explicit instantion in every translation unit using a tag
29 // type in an anonymous namespace.
30 namespace {
31 struct file_access_tag {};
32 } // namespace
33 template <typename Tag, typename BufType, FILE* BufType::*FileMemberPtr>
34 class file_access {
35 friend auto get_file(BufType& obj) -> FILE* { return obj.*FileMemberPtr; }
36 };
37
38 #if FMT_MSC_VERSION
39 template class file_access<file_access_tag, std::filebuf,
40 &std::filebuf::_Myfile>;
41 auto get_file(std::filebuf&) -> FILE*;
42 #endif
43
44 // Write the content of buf to os.
45 // It is a separate function rather than a part of vprint to simplify testing.
46 template <typename Char>
write_buffer(std::basic_ostream<Char> & os,buffer<Char> & buf)47 void write_buffer(std::basic_ostream<Char>& os, buffer<Char>& buf) {
48 const Char* buf_data = buf.data();
49 using unsigned_streamsize = make_unsigned_t<std::streamsize>;
50 unsigned_streamsize size = buf.size();
51 unsigned_streamsize max_size = to_unsigned(max_value<std::streamsize>());
52 do {
53 unsigned_streamsize n = size <= max_size ? size : max_size;
54 os.write(buf_data, static_cast<std::streamsize>(n));
55 buf_data += n;
56 size -= n;
57 } while (size != 0);
58 }
59
60 template <typename T> struct streamed_view {
61 const T& value;
62 };
63 } // namespace detail
64
65 // Formats an object of type T that has an overloaded ostream operator<<.
66 template <typename Char>
67 struct basic_ostream_formatter : formatter<basic_string_view<Char>, Char> {
68 void set_debug_format() = delete;
69
70 template <typename T, typename Context>
71 auto format(const T& value, Context& ctx) const -> decltype(ctx.out()) {
72 auto buffer = basic_memory_buffer<Char>();
73 auto&& formatbuf = detail::formatbuf<std::basic_streambuf<Char>>(buffer);
74 auto&& output = std::basic_ostream<Char>(&formatbuf);
75 output.imbue(std::locale::classic()); // The default is always unlocalized.
76 output << value;
77 output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
78 return formatter<basic_string_view<Char>, Char>::format(
79 {buffer.data(), buffer.size()}, ctx);
80 }
81 };
82
83 using ostream_formatter = basic_ostream_formatter<char>;
84
85 template <typename T, typename Char>
86 struct formatter<detail::streamed_view<T>, Char>
87 : basic_ostream_formatter<Char> {
88 template <typename Context>
89 auto format(detail::streamed_view<T> view, Context& ctx) const
90 -> decltype(ctx.out()) {
91 return basic_ostream_formatter<Char>::format(view.value, ctx);
92 }
93 };
94
95 /**
96 * Returns a view that formats `value` via an ostream `operator<<`.
97 *
98 * **Example**:
99 *
100 * fmt::print("Current thread id: {}\n",
101 * fmt::streamed(std::this_thread::get_id()));
102 */
103 template <typename T>
104 constexpr auto streamed(const T& value) -> detail::streamed_view<T> {
105 return {value};
106 }
107
108 inline void vprint(std::ostream& os, string_view fmt, format_args args) {
109 auto buffer = memory_buffer();
110 detail::vformat_to(buffer, fmt, args);
111 FILE* f = nullptr;
112 #if FMT_MSC_VERSION && FMT_USE_RTTI
113 if (auto* buf = dynamic_cast<std::filebuf*>(os.rdbuf()))
114 f = detail::get_file(*buf);
115 #elif defined(_WIN32) && defined(__GLIBCXX__) && FMT_USE_RTTI
116 auto* rdbuf = os.rdbuf();
117 if (auto* sfbuf = dynamic_cast<__gnu_cxx::stdio_sync_filebuf<char>*>(rdbuf))
118 f = sfbuf->file();
119 else if (auto* fbuf = dynamic_cast<__gnu_cxx::stdio_filebuf<char>*>(rdbuf))
120 f = fbuf->file();
121 #endif
122 #ifdef _WIN32
123 if (f) {
124 int fd = _fileno(f);
125 if (_isatty(fd)) {
126 os.flush();
127 if (detail::write_console(fd, {buffer.data(), buffer.size()})) return;
128 }
129 }
130 #endif
131 detail::ignore_unused(f);
132 detail::write_buffer(os, buffer);
133 }
134
135 /**
136 * Prints formatted data to the stream `os`.
137 *
138 * **Example**:
139 *
140 * fmt::print(cerr, "Don't {}!", "panic");
141 */
142 FMT_EXPORT template <typename... T>
143 void print(std::ostream& os, format_string<T...> fmt, T&&... args) {
144 fmt::vargs<T...> vargs = {{args...}};
145 if (detail::use_utf8) return vprint(os, fmt.str, vargs);
146 auto buffer = memory_buffer();
147 detail::vformat_to(buffer, fmt.str, vargs);
148 detail::write_buffer(os, buffer);
149 }
150
151 FMT_EXPORT template <typename... T>
152 void println(std::ostream& os, format_string<T...> fmt, T&&... args) {
153 fmt::print(os, "{}\n", fmt::format(fmt, std::forward<T>(args)...));
154 }
155
156 FMT_END_NAMESPACE
157
158 #endif // FMT_OSTREAM_H_
159