📄 fstream.tcc
字号:
// File based streams -*- C++ -*-// Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004// Free Software Foundation, Inc.//// This file is part of the GNU ISO C++ Library. This library is free// software; you can redistribute it and/or modify it under the// terms of the GNU General Public License as published by the// Free Software Foundation; either version 2, or (at your option)// any later version.// This library is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.// You should have received a copy of the GNU General Public License along// with this library; see the file COPYING. If not, write to the Free// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,// USA.// As a special exception, you may use this file as part of a free software// library without restriction. Specifically, if other files instantiate// templates or use macros or inline functions from this file, or you compile// this file and link it with other files to produce an executable, this// file does not by itself cause the resulting executable to be covered by// the GNU General Public License. This exception does not however// invalidate any other reasons why the executable file might be covered by// the GNU General Public License.//// ISO C++ 14882: 27.8 File-based streams//#ifndef _FSTREAM_TCC#define _FSTREAM_TCC 1#pragma GCC system_headernamespace std{ template<typename _CharT, typename _Traits> void basic_filebuf<_CharT, _Traits>:: _M_allocate_internal_buffer() { // Allocate internal buffer only if one doesn't already exist // (either allocated or provided by the user via setbuf). if (!_M_buf_allocated && !this->_M_buf) { this->_M_buf = new char_type[this->_M_buf_size]; _M_buf_allocated = true; } } template<typename _CharT, typename _Traits> void basic_filebuf<_CharT, _Traits>:: _M_destroy_internal_buffer() throw() { if (_M_buf_allocated) { delete [] this->_M_buf; this->_M_buf = NULL; _M_buf_allocated = false; } delete [] _M_ext_buf; _M_ext_buf = NULL; _M_ext_buf_size = 0; _M_ext_next = NULL; _M_ext_end = NULL; } template<typename _CharT, typename _Traits> basic_filebuf<_CharT, _Traits>:: basic_filebuf() : __streambuf_type(), _M_lock(), _M_file(&_M_lock), _M_mode(ios_base::openmode(0)), _M_state_beg(), _M_state_cur(), _M_state_last(), _M_buf(NULL), _M_buf_size(BUFSIZ), _M_buf_allocated(false), _M_reading(false), _M_writing(false), _M_pback(), _M_pback_cur_save(0), _M_pback_end_save(0), _M_pback_init(false), _M_codecvt(0), _M_ext_buf(0), _M_ext_buf_size(0), _M_ext_next(0), _M_ext_end(0) { if (has_facet<__codecvt_type>(this->_M_buf_locale)) _M_codecvt = &use_facet<__codecvt_type>(this->_M_buf_locale); } template<typename _CharT, typename _Traits> typename basic_filebuf<_CharT, _Traits>::__filebuf_type* basic_filebuf<_CharT, _Traits>:: open(const char* __s, ios_base::openmode __mode) { __filebuf_type *__ret = NULL; if (!this->is_open()) { _M_file.open(__s, __mode); if (this->is_open()) { _M_allocate_internal_buffer(); this->_M_mode = __mode; // Setup initial buffer to 'uncommitted' mode. _M_reading = false; _M_writing = false; _M_set_buffer(-1); // Reset to initial state. _M_state_last = _M_state_cur = _M_state_beg; // 27.8.1.3,4 if ((__mode & ios_base::ate) && this->seekoff(0, ios_base::end, __mode) == pos_type(off_type(-1))) this->close(); else __ret = this; } } return __ret; } template<typename _CharT, typename _Traits> typename basic_filebuf<_CharT, _Traits>::__filebuf_type* basic_filebuf<_CharT, _Traits>:: close() throw() { __filebuf_type* __ret = NULL; if (this->is_open()) { bool __testfail = false; try { if (!_M_terminate_output()) __testfail = true; } catch(...) { __testfail = true; } // NB: Do this here so that re-opened filebufs will be cool... this->_M_mode = ios_base::openmode(0); this->_M_pback_init = false; _M_destroy_internal_buffer(); _M_reading = false; _M_writing = false; _M_set_buffer(-1); _M_state_last = _M_state_cur = _M_state_beg; if (!_M_file.close()) __testfail = true; if (!__testfail) __ret = this; } return __ret; } template<typename _CharT, typename _Traits> streamsize basic_filebuf<_CharT, _Traits>:: showmanyc() { streamsize __ret = -1; const bool __testin = this->_M_mode & ios_base::in; if (__testin && this->is_open()) { // For a stateful encoding (-1) the pending sequence might be just // shift and unshift prefixes with no actual character. __ret = this->egptr() - this->gptr(); if (__check_facet(_M_codecvt).encoding() >= 0) __ret += _M_file.showmanyc() / _M_codecvt->max_length(); } return __ret; } template<typename _CharT, typename _Traits> typename basic_filebuf<_CharT, _Traits>::int_type basic_filebuf<_CharT, _Traits>:: underflow() { int_type __ret = traits_type::eof(); const bool __testin = this->_M_mode & ios_base::in; if (__testin && !_M_writing) { // Check for pback madness, and if so swich back to the // normal buffers and jet outta here before expensive // fileops happen... _M_destroy_pback(); if (this->gptr() < this->egptr()) return traits_type::to_int_type(*this->gptr()); // Get and convert input sequence. const size_t __buflen = this->_M_buf_size > 1 ? this->_M_buf_size - 1 : 1; // Will be set to true if ::read() returns 0 indicating EOF. bool __got_eof = false; // Number of internal characters produced. streamsize __ilen = 0; codecvt_base::result __r = codecvt_base::ok; if (__check_facet(_M_codecvt).always_noconv()) { __ilen = _M_file.xsgetn(reinterpret_cast<char*>(this->eback()), __buflen); if (__ilen == 0) __got_eof = true; } else { // Worst-case number of external bytes. // XXX Not done encoding() == -1. const int __enc = _M_codecvt->encoding(); streamsize __blen; // Minimum buffer size. streamsize __rlen; // Number of chars to read. if (__enc > 0) __blen = __rlen = __buflen * __enc; else { __blen = __buflen + _M_codecvt->max_length() - 1; __rlen = __buflen; } const streamsize __remainder = _M_ext_end - _M_ext_next; __rlen = __rlen > __remainder ? __rlen - __remainder : 0; // An imbue in 'read' mode implies first converting the external // chars already present. if (_M_reading && this->egptr() == this->eback() && __remainder) __rlen = 0; // Allocate buffer if necessary and move unconverted // bytes to front. if (_M_ext_buf_size < __blen) { char* __buf = new char[__blen]; if (__remainder) std::memcpy(__buf, _M_ext_next, __remainder); delete [] _M_ext_buf; _M_ext_buf = __buf; _M_ext_buf_size = __blen; } else if (__remainder) std::memmove(_M_ext_buf, _M_ext_next, __remainder); _M_ext_next = _M_ext_buf; _M_ext_end = _M_ext_buf + __remainder; _M_state_last = _M_state_cur; do { if (__rlen > 0) { // Sanity check! // This may fail if the return value of // codecvt::max_length() is bogus. if (_M_ext_end - _M_ext_buf + __rlen > _M_ext_buf_size) { __throw_ios_failure(__N("basic_filebuf::underflow " "codecvt::max_length() " "is not valid")); } streamsize __elen = _M_file.xsgetn(_M_ext_end, __rlen); if (__elen == 0) __got_eof = true; else if (__elen == -1) break; _M_ext_end += __elen; } char_type* __iend; __r = _M_codecvt->in(_M_state_cur, _M_ext_next, _M_ext_end, _M_ext_next, this->eback(), this->eback() + __buflen, __iend); if (__r == codecvt_base::noconv) { size_t __avail = _M_ext_end - _M_ext_buf; __ilen = std::min(__avail, __buflen); traits_type::copy(this->eback(), reinterpret_cast<char_type*>(_M_ext_buf), __ilen); _M_ext_next = _M_ext_buf + __ilen; } else __ilen = __iend - this->eback(); // _M_codecvt->in may return error while __ilen > 0: this is // ok, and actually occurs in case of mixed encodings (e.g., // XML files). if (__r == codecvt_base::error) break; __rlen = 1; } while (__ilen == 0 && !__got_eof); } if (__ilen > 0) { _M_set_buffer(__ilen); _M_reading = true; __ret = traits_type::to_int_type(*this->gptr()); } else if (__got_eof) { // If the actual end of file is reached, set 'uncommitted' // mode, thus allowing an immediate write without an // intervening seek. _M_set_buffer(-1); _M_reading = false; // However, reaching it while looping on partial means that // the file has got an incomplete character. if (__r == codecvt_base::partial) __throw_ios_failure(__N("basic_filebuf::underflow " "incomplete character in file")); } else if (__r == codecvt_base::error) __throw_ios_failure(__N("basic_filebuf::underflow " "invalid byte sequence in file")); else __throw_ios_failure(__N("basic_filebuf::underflow " "error reading the file")); } return __ret; } template<typename _CharT, typename _Traits> typename basic_filebuf<_CharT, _Traits>::int_type basic_filebuf<_CharT, _Traits>:: pbackfail(int_type __i) { int_type __ret = traits_type::eof(); const bool __testin = this->_M_mode & ios_base::in; if (__testin && !_M_writing) { // Remember whether the pback buffer is active, otherwise below // we may try to store in it a second char (libstdc++/9761). const bool __testpb = this->_M_pback_init; const bool __testeof = traits_type::eq_int_type(__i, __ret); int_type __tmp; if (this->eback() < this->gptr()) { this->gbump(-1); __tmp = traits_type::to_int_type(*this->gptr()); } else if (this->seekoff(-1, ios_base::cur) != pos_type(off_type(-1))) { __tmp = this->underflow(); if (traits_type::eq_int_type(__tmp, __ret)) return __ret; } else { // At the beginning of the buffer, need to make a // putback position available. But the seek may fail // (f.i., at the beginning of a file, see // libstdc++/9439) and in that case we return // traits_type::eof(). return __ret; } // Try to put back __i into input sequence in one of three ways. // Order these tests done in is unspecified by the standard. if (!__testeof && traits_type::eq_int_type(__i, __tmp)) __ret = __i; else if (__testeof) __ret = traits_type::not_eof(__i); else if (!__testpb) { _M_create_pback(); _M_reading = true; *this->gptr() = traits_type::to_char_type(__i); __ret = __i; } } return __ret; } template<typename _CharT, typename _Traits> typename basic_filebuf<_CharT, _Traits>::int_type basic_filebuf<_CharT, _Traits>:: overflow(int_type __c) { int_type __ret = traits_type::eof(); const bool __testeof = traits_type::eq_int_type(__c, __ret); const bool __testout = this->_M_mode & ios_base::out; if (__testout && !_M_reading) { if (this->pbase() < this->pptr()) { // If appropriate, append the overflow char. if (!__testeof) { *this->pptr() = traits_type::to_char_type(__c); this->pbump(1); } // Convert pending sequence to external representation, // and output. if (_M_convert_to_external(this->pbase(), this->pptr() - this->pbase())) { _M_set_buffer(0); __ret = traits_type::not_eof(__c); } } else if (this->_M_buf_size > 1) { // Overflow in 'uncommitted' mode: set _M_writing, set // the buffer to the initial 'write' mode, and put __c // into the buffer. _M_set_buffer(0); _M_writing = true; if (!__testeof) { *this->pptr() = traits_type::to_char_type(__c); this->pbump(1); } __ret = traits_type::not_eof(__c); } else { // Unbuffered. char_type __conv = traits_type::to_char_type(__c); if (__testeof || _M_convert_to_external(&__conv, 1)) { _M_writing = true; __ret = traits_type::not_eof(__c); } } } return __ret; } template<typename _CharT, typename _Traits> bool basic_filebuf<_CharT, _Traits>:: _M_convert_to_external(_CharT* __ibuf, streamsize __ilen) { // Sizes of external and pending output. streamsize __elen;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -