include/fstream.cc (564 lines of code) (raw):

// -*- C++ -*- /*************************************************************************** * * fstream.cc - Definition for the Standard Library file streams * * $Id$ * *************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * Copyright 1997-2008 Rogue Wave Software, Inc. * **************************************************************************/ _RWSTD_NAMESPACE (std) { template<class _CharT, class _Traits> basic_filebuf<_CharT, _Traits>* basic_filebuf<_CharT, _Traits>:: open (const char *__name, ios_base::openmode __mode, long __prot) { _RWSTD_ASSERT (this->_C_is_valid ()); // fail if `mode' has invalid bits set or if the file is already open if ((__mode & ~_RWSTD_IOS_OPENMODE_MASK) || is_open ()) return 0; _C_file = _RW::__rw_fopen (__name, __mode, __prot); if (!_C_file) return 0; pos_type __pos = pos_type (); if (__mode & ios_base::ate) { // the end of a file is assumed to be in the initial shift state // this assumption is safe as long as the file has been properly // closed (or unshifted) after the last write operation on it __pos = _RW::__rw_fseek (_C_file, 0, 0, ios_base::end); if (-1L == __pos) { _RW::__rw_fclose (_C_file, 0); _C_file = 0; return 0; } } _C_beg_pos = _C_cur_pos = __pos; this->_C_state &= ~_RWSTD_IOS_OPENMODE_MASK; this->_C_state |= __mode; return this; } template<class _CharT, class _Traits> basic_filebuf<_CharT, _Traits>* basic_filebuf<_CharT, _Traits>:: close (bool __close_file /* = true */) { // close_file is false when close() is called from detach() _RWSTD_ASSERT (this->_C_is_valid ()); if (!is_open ()) return 0; // failure // close() returns this on success, 0 on failure basic_filebuf *__retval = this; _TRY { // avoid expensive call to overflow() unless necessary if (this->pptr () != this->pbase () && this->_C_is_eof (overflow ())) __retval = 0; // failure // write out any unshift sequence if necessary // (applies to multibyte, state dependent encodings only) if (__retval && this->_C_out_last () && !_C_unshift ()) __retval = 0; // failure } _CATCH (...) { // either overflow() or codecvt::unshift() threw if (__close_file) { _RW::__rw_fclose (_C_file, this->_C_state); // zero out the file pointer except when detaching fd _C_file = 0; _C_cur_pos = _C_beg_pos = pos_type (off_type (-1)); // reset input/output sequences to prevent any // subsequent I/O attempts on closed file this->setg (0, 0, 0); this->setp (0, 0); } // rethrow the caught exception _RETHROW; } if (__close_file) { if (_RW::__rw_fclose (_C_file, this->_C_state)) __retval = 0; // zero out the file pointer except when detaching fd _C_file = 0; _C_cur_pos = _C_beg_pos = pos_type (off_type (-1)); // reset input/output sequences to prevent any // subsequent I/O attempts on closed file this->setg (0, 0, 0); this->setp (0, 0); } return __retval; } template<class _CharT, class _Traits> streamsize basic_filebuf<_CharT, _Traits>:: showmanyc () { _RWSTD_ASSERT (this->_C_is_valid ()); if ( !this->_C_is_in () || !is_open () || _C_cur_pos == pos_type (off_type (-1))) return -1; // start with the number of chars in get area _RWSTD_STREAMSIZE __retval = this->egptr () - this->gptr (); // no prob if this fails for non-seekable devices const pos_type __end_pos = _RW::__rw_fseek (_C_file, this->_C_state, 0, ios_base::end); if (__end_pos != pos_type (off_type (-1))) { // restore position within file only if seek succeeded _RW::__rw_fseek (_C_file, this->_C_state, _C_cur_pos, ios_base::beg); typedef typename traits_type::state_type _StateT; typedef codecvt<char_type, char, _StateT> _Codecvt; const _Codecvt &__cvt = _USE_FACET (_Codecvt, this->getloc ()); if (__cvt.always_noconv ()) __retval += __end_pos - _C_cur_pos; else // make most pessimistic conversion estimate __retval += (__end_pos - _C_cur_pos) / __cvt.max_length (); } return __retval > 0 ? __retval : 0; } template<class _CharT, class _Traits> typename basic_filebuf<_CharT, _Traits>::int_type basic_filebuf<_CharT, _Traits>:: underflow () { _RWSTD_ASSERT (this->_C_is_valid ()); this->setp (0, 0); // invalidate put area this->_C_out_last (false); // needed by close () if (!this->_C_is_in () || !is_open()) return traits_type::eof (); char_type* const __to_end = this->_C_buffer + this->_C_bufsize; typedef typename traits_type::int_type _IntType; _IntType __ret = _IntType (); // fill the buffer if it's empty if (this->gptr () == this->egptr()) { // N.B.: gptr() could be null here // determine the maximum possible size of putback area (if any) // make sure putback area isn't too big - try to honor // _RWSTD_PBACK_SIZE if possible, otherwise shrink const _RWSTD_SIZE_T __pbackavail = this->_C_putback_avail (); _C_pbacksize = __pbackavail < _RWSTD_PBACK_SIZE ? __pbackavail : _RWSTD_PBACK_SIZE; _RWSTD_ASSERT (0 != this->_C_bufsize); if (_C_pbacksize == this->_C_bufsize) _C_pbacksize = this->_C_bufsize - 1; traits_type::move (this->eback(), this->gptr () - _C_pbacksize, _C_pbacksize); // fill the get area from the file, performing code conversion if // necessary _RWSTD_STREAMSIZE __nread = 0; // number of bytes read from file _C_beg_pos = _C_cur_pos; typedef typename traits_type::state_type _StateT; typedef codecvt<char_type, char, _StateT> _Codecvt; const _Codecvt &__cvt = _USE_FACET (_Codecvt, this->getloc ()); if (__cvt.always_noconv ()) { // no conversion required __nread = (__to_end - this->_C_buffer) - _C_pbacksize; __nread = _RW::__rw_fread (_C_file, this->_C_state, this->_C_buffer + _C_pbacksize, sizeof (char_type) * __nread); if (__nread < 0) return traits_type::eof (); // error while reading this->setg (this->_C_buffer, this->_C_buffer + _C_pbacksize, this->_C_buffer + _C_pbacksize + __nread); // adjust the current position in the file, // taking into account CR/LF conversion on windows __nread += _C_crlf_intern_count (this->gptr (), this->gptr () + __nread); } else { // conversion required char __xbuf [_RWSTD_DEFAULT_BUFSIZE]; char* __from_base = __xbuf; const char* __from_next = 0; char_type* __to_base = this->_C_buffer + _C_pbacksize; char_type* __to_next = __to_base; _StateT __state = _C_cur_pos.state (); codecvt_base::result __res = codecvt_base::ok; const ctype<char_type> &__ctp = _USE_FACET (ctype<char_type>, this->getloc ()); while (__to_next != __to_end && codecvt_base::error != __res) { // read only as many characters as we have positions left in // internal buffer - guarantees we won't read more characters // than we can put into the internal buffer after conversion // and ending file position isn't in the middle of a shift // sequence // N.B.: area between __xbuf and __from_base contains partially // converted sequences left from previous read _RWSTD_STREAMSIZE __n = __to_end - __to_next; if (_RWSTD_DEFAULT_BUFSIZE - (__from_base - __xbuf) < __n) __n = _RWSTD_DEFAULT_BUFSIZE - (__from_base - __xbuf); __n = _RW::__rw_fread (_C_file, this->_C_state, __from_base, __n); if (0 > __n) return traits_type::eof (); // error while reading if (0 == __n) break; // reached eof // take into account CR/LF conversion on Win32 __nread += __n + _C_crlf_extern_count (__from_base, __from_base + __n); // adjust 'n' to hold the number of external chars in buffer __n += __from_base - __xbuf; // convert any partially converted sequence from the previous // iteration (possibly empty) plus what we just read in __res = __cvt.in (__state, __xbuf, __xbuf + __n, __from_next, __to_base, __to_end, __to_next); switch (__res) { case codecvt_base::ok: // there may be yet unconverted elements at the end // of the source sequence, fall through and treat // as partial (`n' below may be 0) case codecvt_base::partial: // compute the length of partially converted sequence __n -= __from_next - __xbuf; typedef char_traits<char> CharTraits; // copy the sequence to beginning of xbuf CharTraits::move (__xbuf, __from_next, __n); // will append external chars to end of the sequence __from_base = __xbuf + __n; break; case codecvt_base::noconv: // note that according to lwg issue 19, codecvt<wchar_t, // char>::in() may not return noconv since internT and // externT are not the same type // since codecvt<char, char>::always_noconv() is required // to return true, this branch only executes for a user- // defined codecvt<T, T> facet with internT and externT // being the same type // FIXME: do not widen external buffer just memcpy it // to internal buffer (externT == internT) __ctp.widen (__xbuf, __xbuf + __n, __to_base); __to_next = __to_base + __n; break; case codecvt_base::error: // failed to convert part of the buffer // retain the part that has been successfully // converted, and disregard the rest __ret = traits_type::eof (); break; default: // bad return value from codecvt return traits_type::eof (); } __to_base = __to_next; // continue at end of converted seq } _C_cur_pos.state (__state); this->setg (this->_C_buffer, this->_C_buffer + _C_pbacksize, __to_next); } // end conversion block if (__nread == 0) return traits_type::eof (); _C_cur_pos += __nread; } return traits_type::eq_int_type (__ret, _IntType ()) ? traits_type::to_int_type (*this->gptr ()) : __ret; } template<class _CharT, class _Traits> typename basic_filebuf<_CharT, _Traits>::int_type basic_filebuf<_CharT, _Traits>:: overflow (int_type __c /* = eof () */) { _RWSTD_ASSERT (this->_C_is_valid ()); if (!this->_C_is_out () || !is_open ()) return traits_type::eof (); this->setg (0, 0, 0); // invalidate the get area const bool __unbuf = this->_C_is_unbuffered (); const char_type __c_to_char = traits_type::to_char_type (__c); if (this->pptr () == 0 && !__unbuf) { // put area not valid yet - just need to initialize it this->setp (this->_C_buffer, this->_C_buf_end ()); } else if ( this->pptr () == this->epptr () || this->_C_is_eof (__c) || __unbuf) { const char_type* __buf; _RWSTD_STREAMSIZE __nchars; if (__unbuf) { if (this->_C_is_eof (__c)){ __buf = 0; __nchars = 0; } else { __buf = &__c_to_char; __nchars = 1; } } else { // call xsputn() with a special value to have it flush // the controlled sequence to the file __buf = _RWSTD_REINTERPRET_CAST (char_type*, this); __nchars = this->pptr () - this->pbase (); } // typedef helps HP aCC 3.27 typedef basic_filebuf _FileBuf; if (__nchars != _FileBuf::xsputn (__buf, __nchars)) return traits_type::eof (); // error while writing } // now that there's room in the buffer, call sputc() recursively // to actually place the character in the buffer (unless we're // in unbuffered mode because we just wrote it out) if (!this->_C_is_eof (__c) && !__unbuf) this->sputc (__c_to_char); this->_C_out_last (true); // needed by close () return traits_type::not_eof (__c); } template <class _CharT, class _Traits> _RWSTD_STREAMSIZE basic_filebuf<_CharT, _Traits>:: xsputn (const char_type* __buf, _RWSTD_STREAMSIZE __nchars) { _RWSTD_ASSERT (0 != __buf || 0 == __nchars); _RWSTD_ASSERT (this->_C_is_valid ()); if (0 == __nchars) return 0; // not an error if (__nchars < 0 || !this->_C_is_out () || !is_open ()) return -1; // error if (0 == this->pptr () && !this->_C_is_unbuffered ()) // put area not valid yet - just need to initialize it this->setp (this->_C_buffer, this->_C_buf_end ()); const _RWSTD_STREAMSIZE __navail = this->epptr () - this->pptr (); const char_type* const __special = _RWSTD_REINTERPRET_CAST (char_type*, this); if (__buf == __special) { __buf = this->pbase (); } else if (__nchars <= __navail) { // the amount of available space is big enough // append the contents of the buffer to the controlled sequence traits_type::copy (this->pptr (), __buf, __nchars); this->pbump (__nchars); return __nchars; } else { // call self recursively to flush the controlled sequence first const _RWSTD_STREAMSIZE __nwrite = this->pptr () - this->pbase (); // typedef helps HP aCC 3.27 typedef basic_filebuf _FileBuf; // return -1 on error to flush the controlled sequence if (__nwrite != _FileBuf::xsputn (__special, __nwrite)) return -1; } // flush buffer to file, performing code conversion if necessary _RWSTD_ASSERT (this->_C_is_valid ()); _RWSTD_ASSERT (this->_C_is_out ()); _RWSTD_ASSERT (is_open ()); const char_type* const __end = __buf + __nchars; typedef typename traits_type::state_type _StateT; _RWSTD_STREAMSIZE __nwrote = 0; // num chars to write _StateT __state = _C_cur_pos.state (); // state of stream _C_beg_pos = _C_cur_pos; typedef codecvt<char_type, char, _StateT> _Codecvt; const _Codecvt &__cvt = _USE_FACET (_Codecvt, this->getloc ()); if (__cvt.always_noconv ()) { // no conversion __nwrote = __end - __buf; const _RWSTD_STREAMSIZE __nbytes = sizeof (char_type) * __nwrote; if (__nbytes != _RW::__rw_fwrite (_C_file, this->_C_state, __buf, __nbytes)) return -1; // error while writing } else { // perform codeset conversion in chunks to avoid dynamic // memory allocation char __xbuf [_RWSTD_DEFAULT_BUFSIZE]; char* __xbuf_end = __xbuf + sizeof __xbuf; char* __to_next = 0; const char_type* __from_next = 0; for (const char_type* __base = __buf; __from_next != __end; __base = __from_next) { // avoid using const codecvt_base::result here // to prevent HP aCC 3.27 errors const int __res = __cvt.out (__state, __base, __end, __from_next, __xbuf, __xbuf_end, __to_next); _RWSTD_STREAMSIZE __nbytes = sizeof (char_type) * (__end - __base); switch (__res) { case codecvt_base::error: // write out the sequence successfully converted up // to the point of the error in the internal sequence // and fail _RW::__rw_fwrite (_C_file, this->_C_state, __base, __nbytes); return traits_type::eof (); case codecvt_base::noconv: // write the entire sequence if (__nbytes != _RW::__rw_fwrite (_C_file, this->_C_state, __base, __nbytes)) return traits_type::eof (); __nwrote += __end - __base + _C_crlf_intern_count (__base, __end); __from_next = __end; // effectively 'break' break; default: _RWSTD_ASSERT ( codecvt_base::ok == __res || codecvt_base::partial == __res); // partial conversion will result if there isn't enough // space in the conversion buffer to hold the converted // sequence, but we're O.K. since we'll be passing any // remaining unconverted characters (starting at // __from_next) in the next iteration __nbytes = __to_next - __xbuf; if (__nbytes != _RW::__rw_fwrite (_C_file, this->_C_state, __xbuf, __nbytes)) return -1; __nwrote += __nbytes + _C_crlf_extern_count (__xbuf, __to_next); } } } // adjust the current position in the file _C_cur_pos += __nwrote; _C_cur_pos.state (__state); // reset the put area if (!this->_C_is_unbuffered ()) this->setp (this->_C_buffer, this->_C_buf_end ()); this->_C_out_last (true); // needed by close () // return the number of characters (not bytes) in the buffer // successfully written to the file return __nchars; } template<class _CharT, class _Traits> typename basic_filebuf<_CharT, _Traits>::int_type basic_filebuf<_CharT, _Traits>:: pbackfail (int_type __c) { _RWSTD_ASSERT (this->_C_is_valid ()); if (!is_open ()) return traits_type::eof (); // we could get here if gptr = eback or if __c != *(gptr-1) if (!this->_C_putback_avail ()) { // try to make a putback area available if (this->seekoff (-1, ios_base::cur) == pos_type (off_type (-1))) return traits_type::eof (); if (this->_C_is_eof (underflow ())) return traits_type::eof (); this->gbump (1); } if (traits_type::eq (traits_type::to_char_type (__c), *(this->gptr () - 1)) || this->_C_is_eof (__c)) { // "put back" original value this->gbump (-1); return traits_type::not_eof (__c); } else if (this->_C_is_out ()) { // overwrite existing value with new value this->gbump (-1); *this->gptr () = traits_type::to_char_type (__c); return __c; } else return traits_type::eof (); } template<class _CharT, class _Traits> basic_streambuf<_CharT, _Traits>* basic_filebuf<_CharT, _Traits>:: setbuf (char_type *__buf, streamsize __ssize) { _RWSTD_ASSERT (this->_C_is_valid ()); if (__ssize < 0) return 0; const _RWSTD_SIZE_T __bufsize = _RWSTD_STATIC_CAST (_RWSTD_SIZE_T, __ssize); // sync the buffer to the external file so it can be deallocated if ((this->gptr () || this->pptr ()) && is_open () && sync () != 0) return 0; bool __reset = true; if (0 < __bufsize) { if (!__buf && (this->_C_bufsize < __bufsize || !this->_C_buffer)) { // if `buf' is 0 and the requested size is greater than // the size of the object's buffer, or of the object's // buffer is 0, try to allocate a new buffer of the // specified size __buf = new char_type [__bufsize]; // delete old buffer if the object owns it if (this->_C_own_buf ()) delete [] this->_C_buffer; // take ownership of the newly allocated buffer this->_C_own_buf (true); } else if (!__buf && __bufsize <= this->_C_bufsize) { // if `buf' is 0 and the requested size is less than // the size of the object's buffer, simply reuse the // object's buffer __buf = this->_C_buffer; __reset = false; } else if (__buf && __buf != this->_C_buffer) { // if `buf' is non-0 and different from the existing // buffer, use it // delete old buffer if the object owns it if (this->_C_own_buf ()) delete [] this->_C_buffer; // the object does not own of the new buffer this->_C_own_buf (false); } this->_C_buffer = __buf; this->_C_bufsize = __bufsize; this->_C_set_unbuffered (false); } else { // unbuffer this stream object // character buffer is preserved (used as get area only), // streambuf object unbuffered for writing // to put a streambuf object into an unbuffered mode (see 27.8.1.4, // p10) and affect the size of the get area, setbuf() should first // be called with the desired (non-zero) size and then again with // both arguments being 0 this->_C_set_unbuffered (true); } if (__reset) { this->setg (0, 0, 0); this->setp (0, 0); } // a character buffer of nonzero size must exist even in unbuffered mode _RWSTD_ASSERT (0 != this->_C_buffer); _RWSTD_ASSERT (0 != this->_C_bufsize); return this; } // 27.8.1.4, p 11 template<class _CharT, class _Traits> typename basic_filebuf<_CharT, _Traits>::pos_type basic_filebuf<_CharT, _Traits>:: seekoff (off_type __off, ios_base::seekdir __way, ios_base::openmode) { _RWSTD_ASSERT (this->_C_is_valid ()); if (!is_open ()) return pos_type (off_type (-1)); typedef typename traits_type::state_type _StateT; typedef codecvt<char_type, char, _StateT> _Codecvt; const int __width = _USE_FACET (_Codecvt, this->getloc ()).encoding (); // offset must be zero with state-dependent encoding if (0 != __off && __width <= 0) return pos_type (off_type (-1)); // sync the buffer... (this also invalidates the get/put area) if (sync () != 0) return pos_type (off_type (-1)); // ...and, if last operation was output, append an unshift sequence if (this->_C_out_last ()) _C_unshift (); if (__width > 1) __off *= __width; // perform the seek and save the result pos_type __pos = _RW::__rw_fseek (_C_file, this->_C_state, __off, __way); if (__pos != pos_type (off_type (-1))) { // preserve the current state if not changing position // (only matters for state-dependent encodings for which // the offset is required and guaranteed to be 0) if (__way == ios_base::cur) __pos.state (_C_cur_pos.state ()); _C_beg_pos = _C_cur_pos = __pos; } this->_C_out_last (false); // needed by close() return __pos; } template<class _CharT, class _Traits> typename basic_filebuf<_CharT, _Traits>::pos_type basic_filebuf<_CharT, _Traits>:: seekpos (pos_type __pos, ios_base::openmode) { _RWSTD_ASSERT (this->_C_is_valid ()); if (!is_open ()) return pos_type (off_type (-1)); // flush the output area if it exists if (this->pptr () != 0) { if (this->_C_is_eof (this->overflow (traits_type::eof ()))) return pos_type (off_type (-1)); } if ( _RW::__rw_fseek (_C_file, this->_C_state, __pos, ios_base::beg) == pos_type (off_type (-1))) return pos_type (off_type (-1)); _C_cur_pos = _C_beg_pos = __pos; this->setg (0, 0, 0); this->setp (0, 0); this->_C_out_last (false); // needed by close() return __pos; } template<class _CharT, class _Traits> int basic_filebuf<_CharT, _Traits>:: sync () { _RWSTD_ASSERT (this->_C_is_valid ()); // put area active if (this->pptr () != 0) { // flush the buffer to the file if (this->_C_is_eof (overflow (traits_type::eof ()))) return -1; if (this->_C_state & _RWSTD_IOS_STDIO) _RW::__rw_fflush (_C_file, this->_C_state); } // get area active if (this->gptr () != 0) { // pbacksize may need to be adjusted if it's greater than // the available putback area (e.g., after calling putback() // at the end of the buffer) const _RWSTD_SIZE_T __pbackavail = this->_C_putback_avail (); if (__pbackavail < _C_pbacksize) _C_pbacksize = __pbackavail; _RWSTD_ASSERT (0 != this->_C_bufsize); if (_C_pbacksize == this->_C_bufsize) _C_pbacksize = this->_C_bufsize - 1; typedef typename traits_type::state_type _StateT; typedef codecvt<char_type, char, _StateT> _Codecvt; const _Codecvt &__cvt = _USE_FACET (_Codecvt, this->getloc ()); int __width = __cvt.encoding (); if (__width > 0) { // get the number of chars consumed in the buffer const off_type __consumed = this->gptr () - this->eback () - _C_pbacksize; // constant width conversion: // adjust the current position/state in the file, // taking into account CR/LF conversion on Win32 _C_cur_pos = _C_beg_pos; _C_cur_pos += (__width * __consumed) + _C_crlf_intern_count (this->eback () + _C_pbacksize, this->gptr()); } else { // This gets a bit tricky here because we don't know the external // file position corresponding to the position in the // internal buffer. To figure this out, we'll use the known // file position/state corresponding to the start of the buffer // (which we have carefully saved in _C_beg_pos) and // convert the characters up to the current position in the // buffer, counting how many external chars result. We can // then use the offset from _C_beg_pos and the state // returned from codecvt::out() to construct the current file // position off_type __ext_chars = 0; // converted external chars char __xbuf [_RWSTD_DEFAULT_BUFSIZE]; char* __xbuf_end = __xbuf + sizeof __xbuf; char* __to_next = 0; const char_type* __from_next = 0; const char_type* __from_end = this->gptr (); _StateT __state = _C_beg_pos.state (); const char_type* __base = this->eback () + _C_pbacksize; while (__from_next != __from_end) { const int __res = __cvt.out (__state, __base, __from_end, __from_next, __xbuf, __xbuf_end, __to_next); switch (__res) { case codecvt_base::error: return -1; case codecvt_base::noconv: __ext_chars += __from_end - __base + _C_crlf_intern_count (__base, __from_end); __from_next = __from_end; // break out of the loop break; default: // __res = ok or partial // take into account CR/LF conversion on Win32 __ext_chars += __to_next - __xbuf + _C_crlf_extern_count (__xbuf, __to_next); } // repeat with next chunk __base = __from_next; } _C_cur_pos = _C_beg_pos; _C_cur_pos += __ext_chars; _C_cur_pos.state (__state); } // seek within the external file to the position // corresponding to the future beginning of the buffer const off_type __off = _RW::__rw_fseek (_C_file, this->_C_state, _C_cur_pos, ios_base::beg); if (-1L == __off) return -1; traits_type::move (this->eback (), this->gptr () - _C_pbacksize, _C_pbacksize); this->setg (this->eback (), this->eback () + _C_pbacksize, this->eback () + _C_pbacksize); } _C_beg_pos = _C_cur_pos; this->setp (0, 0); return 0; } template<class _CharT, class _Traits> basic_filebuf<_CharT, _Traits>* basic_filebuf<_CharT, _Traits>:: _C_open (int __fd, void *__file, char_type *__buf, streamsize __n) { if (is_open () || !__file && -1 == __fd || !setbuf (__buf, __n)) return 0; if (__file) { _RWSTD_ASSERT (-1 == __fd); _C_file = __file; this->_C_state |= this->_C_stdio; } else { _RWSTD_ASSERT (!__file); _C_file = _RW::__rw_fdopen (__fd); if (!_C_file) return 0; this->_C_state &= ~this->_C_stdio; } this->_C_state |= _RW::__rw_fmode (_C_file, this->_C_state); this->setg (0, 0, 0); this->setp (0, 0); _C_cur_pos = _C_beg_pos = pos_type (); return this; } // write out an unshift sequence if not in initial shift state template<class _CharT, class _Traits> bool basic_filebuf<_CharT, _Traits>:: _C_unshift () { typedef typename traits_type::state_type _StateT; typedef codecvt<char_type, char, _StateT> _Codecvt; const _Codecvt &__cvt = _USE_FACET (_Codecvt, this->getloc ()); // unshifting isn't necessary if encoding isn't state dependent // or if the state is equivalent to initial state (determined // by codecvt::unshift()) if (__cvt.encoding () >= 0) return true; // buf to hold unshift sequence - assumes that the shift // sequence will be less than 64 chars (we can't safely // use dynamic allocation because this function could be // called as a result of memory allocation exception) char __useq [64]; char* __useq_end = 0; _StateT __state = _C_cur_pos.state (); const int __res = __cvt.unshift (__state, __useq, __useq + sizeof __useq, __useq_end); const _RWSTD_STREAMSIZE __nbytes = __useq_end - __useq; // in the unlikely event that the buffer isn't big enough, assert _RWSTD_ASSERT (__res != codecvt_base::partial); if (__res == codecvt_base::error) return false; if (__res == codecvt_base::noconv) return true; const off_type __nwrote = _RW::__rw_fwrite (_C_file, this->_C_state, __useq, __nbytes); if (__nwrote < 0) return false; _C_cur_pos += __nwrote; // CR/LF conversion not an issue here return __nwrote == __nbytes; } } // namespace std