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