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