// // corecrt_internal_stdio_input.h // // Copyright (c) Microsoft Corporation. All rights reserved. // // This file defines the core implementation of the formatted output functions, // including scanf and its many variants (sscanf, fscanf, etc.). // #include #include #include #include #include #include #include //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // // Input Adapters // //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // The actual read operations are different depending on whether the source is a // stream or the console. We handle these differences via input adapters. The // stream and console I/O functions pass an adapter to the core input function, // and that function calls various read members of the adapter to perform read // operations. namespace __crt_stdio_input { template class console_input_adapter { public: using traits = __acrt_stdio_char_traits; using char_type = Character; using int_type = typename traits::int_type; console_input_adapter() throw() : _characters_read{0} { } bool validate() const throw() { return true; } int_type get() throw() { int_type const c{traits::gettche_nolock()}; if (c != traits::eof) ++_characters_read; return c; } void unget(int_type const c) throw() { if (c == traits::eof) return; --_characters_read; traits::ungettch_nolock(c); } size_t characters_read() const throw() { return _characters_read; } private: size_t _characters_read; }; template class stream_input_adapter { public: using traits = __acrt_stdio_char_traits; using char_type = Character; using int_type = typename traits::int_type; stream_input_adapter(FILE* const public_stream) throw() : _stream {public_stream}, _characters_read{0 } { } bool validate() const throw() { _VALIDATE_RETURN(_stream.valid(), EINVAL, false); return traits::validate_stream_is_ansi_if_required(_stream.public_stream()); } int_type get() throw() { int_type const c{traits::getc_nolock(_stream.public_stream())}; if (c != traits::eof) ++_characters_read; return c; } void unget(int_type const c) throw() { if (c == traits::eof) return; --_characters_read; traits::ungettc_nolock(c, _stream.public_stream()); } size_t characters_read() const throw() { return _characters_read; } private: __crt_stdio_stream _stream; size_t _characters_read; }; template class string_input_adapter { public: using traits = __acrt_stdio_char_traits; using char_type = Character; using unsigned_char_type = typename traits::unsigned_char_type; using int_type = typename traits::int_type; string_input_adapter( char_type const* const string, size_t const length ) throw() : _first{string}, _last{string + length}, _it{string} { } bool validate() throw() { _VALIDATE_RETURN(_it != nullptr, EINVAL, false); _VALIDATE_RETURN(_it <= _last, EINVAL, false); return true; } int_type get() throw() { if (_it == _last) return traits::eof; // If we are processing narrow characters, the character value may be // negative. In this case, its value will have been sign extended in // the conversion to int_type. Mask the sign extension bits for // compatibility with the other input adapters: return static_cast(*_it++); } void unget(int_type const c) throw() { if (_it == _first) return; if (_it == _last && c == traits::eof) return; --_it; } size_t characters_read() const throw() { return static_cast(_it - _first); } private: char_type const* _first; char_type const* _last; char_type const* _it; }; // Eats whitespace characters from an input adapter. When it returns, the next // call to get() on the input adapter will be either a non-whitespace character // or will be EOF. template