1 // Formatting library for C++ - legacy printf implementation
3 // Copyright (c) 2012 - 2016, Victor Zverovich
4 // All rights reserved.
6 // For the license information refer to format.h.
12 # include <algorithm> // std::max
13 # include <limits> // std::numeric_limits
21 template <typename T
> struct printf_formatter
{
22 printf_formatter() = delete;
25 template <typename Char
> class basic_printf_context
{
27 basic_appender
<Char
> out_
;
28 basic_format_args
<basic_printf_context
> args_
;
30 static_assert(std::is_same
<Char
, char>::value
||
31 std::is_same
<Char
, wchar_t>::value
,
32 "Unsupported code unit type.");
35 using char_type
= Char
;
36 using parse_context_type
= basic_format_parse_context
<Char
>;
37 template <typename T
> using formatter_type
= printf_formatter
<T
>;
39 /// Constructs a `printf_context` object. References to the arguments are
40 /// stored in the context object so make sure they have appropriate lifetimes.
41 basic_printf_context(basic_appender
<Char
> out
,
42 basic_format_args
<basic_printf_context
> args
)
43 : out_(out
), args_(args
) {}
45 auto out() -> basic_appender
<Char
> { return out_
; }
46 void advance_to(basic_appender
<Char
>) {}
48 auto locale() -> detail::locale_ref
{ return {}; }
50 auto arg(int id
) const -> basic_format_arg
<basic_printf_context
> {
57 // Checks if a value fits in int - used to avoid warnings about comparing
58 // signed and unsigned integers.
59 template <bool IsSigned
> struct int_checker
{
60 template <typename T
> static auto fits_in_int(T value
) -> bool {
61 unsigned max
= to_unsigned(max_value
<int>());
64 static auto fits_in_int(bool) -> bool { return true; }
67 template <> struct int_checker
<true> {
68 template <typename T
> static auto fits_in_int(T value
) -> bool {
69 return value
>= (std::numeric_limits
<int>::min
)() &&
70 value
<= max_value
<int>();
72 static auto fits_in_int(int) -> bool { return true; }
75 struct printf_precision_handler
{
76 template <typename T
, FMT_ENABLE_IF(std::is_integral
<T
>::value
)>
77 auto operator()(T value
) -> int {
78 if (!int_checker
<std::numeric_limits
<T
>::is_signed
>::fits_in_int(value
))
79 report_error("number is too big");
80 return (std::max
)(static_cast<int>(value
), 0);
83 template <typename T
, FMT_ENABLE_IF(!std::is_integral
<T
>::value
)>
84 auto operator()(T
) -> int {
85 report_error("precision is not integer");
90 // An argument visitor that returns true iff arg is a zero integer.
92 template <typename T
, FMT_ENABLE_IF(std::is_integral
<T
>::value
)>
93 auto operator()(T value
) -> bool {
97 template <typename T
, FMT_ENABLE_IF(!std::is_integral
<T
>::value
)>
98 auto operator()(T
) -> bool {
103 template <typename T
> struct make_unsigned_or_bool
: std::make_unsigned
<T
> {};
105 template <> struct make_unsigned_or_bool
<bool> {
109 template <typename T
, typename Context
> class arg_converter
{
111 using char_type
= typename
Context::char_type
;
113 basic_format_arg
<Context
>& arg_
;
117 arg_converter(basic_format_arg
<Context
>& arg
, char_type type
)
118 : arg_(arg
), type_(type
) {}
120 void operator()(bool value
) {
121 if (type_
!= 's') operator()<bool>(value
);
124 template <typename U
, FMT_ENABLE_IF(std::is_integral
<U
>::value
)>
125 void operator()(U value
) {
126 bool is_signed
= type_
== 'd' || type_
== 'i';
127 using target_type
= conditional_t
<std::is_same
<T
, void>::value
, U
, T
>;
128 if (const_check(sizeof(target_type
) <= sizeof(int))) {
129 // Extra casts are used to silence warnings.
131 auto n
= static_cast<int>(static_cast<target_type
>(value
));
132 arg_
= detail::make_arg
<Context
>(n
);
134 using unsigned_type
= typename make_unsigned_or_bool
<target_type
>::type
;
135 auto n
= static_cast<unsigned>(static_cast<unsigned_type
>(value
));
136 arg_
= detail::make_arg
<Context
>(n
);
140 // glibc's printf doesn't sign extend arguments of smaller types:
141 // std::printf("%lld", -42); // prints "4294967254"
142 // but we don't have to do the same because it's a UB.
143 auto n
= static_cast<long long>(value
);
144 arg_
= detail::make_arg
<Context
>(n
);
146 auto n
= static_cast<typename make_unsigned_or_bool
<U
>::type
>(value
);
147 arg_
= detail::make_arg
<Context
>(n
);
152 template <typename U
, FMT_ENABLE_IF(!std::is_integral
<U
>::value
)>
153 void operator()(U
) {} // No conversion needed for non-integral types.
156 // Converts an integer argument to T for printf, if T is an integral type.
157 // If T is void, the argument is converted to corresponding signed or unsigned
158 // type depending on the type specifier: 'd' and 'i' - signed, other -
160 template <typename T
, typename Context
, typename Char
>
161 void convert_arg(basic_format_arg
<Context
>& arg
, Char type
) {
162 arg
.visit(arg_converter
<T
, Context
>(arg
, type
));
165 // Converts an integer argument to char for printf.
166 template <typename Context
> class char_converter
{
168 basic_format_arg
<Context
>& arg_
;
171 explicit char_converter(basic_format_arg
<Context
>& arg
) : arg_(arg
) {}
173 template <typename T
, FMT_ENABLE_IF(std::is_integral
<T
>::value
)>
174 void operator()(T value
) {
175 auto c
= static_cast<typename
Context::char_type
>(value
);
176 arg_
= detail::make_arg
<Context
>(c
);
179 template <typename T
, FMT_ENABLE_IF(!std::is_integral
<T
>::value
)>
180 void operator()(T
) {} // No conversion needed for non-integral types.
183 // An argument visitor that return a pointer to a C string if argument is a
184 // string or null otherwise.
185 template <typename Char
> struct get_cstring
{
186 template <typename T
> auto operator()(T
) -> const Char
* { return nullptr; }
187 auto operator()(const Char
* s
) -> const Char
* { return s
; }
190 // Checks if an argument is a valid printf width specifier and sets
191 // left alignment if it is negative.
192 class printf_width_handler
{
194 format_specs
& specs_
;
197 explicit printf_width_handler(format_specs
& specs
) : specs_(specs
) {}
199 template <typename T
, FMT_ENABLE_IF(std::is_integral
<T
>::value
)>
200 auto operator()(T value
) -> unsigned {
201 auto width
= static_cast<uint32_or_64_or_128_t
<T
>>(value
);
202 if (detail::is_negative(value
)) {
203 specs_
.align
= align::left
;
206 unsigned int_max
= to_unsigned(max_value
<int>());
207 if (width
> int_max
) report_error("number is too big");
208 return static_cast<unsigned>(width
);
211 template <typename T
, FMT_ENABLE_IF(!std::is_integral
<T
>::value
)>
212 auto operator()(T
) -> unsigned {
213 report_error("width is not integer");
218 // Workaround for a bug with the XL compiler when initializing
219 // printf_arg_formatter's base class.
220 template <typename Char
>
221 auto make_arg_formatter(basic_appender
<Char
> iter
, format_specs
& s
)
222 -> arg_formatter
<Char
> {
223 return {iter
, s
, locale_ref()};
226 // The `printf` argument formatter.
227 template <typename Char
>
228 class printf_arg_formatter
: public arg_formatter
<Char
> {
230 using base
= arg_formatter
<Char
>;
231 using context_type
= basic_printf_context
<Char
>;
233 context_type
& context_
;
235 void write_null_pointer(bool is_string
= false) {
236 auto s
= this->specs
;
237 s
.type
= presentation_type::none
;
238 write_bytes
<Char
>(this->out
, is_string
? "(null)" : "(nil)", s
);
242 printf_arg_formatter(basic_appender
<Char
> iter
, format_specs
& s
,
244 : base(make_arg_formatter(iter
, s
)), context_(ctx
) {}
246 void operator()(monostate value
) { base::operator()(value
); }
248 template <typename T
, FMT_ENABLE_IF(detail::is_integral
<T
>::value
)>
249 void operator()(T value
) {
250 // MSVC2013 fails to compile separate overloads for bool and Char so use
251 // std::is_same instead.
252 if (!std::is_same
<T
, Char
>::value
) {
253 base::operator()(value
);
256 format_specs s
= this->specs
;
257 if (s
.type
!= presentation_type::none
&& s
.type
!= presentation_type::chr
) {
258 return (*this)(static_cast<int>(value
));
262 s
.fill
= ' '; // Ignore '0' flag for char types.
263 // align::numeric needs to be overwritten here since the '0' flag is
264 // ignored for non-numeric types
265 if (s
.align
== align::none
|| s
.align
== align::numeric
)
266 s
.align
= align::right
;
267 write
<Char
>(this->out
, static_cast<Char
>(value
), s
);
270 template <typename T
, FMT_ENABLE_IF(std::is_floating_point
<T
>::value
)>
271 void operator()(T value
) {
272 base::operator()(value
);
275 void operator()(const char* value
) {
277 base::operator()(value
);
279 write_null_pointer(this->specs
.type
!= presentation_type::pointer
);
282 void operator()(const wchar_t* value
) {
284 base::operator()(value
);
286 write_null_pointer(this->specs
.type
!= presentation_type::pointer
);
289 void operator()(basic_string_view
<Char
> value
) { base::operator()(value
); }
291 void operator()(const void* value
) {
293 base::operator()(value
);
295 write_null_pointer();
298 void operator()(typename basic_format_arg
<context_type
>::handle handle
) {
299 auto parse_ctx
= basic_format_parse_context
<Char
>({});
300 handle
.format(parse_ctx
, context_
);
304 template <typename Char
>
305 void parse_flags(format_specs
& specs
, const Char
*& it
, const Char
* end
) {
306 for (; it
!= end
; ++it
) {
309 specs
.align
= align::left
;
312 specs
.sign
= sign::plus
;
318 if (specs
.sign
!= sign::plus
) specs
.sign
= sign::space
;
329 template <typename Char
, typename GetArg
>
330 auto parse_header(const Char
*& it
, const Char
* end
, format_specs
& specs
,
331 GetArg get_arg
) -> int {
334 if (c
>= '0' && c
<= '9') {
335 // Parse an argument index (if followed by '$') or a width possibly
336 // preceded with '0' flag(s).
337 int value
= parse_nonnegative_int(it
, end
, -1);
338 if (it
!= end
&& *it
== '$') { // value is an argument index
340 arg_index
= value
!= -1 ? value
: max_value
<int>();
342 if (c
== '0') specs
.fill
= '0';
344 // Nonzero value means that we parsed width and don't need to
345 // parse it or flags again, so return now.
346 if (value
== -1) report_error("number is too big");
352 parse_flags(specs
, it
, end
);
355 if (*it
>= '0' && *it
<= '9') {
356 specs
.width
= parse_nonnegative_int(it
, end
, -1);
357 if (specs
.width
== -1) report_error("number is too big");
358 } else if (*it
== '*') {
360 specs
.width
= static_cast<int>(
361 get_arg(-1).visit(detail::printf_width_handler(specs
)));
367 inline auto parse_printf_presentation_type(char c
, type t
, bool& upper
)
368 -> presentation_type
{
369 using pt
= presentation_type
;
370 constexpr auto integral_set
= sint_set
| uint_set
| bool_set
| char_set
;
373 return in(t
, integral_set
) ? pt::dec
: pt::none
;
375 return in(t
, integral_set
) ? pt::oct
: pt::none
;
380 return in(t
, integral_set
) ? pt::hex
: pt::none
;
385 return in(t
, float_set
) ? pt::exp
: pt::none
;
390 return in(t
, float_set
) ? pt::fixed
: pt::none
;
395 return in(t
, float_set
) ? pt::general
: pt::none
;
400 return in(t
, float_set
) ? pt::hexfloat
: pt::none
;
402 return in(t
, integral_set
) ? pt::chr
: pt::none
;
404 return in(t
, string_set
| cstring_set
) ? pt::string
: pt::none
;
406 return in(t
, pointer_set
| cstring_set
) ? pt::pointer
: pt::none
;
412 template <typename Char
, typename Context
>
413 void vprintf(buffer
<Char
>& buf
, basic_string_view
<Char
> format
,
414 basic_format_args
<Context
> args
) {
415 using iterator
= basic_appender
<Char
>;
416 auto out
= iterator(buf
);
417 auto context
= basic_printf_context
<Char
>(out
, args
);
418 auto parse_ctx
= basic_format_parse_context
<Char
>(format
);
420 // Returns the argument with specified index or, if arg_index is -1, the next
422 auto get_arg
= [&](int arg_index
) {
424 arg_index
= parse_ctx
.next_arg_id();
426 parse_ctx
.check_arg_id(--arg_index
);
427 return detail::get_arg(context
, arg_index
);
430 const Char
* start
= parse_ctx
.begin();
431 const Char
* end
= parse_ctx
.end();
434 if (!find
<false, Char
>(it
, end
, '%', it
)) {
435 it
= end
; // find leaves it == nullptr if it doesn't find '%'.
439 if (it
!= end
&& *it
== c
) {
440 write(out
, basic_string_view
<Char
>(start
, to_unsigned(it
- start
)));
444 write(out
, basic_string_view
<Char
>(start
, to_unsigned(it
- 1 - start
)));
446 auto specs
= format_specs();
447 specs
.align
= align::right
;
449 // Parse argument index, flags and width.
450 int arg_index
= parse_header(it
, end
, specs
, get_arg
);
451 if (arg_index
== 0) report_error("argument not found");
454 if (it
!= end
&& *it
== '.') {
456 c
= it
!= end
? *it
: 0;
457 if ('0' <= c
&& c
<= '9') {
458 specs
.precision
= parse_nonnegative_int(it
, end
, 0);
459 } else if (c
== '*') {
462 static_cast<int>(get_arg(-1).visit(printf_precision_handler()));
468 auto arg
= get_arg(arg_index
);
469 // For d, i, o, u, x, and X conversion specifiers, if a precision is
470 // specified, the '0' flag is ignored
471 if (specs
.precision
>= 0 && arg
.is_integral()) {
472 // Ignore '0' for non-numeric types or if '-' present.
475 if (specs
.precision
>= 0 && arg
.type() == type::cstring_type
) {
476 auto str
= arg
.visit(get_cstring
<Char
>());
477 auto str_end
= str
+ specs
.precision
;
478 auto nul
= std::find(str
, str_end
, Char());
479 auto sv
= basic_string_view
<Char
>(
480 str
, to_unsigned(nul
!= str_end
? nul
- str
: specs
.precision
));
481 arg
= make_arg
<basic_printf_context
<Char
>>(sv
);
483 if (specs
.alt
&& arg
.visit(is_zero_int())) specs
.alt
= false;
484 if (specs
.fill
.template get
<Char
>() == '0') {
485 if (arg
.is_arithmetic() && specs
.align
!= align::left
)
486 specs
.align
= align::numeric
;
488 specs
.fill
= ' '; // Ignore '0' flag for non-numeric types or if '-'
489 // flag is also present.
492 // Parse length and convert the argument to the required type.
493 c
= it
!= end
? *it
++ : 0;
494 Char t
= it
!= end
? *it
: 0;
499 t
= it
!= end
? *it
: 0;
500 convert_arg
<signed char>(arg
, t
);
502 convert_arg
<short>(arg
, t
);
508 t
= it
!= end
? *it
: 0;
509 convert_arg
<long long>(arg
, t
);
511 convert_arg
<long>(arg
, t
);
515 convert_arg
<intmax_t>(arg
, t
);
518 convert_arg
<size_t>(arg
, t
);
521 convert_arg
<std::ptrdiff_t>(arg
, t
);
524 // printf produces garbage when 'L' is omitted for long double, no
525 // need to do the same.
529 convert_arg
<void>(arg
, c
);
533 if (it
== end
) report_error("invalid format string");
534 char type
= static_cast<char>(*it
++);
535 if (arg
.is_integral()) {
543 arg
.visit(char_converter
<basic_printf_context
<Char
>>(arg
));
548 specs
.type
= parse_printf_presentation_type(type
, arg
.type(), upper
);
549 if (specs
.type
== presentation_type::none
)
550 report_error("invalid format specifier");
556 arg
.visit(printf_arg_formatter
<Char
>(out
, specs
, context
));
558 write(out
, basic_string_view
<Char
>(start
, to_unsigned(it
- start
)));
560 } // namespace detail
562 using printf_context
= basic_printf_context
<char>;
563 using wprintf_context
= basic_printf_context
<wchar_t>;
565 using printf_args
= basic_format_args
<printf_context
>;
566 using wprintf_args
= basic_format_args
<wprintf_context
>;
568 /// Constructs an `format_arg_store` object that contains references to
569 /// arguments and can be implicitly converted to `printf_args`.
570 template <typename Char
= char, typename
... T
>
571 inline auto make_printf_args(T
&... args
)
572 -> decltype(fmt::make_format_args
<basic_printf_context
<Char
>>(args
...)) {
573 return fmt::make_format_args
<basic_printf_context
<Char
>>(args
...);
576 template <typename Char
> struct vprintf_args
{
577 using type
= basic_format_args
<basic_printf_context
<Char
>>;
580 template <typename Char
>
581 inline auto vsprintf(basic_string_view
<Char
> fmt
,
582 typename vprintf_args
<Char
>::type args
)
583 -> std::basic_string
<Char
> {
584 auto buf
= basic_memory_buffer
<Char
>();
585 detail::vprintf(buf
, fmt
, args
);
586 return to_string(buf
);
590 * Formats `args` according to specifications in `fmt` and returns the result
595 * std::string message = fmt::sprintf("The answer is %d", 42);
597 template <typename S
, typename
... T
, typename Char
= char_t
<S
>>
598 inline auto sprintf(const S
& fmt
, const T
&... args
) -> std::basic_string
<Char
> {
599 return vsprintf(detail::to_string_view(fmt
),
600 fmt::make_format_args
<basic_printf_context
<Char
>>(args
...));
603 template <typename Char
>
604 inline auto vfprintf(std::FILE* f
, basic_string_view
<Char
> fmt
,
605 typename vprintf_args
<Char
>::type args
) -> int {
606 auto buf
= basic_memory_buffer
<Char
>();
607 detail::vprintf(buf
, fmt
, args
);
608 size_t size
= buf
.size();
609 return std::fwrite(buf
.data(), sizeof(Char
), size
, f
) < size
611 : static_cast<int>(size
);
615 * Formats `args` according to specifications in `fmt` and writes the output
620 * fmt::fprintf(stderr, "Don't %s!", "panic");
622 template <typename S
, typename
... T
, typename Char
= char_t
<S
>>
623 inline auto fprintf(std::FILE* f
, const S
& fmt
, const T
&... args
) -> int {
624 return vfprintf(f
, detail::to_string_view(fmt
),
625 make_printf_args
<Char
>(args
...));
628 template <typename Char
>
629 FMT_DEPRECATED
inline auto vprintf(basic_string_view
<Char
> fmt
,
630 typename vprintf_args
<Char
>::type args
)
632 return vfprintf(stdout
, fmt
, args
);
636 * Formats `args` according to specifications in `fmt` and writes the output
641 * fmt::printf("Elapsed time: %.2f seconds", 1.23);
643 template <typename
... T
>
644 inline auto printf(string_view fmt
, const T
&... args
) -> int {
645 return vfprintf(stdout
, fmt
, make_printf_args(args
...));
647 template <typename
... T
>
648 FMT_DEPRECATED
inline auto printf(basic_string_view
<wchar_t> fmt
,
649 const T
&... args
) -> int {
650 return vfprintf(stdout
, fmt
, make_printf_args
<wchar_t>(args
...));
656 #endif // FMT_PRINTF_H_