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
18 FMT_MODULE_EXPORT_BEGIN
20 template <typename T
> struct printf_formatter
{ printf_formatter() = delete; };
22 template <typename Char
>
23 class basic_printf_parse_context
: public basic_format_parse_context
<Char
> {
24 using basic_format_parse_context
<Char
>::basic_format_parse_context
;
27 template <typename OutputIt
, typename Char
> class basic_printf_context
{
30 basic_format_args
<basic_printf_context
> args_
;
33 using char_type
= Char
;
34 using format_arg
= basic_format_arg
<basic_printf_context
>;
35 using parse_context_type
= basic_printf_parse_context
<Char
>;
36 template <typename T
> using formatter_type
= printf_formatter
<T
>;
40 Constructs a ``printf_context`` object. References to the arguments are
41 stored in the context object so make sure they have appropriate lifetimes.
44 basic_printf_context(OutputIt out
,
45 basic_format_args
<basic_printf_context
> args
)
46 : out_(out
), args_(args
) {}
48 OutputIt
out() { return out_
; }
49 void advance_to(OutputIt it
) { out_
= it
; }
51 detail::locale_ref
locale() { return {}; }
53 format_arg
arg(int id
) const { return args_
.get(id
); }
55 FMT_CONSTEXPR
void on_error(const char* message
) {
56 detail::error_handler().on_error(message
);
60 FMT_BEGIN_DETAIL_NAMESPACE
62 // Checks if a value fits in int - used to avoid warnings about comparing
63 // signed and unsigned integers.
64 template <bool IsSigned
> struct int_checker
{
65 template <typename T
> static bool fits_in_int(T value
) {
66 unsigned max
= max_value
<int>();
69 static bool fits_in_int(bool) { return true; }
72 template <> struct int_checker
<true> {
73 template <typename T
> static bool fits_in_int(T value
) {
74 return value
>= (std::numeric_limits
<int>::min
)() &&
75 value
<= max_value
<int>();
77 static bool fits_in_int(int) { return true; }
80 class printf_precision_handler
{
82 template <typename T
, FMT_ENABLE_IF(std::is_integral
<T
>::value
)>
83 int operator()(T value
) {
84 if (!int_checker
<std::numeric_limits
<T
>::is_signed
>::fits_in_int(value
))
85 FMT_THROW(format_error("number is too big"));
86 return (std::max
)(static_cast<int>(value
), 0);
89 template <typename T
, FMT_ENABLE_IF(!std::is_integral
<T
>::value
)>
91 FMT_THROW(format_error("precision is not integer"));
96 // An argument visitor that returns true iff arg is a zero integer.
99 template <typename T
, FMT_ENABLE_IF(std::is_integral
<T
>::value
)>
100 bool operator()(T value
) {
104 template <typename T
, FMT_ENABLE_IF(!std::is_integral
<T
>::value
)>
110 template <typename T
> struct make_unsigned_or_bool
: std::make_unsigned
<T
> {};
112 template <> struct make_unsigned_or_bool
<bool> { using type
= bool; };
114 template <typename T
, typename Context
> class arg_converter
{
116 using char_type
= typename
Context::char_type
;
118 basic_format_arg
<Context
>& arg_
;
122 arg_converter(basic_format_arg
<Context
>& arg
, char_type type
)
123 : arg_(arg
), type_(type
) {}
125 void operator()(bool value
) {
126 if (type_
!= 's') operator()<bool>(value
);
129 template <typename U
, FMT_ENABLE_IF(std::is_integral
<U
>::value
)>
130 void operator()(U value
) {
131 bool is_signed
= type_
== 'd' || type_
== 'i';
132 using target_type
= conditional_t
<std::is_same
<T
, void>::value
, U
, T
>;
133 if (const_check(sizeof(target_type
) <= sizeof(int))) {
134 // Extra casts are used to silence warnings.
136 arg_
= detail::make_arg
<Context
>(
137 static_cast<int>(static_cast<target_type
>(value
)));
139 using unsigned_type
= typename make_unsigned_or_bool
<target_type
>::type
;
140 arg_
= detail::make_arg
<Context
>(
141 static_cast<unsigned>(static_cast<unsigned_type
>(value
)));
145 // glibc's printf doesn't sign extend arguments of smaller types:
146 // std::printf("%lld", -42); // prints "4294967254"
147 // but we don't have to do the same because it's a UB.
148 arg_
= detail::make_arg
<Context
>(static_cast<long long>(value
));
150 arg_
= detail::make_arg
<Context
>(
151 static_cast<typename make_unsigned_or_bool
<U
>::type
>(value
));
156 template <typename U
, FMT_ENABLE_IF(!std::is_integral
<U
>::value
)>
157 void operator()(U
) {} // No conversion needed for non-integral types.
160 // Converts an integer argument to T for printf, if T is an integral type.
161 // If T is void, the argument is converted to corresponding signed or unsigned
162 // type depending on the type specifier: 'd' and 'i' - signed, other -
164 template <typename T
, typename Context
, typename Char
>
165 void convert_arg(basic_format_arg
<Context
>& arg
, Char type
) {
166 visit_format_arg(arg_converter
<T
, Context
>(arg
, type
), arg
);
169 // Converts an integer argument to char for printf.
170 template <typename Context
> class char_converter
{
172 basic_format_arg
<Context
>& arg_
;
175 explicit char_converter(basic_format_arg
<Context
>& arg
) : arg_(arg
) {}
177 template <typename T
, FMT_ENABLE_IF(std::is_integral
<T
>::value
)>
178 void operator()(T value
) {
179 arg_
= detail::make_arg
<Context
>(
180 static_cast<typename
Context::char_type
>(value
));
183 template <typename T
, FMT_ENABLE_IF(!std::is_integral
<T
>::value
)>
184 void operator()(T
) {} // No conversion needed for non-integral types.
187 // An argument visitor that return a pointer to a C string if argument is a
188 // string or null otherwise.
189 template <typename Char
> struct get_cstring
{
190 template <typename T
> const Char
* operator()(T
) { return nullptr; }
191 const Char
* operator()(const Char
* s
) { return s
; }
194 // Checks if an argument is a valid printf width specifier and sets
195 // left alignment if it is negative.
196 template <typename Char
> class printf_width_handler
{
198 using format_specs
= basic_format_specs
<Char
>;
200 format_specs
& specs_
;
203 explicit printf_width_handler(format_specs
& specs
) : specs_(specs
) {}
205 template <typename T
, FMT_ENABLE_IF(std::is_integral
<T
>::value
)>
206 unsigned operator()(T value
) {
207 auto width
= static_cast<uint32_or_64_or_128_t
<T
>>(value
);
208 if (detail::is_negative(value
)) {
209 specs_
.align
= align::left
;
212 unsigned int_max
= max_value
<int>();
213 if (width
> int_max
) FMT_THROW(format_error("number is too big"));
214 return static_cast<unsigned>(width
);
217 template <typename T
, FMT_ENABLE_IF(!std::is_integral
<T
>::value
)>
218 unsigned operator()(T
) {
219 FMT_THROW(format_error("width is not integer"));
224 // The ``printf`` argument formatter.
225 template <typename OutputIt
, typename Char
>
226 class printf_arg_formatter
: public arg_formatter
<Char
> {
228 using base
= arg_formatter
<Char
>;
229 using context_type
= basic_printf_context
<OutputIt
, Char
>;
230 using format_specs
= basic_format_specs
<Char
>;
232 context_type
& context_
;
234 OutputIt
write_null_pointer(bool is_string
= false) {
235 auto s
= this->specs
;
236 s
.type
= presentation_type::none
;
237 return write_bytes(this->out
, is_string
? "(null)" : "(nil)", s
);
241 printf_arg_formatter(OutputIt iter
, format_specs
& s
, context_type
& ctx
)
242 : base
{iter
, s
, locale_ref()}, context_(ctx
) {}
244 OutputIt
operator()(monostate value
) { return base::operator()(value
); }
246 template <typename T
, FMT_ENABLE_IF(detail::is_integral
<T
>::value
)>
247 OutputIt
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 format_specs fmt_specs
= this->specs
;
252 if (fmt_specs
.type
!= presentation_type::none
&&
253 fmt_specs
.type
!= presentation_type::chr
) {
254 return (*this)(static_cast<int>(value
));
256 fmt_specs
.sign
= sign::none
;
257 fmt_specs
.alt
= false;
258 fmt_specs
.fill
[0] = ' '; // Ignore '0' flag for char types.
259 // align::numeric needs to be overwritten here since the '0' flag is
260 // ignored for non-numeric types
261 if (fmt_specs
.align
== align::none
|| fmt_specs
.align
== align::numeric
)
262 fmt_specs
.align
= align::right
;
263 return write
<Char
>(this->out
, static_cast<Char
>(value
), fmt_specs
);
265 return base::operator()(value
);
268 template <typename T
, FMT_ENABLE_IF(std::is_floating_point
<T
>::value
)>
269 OutputIt
operator()(T value
) {
270 return base::operator()(value
);
273 /** Formats a null-terminated C string. */
274 OutputIt
operator()(const char* value
) {
275 if (value
) return base::operator()(value
);
276 return write_null_pointer(this->specs
.type
!= presentation_type::pointer
);
279 /** Formats a null-terminated wide C string. */
280 OutputIt
operator()(const wchar_t* value
) {
281 if (value
) return base::operator()(value
);
282 return write_null_pointer(this->specs
.type
!= presentation_type::pointer
);
285 OutputIt
operator()(basic_string_view
<Char
> value
) {
286 return base::operator()(value
);
289 /** Formats a pointer. */
290 OutputIt
operator()(const void* value
) {
291 return value
? base::operator()(value
) : write_null_pointer();
294 /** Formats an argument of a custom (user-defined) type. */
295 OutputIt
operator()(typename basic_format_arg
<context_type
>::handle handle
) {
297 basic_printf_parse_context
<Char
>(basic_string_view
<Char
>());
298 handle
.format(parse_ctx
, context_
);
303 template <typename Char
>
304 void parse_flags(basic_format_specs
<Char
>& specs
, const Char
*& it
,
306 for (; it
!= end
; ++it
) {
309 specs
.align
= align::left
;
312 specs
.sign
= sign::plus
;
318 if (specs
.sign
!= sign::plus
) {
319 specs
.sign
= sign::space
;
331 template <typename Char
, typename GetArg
>
332 int parse_header(const Char
*& it
, const Char
* end
,
333 basic_format_specs
<Char
>& specs
, GetArg get_arg
) {
336 if (c
>= '0' && c
<= '9') {
337 // Parse an argument index (if followed by '$') or a width possibly
338 // preceded with '0' flag(s).
339 int value
= parse_nonnegative_int(it
, end
, -1);
340 if (it
!= end
&& *it
== '$') { // value is an argument index
342 arg_index
= value
!= -1 ? value
: max_value
<int>();
344 if (c
== '0') specs
.fill
[0] = '0';
346 // Nonzero value means that we parsed width and don't need to
347 // parse it or flags again, so return now.
348 if (value
== -1) FMT_THROW(format_error("number is too big"));
354 parse_flags(specs
, it
, end
);
357 if (*it
>= '0' && *it
<= '9') {
358 specs
.width
= parse_nonnegative_int(it
, end
, -1);
359 if (specs
.width
== -1) FMT_THROW(format_error("number is too big"));
360 } else if (*it
== '*') {
362 specs
.width
= static_cast<int>(visit_format_arg(
363 detail::printf_width_handler
<Char
>(specs
), get_arg(-1)));
369 template <typename Char
, typename Context
>
370 void vprintf(buffer
<Char
>& buf
, basic_string_view
<Char
> format
,
371 basic_format_args
<Context
> args
) {
372 using OutputIt
= buffer_appender
<Char
>;
373 auto out
= OutputIt(buf
);
374 auto context
= basic_printf_context
<OutputIt
, Char
>(out
, args
);
375 auto parse_ctx
= basic_printf_parse_context
<Char
>(format
);
377 // Returns the argument with specified index or, if arg_index is -1, the next
379 auto get_arg
= [&](int arg_index
) {
381 arg_index
= parse_ctx
.next_arg_id();
383 parse_ctx
.check_arg_id(--arg_index
);
384 return detail::get_arg(context
, arg_index
);
387 const Char
* start
= parse_ctx
.begin();
388 const Char
* end
= parse_ctx
.end();
391 if (!detail::find
<false, Char
>(it
, end
, '%', it
)) {
392 it
= end
; // detail::find leaves it == nullptr if it doesn't find '%'
396 if (it
!= end
&& *it
== c
) {
398 out
, basic_string_view
<Char
>(start
, detail::to_unsigned(it
- start
)));
402 out
= detail::write(out
, basic_string_view
<Char
>(
403 start
, detail::to_unsigned(it
- 1 - start
)));
405 basic_format_specs
<Char
> specs
;
406 specs
.align
= align::right
;
408 // Parse argument index, flags and width.
409 int arg_index
= parse_header(it
, end
, specs
, get_arg
);
410 if (arg_index
== 0) parse_ctx
.on_error("argument not found");
413 if (it
!= end
&& *it
== '.') {
415 c
= it
!= end
? *it
: 0;
416 if ('0' <= c
&& c
<= '9') {
417 specs
.precision
= parse_nonnegative_int(it
, end
, 0);
418 } else if (c
== '*') {
420 specs
.precision
= static_cast<int>(
421 visit_format_arg(detail::printf_precision_handler(), get_arg(-1)));
427 auto arg
= get_arg(arg_index
);
428 // For d, i, o, u, x, and X conversion specifiers, if a precision is
429 // specified, the '0' flag is ignored
430 if (specs
.precision
>= 0 && arg
.is_integral())
432 ' '; // Ignore '0' flag for non-numeric types or if '-' present.
433 if (specs
.precision
>= 0 && arg
.type() == detail::type::cstring_type
) {
434 auto str
= visit_format_arg(detail::get_cstring
<Char
>(), arg
);
435 auto str_end
= str
+ specs
.precision
;
436 auto nul
= std::find(str
, str_end
, Char());
437 arg
= detail::make_arg
<basic_printf_context
<OutputIt
, Char
>>(
438 basic_string_view
<Char
>(
439 str
, detail::to_unsigned(nul
!= str_end
? nul
- str
440 : specs
.precision
)));
442 if (specs
.alt
&& visit_format_arg(detail::is_zero_int(), arg
))
444 if (specs
.fill
[0] == '0') {
445 if (arg
.is_arithmetic() && specs
.align
!= align::left
)
446 specs
.align
= align::numeric
;
448 specs
.fill
[0] = ' '; // Ignore '0' flag for non-numeric types or if '-'
449 // flag is also present.
452 // Parse length and convert the argument to the required type.
453 c
= it
!= end
? *it
++ : 0;
454 Char t
= it
!= end
? *it
: 0;
455 using detail::convert_arg
;
460 t
= it
!= end
? *it
: 0;
461 convert_arg
<signed char>(arg
, t
);
463 convert_arg
<short>(arg
, t
);
469 t
= it
!= end
? *it
: 0;
470 convert_arg
<long long>(arg
, t
);
472 convert_arg
<long>(arg
, t
);
476 convert_arg
<intmax_t>(arg
, t
);
479 convert_arg
<size_t>(arg
, t
);
482 convert_arg
<std::ptrdiff_t>(arg
, t
);
485 // printf produces garbage when 'L' is omitted for long double, no
486 // need to do the same.
490 convert_arg
<void>(arg
, c
);
494 if (it
== end
) FMT_THROW(format_error("invalid format string"));
495 char type
= static_cast<char>(*it
++);
496 if (arg
.is_integral()) {
505 detail::char_converter
<basic_printf_context
<OutputIt
, Char
>>(arg
),
510 specs
.type
= parse_presentation_type(type
);
511 if (specs
.type
== presentation_type::none
)
512 parse_ctx
.on_error("invalid type specifier");
517 out
= visit_format_arg(
518 detail::printf_arg_formatter
<OutputIt
, Char
>(out
, specs
, context
), arg
);
520 detail::write(out
, basic_string_view
<Char
>(start
, to_unsigned(it
- start
)));
522 FMT_END_DETAIL_NAMESPACE
524 template <typename Char
>
525 using basic_printf_context_t
=
526 basic_printf_context
<detail::buffer_appender
<Char
>, Char
>;
528 using printf_context
= basic_printf_context_t
<char>;
529 using wprintf_context
= basic_printf_context_t
<wchar_t>;
531 using printf_args
= basic_format_args
<printf_context
>;
532 using wprintf_args
= basic_format_args
<wprintf_context
>;
536 Constructs an `~fmt::format_arg_store` object that contains references to
537 arguments and can be implicitly converted to `~fmt::printf_args`.
540 template <typename
... T
>
541 inline auto make_printf_args(const T
&... args
)
542 -> format_arg_store
<printf_context
, T
...> {
548 Constructs an `~fmt::format_arg_store` object that contains references to
549 arguments and can be implicitly converted to `~fmt::wprintf_args`.
552 template <typename
... T
>
553 inline auto make_wprintf_args(const T
&... args
)
554 -> format_arg_store
<wprintf_context
, T
...> {
558 template <typename S
, typename Char
= char_t
<S
>>
559 inline auto vsprintf(
561 basic_format_args
<basic_printf_context_t
<type_identity_t
<Char
>>> args
)
562 -> std::basic_string
<Char
> {
563 basic_memory_buffer
<Char
> buffer
;
564 vprintf(buffer
, to_string_view(fmt
), args
);
565 return to_string(buffer
);
570 Formats arguments and returns the result as a string.
574 std::string message = fmt::sprintf("The answer is %d", 42);
577 template <typename S
, typename
... T
,
578 typename Char
= enable_if_t
<detail::is_string
<S
>::value
, char_t
<S
>>>
579 inline auto sprintf(const S
& fmt
, const T
&... args
) -> std::basic_string
<Char
> {
580 using context
= basic_printf_context_t
<Char
>;
581 return vsprintf(to_string_view(fmt
), fmt::make_format_args
<context
>(args
...));
584 template <typename S
, typename Char
= char_t
<S
>>
585 inline auto vfprintf(
586 std::FILE* f
, const S
& fmt
,
587 basic_format_args
<basic_printf_context_t
<type_identity_t
<Char
>>> args
)
589 basic_memory_buffer
<Char
> buffer
;
590 vprintf(buffer
, to_string_view(fmt
), args
);
591 size_t size
= buffer
.size();
592 return std::fwrite(buffer
.data(), sizeof(Char
), size
, f
) < size
594 : static_cast<int>(size
);
599 Prints formatted data to the file *f*.
603 fmt::fprintf(stderr, "Don't %s!", "panic");
606 template <typename S
, typename
... T
, typename Char
= char_t
<S
>>
607 inline auto fprintf(std::FILE* f
, const S
& fmt
, const T
&... args
) -> int {
608 using context
= basic_printf_context_t
<Char
>;
609 return vfprintf(f
, to_string_view(fmt
),
610 fmt::make_format_args
<context
>(args
...));
613 template <typename S
, typename Char
= char_t
<S
>>
616 basic_format_args
<basic_printf_context_t
<type_identity_t
<Char
>>> args
)
618 return vfprintf(stdout
, to_string_view(fmt
), args
);
623 Prints formatted data to ``stdout``.
627 fmt::printf("Elapsed time: %.2f seconds", 1.23);
630 template <typename S
, typename
... T
, FMT_ENABLE_IF(detail::is_string
<S
>::value
)>
631 inline auto printf(const S
& fmt
, const T
&... args
) -> int {
634 fmt::make_format_args
<basic_printf_context_t
<char_t
<S
>>>(args
...));
637 template <typename S
, typename Char
= char_t
<S
>>
638 FMT_DEPRECATED
auto vfprintf(
639 std::basic_ostream
<Char
>& os
, const S
& fmt
,
640 basic_format_args
<basic_printf_context_t
<type_identity_t
<Char
>>> args
)
642 basic_memory_buffer
<Char
> buffer
;
643 vprintf(buffer
, to_string_view(fmt
), args
);
644 os
.write(buffer
.data(), static_cast<std::streamsize
>(buffer
.size()));
645 return static_cast<int>(buffer
.size());
647 template <typename S
, typename
... T
, typename Char
= char_t
<S
>>
648 FMT_DEPRECATED
auto fprintf(std::basic_ostream
<Char
>& os
, const S
& fmt
,
649 const T
&... args
) -> int {
650 return vfprintf(os
, to_string_view(fmt
),
651 fmt::make_format_args
<basic_printf_context_t
<Char
>>(args
...));
654 FMT_MODULE_EXPORT_END
657 #endif // FMT_PRINTF_H_