ReactOS 0.4.16-dev-905-gc1b8c4f
corecrt_internal_stdio_output.h
Go to the documentation of this file.
1//
2// corecrt_internal_stdio_output.h
3//
4// Copyright (c) Microsoft Corporation. All rights reserved.
5//
6// This file defines the core implementation of the formatted output functions,
7// including printf and its many variants (sprintf, fprintf, etc.).
8//
9#include <conio.h>
14#include <ctype.h>
15#include <locale.h>
16#include <stdarg.h>
17
19
21
22
23
24//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
25//
26// Argument Handling
27//
28//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
29// These provide a very basic encapsulation over a va_list. The 'read' function
30// reads the next argument of type T from the varargs list and updates the
31// va_list, just like va_arg does. The 'peek' function returns the next argument
32// of type T, but does not modify the va_list.
33#if defined(__GNUC__) || defined(__clang__)
34template<typename T> struct _va_arg_promoted_tye { using type = T; };
35template<> struct _va_arg_promoted_tye<signed char> { using type = int; };
36template<> struct _va_arg_promoted_tye<unsigned char> { using type = int; };
37template<> struct _va_arg_promoted_tye<wchar_t> { using type = int; };
38template<> struct _va_arg_promoted_tye<short int> { using type = int; };
39template<> struct _va_arg_promoted_tye<short unsigned int> { using type = int; };
40#endif
41
42template <typename T>
44{
45#if defined(__GNUC__) || defined(__clang__)
46 return (T)(va_arg(arglist, typename _va_arg_promoted_tye<T>::type));
47#else
48 return va_arg(arglist, T);
49#endif
50}
51
52template <typename T>
54{
55#if defined(__GNUC__) || defined(__clang__)
56 return (T)(va_arg(arglist, typename _va_arg_promoted_tye<T>::type));
57#else
58 return va_arg(arglist, T);
59#endif
60}
61
62
63
64//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
65//
66// Output Adapters
67//
68//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
69// The actual write operations are different depending on whether the target is
70// a stream or the console. We handle these differences via output adapters.
71// The stream and console I/O functions pass an adapter to the core output
72// function, and that function calls the various write members of the adapter to
73// perform the write operations.
74template <typename Character, typename Derived>
76{
77public:
78 void write_character(Character const c, int* const count_written, __crt_cached_ptd_host& ptd) const throw()
79 {
80 if (static_cast<Derived const*>(this)->write_character_without_count_update(c, ptd))
81 {
82 ++*count_written;
83 }
84 else
85 {
86 *count_written = -1;
87 }
88 }
89
90protected:
92 Character const* const string,
93 int const length,
94 int* const count_written,
95 __crt_cached_ptd_host& ptd
96 ) const throw()
97 {
98 auto const reset_errno = ptd.get_errno().create_guard();
99
100 Character const* const string_last{string + length};
101 for (Character const* it{string}; it != string_last; ++it)
102 {
103 if (static_cast<Derived const*>(this)->write_character_without_count_update(*it, ptd))
104 {
105 ++*count_written;
106 }
107 else
108 {
109 // Non-standard extension: EILSEQ errors are recoverable.
110 // Standard behavior when we've encountered an 'illegal sequence' error
111 // (i.e. EILSEQ) is to set 'errno' to EILSEQ and return -1.
112 // Instead, we write '?' and continue writing the string.
113 if (!ptd.get_errno().check(EILSEQ))
114 {
115 // *printf returns the number of characters written
116 // set count written to -1 to indicate an error occurred
117 *count_written = -1;
118 break;
119 }
120
121 write_character('?', count_written, ptd);
122 }
123 }
124 }
125};
126
127template <typename Character>
129 : public output_adapter_common<Character, console_output_adapter<Character>>
130{
131#ifndef _MSC_VER // For retarded compilers!
134#endif
135public:
137
138 bool validate(__crt_cached_ptd_host&) const throw()
139 {
140 return true;
141 }
142
143 bool write_character_without_count_update(Character const c, __crt_cached_ptd_host& ptd) const throw()
144 {
145 return char_traits::puttch_nolock_internal(c, ptd) != char_traits::eof;
146 }
147
149 Character const* const string,
150 int const length,
151 int* const count_written,
152 __crt_cached_ptd_host& ptd
153 ) const throw()
154 {
155 write_string_impl(string, length, count_written, ptd);
156 }
157};
158
159
160
161template <typename Character>
163 : public output_adapter_common<Character, stream_output_adapter<Character>>
164{
165#ifndef _MSC_VER // For retarded compilers!
168#endif
169public:
171
172 stream_output_adapter(FILE* const public_stream) throw()
173 : _stream{public_stream}
174 {
175 }
176
177 bool validate(__crt_cached_ptd_host& ptd) const throw()
178 {
180
181 return char_traits::validate_stream_is_ansi_if_required(_stream.public_stream());
182 }
183
184 bool write_character_without_count_update(Character const c, __crt_cached_ptd_host& ptd) const throw()
185 {
186 if (_stream.is_string_backed() && _stream->_base == nullptr)
187 {
188 return true;
189 }
190
191 return char_traits::puttc_nolock_internal(c, _stream.public_stream(), ptd) != char_traits::eof;
192 }
193
195 Character const* const string,
196 int const length,
197 int* const count_written,
198 __crt_cached_ptd_host& ptd
199 ) const throw()
200 {
201 if (_stream.is_string_backed() && _stream->_base == nullptr)
202 {
203 *count_written += length;
204 return;
205 }
206
207 write_string_impl(string, length, count_written, ptd);
208 }
209
210private:
211
213};
214
215
216
217template <typename Character>
219{
220 Character* _buffer;
224};
225
226template <typename Character>
228{
229public:
230
233
236 {
237 }
238
239 bool validate(__crt_cached_ptd_host& ptd) const throw()
240 {
241 _UCRT_VALIDATE_RETURN(ptd, _context != nullptr, EINVAL, false);
242 return true;
243 }
244
245 __forceinline bool write_character(Character const c, int* const count_written, __crt_cached_ptd_host&) const throw()
246 {
248 {
250 {
251 ++*count_written;
252 }
253 else
254 {
255 *count_written = -1;
256 }
257
259 }
260
261 ++*count_written;
263 *_context->_buffer++ = c;
264 return true;
265 }
266
268 Character const* const string,
269 int const length,
270 int* const count_written,
271 __crt_cached_ptd_host& ptd
272 ) const throw()
273 {
274 // This function does not perform any operations that might reset errno,
275 // so we don't need to use __crt_errno_guard as we do in other output
276 // adapters.
278
279 if (length == 0)
280 {
281 return;
282 }
283
285 {
287 {
288 *count_written += length;
289 }
290 else
291 {
292 *count_written = -1;
293 }
294
295 return;
296 }
297
298 size_t const space_available = _context->_buffer_count - _context->_buffer_used;
299 size_t const elements_to_copy = __min(space_available, static_cast<size_t>(length));
300
301 // Performance note: This is hot code. Profiling has shown the extra
302 // validation done by memcpy_s to be quite expensive. The validation is
303 // unnecessary, so we call memcpy directly here:
304 memcpy(
306 string,
307 elements_to_copy * sizeof(Character));
308
309 _context->_buffer += elements_to_copy;
310 _context->_buffer_used += elements_to_copy;
311
313 {
314 *count_written += length;
315 }
316 else if (elements_to_copy != static_cast<size_t>(length))
317 {
318 *count_written = -1;
319 }
320 else
321 {
322 *count_written += static_cast<int>(elements_to_copy);
323 }
324 }
325
326private:
327
329};
330
331
332
333template <typename OutputAdapter, typename Character>
334__forceinline void write_multiple_characters(
335 OutputAdapter const& adapter,
336 Character const c,
337 int const count,
338 int* const count_written,
339 __crt_cached_ptd_host& ptd
340 ) throw()
341{
342 for (int i{0}; i < count; ++i)
343 {
344 adapter.write_character(c, count_written, ptd);
345 if (*count_written == -1)
346 break;
347 }
348}
349
350
351
352//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
353//
354// Formatting Buffer
355//
356//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
357// This type encapsulates the buffer to be used when formatting numbers. It
358// contains as a data member a large, statically-sized buffer, which is used
359// at first. If a larger buffer is required a new, larger buffer is dynamically
360// allocated.
362{
363public:
364
365 enum
366 {
368 };
369
370 static_assert(member_buffer_size >= (_CVTBUFSIZE + 6) * 2, "Buffer is too small");
371
374 {
375 }
376
377 template <typename T>
378 bool ensure_buffer_is_big_enough(size_t const count, __crt_cached_ptd_host& ptd) throw()
379 {
380 constexpr size_t max_count = SIZE_MAX / sizeof(T) / 2; // avoid runtime division
382
383 size_t const required_size{count * sizeof(T) * 2};
384
385 // Once we allocate a dynamic buffer, we no longer use the member buffer
386 if (!_dynamic_buffer && required_size <= member_buffer_size) {
387 return true;
388 }
389
390 if (required_size <= _dynamic_buffer_size) {
391 return true;
392 }
393
394 __crt_unique_heap_ptr<char> new_buffer{_malloc_crt_t(char, required_size)};
395 if (!new_buffer) {
396 return false;
397 }
398
399 _dynamic_buffer = static_cast<__crt_unique_heap_ptr<char>&&>(new_buffer);
400 _dynamic_buffer_size = required_size;
401 return true;
402 }
403
404 template <typename T>
406 {
407 if (!_dynamic_buffer)
408 return reinterpret_cast<T*>(_member_buffer);
409
410 return reinterpret_cast<T*>(_dynamic_buffer.get());
411 }
412
413 template <typename T>
415 {
416 if (!_dynamic_buffer)
417 return reinterpret_cast<T*>(_member_buffer) + count<T>();
418
419 return reinterpret_cast<T*>(_dynamic_buffer.get()) + count<T>();
420 }
421
422 template <typename T>
423 size_t count() const throw()
424 {
425 if (!_dynamic_buffer)
426 return member_buffer_size / sizeof(T) / 2;
427
428 return _dynamic_buffer_size / sizeof(T) / 2;
429 }
430
431 template <typename T>
432 size_t scratch_count() const throw()
433 {
434 return count<T>();
435 }
436
437private:
438
440
442 __crt_unique_heap_ptr<char> _dynamic_buffer;
443};
444
445
446
447// This function forces a decimal point in floating point output. It is called
448// if '#' flag is given and precision is 0, so we know the number has no '.' in
449// its current representation. We insert the '.' and move everything back one
450// position until '\0' is seen. This function updates the buffer in place.
452{
453 if (_tolower_fast_internal(static_cast<unsigned char>(*buffer), locale) != 'e')
454 {
455 do
456 {
457 ++buffer;
458 }
459 while (_isdigit_fast_internal(static_cast<unsigned char>(*buffer), locale));
460 }
461
462 // Check if the buffer is in hexadecimal format (cfr %a or %A and fp_format_a):
464 {
465 // The buffer is in the form: [-]0xhP+d, and buffer points to the 'x':
466 // we want to put the decimal point after the h digit: [-]0xh.P+d
467 buffer += 2; // REVIEW This can skip terminal nul?
468 }
469
470 char holdchar = *buffer;
471
472 *buffer++ = *locale->locinfo->lconv->decimal_point;
473
474 do
475 {
476 char const nextchar = *buffer;
477 *buffer = holdchar;
478 holdchar = nextchar;
479 }
480 while (*buffer++);
481}
482
483
484
485// This function removes trailing zeroes (after the '.') from a floating point
486// number. This function is called only when formatting in the %g mode when
487// there is no '#' flag and precision is nonzero. This function updates the
488// buffer in-place.
489//
490// This function changes the contents of the buffer from:
491// [-] digit [digit...] [ . [digits...] [0...] ] [(exponent part)]
492// to:
493// [-] digit [digit...] [ . digit [digits...] ] [(exponent part)]
494// or:
495// [-] digit [digit...] [(exponent part)]
496inline void __cdecl crop_zeroes(_Inout_z_ char* buffer, _locale_t const locale) throw()
497{
498 char const decimal_point = *locale->locinfo->lconv->decimal_point;
499
500 while (*buffer && *buffer != decimal_point)
501 ++buffer;
502
503 if (*buffer++)
504 {
505 while (*buffer && *buffer != 'e' && *buffer != 'E')
506 ++buffer;
507
508 char* stop = buffer--;
509
510 while (*buffer == '0')
511 --buffer;
512
513 if (*buffer == decimal_point)
514 --buffer;
515
516 while((*++buffer = *stop++) != '\0') { }
517 }
518}
519
520
521
522//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
523//
524// States and the State Transition Tables
525//
526//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
527// These tables hold the state transition data for the format processor. The
528// lower nibble of each byte is the character class of the character. The upper
529// nibble of each byte gives the next state to enter.
530
531// The states of the format parsing state machine. These are encoded into the
532// transition tables and are referenced throughout the format processor.
533enum class state : unsigned char
534{
535 normal, // Normal state; outputting literal chars
536 percent, // Just read '%'
537 flag, // Just read flag character
538 width, // Just read width specifier
539 dot, // Just read '.'
540 precision, // Just read precision specifier
541 size, // Just read size specifier
542 type, // Just read type specifier
543 invalid // Invalid format
544};
545
546// Manifest constants to represent the different types of characters that may
547// be encountered in the format string. These are not referenced anywhere in
548// the source anymore, but their values are encoded into the state table, so
549// we have retained the definition for reference.
550enum class character_type : unsigned char
551{
552 other, // character with no special meaning
553 percent, // '%'
554 dot, // '.'
555 star, // '*'
556 zero, // '0'
557 digit, // '1'..'9'
558 flag, // ' ', '+', '-', '#'
559 size, // 'h', 'l', 'L', 'N', 'F', 'w'
560 type // type specifying character
561};
562
564{
567};
568
569template <typename T, size_t Size>
571{
572public:
573
574 static size_t const mask = Size - 1;
575 static_assert((Size & mask) == 0, "Size must be a power of two.");
576
577 // Instead of using an lfence mitigation, we can fill the table to a power of two,
578 // then bitwise-and all values used to index into the array.
579 #if defined(_MSC_VER) && !defined(__clang__)
580 __declspec(spectre(nomitigation))
581 #endif
582 T const& operator[](size_t const index) const
583 {
584 return m_array[index & mask];
585 }
586
588};
589
591
592// Note, the state transition and character type are unrelated data - they just occupy the same table.
593// This table skips the 'invalid' state.
594extern __declspec(selectany) printf_state_transition_table const standard_lookup_table_spectre
595{
596 /* prev state -> cur char -> new state character type */
597 /* normal -> other -> */ state::normal, /* ' ' */ character_type::flag,
598 /* percent -> other -> */ state::normal, /* '!' */ character_type::other,
599 /* flag -> other -> */ state::normal, /* '"' */ character_type::other,
600 /* width -> other -> */ state::normal, /* '#' */ character_type::flag,
601 /* dot -> other -> */ state::normal, /* '$' */ character_type::other,
602 /* precision -> other -> */ state::normal, /* '%' */ character_type::percent,
603 /* size -> other -> */ state::normal, /* '&' */ character_type::other,
604 /* type -> other -> */ state::normal, /* ''' */ character_type::other,
605 /* normal -> percent -> */ state::percent, /* '(' */ character_type::other,
606 /* percent -> percent -> */ state::normal, /* ')' */ character_type::other,
607 /* flag -> percent -> */ state::normal, /* '*' */ character_type::star,
608 /* width -> percent -> */ state::normal, /* '+' */ character_type::flag,
609 /* dot -> percent -> */ state::normal, /* ',' */ character_type::other,
610 /* precision -> percent -> */ state::normal, /* '-' */ character_type::flag,
611 /* size -> percent -> */ state::normal, /* '.' */ character_type::dot,
612 /* type -> percent -> */ state::percent, /* '/' */ character_type::other,
613 /* normal -> dot -> */ state::normal, /* '0' */ character_type::zero,
614 /* percent -> dot -> */ state::dot, /* '1' */ character_type::digit,
615 /* flag -> dot -> */ state::dot, /* '2' */ character_type::digit,
616 /* width -> dot -> */ state::dot, /* '3' */ character_type::digit,
617 /* dot -> dot -> */ state::normal, /* '4' */ character_type::digit,
618 /* precision -> dot -> */ state::normal, /* '5' */ character_type::digit,
619 /* size -> dot -> */ state::normal, /* '6' */ character_type::digit,
620 /* type -> dot -> */ state::normal, /* '7' */ character_type::digit,
621 /* normal -> star -> */ state::normal, /* '8' */ character_type::digit,
622 /* percent -> star -> */ state::width, /* '9' */ character_type::digit,
623 /* flag -> star -> */ state::width, /* ':' */ character_type::other,
624 /* width -> star -> */ state::normal, /* ';' */ character_type::other,
625 /* dot -> star -> */ state::precision, /* '<' */ character_type::other,
626 /* precision -> star -> */ state::normal, /* '=' */ character_type::other,
627 /* size -> star -> */ state::normal, /* '>' */ character_type::other,
628 /* type -> star -> */ state::normal, /* '?' */ character_type::other,
629 /* normal -> zero -> */ state::normal, /* '@' */ character_type::other,
630 /* percent -> zero -> */ state::flag, /* 'A' */ character_type::type,
631 /* flag -> zero -> */ state::flag, /* 'B' */ character_type::other,
632 /* width -> zero -> */ state::width, /* 'C' */ character_type::type,
633 /* dot -> zero -> */ state::precision, /* 'D' */ character_type::other,
634 /* precision -> zero -> */ state::precision, /* 'E' */ character_type::type,
635 /* size -> zero -> */ state::normal, /* 'F' */ character_type::size,
636 /* type -> zero -> */ state::normal, /* 'G' */ character_type::type,
637 /* normal -> digit -> */ state::normal, /* 'H' */ character_type::other,
638 /* percent -> digit -> */ state::width, /* 'I' */ character_type::size,
639 /* flag -> digit -> */ state::width, /* 'J' */ character_type::other,
640 /* width -> digit -> */ state::width, /* 'K' */ character_type::other,
641 /* dot -> digit -> */ state::precision, /* 'L' */ character_type::size,
642 /* precision -> digit -> */ state::precision, /* 'M' */ character_type::other,
643 /* size -> digit -> */ state::normal, /* 'N' */ character_type::size,
644 /* type -> digit -> */ state::normal, /* 'O' */ character_type::other,
645 /* normal -> flag -> */ state::normal, /* 'P' */ character_type::other,
646 /* percent -> flag -> */ state::flag, /* 'Q' */ character_type::other,
647 /* flag -> flag -> */ state::flag, /* 'R' */ character_type::other,
648 /* width -> flag -> */ state::normal, /* 'S' */ character_type::type,
649 /* dot -> flag -> */ state::normal, /* 'T' */ character_type::size,
650 /* precision -> flag -> */ state::normal, /* 'U' */ character_type::other,
651 /* size -> flag -> */ state::normal, /* 'V' */ character_type::other,
652 /* type -> flag -> */ state::normal, /* 'W' */ character_type::other,
653 /* normal -> size -> */ state::normal, /* 'X' */ character_type::type,
654 /* percent -> size -> */ state::size, /* 'Y' */ character_type::other,
655 /* flag -> size -> */ state::size, /* 'Z' */ character_type::type,
656 /* width -> size -> */ state::size, /* '[' */ character_type::other,
657 /* dot -> size -> */ state::size, /* '\' */ character_type::other,
658 /* precision -> size -> */ state::size, /* ']' */ character_type::other,
659 /* size -> size -> */ state::size, /* '^' */ character_type::other,
660 /* type -> size -> */ state::normal, /* '_' */ character_type::other,
661 /* normal -> type -> */ state::normal, /* '`' */ character_type::other,
662 /* percent -> type -> */ state::type, /* 'a' */ character_type::type,
663 /* flag -> type -> */ state::type, /* 'b' */ character_type::other,
664 /* width -> type -> */ state::type, /* 'c' */ character_type::type,
665 /* dot -> type -> */ state::type, /* 'd' */ character_type::type,
666 /* precision -> type -> */ state::type, /* 'e' */ character_type::type,
667 /* size -> type -> */ state::type, /* 'f' */ character_type::type,
668 /* type -> type -> */ state::normal, /* 'g' */ character_type::type,
669 /* unused */ state::normal, /* 'h' */ character_type::size,
670 /* unused */ state::normal, /* 'i' */ character_type::type,
671 /* unused */ state::normal, /* 'j' */ character_type::size,
672 /* unused */ state::normal, /* 'k' */ character_type::other,
673 /* unused */ state::normal, /* 'l' */ character_type::size,
674 /* unused */ state::normal, /* 'm' */ character_type::other,
675 /* unused */ state::normal, /* 'n' */ character_type::type,
676 /* unused */ state::normal, /* 'o' */ character_type::type,
677 /* unused */ state::normal, /* 'p' */ character_type::type,
678 /* unused */ state::normal, /* 'q' */ character_type::other,
679 /* unused */ state::normal, /* 'r' */ character_type::other,
680 /* unused */ state::normal, /* 's' */ character_type::type,
681 /* unused */ state::normal, /* 't' */ character_type::size,
682 /* unused */ state::normal, /* 'u' */ character_type::type,
683 /* unused */ state::normal, /* 'v' */ character_type::other,
684 /* unused */ state::normal, /* 'w' */ character_type::size,
685 /* unused */ state::normal, /* 'x' */ character_type::type,
686 /* unused */ state::normal, /* 'y' */ character_type::other,
687 /* unused */ state::normal, /* 'z' */ character_type::size
688};
689
690// Note, the state transition and character type are unrelated data - they just occupy the same table.
691extern __declspec(selectany) printf_state_transition_table const format_validation_lookup_table_spectre
692{
693 /* prev state -> cur char -> new state character type */
694 /* normal -> other -> */ state::normal, /* ' ' */ character_type::flag,
695 /* percent -> other -> */ state::invalid, /* '!' */ character_type::other,
696 /* flag -> other -> */ state::invalid, /* '"' */ character_type::other,
697 /* width -> other -> */ state::invalid, /* '#' */ character_type::flag,
698 /* dot -> other -> */ state::invalid, /* '$' */ character_type::other,
699 /* precision -> other -> */ state::invalid, /* '%' */ character_type::percent,
700 /* size -> other -> */ state::invalid, /* '&' */ character_type::other,
701 /* type -> other -> */ state::normal, /* ''' */ character_type::other,
702 /* invalid -> other -> */ state::normal, /* '(' */ character_type::other,
703 /* normal -> percent -> */ state::percent, /* ')' */ character_type::other,
704 /* percent -> percent -> */ state::normal, /* '*' */ character_type::star,
705 /* flag -> percent -> */ state::invalid, /* '+' */ character_type::flag,
706 /* width -> percent -> */ state::invalid, /* ',' */ character_type::other,
707 /* dot -> percent -> */ state::invalid, /* '-' */ character_type::flag,
708 /* precision -> percent -> */ state::invalid, /* '.' */ character_type::dot,
709 /* size -> percent -> */ state::invalid, /* '/' */ character_type::other,
710 /* type -> percent -> */ state::percent, /* '0' */ character_type::zero,
711 /* invalid -> percent -> */ state::normal, /* '1' */ character_type::digit,
712 /* normal -> dot -> */ state::normal, /* '2' */ character_type::digit,
713 /* percent -> dot -> */ state::dot, /* '3' */ character_type::digit,
714 /* flag -> dot -> */ state::dot, /* '4' */ character_type::digit,
715 /* width -> dot -> */ state::dot, /* '5' */ character_type::digit,
716 /* dot -> dot -> */ state::invalid, /* '6' */ character_type::digit,
717 /* precision -> dot -> */ state::invalid, /* '7' */ character_type::digit,
718 /* size -> dot -> */ state::invalid, /* '8' */ character_type::digit,
719 /* type -> dot -> */ state::normal, /* '9' */ character_type::digit,
720 /* invalid -> dot -> */ state::normal, /* ':' */ character_type::other,
721 /* normal -> star -> */ state::normal, /* ';' */ character_type::other,
722 /* percent -> star -> */ state::width, /* '<' */ character_type::other,
723 /* flag -> star -> */ state::width, /* '=' */ character_type::other,
724 /* width -> star -> */ state::invalid, /* '>' */ character_type::other,
725 /* dot -> star -> */ state::precision, /* '?' */ character_type::other,
726 /* precision -> star -> */ state::invalid, /* '@' */ character_type::other,
727 /* size -> star -> */ state::invalid, /* 'A' */ character_type::type,
728 /* type -> star -> */ state::normal, /* 'B' */ character_type::other,
729 /* invalid -> star -> */ state::normal, /* 'C' */ character_type::type,
730 /* normal -> zero -> */ state::normal, /* 'D' */ character_type::other,
731 /* percent -> zero -> */ state::flag, /* 'E' */ character_type::type,
732 /* flag -> zero -> */ state::flag, /* 'F' */ character_type::size,
733 /* width -> zero -> */ state::width, /* 'G' */ character_type::type,
734 /* dot -> zero -> */ state::precision, /* 'H' */ character_type::other,
735 /* precision -> zero -> */ state::precision, /* 'I' */ character_type::size,
736 /* size -> zero -> */ state::invalid, /* 'J' */ character_type::other,
737 /* type -> zero -> */ state::normal, /* 'K' */ character_type::other,
738 /* invalid -> zero -> */ state::normal, /* 'L' */ character_type::size,
739 /* normal -> digit -> */ state::normal, /* 'M' */ character_type::other,
740 /* percent -> digit -> */ state::width, /* 'N' */ character_type::size,
741 /* flag -> digit -> */ state::width, /* 'O' */ character_type::other,
742 /* width -> digit -> */ state::width, /* 'P' */ character_type::other,
743 /* dot -> digit -> */ state::precision, /* 'Q' */ character_type::other,
744 /* precision -> digit -> */ state::precision, /* 'R' */ character_type::other,
745 /* size -> digit -> */ state::invalid, /* 'S' */ character_type::type,
746 /* type -> digit -> */ state::normal, /* 'T' */ character_type::size,
747 /* invalid -> digit -> */ state::normal, /* 'U' */ character_type::other,
748 /* normal -> flag -> */ state::normal, /* 'V' */ character_type::other,
749 /* percent -> flag -> */ state::flag, /* 'W' */ character_type::other,
750 /* flag -> flag -> */ state::flag, /* 'X' */ character_type::type,
751 /* width -> flag -> */ state::invalid, /* 'Y' */ character_type::other,
752 /* dot -> flag -> */ state::invalid, /* 'Z' */ character_type::type,
753 /* precision -> flag -> */ state::invalid, /* '[' */ character_type::other,
754 /* size -> flag -> */ state::invalid, /* '\' */ character_type::other,
755 /* type -> flag -> */ state::normal, /* ']' */ character_type::other,
756 /* invalid -> flag -> */ state::normal, /* '^' */ character_type::other,
757 /* normal -> size -> */ state::normal, /* '_' */ character_type::other,
758 /* percent -> size -> */ state::size, /* '`' */ character_type::other,
759 /* flag -> size -> */ state::size, /* 'a' */ character_type::type,
760 /* width -> size -> */ state::size, /* 'b' */ character_type::other,
761 /* dot -> size -> */ state::size, /* 'c' */ character_type::type,
762 /* precision -> size -> */ state::size, /* 'd' */ character_type::type,
763 /* size -> size -> */ state::size, /* 'e' */ character_type::type,
764 /* type -> size -> */ state::normal, /* 'f' */ character_type::type,
765 /* invalid -> size -> */ state::normal, /* 'g' */ character_type::type,
766 /* normal -> type -> */ state::normal, /* 'h' */ character_type::size,
767 /* percent -> type -> */ state::type, /* 'i' */ character_type::type,
768 /* flag -> type -> */ state::type, /* 'j' */ character_type::size,
769 /* width -> type -> */ state::type, /* 'k' */ character_type::other,
770 /* dot -> type -> */ state::type, /* 'l' */ character_type::size,
771 /* precision -> type -> */ state::type, /* 'm' */ character_type::other,
772 /* size -> type -> */ state::type, /* 'n' */ character_type::other,
773 /* type -> type -> */ state::normal, /* 'o' */ character_type::type,
774 /* invalid -> type -> */ state::normal, /* 'p' */ character_type::type,
775 /* unused */ state::normal, /* 'q' */ character_type::other,
776 /* unused */ state::normal, /* 'r' */ character_type::other,
777 /* unused */ state::normal, /* 's' */ character_type::type,
778 /* unused */ state::normal, /* 't' */ character_type::size,
779 /* unused */ state::normal, /* 'u' */ character_type::type,
780 /* unused */ state::normal, /* 'v' */ character_type::other,
781 /* unused */ state::normal, /* 'w' */ character_type::size,
782 /* unused */ state::normal, /* 'x' */ character_type::type,
783 /* unused */ state::normal, /* 'y' */ character_type::other,
784 /* unused */ state::normal, /* 'z' */ character_type::size
785};
786
787//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
788//
789// Flags
790//
791//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
792enum FLAG : unsigned
793{
794 FL_SIGN = 0x01, // Put plus or minus in front
795 FL_SIGNSP = 0x02, // Put space or minus in front
796 FL_LEFT = 0x04, // Left justify
797 FL_LEADZERO = 0x08, // Pad with leading zeros
798 FL_SIGNED = 0x10, // Signed data given
799 FL_ALTERNATE = 0x20, // Alternate form requested
800 FL_NEGATIVE = 0x40, // Value is negative
801 FL_FORCEOCTAL = 0x80, // Force leading '0' for octals
802};
803
805{
806 none,
807 hh,
808 h,
809 l,
810 ll,
811 j,
812 z,
813 t,
814 L,
815 I,
816 I32,
817 I64,
818 w,
819 T,
821};
822
823inline size_t __cdecl to_integer_size(length_modifier const length) throw()
824{
825 switch (length)
826 {
827 case length_modifier::none: return sizeof(int );
828 case length_modifier::hh: return sizeof(char );
829 case length_modifier::h: return sizeof(short );
830 case length_modifier::l: return sizeof(long );
831 case length_modifier::ll: return sizeof(long long);
832 case length_modifier::j: return sizeof(intmax_t );
833 case length_modifier::z: return sizeof(size_t );
834 case length_modifier::t: return sizeof(ptrdiff_t);
835 case length_modifier::I: return sizeof(void* );
836 case length_modifier::I32: return sizeof(int32_t );
837 case length_modifier::I64: return sizeof(int64_t );
838 default: return 0;
839 }
840}
841
842template <typename Character>
844 uint64_t const options,
845 Character const format_type,
847 ) throw()
848{
850
851 // If a length specifier was used, use that width:
852 switch (length)
853 {
854 case length_modifier::l: return true;
855 case length_modifier::w: return true;
856 case length_modifier::h: return false;
857 }
858
860 {
861 return sizeof(Character) == sizeof(wchar_t);
862 }
863
864 bool const is_naturally_wide{
865 sizeof(Character) == sizeof(wchar_t) &&
867 };
868
869 bool const is_natural_width{
870 format_type == 'c' ||
871 format_type == 's'
872 };
873
874 return is_naturally_wide == is_natural_width;
875}
876
877
878
879//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
880//
881// Core Base Classes
882//
883//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
884// The format processor consists of a set of base classes that form a single
885// inheritance hierarchy that looks like so:
886//
887// * common_data
888// * output_adapter_data
889// * standard_base [1]
890// * format_validation_base [2]
891// * positional_parameter_base [3]
892//
893// There is a single class template, output_processor, which may be instantiated
894// to derive from any of the three bottom-most classes in the aforementioned
895// base class hierarchy (these are marked with the numbers 1-3). When it derives
896// from standard_base, it provides the standard formatted output functionality
897// as defined in the C Standard Library specification. When it derives from the
898// format_validation_base, it provides that same functionality, but also checks
899// the format string for validity, and invokes the invalid parameter handler if
900// the format string is determined to be invalid. Finally, if it derives from
901// the positional_parameter_base, it supports positional parameters.
902//
903// These three derivable bases allow us to implement the three forms of public
904// functions using a common implementation: the standard, unsuffixed functions,
905// the format validating _s-suffixed functions, and the _p-suffixed functions
906// that permit positional parameter usage.
907//
908// There are no virtual functions used here: each of the three functionality
909// bases "overrides" base class functionality by hiding it. We must therefore
910// be cautious to ensure that functions are called in such a way that the right
911// implementation is called.
912template <typename Character>
914{
915protected:
916 common_data(__crt_cached_ptd_host& ptd)
917 : _options {0 },
918 _ptd {ptd },
923 _flags {0 },
924 _field_width {0 },
925 _precision {0 },
927 _format_char {'\0' },
928 _string_length {0 },
930 {
931 }
932
934
935 // We cache a reference to the PTD and updated locale information
936 // to avoid having to query thread-local storage for every character
937 // write that we perform.
938 __crt_cached_ptd_host& _ptd;
939
940 // These two iterators control the formatting operation. The format iterator
941 // iterates over the format string, and the va_list argument pointer iterates
942 // over the varargs arguments.
943 Character const* _format_it;
945
946 // This stores the number of characters that have been written so far. It is
947 // initialized to zero and is incremented as characters are written. If an
948 // I/O error occurs, it is set to -1 to indicate the I/O failure.
950
951 // These represent the state for the current format specifier. The suppress
952 // output flag is set when output should be suppressed for the current format
953 // specifier (note that this is distinct from the global suppression that we
954 // use during the first pass of positional parameter handling).
956 unsigned _flags;
961
962 // This is the character from the format string that was used to compute the
963 // current state. We need to store this separately because we advance the
964 // format string iterator at various points during processing.
965 Character _format_char;
966
967 // These pointers are used in various places to point to strings that either
968 // [1] are being formatted into, or [2] contain formatted data that is ready
969 // to be printed. At any given time, we may have either a narrow string or
970 // a wide string, but never both. The string length is the length of which-
971 // -ever string is currently present. The wide flag is set if the wide string
972 // is currently in use.
973 union
974 {
976 wchar_t* _wide_string;
977 };
978
979 char*& tchar_string(char ) throw() { return _narrow_string; }
980 wchar_t*& tchar_string(wchar_t) throw() { return _wide_string; }
981
982 Character*& tchar_string() throw() { return tchar_string(Character()); }
983
986
987 // The formatting buffer. This buffer is used to store the result of various
988 // formatting operations--notably, numbers get formatted into strings in this
989 // buffer.
991};
992
993// This data base is split out from the common data base only so that we can
994// more easily value-initialize all of the members of the common data base.
995template <typename Character, typename OutputAdapter>
997 : protected common_data<Character>
998{
999protected:
1000#ifndef _MSC_VER // For retarded compilers!
1001 using common_data<Character>::_options;
1002 using common_data<Character>::_format_it;
1003 using common_data<Character>::_valist_it;
1004#endif
1006 OutputAdapter const& output_adapter,
1007 uint64_t const options,
1008 Character const* const format,
1009 __crt_cached_ptd_host& ptd,
1010 va_list const arglist
1011 ) throw()
1013 _output_adapter(output_adapter)
1014 {
1015 // We initialize several base class data members here, so that we can
1016 // value initialize the entire base class before we get to this point.
1017 _options = options;
1020 }
1021
1022 OutputAdapter _output_adapter;
1023};
1024
1025
1026
1027//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1028//
1029// standard_base
1030//
1031//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1032// This is the base class with which the format processor is instantiated to
1033// provide "standard" printf formatting.
1034template <typename Character, typename OutputAdapter>
1036 : protected output_adapter_data<Character, OutputAdapter>
1037{
1038protected:
1039#ifndef _MSC_VER // For retarded compilers!
1041 using common_data_base::_valist_it;
1042 using common_data_base::_field_width;
1043 using common_data_base::_precision;
1044#endif
1045 template <typename... Ts>
1046 standard_base(Ts&&... arguments) throw()
1049 {
1050 }
1051
1053 {
1054 _current_pass = static_cast<pass>(static_cast<unsigned>(_current_pass) + 1);
1055 return _current_pass != pass::finished;
1056 }
1057
1059 {
1060 // No validation is performed in the standard output implementation:
1061 return true;
1062 }
1063
1065 {
1066 return true;
1067 }
1068
1069 template <typename RequestedParameterType, typename ActualParameterType>
1070 bool extract_argument_from_va_list(ActualParameterType& result) throw()
1071 {
1072 result = static_cast<ActualParameterType>(read_va_arg<RequestedParameterType>(_valist_it));
1073
1074 return true;
1075 }
1076
1078 {
1079 _field_width = read_va_arg<int>(_valist_it);
1080 return true;
1081 }
1082
1084 {
1085 _precision = read_va_arg<int>(_valist_it);
1086 return true;
1087 }
1088
1090 {
1091 return true;
1092 }
1093
1095 {
1096 return false;
1097 }
1098
1100 {
1101 return true;
1102 }
1103
1105 {
1106 return false;
1107 }
1108
1109 static unsigned state_count() throw()
1110 {
1111 return static_cast<unsigned>(state::type) + 1;
1112 }
1113
1115 {
1116 return standard_lookup_table_spectre;
1117 }
1118
1119private:
1120
1121 // In the standard format string processing, there is only one state, in
1122 // which we both evaluate the format specifiers and format the parameters.
1123 enum class pass : unsigned
1124 {
1126 output,
1127 finished
1128 };
1129
1131};
1132
1133
1134
1135//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1136//
1137// format_validation_base
1138//
1139//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1140// This is the base class with which the format processor is instantiated to
1141// provide "standard" printf formatting with additional validation of the format
1142// string.
1143template <typename Character, typename OutputAdapter>
1145 : protected standard_base<Character, OutputAdapter>
1146{
1147protected:
1148#ifndef _MSC_VER // For retarded compilers!
1150 using common_data_base::_ptd;
1151 using common_data_base::_state;
1152#endif
1153 template <typename... Ts>
1154 format_validation_base(Ts&&... arguments) throw()
1156 {
1157 }
1158
1160 {
1161 // When we reach the end of the format string, we ensure that the format
1162 // string is not incomplete. I.e., when we are finished, the lsat thing
1163 // that we should have encountered is a regular character to be written
1164 // or a type specifier. Otherwise, the format string was incomplete.
1166
1167 return true;
1168 }
1169
1170 static unsigned state_count() throw()
1171 {
1172 return static_cast<unsigned>(state::invalid) + 1;
1173 }
1174
1176 {
1177 return format_validation_lookup_table_spectre;
1178 }
1179};
1180
1181
1182
1183//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1184//
1185// positional_parameter_base
1186//
1187//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1188// This is the base class with which the format processor is instantiated to
1189// provide support for the formatted output functions that permit positional
1190// parameter references in the format string. Note that when this base is used,
1191// it also pulls in the format validation functionality.
1192template <typename Character, typename OutputAdapter>
1194 : protected format_validation_base<Character, OutputAdapter>
1195{
1196protected:
1197#if defined(__GNUC__) || defined(__clang__) // For retarded compilers!
1200 using common_data_base::_format_it;
1201 using common_data_base::_ptd;
1202 using common_data_base::_field_width;
1203 using common_data_base::_precision;
1204 using common_data_base::_format_char;
1205 using common_data_base::_valist_it;
1206 using common_data_base::_length;
1207 using common_data_base::_state;
1208 using common_data_base::_options;
1209#endif
1210
1214
1215 template <typename... Ts>
1216 positional_parameter_base(Ts&&... arguments) throw()
1219 _format_mode {mode::unknown },
1221 _type_index {-1 },
1222 _maximum_index {-1 }
1223 {
1224 // Note that we do not zero-initialize the parameter data table until
1225 // the first positional parameter is encountered in the format string.
1226 }
1227
1229 {
1230 _current_pass = static_cast<pass>(static_cast<unsigned>(_current_pass) + 1);
1232 return false;
1233
1234 // If we are in the output pass but the format string is a non-positional,
1235 // ordinary format string, then we do not need a second pass:
1236 if (_current_pass == pass::output && _format_mode == mode::nonpositional)
1237 return false;
1238
1239 // All characters before the first format specifier are output in the
1240 // first pass. We reset the format mode to 'unknown' to ensure that
1241 // they are not output again during the second pass.
1242 _format_mode = mode::unknown;
1243
1244 _maximum_index = -1;
1245 _type_index = -1;
1246
1247 _field_width = 0;
1248 _precision = 0;
1250
1251 return true;
1252 }
1253
1255 {
1257 return false;
1258
1259 if (_format_mode != mode::positional || _current_pass != pass::position_scan)
1260 return true;
1261
1262 // At the end of the first pass, we have the types filled into the
1263 // arg_type member for each positional parameter. We now need to get
1264 // the argument pointer for each positional parameter and store it
1265 // into the arg_ptr member.
1268 for (parameter_data* it{first}; it != last; ++it)
1269 {
1270 it->_valist_it = _valist_it;
1271
1272 switch (it->_actual_type)
1273 {
1274 case parameter_type::int32: read_va_arg<int >(_valist_it); break;
1275 case parameter_type::int64: read_va_arg<__int64 >(_valist_it); break;
1276 case parameter_type::pointer: read_va_arg<void* >(_valist_it); break;
1277 case parameter_type::real64: read_va_arg<_CRT_DOUBLE>(_valist_it); break;
1278
1279 default:
1280 // We should never reach this point:
1281 _UCRT_VALIDATE_RETURN(_ptd, ("Missing position in the format string", 0), EINVAL, false);
1282 break;
1283 }
1284 }
1285
1286 return true;
1287 }
1288
1290 {
1291 return _current_pass != pass::position_scan || _format_mode == mode::nonpositional;
1292 }
1293
1294 template <typename RequestedParameterType, typename ActualParameterType>
1295 bool extract_argument_from_va_list(ActualParameterType& result) throw()
1296 {
1297 if (_format_mode == mode::nonpositional)
1298 {
1299 return base_type::template extract_argument_from_va_list<RequestedParameterType>(result);
1300 }
1301
1303
1305 {
1308 get_parameter_type(RequestedParameterType()),
1310 _length
1311 );
1312 }
1313 else
1314 {
1315 result = static_cast<ActualParameterType>(peek_va_arg<RequestedParameterType>(_parameters[_type_index]._valist_it));
1316 return true;
1317 }
1318 }
1319
1321 {
1322 if (_format_mode == mode::nonpositional)
1323 {
1325 }
1326
1327 Character* end_pointer{nullptr};
1328 int const width_index{_tcstol_internal(_ptd, _format_it, &end_pointer, 10) - 1};
1329 _format_it = end_pointer + 1;
1330
1332 {
1333 _UCRT_VALIDATE_RETURN(_ptd, width_index >= 0 && *end_pointer == '$' && width_index < _ARGMAX, EINVAL, false);
1334
1335 _maximum_index = width_index > _maximum_index
1336 ? width_index
1338
1340 _parameters[width_index],
1343 _length
1344 );
1345 }
1346 else
1347 {
1348 _field_width = peek_va_arg<int>(_parameters[width_index]._valist_it);
1349 }
1350
1351 return true;
1352 }
1353
1355 {
1356 if (_format_mode == mode::nonpositional)
1357 {
1359 }
1360
1361 Character* end_pointer{nullptr};
1362 int const precision_index{_tcstol_internal(_ptd, _format_it, &end_pointer, 10) - 1};
1363 _format_it = end_pointer + 1;
1364
1366 {
1367 _UCRT_VALIDATE_RETURN(_ptd, precision_index >= 0 && *end_pointer == '$' && precision_index < _ARGMAX, EINVAL, false);
1368
1369 _maximum_index = precision_index > _maximum_index
1370 ? precision_index
1372
1374 _parameters[precision_index],
1377 _length
1378 );
1379 }
1380 else
1381 {
1382 _precision = peek_va_arg<int>(_parameters[precision_index]._valist_it);
1383 }
1384
1385 return true;
1386 }
1387
1389 {
1390 if (_format_mode == mode::positional && _current_pass == pass::position_scan)
1391 {
1397 _length
1398 );
1399 }
1400
1401 return true;
1402 }
1403
1405 {
1406 if (_current_pass == pass::position_scan && _format_mode == mode::positional)
1407 return true;
1408
1409 if (_current_pass == pass::output && _format_mode == mode::unknown)
1410 return true;
1411
1412 // We do not output during the first pass if we have already come across
1413 // a positional format specifier. All characters before the first format
1414 // specifier are output in the first pass. We need to check the format
1415 // type during the second pass to ensure that they are not output a second
1416 // time.
1417 return false;
1418 }
1419
1421 {
1422 // We're looking for a format specifier, so we'll have just seen a '%'
1423 // and the next character is not a '%':
1424 if (_state != state::percent || *_format_it == '%')
1425 return true;
1426
1427 // When we encounter the first format specifier, we determine whether
1428 // the format string is a positional format string or a standard format
1429 // string.
1430 if (_format_mode == mode::unknown)
1431 {
1432 Character* end_pointer{nullptr};
1433
1434 // Only digits are permitted between the % and the $ in the positional format specifier.
1435 if (*_format_it < '0' || *_format_it > '9')
1436 {
1437 _format_mode = mode::nonpositional;
1438 }
1439 else if (_tcstol_internal(_ptd, _format_it, &end_pointer, 10) > 0 && *end_pointer == '$')
1440 {
1442 {
1443 memset(_parameters, 0, sizeof(_parameters));
1444 }
1445
1446 _format_mode = mode::positional;
1447 }
1448 else
1449 {
1450 _format_mode = mode::nonpositional;
1451 }
1452 }
1453
1454 if (_format_mode != mode::positional)
1455 {
1456 return true;
1457 }
1458
1459 Character* end_pointer{nullptr};
1460 _type_index = _tcstol_internal(_ptd, _format_it, &end_pointer, 10) - 1;
1461 _format_it = end_pointer + 1;
1462
1464 return true;
1465
1466 // We do not re-perform the type validations during the second pass...
1467 _UCRT_VALIDATE_RETURN(_ptd, _type_index >= 0 && *end_pointer == '$' && _type_index < _ARGMAX, EINVAL, false);
1468
1470 ? _type_index
1472
1473 return true;
1474 }
1475
1477 {
1478 return _format_mode == mode::positional && _current_pass == pass::position_scan;
1479 }
1480
1481private:
1482
1483 // Positional parameter processing occurs in two passes. In the first pass,
1484 // we scan the format string to accumulate type information for the
1485 // positional parameters. If the format string is a standard format string
1486 // (that does not use positional parameters), then this pass also does the
1487 // output. Otherwise, if the format string uses positional parameters,
1488 // the actual output operation takes place in the second pass, after we've
1489 // aggregated all of the information about the positional parameters.
1490 enum class pass : unsigned
1491 {
1494 output,
1495 finished
1496 };
1497
1498 // These represent the two modes of formatting. The processor starts off in
1499 // the unknown mode and can transition to either nonpositional (indicating
1500 // standard format string processing) or positional mode.
1501 enum class mode : unsigned
1502 {
1503 unknown,
1506 };
1507
1508 // These represent the different types of parameters that may be present in
1509 // the argument list (remember that integral types narrower than int and
1510 // real types narrower than double are promoted for the varargs call).
1511 enum class parameter_type : unsigned
1512 {
1513 unused,
1514 int32,
1515 int64,
1516 pointer,
1517 real64
1518 };
1519
1520 // This represents a parameter in the varargs list, along with information
1521 // we have about the parameter from the format string. We store an array
1522 // of these structures internally, and the structures are updated in several
1523 // steps. They start off uninitialized, with the "unused" actual type. If
1524 // the format string uses positional parameters, then the actual type, format
1525 // type, and flags are updated during the positional scan of the format
1526 // string. At the end of that scan, we iterate over the parameters and the
1527 // varargs array to fill in the argptr for each of the positional parameters.
1529 {
1531 Character _format_type;
1532
1535 };
1536
1537 // These provide transformations from the source parameter types to their
1538 // underlying representation enumerators (from the parameter_type enum).
1539 template <typename T>
1542 static parameter_type __cdecl get_parameter_type(unsigned short ) throw() { return parameter_type::int32; }
1545 static parameter_type __cdecl get_parameter_type(unsigned int ) throw() { return parameter_type::int32; }
1549
1550 // With positional parameters, a given parameter may be used multiple times
1551 // in a format string. All appearances of a given parameter must be
1552 // consistent (they must match in type and width). The first time a given
1553 // parameter appears, it is accepted as-is. Each subsequent time that it
1554 // reappears, this function is called to ensure that the reappearance is
1555 // consistent with the previously processed appearance.
1556 //
1557 // Returns true if the reappearance is consistent (and valid). Returns false
1558 // otherwise. This function does not invoke invalid parameter handling.
1560 parameter_data const& parameter,
1561 parameter_type const actual_type,
1562 Character const format_type,
1564 ) throw()
1565 {
1566 // Pointer format specifiers are exclusive; a parameter that previously
1567 // appeared as a pointer may not reappear as a non-pointer, and vice-
1568 // versa.
1569 bool const old_is_pointer{is_pointer_specifier(parameter._format_type)};
1570 bool const new_is_pointer{is_pointer_specifier(format_type)};
1571 if (old_is_pointer || new_is_pointer)
1572 {
1573 return old_is_pointer == new_is_pointer;
1574 }
1575
1576 // String format specifiers are exclusive, just like pointer specifiers.
1577 // We must also ensure that the two appearances match in string type:
1578 // either both must be wide or both must be narrow.
1579 bool const old_is_string{is_string_specifier(parameter._format_type)};
1580 bool const new_is_string{is_string_specifier(format_type)};
1581
1582 bool const old_is_character{is_character_specifier(parameter._format_type)};
1583 bool const new_is_character{is_character_specifier(format_type)};
1584 if (old_is_string || new_is_string || old_is_character || new_is_character)
1585 {
1586 if (old_is_string != new_is_string || old_is_character != new_is_character)
1587 return false;
1588
1589 bool const old_is_wide{is_wide_character_specifier(_options, parameter._format_type, parameter._length)};
1590 bool const new_is_wide{is_wide_character_specifier(_options, format_type, length)};
1591 if (old_is_wide != new_is_wide)
1592 return false;
1593
1594 return true;
1595 }
1596
1597 // Numeric specifiers are exclusive: either both appearances must be
1598 // numeric specifiers or neither appearance may be a numeric specifier.
1599 // Additionally, if both appearances are numeric specifiers, they must
1600 // both have the same width.
1601 bool const old_is_integral{is_integral_specifier(parameter._format_type)};
1602 bool const new_is_integral{is_integral_specifier(format_type)};
1603 if (old_is_integral || new_is_integral)
1604 {
1605 if (old_is_integral != new_is_integral)
1606 return false;
1607
1608 if ((parameter._length == length_modifier::I) != (length == length_modifier::I))
1609 return false;
1610
1611 return to_integer_size(parameter._length) == to_integer_size(length);
1612 }
1613
1614 return parameter._actual_type == actual_type;
1615 }
1616
1618 parameter_data & parameter,
1619 parameter_type const actual_type,
1620 Character const format_type,
1622 ) throw()
1623 {
1624 if (parameter._actual_type == parameter_type::unused)
1625 {
1626 parameter._actual_type = actual_type;
1627 parameter._format_type = format_type;
1628 parameter._length = length;
1629 }
1630 else
1631 {
1633 parameter, actual_type, format_type, length
1634 ), EINVAL, false);
1635 }
1636
1637 return true;
1638 }
1639
1640 template <typename Character2>
1641 static bool __cdecl is_pointer_specifier(Character2 const specifier) throw()
1642 {
1643 return specifier == 'p';
1644 }
1645
1646 template <typename Character2>
1647 static bool __cdecl is_string_specifier(Character2 const specifier) throw()
1648 {
1649 return specifier == 's' || specifier == 'S';
1650 }
1651
1652 template <typename Character2>
1653 static bool __cdecl is_character_specifier(Character2 const specifier) throw()
1654 {
1655 return specifier == 'c' || specifier == 'C';
1656 }
1657
1658 template <typename Character2>
1659 static bool __cdecl is_integral_specifier(Character2 const specifier) throw()
1660 {
1661 return specifier == 'd' || specifier == 'i' || specifier == 'o'
1662 || specifier == 'u' || specifier == 'x' || specifier == 'X'
1663 || specifier == '*';
1664 }
1665
1668
1669 // The original format pointer, which allows us to reset the format iterator
1670 // between the two passes used in positional parameter processing.
1671 Character const* _format;
1672
1673 // The array of positional parameters used in the format string.
1675
1676 // These are indices into the _parameters array. They hold the maximum
1677 // positional parameter index that has been seen so far and the index of the
1678 // current format specifier. Until a positional parameter is encountered in
1679 // the format string, these have the value -1.
1682};
1683
1684
1685
1686//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1687//
1688// output_processor
1689//
1690//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1691// This is the main output processor class, which performs the format string
1692// processing and formats the varargs arguments appropriately. It delegates to
1693// the provided ProcessorBase for certain parts of the functionality. It is
1694// expected that the ProcessorBase argument is one of the base class types
1695// defined above.
1696template <typename Character, typename OutputAdapter, typename ProcessorBase>
1698 : private ProcessorBase
1699{
1700public:
1701#ifndef _MSC_VER // For retarded compilers!
1702 using ProcessorBase::advance_to_next_pass;
1703 using ProcessorBase::validate_and_update_state_at_beginning_of_format_character;
1704 using ProcessorBase::validate_and_update_state_at_end_of_format_string;
1705 using ProcessorBase::should_skip_normal_state_processing;
1706 using ProcessorBase::update_field_width;
1707 using ProcessorBase::should_format;
1708 using ProcessorBase::update_precision;
1709 using ProcessorBase::should_skip_type_state_output;
1710 using ProcessorBase::validate_state_for_type_case_a;
1711 using ProcessorBase::tchar_string;
1712 using ProcessorBase::state_transition_table;
1713 using ProcessorBase::state_count;
1714 using oad_base = typename ProcessorBase::output_adapter_data;
1715 using oad_base::_output_adapter;
1716 using common_data_base = typename ProcessorBase::common_data_base;
1717 using common_data_base::_string_length;
1718 using common_data_base::_ptd;
1719 using common_data_base::_format_it;
1720 using common_data_base::_state;
1721 using common_data_base::_format_char;
1722 using common_data_base::_characters_written;
1723 using common_data_base::_string_is_wide;
1724 using common_data_base::_field_width;
1725 using common_data_base::_suppress_output;
1726 using common_data_base::_flags;
1727 using common_data_base::_precision;
1728 using common_data_base::_length;
1729 using common_data_base::_options;
1730 using common_data_base::_buffer;
1731 using common_data_base::_narrow_string;
1732 using common_data_base::_wide_string;
1733#endif
1734
1736
1738 OutputAdapter const& output_adapter,
1739 uint64_t const options,
1740 Character const* const format,
1741 __crt_cached_ptd_host& ptd,
1742 va_list const arglist
1743 ) throw()
1744 : ProcessorBase{output_adapter, options, format, ptd, arglist}
1745 {
1746 }
1747
1748 // After construction, this function is called to evaluate the formatted
1749 // output operation. This function must be called exactly once, immediately
1750 // after constructing the object.
1752 {
1753 if (!_output_adapter.validate(_ptd))
1754 {
1755 return -1;
1756 }
1757
1758 _UCRT_VALIDATE_RETURN(_ptd, _format_it != nullptr, EINVAL, -1);
1759
1760 while (advance_to_next_pass())
1761 {
1762 // At the start of each pass, we have no buffered string and we are
1763 // in the normal state:
1764 _string_length = 0;
1765 _state = state::normal;
1766
1767 // Iterate over the format string until we reach the end, encounter
1768 // an I/O error, or fail due to some other error:
1769 while ((_format_char = *_format_it++) != '\0' && _characters_written >= 0)
1770 {
1771 _state = find_next_state(_format_char, _state);
1772
1773 if (!validate_and_update_state_at_beginning_of_format_character())
1774 {
1775 return -1;
1776 }
1777
1778 if (_state >= state::invalid)
1779 {
1780 _UCRT_VALIDATE_RETURN(_ptd, ("Incorrect format specifier", 0), EINVAL, -1);
1781 }
1782
1783 bool result = false;
1784
1785 switch (_state)
1786 {
1787 case state::normal: result = state_case_normal (); break;
1788 case state::percent: result = state_case_percent (); break;
1789 case state::flag: result = state_case_flag (); break;
1790 case state::width: result = state_case_width (); break;
1791 case state::dot: result = state_case_dot (); break;
1793 case state::size: result = state_case_size (); break;
1794 case state::type: result = state_case_type (); break;
1795 }
1796
1797 // If the state-specific operation failed, return immediately.
1798 // The individual state cases are responsible for invoking the
1799 // invalid parameter handler if the failure is due to an invalid
1800 // parameter.
1801 if (!result)
1802 return -1;
1803 }
1804
1805 if (!validate_and_update_state_at_end_of_format_string())
1806 return -1;
1807 }
1808
1809 return _characters_written;
1810 }
1811
1812private:
1813
1814 // The normal state is entered when a character that is not part of a format
1815 // specifier is encountered in the format string. We simply write the
1816 // character. There are four parts to the normal state: the state_case_normal
1817 // function is called when the state is entered. It tests whether the actual
1818 // output operation should take place. The state_case_normal_common function
1819 // performs the actual output operation and is called from elsewhere in this
1820 // class.
1821 __forceinline bool state_case_normal() throw()
1822 {
1823 if (should_skip_normal_state_processing())
1824 return true;
1825
1827
1828 return true;
1829 }
1830
1831 __forceinline bool state_case_normal_common() throw()
1832 {
1833 if (!state_case_normal_tchar(Character()))
1834 return false;
1835
1836 _output_adapter.write_character(_format_char, &_characters_written, _ptd);
1837 return true;
1838 }
1839
1840 __forceinline bool state_case_normal_tchar(char) throw()
1841 {
1842 _string_is_wide = false;
1843
1844 if (__acrt_isleadbyte_l_noupdate(_format_char, _ptd.get_locale()))
1845 {
1846 _output_adapter.write_character(_format_char, &_characters_written, _ptd);
1847 _format_char = *_format_it++;
1848
1849 // Ensure that we do not fall off the end of the format string:
1850 _UCRT_VALIDATE_RETURN(_ptd, _format_char != '\0', EINVAL, false);
1851 }
1852
1853 return true;
1854 }
1855
1856 __forceinline bool state_case_normal_tchar(wchar_t) throw()
1857 {
1858 _string_is_wide = true;
1859 return true;
1860 }
1861
1862 // We enter the percent state when we read a '%' from the format string. The
1863 // percent sign begins a format specifier, so we reset our internal state for
1864 // the new format specifier.
1865 __forceinline bool state_case_percent() throw()
1866 {
1867 _field_width = 0;
1868 _suppress_output = false;
1869 _flags = 0;
1870 _precision = -1;
1871 _length = length_modifier::none;
1872 _string_is_wide = false;
1873
1874 return true;
1875 }
1876
1877 // We enter the flag state when we are reading a format specifier and we
1878 // encounter one of the optional flags. We update our state to account for
1879 // the flag.
1880 __forceinline bool state_case_flag() throw()
1881 {
1882 // Set the flag based on which flag character:
1883 switch (_format_char)
1884 {
1885 case '-': set_flag(FL_LEFT ); break; // '-' => left justify
1886 case '+': set_flag(FL_SIGN ); break; // '+' => force sign indicator
1887 case ' ': set_flag(FL_SIGNSP ); break; // ' ' => force sign or space
1888 case '#': set_flag(FL_ALTERNATE); break; // '#' => alternate form
1889 case '0': set_flag(FL_LEADZERO ); break; // '0' => pad with leading zeros
1890 }
1891
1892 return true;
1893 }
1894
1895 // Parses an integer from the format string. It is expected in this function
1896 // that it is called _after_ the format string iterator has been advanced to
1897 // the next character, so it starts parsing from _format_it - 1 (i.e., from
1898 // the character currently being processed, a copy of which is stored in
1899 // the _format_char data member).
1900 bool parse_int_from_format_string(int* const result) throw()
1901 {
1902 auto const reset_errno = _ptd.get_errno().create_guard();
1903
1904 Character* end{};
1905 *result = static_cast<int>(_tcstol_internal(_ptd,
1906 _format_it - 1,
1907 &end,
1908 10));
1909
1910 if (_ptd.get_errno().check(ERANGE))
1911 {
1912 return false;
1913 }
1914
1915 if (end < _format_it)
1916 {
1917 return false;
1918 }
1919
1920 _format_it = end;
1921 return true;
1922 }
1923
1924 // We enter the width state when we are reading a format specifier and we
1925 // encounter either an asterisk (indicating the width should be read from
1926 // the varargs) or a digit (indicating that we are in the process of reading
1927 // the width from the format string.
1928 __forceinline bool state_case_width() throw()
1929 {
1930 if (_format_char != '*')
1931 {
1932 return parse_int_from_format_string(&_field_width);
1933 }
1934
1935 // If the format character is an asterisk, we read the width from the
1936 // varargs. If we read a negative value, we treat it as the '-' flag
1937 // followed by a positive width (per the C Standard Library spec).
1938 if (!update_field_width())
1939 return false;
1940
1941 if (!should_format())
1942 return true;
1943
1944 if (_field_width < 0)
1945 {
1947 _field_width = -_field_width;
1948 }
1949
1950 return true;
1951 }
1952
1953 // We enter the dot state when we read a '.' from the format string. This
1954 // '.' introduces the precision part of the format specifier.
1955 __forceinline bool state_case_dot() throw()
1956 {
1957 // Reset the precision to zero. If the dot is not followed by a number,
1958 // it means a precision of zero, not the default precision (per the C
1959 // Standard Library specification). (Note: We represent the default
1960 // precision with -1.)
1961 _precision = 0;
1962
1963 return true;
1964 }
1965
1966 // We enter the precision state after we read a ',' from the format string.
1967 // At this point, we read the precision, in a manner similar to how we read
1968 // the width.
1969 __forceinline bool state_case_precision() throw()
1970 {
1971 if (_format_char != '*')
1972 {
1973 return parse_int_from_format_string(&_precision);
1974 }
1975
1976 // If the format character is an asterisk, we read the width from the
1977 // varargs. If we read a negative value, we treat it as indicating the
1978 // default precision.
1979 if (!update_precision())
1980 return false;
1981
1982 if (!should_format())
1983 return true;
1984
1985 if (_precision < 0)
1986 _precision = -1;
1987
1988 return true;
1989 }
1990
1991 // We enter the size state when we have read one of the size characters from
1992 // the format string.
1994 {
1995 if (_format_char == 'F')
1996 {
1997 // We hand the 'F' character as a length modifier because the length
1998 // modifier occurs before the type specifier. If we find an 'F' and
1999 // we are in the legacy compatibility mode that supports the 'F' length
2000 // modifier, we just ignore it (it has no meaning). Otherwise we are
2001 // not in compatibility mode so we switch out to the type case to handle
2002 // the 'F' as a %F format specifier:
2004 {
2005 _state = state::type;
2006 return state_case_type();
2007 }
2008
2009 return true;
2010 }
2011
2012 if (_format_char == 'N')
2013 {
2014 // If we find an 'N' and we are in the legacy compatibility mode that
2015 // supports the 'N' length modifier, we just ignore it (it has no
2016 // meaning). Otherwise, we are not in compatibility mode, so we
2017 // invoke the invalid parameter handler and return failure.
2019 {
2020 _state = state::invalid;
2021#pragma warning(suppress: __WARNING_IGNOREDBYCOMMA) // 6319 comma operator
2022 _UCRT_VALIDATE_RETURN(_ptd, ("N length modifier not specifier", false), EINVAL, false);
2023 return false;
2024 }
2025
2026 return true;
2027 }
2028
2029 _UCRT_VALIDATE_RETURN(_ptd, _length == length_modifier::none, EINVAL, false);
2030
2031 // We just read a size specifier; set the flags based on it:
2032 switch (_format_char)
2033 {
2034 case 'h':
2035 {
2036 if (*_format_it == 'h')
2037 {
2038 ++_format_it;
2039 _length = length_modifier::hh;
2040 }
2041 else
2042 {
2043 _length = length_modifier::h;
2044 }
2045
2046 return true;
2047 }
2048
2049 case 'I':
2050 {
2051 // The I32, I64, and I length modifiers are Microsoft extensions.
2052
2053 if (*_format_it == '3' && *(_format_it + 1) == '2')
2054 {
2055 _format_it += 2;
2056 _length = length_modifier::I32;
2057 }
2058 else if (*_format_it == '6' && *(_format_it + 1) == '4')
2059 {
2060 _format_it += 2;
2061 _length = length_modifier::I64;
2062 }
2063 else if (*_format_it == 'd' ||
2064 *_format_it == 'i' ||
2065 *_format_it == 'o' ||
2066 *_format_it == 'u' ||
2067 *_format_it == 'x' ||
2068 *_format_it == 'X')
2069 {
2070 // If we support positional parameters, then %I without a following
2071 // 32 or 64 is platform-dependent:
2072 _length = length_modifier::I;
2073 }
2074
2075 return true;
2076 }
2077
2078 case 'l':
2079 {
2080 if (*_format_it == 'l')
2081 {
2082 ++_format_it;
2083 _length = length_modifier::ll;
2084 }
2085 else
2086 {
2087 _length = length_modifier::l;
2088 }
2089
2090 return true;
2091 }
2092
2093 case 'L':
2094 {
2095 _length = length_modifier::L;
2096 return true;
2097 }
2098
2099 case 'j':
2100 {
2101 _length = length_modifier::j;
2102 return true;
2103 }
2104
2105 case 't':
2106 {
2107 _length = length_modifier::t;
2108 return true;
2109 }
2110
2111 case 'z':
2112 {
2113 _length = length_modifier::z;
2114 return true;
2115 }
2116
2117 case 'w':
2118 {
2119 _length = length_modifier::w;
2120 return true;
2121 }
2122
2123 case 'T':
2124 {
2125 _length = length_modifier::T;
2126 return true;
2127 }
2128 }
2129
2130 return true;
2131 }
2132
2133 // We enter the type case when we read the type part of the format specifier.
2134 // At this point, we have read the entire format specifier and we can extract
2135 // the value to be formatted from the varargs, format it, then output it.
2136 // This state is broken up into subfunctions, one per type category.
2138 {
2139 // Each of the subfunctions is responsible for [1] extracting the next
2140 // argument from the varargs, [2] formatting that argument into the
2141 // internal buffer, and [3] updating the string state variables with
2142 // the correct data for the format operation (either _narrow_string or
2143 // _wide_string must be set correctly, the _string_length must be set
2144 // correctly, and _string_is_wide must be true if the wide string
2145 // should be used.
2146 bool result{false};
2147 switch (_format_char)
2148 {
2149 // Individual character output:
2150 case 'C':
2151 case 'c': result = type_case_c(); break;
2152
2153 // String output:
2154 case 'Z': result = type_case_Z(); break;
2155 case 'S':
2156 case 's': result = type_case_s(); break;
2157
2158 // Floating-point output:
2159 case 'A':
2160 case 'E':
2161 case 'F':
2162 case 'G':
2163 case 'a':
2164 case 'e':
2165 case 'f':
2166 case 'g': result = type_case_a(); break;
2167
2168 // Integer and pointer output:
2169 case 'd':
2170 case 'i': result = type_case_d(); break;
2171 case 'u': result = type_case_u(); break;
2172 case 'o': result = type_case_o(); break;
2173 case 'X': result = type_case_X(); break;
2174 case 'x': result = type_case_x(); break;
2175 case 'p': result = type_case_p(); break;
2176
2177 // State reporting (no output):
2178 case 'n': result = type_case_n(); break;
2179 }
2180
2181 // If the case-specific logic failed, return immediately. The case-
2182 // specific function is responsible for invoking the invalid parameter
2183 // handler if it needs to do so.
2184 if (!result)
2185 return false;
2186
2187 // Check to see whether the output operation should be skipped (we skip
2188 // the output part e.g. during the positional scan pass when positional
2189 // formatting is used).
2190 if (should_skip_type_state_output())
2191 return true;
2192
2193 // At this point, we've completed the bulk of the formatting operation
2194 // and the string is ready to be printed. We now justify the string,
2195 // pre-pend any required prefix and leading zeroes, then print it. Well,
2196 // unless output is suppressed, that is... :-)
2197 if (_suppress_output)
2198 return true;
2199
2200 // Compute the prefix, if one is required...
2201 Character prefix[3]{};
2202 size_t prefix_length{0};
2203
2204 if (has_flag(FL_SIGNED))
2205 {
2206 if (has_flag(FL_NEGATIVE))
2207 {
2208 prefix[prefix_length++] = '-';
2209 }
2210 else if (has_flag(FL_SIGN))
2211 {
2212 prefix[prefix_length++] = '+';
2213 }
2214 else if (has_flag(FL_SIGNSP))
2215 {
2216 prefix[prefix_length++] = ' ';
2217 }
2218 }
2219
2220 bool const print_integer_0x{(_format_char == 'x' || _format_char == 'X') && has_flag(FL_ALTERNATE)};
2221 bool const print_floating_point_0x{_format_char == 'a' || _format_char == 'A'};
2222
2223 if (print_integer_0x || print_floating_point_0x)
2224 {
2225 prefix[prefix_length++] = '0';
2226 prefix[prefix_length++] = adjust_hexit('x' - 'a' + '9' + 1, _format_char == 'X' || _format_char == 'A');
2227 }
2228
2229 // Compute the amount of padding required to get to the desired field
2230 // width, then output the left padding, prefix, leading zeroes, the
2231 // string, and right padding, in that order.
2232 int const padding = static_cast<int>(_field_width - _string_length - prefix_length);
2233
2235 {
2236 // Left-pad with spaces
2237 write_multiple_characters(_output_adapter, ' ', padding, &_characters_written, _ptd);
2238 }
2239
2240 // Write the prefix
2241 _output_adapter.write_string(prefix, static_cast<int>(prefix_length), &_characters_written, _ptd);
2242
2244 {
2245 // Write leading zeroes
2246 write_multiple_characters(_output_adapter, '0', padding, &_characters_written, _ptd);
2247 }
2248
2249 // Write the string
2250 write_stored_string_tchar(Character());
2251
2252 if (_characters_written >= 0 && has_flag(FL_LEFT))
2253 {
2254 // Right-pad with spaces
2255 write_multiple_characters(_output_adapter, ' ', padding, &_characters_written, _ptd);
2256 }
2257
2258 return true;
2259 }
2260
2261 // Individual character output: The 'C' and 'c' format specifiers output an
2262 // individual wide or narrow character, respectively. They both delegate to
2263 // the type_case_c_tchar() overloads, which handle the output appropriately
2264 // for the character type of the output adapter.
2266 {
2267 return type_case_c_tchar(Character());
2268 }
2269
2270 bool type_case_c_tchar(char) throw()
2271 {
2272 // If the character is a wide character, we translate it to multibyte
2273 // to be output, storing the multibyte string in the internal buffer:
2274 if (is_wide_character_specifier(_options, _format_char, _length))
2275 {
2276 wchar_t wide_character{};
2277 if (!this->template extract_argument_from_va_list<wchar_t>(wide_character))
2278 {
2279 return false;
2280 }
2281
2282 if (!should_format())
2283 {
2284 return true;
2285 }
2286
2287 // Convert to multibyte. If the conversion fails, we suppress the
2288 // output operation but we do not fail the entire operation:
2289 errno_t const status{_wctomb_internal(&_string_length, _buffer.template data<char>(), _buffer.template count<char>(), wide_character, _ptd)};
2290 if (status != 0)
2291 {
2292 _suppress_output = true;
2293 }
2294 }
2295 // If the character is a narrow character, we can just write it directly
2296 // to the output, as-is.
2297 else
2298 {
2299 if (!this->template extract_argument_from_va_list<unsigned short>(_buffer.template data<char>()[0]))
2300 {
2301 return false;
2302 }
2303
2304 if (!should_format())
2305 {
2306 return true;
2307 }
2308
2309 _string_length = 1;
2310 }
2311
2312 _narrow_string = _buffer.template data<char>();
2313 return true;
2314 }
2315
2316 bool type_case_c_tchar(wchar_t) throw()
2317 {
2318 // If the output adapter accepts wide characters, then we must transform
2319 // the character into a wide character to be output.
2320 _string_is_wide = true;
2321
2322 wchar_t wide_character{};
2323 if (!this->template extract_argument_from_va_list<wchar_t>(wide_character))
2324 return false;
2325
2326 if (!should_format())
2327 return true;
2328
2329 if (!is_wide_character_specifier(_options, _format_char, _length))
2330 {
2331 // If the character is actually a multibyte character, then we must
2332 // transform it into the equivalent wide character. If the translation
2333 // is unsuccessful, we ignore this character but do not fail the entire
2334 // output operation.
2335 char const local_buffer[2]{ static_cast<char>(wide_character & 0x00ff), '\0' };
2336 int const mbc_length{_mbtowc_internal(
2337 _buffer.template data<wchar_t>(),
2338 local_buffer,
2339 _ptd.get_locale()->locinfo->_public._locale_mb_cur_max,
2340 _ptd
2341 )};
2342 if (mbc_length < 0)
2343 {
2344 _suppress_output = true;
2345 }
2346 }
2347 else
2348 {
2349 _buffer.template data<wchar_t>()[0] = wide_character;
2350 }
2351
2352 _wide_string = _buffer.template data<wchar_t>();
2353 _string_length = 1;
2354 return true;
2355 }
2356
2357 // String Output: The Z, S, and s format specifiers output a string. The Z
2358 // format specifier is an extension, used to print a Windows SDK ANSI_STRING
2359 // or UNICODE_STRING counted string. The S and s format specifiers output a
2360 // wide or narrow C string, respectively. If a null pointer is passed, we
2361 // replace it with a special sentinel string, with the contents "(null)".
2363 {
2364 // This matches the representation of the Windows SDK types ANSI_STRING
2365 // and UNICODE_STRING, which represent a counted string.
2366 struct ansi_string
2367 {
2368 unsigned short _length;
2369 unsigned short _maximum_length;
2370 char* _buffer;
2371 };
2372
2373 ansi_string* string{};
2374 if (!this->template extract_argument_from_va_list<ansi_string*>(string))
2375 return false;
2376
2377 if (!should_format())
2378 return true;
2379
2380 if (!string || string->_buffer == nullptr)
2381 {
2382 _narrow_string = narrow_null_string();
2383 _string_length = static_cast<int>(strlen(_narrow_string));
2384 _string_is_wide = false;
2385 }
2386 else if (is_wide_character_specifier(_options, _format_char, _length))
2387 {
2388 _wide_string = reinterpret_cast<wchar_t*>(string->_buffer);
2389 _string_length = string->_length / static_cast<int>(sizeof(wchar_t));
2390 _string_is_wide = true;
2391 }
2392 else
2393 {
2394 _narrow_string = string->_buffer;
2395 _string_length = string->_length;
2396 _string_is_wide = false;
2397 }
2398
2399 return true;
2400 }
2401
2403 {
2404 // If this format specifier has the default precision, then the entire
2405 // string is output. If a precision is given, then we output the minimum
2406 // of the length of the C string and the given precision. Note that the
2407 // string needs not be null-terminated if a precision is given, so we
2408 // cannot call strlen to compute the length of the string.
2409 if (!this->template extract_argument_from_va_list<char*>(_narrow_string))
2410 return false;
2411
2412 if (!should_format())
2413 return true;
2414
2415 int const maximum_length{(_precision == -1) ? INT_MAX : _precision};
2416
2417 if (is_wide_character_specifier(_options, _format_char, _length))
2418 {
2419 if (!_wide_string)
2420 _wide_string = wide_null_string();
2421
2422 _string_is_wide = true;
2423 _string_length = static_cast<int>(wcsnlen(_wide_string, maximum_length));
2424 }
2425 else
2426 {
2427 if (!_narrow_string)
2428 _narrow_string = narrow_null_string();
2429
2430 _string_length = type_case_s_compute_narrow_string_length(maximum_length, Character());
2431 }
2432
2433 return true;
2434 }
2435
2436 // We have two different implementations of the 's' type case, to handle
2437 // narrow and wide strings, since computation of the length is subtly
2438 // different depending on whether we are outputting narrow or wide
2439 // characters. These functions just update the string state appropriately
2440 // for the string that has just been read from the varargs.
2441 int type_case_s_compute_narrow_string_length(int const maximum_length, char) throw()
2442 {
2443 return static_cast<int>(strnlen(_narrow_string, maximum_length));
2444 }
2445
2446 int type_case_s_compute_narrow_string_length(int const maximum_length, wchar_t) throw()
2447 {
2448 _locale_t locale = _ptd.get_locale();
2449 int string_length{0};
2450
2451 for (char const* p{_narrow_string}; string_length < maximum_length && *p; ++string_length)
2452 {
2453 if (__acrt_isleadbyte_l_noupdate(static_cast<unsigned char>(*p), locale))
2454 {
2455 ++p;
2456 }
2457
2458 ++p;
2459 }
2460
2461 return string_length;
2462 }
2463
2464 // Floating-point output: The A case handles the A, E, F, and G format specifiers.
2465 // The a case handles the a, e, f, and g format specifiers. A capital format
2466 // specifier causes us to output capital hexits, whereas a lowercase format
2467 // specifier causes us to output lowercase hexits.
2469 {
2470 // The double type is signed:
2472
2473 if (!validate_state_for_type_case_a())
2474 return false;
2475
2476 if (!should_format())
2477 return true;
2478
2479 // First, we need to compute the actual precision to use, limited by
2480 // both the maximum precision and the size of the buffer that we can
2481 // allocate.
2482 if (_precision < 0)
2483 {
2484 // The default precision depends on the format specifier used. For
2485 // %e, %f, and %g, C specifies that the default precision is 6. For
2486 // %a, C specifies that "if the precision is missing and FLT_RADIX
2487 // is a power of 2, then the precision is sufficient for an exact
2488 // representation of the value" (C11 7.21.6.1/8).
2489 //
2490 // The 64-bit double has 53 bits of precision. When printing in
2491 // hexadecimal form, we print one bit of precision to the left of the
2492 // radix point and the remaining 52 bits of precision to the right.
2493 // Thus, the default precision is 13 (13 * 4 == 52).
2494 if (_format_char == 'a' || _format_char == 'A')
2495 {
2496 _precision = 13;
2497 }
2498 else
2499 {
2500 _precision = 6;
2501 }
2502 }
2503 else if (_precision == 0 && (_format_char == 'g' || _format_char == 'G'))
2504 {
2505 _precision = 1; // Per C Standard Library specification.
2506 }
2507
2508 if (!_buffer.template ensure_buffer_is_big_enough<char>(_CVTBUFSIZE + _precision, _ptd))
2509 {
2510 // If we fail to enlarge the buffer, cap precision so that the
2511 // statically-sized buffer may be used for the formatting:
2512 _precision = static_cast<int>(_buffer.template count<char>() - _CVTBUFSIZE);
2513 }
2514
2515 _narrow_string = _buffer.template data<char>();
2516
2517 // Note that we separately handle the FORMAT_POSSCAN_PASS above.
2518 _CRT_DOUBLE tmp{};
2519 if (!this->template extract_argument_from_va_list<_CRT_DOUBLE>(tmp))
2520 {
2521 return false;
2522 }
2523
2524 // Format the number into the buffer:
2526 &tmp.x,
2527 _buffer.template data<char>(),
2528 _buffer.template count<char>(),
2529 _buffer.template scratch_data<char>(),
2530 _buffer.template scratch_count<char>(),
2531 static_cast<char>(_format_char),
2532 _precision,
2533 _options,
2534 __acrt_rounding_mode::standard,
2535 _ptd);
2536
2537 // If the precision is zero but the '#' flag is part of the specifier,
2538 // we force a decimal point:
2539 if (has_flag(FL_ALTERNATE) && _precision == 0)
2540 {
2541 force_decimal_point(_narrow_string, _ptd.get_locale());
2542 }
2543
2544 // The 'g' format specifier indicates that zeroes should be cropped
2545 // unless the '#' flag is part of the specifier.
2546 if ((_format_char == 'g' || _format_char == 'G') && !has_flag(FL_ALTERNATE))
2547 {
2548 crop_zeroes(_narrow_string, _ptd.get_locale());
2549 }
2550
2551 // If the result was negative, we save the '-' for later and advance past
2552 // the negative sign (we handle the '-' separately, in code shared with
2553 // the integer formatting, to correctly handle flags).
2554 if (*_narrow_string == '-')
2555 {
2557 ++_narrow_string;
2558 }
2559
2560 // If the result was a special infinity or a nan string, suppress output
2561 // of the "0x" prefix by treating the special string as just a string:
2562 if (*_narrow_string == 'i' || *_narrow_string == 'I' ||
2563 *_narrow_string == 'n' || *_narrow_string == 'N')
2564 {
2565 unset_flag(FL_LEADZERO); // padded with spaces, not zeros.
2566 _format_char = 's';
2567 }
2568
2569 _string_length = static_cast<int>(strlen(_narrow_string));
2570
2571 return true;
2572 }
2573
2574 // Integer output: These functions handle the formatting of integer values.
2575 // There are a number of format specifiers that handle integer formatting;
2576 // we handle them separately, but they all end up calling the common function
2577 // type_case_integer(), defined last.
2579 {
2581
2582 return type_case_integer<10>();
2583 }
2584
2586 {
2587 return type_case_integer<10>();
2588 }
2589
2591 {
2592 // If the alternate flag is set, we force a leading 0:
2595
2596 return type_case_integer<8>();
2597 }
2598
2600 {
2601 return type_case_integer<16>(true);
2602 }
2603
2605 {
2606 return type_case_integer<16>();
2607 }
2608
2609 // The 'p' format specifier writes a pointer, which is simply treated as a
2610 // hexadecimal integer with lowercase hexits.
2612 {
2613 // We force the precision to be 2 * sizeof(void*), which is the number
2614 // of hexits required to represent the pointer, so that it is zero-
2615 // padded.
2616 _precision = 2 * sizeof(void*);
2617
2618 // Ensure that we read a 32-bit integer on 32-bit architectures, and
2619 // a 64-bit integer on 64-bit platforms:
2620 _length = sizeof(void*) == 4
2623
2624 return type_case_integer<16>(true);
2625 }
2626
2627 // This is the first half of the common integer formatting routine. It
2628 // extracts the integer of the specified type from the varargs and does
2629 // pre-processing common to all integer processing.
2630 template <unsigned Radix>
2631 bool type_case_integer(bool const capital_hexits = false) throw()
2632 {
2633 size_t const integer_size = to_integer_size(_length);
2634
2635 // First, extract the argument of the required type from the varargs:
2636 __int64 original_number {};
2637 bool extraction_result{};
2638 switch (integer_size)
2639 {
2640 case sizeof(int8_t):
2641 extraction_result = has_flag(FL_SIGNED)
2642 ? this->template extract_argument_from_va_list<int8_t >(original_number)
2643 : this->template extract_argument_from_va_list<uint8_t>(original_number);
2644 break;
2645 case sizeof(int16_t):
2646 extraction_result = has_flag(FL_SIGNED)
2647 ? this->template extract_argument_from_va_list<int16_t >(original_number)
2648 : this->template extract_argument_from_va_list<uint16_t>(original_number);
2649 break;
2650 case sizeof(int32_t):
2651 extraction_result = has_flag(FL_SIGNED)
2652 ? this->template extract_argument_from_va_list<int32_t >(original_number)
2653 : this->template extract_argument_from_va_list<uint32_t>(original_number);
2654 break;
2655 case sizeof(int64_t):
2656 extraction_result = has_flag(FL_SIGNED)
2657 ? this->template extract_argument_from_va_list<int64_t >(original_number)
2658 : this->template extract_argument_from_va_list<uint64_t>(original_number);
2659 break;
2660 default:
2661 _UCRT_VALIDATE_RETURN(_ptd, ("Invalid integer length modifier", 0), EINVAL, false);
2662 break;
2663 }
2664
2665 if (!extraction_result)
2666 return false;
2667
2668 // If we're not formatting, then we're done; we just needed to read the
2669 // argument from the varargs.
2670 if (!should_format())
2671 return true;
2672
2673 // Check the sign of the number. If it is negative, convert it to
2674 // positive for formatting. We'll handle the minus sign later (after
2675 // we return from this function).
2676 unsigned __int64 number{};
2677
2678 if (has_flag(FL_SIGNED) && original_number < 0)
2679 {
2680 number = static_cast<unsigned __int64>(-original_number);
2682 }
2683 else
2684 {
2685 number = static_cast<unsigned __int64>(original_number);
2686 }
2687
2688 // Check the precision to see if the default precision was specified. If
2689 // a non-default precision was specified, we turn off the zero flag, per
2690 // the C Standard Library specification.
2691 if (_precision < 0)
2692 {
2693 _precision = 1; // Default precision
2694 }
2695 else
2696 {
2698 _buffer.template ensure_buffer_is_big_enough<Character>(_precision, _ptd);
2699 }
2700
2701 // If the number is zero, we do not want to print the hex prefix ("0x"),
2702 // even if it was requested:
2703 if (number == 0)
2704 {
2706 }
2707
2708 _string_is_wide = sizeof(Character) == sizeof(wchar_t);
2709
2710 if (integer_size == sizeof(int64_t))
2711 {
2712 type_case_integer_parse_into_buffer<uint64_t, Radix>(number, capital_hexits);
2713 }
2714 else
2715 {
2716 type_case_integer_parse_into_buffer<uint32_t, Radix>(static_cast<uint32_t>(number), capital_hexits);
2717 }
2718
2719 // If the FORCEOCTAL flag is set, then we output a leading zero, unless
2720 // the formatted string already has a leading zero:
2721 if (has_flag(FL_FORCEOCTAL) && (_string_length == 0 || tchar_string()[0] != '0'))
2722 {
2723 *--tchar_string() = '0';
2724 ++_string_length;
2725 }
2726
2727 return true;
2728 }
2729
2730 // This is the second half of the common integer formatting routine. It
2731 // handles the actual formatting of the number. This logic has been split
2732 // out from the first part so that we only use 64-bit arithmetic when
2733 // absolutely required (on x86, 64-bit division is Slow-with-a-capital-S).
2734 template <typename UnsignedInteger, unsigned Radix>
2736 UnsignedInteger number,
2737 bool const capital_hexits
2738 ) throw()
2739 {
2740 // Format the number into the formatting buffer. Note that we format the
2741 // buffer at the end of the formatting buffer, which allows us to perform
2742 // the formatting from least to greatest magnitude, which maps well to
2743 // the math.
2744 Character* const last_digit{_buffer.template data<Character>() + _buffer.template count<Character>() - 1};
2745
2746 Character*& string_pointer = tchar_string();
2747
2748 string_pointer = last_digit;
2749 while (_precision > 0 || number != 0)
2750 {
2751 --_precision;
2752
2753 Character digit{static_cast<Character>(number % Radix + '0')};
2754 number /= Radix;
2755
2756 // If the digit is greater than 9, we need to convert it to the
2757 // corresponding letter hexit in the required case:
2758 if (digit > '9')
2759 {
2760 digit = adjust_hexit(digit, capital_hexits);
2761 }
2762
2763 *string_pointer-- = static_cast<char>(digit);
2764 }
2765
2766 _string_length = static_cast<int>(last_digit - string_pointer);
2767 ++string_pointer;
2768 }
2769
2770 // The 'n' type specifier is special: We read a short* or int* from the
2771 // varargs and write the number of characters that we've written so far to
2772 // the pointed-to integer.
2774 {
2775 void* p{nullptr};
2776 if (!this->template extract_argument_from_va_list<void*>(p))
2777 return false;
2778
2779 if (!should_format())
2780 return true;
2781
2783 {
2784 _UCRT_VALIDATE_RETURN(_ptd, ("'n' format specifier disabled", 0), EINVAL, false);
2785 return false; // Unreachable
2786 }
2787
2788 switch (to_integer_size(_length))
2789 {
2790 case sizeof(int8_t): *static_cast<int8_t *>(p) = static_cast<int8_t >(_characters_written); break;
2791 case sizeof(int16_t): *static_cast<int16_t*>(p) = static_cast<int16_t>(_characters_written); break;
2792 case sizeof(int32_t): *static_cast<int32_t*>(p) = static_cast<int32_t>(_characters_written); break;
2793 case sizeof(int64_t): *static_cast<int64_t*>(p) = static_cast<int64_t>(_characters_written); break;
2794 default: _UCRT_VALIDATE_RETURN(_ptd, ("Invalid integer length modifier", 0), EINVAL, false); break;
2795 }
2796
2797 // This format specifier never corresponds to an output operation:
2798 _suppress_output = true;
2799 return true;
2800 }
2801
2802 // After we have completed the formatting of the string to be output, we
2803 // perform the output operation, which is handled by these two functions.
2804 __forceinline bool write_stored_string_tchar(char) throw()
2805 {
2806 if (!_string_is_wide || _string_length <= 0)
2807 {
2808 _output_adapter.write_string(_narrow_string, _string_length, &_characters_written, _ptd);
2809 }
2810 else
2811 {
2812 wchar_t* p{_wide_string};
2813 for (int i{0}; i != _string_length; ++i)
2814 {
2815 char local_buffer[MB_LEN_MAX + 1];
2816
2817 int mbc_length{0};
2818 errno_t const status{_wctomb_internal(&mbc_length, local_buffer, _countof(local_buffer), *p++, _ptd)};
2819 if (status != 0 || mbc_length == 0)
2820 {
2821 _characters_written = -1;
2822 return true;
2823 }
2824
2825 _output_adapter.write_string(local_buffer, mbc_length, &_characters_written, _ptd);
2826 }
2827 }
2828
2829 return true;
2830 }
2831
2832 __forceinline bool write_stored_string_tchar(wchar_t) throw()
2833 {
2834 if (_string_is_wide || _string_length <= 0)
2835 {
2836 _output_adapter.write_string(_wide_string, _string_length, &_characters_written, _ptd);
2837 }
2838 else
2839 {
2840 _locale_t locale_ptr = _ptd.get_locale();
2841 char* p{_narrow_string};
2842 for (int i{0}; i != _string_length; ++i)
2843 {
2844 wchar_t wide_character{};
2845 int mbc_length{_mbtowc_internal(&wide_character, p, locale_ptr->locinfo->_public._locale_mb_cur_max, _ptd)};
2846
2847 if (mbc_length <= 0)
2848 {
2849 _characters_written = -1;
2850 return true;
2851 }
2852
2853 _output_adapter.write_character(wide_character, &_characters_written, _ptd);
2854 p += mbc_length;
2855 }
2856 }
2857
2858 return true;
2859 }
2860
2861 // These functions are utilities for working with the flags, and performing
2862 // state transitions.
2863 bool has_flag (unsigned const f) const throw() { return (_flags & f) != 0; }
2864 void set_flag (unsigned const f) throw() { _flags |= f; }
2865 void unset_flag(unsigned const f) throw() { _flags &= ~f; }
2866
2867 state find_next_state(Character const c, state const previous_state) const throw()
2868 {
2869 auto const& lookup_table = state_transition_table();
2870
2871 unsigned const current_class = static_cast<unsigned>((c < ' ' || c > 'z')
2873 : static_cast<character_type>(lookup_table[c - ' '].current_class));
2874
2875 auto const index = current_class * state_count() + static_cast<unsigned>(previous_state);
2876 return static_cast<state>(lookup_table[index].next_state);
2877 }
2878
2879 // Adjusts an out-of-range hexit character to be a lowercase or capital
2880 // letter. This function is called when formatting a number as hexadecimal
2881 // and a hexit is above 9. The normal formatting will not correctly handle
2882 // this case. Here, we adjust it by the required offset to yield a letter,
2883 // in the range [A, F], as either a lowercase or capital letter.
2884 static char __cdecl adjust_hexit(int const value, bool const capitalize) throw()
2885 {
2886 int const base {capitalize ? 'A' : 'a'};
2887 int const offset{base - '9' - 1 };
2888
2889 return static_cast<char>(offset + value);
2890 }
2891
2892 // When a null pointer is passed, we print this string as a placeholder.
2893 static char * __cdecl narrow_null_string() throw() { return "(null)"; }
2894 static wchar_t* __cdecl wide_null_string () throw() { return L"(null)"; }
2895};
2896
2897
2898
2899} // namespace __crt_stdio_output
#define EINVAL
Definition: acclib.h:90
#define ENOMEM
Definition: acclib.h:84
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
#define ERANGE
Definition: acclib.h:92
#define __cdecl
Definition: accygwin.h:79
signed char int8_t
Definition: acefiex.h:50
char * va_list
Definition: acmsvcex.h:78
#define va_arg(ap, T)
Definition: acmsvcex.h:89
#define index(s, c)
Definition: various.h:29
#define __int64
Definition: basetyps.h:16
static int_type _STLP_CALL eof()
Definition: char_traits.h:193
__acrt_stdio_char_traits< Character > char_traits
void write_string(Character const *const string, int const length, int *const count_written, __crt_cached_ptd_host &ptd) const
bool write_character_without_count_update(Character const c, __crt_cached_ptd_host &ptd) const
static printf_state_transition_table const & state_transition_table()
typename standard_base< Character, OutputAdapter >::template output_adapter_data< Character, OutputAdapter >::template common_data< Character > common_data_base
bool ensure_buffer_is_big_enough(size_t const count, __crt_cached_ptd_host &ptd)
void write_character(Character const c, int *const count_written, __crt_cached_ptd_host &ptd) const
void write_string_impl(Character const *const string, int const length, int *const count_written, __crt_cached_ptd_host &ptd) const
output_adapter_data(OutputAdapter const &output_adapter, uint64_t const options, Character const *const format, __crt_cached_ptd_host &ptd, va_list const arglist)
typename ProcessorBase::common_data_base common_data_base
typename ProcessorBase::output_adapter_data oad_base
static char __cdecl adjust_hexit(int const value, bool const capitalize)
bool type_case_integer(bool const capital_hexits=false)
int type_case_s_compute_narrow_string_length(int const maximum_length, wchar_t)
output_processor(OutputAdapter const &output_adapter, uint64_t const options, Character const *const format, __crt_cached_ptd_host &ptd, va_list const arglist)
__acrt_stdio_char_traits< Character > char_traits
void type_case_integer_parse_into_buffer(UnsignedInteger number, bool const capital_hexits)
state find_next_state(Character const c, state const previous_state) const
int type_case_s_compute_narrow_string_length(int const maximum_length, char)
static parameter_type __cdecl get_parameter_type(__int64)
static parameter_type __cdecl get_parameter_type(wchar_t)
static bool __cdecl is_character_specifier(Character2 const specifier)
format_validation_base< Character, OutputAdapter > base_type
static bool __cdecl is_pointer_specifier(Character2 const specifier)
bool validate_and_store_parameter_data(parameter_data &parameter, parameter_type const actual_type, Character const format_type, length_modifier const length)
bool extract_argument_from_va_list(ActualParameterType &result)
static bool __cdecl is_integral_specifier(Character2 const specifier)
static parameter_type __cdecl get_parameter_type(unsigned short)
static parameter_type __cdecl get_parameter_type(unsigned __int64)
static bool __cdecl is_string_specifier(Character2 const specifier)
static parameter_type __cdecl get_parameter_type(unsigned int)
bool is_positional_parameter_reappearance_consistent(parameter_data const &parameter, parameter_type const actual_type, Character const format_type, length_modifier const length)
static parameter_type __cdecl get_parameter_type(_CRT_DOUBLE)
__forceinline bool validate_and_update_state_at_end_of_format_string() const
bool extract_argument_from_va_list(ActualParameterType &result)
static printf_state_transition_table const & state_transition_table()
typename output_adapter_data< Character, OutputAdapter >::template common_data< Character > common_data_base
bool write_character_without_count_update(Character const c, __crt_cached_ptd_host &ptd) const
bool validate(__crt_cached_ptd_host &ptd) const
__acrt_stdio_char_traits< Character > char_traits
void write_string(Character const *const string, int const length, int *const count_written, __crt_cached_ptd_host &ptd) const
bool validate(__crt_cached_ptd_host &ptd) const
string_output_adapter_context< Character > context_type
void write_string(Character const *const string, int const length, int *const count_written, __crt_cached_ptd_host &ptd) const
__forceinline bool write_character(Character const c, int *const count_written, __crt_cached_ptd_host &) const
__acrt_stdio_char_traits< Character > char_traits
Definition: _locale.h:75
_Check_return_ __forceinline unsigned char __cdecl _tolower_fast_internal(_In_ unsigned char const c, _In_ _locale_t const locale)
__inline int __CRTDECL __acrt_isleadbyte_l_noupdate(_In_ int const c, _In_ _locale_t const locale)
_Check_return_ __forceinline unsigned short __cdecl _isdigit_fast_internal(_In_ unsigned char const c, _In_ _locale_t const locale)
#define _UCRT_VALIDATE_RETURN(ptd, expr, errorcode, retexpr)
#define _UCRT_VALIDATE_RETURN_NOEXC(ptd, expr, errorcode, retexpr)
__forceinline long __cdecl _tcstol_internal(__crt_cached_ptd_host &ptd, Character const *const string, EndPointer const end, int const base)
#define _CRT_INTERNAL_PRINTF_LEGACY_WIDE_SPECIFIERS
#define _CRT_INTERNAL_PRINTF_LEGACY_MSVCRT_COMPATIBILITY
result_buffer_count char *const _In_ int const _In_ bool const _In_ unsigned const _In_ STRFLT const _In_ bool const _Inout_ __crt_cached_ptd_host &ptd throw()
Definition: cvt.cpp:119
errno_t __cdecl __acrt_fp_format(double const *const value, char *const result_buffer, size_t const result_buffer_count, char *const scratch_buffer, size_t const scratch_buffer_count, int const format, int const precision, uint64_t const options, __acrt_rounding_mode rounding_mode, __crt_cached_ptd_host &ptd)
Definition: cvt.cpp:786
_In_ size_t const _In_ int _In_ bool const _In_ unsigned const _In_ __acrt_rounding_mode const _Inout_ __crt_cached_ptd_host & ptd
Definition: cvt.cpp:355
format_type
Definition: d3dx9_private.h:49
INT32 int32_t
Definition: types.h:71
UINT32 uint32_t
Definition: types.h:75
INT16 int16_t
Definition: types.h:70
UINT64 uint64_t
Definition: types.h:77
INT64 int64_t
Definition: types.h:72
unsigned char
Definition: typeof.h:29
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:31
unsigned short(__cdecl typeof(TIFFCurrentDirectory))(struct tiff *)
Definition: typeof.h:94
__kernel_size_t size_t
Definition: linux.h:237
__kernel_ptrdiff_t ptrdiff_t
Definition: linux.h:247
return nullptr
Definition: expand.cpp:78
void __declspec(noinline) __cdecl _free_base(void *const block)
Definition: free_base.cpp:98
Character const *const size_t const max_count
Definition: fullpath.cpp:66
return adapter
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
GLuint GLuint end
Definition: gl.h:1545
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
GLuint buffer
Definition: glext.h:5915
GLintptr offset
Definition: glext.h:5920
const GLubyte * c
Definition: glext.h:8905
GLuint index
Definition: glext.h:6031
GLenum GLint GLuint mask
Definition: glext.h:6028
GLfloat f
Definition: glext.h:7540
GLuint GLsizei GLsizei * length
Definition: glext.h:6040
const GLint * first
Definition: glext.h:5794
GLuint64EXT * result
Definition: glext.h:11304
GLfloat GLfloat p
Definition: glext.h:8902
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
_CRTIMP int __cdecl _get_printf_count_output(void)
Definition: stubs.c:5
#define __min(a, b)
Definition: stdlib.h:102
#define MB_LEN_MAX
Definition: stdlib.h:19
#define _CVTBUFSIZE
Definition: stdlib.h:1050
__MINGW_EXTENSION typedef long long intmax_t
Definition: stdint.h:68
#define INT_MAX
Definition: intsafe.h:150
#define f
Definition: ke_i.h:83
#define c
Definition: ke_i.h:80
#define T
Definition: mbstring.h:31
int __cdecl _mbtowc_internal(wchar_t *pwc, const char *s, size_t n, __crt_cached_ptd_host &ptd)
Definition: mbtowc.cpp:45
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
static unsigned int number
Definition: dsound.c:1479
static UINT UINT last
Definition: font.c:45
static const DWORD padding[]
Definition: mciwnd.c:89
static unsigned(__cdecl *hash_bstr)(bstr_t s)
size_t __cdecl to_integer_size(length_modifier const length)
bool __cdecl is_wide_character_specifier(uint64_t const options, Character const format_type, length_modifier const length)
void __cdecl crop_zeroes(_Inout_z_ char *buffer, _locale_t const locale)
spectre_mitigated_lookup_table< state_transition_pair, 128 > printf_state_transition_table
__forceinline void write_multiple_characters(OutputAdapter const &adapter, Character const c, int const count, int *const count_written, __crt_cached_ptd_host &ptd)
void __cdecl force_decimal_point(_Inout_z_ char *buffer, _locale_t const locale)
#define _Inout_z_
Definition: no_sal2.h:166
#define int32_t
Definition: nsiface.idl:56
#define int64_t
Definition: nsiface.idl:57
#define int16_t
Definition: nsiface.idl:55
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:325
#define signed
Definition: prototyp.h:114
#define long
Definition: qsort.c:33
#define EILSEQ
Definition: errno.h:109
__WCHAR_TYPE__ wchar_t
Definition: stddef.h:311
#define SIZE_MAX
Definition: compat.h:66
#define memset(x, y, z)
Definition: compat.h:39
va_lists_t arglist[FMT_ARGMAX+1]
Definition: format.c:284
#define _countof(array)
Definition: sndvol32.h:70
#define false
Definition: stdbool.h:37
size_t __cdecl strnlen(char const *const string, size_t const maximum_count)
Definition: strnlen.cpp:202
size_t __cdecl wcsnlen(wchar_t const *const string, size_t const maximum_count)
Definition: strnlen.cpp:210
Definition: http.c:7252
Definition: format.c:58
pthreadlocinfo locinfo
Definition: corecrt.h:23
Definition: ps.c:97
Character const *const prefix
Definition: tempnam.cpp:195
#define wchar_t
Definition: wchar.h:102
int errno_t
Definition: corecrt.h:615
#define _ARGMAX
Definition: corecrt.h:277
Definition: pdh_main.c:96
wchar_t specifier
Definition: wcsftime.cpp:381
int __cdecl _wctomb_internal(int *const return_value, char *const destination, size_t const destination_count, wchar_t const wchar, __crt_cached_ptd_host &ptd)
Definition: wctomb.cpp:30
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_DEVICE_PROPERTY_DATA _In_ DEVPROPTYPE _In_ ULONG Size
Definition: wdfdevice.h:4533
#define const
Definition: zconf.h:233