]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | // Formatting library for C++ |
2 | // | |
3 | // Copyright (c) 2012 - 2016, Victor Zverovich | |
4 | // All rights reserved. | |
5 | // | |
6 | // For the license information refer to format.h. | |
7 | ||
8 | #ifndef FMT_PRINTF_H_ | |
9 | #define FMT_PRINTF_H_ | |
10 | ||
11 | #include <algorithm> // std::fill_n | |
12 | #include <limits> // std::numeric_limits | |
13 | ||
14 | #include "ostream.h" | |
15 | ||
16 | FMT_BEGIN_NAMESPACE | |
17 | namespace internal { | |
18 | ||
19 | // Checks if a value fits in int - used to avoid warnings about comparing | |
20 | // signed and unsigned integers. | |
21 | template <bool IsSigned> | |
22 | struct int_checker { | |
23 | template <typename T> | |
24 | static bool fits_in_int(T value) { | |
25 | unsigned max = std::numeric_limits<int>::max(); | |
26 | return value <= max; | |
27 | } | |
28 | static bool fits_in_int(bool) { return true; } | |
29 | }; | |
30 | ||
31 | template <> | |
32 | struct int_checker<true> { | |
33 | template <typename T> | |
34 | static bool fits_in_int(T value) { | |
35 | return value >= std::numeric_limits<int>::min() && | |
36 | value <= std::numeric_limits<int>::max(); | |
37 | } | |
38 | static bool fits_in_int(int) { return true; } | |
39 | }; | |
40 | ||
41 | class printf_precision_handler: public function<int> { | |
42 | public: | |
43 | template <typename T> | |
44 | typename std::enable_if<std::is_integral<T>::value, int>::type | |
45 | operator()(T value) { | |
46 | if (!int_checker<std::numeric_limits<T>::is_signed>::fits_in_int(value)) | |
47 | FMT_THROW(format_error("number is too big")); | |
48 | return static_cast<int>(value); | |
49 | } | |
50 | ||
51 | template <typename T> | |
52 | typename std::enable_if<!std::is_integral<T>::value, int>::type operator()(T) { | |
53 | FMT_THROW(format_error("precision is not integer")); | |
54 | return 0; | |
55 | } | |
56 | }; | |
57 | ||
58 | // An argument visitor that returns true iff arg is a zero integer. | |
59 | class is_zero_int: public function<bool> { | |
60 | public: | |
61 | template <typename T> | |
62 | typename std::enable_if<std::is_integral<T>::value, bool>::type | |
63 | operator()(T value) { return value == 0; } | |
64 | ||
65 | template <typename T> | |
66 | typename std::enable_if<!std::is_integral<T>::value, bool>::type | |
67 | operator()(T) { return false; } | |
68 | }; | |
69 | ||
70 | template <typename T> | |
71 | struct make_unsigned_or_bool : std::make_unsigned<T> {}; | |
72 | ||
73 | template <> | |
74 | struct make_unsigned_or_bool<bool> { | |
75 | typedef bool type; | |
76 | }; | |
77 | ||
78 | template <typename T, typename Context> | |
79 | class arg_converter: public function<void> { | |
80 | private: | |
81 | typedef typename Context::char_type Char; | |
82 | ||
83 | basic_format_arg<Context> &arg_; | |
84 | typename Context::char_type type_; | |
85 | ||
86 | public: | |
87 | arg_converter(basic_format_arg<Context> &arg, Char type) | |
88 | : arg_(arg), type_(type) {} | |
89 | ||
90 | void operator()(bool value) { | |
91 | if (type_ != 's') | |
92 | operator()<bool>(value); | |
93 | } | |
94 | ||
95 | template <typename U> | |
96 | typename std::enable_if<std::is_integral<U>::value>::type | |
97 | operator()(U value) { | |
98 | bool is_signed = type_ == 'd' || type_ == 'i'; | |
99 | typedef typename std::conditional< | |
100 | std::is_same<T, void>::value, U, T>::type TargetType; | |
101 | if (const_check(sizeof(TargetType) <= sizeof(int))) { | |
102 | // Extra casts are used to silence warnings. | |
103 | if (is_signed) { | |
104 | arg_ = internal::make_arg<Context>( | |
105 | static_cast<int>(static_cast<TargetType>(value))); | |
106 | } else { | |
107 | typedef typename make_unsigned_or_bool<TargetType>::type Unsigned; | |
108 | arg_ = internal::make_arg<Context>( | |
109 | static_cast<unsigned>(static_cast<Unsigned>(value))); | |
110 | } | |
111 | } else { | |
112 | if (is_signed) { | |
113 | // glibc's printf doesn't sign extend arguments of smaller types: | |
114 | // std::printf("%lld", -42); // prints "4294967254" | |
115 | // but we don't have to do the same because it's a UB. | |
116 | arg_ = internal::make_arg<Context>(static_cast<long long>(value)); | |
117 | } else { | |
118 | arg_ = internal::make_arg<Context>( | |
119 | static_cast<typename make_unsigned_or_bool<U>::type>(value)); | |
120 | } | |
121 | } | |
122 | } | |
123 | ||
124 | template <typename U> | |
125 | typename std::enable_if<!std::is_integral<U>::value>::type operator()(U) { | |
126 | // No coversion needed for non-integral types. | |
127 | } | |
128 | }; | |
129 | ||
130 | // Converts an integer argument to T for printf, if T is an integral type. | |
131 | // If T is void, the argument is converted to corresponding signed or unsigned | |
132 | // type depending on the type specifier: 'd' and 'i' - signed, other - | |
133 | // unsigned). | |
134 | template <typename T, typename Context, typename Char> | |
135 | void convert_arg(basic_format_arg<Context> &arg, Char type) { | |
eafe8130 | 136 | visit_format_arg(arg_converter<T, Context>(arg, type), arg); |
11fdf7f2 TL |
137 | } |
138 | ||
139 | // Converts an integer argument to char for printf. | |
140 | template <typename Context> | |
141 | class char_converter: public function<void> { | |
142 | private: | |
143 | basic_format_arg<Context> &arg_; | |
144 | ||
145 | public: | |
146 | explicit char_converter(basic_format_arg<Context> &arg) : arg_(arg) {} | |
147 | ||
148 | template <typename T> | |
149 | typename std::enable_if<std::is_integral<T>::value>::type | |
150 | operator()(T value) { | |
151 | typedef typename Context::char_type Char; | |
152 | arg_ = internal::make_arg<Context>(static_cast<Char>(value)); | |
153 | } | |
154 | ||
155 | template <typename T> | |
156 | typename std::enable_if<!std::is_integral<T>::value>::type operator()(T) { | |
157 | // No coversion needed for non-integral types. | |
158 | } | |
159 | }; | |
160 | ||
161 | // Checks if an argument is a valid printf width specifier and sets | |
162 | // left alignment if it is negative. | |
163 | template <typename Char> | |
164 | class printf_width_handler: public function<unsigned> { | |
165 | private: | |
166 | typedef basic_format_specs<Char> format_specs; | |
167 | ||
168 | format_specs &spec_; | |
169 | ||
170 | public: | |
171 | explicit printf_width_handler(format_specs &spec) : spec_(spec) {} | |
172 | ||
173 | template <typename T> | |
174 | typename std::enable_if<std::is_integral<T>::value, unsigned>::type | |
175 | operator()(T value) { | |
176 | typedef typename internal::int_traits<T>::main_type UnsignedType; | |
177 | UnsignedType width = static_cast<UnsignedType>(value); | |
178 | if (internal::is_negative(value)) { | |
179 | spec_.align_ = ALIGN_LEFT; | |
180 | width = 0 - width; | |
181 | } | |
182 | unsigned int_max = std::numeric_limits<int>::max(); | |
183 | if (width > int_max) | |
184 | FMT_THROW(format_error("number is too big")); | |
185 | return static_cast<unsigned>(width); | |
186 | } | |
187 | ||
188 | template <typename T> | |
189 | typename std::enable_if<!std::is_integral<T>::value, unsigned>::type | |
190 | operator()(T) { | |
191 | FMT_THROW(format_error("width is not integer")); | |
192 | return 0; | |
193 | } | |
194 | }; | |
195 | } // namespace internal | |
196 | ||
197 | template <typename Range> | |
198 | class printf_arg_formatter; | |
199 | ||
200 | template < | |
201 | typename OutputIt, typename Char, | |
202 | typename ArgFormatter = | |
203 | printf_arg_formatter<back_insert_range<internal::basic_buffer<Char>>>> | |
204 | class basic_printf_context; | |
205 | ||
206 | /** | |
207 | \rst | |
208 | The ``printf`` argument formatter. | |
209 | \endrst | |
210 | */ | |
211 | template <typename Range> | |
212 | class printf_arg_formatter: | |
213 | public internal::function< | |
214 | typename internal::arg_formatter_base<Range>::iterator>, | |
215 | public internal::arg_formatter_base<Range> { | |
216 | private: | |
217 | typedef typename Range::value_type char_type; | |
218 | typedef decltype(internal::declval<Range>().begin()) iterator; | |
219 | typedef internal::arg_formatter_base<Range> base; | |
220 | typedef basic_printf_context<iterator, char_type> context_type; | |
221 | ||
222 | context_type &context_; | |
223 | ||
224 | void write_null_pointer(char) { | |
eafe8130 | 225 | this->spec()->type = 0; |
11fdf7f2 TL |
226 | this->write("(nil)"); |
227 | } | |
228 | ||
229 | void write_null_pointer(wchar_t) { | |
eafe8130 | 230 | this->spec()->type = 0; |
11fdf7f2 TL |
231 | this->write(L"(nil)"); |
232 | } | |
233 | ||
234 | public: | |
235 | typedef typename base::format_specs format_specs; | |
236 | ||
237 | /** | |
238 | \rst | |
239 | Constructs an argument formatter object. | |
240 | *buffer* is a reference to the output buffer and *spec* contains format | |
241 | specifier information for standard argument types. | |
242 | \endrst | |
243 | */ | |
244 | printf_arg_formatter(internal::basic_buffer<char_type> &buffer, | |
245 | format_specs &spec, context_type &ctx) | |
eafe8130 TL |
246 | : base(back_insert_range<internal::basic_buffer<char_type>>(buffer), &spec, |
247 | ctx.locale()), | |
11fdf7f2 TL |
248 | context_(ctx) {} |
249 | ||
250 | template <typename T> | |
251 | typename std::enable_if<std::is_integral<T>::value, iterator>::type | |
252 | operator()(T value) { | |
253 | // MSVC2013 fails to compile separate overloads for bool and char_type so | |
254 | // use std::is_same instead. | |
255 | if (std::is_same<T, bool>::value) { | |
256 | format_specs &fmt_spec = *this->spec(); | |
eafe8130 | 257 | if (fmt_spec.type != 's') |
11fdf7f2 | 258 | return base::operator()(value ? 1 : 0); |
eafe8130 | 259 | fmt_spec.type = 0; |
11fdf7f2 TL |
260 | this->write(value != 0); |
261 | } else if (std::is_same<T, char_type>::value) { | |
262 | format_specs &fmt_spec = *this->spec(); | |
eafe8130 | 263 | if (fmt_spec.type && fmt_spec.type != 'c') |
11fdf7f2 | 264 | return (*this)(static_cast<int>(value)); |
eafe8130 | 265 | fmt_spec.flags = 0; |
11fdf7f2 TL |
266 | fmt_spec.align_ = ALIGN_RIGHT; |
267 | return base::operator()(value); | |
268 | } else { | |
269 | return base::operator()(value); | |
270 | } | |
271 | return this->out(); | |
272 | } | |
273 | ||
274 | template <typename T> | |
275 | typename std::enable_if<std::is_floating_point<T>::value, iterator>::type | |
276 | operator()(T value) { | |
277 | return base::operator()(value); | |
278 | } | |
279 | ||
280 | /** Formats a null-terminated C string. */ | |
281 | iterator operator()(const char *value) { | |
282 | if (value) | |
283 | base::operator()(value); | |
eafe8130 | 284 | else if (this->spec()->type == 'p') |
11fdf7f2 TL |
285 | write_null_pointer(char_type()); |
286 | else | |
287 | this->write("(null)"); | |
288 | return this->out(); | |
289 | } | |
290 | ||
291 | /** Formats a null-terminated wide C string. */ | |
292 | iterator operator()(const wchar_t *value) { | |
293 | if (value) | |
294 | base::operator()(value); | |
eafe8130 | 295 | else if (this->spec()->type == 'p') |
11fdf7f2 TL |
296 | write_null_pointer(char_type()); |
297 | else | |
298 | this->write(L"(null)"); | |
299 | return this->out(); | |
300 | } | |
301 | ||
302 | iterator operator()(basic_string_view<char_type> value) { | |
303 | return base::operator()(value); | |
304 | } | |
305 | ||
306 | iterator operator()(monostate value) { | |
307 | return base::operator()(value); | |
308 | } | |
309 | ||
310 | /** Formats a pointer. */ | |
311 | iterator operator()(const void *value) { | |
312 | if (value) | |
313 | return base::operator()(value); | |
eafe8130 | 314 | this->spec()->type = 0; |
11fdf7f2 TL |
315 | write_null_pointer(char_type()); |
316 | return this->out(); | |
317 | } | |
318 | ||
319 | /** Formats an argument of a custom (user-defined) type. */ | |
320 | iterator operator()(typename basic_format_arg<context_type>::handle handle) { | |
321 | handle.format(context_); | |
322 | return this->out(); | |
323 | } | |
324 | }; | |
325 | ||
326 | template <typename T> | |
327 | struct printf_formatter { | |
328 | template <typename ParseContext> | |
329 | auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { return ctx.begin(); } | |
330 | ||
331 | template <typename FormatContext> | |
332 | auto format(const T &value, FormatContext &ctx) -> decltype(ctx.out()) { | |
333 | internal::format_value(internal::get_container(ctx.out()), value); | |
334 | return ctx.out(); | |
335 | } | |
336 | }; | |
337 | ||
338 | /** This template formats data and writes the output to a writer. */ | |
339 | template <typename OutputIt, typename Char, typename ArgFormatter> | |
340 | class basic_printf_context : | |
341 | // Inherit publicly as a workaround for the icc bug | |
342 | // https://software.intel.com/en-us/forums/intel-c-compiler/topic/783476. | |
343 | public internal::context_base< | |
344 | OutputIt, basic_printf_context<OutputIt, Char, ArgFormatter>, Char> { | |
345 | public: | |
346 | /** The character type for the output. */ | |
347 | typedef Char char_type; | |
348 | ||
349 | template <typename T> | |
350 | struct formatter_type { typedef printf_formatter<T> type; }; | |
351 | ||
352 | private: | |
353 | typedef internal::context_base<OutputIt, basic_printf_context, Char> base; | |
354 | typedef typename base::format_arg format_arg; | |
355 | typedef basic_format_specs<char_type> format_specs; | |
356 | typedef internal::null_terminating_iterator<char_type> iterator; | |
357 | ||
358 | void parse_flags(format_specs &spec, iterator &it); | |
359 | ||
360 | // Returns the argument with specified index or, if arg_index is equal | |
361 | // to the maximum unsigned value, the next argument. | |
362 | format_arg get_arg( | |
363 | iterator it, | |
364 | unsigned arg_index = (std::numeric_limits<unsigned>::max)()); | |
365 | ||
366 | // Parses argument index, flags and width and returns the argument index. | |
367 | unsigned parse_header(iterator &it, format_specs &spec); | |
368 | ||
369 | public: | |
370 | /** | |
371 | \rst | |
372 | Constructs a ``printf_context`` object. References to the arguments and | |
373 | the writer are stored in the context object so make sure they have | |
374 | appropriate lifetimes. | |
375 | \endrst | |
376 | */ | |
377 | basic_printf_context(OutputIt out, basic_string_view<char_type> format_str, | |
378 | basic_format_args<basic_printf_context> args) | |
379 | : base(out, format_str, args) {} | |
380 | ||
381 | using base::parse_context; | |
382 | using base::out; | |
383 | using base::advance_to; | |
384 | ||
385 | /** Formats stored arguments and writes the output to the range. */ | |
386 | void format(); | |
387 | }; | |
388 | ||
389 | template <typename OutputIt, typename Char, typename AF> | |
390 | void basic_printf_context<OutputIt, Char, AF>::parse_flags( | |
391 | format_specs &spec, iterator &it) { | |
392 | for (;;) { | |
393 | switch (*it++) { | |
394 | case '-': | |
395 | spec.align_ = ALIGN_LEFT; | |
396 | break; | |
397 | case '+': | |
eafe8130 | 398 | spec.flags |= SIGN_FLAG | PLUS_FLAG; |
11fdf7f2 TL |
399 | break; |
400 | case '0': | |
401 | spec.fill_ = '0'; | |
402 | break; | |
403 | case ' ': | |
eafe8130 | 404 | spec.flags |= SIGN_FLAG; |
11fdf7f2 TL |
405 | break; |
406 | case '#': | |
eafe8130 | 407 | spec.flags |= HASH_FLAG; |
11fdf7f2 TL |
408 | break; |
409 | default: | |
410 | --it; | |
411 | return; | |
412 | } | |
413 | } | |
414 | } | |
415 | ||
416 | template <typename OutputIt, typename Char, typename AF> | |
417 | typename basic_printf_context<OutputIt, Char, AF>::format_arg | |
418 | basic_printf_context<OutputIt, Char, AF>::get_arg( | |
419 | iterator it, unsigned arg_index) { | |
420 | (void)it; | |
421 | if (arg_index == std::numeric_limits<unsigned>::max()) | |
422 | return this->do_get_arg(this->parse_context().next_arg_id()); | |
423 | return base::get_arg(arg_index - 1); | |
424 | } | |
425 | ||
426 | template <typename OutputIt, typename Char, typename AF> | |
427 | unsigned basic_printf_context<OutputIt, Char, AF>::parse_header( | |
428 | iterator &it, format_specs &spec) { | |
429 | unsigned arg_index = std::numeric_limits<unsigned>::max(); | |
430 | char_type c = *it; | |
431 | if (c >= '0' && c <= '9') { | |
432 | // Parse an argument index (if followed by '$') or a width possibly | |
433 | // preceded with '0' flag(s). | |
434 | internal::error_handler eh; | |
435 | unsigned value = parse_nonnegative_int(it, eh); | |
436 | if (*it == '$') { // value is an argument index | |
437 | ++it; | |
438 | arg_index = value; | |
439 | } else { | |
440 | if (c == '0') | |
441 | spec.fill_ = '0'; | |
442 | if (value != 0) { | |
443 | // Nonzero value means that we parsed width and don't need to | |
444 | // parse it or flags again, so return now. | |
445 | spec.width_ = value; | |
446 | return arg_index; | |
447 | } | |
448 | } | |
449 | } | |
450 | parse_flags(spec, it); | |
451 | // Parse width. | |
452 | if (*it >= '0' && *it <= '9') { | |
453 | internal::error_handler eh; | |
454 | spec.width_ = parse_nonnegative_int(it, eh); | |
455 | } else if (*it == '*') { | |
456 | ++it; | |
eafe8130 TL |
457 | spec.width_ = visit_format_arg( |
458 | internal::printf_width_handler<char_type>(spec), get_arg(it)); | |
11fdf7f2 TL |
459 | } |
460 | return arg_index; | |
461 | } | |
462 | ||
463 | template <typename OutputIt, typename Char, typename AF> | |
464 | void basic_printf_context<OutputIt, Char, AF>::format() { | |
465 | auto &buffer = internal::get_container(this->out()); | |
466 | auto start = iterator(this->parse_context()); | |
467 | auto it = start; | |
468 | using internal::pointer_from; | |
469 | while (*it) { | |
470 | char_type c = *it++; | |
471 | if (c != '%') continue; | |
472 | if (*it == c) { | |
473 | buffer.append(pointer_from(start), pointer_from(it)); | |
474 | start = ++it; | |
475 | continue; | |
476 | } | |
477 | buffer.append(pointer_from(start), pointer_from(it) - 1); | |
478 | ||
479 | format_specs spec; | |
480 | spec.align_ = ALIGN_RIGHT; | |
481 | ||
482 | // Parse argument index, flags and width. | |
483 | unsigned arg_index = parse_header(it, spec); | |
484 | ||
485 | // Parse precision. | |
486 | if (*it == '.') { | |
487 | ++it; | |
488 | if ('0' <= *it && *it <= '9') { | |
489 | internal::error_handler eh; | |
eafe8130 | 490 | spec.precision = static_cast<int>(parse_nonnegative_int(it, eh)); |
11fdf7f2 TL |
491 | } else if (*it == '*') { |
492 | ++it; | |
eafe8130 TL |
493 | spec.precision = |
494 | visit_format_arg(internal::printf_precision_handler(), get_arg(it)); | |
11fdf7f2 | 495 | } else { |
eafe8130 | 496 | spec.precision = 0; |
11fdf7f2 TL |
497 | } |
498 | } | |
499 | ||
500 | format_arg arg = get_arg(it, arg_index); | |
eafe8130 TL |
501 | if (spec.has(HASH_FLAG) && visit_format_arg(internal::is_zero_int(), arg)) |
502 | spec.flags &= ~internal::to_unsigned<int>(HASH_FLAG); | |
11fdf7f2 TL |
503 | if (spec.fill_ == '0') { |
504 | if (arg.is_arithmetic()) | |
505 | spec.align_ = ALIGN_NUMERIC; | |
506 | else | |
507 | spec.fill_ = ' '; // Ignore '0' flag for non-numeric types. | |
508 | } | |
509 | ||
510 | // Parse length and convert the argument to the required type. | |
511 | using internal::convert_arg; | |
512 | switch (*it++) { | |
513 | case 'h': | |
514 | if (*it == 'h') | |
515 | convert_arg<signed char>(arg, *++it); | |
516 | else | |
517 | convert_arg<short>(arg, *it); | |
518 | break; | |
519 | case 'l': | |
520 | if (*it == 'l') | |
521 | convert_arg<long long>(arg, *++it); | |
522 | else | |
523 | convert_arg<long>(arg, *it); | |
524 | break; | |
525 | case 'j': | |
526 | convert_arg<intmax_t>(arg, *it); | |
527 | break; | |
528 | case 'z': | |
529 | convert_arg<std::size_t>(arg, *it); | |
530 | break; | |
531 | case 't': | |
532 | convert_arg<std::ptrdiff_t>(arg, *it); | |
533 | break; | |
534 | case 'L': | |
535 | // printf produces garbage when 'L' is omitted for long double, no | |
536 | // need to do the same. | |
537 | break; | |
538 | default: | |
539 | --it; | |
540 | convert_arg<void>(arg, *it); | |
541 | } | |
542 | ||
543 | // Parse type. | |
544 | if (!*it) | |
545 | FMT_THROW(format_error("invalid format string")); | |
eafe8130 | 546 | spec.type = static_cast<char>(*it++); |
11fdf7f2 TL |
547 | if (arg.is_integral()) { |
548 | // Normalize type. | |
eafe8130 | 549 | switch (spec.type) { |
11fdf7f2 | 550 | case 'i': case 'u': |
eafe8130 | 551 | spec.type = 'd'; |
11fdf7f2 TL |
552 | break; |
553 | case 'c': | |
554 | // TODO: handle wchar_t better? | |
eafe8130 TL |
555 | visit_format_arg( |
556 | internal::char_converter<basic_printf_context>(arg), arg); | |
11fdf7f2 TL |
557 | break; |
558 | } | |
559 | } | |
560 | ||
561 | start = it; | |
562 | ||
563 | // Format argument. | |
eafe8130 | 564 | visit_format_arg(AF(buffer, spec, *this), arg); |
11fdf7f2 TL |
565 | } |
566 | buffer.append(pointer_from(start), pointer_from(it)); | |
567 | } | |
568 | ||
569 | template <typename Char, typename Context> | |
570 | void printf(internal::basic_buffer<Char> &buf, basic_string_view<Char> format, | |
571 | basic_format_args<Context> args) { | |
572 | Context(std::back_inserter(buf), format, args).format(); | |
573 | } | |
574 | ||
575 | template <typename Buffer> | |
eafe8130 | 576 | struct basic_printf_context_t { |
11fdf7f2 TL |
577 | typedef basic_printf_context< |
578 | std::back_insert_iterator<Buffer>, typename Buffer::value_type> type; | |
579 | }; | |
580 | ||
eafe8130 TL |
581 | typedef basic_printf_context_t<internal::buffer>::type printf_context; |
582 | typedef basic_printf_context_t<internal::wbuffer>::type wprintf_context; | |
583 | ||
584 | typedef basic_format_args<printf_context> printf_args; | |
585 | typedef basic_format_args<wprintf_context> wprintf_args; | |
586 | ||
587 | /** | |
588 | \rst | |
589 | Constructs an `~fmt::format_arg_store` object that contains references to | |
590 | arguments and can be implicitly converted to `~fmt::printf_args`. | |
591 | \endrst | |
592 | */ | |
593 | template<typename... Args> | |
594 | inline format_arg_store<printf_context, Args...> | |
595 | make_printf_args(const Args &... args) { return {args...}; } | |
11fdf7f2 | 596 | |
eafe8130 TL |
597 | /** |
598 | \rst | |
599 | Constructs an `~fmt::format_arg_store` object that contains references to | |
600 | arguments and can be implicitly converted to `~fmt::wprintf_args`. | |
601 | \endrst | |
602 | */ | |
603 | template<typename... Args> | |
604 | inline format_arg_store<wprintf_context, Args...> | |
605 | make_wprintf_args(const Args &... args) { return {args...}; } | |
606 | ||
607 | template <typename S, typename Char = FMT_CHAR(S)> | |
608 | inline std::basic_string<Char> | |
609 | vsprintf(const S &format, | |
610 | basic_format_args<typename basic_printf_context_t< | |
611 | internal::basic_buffer<Char>>::type> args) { | |
612 | basic_memory_buffer<Char> buffer; | |
613 | printf(buffer, to_string_view(format), args); | |
11fdf7f2 TL |
614 | return to_string(buffer); |
615 | } | |
616 | ||
617 | /** | |
618 | \rst | |
619 | Formats arguments and returns the result as a string. | |
620 | ||
621 | **Example**:: | |
622 | ||
623 | std::string message = fmt::sprintf("The answer is %d", 42); | |
624 | \endrst | |
625 | */ | |
eafe8130 TL |
626 | template <typename S, typename... Args> |
627 | inline FMT_ENABLE_IF_STRING(S, std::basic_string<FMT_CHAR(S)>) | |
628 | sprintf(const S &format, const Args & ... args) { | |
629 | internal::check_format_string<Args...>(format); | |
630 | typedef internal::basic_buffer<FMT_CHAR(S)> buffer; | |
631 | typedef typename basic_printf_context_t<buffer>::type context; | |
632 | format_arg_store<context, Args...> as{ args... }; | |
633 | return vsprintf(to_string_view(format), | |
634 | basic_format_args<context>(as)); | |
11fdf7f2 TL |
635 | } |
636 | ||
eafe8130 TL |
637 | template <typename S, typename Char = FMT_CHAR(S)> |
638 | inline int vfprintf(std::FILE *f, const S &format, | |
639 | basic_format_args<typename basic_printf_context_t< | |
11fdf7f2 TL |
640 | internal::basic_buffer<Char>>::type> args) { |
641 | basic_memory_buffer<Char> buffer; | |
eafe8130 | 642 | printf(buffer, to_string_view(format), args); |
11fdf7f2 TL |
643 | std::size_t size = buffer.size(); |
644 | return std::fwrite( | |
645 | buffer.data(), sizeof(Char), size, f) < size ? -1 : static_cast<int>(size); | |
646 | } | |
647 | ||
648 | /** | |
649 | \rst | |
650 | Prints formatted data to the file *f*. | |
651 | ||
652 | **Example**:: | |
653 | ||
654 | fmt::fprintf(stderr, "Don't %s!", "panic"); | |
655 | \endrst | |
656 | */ | |
eafe8130 TL |
657 | template <typename S, typename... Args> |
658 | inline FMT_ENABLE_IF_STRING(S, int) | |
659 | fprintf(std::FILE *f, const S &format, const Args & ... args) { | |
660 | internal::check_format_string<Args...>(format); | |
661 | typedef internal::basic_buffer<FMT_CHAR(S)> buffer; | |
662 | typedef typename basic_printf_context_t<buffer>::type context; | |
663 | format_arg_store<context, Args...> as{ args... }; | |
664 | return vfprintf(f, to_string_view(format), | |
665 | basic_format_args<context>(as)); | |
11fdf7f2 TL |
666 | } |
667 | ||
eafe8130 TL |
668 | template <typename S, typename Char = FMT_CHAR(S)> |
669 | inline int vprintf(const S &format, | |
670 | basic_format_args<typename basic_printf_context_t< | |
671 | internal::basic_buffer<Char>>::type> args) { | |
672 | return vfprintf(stdout, to_string_view(format), args); | |
11fdf7f2 TL |
673 | } |
674 | ||
675 | /** | |
676 | \rst | |
677 | Prints formatted data to ``stdout``. | |
678 | ||
679 | **Example**:: | |
680 | ||
681 | fmt::printf("Elapsed time: %.2f seconds", 1.23); | |
682 | \endrst | |
683 | */ | |
eafe8130 TL |
684 | template <typename S, typename... Args> |
685 | inline FMT_ENABLE_IF_STRING(S, int) | |
686 | printf(const S &format_str, const Args & ... args) { | |
687 | internal::check_format_string<Args...>(format_str); | |
688 | typedef internal::basic_buffer<FMT_CHAR(S)> buffer; | |
689 | typedef typename basic_printf_context_t<buffer>::type context; | |
690 | format_arg_store<context, Args...> as{ args... }; | |
691 | return vprintf(to_string_view(format_str), | |
692 | basic_format_args<context>(as)); | |
11fdf7f2 TL |
693 | } |
694 | ||
eafe8130 TL |
695 | template <typename S, typename Char = FMT_CHAR(S)> |
696 | inline int vfprintf(std::basic_ostream<Char> &os, | |
697 | const S &format, | |
698 | basic_format_args<typename basic_printf_context_t< | |
699 | internal::basic_buffer<Char>>::type> args) { | |
700 | basic_memory_buffer<Char> buffer; | |
701 | printf(buffer, to_string_view(format), args); | |
11fdf7f2 TL |
702 | internal::write(os, buffer); |
703 | return static_cast<int>(buffer.size()); | |
704 | } | |
705 | ||
706 | /** | |
707 | \rst | |
708 | Prints formatted data to the stream *os*. | |
709 | ||
710 | **Example**:: | |
711 | ||
712 | fmt::fprintf(cerr, "Don't %s!", "panic"); | |
713 | \endrst | |
714 | */ | |
eafe8130 TL |
715 | template <typename S, typename... Args> |
716 | inline FMT_ENABLE_IF_STRING(S, int) | |
717 | fprintf(std::basic_ostream<FMT_CHAR(S)> &os, | |
718 | const S &format_str, const Args & ... args) { | |
719 | internal::check_format_string<Args...>(format_str); | |
720 | typedef internal::basic_buffer<FMT_CHAR(S)> buffer; | |
721 | typedef typename basic_printf_context_t<buffer>::type context; | |
722 | format_arg_store<context, Args...> as{ args... }; | |
723 | return vfprintf(os, to_string_view(format_str), | |
724 | basic_format_args<context>(as)); | |
11fdf7f2 TL |
725 | } |
726 | FMT_END_NAMESPACE | |
727 | ||
728 | #endif // FMT_PRINTF_H_ |