Clang Project

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