xref: /aosp_15_r20/external/gmmlib/Source/GmmLib/Utility/GmmLog/spdlog/details/format.cc (revision 35ffd701415c9e32e53136d61a677a8d0a8fc4a5)
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 #if FMT_EXCEPTIONS
56 # define FMT_TRY try
57 # define FMT_CATCH(x) catch (x)
58 #else
59 # define FMT_TRY if (true)
60 # define FMT_CATCH(x) if (false)
61 #endif
62 
63 #ifdef FMT_HEADER_ONLY
64 # define FMT_FUNC inline
65 #else
66 # define FMT_FUNC
67 #endif
68 
69 #ifdef _MSC_VER
70 # pragma warning(push)
71 # pragma warning(disable: 4127)  // conditional expression is constant
72 # pragma warning(disable: 4702)  // unreachable code
73 // Disable deprecation warning for strerror. The latter is not called but
74 // MSVC fails to detect it.
75 # pragma warning(disable: 4996)
76 #endif
77 
78 // Dummy implementations of strerror_r and strerror_s called if corresponding
79 // system functions are not available.
strerror_r(int,char *,...)80 static inline fmt::internal::Null<> strerror_r(int, char *, ...)
81 {
82 	return fmt::internal::Null<>();
83 }
strerror_s(char *,std::size_t,...)84 static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...)
85 {
86 	return fmt::internal::Null<>();
87 }
88 
89 namespace fmt {
90 	namespace {
91 
92 #ifndef _MSC_VER
93 # define FMT_SNPRINTF snprintf
94 #else  // _MSC_VER
95 		inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...)
96 		{
97 			va_list args;
98 			va_start(args, format);
99 			int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
100 			va_end(args);
101 			return result;
102 		}
103 # define FMT_SNPRINTF fmt_snprintf
104 #endif  // _MSC_VER
105 
106 #if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
107 # define FMT_SWPRINTF snwprintf
108 #else
109 # define FMT_SWPRINTF swprintf
110 #endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
111 
112 		// Checks if a value fits in int - used to avoid warnings about comparing
113 		// signed and unsigned integers.
114 		template <bool IsSigned>
115 		struct IntChecker
116 		{
117 			template <typename T>
fits_in_intfmt::__anon35f1b3140111::IntChecker118 			static bool fits_in_int(T value)
119 			{
120 				unsigned max = INT_MAX;
121 				return value <= max;
122 			}
fits_in_intfmt::__anon35f1b3140111::IntChecker123 			static bool fits_in_int(bool)
124 			{
125 				return true;
126 			}
127 		};
128 
129 		template <>
130 		struct IntChecker<true>
131 		{
132 			template <typename T>
fits_in_intfmt::__anon35f1b3140111::IntChecker133 			static bool fits_in_int(T value)
134 			{
135 				return value >= INT_MIN && value <= INT_MAX;
136 			}
fits_in_intfmt::__anon35f1b3140111::IntChecker137 			static bool fits_in_int(int)
138 			{
139 				return true;
140 			}
141 		};
142 
143 		const char RESET_COLOR[] = "\x1b[0m";
144 
145 		typedef void(*FormatFunc)(fmt::Writer &, int, fmt::StringRef);
146 
147 		// Portable thread-safe version of strerror.
148 		// Sets buffer to point to a string describing the error code.
149 		// This can be either a pointer to a string stored in buffer,
150 		// or a pointer to some static immutable string.
151 		// Returns one of the following values:
152 		//   0      - success
153 		//   ERANGE - buffer is not large enough to store the error message
154 		//   other  - failure
155 		// Buffer should be at least of size 1.
safe_strerror(int error_code,char * & buffer,std::size_t buffer_size)156 		int safe_strerror(
157 			int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT
158 		{
159 			FMT_ASSERT(buffer != 0 && buffer_size != 0, "invalid buffer");
160 
161 			class StrError
162 			{
163 			private:
164 				int error_code_;
165 				char *&buffer_;
166 				std::size_t buffer_size_;
167 
168 				// A noop assignment operator to avoid bogus warnings.
169 				void operator=(const StrError &)
170 				{}
171 
172 				// Handle the result of XSI-compliant version of strerror_r.
173 				int handle(int result)
174 				{
175 					// glibc versions before 2.13 return result in errno.
176 					return result == -1 ? errno : result;
177 				}
178 
179 				// Handle the result of GNU-specific version of strerror_r.
180 				int handle(char *message)
181 				{
182 					// If the buffer is full then the message is probably truncated.
183 					if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1)
184 						return ERANGE;
185 					buffer_ = message;
186 					return 0;
187 				}
188 
189 				// Handle the case when strerror_r is not available.
190 				int handle(fmt::internal::Null<>)
191 				{
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 				{
198 					// If the buffer is full then the message is probably truncated.
199 					return result == 0 && strlen(buffer_) == buffer_size_ - 1 ?
200 						ERANGE : result;
201 				}
202 
203 				// Fallback to strerror if strerror_r and strerror_s are not available.
204 				int fallback(fmt::internal::Null<>)
205 				{
206 					errno = 0;
207 					buffer_ = strerror(error_code_);
208 					return errno;
209 				}
210 
211 			public:
212 				StrError(int err_code, char *&buf, std::size_t buf_size)
213 					: error_code_(err_code), buffer_(buf), buffer_size_(buf_size)
214 				{}
215 
216 				int run()
217 				{
218 					strerror_r(0, 0, "");  // Suppress a warning about unused strerror_r.
219 					return handle(strerror_r(error_code_, buffer_, buffer_size_));
220 				}
221 			};
222 			return StrError(error_code, buffer, buffer_size).run();
223 		}
224 
format_error_code(fmt::Writer & out,int error_code,fmt::StringRef message)225 		void format_error_code(fmt::Writer &out, int error_code,
226 			fmt::StringRef message) FMT_NOEXCEPT
227 		{
228 			// Report error code making sure that the output fits into
229 			// INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential
230 			// bad_alloc.
231 			out.clear();
232 			static const char SEP[] = ": ";
233 			static const char ERROR_STR[] = "error ";
234 			// Subtract 2 to account for terminating null characters in SEP and ERROR_STR.
235 			std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2;
236 			typedef fmt::internal::IntTraits<int>::MainType MainType;
237 			MainType abs_value = static_cast<MainType>(error_code);
238 			if (internal::is_negative(error_code)) {
239 				abs_value = 0 - abs_value;
240 				++error_code_size;
241 			}
242 			error_code_size += fmt::internal::count_digits(abs_value);
243 			if (message.size() <= fmt::internal::INLINE_BUFFER_SIZE - error_code_size)
244 				out << message << SEP;
245 			out << ERROR_STR << error_code;
246 			assert(out.size() <= fmt::internal::INLINE_BUFFER_SIZE);
247 		}
248 
report_error(FormatFunc func,int error_code,fmt::StringRef message)249 		void report_error(FormatFunc func,
250 			int error_code, fmt::StringRef message) FMT_NOEXCEPT
251 		{
252 			fmt::MemoryWriter full_message;
253 			func(full_message, error_code, message);
254 			// Use Writer::data instead of Writer::c_str to avoid potential memory
255 			// allocation.
256 			std::fwrite(full_message.data(), full_message.size(), 1, stderr);
257 			std::fputc('\n', stderr);
258 		}
259 
260 		// IsZeroInt::visit(arg) returns true iff arg is a zero integer.
261 		class IsZeroInt: public fmt::internal::ArgVisitor<IsZeroInt, bool>
262 		{
263 		public:
264 			template <typename T>
visit_any_int(T value)265 			bool visit_any_int(T value)
266 			{
267 				return value == 0;
268 			}
269 		};
270 
271 		// Checks if an argument is a valid printf width specifier and sets
272 		// left alignment if it is negative.
273 		class WidthHandler: public fmt::internal::ArgVisitor<WidthHandler, unsigned>
274 		{
275 		private:
276 			fmt::FormatSpec &spec_;
277 
278 			FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler);
279 
280 		public:
WidthHandler(fmt::FormatSpec & spec)281 			explicit WidthHandler(fmt::FormatSpec &spec): spec_(spec)
282 			{}
283 
report_unhandled_arg()284 			void report_unhandled_arg()
285 			{
286 				FMT_THROW(fmt::FormatError("width is not integer"));
287 			}
288 
289 			template <typename T>
visit_any_int(T value)290 			unsigned visit_any_int(T value)
291 			{
292 				typedef typename fmt::internal::IntTraits<T>::MainType UnsignedType;
293 				UnsignedType width = static_cast<UnsignedType>(value);
294 				if (fmt::internal::is_negative(value)) {
295 					spec_.align_ = fmt::ALIGN_LEFT;
296 					width = 0 - width;
297 				}
298 				if (width > INT_MAX)
299 					FMT_THROW(fmt::FormatError("number is too big"));
300 				return static_cast<unsigned>(width);
301 			}
302 		};
303 
304 		class PrecisionHandler:
305 			public fmt::internal::ArgVisitor<PrecisionHandler, int>
306 		{
307 		public:
report_unhandled_arg()308 			void report_unhandled_arg()
309 			{
310 				FMT_THROW(fmt::FormatError("precision is not integer"));
311 			}
312 
313 			template <typename T>
visit_any_int(T value)314 			int visit_any_int(T value)
315 			{
316 				if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
317 					FMT_THROW(fmt::FormatError("number is too big"));
318 				return static_cast<int>(value);
319 			}
320 		};
321 
322 		template <typename T, typename U>
323 		struct is_same
324 		{
325 			enum
326 			{
327 				value = 0
328 			};
329 		};
330 
331 		template <typename T>
332 		struct is_same<T, T>
333 		{
334 			enum
335 			{
336 				value = 1
337 			};
338 		};
339 
340 		// An argument visitor that converts an integer argument to T for printf,
341 		// if T is an integral type. If T is void, the argument is converted to
342 		// corresponding signed or unsigned type depending on the type specifier:
343 		// 'd' and 'i' - signed, other - unsigned)
344 		template <typename T = void>
345 		class ArgConverter: public fmt::internal::ArgVisitor<ArgConverter<T>, void>
346 		{
347 		private:
348 			fmt::internal::Arg &arg_;
349 			wchar_t type_;
350 
351 			FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter);
352 
353 		public:
ArgConverter(fmt::internal::Arg & arg,wchar_t type)354 			ArgConverter(fmt::internal::Arg &arg, wchar_t type)
355 				: arg_(arg), type_(type)
356 			{}
357 
visit_bool(bool value)358 			void visit_bool(bool value)
359 			{
360 				if (type_ != 's')
361 					visit_any_int(value);
362 			}
363 
364 			template <typename U>
visit_any_int(U value)365 			void visit_any_int(U value)
366 			{
367 				bool is_signed = type_ == 'd' || type_ == 'i';
368 				using fmt::internal::Arg;
369 				typedef typename fmt::internal::Conditional<
370 					is_same<T, void>::value, U, T>::type TargetType;
371 				if (sizeof(TargetType) <= sizeof(int)) {
372 					// Extra casts are used to silence warnings.
373 					if (is_signed) {
374 						arg_.type = Arg::INT;
375 						arg_.int_value = static_cast<int>(static_cast<TargetType>(value));
376 					}
377 					else {
378 						arg_.type = Arg::UINT;
379 						typedef typename fmt::internal::MakeUnsigned<TargetType>::Type Unsigned;
380 						arg_.uint_value = static_cast<unsigned>(static_cast<Unsigned>(value));
381 					}
382 				}
383 				else {
384 					if (is_signed) {
385 						arg_.type = Arg::LONG_LONG;
386 						// glibc's printf doesn't sign extend arguments of smaller types:
387 						//   std::printf("%lld", -42);  // prints "4294967254"
388 						// but we don't have to do the same because it's a UB.
389 						arg_.long_long_value = static_cast<fmt::LongLong>(value);
390 					}
391 					else {
392 						arg_.type = Arg::ULONG_LONG;
393 						arg_.ulong_long_value =
394 							static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
395 					}
396 				}
397 			}
398 		};
399 
400 		// Converts an integer argument to char for printf.
401 		class CharConverter: public fmt::internal::ArgVisitor<CharConverter, void>
402 		{
403 		private:
404 			fmt::internal::Arg &arg_;
405 
406 			FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter);
407 
408 		public:
CharConverter(fmt::internal::Arg & arg)409 			explicit CharConverter(fmt::internal::Arg &arg): arg_(arg)
410 			{}
411 
412 			template <typename T>
visit_any_int(T value)413 			void visit_any_int(T value)
414 			{
415 				arg_.type = Arg::CHAR;
416 				arg_.int_value = static_cast<char>(value);
417 			}
418 		};
419 
420 		// Write the content of w to os.
write(std::ostream & os,fmt::Writer & w)421 		void write(std::ostream &os, fmt::Writer &w)
422 		{
423 			const char *data = w.data();
424 			typedef internal::MakeUnsigned<std::streamsize>::Type UnsignedStreamSize;
425 			UnsignedStreamSize size = w.size();
426 			UnsignedStreamSize max_size =
427 				internal::to_unsigned((std::numeric_limits<std::streamsize>::max)());
428 			do {
429 				UnsignedStreamSize n = size <= max_size ? size : max_size;
430 				os.write(data, static_cast<std::streamsize>(n));
431 				data += n;
432 				size -= n;
433 			} while (size != 0);
434 		}
435 	}  // namespace
436 
437 	namespace internal {
438 
439 		template <typename Char>
440 		class PrintfArgFormatter:
441 			public ArgFormatterBase<PrintfArgFormatter<Char>, Char>
442 		{
443 
write_null_pointer()444 			void write_null_pointer()
445 			{
446 				this->spec().type_ = 0;
447 				this->write("(nil)");
448 			}
449 
450 			typedef ArgFormatterBase<PrintfArgFormatter<Char>, Char> Base;
451 
452 		public:
PrintfArgFormatter(BasicWriter<Char> & w,FormatSpec & s)453 			PrintfArgFormatter(BasicWriter<Char> &w, FormatSpec &s)
454 				: ArgFormatterBase<PrintfArgFormatter<Char>, Char>(w, s)
455 			{}
456 
visit_bool(bool value)457 			void visit_bool(bool value)
458 			{
459 				FormatSpec &fmt_spec = this->spec();
460 				if (fmt_spec.type_ != 's')
461 					return this->visit_any_int(value);
462 				fmt_spec.type_ = 0;
463 				this->write(value);
464 			}
465 
visit_char(int value)466 			void visit_char(int value)
467 			{
468 				const FormatSpec &fmt_spec = this->spec();
469 				BasicWriter<Char> &w = this->writer();
470 				if (fmt_spec.type_ && fmt_spec.type_ != 'c')
471 					w.write_int(value, fmt_spec);
472 				typedef typename BasicWriter<Char>::CharPtr CharPtr;
473 				CharPtr out = CharPtr();
474 				if (fmt_spec.width_ > 1) {
475 					Char fill = ' ';
476 					out = w.grow_buffer(fmt_spec.width_);
477 					if (fmt_spec.align_ != ALIGN_LEFT) {
478 						std::fill_n(out, fmt_spec.width_ - 1, fill);
479 						out += fmt_spec.width_ - 1;
480 					}
481 					else {
482 						std::fill_n(out + 1, fmt_spec.width_ - 1, fill);
483 					}
484 				}
485 				else {
486 					out = w.grow_buffer(1);
487 				}
488 				*out = static_cast<Char>(value);
489 			}
490 
visit_cstring(const char * value)491 			void visit_cstring(const char *value)
492 			{
493 				if (value)
494 					Base::visit_cstring(value);
495 				else if (this->spec().type_ == 'p')
496 					write_null_pointer();
497 				else
498 					this->write("(null)");
499 			}
500 
visit_pointer(const void * value)501 			void visit_pointer(const void *value)
502 			{
503 				if (value)
504 					return Base::visit_pointer(value);
505 				this->spec().type_ = 0;
506 				write_null_pointer();
507 			}
508 
visit_custom(Arg::CustomValue c)509 			void visit_custom(Arg::CustomValue c)
510 			{
511 				BasicFormatter<Char> formatter(ArgList(), this->writer());
512 				const Char format_str[] = { '}', 0 };
513 				const Char *format = format_str;
514 				c.format(&formatter, c.value, &format);
515 			}
516 		};
517 	}  // namespace internal
518 }  // namespace fmt
519 
init(int err_code,CStringRef format_str,ArgList args)520 FMT_FUNC void fmt::SystemError::init(
521 	int err_code, CStringRef format_str, ArgList args)
522 {
523 	error_code_ = err_code;
524 	MemoryWriter w;
525 	internal::format_system_error(w, err_code, format(format_str, args));
526 	std::runtime_error &base = *this;
527 	base = std::runtime_error(w.str());
528 }
529 
530 template <typename T>
format_float(char * buffer,std::size_t size,const char * format,unsigned width,int precision,T value)531 int fmt::internal::CharTraits<char>::format_float(
532 	char *buffer, std::size_t size, const char *format,
533 	unsigned width, int precision, T value)
534 {
535 	if (width == 0) {
536 		return precision < 0 ?
537 			FMT_SNPRINTF(buffer, size, format, value) :
538 			FMT_SNPRINTF(buffer, size, format, precision, value);
539 	}
540 	return precision < 0 ?
541 		FMT_SNPRINTF(buffer, size, format, width, value) :
542 		FMT_SNPRINTF(buffer, size, format, width, precision, value);
543 }
544 
545 template <typename T>
format_float(wchar_t * buffer,std::size_t size,const wchar_t * format,unsigned width,int precision,T value)546 int fmt::internal::CharTraits<wchar_t>::format_float(
547 	wchar_t *buffer, std::size_t size, const wchar_t *format,
548 	unsigned width, int precision, T value)
549 {
550 	if (width == 0) {
551 		return precision < 0 ?
552 			FMT_SWPRINTF(buffer, size, format, value) :
553 			FMT_SWPRINTF(buffer, size, format, precision, value);
554 	}
555 	return precision < 0 ?
556 		FMT_SWPRINTF(buffer, size, format, width, value) :
557 		FMT_SWPRINTF(buffer, size, format, width, precision, value);
558 }
559 
560 template <typename T>
561 const char fmt::internal::BasicData<T>::DIGITS[] =
562 "0001020304050607080910111213141516171819"
563 "2021222324252627282930313233343536373839"
564 "4041424344454647484950515253545556575859"
565 "6061626364656667686970717273747576777879"
566 "8081828384858687888990919293949596979899";
567 
568 #define FMT_POWERS_OF_10(factor) \
569   factor * 10, \
570   factor * 100, \
571   factor * 1000, \
572   factor * 10000, \
573   factor * 100000, \
574   factor * 1000000, \
575   factor * 10000000, \
576   factor * 100000000, \
577   factor * 1000000000
578 
579 template <typename T>
580 const uint32_t fmt::internal::BasicData<T>::POWERS_OF_10_32[] = {
581 	0, FMT_POWERS_OF_10(1)
582 };
583 
584 template <typename T>
585 const uint64_t fmt::internal::BasicData<T>::POWERS_OF_10_64[] = {
586 	0,
587 	FMT_POWERS_OF_10(1),
588 	FMT_POWERS_OF_10(fmt::ULongLong(1000000000)),
589 	// Multiply several constants instead of using a single long long constant
590 	// to avoid warnings about C++98 not supporting long long.
591 	fmt::ULongLong(1000000000) * fmt::ULongLong(1000000000) * 10
592 };
593 
report_unknown_type(char code,const char * type)594 FMT_FUNC void fmt::internal::report_unknown_type(char code, const char *type)
595 {
596 	(void)type;
597 	if (std::isprint(static_cast<unsigned char>(code))) {
598 		FMT_THROW(fmt::FormatError(
599 			fmt::format("unknown format code '{}' for {}", code, type)));
600 	}
601 	FMT_THROW(fmt::FormatError(
602 		fmt::format("unknown format code '\\x{:02x}' for {}",
603 			static_cast<unsigned>(code), type)));
604 }
605 
606 #if FMT_USE_WINDOWS_H
607 
UTF8ToUTF16(fmt::StringRef s)608 FMT_FUNC fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s)
609 {
610 	static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
611 	if (s.size() > INT_MAX)
612 		FMT_THROW(WindowsError(ERROR_INVALID_PARAMETER, ERROR_MSG));
613 	int s_size = static_cast<int>(s.size());
614 	int length = MultiByteToWideChar(
615 		CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, 0, 0);
616 	if (length == 0)
617 		FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
618 	buffer_.resize(length + 1);
619 	length = MultiByteToWideChar(
620 		CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length);
621 	if (length == 0)
622 		FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
623 	buffer_[length] = 0;
624 }
625 
UTF16ToUTF8(fmt::WStringRef s)626 FMT_FUNC fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s)
627 {
628 	if (int error_code = convert(s)) {
629 		FMT_THROW(WindowsError(error_code,
630 			"cannot convert string from UTF-16 to UTF-8"));
631 	}
632 }
633 
convert(fmt::WStringRef s)634 FMT_FUNC int fmt::internal::UTF16ToUTF8::convert(fmt::WStringRef s)
635 {
636 	if (s.size() > INT_MAX)
637 		return ERROR_INVALID_PARAMETER;
638 	int s_size = static_cast<int>(s.size());
639 	int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, 0, 0, 0, 0);
640 	if (length == 0)
641 		return GetLastError();
642 	buffer_.resize(length + 1);
643 	length = WideCharToMultiByte(
644 		CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, 0, 0);
645 	if (length == 0)
646 		return GetLastError();
647 	buffer_[length] = 0;
648 	return 0;
649 }
650 
init(int err_code,CStringRef format_str,ArgList args)651 FMT_FUNC void fmt::WindowsError::init(
652 	int err_code, CStringRef format_str, ArgList args)
653 {
654 	error_code_ = err_code;
655 	MemoryWriter w;
656 	internal::format_windows_error(w, err_code, format(format_str, args));
657 	std::runtime_error &base = *this;
658 	base = std::runtime_error(w.str());
659 }
660 
format_windows_error(fmt::Writer & out,int error_code,fmt::StringRef message)661 FMT_FUNC void fmt::internal::format_windows_error(
662 	fmt::Writer &out, int error_code,
663 	fmt::StringRef message) FMT_NOEXCEPT
664 {
665 	FMT_TRY{
666 		MemoryBuffer<wchar_t, INLINE_BUFFER_SIZE> buffer;
667 	buffer.resize(INLINE_BUFFER_SIZE);
668 	for (;;) {
669 		wchar_t *system_message = &buffer[0];
670 		int result = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
671 			0, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
672 			system_message, static_cast<uint32_t>(buffer.size()), 0);
673 		if (result != 0) {
674 			UTF16ToUTF8 utf8_message;
675 			if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
676 				out << message << ": " << utf8_message;
677 				return;
678 			}
679 			break;
680 		}
681 		if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
682 			break;  // Can't get error message, report error code instead.
683 		buffer.resize(buffer.size() * 2);
684 	}
685 	} FMT_CATCH(...)
686 	{}
687 	fmt::format_error_code(out, error_code, message);  // 'fmt::' is for bcc32.
688 }
689 
690 #endif  // FMT_USE_WINDOWS_H
691 
format_system_error(fmt::Writer & out,int error_code,fmt::StringRef message)692 FMT_FUNC void fmt::internal::format_system_error(
693 	fmt::Writer &out, int error_code,
694 	fmt::StringRef message) FMT_NOEXCEPT
695 {
696 	FMT_TRY{
697 		MemoryBuffer<char, INLINE_BUFFER_SIZE> buffer;
698 	buffer.resize(INLINE_BUFFER_SIZE);
699 	for (;;) {
700 		char *system_message = &buffer[0];
701 		int result = safe_strerror(error_code, system_message, buffer.size());
702 		if (result == 0) {
703 			out << message << ": " << system_message;
704 			return;
705 		}
706 		if (result != ERANGE)
707 			break;  // Can't get error message, report error code instead.
708 		buffer.resize(buffer.size() * 2);
709 	}
710 	} FMT_CATCH(...)
711 	{}
712 	fmt::format_error_code(out, error_code, message);  // 'fmt::' is for bcc32.
713 }
714 
715 template <typename Char>
init(const ArgList & args)716 void fmt::internal::ArgMap<Char>::init(const ArgList &args)
717 {
718 	if (!map_.empty())
719 		return;
720 	typedef internal::NamedArg<Char> NamedArg;
721 	const NamedArg *named_arg = 0;
722 	bool use_values =
723 		args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE;
724 	if (use_values) {
725 		for (unsigned i = 0;/*nothing*/; ++i) {
726 			internal::Arg::Type arg_type = args.type(i);
727 			switch (arg_type) {
728 			case internal::Arg::NONE:
729 				return;
730 			case internal::Arg::NAMED_ARG:
731 				named_arg = static_cast<const NamedArg*>(args.values_[i].pointer);
732 				map_.push_back(Pair(named_arg->name, *named_arg));
733 				break;
734 			default:
735 				/*nothing*/;
736 			}
737 		}
738 		return;
739 	}
740 	for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) {
741 		internal::Arg::Type arg_type = args.type(i);
742 		if (arg_type == internal::Arg::NAMED_ARG) {
743 			named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
744 			map_.push_back(Pair(named_arg->name, *named_arg));
745 		}
746 	}
747 	for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) {
748 		switch (args.args_[i].type) {
749 		case internal::Arg::NONE:
750 			return;
751 		case internal::Arg::NAMED_ARG:
752 			named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
753 			map_.push_back(Pair(named_arg->name, *named_arg));
754 			break;
755 		default:
756 			/*nothing*/;
757 		}
758 	}
759 }
760 
761 template <typename Char>
grow(std::size_t)762 void fmt::internal::FixedBuffer<Char>::grow(std::size_t)
763 {
764 	FMT_THROW(std::runtime_error("buffer overflow"));
765 }
766 
do_get_arg(unsigned arg_index,const char * & error)767 FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg(
768 	unsigned arg_index, const char *&error)
769 {
770 	Arg arg = args_[arg_index];
771 	switch (arg.type) {
772 	case Arg::NONE:
773 		error = "argument index out of range";
774 		break;
775 	case Arg::NAMED_ARG:
776 		arg = *static_cast<const internal::Arg*>(arg.pointer);
777 		break;
778 	default:
779 		/*nothing*/;
780 	}
781 	return arg;
782 }
783 
784 template <typename Char>
parse_flags(FormatSpec & spec,const Char * & s)785 void fmt::internal::PrintfFormatter<Char>::parse_flags(
786 	FormatSpec &spec, const Char *&s)
787 {
788 	for (;;) {
789 		switch (*s++) {
790 		case '-':
791 			spec.align_ = ALIGN_LEFT;
792 			break;
793 		case '+':
794 			spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
795 			break;
796 		case '0':
797 			spec.fill_ = '0';
798 			break;
799 		case ' ':
800 			spec.flags_ |= SIGN_FLAG;
801 			break;
802 		case '#':
803 			spec.flags_ |= HASH_FLAG;
804 			break;
805 		default:
806 			--s;
807 			return;
808 		}
809 	}
810 }
811 
812 template <typename Char>
get_arg(const Char * s,unsigned arg_index)813 Arg fmt::internal::PrintfFormatter<Char>::get_arg(
814 	const Char *s, unsigned arg_index)
815 {
816 	(void)s;
817 	const char *error = 0;
818 	Arg arg = arg_index == UINT_MAX ?
819 		next_arg(error) : FormatterBase::get_arg(arg_index - 1, error);
820 	if (error)
821 		FMT_THROW(FormatError(!*s ? "invalid format string" : error));
822 	return arg;
823 }
824 
825 template <typename Char>
parse_header(const Char * & s,FormatSpec & spec)826 unsigned fmt::internal::PrintfFormatter<Char>::parse_header(
827 	const Char *&s, FormatSpec &spec)
828 {
829 	unsigned arg_index = UINT_MAX;
830 	Char c = *s;
831 	if (c >= '0' && c <= '9') {
832 		// Parse an argument index (if followed by '$') or a width possibly
833 		// preceded with '0' flag(s).
834 		unsigned value = parse_nonnegative_int(s);
835 		if (*s == '$') {  // value is an argument index
836 			++s;
837 			arg_index = value;
838 		}
839 		else {
840 			if (c == '0')
841 				spec.fill_ = '0';
842 			if (value != 0) {
843 				// Nonzero value means that we parsed width and don't need to
844 				// parse it or flags again, so return now.
845 				spec.width_ = value;
846 				return arg_index;
847 			}
848 		}
849 	}
850 	parse_flags(spec, s);
851 	// Parse width.
852 	if (*s >= '0' && *s <= '9') {
853 		spec.width_ = parse_nonnegative_int(s);
854 	}
855 	else if (*s == '*') {
856 		++s;
857 		spec.width_ = WidthHandler(spec).visit(get_arg(s));
858 	}
859 	return arg_index;
860 }
861 
862 template <typename Char>
format(BasicWriter<Char> & writer,BasicCStringRef<Char> format_str)863 void fmt::internal::PrintfFormatter<Char>::format(
864 	BasicWriter<Char> &writer, BasicCStringRef<Char> format_str)
865 {
866 	const Char *start = format_str.c_str();
867 	const Char *s = start;
868 	while (*s) {
869 		Char c = *s++;
870 		if (c != '%') continue;
871 		if (*s == c) {
872 			write(writer, start, s);
873 			start = ++s;
874 			continue;
875 		}
876 		write(writer, start, s - 1);
877 
878 		FormatSpec spec;
879 		spec.align_ = ALIGN_RIGHT;
880 
881 		// Parse argument index, flags and width.
882 		unsigned arg_index = parse_header(s, spec);
883 
884 		// Parse precision.
885 		if (*s == '.') {
886 			++s;
887 			if ('0' <= *s && *s <= '9') {
888 				spec.precision_ = static_cast<int>(parse_nonnegative_int(s));
889 			}
890 			else if (*s == '*') {
891 				++s;
892 				spec.precision_ = PrecisionHandler().visit(get_arg(s));
893 			}
894 		}
895 
896 		Arg arg = get_arg(s, arg_index);
897 		if (spec.flag(HASH_FLAG) && IsZeroInt().visit(arg))
898 			spec.flags_ &= ~to_unsigned<int>(HASH_FLAG);
899 		if (spec.fill_ == '0') {
900 			if (arg.type <= Arg::LAST_NUMERIC_TYPE)
901 				spec.align_ = ALIGN_NUMERIC;
902 			else
903 				spec.fill_ = ' ';  // Ignore '0' flag for non-numeric types.
904 		}
905 
906 		// Parse length and convert the argument to the required type.
907 		switch (*s++) {
908 		case 'h':
909 			if (*s == 'h')
910 				ArgConverter<signed char>(arg, *++s).visit(arg);
911 			else
912 				ArgConverter<short>(arg, *s).visit(arg);
913 			break;
914 		case 'l':
915 			if (*s == 'l')
916 				ArgConverter<fmt::LongLong>(arg, *++s).visit(arg);
917 			else
918 				ArgConverter<long>(arg, *s).visit(arg);
919 			break;
920 		case 'j':
921 			ArgConverter<intmax_t>(arg, *s).visit(arg);
922 			break;
923 		case 'z':
924 			ArgConverter<std::size_t>(arg, *s).visit(arg);
925 			break;
926 		case 't':
927 			ArgConverter<std::ptrdiff_t>(arg, *s).visit(arg);
928 			break;
929 		case 'L':
930 			// printf produces garbage when 'L' is omitted for long double, no
931 			// need to do the same.
932 			break;
933 		default:
934 			--s;
935 			ArgConverter<void>(arg, *s).visit(arg);
936 		}
937 
938 		// Parse type.
939 		if (!*s)
940 			FMT_THROW(FormatError("invalid format string"));
941 		spec.type_ = static_cast<char>(*s++);
942 		if (arg.type <= Arg::LAST_INTEGER_TYPE) {
943 			// Normalize type.
944 			switch (spec.type_) {
945 			case 'i': case 'u':
946 				spec.type_ = 'd';
947 				break;
948 			case 'c':
949 				// TODO: handle wchar_t
950 				CharConverter(arg).visit(arg);
951 				break;
952 			}
953 		}
954 
955 		start = s;
956 
957 		// Format argument.
958 		internal::PrintfArgFormatter<Char>(writer, spec).visit(arg);
959 	}
960 	write(writer, start, s);
961 }
962 
report_system_error(int error_code,fmt::StringRef message)963 FMT_FUNC void fmt::report_system_error(
964 	int error_code, fmt::StringRef message) FMT_NOEXCEPT
965 {
966 	// 'fmt::' is for bcc32.
967 	fmt::report_error(internal::format_system_error, error_code, message);
968 }
969 
970 #if FMT_USE_WINDOWS_H
report_windows_error(int error_code,fmt::StringRef message)971 FMT_FUNC void fmt::report_windows_error(
972 	int error_code, fmt::StringRef message) FMT_NOEXCEPT
973 {
974 	// 'fmt::' is for bcc32.
975 	fmt::report_error(internal::format_windows_error, error_code, message);
976 }
977 #endif
978 
print(std::FILE * f,CStringRef format_str,ArgList args)979 FMT_FUNC void fmt::print(std::FILE *f, CStringRef format_str, ArgList args)
980 {
981 	MemoryWriter w;
982 	w.write(format_str, args);
983 	std::fwrite(w.data(), 1, w.size(), f);
984 }
985 
print(CStringRef format_str,ArgList args)986 FMT_FUNC void fmt::print(CStringRef format_str, ArgList args)
987 {
988 	print(stdout, format_str, args);
989 }
990 
print(std::ostream & os,CStringRef format_str,ArgList args)991 FMT_FUNC void fmt::print(std::ostream &os, CStringRef format_str,
992 	ArgList args)
993 {
994 	MemoryWriter w;
995 	w.write(format_str, args);
996 	write(os, w);
997 }
998 
print_colored(Color c,CStringRef format,ArgList args)999 FMT_FUNC void fmt::print_colored(Color c, CStringRef format, ArgList args)
1000 {
1001 	char escape[] = "\x1b[30m";
1002 	escape[3] = static_cast<char>('0' + c);
1003 	std::fputs(escape, stdout);
1004 	print(format, args);
1005 	std::fputs(RESET_COLOR, stdout);
1006 }
1007 
fprintf(std::FILE * f,CStringRef format,ArgList args)1008 FMT_FUNC int fmt::fprintf(std::FILE *f, CStringRef format, ArgList args)
1009 {
1010 	MemoryWriter w;
1011 	printf(w, format, args);
1012 	std::size_t size = w.size();
1013 	return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size);
1014 }
1015 
fprintf(std::ostream & os,CStringRef format,ArgList args)1016 FMT_FUNC int fmt::fprintf(std::ostream &os, CStringRef format, ArgList args)
1017 {
1018 	MemoryWriter w;
1019 	printf(w, format, args);
1020 	write(os, w);
1021 	return static_cast<int>(w.size());
1022 }
1023 
1024 #ifndef FMT_HEADER_ONLY
1025 
1026 template struct fmt::internal::BasicData<void>;
1027 
1028 // Explicit instantiations for char.
1029 
1030 template void fmt::internal::FixedBuffer<char>::grow(std::size_t);
1031 
1032 template void fmt::internal::ArgMap<char>::init(const fmt::ArgList &args);
1033 
1034 template void fmt::internal::PrintfFormatter<char>::format(
1035 	BasicWriter<char> &writer, CStringRef format);
1036 
1037 template int fmt::internal::CharTraits<char>::format_float(
1038 	char *buffer, std::size_t size, const char *format,
1039 	unsigned width, int precision, double value);
1040 
1041 template int fmt::internal::CharTraits<char>::format_float(
1042 	char *buffer, std::size_t size, const char *format,
1043 	unsigned width, int precision, long double value);
1044 
1045 // Explicit instantiations for wchar_t.
1046 
1047 template void fmt::internal::FixedBuffer<wchar_t>::grow(std::size_t);
1048 
1049 template void fmt::internal::ArgMap<wchar_t>::init(const fmt::ArgList &args);
1050 
1051 template void fmt::internal::PrintfFormatter<wchar_t>::format(
1052 	BasicWriter<wchar_t> &writer, WCStringRef format);
1053 
1054 template int fmt::internal::CharTraits<wchar_t>::format_float(
1055 	wchar_t *buffer, std::size_t size, const wchar_t *format,
1056 	unsigned width, int precision, double value);
1057 
1058 template int fmt::internal::CharTraits<wchar_t>::format_float(
1059 	wchar_t *buffer, std::size_t size, const wchar_t *format,
1060 	unsigned width, int precision, long double value);
1061 
1062 #endif  // FMT_HEADER_ONLY
1063 
1064 #ifdef _MSC_VER
1065 # pragma warning(pop)
1066 #endif