blob: f068b959844a585ca4e0ec023085b63a1bbd3422 [file] [log] [blame]
Glen Stark72d51e02016-06-08 01:23:32 +02001/*
2 Formatting library for C++
3
4 Copyright (c) 2012 - 2016, Victor Zverovich
5 All rights reserved.
6
7 For the license information refer to format.h.
8 */
9
10#ifndef FMT_PRINTF_H_
11#define FMT_PRINTF_H_
12
13#include <algorithm> // std::fill_n
14#include <limits> // std::numeric_limits
15
Victor Zverovich9dbb60c2016-08-03 08:52:05 -070016#include "fmt/ostream.h"
Glen Stark72d51e02016-06-08 01:23:32 +020017
18namespace fmt {
19namespace internal {
20
21// Checks if a value fits in int - used to avoid warnings about comparing
22// signed and unsigned integers.
23template <bool IsSigned>
24struct IntChecker {
25 template <typename T>
26 static bool fits_in_int(T value) {
27 unsigned max = std::numeric_limits<int>::max();
28 return value <= max;
29 }
30 static bool fits_in_int(bool) { return true; }
31};
32
33template <>
34struct IntChecker<true> {
35 template <typename T>
36 static bool fits_in_int(T value) {
37 return value >= std::numeric_limits<int>::min() &&
38 value <= std::numeric_limits<int>::max();
39 }
40 static bool fits_in_int(int) { return true; }
41};
42
Victor Zverovich0854f8c2016-12-11 13:22:45 -080043class PrintfPrecisionHandler {
Glen Stark72d51e02016-06-08 01:23:32 +020044 public:
Glen Stark72d51e02016-06-08 01:23:32 +020045 template <typename T>
Victor Zveroviche2dfd392016-11-19 09:29:09 -080046 typename std::enable_if<std::is_integral<T>::value, int>::type
47 operator()(T value) {
Glen Stark72d51e02016-06-08 01:23:32 +020048 if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
Victor Zverovich9bb213e2016-08-25 08:38:07 -070049 FMT_THROW(format_error("number is too big"));
Glen Stark72d51e02016-06-08 01:23:32 +020050 return static_cast<int>(value);
51 }
Victor Zveroviche2dfd392016-11-19 09:29:09 -080052
53 template <typename T>
54 typename std::enable_if<!std::is_integral<T>::value, int>::type
55 operator()(T) {
56 FMT_THROW(format_error("precision is not integer"));
57 return 0;
58 }
Glen Stark72d51e02016-06-08 01:23:32 +020059};
60
Victor Zveroviche2dfd392016-11-19 09:29:09 -080061// An argument visitor that returns true iff arg is a zero integer.
62class IsZeroInt {
Glen Stark72d51e02016-06-08 01:23:32 +020063 public:
64 template <typename T>
Victor Zveroviche2dfd392016-11-19 09:29:09 -080065 typename std::enable_if<std::is_integral<T>::value, bool>::type
66 operator()(T value) { return value == 0; }
67
68 template <typename T>
69 typename std::enable_if<!std::is_integral<T>::value, bool>::type
Victor Zverovich77c892c2017-08-27 08:16:46 -070070 operator()(T) { return false; }
Glen Stark72d51e02016-06-08 01:23:32 +020071};
72
73template <typename T, typename U>
74struct is_same {
75 enum { value = 0 };
76};
77
78template <typename T>
79struct is_same<T, T> {
80 enum { value = 1 };
81};
82
Victor Zverovichd705d512016-12-29 09:07:39 -080083template <typename T, typename Context>
Victor Zverovich751ff642016-11-19 08:40:24 -080084class ArgConverter {
Glen Stark72d51e02016-06-08 01:23:32 +020085 private:
Victor Zverovichd705d512016-12-29 09:07:39 -080086 typedef typename Context::char_type Char;
87
Victor Zverovich7ae8bd72017-02-05 06:09:06 -080088 basic_arg<Context> &arg_;
Victor Zverovichd705d512016-12-29 09:07:39 -080089 typename Context::char_type type_;
Glen Stark72d51e02016-06-08 01:23:32 +020090
Glen Stark72d51e02016-06-08 01:23:32 +020091 public:
Victor Zverovich7ae8bd72017-02-05 06:09:06 -080092 ArgConverter(basic_arg<Context> &arg, Char type)
Glen Stark72d51e02016-06-08 01:23:32 +020093 : arg_(arg), type_(type) {}
94
Victor Zverovich751ff642016-11-19 08:40:24 -080095 void operator()(bool value) {
Glen Stark72d51e02016-06-08 01:23:32 +020096 if (type_ != 's')
Victor Zverovich751ff642016-11-19 08:40:24 -080097 operator()<bool>(value);
Glen Stark72d51e02016-06-08 01:23:32 +020098 }
99
100 template <typename U>
Victor Zverovich751ff642016-11-19 08:40:24 -0800101 typename std::enable_if<std::is_integral<U>::value>::type
102 operator()(U value) {
Glen Stark72d51e02016-06-08 01:23:32 +0200103 bool is_signed = type_ == 'd' || type_ == 'i';
Victor Zverovich6a2ff282017-02-19 06:46:51 -0800104 typedef typename internal::conditional<
Glen Stark72d51e02016-06-08 01:23:32 +0200105 is_same<T, void>::value, U, T>::type TargetType;
106 if (sizeof(TargetType) <= sizeof(int)) {
107 // Extra casts are used to silence warnings.
108 if (is_signed) {
Victor Zverovichd705d512016-12-29 09:07:39 -0800109 arg_ = internal::make_arg<Context>(
Victor Zverovich0854f8c2016-12-11 13:22:45 -0800110 static_cast<int>(static_cast<TargetType>(value)));
Glen Stark72d51e02016-06-08 01:23:32 +0200111 } else {
Victor Zverovich6a2ff282017-02-19 06:46:51 -0800112 typedef typename internal::make_unsigned<TargetType>::type Unsigned;
Victor Zverovichd705d512016-12-29 09:07:39 -0800113 arg_ = internal::make_arg<Context>(
Victor Zverovich0854f8c2016-12-11 13:22:45 -0800114 static_cast<unsigned>(static_cast<Unsigned>(value)));
Glen Stark72d51e02016-06-08 01:23:32 +0200115 }
116 } else {
117 if (is_signed) {
Glen Stark72d51e02016-06-08 01:23:32 +0200118 // glibc's printf doesn't sign extend arguments of smaller types:
119 // std::printf("%lld", -42); // prints "4294967254"
120 // but we don't have to do the same because it's a UB.
Victor Zverovich016aceb2017-08-26 09:09:43 -0700121 arg_ = internal::make_arg<Context>(static_cast<long long>(value));
Glen Stark72d51e02016-06-08 01:23:32 +0200122 } else {
Victor Zverovichd705d512016-12-29 09:07:39 -0800123 arg_ = internal::make_arg<Context>(
Victor Zverovich6a2ff282017-02-19 06:46:51 -0800124 static_cast<typename internal::make_unsigned<U>::type>(value));
Glen Stark72d51e02016-06-08 01:23:32 +0200125 }
126 }
127 }
Victor Zverovich751ff642016-11-19 08:40:24 -0800128
129 template <typename U>
Victor Zverovich77c892c2017-08-27 08:16:46 -0700130 typename std::enable_if<!std::is_integral<U>::value>::type operator()(U) {
Victor Zverovich751ff642016-11-19 08:40:24 -0800131 // No coversion needed for non-integral types.
132 }
Glen Stark72d51e02016-06-08 01:23:32 +0200133};
134
Victor Zverovich751ff642016-11-19 08:40:24 -0800135// Converts an integer argument to T for printf, if T is an integral type.
136// If T is void, the argument is converted to corresponding signed or unsigned
137// type depending on the type specifier: 'd' and 'i' - signed, other -
138// unsigned).
Victor Zverovichd705d512016-12-29 09:07:39 -0800139template <typename T, typename Context, typename Char>
Victor Zverovich7ae8bd72017-02-05 06:09:06 -0800140void convert_arg(basic_arg<Context> &arg, Char type) {
Victor Zverovichd705d512016-12-29 09:07:39 -0800141 visit(ArgConverter<T, Context>(arg, type), arg);
Victor Zverovich751ff642016-11-19 08:40:24 -0800142}
143
Glen Stark72d51e02016-06-08 01:23:32 +0200144// Converts an integer argument to char for printf.
Victor Zverovichd705d512016-12-29 09:07:39 -0800145template <typename Context>
Victor Zveroviche2dfd392016-11-19 09:29:09 -0800146class CharConverter {
Glen Stark72d51e02016-06-08 01:23:32 +0200147 private:
Victor Zverovich7ae8bd72017-02-05 06:09:06 -0800148 basic_arg<Context> &arg_;
Glen Stark72d51e02016-06-08 01:23:32 +0200149
150 FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter);
151
152 public:
Victor Zverovich7ae8bd72017-02-05 06:09:06 -0800153 explicit CharConverter(basic_arg<Context> &arg) : arg_(arg) {}
Glen Stark72d51e02016-06-08 01:23:32 +0200154
155 template <typename T>
Victor Zveroviche2dfd392016-11-19 09:29:09 -0800156 typename std::enable_if<std::is_integral<T>::value>::type
157 operator()(T value) {
Victor Zverovichd705d512016-12-29 09:07:39 -0800158 arg_ = internal::make_arg<Context>(static_cast<char>(value));
Glen Stark72d51e02016-06-08 01:23:32 +0200159 }
Victor Zveroviche2dfd392016-11-19 09:29:09 -0800160
161 template <typename T>
Victor Zverovichd705d512016-12-29 09:07:39 -0800162 typename std::enable_if<!std::is_integral<T>::value>::type operator()(T) {
Victor Zveroviche2dfd392016-11-19 09:29:09 -0800163 // No coversion needed for non-integral types.
164 }
Glen Stark72d51e02016-06-08 01:23:32 +0200165};
166
167// Checks if an argument is a valid printf width specifier and sets
168// left alignment if it is negative.
Victor Zverovichbf0f1072017-01-28 13:17:47 +0000169template <typename Char>
Victor Zverovich0854f8c2016-12-11 13:22:45 -0800170class PrintfWidthHandler {
Glen Stark72d51e02016-06-08 01:23:32 +0200171 private:
Victor Zverovichbf0f1072017-01-28 13:17:47 +0000172 typedef basic_format_specs<Char> format_specs;
173
Victor Zverovich296e9ca2017-01-28 12:51:35 +0000174 format_specs &spec_;
Glen Stark72d51e02016-06-08 01:23:32 +0200175
Victor Zverovich0854f8c2016-12-11 13:22:45 -0800176 FMT_DISALLOW_COPY_AND_ASSIGN(PrintfWidthHandler);
Glen Stark72d51e02016-06-08 01:23:32 +0200177
178 public:
Victor Zverovich296e9ca2017-01-28 12:51:35 +0000179 explicit PrintfWidthHandler(format_specs &spec) : spec_(spec) {}
Glen Stark72d51e02016-06-08 01:23:32 +0200180
Glen Stark72d51e02016-06-08 01:23:32 +0200181 template <typename T>
Victor Zveroviche2dfd392016-11-19 09:29:09 -0800182 typename std::enable_if<std::is_integral<T>::value, unsigned>::type
183 operator()(T value) {
Victor Zverovich6a2ff282017-02-19 06:46:51 -0800184 typedef typename internal::int_traits<T>::main_type UnsignedType;
Glen Stark72d51e02016-06-08 01:23:32 +0200185 UnsignedType width = static_cast<UnsignedType>(value);
186 if (internal::is_negative(value)) {
187 spec_.align_ = ALIGN_LEFT;
188 width = 0 - width;
189 }
Victor Zveroviche0d6f632016-06-15 06:29:47 -0700190 unsigned int_max = std::numeric_limits<int>::max();
191 if (width > int_max)
Victor Zverovich9bb213e2016-08-25 08:38:07 -0700192 FMT_THROW(format_error("number is too big"));
Glen Stark72d51e02016-06-08 01:23:32 +0200193 return static_cast<unsigned>(width);
194 }
Victor Zveroviche2dfd392016-11-19 09:29:09 -0800195
196 template <typename T>
197 typename std::enable_if<!std::is_integral<T>::value, unsigned>::type
Victor Zverovich77c892c2017-08-27 08:16:46 -0700198 operator()(T) {
Victor Zveroviche2dfd392016-11-19 09:29:09 -0800199 FMT_THROW(format_error("width is not integer"));
200 return 0;
201 }
Glen Stark72d51e02016-06-08 01:23:32 +0200202};
Victor Zverovich6ee9f2e2016-07-21 06:59:28 -0700203} // namespace internal
Glen Stark72d51e02016-06-08 01:23:32 +0200204
Victor Zverovich6ee9f2e2016-07-21 06:59:28 -0700205/**
206 \rst
Victor Zverovichd58cc8a2016-11-20 07:42:38 -0800207 The ``printf`` argument formatter.
Victor Zverovich6ee9f2e2016-07-21 06:59:28 -0700208 \endrst
209 */
Victor Zverovichd58cc8a2016-11-20 07:42:38 -0800210template <typename Char>
Victor Zverovichc333dca2017-02-19 08:41:38 -0800211class printf_arg_formatter : public internal::arg_formatter_base<Char> {
Glen Stark72d51e02016-06-08 01:23:32 +0200212 private:
213 void write_null_pointer() {
214 this->spec().type_ = 0;
215 this->write("(nil)");
216 }
217
Victor Zverovichc333dca2017-02-19 08:41:38 -0800218 typedef internal::arg_formatter_base<Char> Base;
Glen Stark72d51e02016-06-08 01:23:32 +0200219
220 public:
Victor Zverovichbf0f1072017-01-28 13:17:47 +0000221 typedef typename Base::format_specs format_specs;
222
Victor Zverovich6ee9f2e2016-07-21 06:59:28 -0700223 /**
224 \rst
225 Constructs an argument formatter object.
Victor Zverovichfefaf072017-02-14 16:29:47 -0500226 *buffer* is a reference to the output buffer and *spec* contains format
Victor Zverovich6ee9f2e2016-07-21 06:59:28 -0700227 specifier information for standard argument types.
228 \endrst
229 */
Victor Zverovich4ec88602017-02-18 07:46:32 -0800230 printf_arg_formatter(basic_buffer<Char> &buffer, format_specs &spec)
Victor Zverovichc333dca2017-02-19 08:41:38 -0800231 : internal::arg_formatter_base<Char>(buffer, spec) {}
Glen Stark72d51e02016-06-08 01:23:32 +0200232
Victor Zverovich95a53e12016-11-19 07:39:07 -0800233 using Base::operator();
234
Victor Zverovich6ee9f2e2016-07-21 06:59:28 -0700235 /** Formats an argument of type ``bool``. */
Victor Zverovich95a53e12016-11-19 07:39:07 -0800236 void operator()(bool value) {
Victor Zverovich296e9ca2017-01-28 12:51:35 +0000237 format_specs &fmt_spec = this->spec();
Glen Stark72d51e02016-06-08 01:23:32 +0200238 if (fmt_spec.type_ != 's')
Victor Zverovichd58cc8a2016-11-20 07:42:38 -0800239 return (*this)(value ? 1 : 0);
Glen Stark72d51e02016-06-08 01:23:32 +0200240 fmt_spec.type_ = 0;
241 this->write(value);
242 }
243
Victor Zverovich6ee9f2e2016-07-21 06:59:28 -0700244 /** Formats a character. */
Victor Zverovich0854f8c2016-12-11 13:22:45 -0800245 void operator()(Char value) {
Victor Zverovich296e9ca2017-01-28 12:51:35 +0000246 const format_specs &fmt_spec = this->spec();
Victor Zverovich84286212016-12-30 12:11:27 -0800247 basic_writer<Char> &w = this->writer();
Glen Stark72d51e02016-06-08 01:23:32 +0200248 if (fmt_spec.type_ && fmt_spec.type_ != 'c')
249 w.write_int(value, fmt_spec);
Victor Zverovich84286212016-12-30 12:11:27 -0800250 typedef typename basic_writer<Char>::CharPtr CharPtr;
Glen Stark72d51e02016-06-08 01:23:32 +0200251 CharPtr out = CharPtr();
252 if (fmt_spec.width_ > 1) {
253 Char fill = ' ';
254 out = w.grow_buffer(fmt_spec.width_);
255 if (fmt_spec.align_ != ALIGN_LEFT) {
256 std::fill_n(out, fmt_spec.width_ - 1, fill);
257 out += fmt_spec.width_ - 1;
258 } else {
259 std::fill_n(out + 1, fmt_spec.width_ - 1, fill);
260 }
261 } else {
262 out = w.grow_buffer(1);
263 }
264 *out = static_cast<Char>(value);
265 }
266
Victor Zverovich6ee9f2e2016-07-21 06:59:28 -0700267 /** Formats a null-terminated C string. */
Victor Zverovich95a53e12016-11-19 07:39:07 -0800268 void operator()(const char *value) {
Glen Stark72d51e02016-06-08 01:23:32 +0200269 if (value)
Victor Zverovich95a53e12016-11-19 07:39:07 -0800270 Base::operator()(value);
Glen Stark72d51e02016-06-08 01:23:32 +0200271 else if (this->spec().type_ == 'p')
272 write_null_pointer();
273 else
274 this->write("(null)");
275 }
276
Victor Zverovich6ee9f2e2016-07-21 06:59:28 -0700277 /** Formats a pointer. */
Victor Zverovich95a53e12016-11-19 07:39:07 -0800278 void operator()(const void *value) {
Glen Stark72d51e02016-06-08 01:23:32 +0200279 if (value)
Victor Zverovich95a53e12016-11-19 07:39:07 -0800280 return Base::operator()(value);
Glen Stark72d51e02016-06-08 01:23:32 +0200281 this->spec().type_ = 0;
282 write_null_pointer();
283 }
284
Victor Zverovich6ee9f2e2016-07-21 06:59:28 -0700285 /** Formats an argument of a custom (user-defined) type. */
Victor Zverovich6a2ff282017-02-19 06:46:51 -0800286 void operator()(internal::custom_value<Char> c) {
Victor Zverovich5e0562a2017-08-13 13:09:02 -0700287 const Char format_str_data[] = {'}', '\0'};
288 basic_string_view<Char> format_str = format_str_data;
Victor Zverovich624c5862017-02-05 06:41:39 -0800289 auto args = basic_args<basic_context<Char>>();
Victor Zverovich5e0562a2017-08-13 13:09:02 -0700290 basic_context<Char> ctx(args);
291 c.format(this->writer().buffer(), c.value, format_str, &ctx);
292 }
293};
294
295template <typename Char,
296 typename ArgFormatter = printf_arg_formatter<Char> >
297class printf_context;
298
299template <typename T, typename Char = char>
300struct printf_formatter {
301 const Char *parse(basic_string_view<Char> s) {
302 return s.data();
303 }
304
305 void format(basic_buffer<Char> &buf, const T &value, printf_context<Char> &) {
306 internal::format_value(buf, value);
Glen Stark72d51e02016-06-08 01:23:32 +0200307 }
308};
309
Victor Zverovichd4ddaaf2016-07-20 08:09:14 -0700310/** This template formats data and writes the output to a writer. */
Victor Zverovich5e0562a2017-08-13 13:09:02 -0700311template <typename Char, typename ArgFormatter>
Victor Zverovich9998f662016-11-06 16:11:24 -0800312class printf_context :
Victor Zverovich624c5862017-02-05 06:41:39 -0800313 private internal::context_base<
Victor Zverovich9998f662016-11-06 16:11:24 -0800314 Char, printf_context<Char, ArgFormatter>> {
Victor Zverovich18dfa252016-10-21 06:46:21 -0700315 public:
316 /** The character type for the output. */
Victor Zverovich5e0562a2017-08-13 13:09:02 -0700317 using char_type = Char;
318
319 template <typename T>
320 using formatter_type = printf_formatter<T>;
Victor Zverovich18dfa252016-10-21 06:46:21 -0700321
Glen Stark72d51e02016-06-08 01:23:32 +0200322 private:
Victor Zverovich624c5862017-02-05 06:41:39 -0800323 typedef internal::context_base<Char, printf_context> Base;
Victor Zverovichd705d512016-12-29 09:07:39 -0800324 typedef typename Base::format_arg format_arg;
Victor Zverovichbf0f1072017-01-28 13:17:47 +0000325 typedef basic_format_specs<Char> format_specs;
Victor Zverovich5e0562a2017-08-13 13:09:02 -0700326 typedef internal::null_terminating_iterator<Char> iterator;
Victor Zverovichdafbec72016-10-07 08:37:06 -0700327
Victor Zverovich2f4f49f2017-07-18 19:40:48 -0700328 void parse_flags(format_specs &spec, iterator &it);
Glen Stark72d51e02016-06-08 01:23:32 +0200329
330 // Returns the argument with specified index or, if arg_index is equal
331 // to the maximum unsigned value, the next argument.
Victor Zverovichd705d512016-12-29 09:07:39 -0800332 format_arg get_arg(
Victor Zverovich2f4f49f2017-07-18 19:40:48 -0700333 iterator it,
Glen Stark72d51e02016-06-08 01:23:32 +0200334 unsigned arg_index = (std::numeric_limits<unsigned>::max)());
335
336 // Parses argument index, flags and width and returns the argument index.
Victor Zverovich2f4f49f2017-07-18 19:40:48 -0700337 unsigned parse_header(iterator &it, format_specs &spec);
Glen Stark72d51e02016-06-08 01:23:32 +0200338
339 public:
Victor Zverovichd4ddaaf2016-07-20 08:09:14 -0700340 /**
341 \rst
Victor Zverovich9998f662016-11-06 16:11:24 -0800342 Constructs a ``printf_context`` object. References to the arguments and
343 the writer are stored in the context object so make sure they have
Victor Zverovichab054532016-07-20 08:21:13 -0700344 appropriate lifetimes.
Victor Zverovichd4ddaaf2016-07-20 08:09:14 -0700345 \endrst
346 */
Victor Zverovich5e0562a2017-08-13 13:09:02 -0700347 explicit printf_context(basic_args<printf_context> args): Base(args) {}
Victor Zverovich9998f662016-11-06 16:11:24 -0800348
Victor Zverovichfefaf072017-02-14 16:29:47 -0500349 /** Formats stored arguments and writes the output to the buffer. */
Victor Zverovich5e0562a2017-08-13 13:09:02 -0700350 FMT_API void format(
351 basic_string_view<Char> format_str, basic_buffer<Char> &buffer);
Glen Stark72d51e02016-06-08 01:23:32 +0200352};
353
354template <typename Char, typename AF>
Victor Zverovich2f4f49f2017-07-18 19:40:48 -0700355void printf_context<Char, AF>::parse_flags(format_specs &spec, iterator &it) {
Glen Stark72d51e02016-06-08 01:23:32 +0200356 for (;;) {
Victor Zverovich2f4f49f2017-07-18 19:40:48 -0700357 switch (*it++) {
Glen Stark72d51e02016-06-08 01:23:32 +0200358 case '-':
359 spec.align_ = ALIGN_LEFT;
360 break;
361 case '+':
362 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
363 break;
364 case '0':
365 spec.fill_ = '0';
366 break;
367 case ' ':
368 spec.flags_ |= SIGN_FLAG;
369 break;
370 case '#':
371 spec.flags_ |= HASH_FLAG;
372 break;
373 default:
Victor Zverovich2f4f49f2017-07-18 19:40:48 -0700374 --it;
Glen Stark72d51e02016-06-08 01:23:32 +0200375 return;
376 }
377 }
378}
379
380template <typename Char, typename AF>
Victor Zverovichd705d512016-12-29 09:07:39 -0800381typename printf_context<Char, AF>::format_arg printf_context<Char, AF>::get_arg(
Victor Zverovich2f4f49f2017-07-18 19:40:48 -0700382 iterator it, unsigned arg_index) {
383 (void)it;
Glen Stark72d51e02016-06-08 01:23:32 +0200384 const char *error = 0;
Victor Zverovich1102d462017-07-30 08:37:26 -0700385 format_arg arg;
386 if (arg_index == std::numeric_limits<unsigned>::max()) {
387 arg_index = this->next_arg_index(error);
388 if (!error)
389 arg = this->do_get_arg(arg_index, error);
390 } else {
391 arg = Base::get_arg(arg_index - 1, error);
392 }
Glen Stark72d51e02016-06-08 01:23:32 +0200393 if (error)
Victor Zverovich2f4f49f2017-07-18 19:40:48 -0700394 FMT_THROW(format_error(!*it ? "invalid format string" : error));
Glen Stark72d51e02016-06-08 01:23:32 +0200395 return arg;
396}
397
398template <typename Char, typename AF>
Victor Zverovich9998f662016-11-06 16:11:24 -0800399unsigned printf_context<Char, AF>::parse_header(
Victor Zverovich2f4f49f2017-07-18 19:40:48 -0700400 iterator &it, format_specs &spec) {
Glen Stark72d51e02016-06-08 01:23:32 +0200401 unsigned arg_index = std::numeric_limits<unsigned>::max();
Victor Zverovich2f4f49f2017-07-18 19:40:48 -0700402 Char c = *it;
Glen Stark72d51e02016-06-08 01:23:32 +0200403 if (c >= '0' && c <= '9') {
404 // Parse an argument index (if followed by '$') or a width possibly
405 // preceded with '0' flag(s).
Victor Zverovich2f4f49f2017-07-18 19:40:48 -0700406 unsigned value = internal::parse_nonnegative_int(it);
407 if (*it == '$') { // value is an argument index
408 ++it;
Glen Stark72d51e02016-06-08 01:23:32 +0200409 arg_index = value;
410 } else {
411 if (c == '0')
412 spec.fill_ = '0';
413 if (value != 0) {
414 // Nonzero value means that we parsed width and don't need to
415 // parse it or flags again, so return now.
416 spec.width_ = value;
417 return arg_index;
418 }
419 }
420 }
Victor Zverovich2f4f49f2017-07-18 19:40:48 -0700421 parse_flags(spec, it);
Glen Stark72d51e02016-06-08 01:23:32 +0200422 // Parse width.
Victor Zverovich2f4f49f2017-07-18 19:40:48 -0700423 if (*it >= '0' && *it <= '9') {
424 spec.width_ = internal::parse_nonnegative_int(it);
425 } else if (*it == '*') {
426 ++it;
427 spec.width_ = visit(internal::PrintfWidthHandler<Char>(spec), get_arg(it));
Glen Stark72d51e02016-06-08 01:23:32 +0200428 }
429 return arg_index;
430}
431
432template <typename Char, typename AF>
Victor Zverovich5e0562a2017-08-13 13:09:02 -0700433void printf_context<Char, AF>::format(
434 basic_string_view<Char> format_str, basic_buffer<Char> &buffer) {
435 auto start = iterator(format_str);
Victor Zverovich2f4f49f2017-07-18 19:40:48 -0700436 auto it = start;
437 using internal::pointer_from;
438 while (*it) {
439 Char c = *it++;
Glen Stark72d51e02016-06-08 01:23:32 +0200440 if (c != '%') continue;
Victor Zverovich2f4f49f2017-07-18 19:40:48 -0700441 if (*it == c) {
442 buffer.append(pointer_from(start), pointer_from(it));
443 start = ++it;
Glen Stark72d51e02016-06-08 01:23:32 +0200444 continue;
445 }
Victor Zverovich2f4f49f2017-07-18 19:40:48 -0700446 buffer.append(pointer_from(start), pointer_from(it) - 1);
Glen Stark72d51e02016-06-08 01:23:32 +0200447
Victor Zverovich296e9ca2017-01-28 12:51:35 +0000448 format_specs spec;
Glen Stark72d51e02016-06-08 01:23:32 +0200449 spec.align_ = ALIGN_RIGHT;
450
451 // Parse argument index, flags and width.
Victor Zverovich2f4f49f2017-07-18 19:40:48 -0700452 unsigned arg_index = parse_header(it, spec);
Glen Stark72d51e02016-06-08 01:23:32 +0200453
454 // Parse precision.
Victor Zverovich2f4f49f2017-07-18 19:40:48 -0700455 if (*it == '.') {
456 ++it;
457 if ('0' <= *it && *it <= '9') {
458 spec.precision_ = static_cast<int>(internal::parse_nonnegative_int(it));
459 } else if (*it == '*') {
460 ++it;
461 spec.precision_ =
462 visit(internal::PrintfPrecisionHandler(), get_arg(it));
Glen Stark72d51e02016-06-08 01:23:32 +0200463 }
464 }
465
Victor Zverovich2f4f49f2017-07-18 19:40:48 -0700466 format_arg arg = get_arg(it, arg_index);
Victor Zverovichc9dc41a2016-11-19 07:59:54 -0800467 if (spec.flag(HASH_FLAG) && visit(internal::IsZeroInt(), arg))
Victor Zverovichd4ddaaf2016-07-20 08:09:14 -0700468 spec.flags_ &= ~internal::to_unsigned<int>(HASH_FLAG);
Glen Stark72d51e02016-06-08 01:23:32 +0200469 if (spec.fill_ == '0') {
Victor Zverovich0854f8c2016-12-11 13:22:45 -0800470 if (arg.is_numeric())
Glen Stark72d51e02016-06-08 01:23:32 +0200471 spec.align_ = ALIGN_NUMERIC;
472 else
473 spec.fill_ = ' '; // Ignore '0' flag for non-numeric types.
474 }
475
476 // Parse length and convert the argument to the required type.
Victor Zverovich751ff642016-11-19 08:40:24 -0800477 using internal::convert_arg;
Victor Zverovich2f4f49f2017-07-18 19:40:48 -0700478 switch (*it++) {
Glen Stark72d51e02016-06-08 01:23:32 +0200479 case 'h':
Victor Zverovich2f4f49f2017-07-18 19:40:48 -0700480 if (*it == 'h')
481 convert_arg<signed char>(arg, *++it);
Glen Stark72d51e02016-06-08 01:23:32 +0200482 else
Victor Zverovich2f4f49f2017-07-18 19:40:48 -0700483 convert_arg<short>(arg, *it);
Glen Stark72d51e02016-06-08 01:23:32 +0200484 break;
485 case 'l':
Victor Zverovich2f4f49f2017-07-18 19:40:48 -0700486 if (*it == 'l')
Victor Zverovich016aceb2017-08-26 09:09:43 -0700487 convert_arg<long long>(arg, *++it);
Glen Stark72d51e02016-06-08 01:23:32 +0200488 else
Victor Zverovich2f4f49f2017-07-18 19:40:48 -0700489 convert_arg<long>(arg, *it);
Glen Stark72d51e02016-06-08 01:23:32 +0200490 break;
491 case 'j':
Victor Zverovich2f4f49f2017-07-18 19:40:48 -0700492 convert_arg<intmax_t>(arg, *it);
Glen Stark72d51e02016-06-08 01:23:32 +0200493 break;
494 case 'z':
Victor Zverovich2f4f49f2017-07-18 19:40:48 -0700495 convert_arg<std::size_t>(arg, *it);
Glen Stark72d51e02016-06-08 01:23:32 +0200496 break;
497 case 't':
Victor Zverovich2f4f49f2017-07-18 19:40:48 -0700498 convert_arg<std::ptrdiff_t>(arg, *it);
Glen Stark72d51e02016-06-08 01:23:32 +0200499 break;
500 case 'L':
501 // printf produces garbage when 'L' is omitted for long double, no
502 // need to do the same.
503 break;
504 default:
Victor Zverovich2f4f49f2017-07-18 19:40:48 -0700505 --it;
506 convert_arg<void>(arg, *it);
Glen Stark72d51e02016-06-08 01:23:32 +0200507 }
508
509 // Parse type.
Victor Zverovich2f4f49f2017-07-18 19:40:48 -0700510 if (!*it)
Victor Zverovich9bb213e2016-08-25 08:38:07 -0700511 FMT_THROW(format_error("invalid format string"));
Victor Zverovich2f4f49f2017-07-18 19:40:48 -0700512 spec.type_ = static_cast<char>(*it++);
Victor Zverovich0854f8c2016-12-11 13:22:45 -0800513 if (arg.is_integral()) {
Glen Stark72d51e02016-06-08 01:23:32 +0200514 // Normalize type.
515 switch (spec.type_) {
516 case 'i': case 'u':
517 spec.type_ = 'd';
518 break;
519 case 'c':
520 // TODO: handle wchar_t
Victor Zverovichd705d512016-12-29 09:07:39 -0800521 visit(internal::CharConverter<printf_context<Char, AF>>(arg), arg);
Glen Stark72d51e02016-06-08 01:23:32 +0200522 break;
523 }
524 }
525
Victor Zverovich2f4f49f2017-07-18 19:40:48 -0700526 start = it;
Glen Stark72d51e02016-06-08 01:23:32 +0200527
528 // Format argument.
Victor Zverovichfefaf072017-02-14 16:29:47 -0500529 visit(AF(buffer, spec), arg);
Glen Stark72d51e02016-06-08 01:23:32 +0200530 }
Victor Zverovich2f4f49f2017-07-18 19:40:48 -0700531 buffer.append(pointer_from(start), pointer_from(it));
Glen Stark72d51e02016-06-08 01:23:32 +0200532}
Glen Stark72d51e02016-06-08 01:23:32 +0200533
534template <typename Char>
Victor Zverovich2f4f49f2017-07-18 19:40:48 -0700535void printf(basic_buffer<Char> &buf, basic_string_view<Char> format,
Victor Zverovich7ae8bd72017-02-05 06:09:06 -0800536 basic_args<printf_context<Char>> args) {
Victor Zverovich5e0562a2017-08-13 13:09:02 -0700537 printf_context<Char>(args).format(format, buf);
Glen Stark72d51e02016-06-08 01:23:32 +0200538}
539
Victor Zverovich7ae8bd72017-02-05 06:09:06 -0800540typedef basic_args<printf_context<char>> printf_args;
Victor Zverovich0854f8c2016-12-11 13:22:45 -0800541
Victor Zverovich2f4f49f2017-07-18 19:40:48 -0700542inline std::string vsprintf(string_view format, printf_args args) {
Victor Zverovicheedfd072017-02-18 09:13:12 -0800543 memory_buffer buffer;
Victor Zverovichfefaf072017-02-14 16:29:47 -0500544 printf(buffer, format, args);
545 return to_string(buffer);
Victor Zverovich0028ce52016-08-26 17:23:13 -0700546}
547
Glen Stark72d51e02016-06-08 01:23:32 +0200548/**
549 \rst
550 Formats arguments and returns the result as a string.
551
552 **Example**::
553
554 std::string message = fmt::sprintf("The answer is %d", 42);
555 \endrst
556*/
Victor Zverovich0028ce52016-08-26 17:23:13 -0700557template <typename... Args>
Victor Zverovich2f4f49f2017-07-18 19:40:48 -0700558inline std::string sprintf(string_view format_str, const Args & ... args) {
Victor Zverovich624c5862017-02-05 06:41:39 -0800559 return vsprintf(format_str, make_args<printf_context<char>>(args...));
Glen Stark72d51e02016-06-08 01:23:32 +0200560}
Glen Stark72d51e02016-06-08 01:23:32 +0200561
Victor Zverovich0854f8c2016-12-11 13:22:45 -0800562inline std::wstring vsprintf(
Victor Zverovich2f4f49f2017-07-18 19:40:48 -0700563 wstring_view format, basic_args<printf_context<wchar_t>> args) {
Victor Zverovicheedfd072017-02-18 09:13:12 -0800564 wmemory_buffer buffer;
Victor Zverovichfefaf072017-02-14 16:29:47 -0500565 printf(buffer, format, args);
566 return to_string(buffer);
Glen Stark72d51e02016-06-08 01:23:32 +0200567}
Victor Zverovich0028ce52016-08-26 17:23:13 -0700568
569template <typename... Args>
Victor Zverovich2f4f49f2017-07-18 19:40:48 -0700570inline std::wstring sprintf(wstring_view format_str, const Args & ... args) {
Victor Zverovich624c5862017-02-05 06:41:39 -0800571 auto vargs = make_args<printf_context<wchar_t>>(args...);
Victor Zverovich0028ce52016-08-26 17:23:13 -0700572 return vsprintf(format_str, vargs);
573}
574
Victor Zverovich2f4f49f2017-07-18 19:40:48 -0700575FMT_API int vfprintf(std::FILE *f, string_view format, printf_args args);
Glen Stark72d51e02016-06-08 01:23:32 +0200576
577/**
578 \rst
579 Prints formatted data to the file *f*.
580
581 **Example**::
582
583 fmt::fprintf(stderr, "Don't %s!", "panic");
584 \endrst
585 */
Victor Zverovich0028ce52016-08-26 17:23:13 -0700586template <typename... Args>
Victor Zverovich2f4f49f2017-07-18 19:40:48 -0700587inline int fprintf(std::FILE *f, string_view format_str, const Args & ... args) {
Victor Zverovich624c5862017-02-05 06:41:39 -0800588 auto vargs = make_args<printf_context<char>>(args...);
Victor Zverovich0028ce52016-08-26 17:23:13 -0700589 return vfprintf(f, format_str, vargs);
590}
591
Victor Zverovich2f4f49f2017-07-18 19:40:48 -0700592inline int vprintf(string_view format, printf_args args) {
Victor Zverovich0028ce52016-08-26 17:23:13 -0700593 return vfprintf(stdout, format, args);
594}
Glen Stark72d51e02016-06-08 01:23:32 +0200595
596/**
597 \rst
598 Prints formatted data to ``stdout``.
599
600 **Example**::
601
602 fmt::printf("Elapsed time: %.2f seconds", 1.23);
603 \endrst
604 */
Victor Zverovich0028ce52016-08-26 17:23:13 -0700605template <typename... Args>
Victor Zverovich2f4f49f2017-07-18 19:40:48 -0700606inline int printf(string_view format_str, const Args & ... args) {
Victor Zverovich624c5862017-02-05 06:41:39 -0800607 return vprintf(format_str, make_args<printf_context<char>>(args...));
Glen Stark72d51e02016-06-08 01:23:32 +0200608}
Victor Zverovich0028ce52016-08-26 17:23:13 -0700609
Victor Zverovich2f4f49f2017-07-18 19:40:48 -0700610inline int vfprintf(std::ostream &os, string_view format_str, printf_args args) {
Victor Zverovicheedfd072017-02-18 09:13:12 -0800611 memory_buffer buffer;
Victor Zverovichfefaf072017-02-14 16:29:47 -0500612 printf(buffer, format_str, args);
613 internal::write(os, buffer);
614 return static_cast<int>(buffer.size());
Victor Zverovich0028ce52016-08-26 17:23:13 -0700615}
Victor Zverovich9dbb60c2016-08-03 08:52:05 -0700616
617/**
618 \rst
619 Prints formatted data to the stream *os*.
620
621 **Example**::
622
623 fprintf(cerr, "Don't %s!", "panic");
624 \endrst
625 */
Victor Zverovich0028ce52016-08-26 17:23:13 -0700626template <typename... Args>
Victor Zverovich2f4f49f2017-07-18 19:40:48 -0700627inline int fprintf(std::ostream &os, string_view format_str,
Victor Zverovich0028ce52016-08-26 17:23:13 -0700628 const Args & ... args) {
Victor Zverovich624c5862017-02-05 06:41:39 -0800629 auto vargs = make_args<printf_context<char>>(args...);
Victor Zverovich0028ce52016-08-26 17:23:13 -0700630 return vfprintf(os, format_str, vargs);
Victor Zverovich9dbb60c2016-08-03 08:52:05 -0700631}
Glen Stark72d51e02016-06-08 01:23:32 +0200632} // namespace fmt
633
634#endif // FMT_PRINTF_H_