197403Sobrien// File based streams -*- C++ -*- 297403Sobrien 3169691Skan// Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 497403Sobrien// Free Software Foundation, Inc. 597403Sobrien// 697403Sobrien// This file is part of the GNU ISO C++ Library. This library is free 797403Sobrien// software; you can redistribute it and/or modify it under the 897403Sobrien// terms of the GNU General Public License as published by the 997403Sobrien// Free Software Foundation; either version 2, or (at your option) 1097403Sobrien// any later version. 1197403Sobrien 1297403Sobrien// This library is distributed in the hope that it will be useful, 1397403Sobrien// but WITHOUT ANY WARRANTY; without even the implied warranty of 1497403Sobrien// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1597403Sobrien// GNU General Public License for more details. 1697403Sobrien 1797403Sobrien// You should have received a copy of the GNU General Public License along 1897403Sobrien// with this library; see the file COPYING. If not, write to the Free 19169691Skan// Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 2097403Sobrien// USA. 2197403Sobrien 2297403Sobrien// As a special exception, you may use this file as part of a free software 2397403Sobrien// library without restriction. Specifically, if other files instantiate 2497403Sobrien// templates or use macros or inline functions from this file, or you compile 2597403Sobrien// this file and link it with other files to produce an executable, this 2697403Sobrien// file does not by itself cause the resulting executable to be covered by 2797403Sobrien// the GNU General Public License. This exception does not however 2897403Sobrien// invalidate any other reasons why the executable file might be covered by 2997403Sobrien// the GNU General Public License. 3097403Sobrien 31169691Skan/** @file fstream.tcc 32169691Skan * This is an internal header file, included by other library headers. 33169691Skan * You should not attempt to use it directly. 34169691Skan */ 35169691Skan 3697403Sobrien// 3797403Sobrien// ISO C++ 14882: 27.8 File-based streams 3897403Sobrien// 3997403Sobrien 40132720Skan#ifndef _FSTREAM_TCC 41132720Skan#define _FSTREAM_TCC 1 4297403Sobrien 4397403Sobrien#pragma GCC system_header 4497403Sobrien 45169691Skan_GLIBCXX_BEGIN_NAMESPACE(std) 46169691Skan 4797403Sobrien template<typename _CharT, typename _Traits> 4897403Sobrien void 4997403Sobrien basic_filebuf<_CharT, _Traits>:: 5097403Sobrien _M_allocate_internal_buffer() 5197403Sobrien { 52132720Skan // Allocate internal buffer only if one doesn't already exist 53132720Skan // (either allocated or provided by the user via setbuf). 54169691Skan if (!_M_buf_allocated && !_M_buf) 5597403Sobrien { 56169691Skan _M_buf = new char_type[_M_buf_size]; 5797403Sobrien _M_buf_allocated = true; 5897403Sobrien } 5997403Sobrien } 6097403Sobrien 6197403Sobrien template<typename _CharT, typename _Traits> 6297403Sobrien void 6397403Sobrien basic_filebuf<_CharT, _Traits>:: 64117397Skan _M_destroy_internal_buffer() throw() 6597403Sobrien { 6697403Sobrien if (_M_buf_allocated) 6797403Sobrien { 68169691Skan delete [] _M_buf; 69169691Skan _M_buf = NULL; 7097403Sobrien _M_buf_allocated = false; 7197403Sobrien } 72132720Skan delete [] _M_ext_buf; 73132720Skan _M_ext_buf = NULL; 74132720Skan _M_ext_buf_size = 0; 75132720Skan _M_ext_next = NULL; 76132720Skan _M_ext_end = NULL; 7797403Sobrien } 7897403Sobrien 7997403Sobrien template<typename _CharT, typename _Traits> 8097403Sobrien basic_filebuf<_CharT, _Traits>:: 81132720Skan basic_filebuf() : __streambuf_type(), _M_lock(), _M_file(&_M_lock), 82132720Skan _M_mode(ios_base::openmode(0)), _M_state_beg(), _M_state_cur(), 83132720Skan _M_state_last(), _M_buf(NULL), _M_buf_size(BUFSIZ), 84132720Skan _M_buf_allocated(false), _M_reading(false), _M_writing(false), _M_pback(), 85132720Skan _M_pback_cur_save(0), _M_pback_end_save(0), _M_pback_init(false), 86132720Skan _M_codecvt(0), _M_ext_buf(0), _M_ext_buf_size(0), _M_ext_next(0), 87132720Skan _M_ext_end(0) 88132720Skan { 89132720Skan if (has_facet<__codecvt_type>(this->_M_buf_locale)) 90132720Skan _M_codecvt = &use_facet<__codecvt_type>(this->_M_buf_locale); 91132720Skan } 9297403Sobrien 9397403Sobrien template<typename _CharT, typename _Traits> 94132720Skan typename basic_filebuf<_CharT, _Traits>::__filebuf_type* 9597403Sobrien basic_filebuf<_CharT, _Traits>:: 9697403Sobrien open(const char* __s, ios_base::openmode __mode) 9797403Sobrien { 9897403Sobrien __filebuf_type *__ret = NULL; 9997403Sobrien if (!this->is_open()) 10097403Sobrien { 10197403Sobrien _M_file.open(__s, __mode); 10297403Sobrien if (this->is_open()) 10397403Sobrien { 10497403Sobrien _M_allocate_internal_buffer(); 105169691Skan _M_mode = __mode; 106117397Skan 107132720Skan // Setup initial buffer to 'uncommitted' mode. 108132720Skan _M_reading = false; 109132720Skan _M_writing = false; 110132720Skan _M_set_buffer(-1); 111102782Skan 112132720Skan // Reset to initial state. 113132720Skan _M_state_last = _M_state_cur = _M_state_beg; 114132720Skan 115132720Skan // 27.8.1.3,4 11697403Sobrien if ((__mode & ios_base::ate) 117132720Skan && this->seekoff(0, ios_base::end, __mode) 118132720Skan == pos_type(off_type(-1))) 119132720Skan this->close(); 120132720Skan else 121132720Skan __ret = this; 12297403Sobrien } 12397403Sobrien } 12497403Sobrien return __ret; 12597403Sobrien } 12697403Sobrien 12797403Sobrien template<typename _CharT, typename _Traits> 128132720Skan typename basic_filebuf<_CharT, _Traits>::__filebuf_type* 12997403Sobrien basic_filebuf<_CharT, _Traits>:: 130117397Skan close() throw() 13197403Sobrien { 132117397Skan __filebuf_type* __ret = NULL; 13397403Sobrien if (this->is_open()) 13497403Sobrien { 135117397Skan bool __testfail = false; 136117397Skan try 137117397Skan { 138132720Skan if (!_M_terminate_output()) 139117397Skan __testfail = true; 140117397Skan } 141117397Skan catch(...) 142132720Skan { __testfail = true; } 14397403Sobrien 14497403Sobrien // NB: Do this here so that re-opened filebufs will be cool... 145169691Skan _M_mode = ios_base::openmode(0); 146169691Skan _M_pback_init = false; 14797403Sobrien _M_destroy_internal_buffer(); 148132720Skan _M_reading = false; 149132720Skan _M_writing = false; 150132720Skan _M_set_buffer(-1); 151132720Skan _M_state_last = _M_state_cur = _M_state_beg; 15297403Sobrien 153117397Skan if (!_M_file.close()) 154117397Skan __testfail = true; 155117397Skan 156117397Skan if (!__testfail) 15797403Sobrien __ret = this; 15897403Sobrien } 15997403Sobrien return __ret; 16097403Sobrien } 16197403Sobrien 16297403Sobrien template<typename _CharT, typename _Traits> 163132720Skan streamsize 16497403Sobrien basic_filebuf<_CharT, _Traits>:: 16597403Sobrien showmanyc() 16697403Sobrien { 16797403Sobrien streamsize __ret = -1; 168169691Skan const bool __testin = _M_mode & ios_base::in; 16997403Sobrien if (__testin && this->is_open()) 170117397Skan { 171132720Skan // For a stateful encoding (-1) the pending sequence might be just 172132720Skan // shift and unshift prefixes with no actual character. 173132720Skan __ret = this->egptr() - this->gptr(); 174169691Skan 175169691Skan#if _GLIBCXX_HAVE_DOS_BASED_FILESYSTEM 176169691Skan // About this workaround, see libstdc++/20806. 177169691Skan const bool __testbinary = _M_mode & ios_base::binary; 178169691Skan if (__check_facet(_M_codecvt).encoding() >= 0 179169691Skan && __testbinary) 180169691Skan#else 181132720Skan if (__check_facet(_M_codecvt).encoding() >= 0) 182169691Skan#endif 183132720Skan __ret += _M_file.showmanyc() / _M_codecvt->max_length(); 184117397Skan } 18597403Sobrien return __ret; 18697403Sobrien } 187132720Skan 18897403Sobrien template<typename _CharT, typename _Traits> 189132720Skan typename basic_filebuf<_CharT, _Traits>::int_type 19097403Sobrien basic_filebuf<_CharT, _Traits>:: 191132720Skan underflow() 19297403Sobrien { 19397403Sobrien int_type __ret = traits_type::eof(); 194169691Skan const bool __testin = _M_mode & ios_base::in; 195132720Skan if (__testin && !_M_writing) 19697403Sobrien { 197228780Spfg // Check for pback madness, and if so switch back to the 198132720Skan // normal buffers and jet outta here before expensive 199132720Skan // fileops happen... 200132720Skan _M_destroy_pback(); 20197403Sobrien 202132720Skan if (this->gptr() < this->egptr()) 203132720Skan return traits_type::to_int_type(*this->gptr()); 204132720Skan 205132720Skan // Get and convert input sequence. 206169691Skan const size_t __buflen = _M_buf_size > 1 ? _M_buf_size - 1 : 1; 207132720Skan 208132720Skan // Will be set to true if ::read() returns 0 indicating EOF. 209132720Skan bool __got_eof = false; 210132720Skan // Number of internal characters produced. 211132720Skan streamsize __ilen = 0; 212132720Skan codecvt_base::result __r = codecvt_base::ok; 213132720Skan if (__check_facet(_M_codecvt).always_noconv()) 21497403Sobrien { 215132720Skan __ilen = _M_file.xsgetn(reinterpret_cast<char*>(this->eback()), 216132720Skan __buflen); 217132720Skan if (__ilen == 0) 218132720Skan __got_eof = true; 219132720Skan } 220132720Skan else 221132720Skan { 222132720Skan // Worst-case number of external bytes. 223132720Skan // XXX Not done encoding() == -1. 224132720Skan const int __enc = _M_codecvt->encoding(); 225132720Skan streamsize __blen; // Minimum buffer size. 226132720Skan streamsize __rlen; // Number of chars to read. 227132720Skan if (__enc > 0) 228132720Skan __blen = __rlen = __buflen * __enc; 229132720Skan else 23097403Sobrien { 231132720Skan __blen = __buflen + _M_codecvt->max_length() - 1; 232132720Skan __rlen = __buflen; 23397403Sobrien } 234132720Skan const streamsize __remainder = _M_ext_end - _M_ext_next; 235132720Skan __rlen = __rlen > __remainder ? __rlen - __remainder : 0; 236132720Skan 237132720Skan // An imbue in 'read' mode implies first converting the external 238132720Skan // chars already present. 239132720Skan if (_M_reading && this->egptr() == this->eback() && __remainder) 240132720Skan __rlen = 0; 241132720Skan 242132720Skan // Allocate buffer if necessary and move unconverted 243132720Skan // bytes to front. 244132720Skan if (_M_ext_buf_size < __blen) 24597403Sobrien { 246132720Skan char* __buf = new char[__blen]; 247132720Skan if (__remainder) 248132720Skan std::memcpy(__buf, _M_ext_next, __remainder); 249132720Skan 250132720Skan delete [] _M_ext_buf; 251132720Skan _M_ext_buf = __buf; 252132720Skan _M_ext_buf_size = __blen; 25397403Sobrien } 254132720Skan else if (__remainder) 255132720Skan std::memmove(_M_ext_buf, _M_ext_next, __remainder); 256132720Skan 257132720Skan _M_ext_next = _M_ext_buf; 258132720Skan _M_ext_end = _M_ext_buf + __remainder; 259132720Skan _M_state_last = _M_state_cur; 260132720Skan 261132720Skan do 26297403Sobrien { 263132720Skan if (__rlen > 0) 264132720Skan { 265132720Skan // Sanity check! 266132720Skan // This may fail if the return value of 267132720Skan // codecvt::max_length() is bogus. 268132720Skan if (_M_ext_end - _M_ext_buf + __rlen > _M_ext_buf_size) 269132720Skan { 270132720Skan __throw_ios_failure(__N("basic_filebuf::underflow " 271132720Skan "codecvt::max_length() " 272132720Skan "is not valid")); 273132720Skan } 274132720Skan streamsize __elen = _M_file.xsgetn(_M_ext_end, __rlen); 275132720Skan if (__elen == 0) 276132720Skan __got_eof = true; 277132720Skan else if (__elen == -1) 278132720Skan break; 279132720Skan _M_ext_end += __elen; 280132720Skan } 281132720Skan 282132720Skan char_type* __iend; 283132720Skan __r = _M_codecvt->in(_M_state_cur, _M_ext_next, 284132720Skan _M_ext_end, _M_ext_next, this->eback(), 285132720Skan this->eback() + __buflen, __iend); 286132720Skan if (__r == codecvt_base::noconv) 287132720Skan { 288132720Skan size_t __avail = _M_ext_end - _M_ext_buf; 289132720Skan __ilen = std::min(__avail, __buflen); 290132720Skan traits_type::copy(this->eback(), 291132720Skan reinterpret_cast<char_type*>(_M_ext_buf), __ilen); 292132720Skan _M_ext_next = _M_ext_buf + __ilen; 293132720Skan } 294132720Skan else 295132720Skan __ilen = __iend - this->eback(); 296132720Skan 297132720Skan // _M_codecvt->in may return error while __ilen > 0: this is 298132720Skan // ok, and actually occurs in case of mixed encodings (e.g., 299132720Skan // XML files). 300132720Skan if (__r == codecvt_base::error) 301132720Skan break; 302132720Skan 303132720Skan __rlen = 1; 30497403Sobrien } 305132720Skan while (__ilen == 0 && !__got_eof); 30697403Sobrien } 307132720Skan 308132720Skan if (__ilen > 0) 309132720Skan { 310132720Skan _M_set_buffer(__ilen); 311132720Skan _M_reading = true; 312132720Skan __ret = traits_type::to_int_type(*this->gptr()); 313132720Skan } 314132720Skan else if (__got_eof) 315132720Skan { 316132720Skan // If the actual end of file is reached, set 'uncommitted' 317132720Skan // mode, thus allowing an immediate write without an 318132720Skan // intervening seek. 319132720Skan _M_set_buffer(-1); 320132720Skan _M_reading = false; 321132720Skan // However, reaching it while looping on partial means that 322132720Skan // the file has got an incomplete character. 323132720Skan if (__r == codecvt_base::partial) 324132720Skan __throw_ios_failure(__N("basic_filebuf::underflow " 325132720Skan "incomplete character in file")); 326132720Skan } 327132720Skan else if (__r == codecvt_base::error) 328132720Skan __throw_ios_failure(__N("basic_filebuf::underflow " 329132720Skan "invalid byte sequence in file")); 33097403Sobrien else 331132720Skan __throw_ios_failure(__N("basic_filebuf::underflow " 332132720Skan "error reading the file")); 33397403Sobrien } 33497403Sobrien return __ret; 33597403Sobrien } 33697403Sobrien 33797403Sobrien template<typename _CharT, typename _Traits> 338132720Skan typename basic_filebuf<_CharT, _Traits>::int_type 33997403Sobrien basic_filebuf<_CharT, _Traits>:: 340132720Skan pbackfail(int_type __i) 341132720Skan { 342132720Skan int_type __ret = traits_type::eof(); 343169691Skan const bool __testin = _M_mode & ios_base::in; 344132720Skan if (__testin && !_M_writing) 345132720Skan { 346132720Skan // Remember whether the pback buffer is active, otherwise below 347132720Skan // we may try to store in it a second char (libstdc++/9761). 348169691Skan const bool __testpb = _M_pback_init; 349132720Skan const bool __testeof = traits_type::eq_int_type(__i, __ret); 350132720Skan int_type __tmp; 351132720Skan if (this->eback() < this->gptr()) 352132720Skan { 353132720Skan this->gbump(-1); 354132720Skan __tmp = traits_type::to_int_type(*this->gptr()); 355132720Skan } 356132720Skan else if (this->seekoff(-1, ios_base::cur) != pos_type(off_type(-1))) 357132720Skan { 358132720Skan __tmp = this->underflow(); 359132720Skan if (traits_type::eq_int_type(__tmp, __ret)) 360132720Skan return __ret; 361132720Skan } 362132720Skan else 363132720Skan { 364132720Skan // At the beginning of the buffer, need to make a 365132720Skan // putback position available. But the seek may fail 366132720Skan // (f.i., at the beginning of a file, see 367132720Skan // libstdc++/9439) and in that case we return 368132720Skan // traits_type::eof(). 369132720Skan return __ret; 370132720Skan } 371132720Skan 372132720Skan // Try to put back __i into input sequence in one of three ways. 373132720Skan // Order these tests done in is unspecified by the standard. 374132720Skan if (!__testeof && traits_type::eq_int_type(__i, __tmp)) 375132720Skan __ret = __i; 376132720Skan else if (__testeof) 377132720Skan __ret = traits_type::not_eof(__i); 378132720Skan else if (!__testpb) 379132720Skan { 380132720Skan _M_create_pback(); 381132720Skan _M_reading = true; 382132720Skan *this->gptr() = traits_type::to_char_type(__i); 383132720Skan __ret = __i; 384132720Skan } 385132720Skan } 386132720Skan return __ret; 387132720Skan } 388132720Skan 389132720Skan template<typename _CharT, typename _Traits> 390132720Skan typename basic_filebuf<_CharT, _Traits>::int_type 391132720Skan basic_filebuf<_CharT, _Traits>:: 39297403Sobrien overflow(int_type __c) 39397403Sobrien { 39497403Sobrien int_type __ret = traits_type::eof(); 395132720Skan const bool __testeof = traits_type::eq_int_type(__c, __ret); 396169691Skan const bool __testout = _M_mode & ios_base::out; 397132720Skan if (__testout && !_M_reading) 39897403Sobrien { 399132720Skan if (this->pbase() < this->pptr()) 40097403Sobrien { 401132720Skan // If appropriate, append the overflow char. 402132720Skan if (!__testeof) 403132720Skan { 404132720Skan *this->pptr() = traits_type::to_char_type(__c); 405132720Skan this->pbump(1); 406132720Skan } 407132720Skan 408132720Skan // Convert pending sequence to external representation, 409132720Skan // and output. 410132720Skan if (_M_convert_to_external(this->pbase(), 411146897Skan this->pptr() - this->pbase())) 412132720Skan { 413132720Skan _M_set_buffer(0); 414132720Skan __ret = traits_type::not_eof(__c); 415132720Skan } 416132720Skan } 417169691Skan else if (_M_buf_size > 1) 418132720Skan { 419132720Skan // Overflow in 'uncommitted' mode: set _M_writing, set 420132720Skan // the buffer to the initial 'write' mode, and put __c 421132720Skan // into the buffer. 422132720Skan _M_set_buffer(0); 423132720Skan _M_writing = true; 424132720Skan if (!__testeof) 425132720Skan { 426132720Skan *this->pptr() = traits_type::to_char_type(__c); 427132720Skan this->pbump(1); 428132720Skan } 42997403Sobrien __ret = traits_type::not_eof(__c); 43097403Sobrien } 431132720Skan else 432132720Skan { 433132720Skan // Unbuffered. 434132720Skan char_type __conv = traits_type::to_char_type(__c); 435132720Skan if (__testeof || _M_convert_to_external(&__conv, 1)) 436132720Skan { 437132720Skan _M_writing = true; 438132720Skan __ret = traits_type::not_eof(__c); 439132720Skan } 440132720Skan } 44197403Sobrien } 44297403Sobrien return __ret; 44397403Sobrien } 444132720Skan 44597403Sobrien template<typename _CharT, typename _Traits> 446132720Skan bool 44797403Sobrien basic_filebuf<_CharT, _Traits>:: 448132720Skan _M_convert_to_external(_CharT* __ibuf, streamsize __ilen) 44997403Sobrien { 450132720Skan // Sizes of external and pending output. 451132720Skan streamsize __elen; 452132720Skan streamsize __plen; 453132720Skan if (__check_facet(_M_codecvt).always_noconv()) 45497403Sobrien { 455132720Skan __elen = _M_file.xsputn(reinterpret_cast<char*>(__ibuf), __ilen); 456132720Skan __plen = __ilen; 45797403Sobrien } 45897403Sobrien else 45997403Sobrien { 46097403Sobrien // Worst-case number of external bytes needed. 461132720Skan // XXX Not done encoding() == -1. 462132720Skan streamsize __blen = __ilen * _M_codecvt->max_length(); 46397403Sobrien char* __buf = static_cast<char*>(__builtin_alloca(__blen)); 464132720Skan 46597403Sobrien char* __bend; 46697403Sobrien const char_type* __iend; 467117397Skan codecvt_base::result __r; 468132720Skan __r = _M_codecvt->out(_M_state_cur, __ibuf, __ibuf + __ilen, 469132720Skan __iend, __buf, __buf + __blen, __bend); 470117397Skan 471117397Skan if (__r == codecvt_base::ok || __r == codecvt_base::partial) 47297403Sobrien __blen = __bend - __buf; 473117397Skan else if (__r == codecvt_base::noconv) 474117397Skan { 475117397Skan // Same as the always_noconv case above. 476117397Skan __buf = reinterpret_cast<char*>(__ibuf); 477117397Skan __blen = __ilen; 478117397Skan } 479117397Skan else 480132720Skan __throw_ios_failure(__N("basic_filebuf::_M_convert_to_external " 481132720Skan "conversion error")); 482132720Skan 483132720Skan __elen = _M_file.xsputn(__buf, __blen); 484132720Skan __plen = __blen; 48597403Sobrien 48697403Sobrien // Try once more for partial conversions. 487132720Skan if (__r == codecvt_base::partial && __elen == __plen) 48897403Sobrien { 48997403Sobrien const char_type* __iresume = __iend; 490132720Skan streamsize __rlen = this->pptr() - __iend; 491132720Skan __r = _M_codecvt->out(_M_state_cur, __iresume, 492132720Skan __iresume + __rlen, __iend, __buf, 493132720Skan __buf + __blen, __bend); 49497403Sobrien if (__r != codecvt_base::error) 49597403Sobrien { 496117397Skan __rlen = __bend - __buf; 497132720Skan __elen = _M_file.xsputn(__buf, __rlen); 498132720Skan __plen = __rlen; 49997403Sobrien } 500132720Skan else 501132720Skan __throw_ios_failure(__N("basic_filebuf::_M_convert_to_external " 502132720Skan "conversion error")); 50397403Sobrien } 50497403Sobrien } 505132720Skan return __elen == __plen; 50697403Sobrien } 50797403Sobrien 508132720Skan template<typename _CharT, typename _Traits> 509132720Skan streamsize 510132720Skan basic_filebuf<_CharT, _Traits>:: 511146897Skan xsgetn(_CharT* __s, streamsize __n) 512146897Skan { 513146897Skan // Clear out pback buffer before going on to the real deal... 514146897Skan streamsize __ret = 0; 515169691Skan if (_M_pback_init) 516146897Skan { 517146897Skan if (__n > 0 && this->gptr() == this->eback()) 518146897Skan { 519146897Skan *__s++ = *this->gptr(); 520146897Skan this->gbump(1); 521146897Skan __ret = 1; 522146897Skan --__n; 523146897Skan } 524146897Skan _M_destroy_pback(); 525146897Skan } 526146897Skan 527146897Skan // Optimization in the always_noconv() case, to be generalized in the 528146897Skan // future: when __n > __buflen we read directly instead of using the 529146897Skan // buffer repeatedly. 530169691Skan const bool __testin = _M_mode & ios_base::in; 531169691Skan const streamsize __buflen = _M_buf_size > 1 ? _M_buf_size - 1 : 1; 532169691Skan 533146897Skan if (__n > __buflen && __check_facet(_M_codecvt).always_noconv() 534146897Skan && __testin && !_M_writing) 535146897Skan { 536146897Skan // First, copy the chars already present in the buffer. 537146897Skan const streamsize __avail = this->egptr() - this->gptr(); 538146897Skan if (__avail != 0) 539146897Skan { 540146897Skan if (__avail == 1) 541146897Skan *__s = *this->gptr(); 542146897Skan else 543146897Skan traits_type::copy(__s, this->gptr(), __avail); 544146897Skan __s += __avail; 545146897Skan this->gbump(__avail); 546146897Skan __ret += __avail; 547146897Skan __n -= __avail; 548146897Skan } 549146897Skan 550161653Skan // Need to loop in case of short reads (relatively common 551161653Skan // with pipes). 552161653Skan streamsize __len; 553161653Skan for (;;) 554146897Skan { 555161653Skan __len = _M_file.xsgetn(reinterpret_cast<char*>(__s), 556161653Skan __n); 557161653Skan if (__len == -1) 558161653Skan __throw_ios_failure(__N("basic_filebuf::xsgetn " 559161653Skan "error reading the file")); 560161653Skan if (__len == 0) 561161653Skan break; 562161653Skan 563161653Skan __n -= __len; 564161653Skan __ret += __len; 565161653Skan if (__n == 0) 566161653Skan break; 567161653Skan 568161653Skan __s += __len; 569161653Skan } 570161653Skan 571161653Skan if (__n == 0) 572161653Skan { 573146897Skan _M_set_buffer(0); 574146897Skan _M_reading = true; 575146897Skan } 576146897Skan else if (__len == 0) 577146897Skan { 578146897Skan // If end of file is reached, set 'uncommitted' 579146897Skan // mode, thus allowing an immediate write without 580146897Skan // an intervening seek. 581146897Skan _M_set_buffer(-1); 582146897Skan _M_reading = false; 583146897Skan } 584146897Skan } 585146897Skan else 586146897Skan __ret += __streambuf_type::xsgetn(__s, __n); 587146897Skan 588146897Skan return __ret; 589146897Skan } 590146897Skan 591146897Skan template<typename _CharT, typename _Traits> 592146897Skan streamsize 593146897Skan basic_filebuf<_CharT, _Traits>:: 594132720Skan xsputn(const _CharT* __s, streamsize __n) 595132720Skan { 596132720Skan // Optimization in the always_noconv() case, to be generalized in the 597132720Skan // future: when __n is sufficiently large we write directly instead of 598132720Skan // using the buffer. 599132720Skan streamsize __ret = 0; 600169691Skan const bool __testout = _M_mode & ios_base::out; 601146897Skan if (__check_facet(_M_codecvt).always_noconv() 602146897Skan && __testout && !_M_reading) 60397403Sobrien { 604132720Skan // Measurement would reveal the best choice. 605132720Skan const streamsize __chunk = 1ul << 10; 606132720Skan streamsize __bufavail = this->epptr() - this->pptr(); 60797403Sobrien 608132720Skan // Don't mistake 'uncommitted' mode buffered with unbuffered. 609169691Skan if (!_M_writing && _M_buf_size > 1) 610169691Skan __bufavail = _M_buf_size - 1; 611132720Skan 612132720Skan const streamsize __limit = std::min(__chunk, __bufavail); 613132720Skan if (__n >= __limit) 61497403Sobrien { 615132720Skan const streamsize __buffill = this->pptr() - this->pbase(); 616132720Skan const char* __buf = reinterpret_cast<const char*>(this->pbase()); 617132720Skan __ret = _M_file.xsputn_2(__buf, __buffill, 618132720Skan reinterpret_cast<const char*>(__s), 619132720Skan __n); 620132720Skan if (__ret == __buffill + __n) 62197403Sobrien { 622132720Skan _M_set_buffer(0); 623132720Skan _M_writing = true; 62497403Sobrien } 625132720Skan if (__ret > __buffill) 626132720Skan __ret -= __buffill; 627132720Skan else 628132720Skan __ret = 0; 629132720Skan } 630132720Skan else 631132720Skan __ret = __streambuf_type::xsputn(__s, __n); 632117397Skan } 633132720Skan else 634132720Skan __ret = __streambuf_type::xsputn(__s, __n); 635132720Skan return __ret; 63697403Sobrien } 63797403Sobrien 63897403Sobrien template<typename _CharT, typename _Traits> 639132720Skan typename basic_filebuf<_CharT, _Traits>::__streambuf_type* 64097403Sobrien basic_filebuf<_CharT, _Traits>:: 64197403Sobrien setbuf(char_type* __s, streamsize __n) 64297403Sobrien { 643132720Skan if (!this->is_open()) 644241957Sdim { 645241957Sdim if (__s == 0 && __n == 0) 646241957Sdim _M_buf_size = 1; 647241957Sdim else if (__s && __n > 0) 648241957Sdim { 649241957Sdim // This is implementation-defined behavior, and assumes that 650241957Sdim // an external char_type array of length __n exists and has 651241957Sdim // been pre-allocated. If this is not the case, things will 652241957Sdim // quickly blow up. When __n > 1, __n - 1 positions will be 653241957Sdim // used for the get area, __n - 1 for the put area and 1 654241957Sdim // position to host the overflow char of a full put area. 655241957Sdim // When __n == 1, 1 position will be used for the get area 656241957Sdim // and 0 for the put area, as in the unbuffered case above. 657241957Sdim _M_buf = __s; 658241957Sdim _M_buf_size = __n; 659241957Sdim } 660241957Sdim } 661132720Skan return this; 66297403Sobrien } 663132720Skan 664132720Skan 665132720Skan // According to 27.8.1.4 p11 - 13, seekoff should ignore the last 666132720Skan // argument (of type openmode). 66797403Sobrien template<typename _CharT, typename _Traits> 66897403Sobrien typename basic_filebuf<_CharT, _Traits>::pos_type 66997403Sobrien basic_filebuf<_CharT, _Traits>:: 670132720Skan seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode) 67197403Sobrien { 672117397Skan int __width = 0; 673132720Skan if (_M_codecvt) 674132720Skan __width = _M_codecvt->encoding(); 67597403Sobrien if (__width < 0) 67697403Sobrien __width = 0; 677117397Skan 678132720Skan pos_type __ret = pos_type(off_type(-1)); 679132720Skan const bool __testfail = __off != 0 && __width <= 0; 680132720Skan if (this->is_open() && !__testfail) 68197403Sobrien { 68297403Sobrien // Ditch any pback buffers to avoid confusion. 683132720Skan _M_destroy_pback(); 68497403Sobrien 685132720Skan // Correct state at destination. Note that this is the correct 686132720Skan // state for the current position during output, because 687132720Skan // codecvt::unshift() returns the state to the initial state. 688132720Skan // This is also the correct state at the end of the file because 689132720Skan // an unshift sequence should have been written at the end. 690132720Skan __state_type __state = _M_state_beg; 691132720Skan off_type __computed_off = __off * __width; 692132720Skan if (_M_reading && __way == ios_base::cur) 693132720Skan { 694132720Skan if (_M_codecvt->always_noconv()) 695132720Skan __computed_off += this->gptr() - this->egptr(); 696132720Skan else 69797403Sobrien { 698132720Skan // Calculate offset from _M_ext_buf that corresponds 699132720Skan // to gptr(). Note: uses _M_state_last, which 700132720Skan // corresponds to eback(). 701132720Skan const int __gptr_off = 702132720Skan _M_codecvt->length(_M_state_last, _M_ext_buf, _M_ext_next, 703132720Skan this->gptr() - this->eback()); 704132720Skan __computed_off += _M_ext_buf + __gptr_off - _M_ext_end; 705117397Skan 706132720Skan // _M_state_last is modified by codecvt::length() so 707132720Skan // it now corresponds to gptr(). 708132720Skan __state = _M_state_last; 709117397Skan } 71097403Sobrien } 711132720Skan __ret = _M_seek(__computed_off, __way, __state); 71297403Sobrien } 71397403Sobrien return __ret; 71497403Sobrien } 71597403Sobrien 716132720Skan // _GLIBCXX_RESOLVE_LIB_DEFECTS 717132720Skan // 171. Strange seekpos() semantics due to joint position 718132720Skan // According to the resolution of DR 171, seekpos should ignore the last 719132720Skan // argument (of type openmode). 72097403Sobrien template<typename _CharT, typename _Traits> 72197403Sobrien typename basic_filebuf<_CharT, _Traits>::pos_type 72297403Sobrien basic_filebuf<_CharT, _Traits>:: 723132720Skan seekpos(pos_type __pos, ios_base::openmode) 72497403Sobrien { 725132720Skan pos_type __ret = pos_type(off_type(-1)); 726132720Skan if (this->is_open()) 727132720Skan { 728132720Skan // Ditch any pback buffers to avoid confusion. 729132720Skan _M_destroy_pback(); 730132720Skan __ret = _M_seek(off_type(__pos), ios_base::beg, __pos.state()); 731132720Skan } 732132720Skan return __ret; 73397403Sobrien } 73497403Sobrien 73597403Sobrien template<typename _CharT, typename _Traits> 736132720Skan typename basic_filebuf<_CharT, _Traits>::pos_type 73797403Sobrien basic_filebuf<_CharT, _Traits>:: 738132720Skan _M_seek(off_type __off, ios_base::seekdir __way, __state_type __state) 739132720Skan { 740132720Skan pos_type __ret = pos_type(off_type(-1)); 741132720Skan if (_M_terminate_output()) 742132720Skan { 743132720Skan // Returns pos_type(off_type(-1)) in case of failure. 744132720Skan __ret = pos_type(_M_file.seekoff(__off, __way)); 745169691Skan if (__ret != pos_type(off_type(-1))) 746169691Skan { 747169691Skan _M_reading = false; 748169691Skan _M_writing = false; 749169691Skan _M_ext_next = _M_ext_end = _M_ext_buf; 750169691Skan _M_set_buffer(-1); 751169691Skan _M_state_cur = __state; 752169691Skan __ret.state(_M_state_cur); 753169691Skan } 754132720Skan } 755132720Skan return __ret; 756132720Skan } 75797403Sobrien 75897403Sobrien template<typename _CharT, typename _Traits> 759132720Skan bool 760132720Skan basic_filebuf<_CharT, _Traits>:: 761132720Skan _M_terminate_output() 762132720Skan { 763132720Skan // Part one: update the output sequence. 764132720Skan bool __testvalid = true; 765132720Skan if (this->pbase() < this->pptr()) 766132720Skan { 767132720Skan const int_type __tmp = this->overflow(); 768132720Skan if (traits_type::eq_int_type(__tmp, traits_type::eof())) 769132720Skan __testvalid = false; 770132720Skan } 771132720Skan 772132720Skan // Part two: output unshift sequence. 773132720Skan if (_M_writing && !__check_facet(_M_codecvt).always_noconv() 774132720Skan && __testvalid) 775132720Skan { 776132720Skan // Note: this value is arbitrary, since there is no way to 777132720Skan // get the length of the unshift sequence from codecvt, 778132720Skan // without calling unshift. 779132720Skan const size_t __blen = 128; 780132720Skan char __buf[__blen]; 781132720Skan codecvt_base::result __r; 782132720Skan streamsize __ilen = 0; 783132720Skan 784132720Skan do 785132720Skan { 786132720Skan char* __next; 787132720Skan __r = _M_codecvt->unshift(_M_state_cur, __buf, 788132720Skan __buf + __blen, __next); 789132720Skan if (__r == codecvt_base::error) 790132720Skan __testvalid = false; 791132720Skan else if (__r == codecvt_base::ok || 792132720Skan __r == codecvt_base::partial) 793132720Skan { 794132720Skan __ilen = __next - __buf; 795132720Skan if (__ilen > 0) 796132720Skan { 797132720Skan const streamsize __elen = _M_file.xsputn(__buf, __ilen); 798132720Skan if (__elen != __ilen) 799132720Skan __testvalid = false; 800132720Skan } 801132720Skan } 802132720Skan } 803132720Skan while (__r == codecvt_base::partial && __ilen > 0 && __testvalid); 804132720Skan 805132720Skan if (__testvalid) 806132720Skan { 807132720Skan // This second call to overflow() is required by the standard, 808132720Skan // but it's not clear why it's needed, since the output buffer 809132720Skan // should be empty by this point (it should have been emptied 810132720Skan // in the first call to overflow()). 811132720Skan const int_type __tmp = this->overflow(); 812132720Skan if (traits_type::eq_int_type(__tmp, traits_type::eof())) 813132720Skan __testvalid = false; 814132720Skan } 815132720Skan } 816132720Skan return __testvalid; 817132720Skan } 818132720Skan 819132720Skan template<typename _CharT, typename _Traits> 820132720Skan int 821132720Skan basic_filebuf<_CharT, _Traits>:: 822132720Skan sync() 823132720Skan { 824132720Skan // Make sure that the internal buffer resyncs its idea of 825132720Skan // the file position with the external file. 826132720Skan int __ret = 0; 827132720Skan if (this->pbase() < this->pptr()) 828132720Skan { 829132720Skan const int_type __tmp = this->overflow(); 830132720Skan if (traits_type::eq_int_type(__tmp, traits_type::eof())) 831132720Skan __ret = -1; 832132720Skan } 833132720Skan return __ret; 834132720Skan } 835132720Skan 836132720Skan template<typename _CharT, typename _Traits> 83797403Sobrien void 83897403Sobrien basic_filebuf<_CharT, _Traits>:: 83997403Sobrien imbue(const locale& __loc) 84097403Sobrien { 841132720Skan bool __testvalid = true; 84297403Sobrien 843132720Skan const __codecvt_type* _M_codecvt_tmp = 0; 844132720Skan if (__builtin_expect(has_facet<__codecvt_type>(__loc), true)) 845132720Skan _M_codecvt_tmp = &use_facet<__codecvt_type>(__loc); 84697403Sobrien 847132720Skan if (this->is_open()) 848132720Skan { 849132720Skan // encoding() == -1 is ok only at the beginning. 850132720Skan if ((_M_reading || _M_writing) 851132720Skan && __check_facet(_M_codecvt).encoding() == -1) 852132720Skan __testvalid = false; 853132720Skan else 854132720Skan { 855132720Skan if (_M_reading) 856132720Skan { 857132720Skan if (__check_facet(_M_codecvt).always_noconv()) 858132720Skan { 859132720Skan if (_M_codecvt_tmp 860132720Skan && !__check_facet(_M_codecvt_tmp).always_noconv()) 861169691Skan __testvalid = this->seekoff(0, ios_base::cur, _M_mode) 862132720Skan != pos_type(off_type(-1)); 863132720Skan } 864132720Skan else 865132720Skan { 866132720Skan // External position corresponding to gptr(). 867132720Skan _M_ext_next = _M_ext_buf 868132720Skan + _M_codecvt->length(_M_state_last, _M_ext_buf, _M_ext_next, 869132720Skan this->gptr() - this->eback()); 870132720Skan const streamsize __remainder = _M_ext_end - _M_ext_next; 871132720Skan if (__remainder) 872132720Skan std::memmove(_M_ext_buf, _M_ext_next, __remainder); 873132720Skan 874132720Skan _M_ext_next = _M_ext_buf; 875132720Skan _M_ext_end = _M_ext_buf + __remainder; 876132720Skan _M_set_buffer(-1); 877132720Skan _M_state_last = _M_state_cur = _M_state_beg; 878132720Skan } 879132720Skan } 880132720Skan else if (_M_writing && (__testvalid = _M_terminate_output())) 881132720Skan _M_set_buffer(-1); 882132720Skan } 883132720Skan } 884132720Skan 885132720Skan if (__testvalid) 886132720Skan _M_codecvt = _M_codecvt_tmp; 887132720Skan else 888132720Skan _M_codecvt = 0; 88997403Sobrien } 89097403Sobrien 89197403Sobrien // Inhibit implicit instantiations for required instantiations, 892132720Skan // which are defined via explicit instantiations elsewhere. 89397403Sobrien // NB: This syntax is a GNU extension. 894132720Skan#if _GLIBCXX_EXTERN_TEMPLATE 89597403Sobrien extern template class basic_filebuf<char>; 896107606Sobrien extern template class basic_ifstream<char>; 897107606Sobrien extern template class basic_ofstream<char>; 898107606Sobrien extern template class basic_fstream<char>; 899107606Sobrien 900132720Skan#ifdef _GLIBCXX_USE_WCHAR_T 90197403Sobrien extern template class basic_filebuf<wchar_t>; 90297403Sobrien extern template class basic_ifstream<wchar_t>; 90397403Sobrien extern template class basic_ofstream<wchar_t>; 90497403Sobrien extern template class basic_fstream<wchar_t>; 905107606Sobrien#endif 906117397Skan#endif 90797403Sobrien 908169691Skan_GLIBCXX_END_NAMESPACE 909169691Skan 910132720Skan#endif 911