blob: bbc9b423c0ea5b1f69e7d90aab84b6ee24c31ef2 [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#include <stdint.h>
38
Victor Zverovichb076df42012-12-07 08:31:09 -080039#include <cassert>
Victor Zverovich72f896d2012-12-12 09:17:28 -080040#include <cctype>
Victor Zverovich63539c02012-12-08 08:17:12 -080041#include <climits>
Victor Zverovichb076df42012-12-07 08:31:09 -080042#include <cstring>
43#include <algorithm>
44
45using std::size_t;
Victor Zverovich3f739872012-12-25 17:55:41 -080046using fmt::BasicFormatter;
Victor Zverovich36335272012-12-12 15:21:11 -080047using fmt::Formatter;
Victor Zverovichf28ecaf2012-12-21 09:14:18 -080048using fmt::FormatSpec;
Victor Zverovich0f46a3d2012-12-25 13:30:42 -080049using fmt::StringRef;
Victor Zverovichb076df42012-12-07 08:31:09 -080050
Victor Zveroviche8ba9602012-12-12 09:29:50 -080051#if _MSC_VER
Victor Zverovichf8c91062012-12-17 15:41:00 -080052# undef snprintf
Victor Zveroviche8ba9602012-12-12 09:29:50 -080053# define snprintf _snprintf
54#endif
55
Victor Zverovich8b1c7092012-12-08 18:45:35 -080056namespace {
57
Victor Zverovichb98b2e92012-12-10 11:08:16 -080058// Flags.
Victor Zverovich73f13ee2012-12-25 18:19:51 -080059enum { SIGN_FLAG = 1, PLUS_FLAG = 2, HASH_FLAG = 4 };
Victor Zverovich64236892012-12-21 09:12:04 -080060
Victor Zverovichd599e3b2012-12-10 13:30:06 -080061void ReportUnknownType(char code, const char *type) {
Victor Zverovich1dc0cc32012-12-16 15:56:44 -080062 if (std::isprint(static_cast<unsigned char>(code))) {
Victor Zverovichd599e3b2012-12-10 13:30:06 -080063 throw fmt::FormatError(
64 str(fmt::Format("unknown format code '{0}' for {1}") << code << type));
65 }
66 throw fmt::FormatError(
67 str(fmt::Format("unknown format code '\\x{0:02x}' for {1}")
68 << static_cast<unsigned>(code) << type));
69}
70
Victor Zverovich33bb6ee2012-12-11 21:47:05 -080071// Information about an integer type.
Victor Zverovichb98b2e92012-12-10 11:08:16 -080072template <typename T>
Victor Zverovich33bb6ee2012-12-11 21:47:05 -080073struct IntTraits {
74 typedef T UnsignedType;
75 static bool IsNegative(T) { return false; }
Victor Zverovichb98b2e92012-12-10 11:08:16 -080076};
77
78template <>
Victor Zverovich33bb6ee2012-12-11 21:47:05 -080079struct IntTraits<int> {
80 typedef unsigned UnsignedType;
81 static bool IsNegative(int value) { return value < 0; }
Victor Zverovichb98b2e92012-12-10 11:08:16 -080082};
83
84template <>
Victor Zverovich33bb6ee2012-12-11 21:47:05 -080085struct IntTraits<long> {
86 typedef unsigned long UnsignedType;
87 static bool IsNegative(long value) { return value < 0; }
Victor Zverovichb98b2e92012-12-10 11:08:16 -080088};
89
90template <typename T>
91struct IsLongDouble { enum {VALUE = 0}; };
92
93template <>
94struct IsLongDouble<long double> { enum {VALUE = 1}; };
Victor Zverovichccbe9412012-12-24 08:34:44 -080095
Victor Zverovich4d1ee0b2012-12-24 18:19:33 -080096inline unsigned CountDigits(uint64_t n) {
Victor Zverovichccbe9412012-12-24 08:34:44 -080097 unsigned count = 1;
98 for (;;) {
99 // Integer division is slow so do it for a group of four digits instead
100 // of for every digit. The idea comes from the talk by Alexandrescu
101 // "Three Optimization Tips for C++". See speed-test for a comparison.
102 if (n < 10) return count;
103 if (n < 100) return count + 1;
104 if (n < 1000) return count + 2;
105 if (n < 10000) return count + 3;
106 n /= 10000u;
107 count += 4;
108 }
109}
Victor Zverovichd9633792012-12-25 09:00:11 -0800110
111const char DIGITS[] =
112 "0001020304050607080910111213141516171819"
113 "2021222324252627282930313233343536373839"
114 "4041424344454647484950515253545556575859"
115 "6061626364656667686970717273747576777879"
116 "8081828384858687888990919293949596979899";
117
118void FormatDecimal(char *buffer, uint64_t value, unsigned num_digits) {
119 --num_digits;
120 while (value >= 100) {
121 // Integer division is slow so do it for a group of two digits instead
122 // of for every digit. The idea comes from the talk by Alexandrescu
123 // "Three Optimization Tips for C++". See speed-test for a comparison.
124 unsigned index = (value % 100) * 2;
125 value /= 100;
126 buffer[num_digits] = DIGITS[index + 1];
127 buffer[num_digits - 1] = DIGITS[index];
128 num_digits -= 2;
129 }
130 if (value < 10) {
131 *buffer = static_cast<char>('0' + value);
132 return;
133 }
Victor Zverovich17ca8092012-12-25 13:45:12 -0800134 unsigned index = static_cast<unsigned>(value * 2);
Victor Zverovichd9633792012-12-25 09:00:11 -0800135 buffer[1] = DIGITS[index + 1];
136 buffer[0] = DIGITS[index];
137}
Victor Zverovich10108c72012-12-28 09:08:29 -0800138
139#ifdef _MSC_VER
140int signbit(double value) {
141 if (value < 0) return 1;
Victor Zverovich7b970282012-12-28 09:24:06 -0800142 if (value == value) return 0;
Victor Zverovich10108c72012-12-28 09:08:29 -0800143 int dec = 0, sign = 0;
Victor Zverovich4762a8a2012-12-29 06:44:14 -0800144 _ecvt(value, 0, &dec, &sign);
Victor Zverovich10108c72012-12-28 09:08:29 -0800145 return sign;
146}
147#endif
Victor Zverovich8b1c7092012-12-08 18:45:35 -0800148}
149
Victor Zverovich3f739872012-12-25 17:55:41 -0800150void BasicFormatter::operator<<(int value) {
151 unsigned abs_value = value;
152 unsigned num_digits = 0;
153 char *out = 0;
154 if (value >= 0) {
155 num_digits = CountDigits(abs_value);
156 out = GrowBuffer(num_digits);
157 } else {
158 abs_value = 0 - abs_value;
159 num_digits = CountDigits(abs_value);
160 out = GrowBuffer(num_digits + 1);
161 *out++ = '-';
162 }
163 FormatDecimal(out, abs_value, num_digits);
164}
165
Victor Zverovich36335272012-12-12 15:21:11 -0800166// Throws Exception(message) if format contains '}', otherwise throws
167// FormatError reporting unmatched '{'. The idea is that unmatched '{'
168// should override other errors.
Victor Zverovich0a138ad2012-12-25 13:25:14 -0800169void Formatter::ReportError(const char *s, StringRef message) const {
Victor Zverovich36335272012-12-12 15:21:11 -0800170 for (int num_open_braces = num_open_braces_; *s; ++s) {
171 if (*s == '{') {
172 ++num_open_braces;
173 } else if (*s == '}') {
174 if (--num_open_braces == 0)
175 throw fmt::FormatError(message);
176 }
177 }
178 throw fmt::FormatError("unmatched '{' in format");
179}
180
Victor Zverovich84310c32012-12-24 19:37:50 -0800181// Fills the padding around the content and returns the pointer to the
182// content area.
183char *FillPadding(char *buffer,
Victor Zverovich3f739872012-12-25 17:55:41 -0800184 unsigned total_size, std::size_t content_size, char fill) {
Victor Zverovich8412ad62012-12-27 06:56:55 -0800185 std::size_t padding = total_size - content_size;
186 std::size_t left_padding = padding / 2;
Victor Zverovich84310c32012-12-24 19:37:50 -0800187 std::fill_n(buffer, left_padding, fill);
188 buffer += left_padding;
189 char *content = buffer;
190 std::fill_n(buffer + content_size, padding - left_padding, fill);
191 return content;
192}
193
Victor Zverovichbe6e54d2012-12-22 14:05:56 -0800194char *Formatter::PrepareFilledBuffer(
Victor Zverovichccbe9412012-12-24 08:34:44 -0800195 unsigned size, const FormatSpec &spec, char sign) {
Victor Zverovichbe6e54d2012-12-22 14:05:56 -0800196 if (spec.width <= size) {
197 char *p = GrowBuffer(size);
198 *p = sign;
199 return p + size - 1;
200 }
201 char *p = GrowBuffer(spec.width);
202 char *end = p + spec.width;
Victor Zverovich84310c32012-12-24 19:37:50 -0800203 if (spec.align == ALIGN_LEFT) {
204 *p = sign;
205 p += size;
206 std::fill(p, end, spec.fill);
207 } else if (spec.align == ALIGN_CENTER) {
208 p = FillPadding(p, spec.width, size, spec.fill);
209 *p = sign;
210 p += size;
211 } else {
Victor Zverovich1b9c22c2012-12-22 17:53:13 -0800212 if (spec.align == ALIGN_NUMERIC) {
213 if (sign) {
214 *p++ = sign;
215 --size;
216 }
217 } else {
218 *(end - size) = sign;
219 }
Victor Zverovichbe6e54d2012-12-22 14:05:56 -0800220 std::fill(p, end - size, spec.fill);
221 p = end;
222 }
223 return p - 1;
224}
225
Victor Zverovichb076df42012-12-07 08:31:09 -0800226template <typename T>
Victor Zverovichccbe9412012-12-24 08:34:44 -0800227void Formatter::FormatInt(T value, const FormatSpec &spec) {
Victor Zverovicha0d685c2012-12-20 20:10:55 -0800228 unsigned size = 0;
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800229 char sign = 0;
Victor Zverovich33bb6ee2012-12-11 21:47:05 -0800230 typedef typename IntTraits<T>::UnsignedType UnsignedType;
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800231 UnsignedType abs_value = value;
Victor Zverovich33bb6ee2012-12-11 21:47:05 -0800232 if (IntTraits<T>::IsNegative(value)) {
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800233 sign = '-';
234 ++size;
Victor Zverovich51613762012-12-21 15:43:10 -0800235 abs_value = 0 - abs_value;
Victor Zverovich17ca8092012-12-25 13:45:12 -0800236 } else if ((spec.flags & SIGN_FLAG) != 0) {
237 sign = (spec.flags & PLUS_FLAG) != 0 ? '+' : ' ';
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800238 ++size;
239 }
Victor Zverovicha0d685c2012-12-20 20:10:55 -0800240 switch (spec.type) {
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800241 case 0: case 'd': {
Victor Zverovichd9633792012-12-25 09:00:11 -0800242 unsigned num_digits = CountDigits(abs_value);
243 char *p = PrepareFilledBuffer(size + num_digits, spec, sign)
244 - num_digits + 1;
245 FormatDecimal(p, abs_value, num_digits);
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800246 break;
247 }
248 case 'x': case 'X': {
249 UnsignedType n = abs_value;
Victor Zverovich73f13ee2012-12-25 18:19:51 -0800250 bool print_prefix = (spec.flags & HASH_FLAG) != 0;
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800251 if (print_prefix) size += 2;
252 do {
253 ++size;
254 } while ((n >>= 4) != 0);
Victor Zverovichbe6e54d2012-12-22 14:05:56 -0800255 char *p = PrepareFilledBuffer(size, spec, sign);
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800256 n = abs_value;
Victor Zverovicha0d685c2012-12-20 20:10:55 -0800257 const char *digits = spec.type == 'x' ?
258 "0123456789abcdef" : "0123456789ABCDEF";
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800259 do {
260 *p-- = digits[n & 0xf];
261 } while ((n >>= 4) != 0);
262 if (print_prefix) {
Victor Zverovicha0d685c2012-12-20 20:10:55 -0800263 *p-- = spec.type;
Victor Zverovich73f13ee2012-12-25 18:19:51 -0800264 *p = '0';
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800265 }
266 break;
267 }
268 case 'o': {
269 UnsignedType n = abs_value;
Victor Zverovich73f13ee2012-12-25 18:19:51 -0800270 bool print_prefix = (spec.flags & HASH_FLAG) != 0;
271 if (print_prefix) ++size;
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800272 do {
273 ++size;
274 } while ((n >>= 3) != 0);
Victor Zverovichbe6e54d2012-12-22 14:05:56 -0800275 char *p = PrepareFilledBuffer(size, spec, sign);
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800276 n = abs_value;
277 do {
278 *p-- = '0' + (n & 7);
279 } while ((n >>= 3) != 0);
Victor Zverovich73f13ee2012-12-25 18:19:51 -0800280 if (print_prefix)
281 *p = '0';
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800282 break;
283 }
284 default:
Victor Zverovicha0d685c2012-12-20 20:10:55 -0800285 ReportUnknownType(spec.type, "integer");
Victor Zverovichd599e3b2012-12-10 13:30:06 -0800286 break;
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800287 }
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800288}
289
290template <typename T>
Victor Zverovicha0d685c2012-12-20 20:10:55 -0800291void Formatter::FormatDouble(T value, const FormatSpec &spec, int precision) {
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800292 // Check type.
Victor Zverovicha0d685c2012-12-20 20:10:55 -0800293 char type = spec.type;
Victor Zverovichce604832012-12-28 08:27:54 -0800294 bool upper = false;
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800295 switch (type) {
Victor Zverovichd73306b2012-12-10 12:16:02 -0800296 case 0:
297 type = 'g';
298 break;
Victor Zverovichce604832012-12-28 08:27:54 -0800299 case 'e': case 'f': case 'g':
Victor Zverovicha2a87412012-12-12 10:11:40 -0800300 break;
301 case 'F':
Victor Zverovich36335272012-12-12 15:21:11 -0800302#ifdef _MSC_VER
303 // MSVC's printf doesn't support 'F'.
Victor Zverovicha2a87412012-12-12 10:11:40 -0800304 type = 'f';
Victor Zverovich36335272012-12-12 15:21:11 -0800305#endif
Victor Zverovichce604832012-12-28 08:27:54 -0800306 // Fall through.
307 case 'E': case 'G':
308 upper = true;
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800309 break;
310 default:
Victor Zverovichd599e3b2012-12-10 13:30:06 -0800311 ReportUnknownType(type, "double");
312 break;
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800313 }
314
Victor Zverovichccbe9412012-12-24 08:34:44 -0800315 char sign = 0;
Victor Zverovichce604832012-12-28 08:27:54 -0800316 // Use signbit instead of value < 0 because the latter is always
317 // false for NaN.
318 if (signbit(value)) {
Victor Zverovichccbe9412012-12-24 08:34:44 -0800319 sign = '-';
320 value = -value;
Victor Zverovich17ca8092012-12-25 13:45:12 -0800321 } else if ((spec.flags & SIGN_FLAG) != 0) {
322 sign = (spec.flags & PLUS_FLAG) != 0 ? '+' : ' ';
Victor Zverovichccbe9412012-12-24 08:34:44 -0800323 }
Victor Zverovichce604832012-12-28 08:27:54 -0800324
Victor Zverovich529045b2012-12-28 09:41:03 -0800325 if (value != value) {
Victor Zverovichce604832012-12-28 08:27:54 -0800326 // Format NaN ourselves because sprintf's output is not consistent
327 // across platforms.
328 std::size_t size = 4;
329 const char *nan = upper ? " NAN" : " nan";
330 if (!sign) {
331 --size;
332 ++nan;
333 }
334 char *out = FormatString(nan, size, spec);
335 if (sign)
336 *out = sign;
337 return;
338 }
339
Victor Zverovich4762a8a2012-12-29 06:44:14 -0800340 if (isinf(value)) {
341 // Format infinity ourselves because sprintf's output is not consistent
342 // across platforms.
343 std::size_t size = 4;
344 const char *inf = upper ? " INF" : " inf";
345 if (!sign) {
346 --size;
347 ++inf;
348 }
349 char *out = FormatString(inf, size, spec);
350 if (sign)
351 *out = sign;
352 return;
353 }
354
Victor Zverovichccbe9412012-12-24 08:34:44 -0800355 size_t offset = buffer_.size();
356 unsigned width = spec.width;
357 if (sign) {
358 buffer_.reserve(buffer_.size() + std::max(width, 1u));
359 if (width > 0)
360 --width;
361 ++offset;
362 }
363
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800364 // Build format string.
Victor Zverovich73f13ee2012-12-25 18:19:51 -0800365 enum { MAX_FORMAT_SIZE = 10}; // longest format: %#-*.*Lg
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800366 char format[MAX_FORMAT_SIZE];
367 char *format_ptr = format;
368 *format_ptr++ = '%';
Victor Zverovich84310c32012-12-24 19:37:50 -0800369 unsigned width_for_sprintf = width;
Victor Zverovich73f13ee2012-12-25 18:19:51 -0800370 if ((spec.flags & HASH_FLAG) != 0)
371 *format_ptr++ = '#';
Victor Zverovich84310c32012-12-24 19:37:50 -0800372 if (spec.align == ALIGN_CENTER) {
373 width_for_sprintf = 0;
374 } else {
375 if (spec.align == ALIGN_LEFT)
376 *format_ptr++ = '-';
377 if (width != 0)
378 *format_ptr++ = '*';
379 }
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800380 if (precision >= 0) {
381 *format_ptr++ = '.';
382 *format_ptr++ = '*';
383 }
384 if (IsLongDouble<T>::VALUE)
385 *format_ptr++ = 'L';
Victor Zverovichd73306b2012-12-10 12:16:02 -0800386 *format_ptr++ = type;
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800387 *format_ptr = '\0';
388
389 // Format using snprintf.
Victor Zverovichb076df42012-12-07 08:31:09 -0800390 for (;;) {
Victor Zverovich198ebe92012-12-10 17:16:08 -0800391 size_t size = buffer_.capacity() - offset;
Victor Zverovichb076df42012-12-07 08:31:09 -0800392 int n = 0;
Victor Zverovicha0d685c2012-12-20 20:10:55 -0800393 char *start = &buffer_[offset];
Victor Zverovich84310c32012-12-24 19:37:50 -0800394 if (width_for_sprintf == 0) {
Victor Zverovichb076df42012-12-07 08:31:09 -0800395 n = precision < 0 ?
Victor Zverovicha0d685c2012-12-20 20:10:55 -0800396 snprintf(start, size, format, value) :
397 snprintf(start, size, format, precision, value);
Victor Zverovichb076df42012-12-07 08:31:09 -0800398 } else {
399 n = precision < 0 ?
Victor Zverovich84310c32012-12-24 19:37:50 -0800400 snprintf(start, size, format, width_for_sprintf, value) :
401 snprintf(start, size, format, width_for_sprintf, precision, value);
Victor Zverovichb076df42012-12-07 08:31:09 -0800402 }
Victor Zverovich198ebe92012-12-10 17:16:08 -0800403 if (n >= 0 && offset + n < buffer_.capacity()) {
Victor Zverovichccbe9412012-12-24 08:34:44 -0800404 if (sign) {
405 if ((spec.align != ALIGN_RIGHT && spec.align != ALIGN_DEFAULT) ||
406 *start != ' ') {
407 *(start - 1) = sign;
408 sign = 0;
409 } else {
410 *(start - 1) = spec.fill;
411 }
412 ++n;
413 }
Victor Zverovich84310c32012-12-24 19:37:50 -0800414 if (spec.align == ALIGN_CENTER && spec.width > static_cast<unsigned>(n)) {
415 char *p = GrowBuffer(spec.width);
416 std::copy(p, p + n, p + (spec.width - n) / 2);
417 FillPadding(p, spec.width, n, spec.fill);
418 return;
419 }
Victor Zverovichccbe9412012-12-24 08:34:44 -0800420 if (spec.fill != ' ' || sign) {
Victor Zverovich64236892012-12-21 09:12:04 -0800421 while (*start == ' ')
422 *start++ = spec.fill;
Victor Zverovichccbe9412012-12-24 08:34:44 -0800423 if (sign)
424 *(start - 1) = sign;
Victor Zverovich64236892012-12-21 09:12:04 -0800425 }
Victor Zverovich14e0f872012-12-10 18:08:04 -0800426 GrowBuffer(n);
Victor Zverovichb076df42012-12-07 08:31:09 -0800427 return;
428 }
Victor Zverovich198ebe92012-12-10 17:16:08 -0800429 buffer_.reserve(n >= 0 ? offset + n + 1 : 2 * buffer_.capacity());
Victor Zverovichb076df42012-12-07 08:31:09 -0800430 }
431}
432
Victor Zverovichce604832012-12-28 08:27:54 -0800433char *Formatter::FormatString(
Victor Zverovich1b9c22c2012-12-22 17:53:13 -0800434 const char *s, std::size_t size, const FormatSpec &spec) {
435 char *out = 0;
436 if (spec.width > size) {
437 out = GrowBuffer(spec.width);
Victor Zverovich100149e2012-12-24 11:41:20 -0800438 if (spec.align == ALIGN_RIGHT) {
439 std::fill_n(out, spec.width - size, spec.fill);
440 out += spec.width - size;
Victor Zverovich84310c32012-12-24 19:37:50 -0800441 } else if (spec.align == ALIGN_CENTER) {
442 out = FillPadding(out, spec.width, size, spec.fill);
Victor Zverovich100149e2012-12-24 11:41:20 -0800443 } else {
Victor Zverovich1b9c22c2012-12-22 17:53:13 -0800444 std::fill_n(out + size, spec.width - size, spec.fill);
Victor Zverovich100149e2012-12-24 11:41:20 -0800445 }
Victor Zverovich1b9c22c2012-12-22 17:53:13 -0800446 } else {
447 out = GrowBuffer(size);
448 }
449 std::copy(s, s + size, out);
Victor Zverovichce604832012-12-28 08:27:54 -0800450 return out;
Victor Zverovich1b9c22c2012-12-22 17:53:13 -0800451}
452
Victor Zverovich36335272012-12-12 15:21:11 -0800453// Parses an unsigned integer advancing s to the end of the parsed input.
454// This function assumes that the first character of s is a digit.
455unsigned Formatter::ParseUInt(const char *&s) const {
456 assert('0' <= *s && *s <= '9');
457 unsigned value = 0;
458 do {
459 unsigned new_value = value * 10 + (*s++ - '0');
460 if (new_value < value) // Check if value wrapped around.
461 ReportError(s, "number is too big in format");
462 value = new_value;
463 } while ('0' <= *s && *s <= '9');
464 return value;
465}
466
Victor Zverovich8412ad62012-12-27 06:56:55 -0800467const Formatter::Arg &Formatter::ParseArgIndex(const char *&s) {
468 unsigned arg_index = 0;
469 if (*s < '0' || *s > '9') {
470 if (*s != '}' && *s != ':')
471 ReportError(s, "invalid argument index in format string");
472 if (next_arg_index_ < 0) {
473 ReportError(s,
474 "cannot switch from manual to automatic argument indexing");
475 }
476 arg_index = next_arg_index_++;
477 } else {
478 if (next_arg_index_ > 0) {
479 ReportError(s,
480 "cannot switch from automatic to manual argument indexing");
481 }
482 next_arg_index_ = -1;
483 arg_index = ParseUInt(s);
484 if (arg_index >= args_.size())
485 ReportError(s, "argument index is out of range in format");
486 }
Victor Zverovich36335272012-12-12 15:21:11 -0800487 return *args_[arg_index];
488}
489
Victor Zverovich17ca8092012-12-25 13:45:12 -0800490void Formatter::CheckSign(const char *&s, const Arg &arg) {
491 if (arg.type > LAST_NUMERIC_TYPE) {
492 ReportError(s,
493 Format("format specifier '{0}' requires numeric argument") << *s);
494 }
495 if (arg.type == UINT || arg.type == ULONG) {
496 ReportError(s,
497 Format("format specifier '{0}' requires signed argument") << *s);
498 }
499 ++s;
500}
501
Victor Zverovich36335272012-12-12 15:21:11 -0800502void Formatter::DoFormat() {
Victor Zverovichb076df42012-12-07 08:31:09 -0800503 const char *start = format_;
Victor Zverovich57dbd2c2012-12-11 12:23:52 -0800504 format_ = 0;
Victor Zverovich8412ad62012-12-27 06:56:55 -0800505 next_arg_index_ = 0;
Victor Zverovichb076df42012-12-07 08:31:09 -0800506 const char *s = start;
Victor Zverovich5f3ed202012-12-07 17:48:10 -0800507 while (*s) {
Victor Zverovich31a50702012-12-10 15:04:55 -0800508 char c = *s++;
509 if (c != '{' && c != '}') continue;
510 if (*s == c) {
Victor Zverovich198ebe92012-12-10 17:16:08 -0800511 buffer_.append(start, s);
Victor Zverovich31a50702012-12-10 15:04:55 -0800512 start = ++s;
513 continue;
514 }
515 if (c == '}')
516 throw FormatError("unmatched '}' in format");
Victor Zverovich36335272012-12-12 15:21:11 -0800517 num_open_braces_= 1;
Victor Zverovich198ebe92012-12-10 17:16:08 -0800518 buffer_.append(start, s - 1);
Victor Zverovichb076df42012-12-07 08:31:09 -0800519
Victor Zverovich36335272012-12-12 15:21:11 -0800520 const Arg &arg = ParseArgIndex(s);
Victor Zverovichb076df42012-12-07 08:31:09 -0800521
Victor Zverovich64236892012-12-21 09:12:04 -0800522 FormatSpec spec;
Victor Zverovichb076df42012-12-07 08:31:09 -0800523 int precision = -1;
524 if (*s == ':') {
525 ++s;
Victor Zverovich64236892012-12-21 09:12:04 -0800526
527 // Parse fill and alignment.
Victor Zverovicha0d685c2012-12-20 20:10:55 -0800528 if (char c = *s) {
Victor Zverovich64236892012-12-21 09:12:04 -0800529 const char *p = s + 1;
Victor Zverovichbe6e54d2012-12-22 14:05:56 -0800530 spec.align = ALIGN_DEFAULT;
Victor Zverovich64236892012-12-21 09:12:04 -0800531 do {
532 switch (*p) {
533 case '<':
Victor Zverovichbe6e54d2012-12-22 14:05:56 -0800534 spec.align = ALIGN_LEFT;
Victor Zverovich64236892012-12-21 09:12:04 -0800535 break;
536 case '>':
Victor Zverovichbe6e54d2012-12-22 14:05:56 -0800537 spec.align = ALIGN_RIGHT;
Victor Zverovich64236892012-12-21 09:12:04 -0800538 break;
539 case '=':
Victor Zverovichbe6e54d2012-12-22 14:05:56 -0800540 spec.align = ALIGN_NUMERIC;
Victor Zverovich64236892012-12-21 09:12:04 -0800541 break;
542 case '^':
Victor Zverovichbe6e54d2012-12-22 14:05:56 -0800543 spec.align = ALIGN_CENTER;
Victor Zverovich64236892012-12-21 09:12:04 -0800544 break;
Victor Zverovicha0d685c2012-12-20 20:10:55 -0800545 }
Victor Zverovichbe6e54d2012-12-22 14:05:56 -0800546 if (spec.align != ALIGN_DEFAULT) {
Victor Zverovichccbe9412012-12-24 08:34:44 -0800547 if (p != s) {
548 if (c == '}') break;
549 if (c == '{')
550 ReportError(s, "invalid fill character '{'");
Victor Zverovich64236892012-12-21 09:12:04 -0800551 s += 2;
552 spec.fill = c;
553 } else ++s;
Victor Zverovichccbe9412012-12-24 08:34:44 -0800554 if (spec.align == ALIGN_NUMERIC && arg.type > LAST_NUMERIC_TYPE)
555 ReportError(s, "format specifier '=' requires numeric argument");
Victor Zverovich64236892012-12-21 09:12:04 -0800556 break;
557 }
558 } while (--p >= s);
Victor Zverovicha0d685c2012-12-20 20:10:55 -0800559 }
Victor Zverovich64236892012-12-21 09:12:04 -0800560
561 // Parse sign.
Victor Zverovich0a138ad2012-12-25 13:25:14 -0800562 switch (*s) {
563 case '+':
Victor Zverovich17ca8092012-12-25 13:45:12 -0800564 CheckSign(s, arg);
565 spec.flags |= SIGN_FLAG | PLUS_FLAG;
566 break;
Victor Zverovich0a138ad2012-12-25 13:25:14 -0800567 case '-':
Victor Zverovich17ca8092012-12-25 13:45:12 -0800568 CheckSign(s, arg);
569 break;
570 case ' ':
571 CheckSign(s, arg);
572 spec.flags |= SIGN_FLAG;
Victor Zverovich0a138ad2012-12-25 13:25:14 -0800573 break;
Victor Zverovich8b1c7092012-12-08 18:45:35 -0800574 }
Victor Zverovichb076df42012-12-07 08:31:09 -0800575
Victor Zverovich73f13ee2012-12-25 18:19:51 -0800576 if (*s == '#') {
577 if (arg.type > LAST_NUMERIC_TYPE)
578 ReportError(s, "format specifier '#' requires numeric argument");
579 spec.flags |= HASH_FLAG;
580 ++s;
581 }
582
Victor Zverovich64236892012-12-21 09:12:04 -0800583 // Parse width and zero flag.
Victor Zverovichb076df42012-12-07 08:31:09 -0800584 if ('0' <= *s && *s <= '9') {
Victor Zverovich64236892012-12-21 09:12:04 -0800585 if (*s == '0') {
586 if (arg.type > LAST_NUMERIC_TYPE)
587 ReportError(s, "format specifier '0' requires numeric argument");
Victor Zverovichbe6e54d2012-12-22 14:05:56 -0800588 spec.align = ALIGN_NUMERIC;
Victor Zverovich64236892012-12-21 09:12:04 -0800589 spec.fill = '0';
590 }
591 // Zero may be parsed again as a part of the width, but it is simpler
592 // and more efficient than checking if the next char is a digit.
Victor Zverovich095b43a2012-12-09 11:32:39 -0800593 unsigned value = ParseUInt(s);
594 if (value > INT_MAX)
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800595 ReportError(s, "number is too big in format");
Victor Zverovicha0d685c2012-12-20 20:10:55 -0800596 spec.width = value;
Victor Zverovichb076df42012-12-07 08:31:09 -0800597 }
598
599 // Parse precision.
600 if (*s == '.') {
Victor Zverovichb076df42012-12-07 08:31:09 -0800601 ++s;
602 precision = 0;
603 if ('0' <= *s && *s <= '9') {
Victor Zverovich095b43a2012-12-09 11:32:39 -0800604 unsigned value = ParseUInt(s);
605 if (value > INT_MAX)
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800606 ReportError(s, "number is too big in format");
Victor Zverovich095b43a2012-12-09 11:32:39 -0800607 precision = value;
Victor Zverovich36335272012-12-12 15:21:11 -0800608 } else if (*s == '{') {
609 ++s;
610 ++num_open_braces_;
611 const Arg &precision_arg = ParseArgIndex(s);
612 unsigned long value = 0;
613 switch (precision_arg.type) {
614 case INT:
615 if (precision_arg.int_value < 0)
616 ReportError(s, "negative precision in format");
617 value = precision_arg.int_value;
618 break;
619 case UINT:
620 value = precision_arg.uint_value;
621 break;
622 case LONG:
623 if (precision_arg.long_value < 0)
624 ReportError(s, "negative precision in format");
625 value = precision_arg.long_value;
626 break;
627 case ULONG:
628 value = precision_arg.ulong_value;
629 break;
630 default:
631 ReportError(s, "precision is not integer");
632 }
633 if (value > INT_MAX)
634 ReportError(s, "number is too big in format");
635 precision = value;
636 if (*s++ != '}')
637 throw FormatError("unmatched '{' in format");
638 --num_open_braces_;
Victor Zverovichb076df42012-12-07 08:31:09 -0800639 } else {
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800640 ReportError(s, "missing precision in format");
Victor Zverovichbbd13a42012-12-09 14:13:23 -0800641 }
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800642 if (arg.type != DOUBLE && arg.type != LONG_DOUBLE) {
643 ReportError(s,
644 "precision specifier requires floating-point argument");
Victor Zverovichb076df42012-12-07 08:31:09 -0800645 }
646 }
647
648 // Parse type.
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800649 if (*s != '}' && *s)
Victor Zverovicha0d685c2012-12-20 20:10:55 -0800650 spec.type = *s++;
Victor Zverovichb076df42012-12-07 08:31:09 -0800651 }
652
653 if (*s++ != '}')
Victor Zverovich8b1c7092012-12-08 18:45:35 -0800654 throw FormatError("unmatched '{' in format");
Victor Zverovichb076df42012-12-07 08:31:09 -0800655 start = s;
656
657 // Format argument.
Victor Zverovichb076df42012-12-07 08:31:09 -0800658 switch (arg.type) {
Victor Zverovichb076df42012-12-07 08:31:09 -0800659 case INT:
Victor Zverovicha0d685c2012-12-20 20:10:55 -0800660 FormatInt(arg.int_value, spec);
Victor Zverovichb076df42012-12-07 08:31:09 -0800661 break;
662 case UINT:
Victor Zverovicha0d685c2012-12-20 20:10:55 -0800663 FormatInt(arg.uint_value, spec);
Victor Zverovichb076df42012-12-07 08:31:09 -0800664 break;
665 case LONG:
Victor Zverovicha0d685c2012-12-20 20:10:55 -0800666 FormatInt(arg.long_value, spec);
Victor Zverovichb076df42012-12-07 08:31:09 -0800667 break;
668 case ULONG:
Victor Zverovicha0d685c2012-12-20 20:10:55 -0800669 FormatInt(arg.ulong_value, spec);
Victor Zverovichb076df42012-12-07 08:31:09 -0800670 break;
671 case DOUBLE:
Victor Zverovicha0d685c2012-12-20 20:10:55 -0800672 FormatDouble(arg.double_value, spec, precision);
Victor Zverovichb076df42012-12-07 08:31:09 -0800673 break;
674 case LONG_DOUBLE:
Victor Zverovicha0d685c2012-12-20 20:10:55 -0800675 FormatDouble(arg.long_double_value, spec, precision);
Victor Zverovichbbd13a42012-12-09 14:13:23 -0800676 break;
Victor Zverovich198ebe92012-12-10 17:16:08 -0800677 case CHAR: {
Victor Zverovicha0d685c2012-12-20 20:10:55 -0800678 if (spec.type && spec.type != 'c')
679 ReportUnknownType(spec.type, "char");
Victor Zverovich1b9c22c2012-12-22 17:53:13 -0800680 char *out = 0;
681 if (spec.width > 1) {
682 out = GrowBuffer(spec.width);
Victor Zverovich26d2ae62012-12-24 11:58:49 -0800683 if (spec.align == ALIGN_RIGHT) {
684 std::fill_n(out, spec.width - 1, spec.fill);
685 out += spec.width - 1;
Victor Zverovich84310c32012-12-24 19:37:50 -0800686 } else if (spec.align == ALIGN_CENTER) {
687 out = FillPadding(out, spec.width, 1, spec.fill);
Victor Zverovich26d2ae62012-12-24 11:58:49 -0800688 } else {
Victor Zverovich1b9c22c2012-12-22 17:53:13 -0800689 std::fill_n(out + 1, spec.width - 1, spec.fill);
Victor Zverovich26d2ae62012-12-24 11:58:49 -0800690 }
Victor Zverovich1b9c22c2012-12-22 17:53:13 -0800691 } else {
692 out = GrowBuffer(1);
693 }
694 *out = arg.int_value;
Victor Zverovichbbd13a42012-12-09 14:13:23 -0800695 break;
Victor Zverovich198ebe92012-12-10 17:16:08 -0800696 }
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800697 case STRING: {
Victor Zverovicha0d685c2012-12-20 20:10:55 -0800698 if (spec.type && spec.type != 's')
699 ReportUnknownType(spec.type, "string");
Victor Zverovich33bb6ee2012-12-11 21:47:05 -0800700 const char *str = arg.string.value;
701 size_t size = arg.string.size;
Victor Zverovich1b3c1972012-12-17 16:39:49 -0800702 if (size == 0) {
703 if (!str)
704 throw FormatError("string pointer is null");
705 if (*str)
706 size = std::strlen(str);
707 }
Victor Zverovich1b9c22c2012-12-22 17:53:13 -0800708 FormatString(str, size, spec);
Victor Zverovichb076df42012-12-07 08:31:09 -0800709 break;
Victor Zverovichb98b2e92012-12-10 11:08:16 -0800710 }
711 case POINTER:
Victor Zverovicha0d685c2012-12-20 20:10:55 -0800712 if (spec.type && spec.type != 'p')
713 ReportUnknownType(spec.type, "pointer");
Victor Zverovich73f13ee2012-12-25 18:19:51 -0800714 spec.flags = HASH_FLAG;
Victor Zverovicha0d685c2012-12-20 20:10:55 -0800715 spec.type = 'x';
716 FormatInt(reinterpret_cast<uintptr_t>(arg.pointer_value), spec);
Victor Zverovichb076df42012-12-07 08:31:09 -0800717 break;
Victor Zverovich280ea8b2012-12-09 09:03:47 -0800718 case CUSTOM:
Victor Zverovicha0d685c2012-12-20 20:10:55 -0800719 if (spec.type)
720 ReportUnknownType(spec.type, "object");
721 (this->*arg.custom.format)(arg.custom.value, spec);
Victor Zverovich63539c02012-12-08 08:17:12 -0800722 break;
Victor Zverovichb076df42012-12-07 08:31:09 -0800723 default:
724 assert(false);
725 break;
726 }
727 }
Victor Zverovich198ebe92012-12-10 17:16:08 -0800728 buffer_.append(start, s + 1);
Victor Zverovich0996e982012-12-10 20:37:35 -0800729 buffer_.resize(buffer_.size() - 1); // Don't count the terminating zero.
Victor Zverovichb076df42012-12-07 08:31:09 -0800730}