Mercurial > irccd
comparison extern/cppformat/format.cc @ 104:be4b9ed19a17
Irccd: import cppformat, #483
author | David Demelier <markand@malikania.fr> |
---|---|
date | Tue, 26 Apr 2016 22:09:02 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
103:04d672ab41a4 | 104:be4b9ed19a17 |
---|---|
1 /* | |
2 Formatting library for C++ | |
3 | |
4 Copyright (c) 2012 - 2015, 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. | |
26 */ | |
27 | |
28 #include "format.h" | |
29 | |
30 #include <string.h> | |
31 | |
32 #include <cctype> | |
33 #include <cerrno> | |
34 #include <climits> | |
35 #include <cmath> | |
36 #include <cstdarg> | |
37 #include <cstddef> // for std::ptrdiff_t | |
38 | |
39 #if defined(_WIN32) && defined(__MINGW32__) | |
40 # include <cstring> | |
41 #endif | |
42 | |
43 #if FMT_USE_WINDOWS_H | |
44 # if defined(NOMINMAX) || defined(FMT_WIN_MINMAX) | |
45 # include <windows.h> | |
46 # else | |
47 # define NOMINMAX | |
48 # include <windows.h> | |
49 # undef NOMINMAX | |
50 # endif | |
51 #endif | |
52 | |
53 using fmt::internal::Arg; | |
54 | |
55 // Check if exceptions are disabled. | |
56 #if defined(__GNUC__) && !defined(__EXCEPTIONS) | |
57 # define FMT_EXCEPTIONS 0 | |
58 #endif | |
59 #if defined(_MSC_VER) && !_HAS_EXCEPTIONS | |
60 # define FMT_EXCEPTIONS 0 | |
61 #endif | |
62 #ifndef FMT_EXCEPTIONS | |
63 # define FMT_EXCEPTIONS 1 | |
64 #endif | |
65 | |
66 #if FMT_EXCEPTIONS | |
67 # define FMT_TRY try | |
68 # define FMT_CATCH(x) catch (x) | |
69 #else | |
70 # define FMT_TRY if (true) | |
71 # define FMT_CATCH(x) if (false) | |
72 #endif | |
73 | |
74 #ifndef FMT_THROW | |
75 # if FMT_EXCEPTIONS | |
76 # define FMT_THROW(x) throw x | |
77 # else | |
78 # define FMT_THROW(x) assert(false) | |
79 # endif | |
80 #endif | |
81 | |
82 #ifdef FMT_HEADER_ONLY | |
83 # define FMT_FUNC inline | |
84 #else | |
85 # define FMT_FUNC | |
86 #endif | |
87 | |
88 #ifdef _MSC_VER | |
89 # pragma warning(push) | |
90 # pragma warning(disable: 4127) // conditional expression is constant | |
91 # pragma warning(disable: 4702) // unreachable code | |
92 // Disable deprecation warning for strerror. The latter is not called but | |
93 // MSVC fails to detect it. | |
94 # pragma warning(disable: 4996) | |
95 #endif | |
96 | |
97 // Dummy implementations of strerror_r and strerror_s called if corresponding | |
98 // system functions are not available. | |
99 static inline fmt::internal::Null<> strerror_r(int, char *, ...) { | |
100 return fmt::internal::Null<>(); | |
101 } | |
102 static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) { | |
103 return fmt::internal::Null<>(); | |
104 } | |
105 | |
106 namespace fmt { | |
107 namespace { | |
108 | |
109 #ifndef _MSC_VER | |
110 # define FMT_SNPRINTF snprintf | |
111 #else // _MSC_VER | |
112 inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) { | |
113 va_list args; | |
114 va_start(args, format); | |
115 int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args); | |
116 va_end(args); | |
117 return result; | |
118 } | |
119 # define FMT_SNPRINTF fmt_snprintf | |
120 #endif // _MSC_VER | |
121 | |
122 #if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT) | |
123 # define FMT_SWPRINTF snwprintf | |
124 #else | |
125 # define FMT_SWPRINTF swprintf | |
126 #endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT) | |
127 | |
128 // Checks if a value fits in int - used to avoid warnings about comparing | |
129 // signed and unsigned integers. | |
130 template <bool IsSigned> | |
131 struct IntChecker { | |
132 template <typename T> | |
133 static bool fits_in_int(T value) { | |
134 unsigned max = INT_MAX; | |
135 return value <= max; | |
136 } | |
137 static bool fits_in_int(bool) { return true; } | |
138 }; | |
139 | |
140 template <> | |
141 struct IntChecker<true> { | |
142 template <typename T> | |
143 static bool fits_in_int(T value) { | |
144 return value >= INT_MIN && value <= INT_MAX; | |
145 } | |
146 static bool fits_in_int(int) { return true; } | |
147 }; | |
148 | |
149 const char RESET_COLOR[] = "\x1b[0m"; | |
150 | |
151 typedef void (*FormatFunc)(fmt::Writer &, int, fmt::StringRef); | |
152 | |
153 // Portable thread-safe version of strerror. | |
154 // Sets buffer to point to a string describing the error code. | |
155 // This can be either a pointer to a string stored in buffer, | |
156 // or a pointer to some static immutable string. | |
157 // Returns one of the following values: | |
158 // 0 - success | |
159 // ERANGE - buffer is not large enough to store the error message | |
160 // other - failure | |
161 // Buffer should be at least of size 1. | |
162 int safe_strerror( | |
163 int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT { | |
164 FMT_ASSERT(buffer != 0 && buffer_size != 0, "invalid buffer"); | |
165 | |
166 class StrError { | |
167 private: | |
168 int error_code_; | |
169 char *&buffer_; | |
170 std::size_t buffer_size_; | |
171 | |
172 // A noop assignment operator to avoid bogus warnings. | |
173 void operator=(const StrError &) {} | |
174 | |
175 // Handle the result of XSI-compliant version of strerror_r. | |
176 int handle(int result) { | |
177 // glibc versions before 2.13 return result in errno. | |
178 return result == -1 ? errno : result; | |
179 } | |
180 | |
181 // Handle the result of GNU-specific version of strerror_r. | |
182 int handle(char *message) { | |
183 // If the buffer is full then the message is probably truncated. | |
184 if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1) | |
185 return ERANGE; | |
186 buffer_ = message; | |
187 return 0; | |
188 } | |
189 | |
190 // Handle the case when strerror_r is not available. | |
191 int handle(fmt::internal::Null<>) { | |
192 return fallback(strerror_s(buffer_, buffer_size_, error_code_)); | |
193 } | |
194 | |
195 // Fallback to strerror_s when strerror_r is not available. | |
196 int fallback(int result) { | |
197 // If the buffer is full then the message is probably truncated. | |
198 return result == 0 && strlen(buffer_) == buffer_size_ - 1 ? | |
199 ERANGE : result; | |
200 } | |
201 | |
202 // Fallback to strerror if strerror_r and strerror_s are not available. | |
203 int fallback(fmt::internal::Null<>) { | |
204 errno = 0; | |
205 buffer_ = strerror(error_code_); | |
206 return errno; | |
207 } | |
208 | |
209 public: | |
210 StrError(int err_code, char *&buf, std::size_t buf_size) | |
211 : error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {} | |
212 | |
213 int run() { | |
214 strerror_r(0, 0, ""); // Suppress a warning about unused strerror_r. | |
215 return handle(strerror_r(error_code_, buffer_, buffer_size_)); | |
216 } | |
217 }; | |
218 return StrError(error_code, buffer, buffer_size).run(); | |
219 } | |
220 | |
221 void format_error_code(fmt::Writer &out, int error_code, | |
222 fmt::StringRef message) FMT_NOEXCEPT { | |
223 // Report error code making sure that the output fits into | |
224 // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential | |
225 // bad_alloc. | |
226 out.clear(); | |
227 static const char SEP[] = ": "; | |
228 static const char ERROR_STR[] = "error "; | |
229 fmt::internal::IntTraits<int>::MainType ec_value = error_code; | |
230 // Subtract 2 to account for terminating null characters in SEP and ERROR_STR. | |
231 std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2; | |
232 error_code_size += fmt::internal::count_digits(ec_value); | |
233 if (message.size() <= fmt::internal::INLINE_BUFFER_SIZE - error_code_size) | |
234 out << message << SEP; | |
235 out << ERROR_STR << error_code; | |
236 assert(out.size() <= fmt::internal::INLINE_BUFFER_SIZE); | |
237 } | |
238 | |
239 void report_error(FormatFunc func, | |
240 int error_code, fmt::StringRef message) FMT_NOEXCEPT { | |
241 fmt::MemoryWriter full_message; | |
242 func(full_message, error_code, message); | |
243 // Use Writer::data instead of Writer::c_str to avoid potential memory | |
244 // allocation. | |
245 std::fwrite(full_message.data(), full_message.size(), 1, stderr); | |
246 std::fputc('\n', stderr); | |
247 } | |
248 | |
249 // IsZeroInt::visit(arg) returns true iff arg is a zero integer. | |
250 class IsZeroInt : public fmt::internal::ArgVisitor<IsZeroInt, bool> { | |
251 public: | |
252 template <typename T> | |
253 bool visit_any_int(T value) { return value == 0; } | |
254 }; | |
255 | |
256 // Parses an unsigned integer advancing s to the end of the parsed input. | |
257 // This function assumes that the first character of s is a digit. | |
258 template <typename Char> | |
259 int parse_nonnegative_int(const Char *&s) { | |
260 assert('0' <= *s && *s <= '9'); | |
261 unsigned value = 0; | |
262 do { | |
263 unsigned new_value = value * 10 + (*s++ - '0'); | |
264 // Check if value wrapped around. | |
265 if (new_value < value) { | |
266 value = UINT_MAX; | |
267 break; | |
268 } | |
269 value = new_value; | |
270 } while ('0' <= *s && *s <= '9'); | |
271 if (value > INT_MAX) | |
272 FMT_THROW(fmt::FormatError("number is too big")); | |
273 return value; | |
274 } | |
275 | |
276 template <typename Char> | |
277 inline bool is_name_start(Char c) { | |
278 return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c; | |
279 } | |
280 | |
281 inline void require_numeric_argument(const Arg &arg, char spec) { | |
282 if (arg.type > Arg::LAST_NUMERIC_TYPE) { | |
283 std::string message = | |
284 fmt::format("format specifier '{}' requires numeric argument", spec); | |
285 FMT_THROW(fmt::FormatError(message)); | |
286 } | |
287 } | |
288 | |
289 template <typename Char> | |
290 void check_sign(const Char *&s, const Arg &arg) { | |
291 char sign = static_cast<char>(*s); | |
292 require_numeric_argument(arg, sign); | |
293 if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG) { | |
294 FMT_THROW(fmt::FormatError(fmt::format( | |
295 "format specifier '{}' requires signed argument", sign))); | |
296 } | |
297 ++s; | |
298 } | |
299 | |
300 // Checks if an argument is a valid printf width specifier and sets | |
301 // left alignment if it is negative. | |
302 class WidthHandler : public fmt::internal::ArgVisitor<WidthHandler, unsigned> { | |
303 private: | |
304 fmt::FormatSpec &spec_; | |
305 | |
306 FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler); | |
307 | |
308 public: | |
309 explicit WidthHandler(fmt::FormatSpec &spec) : spec_(spec) {} | |
310 | |
311 void report_unhandled_arg() { | |
312 FMT_THROW(fmt::FormatError("width is not integer")); | |
313 } | |
314 | |
315 template <typename T> | |
316 unsigned visit_any_int(T value) { | |
317 typedef typename fmt::internal::IntTraits<T>::MainType UnsignedType; | |
318 UnsignedType width = value; | |
319 if (fmt::internal::is_negative(value)) { | |
320 spec_.align_ = fmt::ALIGN_LEFT; | |
321 width = 0 - width; | |
322 } | |
323 if (width > INT_MAX) | |
324 FMT_THROW(fmt::FormatError("number is too big")); | |
325 return static_cast<unsigned>(width); | |
326 } | |
327 }; | |
328 | |
329 class PrecisionHandler : | |
330 public fmt::internal::ArgVisitor<PrecisionHandler, int> { | |
331 public: | |
332 void report_unhandled_arg() { | |
333 FMT_THROW(fmt::FormatError("precision is not integer")); | |
334 } | |
335 | |
336 template <typename T> | |
337 int visit_any_int(T value) { | |
338 if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value)) | |
339 FMT_THROW(fmt::FormatError("number is too big")); | |
340 return static_cast<int>(value); | |
341 } | |
342 }; | |
343 | |
344 // Converts an integer argument to an integral type T for printf. | |
345 template <typename T> | |
346 class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> { | |
347 private: | |
348 fmt::internal::Arg &arg_; | |
349 wchar_t type_; | |
350 | |
351 FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter); | |
352 | |
353 public: | |
354 ArgConverter(fmt::internal::Arg &arg, wchar_t type) | |
355 : arg_(arg), type_(type) {} | |
356 | |
357 void visit_bool(bool value) { | |
358 if (type_ != 's') | |
359 visit_any_int(value); | |
360 } | |
361 | |
362 template <typename U> | |
363 void visit_any_int(U value) { | |
364 bool is_signed = type_ == 'd' || type_ == 'i'; | |
365 using fmt::internal::Arg; | |
366 if (sizeof(T) <= sizeof(int)) { | |
367 // Extra casts are used to silence warnings. | |
368 if (is_signed) { | |
369 arg_.type = Arg::INT; | |
370 arg_.int_value = static_cast<int>(static_cast<T>(value)); | |
371 } else { | |
372 arg_.type = Arg::UINT; | |
373 arg_.uint_value = static_cast<unsigned>( | |
374 static_cast<typename fmt::internal::MakeUnsigned<T>::Type>(value)); | |
375 } | |
376 } else { | |
377 if (is_signed) { | |
378 arg_.type = Arg::LONG_LONG; | |
379 arg_.long_long_value = | |
380 static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value); | |
381 } else { | |
382 arg_.type = Arg::ULONG_LONG; | |
383 arg_.ulong_long_value = | |
384 static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value); | |
385 } | |
386 } | |
387 } | |
388 }; | |
389 | |
390 // Converts an integer argument to char for printf. | |
391 class CharConverter : public fmt::internal::ArgVisitor<CharConverter, void> { | |
392 private: | |
393 fmt::internal::Arg &arg_; | |
394 | |
395 FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter); | |
396 | |
397 public: | |
398 explicit CharConverter(fmt::internal::Arg &arg) : arg_(arg) {} | |
399 | |
400 template <typename T> | |
401 void visit_any_int(T value) { | |
402 arg_.type = Arg::CHAR; | |
403 arg_.int_value = static_cast<char>(value); | |
404 } | |
405 }; | |
406 } // namespace | |
407 | |
408 namespace internal { | |
409 | |
410 template <typename Impl, typename Char> | |
411 class BasicArgFormatter : public ArgVisitor<Impl, void> { | |
412 private: | |
413 BasicWriter<Char> &writer_; | |
414 FormatSpec &spec_; | |
415 | |
416 FMT_DISALLOW_COPY_AND_ASSIGN(BasicArgFormatter); | |
417 | |
418 void write_pointer(const void *p) { | |
419 spec_.flags_ = HASH_FLAG; | |
420 spec_.type_ = 'x'; | |
421 writer_.write_int(reinterpret_cast<uintptr_t>(p), spec_); | |
422 } | |
423 | |
424 protected: | |
425 BasicWriter<Char> &writer() { return writer_; } | |
426 FormatSpec &spec() { return spec_; } | |
427 | |
428 void write(bool value) { | |
429 const char *str_value = value ? "true" : "false"; | |
430 Arg::StringValue<char> str = { str_value, strlen(str_value) }; | |
431 writer_.write_str(str, spec_); | |
432 } | |
433 | |
434 void write(const char *value) { | |
435 Arg::StringValue<char> str = {value, value != 0 ? strlen(value) : 0}; | |
436 writer_.write_str(str, spec_); | |
437 } | |
438 | |
439 public: | |
440 BasicArgFormatter(BasicWriter<Char> &w, FormatSpec &s) | |
441 : writer_(w), spec_(s) {} | |
442 | |
443 template <typename T> | |
444 void visit_any_int(T value) { writer_.write_int(value, spec_); } | |
445 | |
446 template <typename T> | |
447 void visit_any_double(T value) { writer_.write_double(value, spec_); } | |
448 | |
449 void visit_bool(bool value) { | |
450 if (spec_.type_) | |
451 return visit_any_int(value); | |
452 write(value); | |
453 } | |
454 | |
455 void visit_char(int value) { | |
456 if (spec_.type_ && spec_.type_ != 'c') { | |
457 spec_.flags_ |= CHAR_FLAG; | |
458 writer_.write_int(value, spec_); | |
459 return; | |
460 } | |
461 if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0) | |
462 FMT_THROW(FormatError("invalid format specifier for char")); | |
463 typedef typename BasicWriter<Char>::CharPtr CharPtr; | |
464 Char fill = internal::CharTraits<Char>::cast(spec_.fill()); | |
465 CharPtr out = CharPtr(); | |
466 const unsigned CHAR_WIDTH = 1; | |
467 if (spec_.width_ > CHAR_WIDTH) { | |
468 out = writer_.grow_buffer(spec_.width_); | |
469 if (spec_.align_ == ALIGN_RIGHT) { | |
470 std::fill_n(out, spec_.width_ - CHAR_WIDTH, fill); | |
471 out += spec_.width_ - CHAR_WIDTH; | |
472 } else if (spec_.align_ == ALIGN_CENTER) { | |
473 out = writer_.fill_padding(out, spec_.width_, | |
474 internal::check(CHAR_WIDTH), fill); | |
475 } else { | |
476 std::fill_n(out + CHAR_WIDTH, spec_.width_ - CHAR_WIDTH, fill); | |
477 } | |
478 } else { | |
479 out = writer_.grow_buffer(CHAR_WIDTH); | |
480 } | |
481 *out = internal::CharTraits<Char>::cast(value); | |
482 } | |
483 | |
484 void visit_cstring(const char *value) { | |
485 if (spec_.type_ == 'p') | |
486 return write_pointer(value); | |
487 write(value); | |
488 } | |
489 | |
490 void visit_string(Arg::StringValue<char> value) { | |
491 writer_.write_str(value, spec_); | |
492 } | |
493 | |
494 using ArgVisitor<Impl, void>::visit_wstring; | |
495 | |
496 void visit_wstring(Arg::StringValue<Char> value) { | |
497 writer_.write_str(value, spec_); | |
498 } | |
499 | |
500 void visit_pointer(const void *value) { | |
501 if (spec_.type_ && spec_.type_ != 'p') | |
502 report_unknown_type(spec_.type_, "pointer"); | |
503 write_pointer(value); | |
504 } | |
505 }; | |
506 | |
507 // An argument formatter. | |
508 template <typename Char> | |
509 class ArgFormatter : public BasicArgFormatter<ArgFormatter<Char>, Char> { | |
510 private: | |
511 BasicFormatter<Char> &formatter_; | |
512 const Char *format_; | |
513 | |
514 public: | |
515 ArgFormatter(BasicFormatter<Char> &f, FormatSpec &s, const Char *fmt) | |
516 : BasicArgFormatter<ArgFormatter<Char>, Char>(f.writer(), s), | |
517 formatter_(f), format_(fmt) {} | |
518 | |
519 void visit_custom(Arg::CustomValue c) { | |
520 c.format(&formatter_, c.value, &format_); | |
521 } | |
522 }; | |
523 | |
524 template <typename Char> | |
525 class PrintfArgFormatter : | |
526 public BasicArgFormatter<PrintfArgFormatter<Char>, Char> { | |
527 | |
528 void write_null_pointer() { | |
529 this->spec().type_ = 0; | |
530 this->write("(nil)"); | |
531 } | |
532 | |
533 typedef BasicArgFormatter<PrintfArgFormatter<Char>, Char> Base; | |
534 | |
535 public: | |
536 PrintfArgFormatter(BasicWriter<Char> &w, FormatSpec &s) | |
537 : BasicArgFormatter<PrintfArgFormatter<Char>, Char>(w, s) {} | |
538 | |
539 void visit_bool(bool value) { | |
540 FormatSpec &fmt_spec = this->spec(); | |
541 if (fmt_spec.type_ != 's') | |
542 return this->visit_any_int(value); | |
543 fmt_spec.type_ = 0; | |
544 this->write(value); | |
545 } | |
546 | |
547 void visit_char(int value) { | |
548 const FormatSpec &fmt_spec = this->spec(); | |
549 BasicWriter<Char> &w = this->writer(); | |
550 if (fmt_spec.type_ && fmt_spec.type_ != 'c') | |
551 w.write_int(value, fmt_spec); | |
552 typedef typename BasicWriter<Char>::CharPtr CharPtr; | |
553 CharPtr out = CharPtr(); | |
554 if (fmt_spec.width_ > 1) { | |
555 Char fill = ' '; | |
556 out = w.grow_buffer(fmt_spec.width_); | |
557 if (fmt_spec.align_ != ALIGN_LEFT) { | |
558 std::fill_n(out, fmt_spec.width_ - 1, fill); | |
559 out += fmt_spec.width_ - 1; | |
560 } else { | |
561 std::fill_n(out + 1, fmt_spec.width_ - 1, fill); | |
562 } | |
563 } else { | |
564 out = w.grow_buffer(1); | |
565 } | |
566 *out = static_cast<Char>(value); | |
567 } | |
568 | |
569 void visit_cstring(const char *value) { | |
570 if (value) | |
571 Base::visit_cstring(value); | |
572 else if (this->spec().type_ == 'p') | |
573 write_null_pointer(); | |
574 else | |
575 this->write("(null)"); | |
576 } | |
577 | |
578 void visit_pointer(const void *value) { | |
579 if (value) | |
580 return Base::visit_pointer(value); | |
581 this->spec().type_ = 0; | |
582 write_null_pointer(); | |
583 } | |
584 | |
585 void visit_custom(Arg::CustomValue c) { | |
586 BasicFormatter<Char> formatter(ArgList(), this->writer()); | |
587 const Char format_str[] = {'}', 0}; | |
588 const Char *format = format_str; | |
589 c.format(&formatter, c.value, &format); | |
590 } | |
591 }; | |
592 } // namespace internal | |
593 } // namespace fmt | |
594 | |
595 FMT_FUNC void fmt::SystemError::init( | |
596 int err_code, CStringRef format_str, ArgList args) { | |
597 error_code_ = err_code; | |
598 MemoryWriter w; | |
599 internal::format_system_error(w, err_code, format(format_str, args)); | |
600 std::runtime_error &base = *this; | |
601 base = std::runtime_error(w.str()); | |
602 } | |
603 | |
604 template <typename T> | |
605 int fmt::internal::CharTraits<char>::format_float( | |
606 char *buffer, std::size_t size, const char *format, | |
607 unsigned width, int precision, T value) { | |
608 if (width == 0) { | |
609 return precision < 0 ? | |
610 FMT_SNPRINTF(buffer, size, format, value) : | |
611 FMT_SNPRINTF(buffer, size, format, precision, value); | |
612 } | |
613 return precision < 0 ? | |
614 FMT_SNPRINTF(buffer, size, format, width, value) : | |
615 FMT_SNPRINTF(buffer, size, format, width, precision, value); | |
616 } | |
617 | |
618 template <typename T> | |
619 int fmt::internal::CharTraits<wchar_t>::format_float( | |
620 wchar_t *buffer, std::size_t size, const wchar_t *format, | |
621 unsigned width, int precision, T value) { | |
622 if (width == 0) { | |
623 return precision < 0 ? | |
624 FMT_SWPRINTF(buffer, size, format, value) : | |
625 FMT_SWPRINTF(buffer, size, format, precision, value); | |
626 } | |
627 return precision < 0 ? | |
628 FMT_SWPRINTF(buffer, size, format, width, value) : | |
629 FMT_SWPRINTF(buffer, size, format, width, precision, value); | |
630 } | |
631 | |
632 template <typename T> | |
633 const char fmt::internal::BasicData<T>::DIGITS[] = | |
634 "0001020304050607080910111213141516171819" | |
635 "2021222324252627282930313233343536373839" | |
636 "4041424344454647484950515253545556575859" | |
637 "6061626364656667686970717273747576777879" | |
638 "8081828384858687888990919293949596979899"; | |
639 | |
640 #define FMT_POWERS_OF_10(factor) \ | |
641 factor * 10, \ | |
642 factor * 100, \ | |
643 factor * 1000, \ | |
644 factor * 10000, \ | |
645 factor * 100000, \ | |
646 factor * 1000000, \ | |
647 factor * 10000000, \ | |
648 factor * 100000000, \ | |
649 factor * 1000000000 | |
650 | |
651 template <typename T> | |
652 const uint32_t fmt::internal::BasicData<T>::POWERS_OF_10_32[] = { | |
653 0, FMT_POWERS_OF_10(1) | |
654 }; | |
655 | |
656 template <typename T> | |
657 const uint64_t fmt::internal::BasicData<T>::POWERS_OF_10_64[] = { | |
658 0, | |
659 FMT_POWERS_OF_10(1), | |
660 FMT_POWERS_OF_10(fmt::ULongLong(1000000000)), | |
661 // Multiply several constants instead of using a single long long constant | |
662 // to avoid warnings about C++98 not supporting long long. | |
663 fmt::ULongLong(1000000000) * fmt::ULongLong(1000000000) * 10 | |
664 }; | |
665 | |
666 FMT_FUNC void fmt::internal::report_unknown_type(char code, const char *type) { | |
667 (void)type; | |
668 if (std::isprint(static_cast<unsigned char>(code))) { | |
669 FMT_THROW(fmt::FormatError( | |
670 fmt::format("unknown format code '{}' for {}", code, type))); | |
671 } | |
672 FMT_THROW(fmt::FormatError( | |
673 fmt::format("unknown format code '\\x{:02x}' for {}", | |
674 static_cast<unsigned>(code), type))); | |
675 } | |
676 | |
677 #if FMT_USE_WINDOWS_H | |
678 | |
679 FMT_FUNC fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) { | |
680 static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16"; | |
681 if (s.size() > INT_MAX) | |
682 FMT_THROW(WindowsError(ERROR_INVALID_PARAMETER, ERROR_MSG)); | |
683 int s_size = static_cast<int>(s.size()); | |
684 int length = MultiByteToWideChar( | |
685 CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, 0, 0); | |
686 if (length == 0) | |
687 FMT_THROW(WindowsError(GetLastError(), ERROR_MSG)); | |
688 buffer_.resize(length + 1); | |
689 length = MultiByteToWideChar( | |
690 CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length); | |
691 if (length == 0) | |
692 FMT_THROW(WindowsError(GetLastError(), ERROR_MSG)); | |
693 buffer_[length] = 0; | |
694 } | |
695 | |
696 FMT_FUNC fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) { | |
697 if (int error_code = convert(s)) { | |
698 FMT_THROW(WindowsError(error_code, | |
699 "cannot convert string from UTF-16 to UTF-8")); | |
700 } | |
701 } | |
702 | |
703 FMT_FUNC int fmt::internal::UTF16ToUTF8::convert(fmt::WStringRef s) { | |
704 if (s.size() > INT_MAX) | |
705 return ERROR_INVALID_PARAMETER; | |
706 int s_size = static_cast<int>(s.size()); | |
707 int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, 0, 0, 0, 0); | |
708 if (length == 0) | |
709 return GetLastError(); | |
710 buffer_.resize(length + 1); | |
711 length = WideCharToMultiByte( | |
712 CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, 0, 0); | |
713 if (length == 0) | |
714 return GetLastError(); | |
715 buffer_[length] = 0; | |
716 return 0; | |
717 } | |
718 | |
719 FMT_FUNC void fmt::WindowsError::init( | |
720 int err_code, CStringRef format_str, ArgList args) { | |
721 error_code_ = err_code; | |
722 MemoryWriter w; | |
723 internal::format_windows_error(w, err_code, format(format_str, args)); | |
724 std::runtime_error &base = *this; | |
725 base = std::runtime_error(w.str()); | |
726 } | |
727 | |
728 FMT_FUNC void fmt::internal::format_windows_error( | |
729 fmt::Writer &out, int error_code, | |
730 fmt::StringRef message) FMT_NOEXCEPT { | |
731 class String { | |
732 private: | |
733 LPWSTR str_; | |
734 | |
735 public: | |
736 String() : str_() {} | |
737 ~String() { LocalFree(str_); } | |
738 LPWSTR *ptr() { return &str_; } | |
739 LPCWSTR c_str() const { return str_; } | |
740 }; | |
741 FMT_TRY { | |
742 String system_message; | |
743 if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | | |
744 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, | |
745 error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), | |
746 reinterpret_cast<LPWSTR>(system_message.ptr()), 0, 0)) { | |
747 UTF16ToUTF8 utf8_message; | |
748 if (utf8_message.convert(system_message.c_str()) == ERROR_SUCCESS) { | |
749 out << message << ": " << utf8_message; | |
750 return; | |
751 } | |
752 } | |
753 } FMT_CATCH(...) {} | |
754 fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32. | |
755 } | |
756 | |
757 #endif // FMT_USE_WINDOWS_H | |
758 | |
759 FMT_FUNC void fmt::internal::format_system_error( | |
760 fmt::Writer &out, int error_code, | |
761 fmt::StringRef message) FMT_NOEXCEPT { | |
762 FMT_TRY { | |
763 MemoryBuffer<char, INLINE_BUFFER_SIZE> buffer; | |
764 buffer.resize(INLINE_BUFFER_SIZE); | |
765 for (;;) { | |
766 char *system_message = &buffer[0]; | |
767 int result = safe_strerror(error_code, system_message, buffer.size()); | |
768 if (result == 0) { | |
769 out << message << ": " << system_message; | |
770 return; | |
771 } | |
772 if (result != ERANGE) | |
773 break; // Can't get error message, report error code instead. | |
774 buffer.resize(buffer.size() * 2); | |
775 } | |
776 } FMT_CATCH(...) {} | |
777 fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32. | |
778 } | |
779 | |
780 template <typename Char> | |
781 void fmt::internal::ArgMap<Char>::init(const ArgList &args) { | |
782 if (!map_.empty()) | |
783 return; | |
784 typedef internal::NamedArg<Char> NamedArg; | |
785 const NamedArg *named_arg = 0; | |
786 bool use_values = | |
787 args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE; | |
788 if (use_values) { | |
789 for (unsigned i = 0;/*nothing*/; ++i) { | |
790 internal::Arg::Type arg_type = args.type(i); | |
791 switch (arg_type) { | |
792 case internal::Arg::NONE: | |
793 return; | |
794 case internal::Arg::NAMED_ARG: | |
795 named_arg = static_cast<const NamedArg*>(args.values_[i].pointer); | |
796 map_.insert(Pair(named_arg->name, *named_arg)); | |
797 break; | |
798 default: | |
799 /*nothing*/; | |
800 } | |
801 } | |
802 return; | |
803 } | |
804 for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) { | |
805 internal::Arg::Type arg_type = args.type(i); | |
806 if (arg_type == internal::Arg::NAMED_ARG) { | |
807 named_arg = static_cast<const NamedArg*>(args.args_[i].pointer); | |
808 map_.insert(Pair(named_arg->name, *named_arg)); | |
809 } | |
810 } | |
811 for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) { | |
812 switch (args.args_[i].type) { | |
813 case internal::Arg::NONE: | |
814 return; | |
815 case internal::Arg::NAMED_ARG: | |
816 named_arg = static_cast<const NamedArg*>(args.args_[i].pointer); | |
817 map_.insert(Pair(named_arg->name, *named_arg)); | |
818 break; | |
819 default: | |
820 /*nothing*/; | |
821 } | |
822 } | |
823 } | |
824 | |
825 template <typename Char> | |
826 void fmt::internal::FixedBuffer<Char>::grow(std::size_t) { | |
827 FMT_THROW(std::runtime_error("buffer overflow")); | |
828 } | |
829 | |
830 template <typename Char> | |
831 template <typename StrChar> | |
832 void fmt::BasicWriter<Char>::write_str( | |
833 const Arg::StringValue<StrChar> &s, const FormatSpec &spec) { | |
834 // Check if StrChar is convertible to Char. | |
835 internal::CharTraits<Char>::convert(StrChar()); | |
836 if (spec.type_ && spec.type_ != 's') | |
837 internal::report_unknown_type(spec.type_, "string"); | |
838 const StrChar *str_value = s.value; | |
839 std::size_t str_size = s.size; | |
840 if (str_size == 0) { | |
841 if (!str_value) { | |
842 FMT_THROW(FormatError("string pointer is null")); | |
843 return; | |
844 } | |
845 } | |
846 std::size_t precision = spec.precision_; | |
847 if (spec.precision_ >= 0 && precision < str_size) | |
848 str_size = spec.precision_; | |
849 write_str(str_value, str_size, spec); | |
850 } | |
851 | |
852 template <typename Char> | |
853 inline Arg fmt::BasicFormatter<Char>::get_arg( | |
854 BasicStringRef<Char> arg_name, const char *&error) { | |
855 if (check_no_auto_index(error)) { | |
856 map_.init(args()); | |
857 const Arg *arg = map_.find(arg_name); | |
858 if (arg) | |
859 return *arg; | |
860 error = "argument not found"; | |
861 } | |
862 return Arg(); | |
863 } | |
864 | |
865 template <typename Char> | |
866 inline Arg fmt::BasicFormatter<Char>::parse_arg_index(const Char *&s) { | |
867 const char *error = 0; | |
868 Arg arg = *s < '0' || *s > '9' ? | |
869 next_arg(error) : get_arg(parse_nonnegative_int(s), error); | |
870 if (error) { | |
871 FMT_THROW(FormatError( | |
872 *s != '}' && *s != ':' ? "invalid format string" : error)); | |
873 } | |
874 return arg; | |
875 } | |
876 | |
877 template <typename Char> | |
878 inline Arg fmt::BasicFormatter<Char>::parse_arg_name(const Char *&s) { | |
879 assert(is_name_start(*s)); | |
880 const Char *start = s; | |
881 Char c; | |
882 do { | |
883 c = *++s; | |
884 } while (is_name_start(c) || ('0' <= c && c <= '9')); | |
885 const char *error = 0; | |
886 Arg arg = get_arg(fmt::BasicStringRef<Char>(start, s - start), error); | |
887 if (error) | |
888 FMT_THROW(fmt::FormatError(error)); | |
889 return arg; | |
890 } | |
891 | |
892 FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg( | |
893 unsigned arg_index, const char *&error) { | |
894 Arg arg = args_[arg_index]; | |
895 switch (arg.type) { | |
896 case Arg::NONE: | |
897 error = "argument index out of range"; | |
898 break; | |
899 case Arg::NAMED_ARG: | |
900 arg = *static_cast<const internal::Arg*>(arg.pointer); | |
901 default: | |
902 /*nothing*/; | |
903 } | |
904 return arg; | |
905 } | |
906 | |
907 inline Arg fmt::internal::FormatterBase::next_arg(const char *&error) { | |
908 if (next_arg_index_ >= 0) | |
909 return do_get_arg(next_arg_index_++, error); | |
910 error = "cannot switch from manual to automatic argument indexing"; | |
911 return Arg(); | |
912 } | |
913 | |
914 inline bool fmt::internal::FormatterBase::check_no_auto_index( | |
915 const char *&error) { | |
916 if (next_arg_index_ > 0) { | |
917 error = "cannot switch from automatic to manual argument indexing"; | |
918 return false; | |
919 } | |
920 next_arg_index_ = -1; | |
921 return true; | |
922 } | |
923 | |
924 inline Arg fmt::internal::FormatterBase::get_arg( | |
925 unsigned arg_index, const char *&error) { | |
926 return check_no_auto_index(error) ? do_get_arg(arg_index, error) : Arg(); | |
927 } | |
928 | |
929 template <typename Char> | |
930 void fmt::internal::PrintfFormatter<Char>::parse_flags( | |
931 FormatSpec &spec, const Char *&s) { | |
932 for (;;) { | |
933 switch (*s++) { | |
934 case '-': | |
935 spec.align_ = ALIGN_LEFT; | |
936 break; | |
937 case '+': | |
938 spec.flags_ |= SIGN_FLAG | PLUS_FLAG; | |
939 break; | |
940 case '0': | |
941 spec.fill_ = '0'; | |
942 break; | |
943 case ' ': | |
944 spec.flags_ |= SIGN_FLAG; | |
945 break; | |
946 case '#': | |
947 spec.flags_ |= HASH_FLAG; | |
948 break; | |
949 default: | |
950 --s; | |
951 return; | |
952 } | |
953 } | |
954 } | |
955 | |
956 template <typename Char> | |
957 Arg fmt::internal::PrintfFormatter<Char>::get_arg( | |
958 const Char *s, unsigned arg_index) { | |
959 (void)s; | |
960 const char *error = 0; | |
961 Arg arg = arg_index == UINT_MAX ? | |
962 next_arg(error) : FormatterBase::get_arg(arg_index - 1, error); | |
963 if (error) | |
964 FMT_THROW(FormatError(!*s ? "invalid format string" : error)); | |
965 return arg; | |
966 } | |
967 | |
968 template <typename Char> | |
969 unsigned fmt::internal::PrintfFormatter<Char>::parse_header( | |
970 const Char *&s, FormatSpec &spec) { | |
971 unsigned arg_index = UINT_MAX; | |
972 Char c = *s; | |
973 if (c >= '0' && c <= '9') { | |
974 // Parse an argument index (if followed by '$') or a width possibly | |
975 // preceded with '0' flag(s). | |
976 unsigned value = parse_nonnegative_int(s); | |
977 if (*s == '$') { // value is an argument index | |
978 ++s; | |
979 arg_index = value; | |
980 } else { | |
981 if (c == '0') | |
982 spec.fill_ = '0'; | |
983 if (value != 0) { | |
984 // Nonzero value means that we parsed width and don't need to | |
985 // parse it or flags again, so return now. | |
986 spec.width_ = value; | |
987 return arg_index; | |
988 } | |
989 } | |
990 } | |
991 parse_flags(spec, s); | |
992 // Parse width. | |
993 if (*s >= '0' && *s <= '9') { | |
994 spec.width_ = parse_nonnegative_int(s); | |
995 } else if (*s == '*') { | |
996 ++s; | |
997 spec.width_ = WidthHandler(spec).visit(get_arg(s)); | |
998 } | |
999 return arg_index; | |
1000 } | |
1001 | |
1002 template <typename Char> | |
1003 void fmt::internal::PrintfFormatter<Char>::format( | |
1004 BasicWriter<Char> &writer, BasicCStringRef<Char> format_str) { | |
1005 const Char *start = format_str.c_str(); | |
1006 const Char *s = start; | |
1007 while (*s) { | |
1008 Char c = *s++; | |
1009 if (c != '%') continue; | |
1010 if (*s == c) { | |
1011 write(writer, start, s); | |
1012 start = ++s; | |
1013 continue; | |
1014 } | |
1015 write(writer, start, s - 1); | |
1016 | |
1017 FormatSpec spec; | |
1018 spec.align_ = ALIGN_RIGHT; | |
1019 | |
1020 // Parse argument index, flags and width. | |
1021 unsigned arg_index = parse_header(s, spec); | |
1022 | |
1023 // Parse precision. | |
1024 if (*s == '.') { | |
1025 ++s; | |
1026 if ('0' <= *s && *s <= '9') { | |
1027 spec.precision_ = parse_nonnegative_int(s); | |
1028 } else if (*s == '*') { | |
1029 ++s; | |
1030 spec.precision_ = PrecisionHandler().visit(get_arg(s)); | |
1031 } | |
1032 } | |
1033 | |
1034 Arg arg = get_arg(s, arg_index); | |
1035 if (spec.flag(HASH_FLAG) && IsZeroInt().visit(arg)) | |
1036 spec.flags_ &= ~HASH_FLAG; | |
1037 if (spec.fill_ == '0') { | |
1038 if (arg.type <= Arg::LAST_NUMERIC_TYPE) | |
1039 spec.align_ = ALIGN_NUMERIC; | |
1040 else | |
1041 spec.fill_ = ' '; // Ignore '0' flag for non-numeric types. | |
1042 } | |
1043 | |
1044 // Parse length and convert the argument to the required type. | |
1045 switch (*s++) { | |
1046 case 'h': | |
1047 if (*s == 'h') | |
1048 ArgConverter<signed char>(arg, *++s).visit(arg); | |
1049 else | |
1050 ArgConverter<short>(arg, *s).visit(arg); | |
1051 break; | |
1052 case 'l': | |
1053 if (*s == 'l') | |
1054 ArgConverter<fmt::LongLong>(arg, *++s).visit(arg); | |
1055 else | |
1056 ArgConverter<long>(arg, *s).visit(arg); | |
1057 break; | |
1058 case 'j': | |
1059 ArgConverter<intmax_t>(arg, *s).visit(arg); | |
1060 break; | |
1061 case 'z': | |
1062 ArgConverter<std::size_t>(arg, *s).visit(arg); | |
1063 break; | |
1064 case 't': | |
1065 ArgConverter<std::ptrdiff_t>(arg, *s).visit(arg); | |
1066 break; | |
1067 case 'L': | |
1068 // printf produces garbage when 'L' is omitted for long double, no | |
1069 // need to do the same. | |
1070 break; | |
1071 default: | |
1072 --s; | |
1073 ArgConverter<int>(arg, *s).visit(arg); | |
1074 } | |
1075 | |
1076 // Parse type. | |
1077 if (!*s) | |
1078 FMT_THROW(FormatError("invalid format string")); | |
1079 spec.type_ = static_cast<char>(*s++); | |
1080 if (arg.type <= Arg::LAST_INTEGER_TYPE) { | |
1081 // Normalize type. | |
1082 switch (spec.type_) { | |
1083 case 'i': case 'u': | |
1084 spec.type_ = 'd'; | |
1085 break; | |
1086 case 'c': | |
1087 // TODO: handle wchar_t | |
1088 CharConverter(arg).visit(arg); | |
1089 break; | |
1090 } | |
1091 } | |
1092 | |
1093 start = s; | |
1094 | |
1095 // Format argument. | |
1096 internal::PrintfArgFormatter<Char>(writer, spec).visit(arg); | |
1097 } | |
1098 write(writer, start, s); | |
1099 } | |
1100 | |
1101 template <typename Char> | |
1102 const Char *fmt::BasicFormatter<Char>::format( | |
1103 const Char *&format_str, const Arg &arg) { | |
1104 const Char *s = format_str; | |
1105 FormatSpec spec; | |
1106 if (*s == ':') { | |
1107 if (arg.type == Arg::CUSTOM) { | |
1108 arg.custom.format(this, arg.custom.value, &s); | |
1109 return s; | |
1110 } | |
1111 ++s; | |
1112 // Parse fill and alignment. | |
1113 if (Char c = *s) { | |
1114 const Char *p = s + 1; | |
1115 spec.align_ = ALIGN_DEFAULT; | |
1116 do { | |
1117 switch (*p) { | |
1118 case '<': | |
1119 spec.align_ = ALIGN_LEFT; | |
1120 break; | |
1121 case '>': | |
1122 spec.align_ = ALIGN_RIGHT; | |
1123 break; | |
1124 case '=': | |
1125 spec.align_ = ALIGN_NUMERIC; | |
1126 break; | |
1127 case '^': | |
1128 spec.align_ = ALIGN_CENTER; | |
1129 break; | |
1130 } | |
1131 if (spec.align_ != ALIGN_DEFAULT) { | |
1132 if (p != s) { | |
1133 if (c == '}') break; | |
1134 if (c == '{') | |
1135 FMT_THROW(FormatError("invalid fill character '{'")); | |
1136 s += 2; | |
1137 spec.fill_ = c; | |
1138 } else ++s; | |
1139 if (spec.align_ == ALIGN_NUMERIC) | |
1140 require_numeric_argument(arg, '='); | |
1141 break; | |
1142 } | |
1143 } while (--p >= s); | |
1144 } | |
1145 | |
1146 // Parse sign. | |
1147 switch (*s) { | |
1148 case '+': | |
1149 check_sign(s, arg); | |
1150 spec.flags_ |= SIGN_FLAG | PLUS_FLAG; | |
1151 break; | |
1152 case '-': | |
1153 check_sign(s, arg); | |
1154 spec.flags_ |= MINUS_FLAG; | |
1155 break; | |
1156 case ' ': | |
1157 check_sign(s, arg); | |
1158 spec.flags_ |= SIGN_FLAG; | |
1159 break; | |
1160 } | |
1161 | |
1162 if (*s == '#') { | |
1163 require_numeric_argument(arg, '#'); | |
1164 spec.flags_ |= HASH_FLAG; | |
1165 ++s; | |
1166 } | |
1167 | |
1168 // Parse zero flag. | |
1169 if (*s == '0') { | |
1170 require_numeric_argument(arg, '0'); | |
1171 spec.align_ = ALIGN_NUMERIC; | |
1172 spec.fill_ = '0'; | |
1173 ++s; | |
1174 } | |
1175 | |
1176 // Parse width. | |
1177 if ('0' <= *s && *s <= '9') { | |
1178 spec.width_ = parse_nonnegative_int(s); | |
1179 } else if (*s == '{') { | |
1180 ++s; | |
1181 Arg width_arg = is_name_start(*s) ? | |
1182 parse_arg_name(s) : parse_arg_index(s); | |
1183 if (*s++ != '}') | |
1184 FMT_THROW(FormatError("invalid format string")); | |
1185 ULongLong value = 0; | |
1186 switch (width_arg.type) { | |
1187 case Arg::INT: | |
1188 if (width_arg.int_value < 0) | |
1189 FMT_THROW(FormatError("negative width")); | |
1190 value = width_arg.int_value; | |
1191 break; | |
1192 case Arg::UINT: | |
1193 value = width_arg.uint_value; | |
1194 break; | |
1195 case Arg::LONG_LONG: | |
1196 if (width_arg.long_long_value < 0) | |
1197 FMT_THROW(FormatError("negative width")); | |
1198 value = width_arg.long_long_value; | |
1199 break; | |
1200 case Arg::ULONG_LONG: | |
1201 value = width_arg.ulong_long_value; | |
1202 break; | |
1203 default: | |
1204 FMT_THROW(FormatError("width is not integer")); | |
1205 } | |
1206 if (value > INT_MAX) | |
1207 FMT_THROW(FormatError("number is too big")); | |
1208 spec.width_ = static_cast<int>(value); | |
1209 } | |
1210 | |
1211 // Parse precision. | |
1212 if (*s == '.') { | |
1213 ++s; | |
1214 spec.precision_ = 0; | |
1215 if ('0' <= *s && *s <= '9') { | |
1216 spec.precision_ = parse_nonnegative_int(s); | |
1217 } else if (*s == '{') { | |
1218 ++s; | |
1219 Arg precision_arg = | |
1220 is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s); | |
1221 if (*s++ != '}') | |
1222 FMT_THROW(FormatError("invalid format string")); | |
1223 ULongLong value = 0; | |
1224 switch (precision_arg.type) { | |
1225 case Arg::INT: | |
1226 if (precision_arg.int_value < 0) | |
1227 FMT_THROW(FormatError("negative precision")); | |
1228 value = precision_arg.int_value; | |
1229 break; | |
1230 case Arg::UINT: | |
1231 value = precision_arg.uint_value; | |
1232 break; | |
1233 case Arg::LONG_LONG: | |
1234 if (precision_arg.long_long_value < 0) | |
1235 FMT_THROW(FormatError("negative precision")); | |
1236 value = precision_arg.long_long_value; | |
1237 break; | |
1238 case Arg::ULONG_LONG: | |
1239 value = precision_arg.ulong_long_value; | |
1240 break; | |
1241 default: | |
1242 FMT_THROW(FormatError("precision is not integer")); | |
1243 } | |
1244 if (value > INT_MAX) | |
1245 FMT_THROW(FormatError("number is too big")); | |
1246 spec.precision_ = static_cast<int>(value); | |
1247 } else { | |
1248 FMT_THROW(FormatError("missing precision specifier")); | |
1249 } | |
1250 if (arg.type <= Arg::LAST_INTEGER_TYPE || arg.type == Arg::POINTER) { | |
1251 FMT_THROW(FormatError( | |
1252 fmt::format("precision not allowed in {} format specifier", | |
1253 arg.type == Arg::POINTER ? "pointer" : "integer"))); | |
1254 } | |
1255 } | |
1256 | |
1257 // Parse type. | |
1258 if (*s != '}' && *s) | |
1259 spec.type_ = static_cast<char>(*s++); | |
1260 } | |
1261 | |
1262 if (*s++ != '}') | |
1263 FMT_THROW(FormatError("missing '}' in format string")); | |
1264 | |
1265 // Format argument. | |
1266 internal::ArgFormatter<Char>(*this, spec, s - 1).visit(arg); | |
1267 return s; | |
1268 } | |
1269 | |
1270 template <typename Char> | |
1271 void fmt::BasicFormatter<Char>::format(BasicCStringRef<Char> format_str) { | |
1272 const Char *s = format_str.c_str(); | |
1273 const Char *start = s; | |
1274 while (*s) { | |
1275 Char c = *s++; | |
1276 if (c != '{' && c != '}') continue; | |
1277 if (*s == c) { | |
1278 write(writer_, start, s); | |
1279 start = ++s; | |
1280 continue; | |
1281 } | |
1282 if (c == '}') | |
1283 FMT_THROW(FormatError("unmatched '}' in format string")); | |
1284 write(writer_, start, s - 1); | |
1285 Arg arg = is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s); | |
1286 start = s = format(s, arg); | |
1287 } | |
1288 write(writer_, start, s); | |
1289 } | |
1290 | |
1291 FMT_FUNC void fmt::report_system_error( | |
1292 int error_code, fmt::StringRef message) FMT_NOEXCEPT { | |
1293 // 'fmt::' is for bcc32. | |
1294 fmt::report_error(internal::format_system_error, error_code, message); | |
1295 } | |
1296 | |
1297 #if FMT_USE_WINDOWS_H | |
1298 FMT_FUNC void fmt::report_windows_error( | |
1299 int error_code, fmt::StringRef message) FMT_NOEXCEPT { | |
1300 // 'fmt::' is for bcc32. | |
1301 fmt::report_error(internal::format_windows_error, error_code, message); | |
1302 } | |
1303 #endif | |
1304 | |
1305 FMT_FUNC void fmt::print(std::FILE *f, CStringRef format_str, ArgList args) { | |
1306 MemoryWriter w; | |
1307 w.write(format_str, args); | |
1308 std::fwrite(w.data(), 1, w.size(), f); | |
1309 } | |
1310 | |
1311 FMT_FUNC void fmt::print(CStringRef format_str, ArgList args) { | |
1312 print(stdout, format_str, args); | |
1313 } | |
1314 | |
1315 FMT_FUNC void fmt::print(std::ostream &os, CStringRef format_str, ArgList args) { | |
1316 MemoryWriter w; | |
1317 w.write(format_str, args); | |
1318 os.write(w.data(), w.size()); | |
1319 } | |
1320 | |
1321 FMT_FUNC void fmt::print_colored(Color c, CStringRef format, ArgList args) { | |
1322 char escape[] = "\x1b[30m"; | |
1323 escape[3] = static_cast<char>('0' + c); | |
1324 std::fputs(escape, stdout); | |
1325 print(format, args); | |
1326 std::fputs(RESET_COLOR, stdout); | |
1327 } | |
1328 | |
1329 FMT_FUNC int fmt::fprintf(std::FILE *f, CStringRef format, ArgList args) { | |
1330 MemoryWriter w; | |
1331 printf(w, format, args); | |
1332 std::size_t size = w.size(); | |
1333 return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size); | |
1334 } | |
1335 | |
1336 #ifndef FMT_HEADER_ONLY | |
1337 | |
1338 template struct fmt::internal::BasicData<void>; | |
1339 | |
1340 // Explicit instantiations for char. | |
1341 | |
1342 template void fmt::internal::FixedBuffer<char>::grow(std::size_t); | |
1343 | |
1344 template const char *fmt::BasicFormatter<char>::format( | |
1345 const char *&format_str, const fmt::internal::Arg &arg); | |
1346 | |
1347 template void fmt::BasicFormatter<char>::format(CStringRef format); | |
1348 | |
1349 template void fmt::internal::PrintfFormatter<char>::format( | |
1350 BasicWriter<char> &writer, CStringRef format); | |
1351 | |
1352 template int fmt::internal::CharTraits<char>::format_float( | |
1353 char *buffer, std::size_t size, const char *format, | |
1354 unsigned width, int precision, double value); | |
1355 | |
1356 template int fmt::internal::CharTraits<char>::format_float( | |
1357 char *buffer, std::size_t size, const char *format, | |
1358 unsigned width, int precision, long double value); | |
1359 | |
1360 // Explicit instantiations for wchar_t. | |
1361 | |
1362 template void fmt::internal::FixedBuffer<wchar_t>::grow(std::size_t); | |
1363 | |
1364 template const wchar_t *fmt::BasicFormatter<wchar_t>::format( | |
1365 const wchar_t *&format_str, const fmt::internal::Arg &arg); | |
1366 | |
1367 template void fmt::BasicFormatter<wchar_t>::format( | |
1368 BasicCStringRef<wchar_t> format); | |
1369 | |
1370 template void fmt::internal::PrintfFormatter<wchar_t>::format( | |
1371 BasicWriter<wchar_t> &writer, WCStringRef format); | |
1372 | |
1373 template int fmt::internal::CharTraits<wchar_t>::format_float( | |
1374 wchar_t *buffer, std::size_t size, const wchar_t *format, | |
1375 unsigned width, int precision, double value); | |
1376 | |
1377 template int fmt::internal::CharTraits<wchar_t>::format_float( | |
1378 wchar_t *buffer, std::size_t size, const wchar_t *format, | |
1379 unsigned width, int precision, long double value); | |
1380 | |
1381 #endif // FMT_HEADER_ONLY | |
1382 | |
1383 #ifdef _MSC_VER | |
1384 # pragma warning(pop) | |
1385 #endif |