OSDN Git Service

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