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.
11 #include <algorithm> // std::max
12 #include <limits> // std::numeric_limits
19 template <typename T
> struct printf_formatter
{ printf_formatter() = delete; };
21 template <typename Char
> class basic_printf_context
{
23 detail::buffer_appender
<Char
> out_
;
24 basic_format_args
<basic_printf_context
> args_
;
27 using char_type
= Char
;
28 using parse_context_type
= basic_format_parse_context
<Char
>;
29 template <typename T
> using formatter_type
= printf_formatter
<T
>;
33 Constructs a ``printf_context`` object. References to the arguments are
34 stored in the context object so make sure they have appropriate lifetimes.
37 basic_printf_context(detail::buffer_appender
<Char
> out
,
38 basic_format_args
<basic_printf_context
> args
)
39 : out_(out
), args_(args
) {}
41 auto out() -> detail::buffer_appender
<Char
> { return out_
; }
42 void advance_to(detail::buffer_appender
<Char
>) {}
44 auto locale() -> detail::locale_ref
{ return {}; }
46 auto arg(int id
) const -> basic_format_arg
<basic_printf_context
> {
50 FMT_CONSTEXPR
void on_error(const char* message
) {
51 detail::error_handler().on_error(message
);
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
= 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 throw_format_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 throw_format_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> { using type
= bool; };
107 template <typename T
, typename Context
> class arg_converter
{
109 using char_type
= typename
Context::char_type
;
111 basic_format_arg
<Context
>& arg_
;
115 arg_converter(basic_format_arg
<Context
>& arg
, char_type type
)
116 : arg_(arg
), type_(type
) {}
118 void operator()(bool value
) {
119 if (type_
!= 's') operator()<bool>(value
);
122 template <typename U
, FMT_ENABLE_IF(std::is_integral
<U
>::value
)>
123 void operator()(U value
) {
124 bool is_signed
= type_
== 'd' || type_
== 'i';
125 using target_type
= conditional_t
<std::is_same
<T
, void>::value
, U
, T
>;
126 if (const_check(sizeof(target_type
) <= sizeof(int))) {
127 // Extra casts are used to silence warnings.
129 auto n
= static_cast<int>(static_cast<target_type
>(value
));
130 arg_
= detail::make_arg
<Context
>(n
);
132 using unsigned_type
= typename make_unsigned_or_bool
<target_type
>::type
;
133 auto n
= static_cast<unsigned>(static_cast<unsigned_type
>(value
));
134 arg_
= detail::make_arg
<Context
>(n
);
138 // glibc's printf doesn't sign extend arguments of smaller types:
139 // std::printf("%lld", -42); // prints "4294967254"
140 // but we don't have to do the same because it's a UB.
141 auto n
= static_cast<long long>(value
);
142 arg_
= detail::make_arg
<Context
>(n
);
144 auto n
= static_cast<typename make_unsigned_or_bool
<U
>::type
>(value
);
145 arg_
= detail::make_arg
<Context
>(n
);
150 template <typename U
, FMT_ENABLE_IF(!std::is_integral
<U
>::value
)>
151 void operator()(U
) {} // No conversion needed for non-integral types.
154 // Converts an integer argument to T for printf, if T is an integral type.
155 // If T is void, the argument is converted to corresponding signed or unsigned
156 // type depending on the type specifier: 'd' and 'i' - signed, other -
158 template <typename T
, typename Context
, typename Char
>
159 void convert_arg(basic_format_arg
<Context
>& arg
, Char type
) {
160 visit_format_arg(arg_converter
<T
, Context
>(arg
, type
), arg
);
163 // Converts an integer argument to char for printf.
164 template <typename Context
> class char_converter
{
166 basic_format_arg
<Context
>& arg_
;
169 explicit char_converter(basic_format_arg
<Context
>& arg
) : arg_(arg
) {}
171 template <typename T
, FMT_ENABLE_IF(std::is_integral
<T
>::value
)>
172 void operator()(T value
) {
173 auto c
= static_cast<typename
Context::char_type
>(value
);
174 arg_
= detail::make_arg
<Context
>(c
);
177 template <typename T
, FMT_ENABLE_IF(!std::is_integral
<T
>::value
)>
178 void operator()(T
) {} // No conversion needed for non-integral types.
181 // An argument visitor that return a pointer to a C string if argument is a
182 // string or null otherwise.
183 template <typename Char
> struct get_cstring
{
184 template <typename T
> auto operator()(T
) -> const Char
* { return nullptr; }
185 auto operator()(const Char
* s
) -> const Char
* { return s
; }
188 // Checks if an argument is a valid printf width specifier and sets
189 // left alignment if it is negative.
190 template <typename Char
> class printf_width_handler
{
192 format_specs
<Char
>& specs_
;
195 explicit printf_width_handler(format_specs
<Char
>& specs
) : specs_(specs
) {}
197 template <typename T
, FMT_ENABLE_IF(std::is_integral
<T
>::value
)>
198 auto operator()(T value
) -> unsigned {
199 auto width
= static_cast<uint32_or_64_or_128_t
<T
>>(value
);
200 if (detail::is_negative(value
)) {
201 specs_
.align
= align::left
;
204 unsigned int_max
= max_value
<int>();
205 if (width
> int_max
) throw_format_error("number is too big");
206 return static_cast<unsigned>(width
);
209 template <typename T
, FMT_ENABLE_IF(!std::is_integral
<T
>::value
)>
210 auto operator()(T
) -> unsigned {
211 throw_format_error("width is not integer");
216 // Workaround for a bug with the XL compiler when initializing
217 // printf_arg_formatter's base class.
218 template <typename Char
>
219 auto make_arg_formatter(buffer_appender
<Char
> iter
, format_specs
<Char
>& s
)
220 -> arg_formatter
<Char
> {
221 return {iter
, s
, locale_ref()};
224 // The ``printf`` argument formatter.
225 template <typename Char
>
226 class printf_arg_formatter
: public arg_formatter
<Char
> {
228 using base
= arg_formatter
<Char
>;
229 using context_type
= basic_printf_context
<Char
>;
231 context_type
& context_
;
233 void write_null_pointer(bool is_string
= false) {
234 auto s
= this->specs
;
235 s
.type
= presentation_type::none
;
236 write_bytes(this->out
, is_string
? "(null)" : "(nil)", s
);
240 printf_arg_formatter(buffer_appender
<Char
> iter
, format_specs
<Char
>& s
,
242 : base(make_arg_formatter(iter
, s
)), context_(ctx
) {}
244 void operator()(monostate value
) { base::operator()(value
); }
246 template <typename T
, FMT_ENABLE_IF(detail::is_integral
<T
>::value
)>
247 void operator()(T value
) {
248 // MSVC2013 fails to compile separate overloads for bool and Char so use
249 // std::is_same instead.
250 if (!std::is_same
<T
, Char
>::value
) {
251 base::operator()(value
);
254 format_specs
<Char
> fmt_specs
= this->specs
;
255 if (fmt_specs
.type
!= presentation_type::none
&&
256 fmt_specs
.type
!= presentation_type::chr
) {
257 return (*this)(static_cast<int>(value
));
259 fmt_specs
.sign
= sign::none
;
260 fmt_specs
.alt
= false;
261 fmt_specs
.fill
[0] = ' '; // Ignore '0' flag for char types.
262 // align::numeric needs to be overwritten here since the '0' flag is
263 // ignored for non-numeric types
264 if (fmt_specs
.align
== align::none
|| fmt_specs
.align
== align::numeric
)
265 fmt_specs
.align
= align::right
;
266 write
<Char
>(this->out
, static_cast<Char
>(value
), fmt_specs
);
269 template <typename T
, FMT_ENABLE_IF(std::is_floating_point
<T
>::value
)>
270 void operator()(T value
) {
271 base::operator()(value
);
274 /** Formats a null-terminated C string. */
275 void operator()(const char* value
) {
277 base::operator()(value
);
279 write_null_pointer(this->specs
.type
!= presentation_type::pointer
);
282 /** Formats a null-terminated wide C string. */
283 void operator()(const wchar_t* value
) {
285 base::operator()(value
);
287 write_null_pointer(this->specs
.type
!= presentation_type::pointer
);
290 void operator()(basic_string_view
<Char
> value
) { base::operator()(value
); }
292 /** Formats a pointer. */
293 void operator()(const void* value
) {
295 base::operator()(value
);
297 write_null_pointer();
300 /** Formats an argument of a custom (user-defined) type. */
301 void operator()(typename basic_format_arg
<context_type
>::handle handle
) {
302 auto parse_ctx
= basic_format_parse_context
<Char
>({});
303 handle
.format(parse_ctx
, context_
);
307 template <typename Char
>
308 void parse_flags(format_specs
<Char
>& specs
, const Char
*& it
, const Char
* end
) {
309 for (; it
!= end
; ++it
) {
312 specs
.align
= align::left
;
315 specs
.sign
= sign::plus
;
321 if (specs
.sign
!= sign::plus
) specs
.sign
= sign::space
;
332 template <typename Char
, typename GetArg
>
333 auto parse_header(const Char
*& it
, const Char
* end
, format_specs
<Char
>& specs
,
334 GetArg get_arg
) -> int {
337 if (c
>= '0' && c
<= '9') {
338 // Parse an argument index (if followed by '$') or a width possibly
339 // preceded with '0' flag(s).
340 int value
= parse_nonnegative_int(it
, end
, -1);
341 if (it
!= end
&& *it
== '$') { // value is an argument index
343 arg_index
= value
!= -1 ? value
: max_value
<int>();
345 if (c
== '0') specs
.fill
[0] = '0';
347 // Nonzero value means that we parsed width and don't need to
348 // parse it or flags again, so return now.
349 if (value
== -1) throw_format_error("number is too big");
355 parse_flags(specs
, it
, end
);
358 if (*it
>= '0' && *it
<= '9') {
359 specs
.width
= parse_nonnegative_int(it
, end
, -1);
360 if (specs
.width
== -1) throw_format_error("number is too big");
361 } else if (*it
== '*') {
363 specs
.width
= static_cast<int>(visit_format_arg(
364 detail::printf_width_handler
<Char
>(specs
), get_arg(-1)));
370 inline auto parse_printf_presentation_type(char c
, type t
)
371 -> presentation_type
{
372 using pt
= presentation_type
;
373 constexpr auto integral_set
= sint_set
| uint_set
| bool_set
| char_set
;
376 return in(t
, integral_set
) ? pt::dec
: pt::none
;
378 return in(t
, integral_set
) ? pt::oct
: pt::none
;
380 return in(t
, integral_set
) ? pt::hex_lower
: pt::none
;
382 return in(t
, integral_set
) ? pt::hex_upper
: pt::none
;
384 return in(t
, float_set
) ? pt::hexfloat_lower
: pt::none
;
386 return in(t
, float_set
) ? pt::hexfloat_upper
: pt::none
;
388 return in(t
, float_set
) ? pt::exp_lower
: pt::none
;
390 return in(t
, float_set
) ? pt::exp_upper
: pt::none
;
392 return in(t
, float_set
) ? pt::fixed_lower
: pt::none
;
394 return in(t
, float_set
) ? pt::fixed_upper
: pt::none
;
396 return in(t
, float_set
) ? pt::general_lower
: pt::none
;
398 return in(t
, float_set
) ? pt::general_upper
: pt::none
;
400 return in(t
, integral_set
) ? pt::chr
: pt::none
;
402 return in(t
, string_set
| cstring_set
) ? pt::string
: pt::none
;
404 return in(t
, pointer_set
| cstring_set
) ? pt::pointer
: pt::none
;
410 template <typename Char
, typename Context
>
411 void vprintf(buffer
<Char
>& buf
, basic_string_view
<Char
> format
,
412 basic_format_args
<Context
> args
) {
413 using iterator
= buffer_appender
<Char
>;
414 auto out
= iterator(buf
);
415 auto context
= basic_printf_context
<Char
>(out
, args
);
416 auto parse_ctx
= basic_format_parse_context
<Char
>(format
);
418 // Returns the argument with specified index or, if arg_index is -1, the next
420 auto get_arg
= [&](int arg_index
) {
422 arg_index
= parse_ctx
.next_arg_id();
424 parse_ctx
.check_arg_id(--arg_index
);
425 return detail::get_arg(context
, arg_index
);
428 const Char
* start
= parse_ctx
.begin();
429 const Char
* end
= parse_ctx
.end();
432 if (!find
<false, Char
>(it
, end
, '%', it
)) {
433 it
= end
; // find leaves it == nullptr if it doesn't find '%'.
437 if (it
!= end
&& *it
== c
) {
438 write(out
, basic_string_view
<Char
>(start
, to_unsigned(it
- start
)));
442 write(out
, basic_string_view
<Char
>(start
, to_unsigned(it
- 1 - start
)));
444 auto specs
= format_specs
<Char
>();
445 specs
.align
= align::right
;
447 // Parse argument index, flags and width.
448 int arg_index
= parse_header(it
, end
, specs
, get_arg
);
449 if (arg_index
== 0) throw_format_error("argument not found");
452 if (it
!= end
&& *it
== '.') {
454 c
= it
!= end
? *it
: 0;
455 if ('0' <= c
&& c
<= '9') {
456 specs
.precision
= parse_nonnegative_int(it
, end
, 0);
457 } else if (c
== '*') {
459 specs
.precision
= static_cast<int>(
460 visit_format_arg(printf_precision_handler(), get_arg(-1)));
466 auto arg
= get_arg(arg_index
);
467 // For d, i, o, u, x, and X conversion specifiers, if a precision is
468 // specified, the '0' flag is ignored
469 if (specs
.precision
>= 0 && arg
.is_integral()) {
470 // Ignore '0' for non-numeric types or if '-' present.
473 if (specs
.precision
>= 0 && arg
.type() == type::cstring_type
) {
474 auto str
= visit_format_arg(get_cstring
<Char
>(), arg
);
475 auto str_end
= str
+ specs
.precision
;
476 auto nul
= std::find(str
, str_end
, Char());
477 auto sv
= basic_string_view
<Char
>(
478 str
, to_unsigned(nul
!= str_end
? nul
- str
: specs
.precision
));
479 arg
= make_arg
<basic_printf_context
<Char
>>(sv
);
481 if (specs
.alt
&& visit_format_arg(is_zero_int(), arg
)) specs
.alt
= false;
482 if (specs
.fill
[0] == '0') {
483 if (arg
.is_arithmetic() && specs
.align
!= align::left
)
484 specs
.align
= align::numeric
;
486 specs
.fill
[0] = ' '; // Ignore '0' flag for non-numeric types or if '-'
487 // flag is also present.
490 // Parse length and convert the argument to the required type.
491 c
= it
!= end
? *it
++ : 0;
492 Char t
= it
!= end
? *it
: 0;
497 t
= it
!= end
? *it
: 0;
498 convert_arg
<signed char>(arg
, t
);
500 convert_arg
<short>(arg
, t
);
506 t
= it
!= end
? *it
: 0;
507 convert_arg
<long long>(arg
, t
);
509 convert_arg
<long>(arg
, t
);
513 convert_arg
<intmax_t>(arg
, t
);
516 convert_arg
<size_t>(arg
, t
);
519 convert_arg
<std::ptrdiff_t>(arg
, t
);
522 // printf produces garbage when 'L' is omitted for long double, no
523 // need to do the same.
527 convert_arg
<void>(arg
, c
);
531 if (it
== end
) throw_format_error("invalid format string");
532 char type
= static_cast<char>(*it
++);
533 if (arg
.is_integral()) {
541 visit_format_arg(char_converter
<basic_printf_context
<Char
>>(arg
), arg
);
545 specs
.type
= parse_printf_presentation_type(type
, arg
.type());
546 if (specs
.type
== presentation_type::none
)
547 throw_format_error("invalid format specifier");
552 visit_format_arg(printf_arg_formatter
<Char
>(out
, specs
, context
), arg
);
554 write(out
, basic_string_view
<Char
>(start
, to_unsigned(it
- start
)));
556 } // namespace detail
558 using printf_context
= basic_printf_context
<char>;
559 using wprintf_context
= basic_printf_context
<wchar_t>;
561 using printf_args
= basic_format_args
<printf_context
>;
562 using wprintf_args
= basic_format_args
<wprintf_context
>;
566 Constructs an `~fmt::format_arg_store` object that contains references to
567 arguments and can be implicitly converted to `~fmt::printf_args`.
570 template <typename
... T
>
571 inline auto make_printf_args(const T
&... args
)
572 -> format_arg_store
<printf_context
, T
...> {
577 template <typename
... T
>
578 inline auto make_wprintf_args(const T
&... args
)
579 -> format_arg_store
<wprintf_context
, T
...> {
583 template <typename Char
>
584 inline auto vsprintf(
585 basic_string_view
<Char
> fmt
,
586 basic_format_args
<basic_printf_context
<type_identity_t
<Char
>>> args
)
587 -> std::basic_string
<Char
> {
588 auto buf
= basic_memory_buffer
<Char
>();
589 detail::vprintf(buf
, fmt
, args
);
590 return to_string(buf
);
595 Formats arguments and returns the result as a string.
599 std::string message = fmt::sprintf("The answer is %d", 42);
602 template <typename S
, typename
... T
,
603 typename Char
= enable_if_t
<detail::is_string
<S
>::value
, char_t
<S
>>>
604 inline auto sprintf(const S
& fmt
, const T
&... args
) -> std::basic_string
<Char
> {
605 return vsprintf(detail::to_string_view(fmt
),
606 fmt::make_format_args
<basic_printf_context
<Char
>>(args
...));
609 template <typename Char
>
610 inline auto vfprintf(
611 std::FILE* f
, basic_string_view
<Char
> fmt
,
612 basic_format_args
<basic_printf_context
<type_identity_t
<Char
>>> args
)
614 auto buf
= basic_memory_buffer
<Char
>();
615 detail::vprintf(buf
, fmt
, args
);
616 size_t size
= buf
.size();
617 return std::fwrite(buf
.data(), sizeof(Char
), size
, f
) < size
619 : static_cast<int>(size
);
624 Prints formatted data to the file *f*.
628 fmt::fprintf(stderr, "Don't %s!", "panic");
631 template <typename S
, typename
... T
, typename Char
= char_t
<S
>>
632 inline auto fprintf(std::FILE* f
, const S
& fmt
, const T
&... args
) -> int {
633 return vfprintf(f
, detail::to_string_view(fmt
),
634 fmt::make_format_args
<basic_printf_context
<Char
>>(args
...));
637 template <typename Char
>
638 FMT_DEPRECATED
inline auto vprintf(
639 basic_string_view
<Char
> fmt
,
640 basic_format_args
<basic_printf_context
<type_identity_t
<Char
>>> args
)
642 return vfprintf(stdout
, fmt
, args
);
647 Prints formatted data to ``stdout``.
651 fmt::printf("Elapsed time: %.2f seconds", 1.23);
654 template <typename
... T
>
655 inline auto printf(string_view fmt
, const T
&... args
) -> int {
656 return vfprintf(stdout
, fmt
, make_printf_args(args
...));
658 template <typename
... T
>
659 FMT_DEPRECATED
inline auto printf(basic_string_view
<wchar_t> fmt
,
660 const T
&... args
) -> int {
661 return vfprintf(stdout
, fmt
, make_wprintf_args(args
...));
667 #endif // FMT_PRINTF_H_