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