xref: /openbsd-src/gnu/gcc/libstdc++-v3/include/bits/fstream.tcc (revision 404b540a9034ac75a6199ad1a32d1bbc7a0d4210)
1*404b540aSrobert // File based streams -*- C++ -*-
2*404b540aSrobert 
3*404b540aSrobert // Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
4*404b540aSrobert // Free Software Foundation, Inc.
5*404b540aSrobert //
6*404b540aSrobert // This file is part of the GNU ISO C++ Library.  This library is free
7*404b540aSrobert // software; you can redistribute it and/or modify it under the
8*404b540aSrobert // terms of the GNU General Public License as published by the
9*404b540aSrobert // Free Software Foundation; either version 2, or (at your option)
10*404b540aSrobert // any later version.
11*404b540aSrobert 
12*404b540aSrobert // This library is distributed in the hope that it will be useful,
13*404b540aSrobert // but WITHOUT ANY WARRANTY; without even the implied warranty of
14*404b540aSrobert // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15*404b540aSrobert // GNU General Public License for more details.
16*404b540aSrobert 
17*404b540aSrobert // You should have received a copy of the GNU General Public License along
18*404b540aSrobert // with this library; see the file COPYING.  If not, write to the Free
19*404b540aSrobert // Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
20*404b540aSrobert // USA.
21*404b540aSrobert 
22*404b540aSrobert // As a special exception, you may use this file as part of a free software
23*404b540aSrobert // library without restriction.  Specifically, if other files instantiate
24*404b540aSrobert // templates or use macros or inline functions from this file, or you compile
25*404b540aSrobert // this file and link it with other files to produce an executable, this
26*404b540aSrobert // file does not by itself cause the resulting executable to be covered by
27*404b540aSrobert // the GNU General Public License.  This exception does not however
28*404b540aSrobert // invalidate any other reasons why the executable file might be covered by
29*404b540aSrobert // the GNU General Public License.
30*404b540aSrobert 
31*404b540aSrobert /** @file fstream.tcc
32*404b540aSrobert  *  This is an internal header file, included by other library headers.
33*404b540aSrobert  *  You should not attempt to use it directly.
34*404b540aSrobert  */
35*404b540aSrobert 
36*404b540aSrobert //
37*404b540aSrobert // ISO C++ 14882: 27.8  File-based streams
38*404b540aSrobert //
39*404b540aSrobert 
40*404b540aSrobert #ifndef _FSTREAM_TCC
41*404b540aSrobert #define _FSTREAM_TCC 1
42*404b540aSrobert 
43*404b540aSrobert #pragma GCC system_header
44*404b540aSrobert 
_GLIBCXX_BEGIN_NAMESPACE(std)45*404b540aSrobert _GLIBCXX_BEGIN_NAMESPACE(std)
46*404b540aSrobert 
47*404b540aSrobert   template<typename _CharT, typename _Traits>
48*404b540aSrobert     void
49*404b540aSrobert     basic_filebuf<_CharT, _Traits>::
50*404b540aSrobert     _M_allocate_internal_buffer()
51*404b540aSrobert     {
52*404b540aSrobert       // Allocate internal buffer only if one doesn't already exist
53*404b540aSrobert       // (either allocated or provided by the user via setbuf).
54*404b540aSrobert       if (!_M_buf_allocated && !_M_buf)
55*404b540aSrobert 	{
56*404b540aSrobert 	  _M_buf = new char_type[_M_buf_size];
57*404b540aSrobert 	  _M_buf_allocated = true;
58*404b540aSrobert 	}
59*404b540aSrobert     }
60*404b540aSrobert 
61*404b540aSrobert   template<typename _CharT, typename _Traits>
62*404b540aSrobert     void
63*404b540aSrobert     basic_filebuf<_CharT, _Traits>::
_M_destroy_internal_buffer()64*404b540aSrobert     _M_destroy_internal_buffer() throw()
65*404b540aSrobert     {
66*404b540aSrobert       if (_M_buf_allocated)
67*404b540aSrobert 	{
68*404b540aSrobert 	  delete [] _M_buf;
69*404b540aSrobert 	  _M_buf = NULL;
70*404b540aSrobert 	  _M_buf_allocated = false;
71*404b540aSrobert 	}
72*404b540aSrobert       delete [] _M_ext_buf;
73*404b540aSrobert       _M_ext_buf = NULL;
74*404b540aSrobert       _M_ext_buf_size = 0;
75*404b540aSrobert       _M_ext_next = NULL;
76*404b540aSrobert       _M_ext_end = NULL;
77*404b540aSrobert     }
78*404b540aSrobert 
79*404b540aSrobert   template<typename _CharT, typename _Traits>
80*404b540aSrobert     basic_filebuf<_CharT, _Traits>::
basic_filebuf()81*404b540aSrobert     basic_filebuf() : __streambuf_type(), _M_lock(), _M_file(&_M_lock),
82*404b540aSrobert     _M_mode(ios_base::openmode(0)), _M_state_beg(), _M_state_cur(),
83*404b540aSrobert     _M_state_last(), _M_buf(NULL), _M_buf_size(BUFSIZ),
84*404b540aSrobert     _M_buf_allocated(false), _M_reading(false), _M_writing(false), _M_pback(),
85*404b540aSrobert     _M_pback_cur_save(0), _M_pback_end_save(0), _M_pback_init(false),
86*404b540aSrobert     _M_codecvt(0), _M_ext_buf(0), _M_ext_buf_size(0), _M_ext_next(0),
87*404b540aSrobert     _M_ext_end(0)
88*404b540aSrobert     {
89*404b540aSrobert       if (has_facet<__codecvt_type>(this->_M_buf_locale))
90*404b540aSrobert 	_M_codecvt = &use_facet<__codecvt_type>(this->_M_buf_locale);
91*404b540aSrobert     }
92*404b540aSrobert 
93*404b540aSrobert   template<typename _CharT, typename _Traits>
94*404b540aSrobert     typename basic_filebuf<_CharT, _Traits>::__filebuf_type*
95*404b540aSrobert     basic_filebuf<_CharT, _Traits>::
open(const char * __s,ios_base::openmode __mode)96*404b540aSrobert     open(const char* __s, ios_base::openmode __mode)
97*404b540aSrobert     {
98*404b540aSrobert       __filebuf_type *__ret = NULL;
99*404b540aSrobert       if (!this->is_open())
100*404b540aSrobert 	{
101*404b540aSrobert 	  _M_file.open(__s, __mode);
102*404b540aSrobert 	  if (this->is_open())
103*404b540aSrobert 	    {
104*404b540aSrobert 	      _M_allocate_internal_buffer();
105*404b540aSrobert 	      _M_mode = __mode;
106*404b540aSrobert 
107*404b540aSrobert 	      // Setup initial buffer to 'uncommitted' mode.
108*404b540aSrobert 	      _M_reading = false;
109*404b540aSrobert 	      _M_writing = false;
110*404b540aSrobert 	      _M_set_buffer(-1);
111*404b540aSrobert 
112*404b540aSrobert 	      // Reset to initial state.
113*404b540aSrobert 	      _M_state_last = _M_state_cur = _M_state_beg;
114*404b540aSrobert 
115*404b540aSrobert 	      // 27.8.1.3,4
116*404b540aSrobert 	      if ((__mode & ios_base::ate)
117*404b540aSrobert 		  && this->seekoff(0, ios_base::end, __mode)
118*404b540aSrobert 		  == pos_type(off_type(-1)))
119*404b540aSrobert 		this->close();
120*404b540aSrobert 	      else
121*404b540aSrobert 		__ret = this;
122*404b540aSrobert 	    }
123*404b540aSrobert 	}
124*404b540aSrobert       return __ret;
125*404b540aSrobert     }
126*404b540aSrobert 
127*404b540aSrobert   template<typename _CharT, typename _Traits>
128*404b540aSrobert     typename basic_filebuf<_CharT, _Traits>::__filebuf_type*
129*404b540aSrobert     basic_filebuf<_CharT, _Traits>::
close()130*404b540aSrobert     close() throw()
131*404b540aSrobert     {
132*404b540aSrobert       __filebuf_type* __ret = NULL;
133*404b540aSrobert       if (this->is_open())
134*404b540aSrobert 	{
135*404b540aSrobert 	  bool __testfail = false;
136*404b540aSrobert 	  try
137*404b540aSrobert 	    {
138*404b540aSrobert 	      if (!_M_terminate_output())
139*404b540aSrobert 		__testfail = true;
140*404b540aSrobert 	    }
141*404b540aSrobert 	  catch(...)
142*404b540aSrobert 	    { __testfail = true; }
143*404b540aSrobert 
144*404b540aSrobert 	  // NB: Do this here so that re-opened filebufs will be cool...
145*404b540aSrobert 	  _M_mode = ios_base::openmode(0);
146*404b540aSrobert 	  _M_pback_init = false;
147*404b540aSrobert 	  _M_destroy_internal_buffer();
148*404b540aSrobert 	  _M_reading = false;
149*404b540aSrobert 	  _M_writing = false;
150*404b540aSrobert 	  _M_set_buffer(-1);
151*404b540aSrobert 	  _M_state_last = _M_state_cur = _M_state_beg;
152*404b540aSrobert 
153*404b540aSrobert 	  if (!_M_file.close())
154*404b540aSrobert 	    __testfail = true;
155*404b540aSrobert 
156*404b540aSrobert 	  if (!__testfail)
157*404b540aSrobert 	    __ret = this;
158*404b540aSrobert 	}
159*404b540aSrobert       return __ret;
160*404b540aSrobert     }
161*404b540aSrobert 
162*404b540aSrobert   template<typename _CharT, typename _Traits>
163*404b540aSrobert     streamsize
164*404b540aSrobert     basic_filebuf<_CharT, _Traits>::
showmanyc()165*404b540aSrobert     showmanyc()
166*404b540aSrobert     {
167*404b540aSrobert       streamsize __ret = -1;
168*404b540aSrobert       const bool __testin = _M_mode & ios_base::in;
169*404b540aSrobert       if (__testin && this->is_open())
170*404b540aSrobert 	{
171*404b540aSrobert 	  // For a stateful encoding (-1) the pending sequence might be just
172*404b540aSrobert 	  // shift and unshift prefixes with no actual character.
173*404b540aSrobert 	  __ret = this->egptr() - this->gptr();
174*404b540aSrobert 
175*404b540aSrobert #if _GLIBCXX_HAVE_DOS_BASED_FILESYSTEM
176*404b540aSrobert 	  // About this workaround, see libstdc++/20806.
177*404b540aSrobert 	  const bool __testbinary = _M_mode & ios_base::binary;
178*404b540aSrobert 	  if (__check_facet(_M_codecvt).encoding() >= 0
179*404b540aSrobert 	      && __testbinary)
180*404b540aSrobert #else
181*404b540aSrobert 	  if (__check_facet(_M_codecvt).encoding() >= 0)
182*404b540aSrobert #endif
183*404b540aSrobert 	    __ret += _M_file.showmanyc() / _M_codecvt->max_length();
184*404b540aSrobert 	}
185*404b540aSrobert       return __ret;
186*404b540aSrobert     }
187*404b540aSrobert 
188*404b540aSrobert   template<typename _CharT, typename _Traits>
189*404b540aSrobert     typename basic_filebuf<_CharT, _Traits>::int_type
190*404b540aSrobert     basic_filebuf<_CharT, _Traits>::
underflow()191*404b540aSrobert     underflow()
192*404b540aSrobert     {
193*404b540aSrobert       int_type __ret = traits_type::eof();
194*404b540aSrobert       const bool __testin = _M_mode & ios_base::in;
195*404b540aSrobert       if (__testin && !_M_writing)
196*404b540aSrobert 	{
197*404b540aSrobert 	  // Check for pback madness, and if so swich back to the
198*404b540aSrobert 	  // normal buffers and jet outta here before expensive
199*404b540aSrobert 	  // fileops happen...
200*404b540aSrobert 	  _M_destroy_pback();
201*404b540aSrobert 
202*404b540aSrobert 	  if (this->gptr() < this->egptr())
203*404b540aSrobert 	    return traits_type::to_int_type(*this->gptr());
204*404b540aSrobert 
205*404b540aSrobert 	  // Get and convert input sequence.
206*404b540aSrobert 	  const size_t __buflen = _M_buf_size > 1 ? _M_buf_size - 1 : 1;
207*404b540aSrobert 
208*404b540aSrobert 	  // Will be set to true if ::read() returns 0 indicating EOF.
209*404b540aSrobert 	  bool __got_eof = false;
210*404b540aSrobert 	  // Number of internal characters produced.
211*404b540aSrobert 	  streamsize __ilen = 0;
212*404b540aSrobert 	  codecvt_base::result __r = codecvt_base::ok;
213*404b540aSrobert 	  if (__check_facet(_M_codecvt).always_noconv())
214*404b540aSrobert 	    {
215*404b540aSrobert 	      __ilen = _M_file.xsgetn(reinterpret_cast<char*>(this->eback()),
216*404b540aSrobert 				      __buflen);
217*404b540aSrobert 	      if (__ilen == 0)
218*404b540aSrobert 		__got_eof = true;
219*404b540aSrobert 	    }
220*404b540aSrobert 	  else
221*404b540aSrobert 	    {
222*404b540aSrobert               // Worst-case number of external bytes.
223*404b540aSrobert 	      // XXX Not done encoding() == -1.
224*404b540aSrobert 	      const int __enc = _M_codecvt->encoding();
225*404b540aSrobert 	      streamsize __blen; // Minimum buffer size.
226*404b540aSrobert 	      streamsize __rlen; // Number of chars to read.
227*404b540aSrobert 	      if (__enc > 0)
228*404b540aSrobert 		__blen = __rlen = __buflen * __enc;
229*404b540aSrobert 	      else
230*404b540aSrobert 		{
231*404b540aSrobert 		  __blen = __buflen + _M_codecvt->max_length() - 1;
232*404b540aSrobert 		  __rlen = __buflen;
233*404b540aSrobert 		}
234*404b540aSrobert 	      const streamsize __remainder = _M_ext_end - _M_ext_next;
235*404b540aSrobert 	      __rlen = __rlen > __remainder ? __rlen - __remainder : 0;
236*404b540aSrobert 
237*404b540aSrobert 	      // An imbue in 'read' mode implies first converting the external
238*404b540aSrobert 	      // chars already present.
239*404b540aSrobert 	      if (_M_reading && this->egptr() == this->eback() && __remainder)
240*404b540aSrobert 		__rlen = 0;
241*404b540aSrobert 
242*404b540aSrobert 	      // Allocate buffer if necessary and move unconverted
243*404b540aSrobert 	      // bytes to front.
244*404b540aSrobert 	      if (_M_ext_buf_size < __blen)
245*404b540aSrobert 		{
246*404b540aSrobert 		  char* __buf = new char[__blen];
247*404b540aSrobert 		  if (__remainder)
248*404b540aSrobert 		    std::memcpy(__buf, _M_ext_next, __remainder);
249*404b540aSrobert 
250*404b540aSrobert 		  delete [] _M_ext_buf;
251*404b540aSrobert 		  _M_ext_buf = __buf;
252*404b540aSrobert 		  _M_ext_buf_size = __blen;
253*404b540aSrobert 		}
254*404b540aSrobert 	      else if (__remainder)
255*404b540aSrobert 		std::memmove(_M_ext_buf, _M_ext_next, __remainder);
256*404b540aSrobert 
257*404b540aSrobert 	      _M_ext_next = _M_ext_buf;
258*404b540aSrobert 	      _M_ext_end = _M_ext_buf + __remainder;
259*404b540aSrobert 	      _M_state_last = _M_state_cur;
260*404b540aSrobert 
261*404b540aSrobert 	      do
262*404b540aSrobert 		{
263*404b540aSrobert 		  if (__rlen > 0)
264*404b540aSrobert 		    {
265*404b540aSrobert 		      // Sanity check!
266*404b540aSrobert 		      // This may fail if the return value of
267*404b540aSrobert 		      // codecvt::max_length() is bogus.
268*404b540aSrobert 		      if (_M_ext_end - _M_ext_buf + __rlen > _M_ext_buf_size)
269*404b540aSrobert 			{
270*404b540aSrobert 			  __throw_ios_failure(__N("basic_filebuf::underflow "
271*404b540aSrobert 					      "codecvt::max_length() "
272*404b540aSrobert 					      "is not valid"));
273*404b540aSrobert 			}
274*404b540aSrobert 		      streamsize __elen = _M_file.xsgetn(_M_ext_end, __rlen);
275*404b540aSrobert 		      if (__elen == 0)
276*404b540aSrobert 			__got_eof = true;
277*404b540aSrobert 		      else if (__elen == -1)
278*404b540aSrobert 			break;
279*404b540aSrobert 		      _M_ext_end += __elen;
280*404b540aSrobert 		    }
281*404b540aSrobert 
282*404b540aSrobert 		  char_type* __iend;
283*404b540aSrobert 		  __r = _M_codecvt->in(_M_state_cur, _M_ext_next,
284*404b540aSrobert 				       _M_ext_end, _M_ext_next, this->eback(),
285*404b540aSrobert 				       this->eback() + __buflen, __iend);
286*404b540aSrobert 		  if (__r == codecvt_base::noconv)
287*404b540aSrobert 		    {
288*404b540aSrobert 		      size_t __avail = _M_ext_end - _M_ext_buf;
289*404b540aSrobert 		      __ilen = std::min(__avail, __buflen);
290*404b540aSrobert 		      traits_type::copy(this->eback(),
291*404b540aSrobert 					reinterpret_cast<char_type*>(_M_ext_buf), __ilen);
292*404b540aSrobert 		      _M_ext_next = _M_ext_buf + __ilen;
293*404b540aSrobert 		    }
294*404b540aSrobert 		  else
295*404b540aSrobert 		    __ilen = __iend - this->eback();
296*404b540aSrobert 
297*404b540aSrobert 		  // _M_codecvt->in may return error while __ilen > 0: this is
298*404b540aSrobert 		  // ok, and actually occurs in case of mixed encodings (e.g.,
299*404b540aSrobert 		  // XML files).
300*404b540aSrobert 		  if (__r == codecvt_base::error)
301*404b540aSrobert 		    break;
302*404b540aSrobert 
303*404b540aSrobert 		  __rlen = 1;
304*404b540aSrobert 		}
305*404b540aSrobert 	      while (__ilen == 0 && !__got_eof);
306*404b540aSrobert 	    }
307*404b540aSrobert 
308*404b540aSrobert 	  if (__ilen > 0)
309*404b540aSrobert 	    {
310*404b540aSrobert 	      _M_set_buffer(__ilen);
311*404b540aSrobert 	      _M_reading = true;
312*404b540aSrobert 	      __ret = traits_type::to_int_type(*this->gptr());
313*404b540aSrobert 	    }
314*404b540aSrobert 	  else if (__got_eof)
315*404b540aSrobert 	    {
316*404b540aSrobert 	      // If the actual end of file is reached, set 'uncommitted'
317*404b540aSrobert 	      // mode, thus allowing an immediate write without an
318*404b540aSrobert 	      // intervening seek.
319*404b540aSrobert 	      _M_set_buffer(-1);
320*404b540aSrobert 	      _M_reading = false;
321*404b540aSrobert 	      // However, reaching it while looping on partial means that
322*404b540aSrobert 	      // the file has got an incomplete character.
323*404b540aSrobert 	      if (__r == codecvt_base::partial)
324*404b540aSrobert 		__throw_ios_failure(__N("basic_filebuf::underflow "
325*404b540aSrobert 				    "incomplete character in file"));
326*404b540aSrobert 	    }
327*404b540aSrobert 	  else if (__r == codecvt_base::error)
328*404b540aSrobert 	    __throw_ios_failure(__N("basic_filebuf::underflow "
329*404b540aSrobert 				"invalid byte sequence in file"));
330*404b540aSrobert 	  else
331*404b540aSrobert 	    __throw_ios_failure(__N("basic_filebuf::underflow "
332*404b540aSrobert 				"error reading the file"));
333*404b540aSrobert 	}
334*404b540aSrobert       return __ret;
335*404b540aSrobert     }
336*404b540aSrobert 
337*404b540aSrobert   template<typename _CharT, typename _Traits>
338*404b540aSrobert     typename basic_filebuf<_CharT, _Traits>::int_type
339*404b540aSrobert     basic_filebuf<_CharT, _Traits>::
pbackfail(int_type __i)340*404b540aSrobert     pbackfail(int_type __i)
341*404b540aSrobert     {
342*404b540aSrobert       int_type __ret = traits_type::eof();
343*404b540aSrobert       const bool __testin = _M_mode & ios_base::in;
344*404b540aSrobert       if (__testin && !_M_writing)
345*404b540aSrobert 	{
346*404b540aSrobert 	  // Remember whether the pback buffer is active, otherwise below
347*404b540aSrobert 	  // we may try to store in it a second char (libstdc++/9761).
348*404b540aSrobert 	  const bool __testpb = _M_pback_init;
349*404b540aSrobert 	  const bool __testeof = traits_type::eq_int_type(__i, __ret);
350*404b540aSrobert 	  int_type __tmp;
351*404b540aSrobert 	  if (this->eback() < this->gptr())
352*404b540aSrobert 	    {
353*404b540aSrobert 	      this->gbump(-1);
354*404b540aSrobert 	      __tmp = traits_type::to_int_type(*this->gptr());
355*404b540aSrobert 	    }
356*404b540aSrobert 	  else if (this->seekoff(-1, ios_base::cur) != pos_type(off_type(-1)))
357*404b540aSrobert 	    {
358*404b540aSrobert 	      __tmp = this->underflow();
359*404b540aSrobert 	      if (traits_type::eq_int_type(__tmp, __ret))
360*404b540aSrobert 		return __ret;
361*404b540aSrobert 	    }
362*404b540aSrobert 	  else
363*404b540aSrobert 	    {
364*404b540aSrobert 	      // At the beginning of the buffer, need to make a
365*404b540aSrobert 	      // putback position available.  But the seek may fail
366*404b540aSrobert 	      // (f.i., at the beginning of a file, see
367*404b540aSrobert 	      // libstdc++/9439) and in that case we return
368*404b540aSrobert 	      // traits_type::eof().
369*404b540aSrobert 	      return __ret;
370*404b540aSrobert 	    }
371*404b540aSrobert 
372*404b540aSrobert 	  // Try to put back __i into input sequence in one of three ways.
373*404b540aSrobert 	  // Order these tests done in is unspecified by the standard.
374*404b540aSrobert 	  if (!__testeof && traits_type::eq_int_type(__i, __tmp))
375*404b540aSrobert 	    __ret = __i;
376*404b540aSrobert 	  else if (__testeof)
377*404b540aSrobert 	    __ret = traits_type::not_eof(__i);
378*404b540aSrobert 	  else if (!__testpb)
379*404b540aSrobert 	    {
380*404b540aSrobert 	      _M_create_pback();
381*404b540aSrobert 	      _M_reading = true;
382*404b540aSrobert 	      *this->gptr() = traits_type::to_char_type(__i);
383*404b540aSrobert 	      __ret = __i;
384*404b540aSrobert 	    }
385*404b540aSrobert 	}
386*404b540aSrobert       return __ret;
387*404b540aSrobert     }
388*404b540aSrobert 
389*404b540aSrobert   template<typename _CharT, typename _Traits>
390*404b540aSrobert     typename basic_filebuf<_CharT, _Traits>::int_type
391*404b540aSrobert     basic_filebuf<_CharT, _Traits>::
overflow(int_type __c)392*404b540aSrobert     overflow(int_type __c)
393*404b540aSrobert     {
394*404b540aSrobert       int_type __ret = traits_type::eof();
395*404b540aSrobert       const bool __testeof = traits_type::eq_int_type(__c, __ret);
396*404b540aSrobert       const bool __testout = _M_mode & ios_base::out;
397*404b540aSrobert       if (__testout && !_M_reading)
398*404b540aSrobert 	{
399*404b540aSrobert 	  if (this->pbase() < this->pptr())
400*404b540aSrobert 	    {
401*404b540aSrobert 	      // If appropriate, append the overflow char.
402*404b540aSrobert 	      if (!__testeof)
403*404b540aSrobert 		{
404*404b540aSrobert 		  *this->pptr() = traits_type::to_char_type(__c);
405*404b540aSrobert 		  this->pbump(1);
406*404b540aSrobert 		}
407*404b540aSrobert 
408*404b540aSrobert 	      // Convert pending sequence to external representation,
409*404b540aSrobert 	      // and output.
410*404b540aSrobert 	      if (_M_convert_to_external(this->pbase(),
411*404b540aSrobert 					 this->pptr() - this->pbase()))
412*404b540aSrobert 		{
413*404b540aSrobert 		  _M_set_buffer(0);
414*404b540aSrobert 		  __ret = traits_type::not_eof(__c);
415*404b540aSrobert 		}
416*404b540aSrobert 	    }
417*404b540aSrobert 	  else if (_M_buf_size > 1)
418*404b540aSrobert 	    {
419*404b540aSrobert 	      // Overflow in 'uncommitted' mode: set _M_writing, set
420*404b540aSrobert 	      // the buffer to the initial 'write' mode, and put __c
421*404b540aSrobert 	      // into the buffer.
422*404b540aSrobert 	      _M_set_buffer(0);
423*404b540aSrobert 	      _M_writing = true;
424*404b540aSrobert 	      if (!__testeof)
425*404b540aSrobert 		{
426*404b540aSrobert 		  *this->pptr() = traits_type::to_char_type(__c);
427*404b540aSrobert 		  this->pbump(1);
428*404b540aSrobert 		}
429*404b540aSrobert 	      __ret = traits_type::not_eof(__c);
430*404b540aSrobert 	    }
431*404b540aSrobert 	  else
432*404b540aSrobert 	    {
433*404b540aSrobert 	      // Unbuffered.
434*404b540aSrobert 	      char_type __conv = traits_type::to_char_type(__c);
435*404b540aSrobert 	      if (__testeof || _M_convert_to_external(&__conv, 1))
436*404b540aSrobert 		{
437*404b540aSrobert 		  _M_writing = true;
438*404b540aSrobert 		  __ret = traits_type::not_eof(__c);
439*404b540aSrobert 		}
440*404b540aSrobert 	    }
441*404b540aSrobert 	}
442*404b540aSrobert       return __ret;
443*404b540aSrobert     }
444*404b540aSrobert 
445*404b540aSrobert   template<typename _CharT, typename _Traits>
446*404b540aSrobert     bool
447*404b540aSrobert     basic_filebuf<_CharT, _Traits>::
_M_convert_to_external(_CharT * __ibuf,streamsize __ilen)448*404b540aSrobert     _M_convert_to_external(_CharT* __ibuf, streamsize __ilen)
449*404b540aSrobert     {
450*404b540aSrobert       // Sizes of external and pending output.
451*404b540aSrobert       streamsize __elen;
452*404b540aSrobert       streamsize __plen;
453*404b540aSrobert       if (__check_facet(_M_codecvt).always_noconv())
454*404b540aSrobert 	{
455*404b540aSrobert 	  __elen = _M_file.xsputn(reinterpret_cast<char*>(__ibuf), __ilen);
456*404b540aSrobert 	  __plen = __ilen;
457*404b540aSrobert 	}
458*404b540aSrobert       else
459*404b540aSrobert 	{
460*404b540aSrobert 	  // Worst-case number of external bytes needed.
461*404b540aSrobert 	  // XXX Not done encoding() == -1.
462*404b540aSrobert 	  streamsize __blen = __ilen * _M_codecvt->max_length();
463*404b540aSrobert 	  char* __buf = static_cast<char*>(__builtin_alloca(__blen));
464*404b540aSrobert 
465*404b540aSrobert 	  char* __bend;
466*404b540aSrobert 	  const char_type* __iend;
467*404b540aSrobert 	  codecvt_base::result __r;
468*404b540aSrobert 	  __r = _M_codecvt->out(_M_state_cur, __ibuf, __ibuf + __ilen,
469*404b540aSrobert 				__iend, __buf, __buf + __blen, __bend);
470*404b540aSrobert 
471*404b540aSrobert 	  if (__r == codecvt_base::ok || __r == codecvt_base::partial)
472*404b540aSrobert 	    __blen = __bend - __buf;
473*404b540aSrobert 	  else if (__r == codecvt_base::noconv)
474*404b540aSrobert 	    {
475*404b540aSrobert 	      // Same as the always_noconv case above.
476*404b540aSrobert 	      __buf = reinterpret_cast<char*>(__ibuf);
477*404b540aSrobert 	      __blen = __ilen;
478*404b540aSrobert 	    }
479*404b540aSrobert 	  else
480*404b540aSrobert 	    __throw_ios_failure(__N("basic_filebuf::_M_convert_to_external "
481*404b540aSrobert 				    "conversion error"));
482*404b540aSrobert 
483*404b540aSrobert 	  __elen = _M_file.xsputn(__buf, __blen);
484*404b540aSrobert 	  __plen = __blen;
485*404b540aSrobert 
486*404b540aSrobert 	  // Try once more for partial conversions.
487*404b540aSrobert 	  if (__r == codecvt_base::partial && __elen == __plen)
488*404b540aSrobert 	    {
489*404b540aSrobert 	      const char_type* __iresume = __iend;
490*404b540aSrobert 	      streamsize __rlen = this->pptr() - __iend;
491*404b540aSrobert 	      __r = _M_codecvt->out(_M_state_cur, __iresume,
492*404b540aSrobert 				    __iresume + __rlen, __iend, __buf,
493*404b540aSrobert 				    __buf + __blen, __bend);
494*404b540aSrobert 	      if (__r != codecvt_base::error)
495*404b540aSrobert 		{
496*404b540aSrobert 		  __rlen = __bend - __buf;
497*404b540aSrobert 		  __elen = _M_file.xsputn(__buf, __rlen);
498*404b540aSrobert 		  __plen = __rlen;
499*404b540aSrobert 		}
500*404b540aSrobert 	      else
501*404b540aSrobert 		__throw_ios_failure(__N("basic_filebuf::_M_convert_to_external "
502*404b540aSrobert 					"conversion error"));
503*404b540aSrobert 	    }
504*404b540aSrobert 	}
505*404b540aSrobert       return __elen == __plen;
506*404b540aSrobert     }
507*404b540aSrobert 
508*404b540aSrobert    template<typename _CharT, typename _Traits>
509*404b540aSrobert      streamsize
510*404b540aSrobert      basic_filebuf<_CharT, _Traits>::
xsgetn(_CharT * __s,streamsize __n)511*404b540aSrobert      xsgetn(_CharT* __s, streamsize __n)
512*404b540aSrobert      {
513*404b540aSrobert        // Clear out pback buffer before going on to the real deal...
514*404b540aSrobert        streamsize __ret = 0;
515*404b540aSrobert        if (_M_pback_init)
516*404b540aSrobert 	 {
517*404b540aSrobert 	   if (__n > 0 && this->gptr() == this->eback())
518*404b540aSrobert 	     {
519*404b540aSrobert 	       *__s++ = *this->gptr();
520*404b540aSrobert 	       this->gbump(1);
521*404b540aSrobert 	       __ret = 1;
522*404b540aSrobert 	       --__n;
523*404b540aSrobert 	     }
524*404b540aSrobert 	   _M_destroy_pback();
525*404b540aSrobert 	 }
526*404b540aSrobert 
527*404b540aSrobert        // Optimization in the always_noconv() case, to be generalized in the
528*404b540aSrobert        // future: when __n > __buflen we read directly instead of using the
529*404b540aSrobert        // buffer repeatedly.
530*404b540aSrobert        const bool __testin = _M_mode & ios_base::in;
531*404b540aSrobert        const streamsize __buflen = _M_buf_size > 1 ? _M_buf_size - 1 : 1;
532*404b540aSrobert 
533*404b540aSrobert        if (__n > __buflen && __check_facet(_M_codecvt).always_noconv()
534*404b540aSrobert 	   && __testin && !_M_writing)
535*404b540aSrobert 	 {
536*404b540aSrobert 	   // First, copy the chars already present in the buffer.
537*404b540aSrobert 	   const streamsize __avail = this->egptr() - this->gptr();
538*404b540aSrobert 	   if (__avail != 0)
539*404b540aSrobert 	     {
540*404b540aSrobert 	       if (__avail == 1)
541*404b540aSrobert 		 *__s = *this->gptr();
542*404b540aSrobert 	       else
543*404b540aSrobert 		 traits_type::copy(__s, this->gptr(), __avail);
544*404b540aSrobert 	       __s += __avail;
545*404b540aSrobert 	       this->gbump(__avail);
546*404b540aSrobert 	       __ret += __avail;
547*404b540aSrobert 	       __n -= __avail;
548*404b540aSrobert 	     }
549*404b540aSrobert 
550*404b540aSrobert 	   // Need to loop in case of short reads (relatively common
551*404b540aSrobert 	   // with pipes).
552*404b540aSrobert 	   streamsize __len;
553*404b540aSrobert 	   for (;;)
554*404b540aSrobert 	     {
555*404b540aSrobert 	       __len = _M_file.xsgetn(reinterpret_cast<char*>(__s),
556*404b540aSrobert 				      __n);
557*404b540aSrobert 	       if (__len == -1)
558*404b540aSrobert 		 __throw_ios_failure(__N("basic_filebuf::xsgetn "
559*404b540aSrobert 					 "error reading the file"));
560*404b540aSrobert 	       if (__len == 0)
561*404b540aSrobert 		 break;
562*404b540aSrobert 
563*404b540aSrobert 	       __n -= __len;
564*404b540aSrobert 	       __ret += __len;
565*404b540aSrobert 	       if (__n == 0)
566*404b540aSrobert 		 break;
567*404b540aSrobert 
568*404b540aSrobert 	       __s += __len;
569*404b540aSrobert 	     }
570*404b540aSrobert 
571*404b540aSrobert 	   if (__n == 0)
572*404b540aSrobert 	     {
573*404b540aSrobert 	       _M_set_buffer(0);
574*404b540aSrobert 	       _M_reading = true;
575*404b540aSrobert 	     }
576*404b540aSrobert 	   else if (__len == 0)
577*404b540aSrobert 	     {
578*404b540aSrobert 	       // If end of file is reached, set 'uncommitted'
579*404b540aSrobert 	       // mode, thus allowing an immediate write without
580*404b540aSrobert 	       // an intervening seek.
581*404b540aSrobert 	       _M_set_buffer(-1);
582*404b540aSrobert 	       _M_reading = false;
583*404b540aSrobert 	     }
584*404b540aSrobert 	 }
585*404b540aSrobert        else
586*404b540aSrobert 	 __ret += __streambuf_type::xsgetn(__s, __n);
587*404b540aSrobert 
588*404b540aSrobert        return __ret;
589*404b540aSrobert      }
590*404b540aSrobert 
591*404b540aSrobert    template<typename _CharT, typename _Traits>
592*404b540aSrobert      streamsize
593*404b540aSrobert      basic_filebuf<_CharT, _Traits>::
xsputn(const _CharT * __s,streamsize __n)594*404b540aSrobert      xsputn(const _CharT* __s, streamsize __n)
595*404b540aSrobert      {
596*404b540aSrobert        // Optimization in the always_noconv() case, to be generalized in the
597*404b540aSrobert        // future: when __n is sufficiently large we write directly instead of
598*404b540aSrobert        // using the buffer.
599*404b540aSrobert        streamsize __ret = 0;
600*404b540aSrobert        const bool __testout = _M_mode & ios_base::out;
601*404b540aSrobert        if (__check_facet(_M_codecvt).always_noconv()
602*404b540aSrobert 	   && __testout && !_M_reading)
603*404b540aSrobert 	{
604*404b540aSrobert 	  // Measurement would reveal the best choice.
605*404b540aSrobert 	  const streamsize __chunk = 1ul << 10;
606*404b540aSrobert 	  streamsize __bufavail = this->epptr() - this->pptr();
607*404b540aSrobert 
608*404b540aSrobert 	  // Don't mistake 'uncommitted' mode buffered with unbuffered.
609*404b540aSrobert 	  if (!_M_writing && _M_buf_size > 1)
610*404b540aSrobert 	    __bufavail = _M_buf_size - 1;
611*404b540aSrobert 
612*404b540aSrobert 	  const streamsize __limit = std::min(__chunk, __bufavail);
613*404b540aSrobert 	  if (__n >= __limit)
614*404b540aSrobert 	    {
615*404b540aSrobert 	      const streamsize __buffill = this->pptr() - this->pbase();
616*404b540aSrobert 	      const char* __buf = reinterpret_cast<const char*>(this->pbase());
617*404b540aSrobert 	      __ret = _M_file.xsputn_2(__buf, __buffill,
618*404b540aSrobert 				       reinterpret_cast<const char*>(__s),
619*404b540aSrobert 				       __n);
620*404b540aSrobert 	      if (__ret == __buffill + __n)
621*404b540aSrobert 		{
622*404b540aSrobert 		  _M_set_buffer(0);
623*404b540aSrobert 		  _M_writing = true;
624*404b540aSrobert 		}
625*404b540aSrobert 	      if (__ret > __buffill)
626*404b540aSrobert 		__ret -= __buffill;
627*404b540aSrobert 	      else
628*404b540aSrobert 		__ret = 0;
629*404b540aSrobert 	    }
630*404b540aSrobert 	  else
631*404b540aSrobert 	    __ret = __streambuf_type::xsputn(__s, __n);
632*404b540aSrobert 	}
633*404b540aSrobert        else
634*404b540aSrobert 	 __ret = __streambuf_type::xsputn(__s, __n);
635*404b540aSrobert        return __ret;
636*404b540aSrobert     }
637*404b540aSrobert 
638*404b540aSrobert   template<typename _CharT, typename _Traits>
639*404b540aSrobert     typename basic_filebuf<_CharT, _Traits>::__streambuf_type*
640*404b540aSrobert     basic_filebuf<_CharT, _Traits>::
setbuf(char_type * __s,streamsize __n)641*404b540aSrobert     setbuf(char_type* __s, streamsize __n)
642*404b540aSrobert     {
643*404b540aSrobert       if (!this->is_open())
644*404b540aSrobert 	if (__s == 0 && __n == 0)
645*404b540aSrobert 	  _M_buf_size = 1;
646*404b540aSrobert 	else if (__s && __n > 0)
647*404b540aSrobert 	  {
648*404b540aSrobert 	    // This is implementation-defined behavior, and assumes that
649*404b540aSrobert 	    // an external char_type array of length __n exists and has
650*404b540aSrobert 	    // been pre-allocated. If this is not the case, things will
651*404b540aSrobert 	    // quickly blow up. When __n > 1, __n - 1 positions will be
652*404b540aSrobert 	    // used for the get area, __n - 1 for the put area and 1
653*404b540aSrobert 	    // position to host the overflow char of a full put area.
654*404b540aSrobert 	    // When __n == 1, 1 position will be used for the get area
655*404b540aSrobert 	    // and 0 for the put area, as in the unbuffered case above.
656*404b540aSrobert 	    _M_buf = __s;
657*404b540aSrobert 	    _M_buf_size = __n;
658*404b540aSrobert 	  }
659*404b540aSrobert       return this;
660*404b540aSrobert     }
661*404b540aSrobert 
662*404b540aSrobert 
663*404b540aSrobert   // According to 27.8.1.4 p11 - 13, seekoff should ignore the last
664*404b540aSrobert   // argument (of type openmode).
665*404b540aSrobert   template<typename _CharT, typename _Traits>
666*404b540aSrobert     typename basic_filebuf<_CharT, _Traits>::pos_type
667*404b540aSrobert     basic_filebuf<_CharT, _Traits>::
seekoff(off_type __off,ios_base::seekdir __way,ios_base::openmode)668*404b540aSrobert     seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode)
669*404b540aSrobert     {
670*404b540aSrobert       int __width = 0;
671*404b540aSrobert       if (_M_codecvt)
672*404b540aSrobert 	__width = _M_codecvt->encoding();
673*404b540aSrobert       if (__width < 0)
674*404b540aSrobert 	__width = 0;
675*404b540aSrobert 
676*404b540aSrobert       pos_type __ret =  pos_type(off_type(-1));
677*404b540aSrobert       const bool __testfail = __off != 0 && __width <= 0;
678*404b540aSrobert       if (this->is_open() && !__testfail)
679*404b540aSrobert 	{
680*404b540aSrobert 	  // Ditch any pback buffers to avoid confusion.
681*404b540aSrobert 	  _M_destroy_pback();
682*404b540aSrobert 
683*404b540aSrobert 	  // Correct state at destination. Note that this is the correct
684*404b540aSrobert 	  // state for the current position during output, because
685*404b540aSrobert 	  // codecvt::unshift() returns the state to the initial state.
686*404b540aSrobert 	  // This is also the correct state at the end of the file because
687*404b540aSrobert 	  // an unshift sequence should have been written at the end.
688*404b540aSrobert 	  __state_type __state = _M_state_beg;
689*404b540aSrobert 	  off_type __computed_off = __off * __width;
690*404b540aSrobert 	  if (_M_reading && __way == ios_base::cur)
691*404b540aSrobert 	    {
692*404b540aSrobert 	      if (_M_codecvt->always_noconv())
693*404b540aSrobert 		__computed_off += this->gptr() - this->egptr();
694*404b540aSrobert 	      else
695*404b540aSrobert 		{
696*404b540aSrobert 		  // Calculate offset from _M_ext_buf that corresponds
697*404b540aSrobert 		  // to gptr(). Note: uses _M_state_last, which
698*404b540aSrobert 		  // corresponds to eback().
699*404b540aSrobert 		  const int __gptr_off =
700*404b540aSrobert 		    _M_codecvt->length(_M_state_last, _M_ext_buf, _M_ext_next,
701*404b540aSrobert 				       this->gptr() - this->eback());
702*404b540aSrobert 		  __computed_off += _M_ext_buf + __gptr_off - _M_ext_end;
703*404b540aSrobert 
704*404b540aSrobert 		  // _M_state_last is modified by codecvt::length() so
705*404b540aSrobert 		  // it now corresponds to gptr().
706*404b540aSrobert 		  __state = _M_state_last;
707*404b540aSrobert 		}
708*404b540aSrobert 	    }
709*404b540aSrobert 	  __ret = _M_seek(__computed_off, __way, __state);
710*404b540aSrobert 	}
711*404b540aSrobert       return __ret;
712*404b540aSrobert     }
713*404b540aSrobert 
714*404b540aSrobert   // _GLIBCXX_RESOLVE_LIB_DEFECTS
715*404b540aSrobert   // 171. Strange seekpos() semantics due to joint position
716*404b540aSrobert   // According to the resolution of DR 171, seekpos should ignore the last
717*404b540aSrobert   // argument (of type openmode).
718*404b540aSrobert   template<typename _CharT, typename _Traits>
719*404b540aSrobert     typename basic_filebuf<_CharT, _Traits>::pos_type
720*404b540aSrobert     basic_filebuf<_CharT, _Traits>::
seekpos(pos_type __pos,ios_base::openmode)721*404b540aSrobert     seekpos(pos_type __pos, ios_base::openmode)
722*404b540aSrobert     {
723*404b540aSrobert       pos_type __ret =  pos_type(off_type(-1));
724*404b540aSrobert       if (this->is_open())
725*404b540aSrobert 	{
726*404b540aSrobert 	  // Ditch any pback buffers to avoid confusion.
727*404b540aSrobert 	  _M_destroy_pback();
728*404b540aSrobert 	  __ret = _M_seek(off_type(__pos), ios_base::beg, __pos.state());
729*404b540aSrobert 	}
730*404b540aSrobert       return __ret;
731*404b540aSrobert     }
732*404b540aSrobert 
733*404b540aSrobert   template<typename _CharT, typename _Traits>
734*404b540aSrobert     typename basic_filebuf<_CharT, _Traits>::pos_type
735*404b540aSrobert     basic_filebuf<_CharT, _Traits>::
_M_seek(off_type __off,ios_base::seekdir __way,__state_type __state)736*404b540aSrobert     _M_seek(off_type __off, ios_base::seekdir __way, __state_type __state)
737*404b540aSrobert     {
738*404b540aSrobert       pos_type __ret = pos_type(off_type(-1));
739*404b540aSrobert       if (_M_terminate_output())
740*404b540aSrobert 	{
741*404b540aSrobert 	  // Returns pos_type(off_type(-1)) in case of failure.
742*404b540aSrobert 	  __ret = pos_type(_M_file.seekoff(__off, __way));
743*404b540aSrobert 	  if (__ret != pos_type(off_type(-1)))
744*404b540aSrobert 	    {
745*404b540aSrobert 	      _M_reading = false;
746*404b540aSrobert 	      _M_writing = false;
747*404b540aSrobert 	      _M_ext_next = _M_ext_end = _M_ext_buf;
748*404b540aSrobert 	      _M_set_buffer(-1);
749*404b540aSrobert 	      _M_state_cur = __state;
750*404b540aSrobert 	      __ret.state(_M_state_cur);
751*404b540aSrobert 	    }
752*404b540aSrobert 	}
753*404b540aSrobert       return __ret;
754*404b540aSrobert     }
755*404b540aSrobert 
756*404b540aSrobert   template<typename _CharT, typename _Traits>
757*404b540aSrobert     bool
758*404b540aSrobert     basic_filebuf<_CharT, _Traits>::
_M_terminate_output()759*404b540aSrobert     _M_terminate_output()
760*404b540aSrobert     {
761*404b540aSrobert       // Part one: update the output sequence.
762*404b540aSrobert       bool __testvalid = true;
763*404b540aSrobert       if (this->pbase() < this->pptr())
764*404b540aSrobert 	{
765*404b540aSrobert 	  const int_type __tmp = this->overflow();
766*404b540aSrobert 	  if (traits_type::eq_int_type(__tmp, traits_type::eof()))
767*404b540aSrobert 	    __testvalid = false;
768*404b540aSrobert 	}
769*404b540aSrobert 
770*404b540aSrobert       // Part two: output unshift sequence.
771*404b540aSrobert       if (_M_writing && !__check_facet(_M_codecvt).always_noconv()
772*404b540aSrobert 	  && __testvalid)
773*404b540aSrobert 	{
774*404b540aSrobert 	  // Note: this value is arbitrary, since there is no way to
775*404b540aSrobert 	  // get the length of the unshift sequence from codecvt,
776*404b540aSrobert 	  // without calling unshift.
777*404b540aSrobert 	  const size_t __blen = 128;
778*404b540aSrobert 	  char __buf[__blen];
779*404b540aSrobert 	  codecvt_base::result __r;
780*404b540aSrobert 	  streamsize __ilen = 0;
781*404b540aSrobert 
782*404b540aSrobert 	  do
783*404b540aSrobert 	    {
784*404b540aSrobert 	      char* __next;
785*404b540aSrobert 	      __r = _M_codecvt->unshift(_M_state_cur, __buf,
786*404b540aSrobert 					__buf + __blen, __next);
787*404b540aSrobert 	      if (__r == codecvt_base::error)
788*404b540aSrobert 		__testvalid = false;
789*404b540aSrobert 	      else if (__r == codecvt_base::ok ||
790*404b540aSrobert 		       __r == codecvt_base::partial)
791*404b540aSrobert 		{
792*404b540aSrobert 		  __ilen = __next - __buf;
793*404b540aSrobert 		  if (__ilen > 0)
794*404b540aSrobert 		    {
795*404b540aSrobert 		      const streamsize __elen = _M_file.xsputn(__buf, __ilen);
796*404b540aSrobert 		      if (__elen != __ilen)
797*404b540aSrobert 			__testvalid = false;
798*404b540aSrobert 		    }
799*404b540aSrobert 		}
800*404b540aSrobert 	    }
801*404b540aSrobert 	  while (__r == codecvt_base::partial && __ilen > 0 && __testvalid);
802*404b540aSrobert 
803*404b540aSrobert 	  if (__testvalid)
804*404b540aSrobert 	    {
805*404b540aSrobert 	      // This second call to overflow() is required by the standard,
806*404b540aSrobert 	      // but it's not clear why it's needed, since the output buffer
807*404b540aSrobert 	      // should be empty by this point (it should have been emptied
808*404b540aSrobert 	      // in the first call to overflow()).
809*404b540aSrobert 	      const int_type __tmp = this->overflow();
810*404b540aSrobert 	      if (traits_type::eq_int_type(__tmp, traits_type::eof()))
811*404b540aSrobert 		__testvalid = false;
812*404b540aSrobert 	    }
813*404b540aSrobert 	}
814*404b540aSrobert       return __testvalid;
815*404b540aSrobert     }
816*404b540aSrobert 
817*404b540aSrobert   template<typename _CharT, typename _Traits>
818*404b540aSrobert     int
819*404b540aSrobert     basic_filebuf<_CharT, _Traits>::
sync()820*404b540aSrobert     sync()
821*404b540aSrobert     {
822*404b540aSrobert       // Make sure that the internal buffer resyncs its idea of
823*404b540aSrobert       // the file position with the external file.
824*404b540aSrobert       int __ret = 0;
825*404b540aSrobert       if (this->pbase() < this->pptr())
826*404b540aSrobert 	{
827*404b540aSrobert 	  const int_type __tmp = this->overflow();
828*404b540aSrobert 	  if (traits_type::eq_int_type(__tmp, traits_type::eof()))
829*404b540aSrobert 	    __ret = -1;
830*404b540aSrobert 	}
831*404b540aSrobert       return __ret;
832*404b540aSrobert     }
833*404b540aSrobert 
834*404b540aSrobert   template<typename _CharT, typename _Traits>
835*404b540aSrobert     void
836*404b540aSrobert     basic_filebuf<_CharT, _Traits>::
imbue(const locale & __loc)837*404b540aSrobert     imbue(const locale& __loc)
838*404b540aSrobert     {
839*404b540aSrobert       bool __testvalid = true;
840*404b540aSrobert 
841*404b540aSrobert       const __codecvt_type* _M_codecvt_tmp = 0;
842*404b540aSrobert       if (__builtin_expect(has_facet<__codecvt_type>(__loc), true))
843*404b540aSrobert 	_M_codecvt_tmp = &use_facet<__codecvt_type>(__loc);
844*404b540aSrobert 
845*404b540aSrobert       if (this->is_open())
846*404b540aSrobert 	{
847*404b540aSrobert 	  // encoding() == -1 is ok only at the beginning.
848*404b540aSrobert 	  if ((_M_reading || _M_writing)
849*404b540aSrobert 	      && __check_facet(_M_codecvt).encoding() == -1)
850*404b540aSrobert 	    __testvalid = false;
851*404b540aSrobert 	  else
852*404b540aSrobert 	    {
853*404b540aSrobert 	      if (_M_reading)
854*404b540aSrobert 		{
855*404b540aSrobert 		  if (__check_facet(_M_codecvt).always_noconv())
856*404b540aSrobert 		    {
857*404b540aSrobert 		      if (_M_codecvt_tmp
858*404b540aSrobert 			  && !__check_facet(_M_codecvt_tmp).always_noconv())
859*404b540aSrobert 			__testvalid = this->seekoff(0, ios_base::cur, _M_mode)
860*404b540aSrobert 			              != pos_type(off_type(-1));
861*404b540aSrobert 		    }
862*404b540aSrobert 		  else
863*404b540aSrobert 		    {
864*404b540aSrobert 		      // External position corresponding to gptr().
865*404b540aSrobert 		      _M_ext_next = _M_ext_buf
866*404b540aSrobert 			+ _M_codecvt->length(_M_state_last, _M_ext_buf, _M_ext_next,
867*404b540aSrobert 					     this->gptr() - this->eback());
868*404b540aSrobert 		      const streamsize __remainder = _M_ext_end - _M_ext_next;
869*404b540aSrobert 		      if (__remainder)
870*404b540aSrobert 			std::memmove(_M_ext_buf, _M_ext_next, __remainder);
871*404b540aSrobert 
872*404b540aSrobert 		      _M_ext_next = _M_ext_buf;
873*404b540aSrobert 		      _M_ext_end = _M_ext_buf + __remainder;
874*404b540aSrobert 		      _M_set_buffer(-1);
875*404b540aSrobert 		      _M_state_last = _M_state_cur = _M_state_beg;
876*404b540aSrobert 		    }
877*404b540aSrobert 		}
878*404b540aSrobert 	      else if (_M_writing && (__testvalid = _M_terminate_output()))
879*404b540aSrobert 		_M_set_buffer(-1);
880*404b540aSrobert 	    }
881*404b540aSrobert 	}
882*404b540aSrobert 
883*404b540aSrobert       if (__testvalid)
884*404b540aSrobert 	_M_codecvt = _M_codecvt_tmp;
885*404b540aSrobert       else
886*404b540aSrobert 	_M_codecvt = 0;
887*404b540aSrobert     }
888*404b540aSrobert 
889*404b540aSrobert   // Inhibit implicit instantiations for required instantiations,
890*404b540aSrobert   // which are defined via explicit instantiations elsewhere.
891*404b540aSrobert   // NB:  This syntax is a GNU extension.
892*404b540aSrobert #if _GLIBCXX_EXTERN_TEMPLATE
893*404b540aSrobert   extern template class basic_filebuf<char>;
894*404b540aSrobert   extern template class basic_ifstream<char>;
895*404b540aSrobert   extern template class basic_ofstream<char>;
896*404b540aSrobert   extern template class basic_fstream<char>;
897*404b540aSrobert 
898*404b540aSrobert #ifdef _GLIBCXX_USE_WCHAR_T
899*404b540aSrobert   extern template class basic_filebuf<wchar_t>;
900*404b540aSrobert   extern template class basic_ifstream<wchar_t>;
901*404b540aSrobert   extern template class basic_ofstream<wchar_t>;
902*404b540aSrobert   extern template class basic_fstream<wchar_t>;
903*404b540aSrobert #endif
904*404b540aSrobert #endif
905*404b540aSrobert 
906*404b540aSrobert _GLIBCXX_END_NAMESPACE
907*404b540aSrobert 
908*404b540aSrobert #endif
909