blob: eb76e02aaca398af187dd6dfb7bb2e09988a4c09 [file] [log] [blame]
Victor Zverovichb076df42012-12-07 08:31:09 -08001/*
Victor Zverovichfaccb4c2012-12-12 07:44:41 -08002 String formatting library for C++
3
4 Copyright (c) 2012, Victor Zverovich
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9
10 1. Redistributions of source code must retain the above copyright notice, this
11 list of conditions and the following disclaimer.
12 2. Redistributions in binary form must reproduce the above copyright notice,
13 this list of conditions and the following disclaimer in the documentation
14 and/or other materials provided with the distribution.
15
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Victor Zverovichb076df42012-12-07 08:31:09 -080026 */
27
Victor Zverovichd53f2092012-12-16 15:06:31 -080028// Disable useless MSVC warnings.
Victor Zverovichf8c91062012-12-17 15:41:00 -080029#undef _CRT_SECURE_NO_WARNINGS
Victor Zverovichd53f2092012-12-16 15:06:31 -080030#define _CRT_SECURE_NO_WARNINGS
Victor Zverovichc240a122012-12-21 15:02:25 -080031#undef _SCL_SECURE_NO_WARNINGS
32#define _SCL_SECURE_NO_WARNINGS
Victor Zverovichd53f2092012-12-16 15:06:31 -080033
Victor Zverovichb076df42012-12-07 08:31:09 -080034#include "format.h"
35
Victor Zverovichce604832012-12-28 08:27:54 -080036#include <math.h>
Victor Zverovichb98b2e92012-12-10 11:08:16 -080037
Victor Zverovichb076df42012-12-07 08:31:09 -080038#include <cassert>
Victor Zverovich72f896d2012-12-12 09:17:28 -080039#include <cctype>
Victor Zverovich63539c02012-12-08 08:17:12 -080040#include <climits>
Victor Zverovichb076df42012-12-07 08:31:09 -080041#include <cstring>
42#include <algorithm>
43
44using std::size_t;
Victor Zverovich3f739872012-12-25 17:55:41 -080045using fmt::BasicFormatter;
Victor Zverovich877abaf2013-01-08 09:56:05 -080046using fmt::IntFormatter;
Victor Zverovich36335272012-12-12 15:21:11 -080047using fmt::Formatter;
Victor Zverovich3c90a872013-01-12 10:08:16 -080048using fmt::AlignSpec;
Victor Zverovichf28ecaf2012-12-21 09:14:18 -080049using fmt::FormatSpec;
Victor Zverovich877abaf2013-01-08 09:56:05 -080050using fmt::WidthSpec;
Victor Zverovich0f46a3d2012-12-25 13:30:42 -080051using fmt::StringRef;
Victor Zverovichb076df42012-12-07 08:31:09 -080052
Victor Zveroviche8ba9602012-12-12 09:29:50 -080053#if _MSC_VER
Victor Zverovichf8c91062012-12-17 15:41:00 -080054# undef snprintf
Victor Zveroviche8ba9602012-12-12 09:29:50 -080055# define snprintf _snprintf
Victor Zverovich251e8772012-12-29 09:54:57 -080056# define isinf(x) (!_finite(x))
Victor Zveroviche8ba9602012-12-12 09:29:50 -080057#endif
58
Victor Zverovich8b1c7092012-12-08 18:45:35 -080059namespace {
60
Victor Zverovichb98b2e92012-12-10 11:08:16 -080061template <typename T>
62struct IsLongDouble { enum {VALUE = 0}; };
63
64template <>
65struct IsLongDouble<long double> { enum {VALUE = 1}; };
Victor Zverovichccbe9412012-12-24 08:34:44 -080066
Victor Zverovichd9633792012-12-25 09:00:11 -080067const char DIGITS[] =
68 "0001020304050607080910111213141516171819"
69 "2021222324252627282930313233343536373839"
70 "4041424344454647484950515253545556575859"
71 "6061626364656667686970717273747576777879"
72 "8081828384858687888990919293949596979899";
73
Victor Zverovich84310c32012-12-24 19:37:50 -080074// Fills the padding around the content and returns the pointer to the
75// content area.
76char *FillPadding(char *buffer,
Victor Zverovich3f739872012-12-25 17:55:41 -080077 unsigned total_size, std::size_t content_size, char fill) {
Victor Zverovich8412ad62012-12-27 06:56:55 -080078 std::size_t padding = total_size - content_size;
79 std::size_t left_padding = padding / 2;
Victor Zverovich84310c32012-12-24 19:37:50 -080080 std::fill_n(buffer, left_padding, fill);
81 buffer += left_padding;
82 char *content = buffer;
83 std::fill_n(buffer + content_size, padding - left_padding, fill);
84 return content;
85}
86
Victor Zverovichde17baa2013-01-04 09:14:34 -080087#ifdef _MSC_VER
88int signbit(double value) {
89 if (value < 0) return 1;
90 if (value == value) return 0;
91 int dec = 0, sign = 0;
92 _ecvt(value, 0, &dec, &sign);
93 return sign;
94}
95#endif
96}
97
Victor Zverovich877abaf2013-01-08 09:56:05 -080098void BasicFormatter::FormatDecimal(
99 char *buffer, uint64_t value, unsigned num_digits) {
100 --num_digits;
101 while (value >= 100) {
102 // Integer division is slow so do it for a group of two digits instead
103 // of for every digit. The idea comes from the talk by Alexandrescu
104 // "Three Optimization Tips for C++". See speed-test for a comparison.
105 unsigned index = (value % 100) * 2;
106 value /= 100;
107 buffer[num_digits] = DIGITS[index + 1];
108 buffer[num_digits - 1] = DIGITS[index];
109 num_digits -= 2;
110 }
111 if (value < 10) {
112 *buffer = static_cast<char>('0' + value);
113 return;
114 }
115 unsigned index = static_cast<unsigned>(value * 2);
116 buffer[1] = DIGITS[index + 1];
117 buffer[0] = DIGITS[index];
118}
119
120void BasicFormatter::ReportUnknownType(char code, const char *type) {
121 if (std::isprint(static_cast<unsigned char>(code))) {
122 throw fmt::FormatError(fmt::str(
123 fmt::Format("unknown format code '{0}' for {1}") << code << type));
124 }
125 throw fmt::FormatError(
126 fmt::str(fmt::Format("unknown format code '\\x{0:02x}' for {1}")
127 << static_cast<unsigned>(code) << type));
128}
129
Victor Zverovichde17baa2013-01-04 09:14:34 -0800130char *BasicFormatter::PrepareFilledBuffer(
Victor Zverovich877abaf2013-01-08 09:56:05 -0800131 unsigned size, const AlignSpec &spec, char sign) {
132 unsigned width = spec.width();
133 if (width <= size) {
Victor Zverovichbe6e54d2012-12-22 14:05:56 -0800134 char *p = GrowBuffer(size);
135 *p = sign;
136 return p + size - 1;
137 }
Victor Zverovich877abaf2013-01-08 09:56:05 -0800138 char *p = GrowBuffer(width);
139 char *end = p + width;
140 Alignment align = spec.align();
141 if (align == ALIGN_LEFT) {
Victor Zverovich84310c32012-12-24 19:37:50 -0800142 *p = sign;
143 p += size;
Victor Zverovich877abaf2013-01-08 09:56:05 -0800144 std::fill(p, end, spec.fill());
145 } else if (align == ALIGN_CENTER) {
146 p = FillPadding(p, width, size, spec.fill());
Victor Zverovich84310c32012-12-24 19:37:50 -0800147 *p = sign;
148 p += size;
149 } else {
Victor Zverovich877abaf2013-01-08 09:56:05 -0800150 if (align == ALIGN_NUMERIC) {
Victor Zverovich1b9c22c2012-12-22 17:53:13 -0800151 if (sign) {
152 *p++ = sign;
153 --size;
154 }
155 } else {
156 *(end - size) = sign;
157 }
Victor Zverovich877abaf2013-01-08 09:56:05 -0800158 std::fill(p, end - size, spec.fill());
Victor Zverovichbe6e54d2012-12-22 14:05:56 -0800159 p = end;
160 }
161 return p - 1;
162}
163
Victor Zverovichb076df42012-12-07 08:31:09 -0800164template <typename T>
Victor Zverovichde17baa2013-01-04 09:14:34 -0800165void BasicFormatter::FormatDouble(
166 T value, const FormatSpec &spec, int precision) {
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800167 // Check type.
Victor Zverovich877abaf2013-01-08 09:56:05 -0800168 char type = spec.type();
Victor Zverovichce604832012-12-28 08:27:54 -0800169 bool upper = false;
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800170 switch (type) {
Victor Zverovichd73306b2012-12-10 12:16:02 -0800171 case 0:
172 type = 'g';
173 break;
Victor Zverovichce604832012-12-28 08:27:54 -0800174 case 'e': case 'f': case 'g':
Victor Zverovicha2a87412012-12-12 10:11:40 -0800175 break;
176 case 'F':
Victor Zverovich36335272012-12-12 15:21:11 -0800177#ifdef _MSC_VER
178 // MSVC's printf doesn't support 'F'.
Victor Zverovicha2a87412012-12-12 10:11:40 -0800179 type = 'f';
Victor Zverovich36335272012-12-12 15:21:11 -0800180#endif
Victor Zverovichce604832012-12-28 08:27:54 -0800181 // Fall through.
182 case 'E': case 'G':
183 upper = true;
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800184 break;
185 default:
Victor Zverovichd599e3b2012-12-10 13:30:06 -0800186 ReportUnknownType(type, "double");
187 break;
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800188 }
189
Victor Zverovichccbe9412012-12-24 08:34:44 -0800190 char sign = 0;
Victor Zverovichce604832012-12-28 08:27:54 -0800191 // Use signbit instead of value < 0 because the latter is always
192 // false for NaN.
193 if (signbit(value)) {
Victor Zverovichccbe9412012-12-24 08:34:44 -0800194 sign = '-';
195 value = -value;
Victor Zverovich877abaf2013-01-08 09:56:05 -0800196 } else if (spec.sign_flag()) {
197 sign = spec.plus_flag() ? '+' : ' ';
Victor Zverovichccbe9412012-12-24 08:34:44 -0800198 }
Victor Zverovichce604832012-12-28 08:27:54 -0800199
Victor Zverovich529045b2012-12-28 09:41:03 -0800200 if (value != value) {
Victor Zverovichce604832012-12-28 08:27:54 -0800201 // Format NaN ourselves because sprintf's output is not consistent
202 // across platforms.
203 std::size_t size = 4;
204 const char *nan = upper ? " NAN" : " nan";
205 if (!sign) {
206 --size;
207 ++nan;
208 }
209 char *out = FormatString(nan, size, spec);
210 if (sign)
211 *out = sign;
212 return;
213 }
214
Victor Zverovich4762a8a2012-12-29 06:44:14 -0800215 if (isinf(value)) {
216 // Format infinity ourselves because sprintf's output is not consistent
217 // across platforms.
218 std::size_t size = 4;
219 const char *inf = upper ? " INF" : " inf";
220 if (!sign) {
221 --size;
222 ++inf;
223 }
224 char *out = FormatString(inf, size, spec);
225 if (sign)
226 *out = sign;
227 return;
228 }
229
Victor Zverovichccbe9412012-12-24 08:34:44 -0800230 size_t offset = buffer_.size();
Victor Zverovich877abaf2013-01-08 09:56:05 -0800231 unsigned width = spec.width();
Victor Zverovichccbe9412012-12-24 08:34:44 -0800232 if (sign) {
233 buffer_.reserve(buffer_.size() + std::max(width, 1u));
234 if (width > 0)
235 --width;
236 ++offset;
237 }
238
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800239 // Build format string.
Victor Zverovich73f13ee2012-12-25 18:19:51 -0800240 enum { MAX_FORMAT_SIZE = 10}; // longest format: %#-*.*Lg
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800241 char format[MAX_FORMAT_SIZE];
242 char *format_ptr = format;
243 *format_ptr++ = '%';
Victor Zverovich84310c32012-12-24 19:37:50 -0800244 unsigned width_for_sprintf = width;
Victor Zverovich877abaf2013-01-08 09:56:05 -0800245 if (spec.hash_flag())
Victor Zverovich73f13ee2012-12-25 18:19:51 -0800246 *format_ptr++ = '#';
Victor Zverovich877abaf2013-01-08 09:56:05 -0800247 if (spec.align() == ALIGN_CENTER) {
Victor Zverovich84310c32012-12-24 19:37:50 -0800248 width_for_sprintf = 0;
249 } else {
Victor Zverovich877abaf2013-01-08 09:56:05 -0800250 if (spec.align() == ALIGN_LEFT)
Victor Zverovich84310c32012-12-24 19:37:50 -0800251 *format_ptr++ = '-';
252 if (width != 0)
253 *format_ptr++ = '*';
254 }
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800255 if (precision >= 0) {
256 *format_ptr++ = '.';
257 *format_ptr++ = '*';
258 }
259 if (IsLongDouble<T>::VALUE)
260 *format_ptr++ = 'L';
Victor Zverovichd73306b2012-12-10 12:16:02 -0800261 *format_ptr++ = type;
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800262 *format_ptr = '\0';
263
264 // Format using snprintf.
Victor Zverovichb076df42012-12-07 08:31:09 -0800265 for (;;) {
Victor Zverovich198ebe92012-12-10 17:16:08 -0800266 size_t size = buffer_.capacity() - offset;
Victor Zverovichb076df42012-12-07 08:31:09 -0800267 int n = 0;
Victor Zverovicha0d685c2012-12-20 20:10:55 -0800268 char *start = &buffer_[offset];
Victor Zverovich84310c32012-12-24 19:37:50 -0800269 if (width_for_sprintf == 0) {
Victor Zverovichb076df42012-12-07 08:31:09 -0800270 n = precision < 0 ?
Victor Zverovicha0d685c2012-12-20 20:10:55 -0800271 snprintf(start, size, format, value) :
272 snprintf(start, size, format, precision, value);
Victor Zverovichb076df42012-12-07 08:31:09 -0800273 } else {
274 n = precision < 0 ?
Victor Zverovich84310c32012-12-24 19:37:50 -0800275 snprintf(start, size, format, width_for_sprintf, value) :
276 snprintf(start, size, format, width_for_sprintf, precision, value);
Victor Zverovichb076df42012-12-07 08:31:09 -0800277 }
Victor Zverovich198ebe92012-12-10 17:16:08 -0800278 if (n >= 0 && offset + n < buffer_.capacity()) {
Victor Zverovichccbe9412012-12-24 08:34:44 -0800279 if (sign) {
Victor Zverovich877abaf2013-01-08 09:56:05 -0800280 if ((spec.align() != ALIGN_RIGHT && spec.align() != ALIGN_DEFAULT) ||
Victor Zverovichccbe9412012-12-24 08:34:44 -0800281 *start != ' ') {
282 *(start - 1) = sign;
283 sign = 0;
284 } else {
Victor Zverovich877abaf2013-01-08 09:56:05 -0800285 *(start - 1) = spec.fill();
Victor Zverovichccbe9412012-12-24 08:34:44 -0800286 }
287 ++n;
288 }
Victor Zverovich877abaf2013-01-08 09:56:05 -0800289 if (spec.align() == ALIGN_CENTER &&
290 spec.width() > static_cast<unsigned>(n)) {
291 char *p = GrowBuffer(spec.width());
292 std::copy(p, p + n, p + (spec.width() - n) / 2);
293 FillPadding(p, spec.width(), n, spec.fill());
Victor Zverovich84310c32012-12-24 19:37:50 -0800294 return;
295 }
Victor Zverovich877abaf2013-01-08 09:56:05 -0800296 if (spec.fill() != ' ' || sign) {
Victor Zverovich64236892012-12-21 09:12:04 -0800297 while (*start == ' ')
Victor Zverovich877abaf2013-01-08 09:56:05 -0800298 *start++ = spec.fill();
Victor Zverovichccbe9412012-12-24 08:34:44 -0800299 if (sign)
300 *(start - 1) = sign;
Victor Zverovich64236892012-12-21 09:12:04 -0800301 }
Victor Zverovich14e0f872012-12-10 18:08:04 -0800302 GrowBuffer(n);
Victor Zverovichb076df42012-12-07 08:31:09 -0800303 return;
304 }
Victor Zverovich198ebe92012-12-10 17:16:08 -0800305 buffer_.reserve(n >= 0 ? offset + n + 1 : 2 * buffer_.capacity());
Victor Zverovichb076df42012-12-07 08:31:09 -0800306 }
307}
308
Victor Zverovichde17baa2013-01-04 09:14:34 -0800309char *BasicFormatter::FormatString(
Victor Zverovich1b9c22c2012-12-22 17:53:13 -0800310 const char *s, std::size_t size, const FormatSpec &spec) {
311 char *out = 0;
Victor Zverovich877abaf2013-01-08 09:56:05 -0800312 if (spec.width() > size) {
313 out = GrowBuffer(spec.width());
314 if (spec.align() == ALIGN_RIGHT) {
315 std::fill_n(out, spec.width() - size, spec.fill());
316 out += spec.width() - size;
317 } else if (spec.align() == ALIGN_CENTER) {
318 out = FillPadding(out, spec.width(), size, spec.fill());
Victor Zverovich100149e2012-12-24 11:41:20 -0800319 } else {
Victor Zverovich877abaf2013-01-08 09:56:05 -0800320 std::fill_n(out + size, spec.width() - size, spec.fill());
Victor Zverovich100149e2012-12-24 11:41:20 -0800321 }
Victor Zverovich1b9c22c2012-12-22 17:53:13 -0800322 } else {
323 out = GrowBuffer(size);
324 }
325 std::copy(s, s + size, out);
Victor Zverovichce604832012-12-28 08:27:54 -0800326 return out;
Victor Zverovich1b9c22c2012-12-22 17:53:13 -0800327}
328
Victor Zverovichde17baa2013-01-04 09:14:34 -0800329// Throws Exception(message) if format contains '}', otherwise throws
330// FormatError reporting unmatched '{'. The idea is that unmatched '{'
331// should override other errors.
332void Formatter::ReportError(const char *s, StringRef message) const {
333 for (int num_open_braces = num_open_braces_; *s; ++s) {
334 if (*s == '{') {
335 ++num_open_braces;
336 } else if (*s == '}') {
337 if (--num_open_braces == 0)
338 throw fmt::FormatError(message);
339 }
340 }
341 throw fmt::FormatError("unmatched '{' in format");
342}
343
Victor Zverovich36335272012-12-12 15:21:11 -0800344// Parses an unsigned integer advancing s to the end of the parsed input.
345// This function assumes that the first character of s is a digit.
346unsigned Formatter::ParseUInt(const char *&s) const {
347 assert('0' <= *s && *s <= '9');
348 unsigned value = 0;
349 do {
350 unsigned new_value = value * 10 + (*s++ - '0');
351 if (new_value < value) // Check if value wrapped around.
352 ReportError(s, "number is too big in format");
353 value = new_value;
354 } while ('0' <= *s && *s <= '9');
355 return value;
356}
357
Victor Zverovichde17baa2013-01-04 09:14:34 -0800358inline const Formatter::Arg &Formatter::ParseArgIndex(const char *&s) {
Victor Zverovich8412ad62012-12-27 06:56:55 -0800359 unsigned arg_index = 0;
360 if (*s < '0' || *s > '9') {
361 if (*s != '}' && *s != ':')
362 ReportError(s, "invalid argument index in format string");
363 if (next_arg_index_ < 0) {
364 ReportError(s,
365 "cannot switch from manual to automatic argument indexing");
366 }
367 arg_index = next_arg_index_++;
368 } else {
369 if (next_arg_index_ > 0) {
370 ReportError(s,
371 "cannot switch from automatic to manual argument indexing");
372 }
373 next_arg_index_ = -1;
374 arg_index = ParseUInt(s);
375 if (arg_index >= args_.size())
376 ReportError(s, "argument index is out of range in format");
377 }
Victor Zverovich36335272012-12-12 15:21:11 -0800378 return *args_[arg_index];
379}
380
Victor Zverovich17ca8092012-12-25 13:45:12 -0800381void Formatter::CheckSign(const char *&s, const Arg &arg) {
382 if (arg.type > LAST_NUMERIC_TYPE) {
383 ReportError(s,
384 Format("format specifier '{0}' requires numeric argument") << *s);
385 }
386 if (arg.type == UINT || arg.type == ULONG) {
387 ReportError(s,
388 Format("format specifier '{0}' requires signed argument") << *s);
389 }
390 ++s;
391}
392
Victor Zverovich36335272012-12-12 15:21:11 -0800393void Formatter::DoFormat() {
Victor Zverovichb076df42012-12-07 08:31:09 -0800394 const char *start = format_;
Victor Zverovich57dbd2c2012-12-11 12:23:52 -0800395 format_ = 0;
Victor Zverovich8412ad62012-12-27 06:56:55 -0800396 next_arg_index_ = 0;
Victor Zverovichb076df42012-12-07 08:31:09 -0800397 const char *s = start;
Victor Zverovich5f3ed202012-12-07 17:48:10 -0800398 while (*s) {
Victor Zverovich31a50702012-12-10 15:04:55 -0800399 char c = *s++;
400 if (c != '{' && c != '}') continue;
401 if (*s == c) {
Victor Zverovich198ebe92012-12-10 17:16:08 -0800402 buffer_.append(start, s);
Victor Zverovich31a50702012-12-10 15:04:55 -0800403 start = ++s;
404 continue;
405 }
406 if (c == '}')
407 throw FormatError("unmatched '}' in format");
Victor Zverovich36335272012-12-12 15:21:11 -0800408 num_open_braces_= 1;
Victor Zverovich198ebe92012-12-10 17:16:08 -0800409 buffer_.append(start, s - 1);
Victor Zverovichb076df42012-12-07 08:31:09 -0800410
Victor Zverovich36335272012-12-12 15:21:11 -0800411 const Arg &arg = ParseArgIndex(s);
Victor Zverovichb076df42012-12-07 08:31:09 -0800412
Victor Zverovich64236892012-12-21 09:12:04 -0800413 FormatSpec spec;
Victor Zverovichb076df42012-12-07 08:31:09 -0800414 int precision = -1;
415 if (*s == ':') {
416 ++s;
Victor Zverovich64236892012-12-21 09:12:04 -0800417
418 // Parse fill and alignment.
Victor Zverovicha0d685c2012-12-20 20:10:55 -0800419 if (char c = *s) {
Victor Zverovich64236892012-12-21 09:12:04 -0800420 const char *p = s + 1;
Victor Zverovich877abaf2013-01-08 09:56:05 -0800421 spec.align_ = ALIGN_DEFAULT;
Victor Zverovich64236892012-12-21 09:12:04 -0800422 do {
423 switch (*p) {
424 case '<':
Victor Zverovich877abaf2013-01-08 09:56:05 -0800425 spec.align_ = ALIGN_LEFT;
Victor Zverovich64236892012-12-21 09:12:04 -0800426 break;
427 case '>':
Victor Zverovich877abaf2013-01-08 09:56:05 -0800428 spec.align_ = ALIGN_RIGHT;
Victor Zverovich64236892012-12-21 09:12:04 -0800429 break;
430 case '=':
Victor Zverovich877abaf2013-01-08 09:56:05 -0800431 spec.align_ = ALIGN_NUMERIC;
Victor Zverovich64236892012-12-21 09:12:04 -0800432 break;
433 case '^':
Victor Zverovich877abaf2013-01-08 09:56:05 -0800434 spec.align_ = ALIGN_CENTER;
Victor Zverovich64236892012-12-21 09:12:04 -0800435 break;
Victor Zverovicha0d685c2012-12-20 20:10:55 -0800436 }
Victor Zverovich877abaf2013-01-08 09:56:05 -0800437 if (spec.align_ != ALIGN_DEFAULT) {
Victor Zverovichccbe9412012-12-24 08:34:44 -0800438 if (p != s) {
439 if (c == '}') break;
440 if (c == '{')
441 ReportError(s, "invalid fill character '{'");
Victor Zverovich64236892012-12-21 09:12:04 -0800442 s += 2;
Victor Zverovich877abaf2013-01-08 09:56:05 -0800443 spec.fill_ = c;
Victor Zverovich64236892012-12-21 09:12:04 -0800444 } else ++s;
Victor Zverovich877abaf2013-01-08 09:56:05 -0800445 if (spec.align_ == ALIGN_NUMERIC && arg.type > LAST_NUMERIC_TYPE)
Victor Zverovichccbe9412012-12-24 08:34:44 -0800446 ReportError(s, "format specifier '=' requires numeric argument");
Victor Zverovich64236892012-12-21 09:12:04 -0800447 break;
448 }
449 } while (--p >= s);
Victor Zverovicha0d685c2012-12-20 20:10:55 -0800450 }
Victor Zverovich64236892012-12-21 09:12:04 -0800451
452 // Parse sign.
Victor Zverovich0a138ad2012-12-25 13:25:14 -0800453 switch (*s) {
454 case '+':
Victor Zverovich17ca8092012-12-25 13:45:12 -0800455 CheckSign(s, arg);
Victor Zverovich877abaf2013-01-08 09:56:05 -0800456 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
Victor Zverovich17ca8092012-12-25 13:45:12 -0800457 break;
Victor Zverovich0a138ad2012-12-25 13:25:14 -0800458 case '-':
Victor Zverovich17ca8092012-12-25 13:45:12 -0800459 CheckSign(s, arg);
460 break;
461 case ' ':
462 CheckSign(s, arg);
Victor Zverovich877abaf2013-01-08 09:56:05 -0800463 spec.flags_ |= SIGN_FLAG;
Victor Zverovich0a138ad2012-12-25 13:25:14 -0800464 break;
Victor Zverovich8b1c7092012-12-08 18:45:35 -0800465 }
Victor Zverovichb076df42012-12-07 08:31:09 -0800466
Victor Zverovich73f13ee2012-12-25 18:19:51 -0800467 if (*s == '#') {
468 if (arg.type > LAST_NUMERIC_TYPE)
469 ReportError(s, "format specifier '#' requires numeric argument");
Victor Zverovich877abaf2013-01-08 09:56:05 -0800470 spec.flags_ |= HASH_FLAG;
Victor Zverovich73f13ee2012-12-25 18:19:51 -0800471 ++s;
472 }
473
Victor Zverovich64236892012-12-21 09:12:04 -0800474 // Parse width and zero flag.
Victor Zverovichb076df42012-12-07 08:31:09 -0800475 if ('0' <= *s && *s <= '9') {
Victor Zverovich64236892012-12-21 09:12:04 -0800476 if (*s == '0') {
477 if (arg.type > LAST_NUMERIC_TYPE)
478 ReportError(s, "format specifier '0' requires numeric argument");
Victor Zverovich877abaf2013-01-08 09:56:05 -0800479 spec.align_ = ALIGN_NUMERIC;
480 spec.fill_ = '0';
Victor Zverovich64236892012-12-21 09:12:04 -0800481 }
482 // Zero may be parsed again as a part of the width, but it is simpler
483 // and more efficient than checking if the next char is a digit.
Victor Zverovich095b43a2012-12-09 11:32:39 -0800484 unsigned value = ParseUInt(s);
485 if (value > INT_MAX)
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800486 ReportError(s, "number is too big in format");
Victor Zverovich877abaf2013-01-08 09:56:05 -0800487 spec.width_ = value;
Victor Zverovichb076df42012-12-07 08:31:09 -0800488 }
489
490 // Parse precision.
491 if (*s == '.') {
Victor Zverovichb076df42012-12-07 08:31:09 -0800492 ++s;
493 precision = 0;
494 if ('0' <= *s && *s <= '9') {
Victor Zverovich095b43a2012-12-09 11:32:39 -0800495 unsigned value = ParseUInt(s);
496 if (value > INT_MAX)
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800497 ReportError(s, "number is too big in format");
Victor Zverovich095b43a2012-12-09 11:32:39 -0800498 precision = value;
Victor Zverovich36335272012-12-12 15:21:11 -0800499 } else if (*s == '{') {
500 ++s;
501 ++num_open_braces_;
502 const Arg &precision_arg = ParseArgIndex(s);
503 unsigned long value = 0;
504 switch (precision_arg.type) {
505 case INT:
506 if (precision_arg.int_value < 0)
507 ReportError(s, "negative precision in format");
508 value = precision_arg.int_value;
509 break;
510 case UINT:
511 value = precision_arg.uint_value;
512 break;
513 case LONG:
514 if (precision_arg.long_value < 0)
515 ReportError(s, "negative precision in format");
516 value = precision_arg.long_value;
517 break;
518 case ULONG:
519 value = precision_arg.ulong_value;
520 break;
521 default:
522 ReportError(s, "precision is not integer");
523 }
524 if (value > INT_MAX)
525 ReportError(s, "number is too big in format");
526 precision = value;
527 if (*s++ != '}')
528 throw FormatError("unmatched '{' in format");
529 --num_open_braces_;
Victor Zverovichb076df42012-12-07 08:31:09 -0800530 } else {
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800531 ReportError(s, "missing precision in format");
Victor Zverovichbbd13a42012-12-09 14:13:23 -0800532 }
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800533 if (arg.type != DOUBLE && arg.type != LONG_DOUBLE) {
534 ReportError(s,
535 "precision specifier requires floating-point argument");
Victor Zverovichb076df42012-12-07 08:31:09 -0800536 }
537 }
538
539 // Parse type.
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800540 if (*s != '}' && *s)
Victor Zverovich877abaf2013-01-08 09:56:05 -0800541 spec.type_ = *s++;
Victor Zverovichb076df42012-12-07 08:31:09 -0800542 }
543
544 if (*s++ != '}')
Victor Zverovich8b1c7092012-12-08 18:45:35 -0800545 throw FormatError("unmatched '{' in format");
Victor Zverovichb076df42012-12-07 08:31:09 -0800546 start = s;
547
548 // Format argument.
Victor Zverovichb076df42012-12-07 08:31:09 -0800549 switch (arg.type) {
Victor Zverovichb076df42012-12-07 08:31:09 -0800550 case INT:
Victor Zverovicha0d685c2012-12-20 20:10:55 -0800551 FormatInt(arg.int_value, spec);
Victor Zverovichb076df42012-12-07 08:31:09 -0800552 break;
553 case UINT:
Victor Zverovicha0d685c2012-12-20 20:10:55 -0800554 FormatInt(arg.uint_value, spec);
Victor Zverovichb076df42012-12-07 08:31:09 -0800555 break;
556 case LONG:
Victor Zverovicha0d685c2012-12-20 20:10:55 -0800557 FormatInt(arg.long_value, spec);
Victor Zverovichb076df42012-12-07 08:31:09 -0800558 break;
559 case ULONG:
Victor Zverovicha0d685c2012-12-20 20:10:55 -0800560 FormatInt(arg.ulong_value, spec);
Victor Zverovichb076df42012-12-07 08:31:09 -0800561 break;
562 case DOUBLE:
Victor Zverovicha0d685c2012-12-20 20:10:55 -0800563 FormatDouble(arg.double_value, spec, precision);
Victor Zverovichb076df42012-12-07 08:31:09 -0800564 break;
565 case LONG_DOUBLE:
Victor Zverovicha0d685c2012-12-20 20:10:55 -0800566 FormatDouble(arg.long_double_value, spec, precision);
Victor Zverovichbbd13a42012-12-09 14:13:23 -0800567 break;
Victor Zverovich198ebe92012-12-10 17:16:08 -0800568 case CHAR: {
Victor Zverovich877abaf2013-01-08 09:56:05 -0800569 if (spec.type_ && spec.type_ != 'c')
570 ReportUnknownType(spec.type_, "char");
Victor Zverovich1b9c22c2012-12-22 17:53:13 -0800571 char *out = 0;
Victor Zverovich877abaf2013-01-08 09:56:05 -0800572 if (spec.width_ > 1) {
573 out = GrowBuffer(spec.width_);
574 if (spec.align_ == ALIGN_RIGHT) {
575 std::fill_n(out, spec.width_ - 1, spec.fill_);
576 out += spec.width_ - 1;
577 } else if (spec.align_ == ALIGN_CENTER) {
578 out = FillPadding(out, spec.width_, 1, spec.fill_);
Victor Zverovich26d2ae62012-12-24 11:58:49 -0800579 } else {
Victor Zverovich877abaf2013-01-08 09:56:05 -0800580 std::fill_n(out + 1, spec.width_ - 1, spec.fill_);
Victor Zverovich26d2ae62012-12-24 11:58:49 -0800581 }
Victor Zverovich1b9c22c2012-12-22 17:53:13 -0800582 } else {
583 out = GrowBuffer(1);
584 }
585 *out = arg.int_value;
Victor Zverovichbbd13a42012-12-09 14:13:23 -0800586 break;
Victor Zverovich198ebe92012-12-10 17:16:08 -0800587 }
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800588 case STRING: {
Victor Zverovich877abaf2013-01-08 09:56:05 -0800589 if (spec.type_ && spec.type_ != 's')
590 ReportUnknownType(spec.type_, "string");
Victor Zverovich33bb6ee2012-12-11 21:47:05 -0800591 const char *str = arg.string.value;
592 size_t size = arg.string.size;
Victor Zverovich1b3c1972012-12-17 16:39:49 -0800593 if (size == 0) {
594 if (!str)
595 throw FormatError("string pointer is null");
596 if (*str)
597 size = std::strlen(str);
598 }
Victor Zverovich1b9c22c2012-12-22 17:53:13 -0800599 FormatString(str, size, spec);
Victor Zverovichb076df42012-12-07 08:31:09 -0800600 break;
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800601 }
602 case POINTER:
Victor Zverovich877abaf2013-01-08 09:56:05 -0800603 if (spec.type_ && spec.type_ != 'p')
604 ReportUnknownType(spec.type_, "pointer");
605 spec.flags_= HASH_FLAG;
606 spec.type_ = 'x';
Victor Zverovicha0d685c2012-12-20 20:10:55 -0800607 FormatInt(reinterpret_cast<uintptr_t>(arg.pointer_value), spec);
Victor Zverovichb076df42012-12-07 08:31:09 -0800608 break;
Victor Zverovich280ea8b2012-12-09 09:03:47 -0800609 case CUSTOM:
Victor Zverovich877abaf2013-01-08 09:56:05 -0800610 if (spec.type_)
611 ReportUnknownType(spec.type_, "object");
Victor Zverovicha0d685c2012-12-20 20:10:55 -0800612 (this->*arg.custom.format)(arg.custom.value, spec);
Victor Zverovich63539c02012-12-08 08:17:12 -0800613 break;
Victor Zverovichb076df42012-12-07 08:31:09 -0800614 default:
615 assert(false);
616 break;
617 }
618 }
Victor Zverovichde17baa2013-01-04 09:14:34 -0800619 buffer_.append(start, s);
Victor Zverovichb076df42012-12-07 08:31:09 -0800620}