first commit
This commit is contained in:
997
extern/stdcxx/4.2.1/include/fstream.cc
vendored
Normal file
997
extern/stdcxx/4.2.1/include/fstream.cc
vendored
Normal file
@@ -0,0 +1,997 @@
|
||||
// -*- C++ -*-
|
||||
/***************************************************************************
|
||||
*
|
||||
* fstream.cc - Definition for the Standard Library file streams
|
||||
*
|
||||
* $Id: fstream.cc 637130 2008-03-14 15:16:33Z faridz $
|
||||
*
|
||||
***************************************************************************
|
||||
*
|
||||
* 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));
|
||||
|
||||
}
|
||||
|
||||
// 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));
|
||||
}
|
||||
|
||||
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
|
||||
Reference in New Issue
Block a user