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