ReactOS 0.4.16-dev-1007-g2e85425
corecrt_internal_stdio_input.h
Go to the documentation of this file.
1//
2// corecrt_internal_stdio_input.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 scanf and its many variants (sscanf, fscanf, etc.).
8//
9#include <conio.h>
10#include <ctype.h>
14#include <locale.h>
15#include <stdarg.h>
16
17
18
19//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
20//
21// Input Adapters
22//
23//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
24// The actual read operations are different depending on whether the source is a
25// stream or the console. We handle these differences via input adapters. The
26// stream and console I/O functions pass an adapter to the core input function,
27// and that function calls various read members of the adapter to perform read
28// operations.
30
31template <typename Character>
33{
34public:
35
37 using char_type = Character;
38 using int_type = typename traits::int_type;
39
42 {
43 }
44
45 bool validate() const throw()
46 {
47 return true;
48 }
49
51 {
52 int_type const c{traits::gettche_nolock()};
53 if (c != traits::eof)
55
56 return c;
57 }
58
59 void unget(int_type const c) throw()
60 {
61 if (c == traits::eof)
62 return;
63
65 traits::ungettch_nolock(c);
66 }
67
68 size_t characters_read() const throw()
69 {
70 return _characters_read;
71 }
72
73private:
74
76};
77
78template <typename Character>
80{
81public:
82
84 using char_type = Character;
85 using int_type = typename traits::int_type;
86
87 stream_input_adapter(FILE* const public_stream) throw()
88 : _stream {public_stream},
90 {
91 }
92
93 bool validate() const throw()
94 {
96
97 return traits::validate_stream_is_ansi_if_required(_stream.public_stream());
98 }
99
101 {
102 int_type const c{traits::getc_nolock(_stream.public_stream())};
103 if (c != traits::eof)
105
106 return c;
107 }
108
109 void unget(int_type const c) throw()
110 {
111 if (c == traits::eof)
112 return;
113
115 traits::ungettc_nolock(c, _stream.public_stream());
116 }
117
118 size_t characters_read() const throw()
119 {
120 return _characters_read;
121 }
122
123private:
124
127};
128
129template <typename Character>
131{
132public:
133
135 using char_type = Character;
136 using unsigned_char_type = typename traits::unsigned_char_type;
137 using int_type = typename traits::int_type;
138
140 char_type const* const string,
141 size_t const length
142 ) throw()
143 : _first{string}, _last{string + length}, _it{string}
144 {
145 }
146
148 {
149 _VALIDATE_RETURN(_it != nullptr, EINVAL, false);
150 _VALIDATE_RETURN(_it <= _last, EINVAL, false);
151 return true;
152 }
153
155 {
156 if (_it == _last)
157 return traits::eof;
158
159 // If we are processing narrow characters, the character value may be
160 // negative. In this case, its value will have been sign extended in
161 // the conversion to int_type. Mask the sign extension bits for
162 // compatibility with the other input adapters:
163 return static_cast<unsigned_char_type>(*_it++);
164 }
165
166 void unget(int_type const c) throw()
167 {
168 if (_it == _first)
169 return;
170
171 if (_it == _last && c == traits::eof)
172 return;
173
174 --_it;
175 }
176
177 size_t characters_read() const throw()
178 {
179 return static_cast<size_t>(_it - _first);
180 }
181
182private:
183
187};
188
189
190
191// Eats whitespace characters from an input adapter. When it returns, the next
192// call to get() on the input adapter will be either a non-whitespace character
193// or will be EOF.
194template <template <typename> class InputAdapter, typename Character>
196 InputAdapter<Character>& adapter,
197 _locale_t const locale
198 )
199{
201 using char_type = Character;
202 using unsigned_char_type = typename traits::unsigned_char_type;
203 using int_type = typename traits::int_type;
204
205 int_type c;
206
207 do
208 {
209 c = adapter.get();
210
211 if (c == traits::eof)
212 break;
213 }
214 while (__crt_strtox::is_space(static_cast<char_type>(c), locale));
215
216 return c;
217}
218
219} // namespace __crt_stdio_input
220
221
222
223//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
224//
225// Scanset Buffer
226//
227//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
228namespace __crt_stdio_input {
229
230
231
232// The scanset buffer provides storage for a scanset (a set of characters to be
233// matched). We need a bitfield with one bit per character, so for char we can
234// use a member buffer but for wchar_t we need to dynamically allocate a buffer
235// on first use to avoid excessive stack usage.
236template <size_t CharacterSize>
238
239template <>
241{
242public:
243
245 : _buffer{}
246 {
247 }
248
249 unsigned char* data() const throw() { return _buffer; }
250 size_t size() const throw() { return buffer_size; }
251
252private:
253
254 enum : size_t { buffer_size = (static_cast<size_t>(UCHAR_MAX) + 1) / CHAR_BIT };
255
256 mutable unsigned char _buffer[buffer_size];
257};
258
259template <>
261{
262public:
263
264 unsigned char* data() const throw()
265 {
266 if (!_buffer)
267 _buffer = _calloc_crt_t(unsigned char, buffer_size);
268
269 return _buffer.get();
270 }
271
272 size_t size() const throw()
273 {
274 return buffer_size;
275 }
276
277private:
278
279 enum : size_t { buffer_size = (static_cast<size_t>(WCHAR_MAX) + 1) / CHAR_BIT };
280
281 mutable __crt_unique_heap_ptr<unsigned char> _buffer;
282};
283
284template <typename UnsignedCharacter>
286{
287public:
288
290 {
291 return _storage.data() != nullptr;
292 }
293
294 void set(UnsignedCharacter const c) throw()
295 {
296 _storage.data()[c / CHAR_BIT] |= 1 << (c % CHAR_BIT);
297 }
298
299 bool test(UnsignedCharacter const c) const throw()
300 {
301 return (_storage.data()[c / CHAR_BIT] & 1 << (c % CHAR_BIT)) != 0;
302 }
303
304 void reset() throw()
305 {
306 unsigned char* const first{_storage.data()};
307 if (!first)
308 return;
309
310 ::memset(first, 0, _storage.size());
311 }
312
313 void invert() throw()
314 {
315 unsigned char* const first{_storage.data() };
316 unsigned char* const last {first + _storage.size()};
317
318 for (unsigned char* it{first}; it != last; ++it)
319 {
320 *it ^= static_cast<unsigned char>(-1);
321 }
322 }
323
324private:
325
326 scanset_storage<sizeof(UnsignedCharacter)> _storage;
327};
328
329} // namespace __crt_stdio_input
330
331
332
333//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
334//
335// Format String Parser
336//
337//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
338namespace __crt_stdio_input {
339
341{
347};
348
350{
351 none,
352 hh,
353 h,
354 l,
355 ll,
356 j,
357 z,
358 t,
359 L,
360 I32,
361 I64,
362 T,
364};
365
367{
368 switch (length)
369 {
370 case length_modifier::none: return sizeof(int );
371 case length_modifier::hh: return sizeof(char );
372 case length_modifier::h: return sizeof(short );
373 case length_modifier::l: return sizeof(long );
374 case length_modifier::ll: return sizeof(long long);
375 case length_modifier::j: return sizeof(intmax_t );
376 case length_modifier::z: return sizeof(size_t );
377 case length_modifier::t: return sizeof(ptrdiff_t);
378 case length_modifier::I32: return sizeof(int32_t );
379 case length_modifier::I64: return sizeof(int64_t );
380
381 default:
382 _ASSERTE(("Unexpected length specifier", false));
383 return 0;
384 }
385}
386
388{
389 switch (length)
390 {
391 case length_modifier::none: return sizeof(float );
392 case length_modifier::l: return sizeof(double );
393 case length_modifier::L: return sizeof(long double);
394
395 default:
396 _ASSERTE(("Unexpected length specifier", false));
397 return 0;
398 }
399}
400
402{
403 character,
404 string,
405
411
413
414 scanset,
415
417
419};
420
422{
423 static unsigned char const constraints
424 [static_cast<size_t>(conversion_mode::enumerator_count)]
425 [static_cast<size_t>(length_modifier::enumerator_count)]
426 {
427 /* none hh h l ll j z t L I32 I64 T */
428 /* character */ { 1 , 0 , 1 , 1 , 1 , 0 , 0 , 0 , 1 , 0 , 0 , 1 },
429 /* string */ { 1 , 0 , 1 , 1 , 1 , 0 , 0 , 0 , 1 , 0 , 0 , 1 },
430 /* signed decimal */ { 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 1 , 1 , 0 },
431 /* signed unknown */ { 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 1 , 1 , 0 },
432 /* unsigned octal */ { 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 1 , 1 , 0 },
433 /* unsigned decimal */ { 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 1 , 1 , 0 },
434 /* unsigned hexadecimal */ { 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 1 , 1 , 0 },
435 /* floating point */ { 1 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 },
436 /* scanset */ { 1 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 },
437 /* report character count */ { 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 1 , 1 , 0 }
438 };
439
440 return constraints[static_cast<size_t>(mode)][static_cast<size_t>(length)] != 0;
441}
442
443template <size_t N> struct uintn_t_impl;
444template <> struct uintn_t_impl<4> { typedef uint32_t type; };
445template <> struct uintn_t_impl<8> { typedef uint64_t type; };
446
447template <size_t N>
449
450template <typename Character>
452{
453public:
454
456 using char_type = Character;
457 using unsigned_char_type = typename traits::unsigned_char_type;
458 using int_type = typename traits::int_type;
459
461 _In_ uint64_t const options,
462 _In_z_ unsigned_char_type const* const format_it
463 ) throw()
464 : _options {options },
465 _format_it {format_it},
466 _error_code{0 }
467 {
469 }
470
471 bool validate() const throw()
472 {
473 _VALIDATE_RETURN(_format_it != nullptr, EINVAL, false);
474 return true;
475 }
476
477 bool advance() throw()
478 {
479 if (_error_code != 0)
480 {
481 return false;
482 }
483
485
486 if (*_format_it == '\0')
487 {
489 return false;
490 }
491
492 if (traits::istspace(*_format_it))
493 {
495
496 while (traits::istspace(*_format_it))
497 ++_format_it;
498
499 return true;
500 }
501
502 if (_format_it[0] != '%' || _format_it[1] == '%')
503 {
506 _format_it += _format_it[0] != '%' ? 1 : 2;
507
509 }
510
512 ++_format_it; // Advance past the %
513
515
517 {
518 return false;
519 }
520
523
525 {
526 return false;
527 }
528
530 {
532 return false;
533 }
534
535 return true;
536 }
537
539 {
540 return _error_code;
541 }
542
544 {
545 return _kind;
546 }
547
549 {
552 }
553
555 {
558 }
559
561 {
564 }
565
567 {
569 return _width;
570 }
571
572 size_t length() const throw()
573 {
575 switch (_mode)
576 {
580 return _is_wide ? sizeof(wchar_t) : sizeof(char);
581
589
592 }
593
594 return 0; // Unreachable
595 }
596
598 {
600 return _mode;
601 }
602
604 {
606 return _scanset;
607 }
608
609private:
610
612 {
614 {
615 return true;
616 }
617
618 // If we need a trail byte and we're at the end of the format string,
619 // the format string is malformed:
620 if (*_format_it == '\0')
621 {
623 return false;
624 }
625
627 ++_format_it;
628 return true;
629 }
630
632 {
633 return true; // There are no trail bytes for wide character strings
634 }
635
637 {
638 if (*_format_it != '*')
639 return;
640
642 ++_format_it;
643 return;
644 }
645
647 {
648 if (__crt_strtox::parse_digit(static_cast<char_type>(*_format_it)) > 9)
649 return true;
650
651 unsigned_char_type* width_end{};
652 uint64_t const width{traits::tcstoull(
653 reinterpret_cast<char_type const*>(_format_it),
654 reinterpret_cast<char_type**>(&width_end),
655 10)};
656
657 if (width == 0 || width_end == _format_it)
658 {
660 return false;
661 }
662
663 _width = width;
664 _format_it = width_end;
665 return true;
666 }
667
669 {
670 switch (*_format_it)
671 {
672 case 'h':
673 {
674 if (_format_it[1] == 'h')
675 {
676 _format_it += 2; // Advance past "hh"
678 }
679 else
680 {
681 _format_it += 1; // Advance past "h"
683 }
684
685 return;
686 }
687
688 case 'I':
689 {
690 // The I32, I64, and I length modifiers are Microsoft extensions.
691
692 if (_format_it[1] == '3' && _format_it[2] == '2')
693 {
694 _format_it += 3; // Advance past "I32"
696 return;
697 }
698
699 if (_format_it[1] == '6' && _format_it[2] == '4')
700 {
701 _format_it += 3; // Advance past "I64"
703 return;
704 }
705
706 // Some disambiguation is required for the standalone I length
707 // modifier. If the I is followed by a d, i, o, x, or X character,
708 // then we treat it as I32 on 32-bit platforms and I64 on 64-bit
709 // platforms. Otherwise, we do not treat it as a length modifier
710 // and instead treat it as a conversion specifier (equivalent to the
711 // lowercase i).
712 if (_format_it[1] == 'd' ||
713 _format_it[1] == 'i' ||
714 _format_it[1] == 'o' ||
715 _format_it[1] == 'u' ||
716 _format_it[1] == 'x' ||
717 _format_it[1] == 'X')
718 {
719 ++_format_it; // Advance past "I"
720 _length = sizeof(void*) == 4
723 return;
724 }
725
726 return;
727 }
728
729 case 'l':
730 {
731 if (_format_it[1] == 'l')
732 {
733 _format_it += 2; // Advance past "ll"
735 }
736 else
737 {
738 _format_it += 1; // Advance past "l"
740 }
741
742 return;
743 }
744
745 case 'L':
746 {
747 ++_format_it; // Advance past "L"
749 return;
750 }
751
752 case 'j':
753 {
754 ++_format_it; // Advance past "j"
756 return;
757 }
758
759 case 't':
760 {
761 ++_format_it; // Advance past "t"
763 return;
764 }
765
766 case 'z':
767 {
768 ++_format_it; // Advance past "z"
770 return;
771 }
772
773 case 'T':
774 {
775 ++_format_it; // Advance past "T"
777 return;
778 }
779 }
780 }
781
783 {
784 if (*_format_it == 'w')
785 {
786 ++_format_it; // Advance past "w"
787 _is_wide = true;
788 return;
789 }
790
792 {
793 _is_wide = true;
794 return;
795 }
796 }
797
798 bool should_default_to_wide(unsigned char const c) throw()
799 {
800 return c == 'C' || c == 'S';
801 }
802
803 bool should_default_to_wide(wchar_t const c) throw()
804 {
805 if (c == 'C' || c == 'S')
806 return false;
807
809 return true;
810
812 }
813
815 {
817 _is_wide = false;
818
822 _is_wide = true;
823 }
824
826 {
827 switch (*_format_it)
828 {
829 case 'C':
830 case 'c':
831 {
832 // If no width was specified, use a default width of one character:
833 if (_width == 0)
834 _width = 1;
835
837
839 ++_format_it;
840 return true;
841 }
842
843 case 'S':
844 case 's':
845 {
847
849 ++_format_it;
850 return true;
851 }
852
853 case 'i':
854 case 'I':
855 {
857 ++_format_it;
858 return true;
859 }
860
861 case 'd':
862 {
864 ++_format_it;
865 return true;
866 }
867
868 case 'u':
869 {
871 ++_format_it;
872 return true;
873 }
874
875 case 'X':
876 case 'x':
877 {
879 ++_format_it;
880 return true;
881 }
882
883 case 'p':
884 {
885 _length = sizeof(void*) == 4
889 ++_format_it;
890 return true;
891 }
892
893 case 'o':
894 {
896 ++_format_it;
897 return true;
898 }
899
900 case 'A':
901 case 'a':
902 case 'E':
903 case 'e':
904 case 'F':
905 case 'f':
906 case 'G':
907 case 'g':
908 {
910 ++_format_it;
911 return true;
912 }
913
914 case '[':
915 {
917
919 ++_format_it;
920 return scan_scanset_range();
921 }
922
923 case 'n':
924 {
926 ++_format_it;
927 return true;
928 }
929
930 default:
931 {
933 return false;
934 }
935 }
936 }
937
939 {
940 if (!_scanset.is_usable())
941 {
943 return false;
944 }
945
946 _scanset.reset();
947
948 bool const is_reject_set{*_format_it == '^'};
949 if (is_reject_set)
950 {
951 ++_format_it;
952 }
953
954 if (*_format_it == ']')
955 {
956 ++_format_it;
957 _scanset.set(static_cast<unsigned_char_type>(']'));
958 }
959
960 unsigned_char_type const* const first{_format_it};
961 unsigned_char_type const* last_range_end = nullptr;
962 for (; *_format_it != ']' && *_format_it != '\0'; ++_format_it)
963 {
964 // If the current character is not a hyphen, if its the end of a range,
965 // or if it's the first or last character in the scanset, treat it as a
966 // literal character and just add it to the table:
967 if (*_format_it != '-' || _format_it - 1 == last_range_end || _format_it == first || _format_it[1] == ']')
968 {
970 }
971 // Otherwise, we're pointing to a hyphen that falls between two other
972 // characters, so this is a range to be matched (e.g. [a-z]). Toggle
973 // the bits for each character in the range:
974 else
975 {
978 last_range_end = _format_it + 1;
979
980 // We support ranges in both directions ([a-z] and [z-a]). We
981 // can handle both simultaneously by transforming [z-a] into [a-z]:
983 {
986 upper_bound = c;
987 }
988
989 // Convert [lower_bound, upper_bound] into [lower_bound, upper_bound):
990 ++upper_bound;
991
993 {
994 _scanset.set(c);
995 }
996 }
997 }
998
999 if (*_format_it == '\0')
1000 {
1002 return false;
1003 }
1004
1005 if (is_reject_set)
1006 {
1007 _scanset.invert();
1008 }
1009
1010 ++_format_it; // Advance past ']'
1011 return true;
1012 }
1013
1015 {
1016 // Note that we never reset the error code; in theory, we should never
1017 // be trying to use the parser at all once an error is encountered.
1021 _suppress_assignment = false;
1022 _width = 0;
1024 _is_wide = false;
1026 }
1027
1029 {
1032 }
1033
1037
1039
1042
1049};
1050
1051} // namespace __crt_stdio_input
1052
1053
1054
1055//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1056//
1057// Input Processor
1058//
1059//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1060// The input processor constructs a format string parser, iterates over the
1061// format string, and performs the appropriate action for each directive.
1062namespace __crt_stdio_input {
1063
1064template <typename Character, typename InputAdapter>
1066{
1067public:
1068
1070 using char_type = Character;
1071 using unsigned_char_type = typename traits::unsigned_char_type;
1072 using int_type = typename traits::int_type;
1073
1075 InputAdapter const& input_adapter,
1076 uint64_t const options,
1077 char_type const* const format,
1078 _locale_t const locale,
1079 va_list const arglist
1080 ) throw()
1081 : _options {options },
1082 _input_adapter {input_adapter },
1083 _format_parser {options, reinterpret_cast<unsigned_char_type const*>(format)},
1084 _locale {locale },
1085 _valist {arglist },
1087 {
1088 }
1089
1091 {
1092 if (!_input_adapter.validate())
1093 return EOF;
1094
1095 if (!_format_parser.validate())
1096 return EOF;
1097
1098 while (_format_parser.advance())
1099 {
1100 if (!process_state())
1101 break;
1102 }
1103
1104 // Return value is number of receiving arguments assigned,
1105 // or EOF if read failure occurs before the first receiving argument was assigned.
1106 int result{static_cast<int>(_receiving_arguments_assigned)};
1107
1108 // If we haven't reached the 'end_of_string' parse, then a read error occurred.
1110 {
1111 int_type const c{_input_adapter.get()};
1112 if (c == traits::eof)
1113 result = EOF;
1114
1115 _input_adapter.unget(c);
1116 }
1117
1118 if (secure_buffers())
1119 {
1121 }
1122
1123 return result;
1124 }
1125
1126private:
1127
1129 {
1130 switch (_format_parser.kind())
1131 {
1133 {
1134 return process_whitespace();
1135 }
1136
1138 {
1140 }
1141
1143 {
1145 // %n and suppressed conversion specifiers are not considered receiving arguments
1146 if (result
1149 {
1151 }
1152
1153 return result;
1154 }
1155 }
1156
1157 return false;
1158 }
1159
1161 {
1163 return true;
1164 }
1165
1167 {
1168 int_type const c{_input_adapter.get()};
1169 if (c == traits::eof)
1170 {
1171 return false;
1172 }
1173
1175 {
1176 _input_adapter.unget(c);
1177 return false;
1178 }
1179
1180 return process_literal_character_tchar(static_cast<char_type>(c));
1181 }
1182
1183 bool process_literal_character_tchar(char const initial_character) throw()
1184 {
1185 if (isleadbyte(static_cast<unsigned char>(initial_character)) == 0)
1186 {
1187 return true;
1188 }
1189
1190 int_type const c{_input_adapter.get()};
1192 {
1193 _input_adapter.unget(c);
1194 _input_adapter.unget(initial_character);
1195 return false;
1196 }
1197
1198 return true;
1199 }
1200
1202 {
1203 return true; // No-op for Unicode
1204 }
1205
1207 {
1208 switch (_format_parser.mode())
1209 {
1213
1219
1221
1223 }
1224
1225 return false;
1226 }
1227
1229 {
1231 {
1233 }
1234
1235 switch (_format_parser.length())
1236 {
1237 case sizeof(char): return process_string_specifier_tchar(mode, char());
1238 case sizeof(wchar_t): return process_string_specifier_tchar(mode, wchar_t());
1239 default: return false;
1240 }
1241 }
1242
1243 template <typename BufferCharacter>
1244 bool process_string_specifier_tchar(conversion_mode const mode, BufferCharacter) throw()
1245 {
1246 BufferCharacter _UNALIGNED* buffer{nullptr};
1248 {
1249 buffer = va_arg(_valist, BufferCharacter _UNALIGNED*);
1250 _VALIDATE_RETURN(buffer != nullptr, EINVAL, false);
1251 }
1252
1253 size_t const buffer_count{buffer != nullptr && secure_buffers()
1254 ? va_arg(_valist, unsigned)
1256 };
1257
1258 if (buffer_count == 0)
1259 {
1261 {
1262 // For legacy compatibility: in the old implementation, we failed
1263 // to unget the last character read if the buffer had a size of zero
1264 _input_adapter.get();
1265
1266 // Additionally, we wrote a terminator to the buffer, even though
1267 // the caller said the buffer had zero elements
1268 buffer[0] = '\0';
1269 }
1270
1271 errno = ENOMEM;
1272 return false;
1273 }
1274
1276
1277 BufferCharacter _UNALIGNED* buffer_pointer {buffer };
1278 size_t buffer_remaining{buffer_count};
1279
1280 if (mode != conversion_mode::character && buffer_remaining != _CRT_UNBOUNDED_BUFFER_SIZE)
1281 {
1282 --buffer_remaining; // Leave room for terminator when scanning strings
1283 }
1284
1285 uint64_t width_consumed{0};
1286 for (; width == 0 || width_consumed != width; ++width_consumed)
1287 {
1288 int_type c{_input_adapter.get()};
1289
1291 {
1292 _input_adapter.unget(c);
1293 break;
1294 }
1295
1297 {
1298 continue;
1299 }
1300
1301 if (buffer_remaining == 0)
1302 {
1304 errno = ENOMEM;
1305 return false;
1306 }
1307
1308 if (!write_character(buffer, buffer_count, buffer_pointer, buffer_remaining, static_cast<char_type>(c)))
1309 {
1310 break;
1311 }
1312 }
1313
1314 if (width_consumed == 0)
1315 {
1316 return false;
1317 }
1318
1319 // The %c conversion specifier "matches a sequence of characters of exactly
1320 // the number specified by the field width." The legacy behavior was to
1321 // match a sequence of up to that many characters. If legacy mode was not
1322 // requested, fail if we did not match the requested number of characters:
1324 width_consumed != width &&
1326 {
1327 return false;
1328 }
1329
1331 {
1332 return true;
1333 }
1334
1336 {
1337 *buffer_pointer = '\0';
1338 fill_buffer(buffer, buffer_count, buffer_remaining);
1339 }
1340
1341 return true;
1342 }
1343
1344 // There are four overloads of write_character to handle writing both narrow
1345 // and wide characters into either a narrow or a wide buffer.
1347 char* const buffer,
1348 size_t const buffer_count,
1349 char*& buffer_pointer,
1350 size_t& buffer_remaining,
1351 char const c
1352 ) throw()
1353 {
1356
1357 *buffer_pointer++ = c;
1358 --buffer_remaining;
1359 return true;
1360 }
1361
1363 char* const buffer,
1364 size_t const buffer_count,
1365 char*& buffer_pointer,
1366 size_t& buffer_remaining,
1367 wchar_t const c
1368 ) throw()
1369 {
1371 {
1372 int narrow_count{0};
1373 if (_ERRCHECK_EINVAL_ERANGE(wctomb_s(&narrow_count, buffer_pointer, MB_LEN_MAX, c)) == 0)
1374 {
1375 buffer_pointer += narrow_count;
1376 buffer_remaining -= narrow_count;
1377 }
1378 }
1379 else
1380 {
1381 int narrow_count{0};
1382 if (wctomb_s(&narrow_count, buffer_pointer, buffer_remaining, c) == ERANGE)
1383 {
1385 return false;
1386 }
1387
1388 if (narrow_count > 0)
1389 {
1390 buffer_pointer += narrow_count;
1391 buffer_remaining -= narrow_count;
1392 }
1393 }
1394
1395 return true;
1396 }
1397
1399 wchar_t _UNALIGNED* const buffer,
1400 size_t const buffer_count,
1401 wchar_t _UNALIGNED*& buffer_pointer,
1402 size_t& buffer_remaining,
1403 char const c
1404 ) throw()
1405 {
1408
1409 char narrow_temp[2]{c, '\0'};
1410 if (isleadbyte(static_cast<unsigned char>(c)))
1411 {
1412 narrow_temp[1] = static_cast<char>(_input_adapter.get());
1413 }
1414
1415 wchar_t wide_temp{'?'};
1416
1417 _mbtowc_l(&wide_temp, narrow_temp, _locale->locinfo->_public._locale_mb_cur_max, _locale);
1418
1419 *buffer_pointer++ = c;
1420 --buffer_remaining;
1421 return true;
1422 }
1423
1425 wchar_t _UNALIGNED* const buffer,
1426 size_t const buffer_count,
1427 wchar_t _UNALIGNED*& buffer_pointer,
1428 size_t& buffer_remaining,
1429 wchar_t const c
1430 ) throw()
1431 {
1434
1435 *buffer_pointer++ = c;
1436 --buffer_remaining;
1437 return true;
1438 }
1439
1440 template <typename BufferCharacter>
1441 static void fill_buffer(
1442 BufferCharacter _UNALIGNED* const buffer,
1443 size_t const buffer_count,
1444 size_t const buffer_remaining
1445 ) throw()
1446 {
1448 UNREFERENCED_PARAMETER(buffer_remaining);
1449
1451 return;
1452
1453 _FILL_STRING(buffer, buffer_count, buffer_count - buffer_remaining);
1454 }
1455
1456 template <typename BufferCharacter>
1457 static void reset_buffer(
1458 BufferCharacter _UNALIGNED* const buffer,
1459 size_t const buffer_count
1460 ) throw()
1461 {
1463
1465 return;
1466
1468 }
1469
1471 {
1472 if (c == traits::eof)
1473 return false;
1474
1475 switch (mode)
1476 {
1478 {
1479 return true;
1480 }
1481
1483 {
1484 if (c >= '\t' && c <= '\r')
1485 return false;
1486
1487 if (c == ' ')
1488 return false;
1489
1490 return true;
1491 }
1492
1494 {
1495 if (!_format_parser.scanset().test(static_cast<unsigned_char_type>(c)))
1496 return false;
1497
1498 return true;
1499 }
1500 }
1501
1502 return false;
1503 }
1504
1505 bool process_integer_specifier(unsigned base, bool const is_signed) throw()
1506 {
1508
1509 bool succeeded{false};
1510 uint64_t const number{__crt_strtox::parse_integer<uint64_t>(
1511 _locale,
1513 base,
1514 is_signed)};
1515
1516 if (!succeeded)
1517 return false;
1518
1520 return true;
1521
1522 return write_integer(number);
1523 }
1524
1525 template <typename FloatingType>
1527 {
1528 bool succeeded{false};
1529 FloatingType value{};
1531 _locale,
1533 &value)};
1534
1535 if (!succeeded || status == SLD_NODIGITS)
1536 return false;
1537
1539 return true;
1540
1542 }
1543
1545 {
1547
1548 switch (_format_parser.length())
1549 {
1550 case sizeof(float): return process_floating_point_specifier_t<float >();
1551 case sizeof(double): return process_floating_point_specifier_t<double>();
1552 default: return false;
1553 }
1554 }
1555
1557 {
1559 return true;
1560
1561 return write_integer(_input_adapter.characters_read());
1562 }
1563
1564 bool write_integer(uint64_t const value) throw()
1565 {
1566 void* const result_pointer{va_arg(_valist, void*)};
1567 _VALIDATE_RETURN(result_pointer != nullptr, EINVAL, false);
1568
1569 switch (_format_parser.length())
1570 {
1571 case sizeof(uint8_t ): *static_cast<uint8_t *>(result_pointer) = static_cast<uint8_t >(value); return true;
1572 case sizeof(uint16_t): *static_cast<uint16_t*>(result_pointer) = static_cast<uint16_t>(value); return true;
1573 case sizeof(uint32_t): *static_cast<uint32_t*>(result_pointer) = static_cast<uint32_t>(value); return true;
1574 case sizeof(uint64_t): *static_cast<uint64_t*>(result_pointer) = static_cast<uint64_t>(value); return true;
1575 default:
1576 _ASSERTE(("Unexpected length specifier", false));
1577 return false;
1578 }
1579 }
1580
1581 template <typename FloatingType>
1582 bool write_floating_point(FloatingType const& value) throw()
1583 {
1584 using integer_type = uintn_t<sizeof(FloatingType)>;
1585
1586 void* const result_pointer{va_arg(_valist, void*)};
1587 _VALIDATE_RETURN(result_pointer != nullptr, EINVAL, false);
1588
1589 _ASSERTE(sizeof(FloatingType) == _format_parser.length());
1590
1591 // We write through the pointer as if it were an integer pointer, to
1592 // avoid floating point instructions that cause information loss for
1593 // special NaNs (signaling NaNs, indeterminates):
1594 *static_cast<integer_type*>(result_pointer) = reinterpret_cast<integer_type const&>(value);
1595 return true;
1596 }
1597
1598private:
1599
1600 bool secure_buffers() const throw()
1601 {
1603 }
1604
1606 InputAdapter _input_adapter;
1611};
1612
1613} // namespace __crt_stdio_input
_STLP_MOVE_TO_STD_NAMESPACE _ForwardIter upper_bound(_ForwardIter __first, _ForwardIter __last, const _Tp &__val)
Definition: _algo.h:507
_STLP_MOVE_TO_STD_NAMESPACE _ForwardIter lower_bound(_ForwardIter __first, _ForwardIter __last, const _Tp &__val)
Definition: _algo.h:481
#define WCHAR_MAX
Definition: _cwchar.h:123
#define EINVAL
Definition: acclib.h:90
#define ENOMEM
Definition: acclib.h:84
#define ERANGE
Definition: acclib.h:92
#define __cdecl
Definition: accygwin.h:79
unsigned short int uint16_t
Definition: acefiex.h:54
char * va_list
Definition: acmsvcex.h:78
#define va_arg(ap, T)
Definition: acmsvcex.h:89
scanset_buffer< unsigned_char_type > const & scanset() const
scanset_buffer< unsigned_char_type > _scanset
void reset_token_state_for_error(errno_t const error_code)
format_string_parser(_In_ uint64_t const options, _In_z_ unsigned_char_type const *const format_it)
typename traits::unsigned_char_type unsigned_char_type
static void reset_buffer(BufferCharacter _UNALIGNED *const buffer, size_t const buffer_count)
bool process_string_specifier(conversion_mode const mode)
bool process_integer_specifier(unsigned base, bool const is_signed)
bool write_floating_point(FloatingType const &value)
bool process_string_specifier_tchar(conversion_mode const mode, BufferCharacter)
bool write_character(wchar_t _UNALIGNED *const buffer, size_t const buffer_count, wchar_t _UNALIGNED *&buffer_pointer, size_t &buffer_remaining, wchar_t const c)
format_string_parser< char_type > _format_parser
static void fill_buffer(BufferCharacter _UNALIGNED *const buffer, size_t const buffer_count, size_t const buffer_remaining)
bool write_character(wchar_t _UNALIGNED *const buffer, size_t const buffer_count, wchar_t _UNALIGNED *&buffer_pointer, size_t &buffer_remaining, char const c)
bool write_character(char *const buffer, size_t const buffer_count, char *&buffer_pointer, size_t &buffer_remaining, char const c)
bool process_literal_character_tchar(char const initial_character)
bool write_character(char *const buffer, size_t const buffer_count, char *&buffer_pointer, size_t &buffer_remaining, wchar_t const c)
typename traits::unsigned_char_type unsigned_char_type
bool is_character_allowed_in_string(conversion_mode const mode, int_type const c) const
input_processor(InputAdapter const &input_adapter, uint64_t const options, char_type const *const format, _locale_t const locale, va_list const arglist)
bool test(UnsignedCharacter const c) const
scanset_storage< sizeof(UnsignedCharacter)> _storage
typename traits::unsigned_char_type unsigned_char_type
string_input_adapter(char_type const *const string, size_t const length)
Definition: _locale.h:75
#define _CRT_UNBOUNDED_BUFFER_SIZE
#define _ERRCHECK_EINVAL_ERANGE(e)
#define _FILL_STRING
#define _RESET_STRING(_String, _Size)
#define _VALIDATE_RETURN(expr, errorcode, retexpr)
#define _CRT_INTERNAL_SCANF_LEGACY_MSVCRT_COMPATIBILITY
#define _CRT_INTERNAL_SCANF_LEGACY_WIDE_SPECIFIERS
#define _CRT_INTERNAL_SCANF_SECURECRT
#define _ASSERTE(expr)
Definition: crtdbg.h:114
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
UINT32 uint32_t
Definition: types.h:75
UINT64 uint64_t
Definition: types.h:77
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
#define CHAR_BIT
Definition: urlcache.c:62
__kernel_size_t size_t
Definition: linux.h:237
__kernel_ptrdiff_t ptrdiff_t
Definition: linux.h:247
return adapter
GLint GLint GLsizei width
Definition: gl.h:1546
GLuint buffer
Definition: glext.h:5915
const GLubyte * c
Definition: glext.h:8905
GLenum mode
Definition: glext.h:6217
GLuint GLsizei GLsizei * length
Definition: glext.h:6040
const GLint * first
Definition: glext.h:5794
GLuint64EXT * result
Definition: glext.h:11304
#define EOF
Definition: stdio.h:24
_CRTIMP int __cdecl _mbtowc_l(_Pre_notnull_ _Post_z_ wchar_t *_DstCh, _In_reads_bytes_opt_(_SrcSizeInBytes) _Pre_opt_z_ const char *_SrcCh, _In_ size_t _SrcSizeInBytes, _In_opt_ _locale_t _Locale)
#define MB_LEN_MAX
Definition: stdlib.h:19
#define isleadbyte(_c)
Definition: wchar.h:598
#define UCHAR_MAX
Definition: limits.h:25
__MINGW_EXTENSION typedef long long intmax_t
Definition: stdint.h:68
#define c
Definition: ke_i.h:80
static unsigned int number
Definition: dsound.c:1479
static UINT UINT last
Definition: font.c:45
static const char mbstate_t *static wchar_t const char mbstate_t *static const wchar_t int *static double
Definition: string.c:89
static float(__cdecl *square_half_float)(float x
BYTE uint8_t
Definition: msvideo1.c:66
typename uintn_t_impl< N >::type uintn_t
size_t __cdecl to_floating_point_length(length_modifier const length)
size_t __cdecl to_integer_length(length_modifier const length)
bool __cdecl is_length_valid(conversion_mode const mode, length_modifier const length)
input_adapter_character_source< InputAdapter > __cdecl make_input_adapter_character_source(InputAdapter *const input_adapter, uint64_t const width, bool *const succeeded)
__forceinline unsigned __cdecl parse_digit(char const c)
__forceinline bool __cdecl is_space(char const c, _locale_t const locale)
SLD_STATUS __cdecl parse_floating_point(_locale_t const locale, CharacterSource source, FloatingType *const result)
#define _In_z_
Definition: no_sal2.h:164
#define _In_
Definition: no_sal2.h:158
#define uint32_t
Definition: nsiface.idl:61
#define uint64_t
Definition: nsiface.idl:62
#define int32_t
Definition: nsiface.idl:56
#define uint16_t
Definition: nsiface.idl:60
#define int64_t
Definition: nsiface.idl:57
#define uint8_t
Definition: nsiface.idl:59
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:325
#define long
Definition: qsort.c:33
static void skip_whitespace()
Definition: regtests2xml.c:188
#define errno
Definition: errno.h:18
#define EILSEQ
Definition: errno.h:109
__WCHAR_TYPE__ wchar_t
Definition: stddef.h:311
#define memset(x, y, z)
Definition: compat.h:39
va_lists_t arglist[FMT_ARGMAX+1]
Definition: format.c:284
wchar_t const *const size_t const buffer_size
Definition: stat.cpp:95
Definition: format.c:58
pthreadlocinfo locinfo
Definition: corecrt.h:23
Definition: ps.c:97
#define wchar_t
Definition: wchar.h:102
int errno_t
Definition: corecrt.h:615
Definition: pdh_main.c:96
#define _UNALIGNED
Definition: vcruntime.h:207
errno_t __cdecl wctomb_s(int *const return_value, char *const destination, size_t const destination_count, wchar_t const wchar)
Definition: wctomb.cpp:160
ActualNumberDriverObjects * sizeof(PDRIVER_OBJECT)) PDRIVER_OBJECT *DriverObjectList
size_t const buffer_count
Definition: xtoa.cpp:36
#define const
Definition: zconf.h:233