Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183//// ungetwc.cpp//// Copyright (c) Microsoft Corporation. All rights reserved.//// Defines ungetwc(), which pushes a wide character back into a stream.//#include <corecrt_internal_stdio.h>
// Pushes a character ("ungets" it) back into a stream. It is possible to push// back one character. It may not be possible to push back more than one// character in a row. Returns the pushed-back character on success; returns// WEOF on failure. Ungetting WEOF is expressly forbidden.extern "C" wint_t __cdecl ungetwc(wint_t const c, FILE* const stream){ _VALIDATE_RETURN(stream != nullptr, EINVAL, WEOF);
wint_t return_value = WEOF;
_lock_file(stream); __try { return_value = _ungetwc_nolock(c, stream); } __finally { _unlock_file(stream); } __endtry
return return_value;}
// Helper function for _ungetwc_nolock() that handles text mode ungetting.static wint_t __cdecl ungetwc_text_mode_nolock(wint_t const c, __crt_stdio_stream const stream) throw(){ // The stream is open in text mode, and we need to do the unget differently // depending on whether the stream is open in ANSI or Unicode mode. __crt_lowio_text_mode const text_mode = _textmode_safe(_fileno(stream.public_stream()));
int count = 0; char characters[MB_LEN_MAX] = { 0 };
// If the file is open in ANSI mode, we need to convert the wide character // to multibyte so that we can unget the multibyte character back into the // stream: if (text_mode == __crt_lowio_text_mode::ansi) { // If conversion fails, errno is set by wctomb_s and we can just return: if (wctomb_s(&count, characters, MB_LEN_MAX, c) != 0) return WEOF; } // Otherwise, the file is open in Unicode mode. This means the characters // in the stream were originally Unicode (and not multibyte). Hence, we // do not need to translate back to multibyte. This is true for both UTF-16 // and UTF-8, because the lowio read converts UTF-8 data to UTF-16. else { char const* c_bytes = reinterpret_cast<char const*>(&c); characters[0] = c_bytes[0]; characters[1] = c_bytes[1]; count = 2; }
// At this point, the file must be buffered, so we know the base is non-null. // First we need to ensure there is sufficient room in the buffer to store // the translated data: if (stream->_ptr < stream->_base + count) { if (stream->_cnt) return WEOF;
if (count > stream->_bufsiz) return WEOF;
stream->_ptr = count + stream->_base; }
for (int i = count - 1; i >= 0; --i) { *--stream->_ptr = characters[i]; }
stream->_cnt += count;
stream.unset_flags(_IOEOF); stream.set_flags(_IOREAD); return static_cast<wint_t>(0xffff & c);}
// Helper function for _ungetwc_nolock() that handles binary mode ungettingstatic wint_t __cdecl ungetwc_binary_mode_nolock(wint_t const c, __crt_stdio_stream const stream) throw(){ wchar_t const wide_c = static_cast<wchar_t>(c);
// At this point, the file must be buffered, so we know the base is non-null. // First, we need to ensure there is sufficient room in the buffer to store // the character: if (stream->_ptr < stream->_base + sizeof(wchar_t)) { // If we've already ungotten one character and it has not yet been read, // there may not be room for this unget. In this case, there's nothing // we can do so we simply fail: if (stream->_cnt) return WEOF;
if (sizeof(wchar_t) > stream->_bufsiz) return WEOF;
stream->_ptr = sizeof(wchar_t) + stream->_base; }
wchar_t*& wide_stream_ptr = reinterpret_cast<wchar_t*&>(stream->_ptr);
// If the stream is string-backed, we cannot modify the buffer. We retreat // the stream pointer and test if the character being ungotten is the same // as the character that was last read. If they are the same, then we allow // the unget (because we don't have to modify the buffer). If they are not // the same, then we re-advance the stream pointer and fail: if (stream.is_string_backed()) { if (*--wide_stream_ptr != wide_c) { ++wide_stream_ptr; return WEOF; } } // Otherwise, the stream is file-backed and open in binary mode, and we can // just write the character to the front of the stream: else { *--wide_stream_ptr = wide_c; }
stream->_cnt += sizeof(wchar_t);
stream.unset_flags(_IOEOF); stream.set_flags(_IOREAD);
return static_cast<wint_t>(wide_c);}
extern "C" wint_t __cdecl _ungetwc_nolock(wint_t const c, FILE* const public_stream){ __crt_stdio_stream const stream(public_stream);
// Ungetting WEOF is expressly forbidden: if (c == WEOF) return WEOF;
// To unget, the stream must currently be in read mode, _or_ it must be open // for update (read and write) and must not _currently_ be in write mode: bool const is_in_read_mode = stream.has_all_of(_IOREAD); bool const is_in_update_mode = stream.has_all_of(_IOUPDATE); bool const is_in_write_mode = stream.has_all_of(_IOWRITE);
if (!is_in_read_mode && !(is_in_update_mode && !is_in_write_mode)) return WEOF;
// If the stream is currently unbuffered, buffer it: if (stream->_base == nullptr) __acrt_stdio_allocate_buffer_nolock(stream.public_stream());
// If the stream is file-backed and is open in text mode, we need to perform // text mode translations: if (!stream.is_string_backed() && (_osfile_safe(_fileno(stream.public_stream())) & FTEXT) != 0) { return ungetwc_text_mode_nolock(c, stream); }
// Otherwise, the stream is string-backed or is a file-backed file open in // binary mode; we can simply push the character back into the stream: return ungetwc_binary_mode_nolock(c, stream);}