# fstream.tcc

Go to the documentation of this file.

    00001 // File based streams -*- C++ -*-
    00002
    00003 // Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
    00004 // 2007
    00005 // Free Software Foundation, Inc.
    00006 //
    00007 // This file is part of the GNU ISO C++ Library.  This library is free
    00008 // software; you can redistribute it and/or modify it under the
    00009 // terms of the GNU General Public License as published by the
    00010 // Free Software Foundation; either version 2, or (at your option)
    00011 // any later version.
    00012
    00013 // This library is distributed in the hope that it will be useful,
    00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of
    00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    00016 // GNU General Public License for more details.
    00017
    00018 // You should have received a copy of the GNU General Public License along
    00019 // with this library; see the file COPYING.  If not, write to the Free
    00020 // Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
    00021 // USA.
    00022
    00023 // As a special exception, you may use this file as part of a free software
    00024 // library without restriction.  Specifically, if other files instantiate
    00025 // templates or use macros or inline functions from this file, or you compile
    00026 // this file and link it with other files to produce an executable, this
    00027 // file does not by itself cause the resulting executable to be covered by
    00028 // the GNU General Public License.  This exception does not however
    00029 // invalidate any other reasons why the executable file might be covered by
    00030 // the GNU General Public License.
    00031
    00032 /** @file fstream.tcc
    00033  *  This is an internal header file, included by other library headers.
    00034  *  You should not attempt to use it directly.
    00035  */
    00036
    00037 //
    00038 // ISO C++ 14882: 27.8  File-based streams
    00039 //
    00040
    00041 #ifndef _FSTREAM_TCC
    00042 #define _FSTREAM_TCC 1
    00043
    00044 #pragma GCC system_header
    00045
    00046 #include <cxxabi-forced.h>
    00047
    00048 _GLIBCXX_BEGIN_NAMESPACE(std)
    00049
    00050   template<typename _CharT, typename _Traits>
    00051     void
    00052     basic_filebuf<_CharT, _Traits>::
    00053     _M_allocate_internal_buffer()
    00054     {
    00055       // Allocate internal buffer only if one doesn't already exist
    00056       // (either allocated or provided by the user via setbuf).
    00057       if (!_M_buf_allocated && !_M_buf)
    00058     {
    00059       _M_buf = new char_type[_M_buf_size];
    00060       _M_buf_allocated = true;
    00061     }
    00062     }
    00063
    00064   template<typename _CharT, typename _Traits>
    00065     void
    00066     basic_filebuf<_CharT, _Traits>::
    00067     _M_destroy_internal_buffer() throw()
    00068     {
    00069       if (_M_buf_allocated)
    00070     {
    00071       delete [] _M_buf;
    00072       _M_buf = NULL;
    00073       _M_buf_allocated = false;
    00074     }
    00075       delete [] _M_ext_buf;
    00076       _M_ext_buf = NULL;
    00077       _M_ext_buf_size = 0;
    00078       _M_ext_next = NULL;
    00079       _M_ext_end = NULL;
    00080     }
    00081
    00082   template<typename _CharT, typename _Traits>
    00083     basic_filebuf<_CharT, _Traits>::
    00084     basic_filebuf() : __streambuf_type(), _M_lock(), _M_file(&_M_lock),
    00085     _M_mode(ios_base::openmode(0)), _M_state_beg(), _M_state_cur(),
    00086     _M_state_last(), _M_buf(NULL), _M_buf_size(BUFSIZ),
    00087     _M_buf_allocated(false), _M_reading(false), _M_writing(false), _M_pback(),
    00088     _M_pback_cur_save(0), _M_pback_end_save(0), _M_pback_init(false),
    00089     _M_codecvt(0), _M_ext_buf(0), _M_ext_buf_size(0), _M_ext_next(0),
    00090     _M_ext_end(0)
    00091     {
    00092       if (has_facet<__codecvt_type>(this->_M_buf_locale))
    00093     _M_codecvt = &use_facet<__codecvt_type>(this->_M_buf_locale);
    00094     }
    00095
    00096   template<typename _CharT, typename _Traits>
    00097     typename basic_filebuf<_CharT, _Traits>::__filebuf_type*
    00098     basic_filebuf<_CharT, _Traits>::
    00099     open(const char* __s, ios_base::openmode __mode)
    00100     {
    00101       __filebuf_type *__ret = NULL;
    00102       if (!this->is_open())
    00103     {
    00104       _M_file.open(__s, __mode);
    00105       if (this->is_open())
    00106         {
    00107           _M_allocate_internal_buffer();
    00108           _M_mode = __mode;
    00109
    00110           // Setup initial buffer to 'uncommitted' mode.
    00111           _M_reading = false;
    00112           _M_writing = false;
    00113           _M_set_buffer(-1);
    00114
    00115           // Reset to initial state.
    00116           _M_state_last = _M_state_cur = _M_state_beg;
    00117
    00118           // 27.8.1.3,4
    00119           if ((__mode & ios_base::ate)
    00120           && this->seekoff(0, ios_base::end, __mode)
    00121           == pos_type(off_type(-1)))
    00122         this->close();
    00123           else
    00124         __ret = this;
    00125         }
    00126     }
    00127       return __ret;
    00128     }
    00129
    00130   template<typename _CharT, typename _Traits>
    00131     typename basic_filebuf<_CharT, _Traits>::__filebuf_type*
    00132     basic_filebuf<_CharT, _Traits>::
    00133     close()
    00134     {
    00135       if (!this->is_open())
    00136     return NULL;
    00137
    00138       bool __testfail = false;
    00139       {
    00140     // NB: Do this here so that re-opened filebufs will be cool...
    00141     struct __close_sentry
    00142     {
    00143       basic_filebuf *__fb;
    00144       __close_sentry (basic_filebuf *__fbi): __fb(__fbi) { }
    00145       ~__close_sentry ()
    00146       {
    00147         __fb->_M_mode = ios_base::openmode(0);
    00148         __fb->_M_pback_init = false;
    00149         __fb->_M_destroy_internal_buffer();
    00150         __fb->_M_reading = false;
    00151         __fb->_M_writing = false;
    00152         __fb->_M_set_buffer(-1);
    00153         __fb->_M_state_last = __fb->_M_state_cur = __fb->_M_state_beg;
    00154       }
    00155     } __cs (this);
    00156
    00157     try
    00158       {
    00159         if (!_M_terminate_output())
    00160           __testfail = true;
    00161       }
    00162     catch(__cxxabiv1::__forced_unwind&)
    00163       {
    00164         _M_file.close();
    00165         __throw_exception_again;
    00166       }
    00167     catch(...)
    00168       { __testfail = true; }
    00169       }
    00170
    00171       if (!_M_file.close())
    00172     __testfail = true;
    00173
    00174       if (__testfail)
    00175     return NULL;
    00176       else
    00177     return this;
    00178     }
    00179
    00180   template<typename _CharT, typename _Traits>
    00181     streamsize
    00182     basic_filebuf<_CharT, _Traits>::
    00183     showmanyc()
    00184     {
    00185       streamsize __ret = -1;
    00186       const bool __testin = _M_mode & ios_base::in;
    00187       if (__testin && this->is_open())
    00188     {
    00189       // For a stateful encoding (-1) the pending sequence might be just
    00190       // shift and unshift prefixes with no actual character.
    00191       __ret = this->egptr() - this->gptr();
    00192
    00193 #if _GLIBCXX_HAVE_DOS_BASED_FILESYSTEM
    00194       // About this workaround, see libstdc++/20806.
    00195       const bool __testbinary = _M_mode & ios_base::binary;
    00196       if (__check_facet(_M_codecvt).encoding() >= 0
    00197           && __testbinary)
    00198 #else
    00199       if (__check_facet(_M_codecvt).encoding() >= 0)
    00200 #endif
    00201         __ret += _M_file.showmanyc() / _M_codecvt->max_length();
    00202     }
    00203       return __ret;
    00204     }
    00205
    00206   template<typename _CharT, typename _Traits>
    00207     typename basic_filebuf<_CharT, _Traits>::int_type
    00208     basic_filebuf<_CharT, _Traits>::
    00209     underflow()
    00210     {
    00211       int_type __ret = traits_type::eof();
    00212       const bool __testin = _M_mode & ios_base::in;
    00213       if (__testin && !_M_writing)
    00214     {
    00215       // Check for pback madness, and if so switch back to the
    00216       // normal buffers and jet outta here before expensive
    00217       // fileops happen...
    00218       _M_destroy_pback();
    00219
    00220       if (this->gptr() < this->egptr())
    00221         return traits_type::to_int_type(*this->gptr());
    00222
    00223       // Get and convert input sequence.
    00224       const size_t __buflen = _M_buf_size > 1 ? _M_buf_size - 1 : 1;
    00225
    00226       // Will be set to true if ::read() returns 0 indicating EOF.
    00227       bool __got_eof = false;
    00228       // Number of internal characters produced.
    00229       streamsize __ilen = 0;
    00230       codecvt_base::result __r = codecvt_base::ok;
    00231       if (__check_facet(_M_codecvt).always_noconv())
    00232         {
    00233           __ilen = _M_file.xsgetn(reinterpret_cast<char*>(this->eback()),
    00234                       __buflen);
    00235           if (__ilen == 0)
    00236         __got_eof = true;
    00237         }
    00238       else
    00239         {
    00240               // Worst-case number of external bytes.
    00241           // XXX Not done encoding() == -1.
    00242           const int __enc = _M_codecvt->encoding();
    00243           streamsize __blen; // Minimum buffer size.
    00244           streamsize __rlen; // Number of chars to read.
    00245           if (__enc > 0)
    00246         __blen = __rlen = __buflen * __enc;
    00247           else
    00248         {
    00249           __blen = __buflen + _M_codecvt->max_length() - 1;
    00250           __rlen = __buflen;
    00251         }
    00252           const streamsize __remainder = _M_ext_end - _M_ext_next;
    00253           __rlen = __rlen > __remainder ? __rlen - __remainder : 0;
    00254
    00255           // An imbue in 'read' mode implies first converting the external
    00256           // chars already present.
    00257           if (_M_reading && this->egptr() == this->eback() && __remainder)
    00258         __rlen = 0;
    00259
    00260           // Allocate buffer if necessary and move unconverted
    00261           // bytes to front.
    00262           if (_M_ext_buf_size < __blen)
    00263         {
    00264           char* __buf = new char[__blen];
    00265           if (__remainder)
    00266             __builtin_memcpy(__buf, _M_ext_next, __remainder);
    00267
    00268           delete [] _M_ext_buf;
    00269           _M_ext_buf = __buf;
    00270           _M_ext_buf_size = __blen;
    00271         }
    00272           else if (__remainder)
    00273         __builtin_memmove(_M_ext_buf, _M_ext_next, __remainder);
    00274
    00275           _M_ext_next = _M_ext_buf;
    00276           _M_ext_end = _M_ext_buf + __remainder;
    00277           _M_state_last = _M_state_cur;
    00278
    00279           do
    00280         {
    00281           if (__rlen > 0)
    00282             {
    00283               // Sanity check!
    00284               // This may fail if the return value of
    00285               // codecvt::max_length() is bogus.
    00286               if (_M_ext_end - _M_ext_buf + __rlen > _M_ext_buf_size)
    00287             {
    00288               __throw_ios_failure(__N("basic_filebuf::underflow "
    00289                           "codecvt::max_length() "
    00290                           "is not valid"));
    00291             }
    00292               streamsize __elen = _M_file.xsgetn(_M_ext_end, __rlen);
    00293               if (__elen == 0)
    00294             __got_eof = true;
    00295               else if (__elen == -1)
    00296             break;
    00297               _M_ext_end += __elen;
    00298             }
    00299
    00300           char_type* __iend = this->eback();
    00301           if (_M_ext_next < _M_ext_end)
    00302             __r = _M_codecvt->in(_M_state_cur, _M_ext_next,
    00303                      _M_ext_end, _M_ext_next,
    00304                      this->eback(),
    00305                      this->eback() + __buflen, __iend);
    00306           if (__r == codecvt_base::noconv)
    00307             {
    00308               size_t __avail = _M_ext_end - _M_ext_buf;
    00309               __ilen = std::min(__avail, __buflen);
    00310               traits_type::copy(this->eback(),
    00311                     reinterpret_cast<char_type*>
    00312                     (_M_ext_buf), __ilen);
    00313               _M_ext_next = _M_ext_buf + __ilen;
    00314             }
    00315           else
    00316             __ilen = __iend - this->eback();
    00317
    00318           // _M_codecvt->in may return error while __ilen > 0: this is
    00319           // ok, and actually occurs in case of mixed encodings (e.g.,
    00320           // XML files).
    00321           if (__r == codecvt_base::error)
    00322             break;
    00323
    00324           __rlen = 1;
    00325         }
    00326           while (__ilen == 0 && !__got_eof);
    00327         }
    00328
    00329       if (__ilen > 0)
    00330         {
    00331           _M_set_buffer(__ilen);
    00332           _M_reading = true;
    00333           __ret = traits_type::to_int_type(*this->gptr());
    00334         }
    00335       else if (__got_eof)
    00336         {
    00337           // If the actual end of file is reached, set 'uncommitted'
    00338           // mode, thus allowing an immediate write without an
    00339           // intervening seek.
    00340           _M_set_buffer(-1);
    00341           _M_reading = false;
    00342           // However, reaching it while looping on partial means that
    00343           // the file has got an incomplete character.
    00344           if (__r == codecvt_base::partial)
    00345         __throw_ios_failure(__N("basic_filebuf::underflow "
    00346                     "incomplete character in file"));
    00347         }
    00348       else if (__r == codecvt_base::error)
    00349         __throw_ios_failure(__N("basic_filebuf::underflow "
    00350                 "invalid byte sequence in file"));
    00351       else
    00352         __throw_ios_failure(__N("basic_filebuf::underflow "
    00353                 "error reading the file"));
    00354     }
    00355       return __ret;
    00356     }
    00357
    00358   template<typename _CharT, typename _Traits>
    00359     typename basic_filebuf<_CharT, _Traits>::int_type
    00360     basic_filebuf<_CharT, _Traits>::
    00361     pbackfail(int_type __i)
    00362     {
    00363       int_type __ret = traits_type::eof();
    00364       const bool __testin = _M_mode & ios_base::in;
    00365       if (__testin && !_M_writing)
    00366     {
    00367       // Remember whether the pback buffer is active, otherwise below
    00368       // we may try to store in it a second char (libstdc++/9761).
    00369       const bool __testpb = _M_pback_init;
    00370       const bool __testeof = traits_type::eq_int_type(__i, __ret);
    00371       int_type __tmp;
    00372       if (this->eback() < this->gptr())
    00373         {
    00374           this->gbump(-1);
    00375           __tmp = traits_type::to_int_type(*this->gptr());
    00376         }
    00377       else if (this->seekoff(-1, ios_base::cur) != pos_type(off_type(-1)))
    00378         {
    00379           __tmp = this->underflow();
    00380           if (traits_type::eq_int_type(__tmp, __ret))
    00381         return __ret;
    00382         }
    00383       else
    00384         {
    00385           // At the beginning of the buffer, need to make a
    00386           // putback position available.  But the seek may fail
    00387           // (f.i., at the beginning of a file, see
    00388           // libstdc++/9439) and in that case we return
    00389           // traits_type::eof().
    00390           return __ret;
    00391         }
    00392
    00393       // Try to put back __i into input sequence in one of three ways.
    00394       // Order these tests done in is unspecified by the standard.
    00395       if (!__testeof && traits_type::eq_int_type(__i, __tmp))
    00396         __ret = __i;
    00397       else if (__testeof)
    00398         __ret = traits_type::not_eof(__i);
    00399       else if (!__testpb)
    00400         {
    00401           _M_create_pback();
    00402           _M_reading = true;
    00403           *this->gptr() = traits_type::to_char_type(__i);
    00404           __ret = __i;
    00405         }
    00406     }
    00407       return __ret;
    00408     }
    00409
    00410   template<typename _CharT, typename _Traits>
    00411     typename basic_filebuf<_CharT, _Traits>::int_type
    00412     basic_filebuf<_CharT, _Traits>::
    00413     overflow(int_type __c)
    00414     {
    00415       int_type __ret = traits_type::eof();
    00416       const bool __testeof = traits_type::eq_int_type(__c, __ret);
    00417       const bool __testout = _M_mode & ios_base::out;
    00418       if (__testout && !_M_reading)
    00419     {
    00420       if (this->pbase() < this->pptr())
    00421         {
    00422           // If appropriate, append the overflow char.
    00423           if (!__testeof)
    00424         {
    00425           *this->pptr() = traits_type::to_char_type(__c);
    00426           this->pbump(1);
    00427         }
    00428
    00429           // Convert pending sequence to external representation,
    00430           // and output.
    00431           if (_M_convert_to_external(this->pbase(),
    00432                      this->pptr() - this->pbase()))
    00433         {
    00434           _M_set_buffer(0);
    00435           __ret = traits_type::not_eof(__c);
    00436         }
    00437         }
    00438       else if (_M_buf_size > 1)
    00439         {
    00440           // Overflow in 'uncommitted' mode: set _M_writing, set
    00441           // the buffer to the initial 'write' mode, and put __c
    00442           // into the buffer.
    00443           _M_set_buffer(0);
    00444           _M_writing = true;
    00445           if (!__testeof)
    00446         {
    00447           *this->pptr() = traits_type::to_char_type(__c);
    00448           this->pbump(1);
    00449         }
    00450           __ret = traits_type::not_eof(__c);
    00451         }
    00452       else
    00453         {
    00454           // Unbuffered.
    00455           char_type __conv = traits_type::to_char_type(__c);
    00456           if (__testeof || _M_convert_to_external(&__conv, 1))
    00457         {
    00458           _M_writing = true;
    00459           __ret = traits_type::not_eof(__c);
    00460         }
    00461         }
    00462     }
    00463       return __ret;
    00464     }
    00465
    00466   template<typename _CharT, typename _Traits>
    00467     bool
    00468     basic_filebuf<_CharT, _Traits>::
    00469     _M_convert_to_external(_CharT* __ibuf, streamsize __ilen)
    00470     {
    00471       // Sizes of external and pending output.
    00472       streamsize __elen;
    00473       streamsize __plen;
    00474       if (__check_facet(_M_codecvt).always_noconv())
    00475     {
    00476       __elen = _M_file.xsputn(reinterpret_cast<char*>(__ibuf), __ilen);
    00477       __plen = __ilen;
    00478     }
    00479       else
    00480     {
    00481       // Worst-case number of external bytes needed.
    00482       // XXX Not done encoding() == -1.
    00483       streamsize __blen = __ilen * _M_codecvt->max_length();
    00484       char* __buf = static_cast<char*>(__builtin_alloca(__blen));
    00485
    00486       char* __bend;
    00487       const char_type* __iend;
    00488       codecvt_base::result __r;
    00489       __r = _M_codecvt->out(_M_state_cur, __ibuf, __ibuf + __ilen,
    00490                 __iend, __buf, __buf + __blen, __bend);
    00491
    00492       if (__r == codecvt_base::ok || __r == codecvt_base::partial)
    00493         __blen = __bend - __buf;
    00494       else if (__r == codecvt_base::noconv)
    00495         {
    00496           // Same as the always_noconv case above.
    00497           __buf = reinterpret_cast<char*>(__ibuf);
    00498           __blen = __ilen;
    00499         }
    00500       else
    00501         __throw_ios_failure(__N("basic_filebuf::_M_convert_to_external "
    00502                     "conversion error"));
    00503
    00504       __elen = _M_file.xsputn(__buf, __blen);
    00505       __plen = __blen;
    00506
    00507       // Try once more for partial conversions.
    00508       if (__r == codecvt_base::partial && __elen == __plen)
    00509         {
    00510           const char_type* __iresume = __iend;
    00511           streamsize __rlen = this->pptr() - __iend;
    00512           __r = _M_codecvt->out(_M_state_cur, __iresume,
    00513                     __iresume + __rlen, __iend, __buf,
    00514                     __buf + __blen, __bend);
    00515           if (__r != codecvt_base::error)
    00516         {
    00517           __rlen = __bend - __buf;
    00518           __elen = _M_file.xsputn(__buf, __rlen);
    00519           __plen = __rlen;
    00520         }
    00521           else
    00522         __throw_ios_failure(__N("basic_filebuf::_M_convert_to_external "
    00523                     "conversion error"));
    00524         }
    00525     }
    00526       return __elen == __plen;
    00527     }
    00528
    00529    template<typename _CharT, typename _Traits>
    00530      streamsize
    00531      basic_filebuf<_CharT, _Traits>::
    00532      xsgetn(_CharT* __s, streamsize __n)
    00533      {
    00534        // Clear out pback buffer before going on to the real deal...
    00535        streamsize __ret = 0;
    00536        if (_M_pback_init)
    00537      {
    00538        if (__n > 0 && this->gptr() == this->eback())
    00539          {
    00540            *__s++ = *this->gptr();
    00541            this->gbump(1);
    00542            __ret = 1;
    00543            --__n;
    00544          }
    00545        _M_destroy_pback();
    00546      }
    00547
    00548        // Optimization in the always_noconv() case, to be generalized in the
    00549        // future: when __n > __buflen we read directly instead of using the
    00550        // buffer repeatedly.
    00551        const bool __testin = _M_mode & ios_base::in;
    00552        const streamsize __buflen = _M_buf_size > 1 ? _M_buf_size - 1 : 1;
    00553
    00554        if (__n > __buflen && __check_facet(_M_codecvt).always_noconv()
    00555        && __testin && !_M_writing)
    00556      {
    00557        // First, copy the chars already present in the buffer.
    00558        const streamsize __avail = this->egptr() - this->gptr();
    00559        if (__avail != 0)
    00560          {
    00561            if (__avail == 1)
    00562          *__s = *this->gptr();
    00563            else
    00564          traits_type::copy(__s, this->gptr(), __avail);
    00565            __s += __avail;
    00566            this->gbump(__avail);
    00567            __ret += __avail;
    00568            __n -= __avail;
    00569          }
    00570
    00571        // Need to loop in case of short reads (relatively common
    00572        // with pipes).
    00573        streamsize __len;
    00574        for (;;)
    00575          {
    00576            __len = _M_file.xsgetn(reinterpret_cast<char*>(__s),
    00577                       __n);
    00578            if (__len == -1)
    00579          __throw_ios_failure(__N("basic_filebuf::xsgetn "
    00580                      "error reading the file"));
    00581            if (__len == 0)
    00582          break;
    00583
    00584            __n -= __len;
    00585            __ret += __len;
    00586            if (__n == 0)
    00587          break;
    00588
    00589            __s += __len;
    00590          }
    00591
    00592        if (__n == 0)
    00593          {
    00594            _M_set_buffer(0);
    00595            _M_reading = true;
    00596          }
    00597        else if (__len == 0)
    00598          {
    00599            // If end of file is reached, set 'uncommitted'
    00600            // mode, thus allowing an immediate write without
    00601            // an intervening seek.
    00602            _M_set_buffer(-1);
    00603            _M_reading = false;
    00604          }
    00605      }
    00606        else
    00607      __ret += __streambuf_type::xsgetn(__s, __n);
    00608
    00609        return __ret;
    00610      }
    00611
    00612    template<typename _CharT, typename _Traits>
    00613      streamsize
    00614      basic_filebuf<_CharT, _Traits>::
    00615      xsputn(const _CharT* __s, streamsize __n)
    00616      {
    00617        // Optimization in the always_noconv() case, to be generalized in the
    00618        // future: when __n is sufficiently large we write directly instead of
    00619        // using the buffer.
    00620        streamsize __ret = 0;
    00621        const bool __testout = _M_mode & ios_base::out;
    00622        if (__check_facet(_M_codecvt).always_noconv()
    00623        && __testout && !_M_reading)
    00624     {
    00625       // Measurement would reveal the best choice.
    00626       const streamsize __chunk = 1ul << 10;
    00627       streamsize __bufavail = this->epptr() - this->pptr();
    00628
    00629       // Don't mistake 'uncommitted' mode buffered with unbuffered.
    00630       if (!_M_writing && _M_buf_size > 1)
    00631         __bufavail = _M_buf_size - 1;
    00632
    00633       const streamsize __limit = std::min(__chunk, __bufavail);
    00634       if (__n >= __limit)
    00635         {
    00636           const streamsize __buffill = this->pptr() - this->pbase();
    00637           const char* __buf = reinterpret_cast<const char*>(this->pbase());
    00638           __ret = _M_file.xsputn_2(__buf, __buffill,
    00639                        reinterpret_cast<const char*>(__s),
    00640                        __n);
    00641           if (__ret == __buffill + __n)
    00642         {
    00643           _M_set_buffer(0);
    00644           _M_writing = true;
    00645         }
    00646           if (__ret > __buffill)
    00647         __ret -= __buffill;
    00648           else
    00649         __ret = 0;
    00650         }
    00651       else
    00652         __ret = __streambuf_type::xsputn(__s, __n);
    00653     }
    00654        else
    00655      __ret = __streambuf_type::xsputn(__s, __n);
    00656        return __ret;
    00657     }
    00658
    00659   template<typename _CharT, typename _Traits>
    00660     typename basic_filebuf<_CharT, _Traits>::__streambuf_type*
    00661     basic_filebuf<_CharT, _Traits>::
    00662     setbuf(char_type* __s, streamsize __n)
    00663     {
    00664       if (!this->is_open())
    00665     if (__s == 0 && __n == 0)
    00666       _M_buf_size = 1;
    00667     else if (__s && __n > 0)
    00668       {
    00669         // This is implementation-defined behavior, and assumes that
    00670         // an external char_type array of length __n exists and has
    00671         // been pre-allocated. If this is not the case, things will
    00672         // quickly blow up. When __n > 1, __n - 1 positions will be
    00673         // used for the get area, __n - 1 for the put area and 1
    00674         // position to host the overflow char of a full put area.
    00675         // When __n == 1, 1 position will be used for the get area
    00676         // and 0 for the put area, as in the unbuffered case above.
    00677         _M_buf = __s;
    00678         _M_buf_size = __n;
    00679       }
    00680       return this;
    00681     }
    00682
    00683
    00684   // According to 27.8.1.4 p11 - 13, seekoff should ignore the last
    00685   // argument (of type openmode).
    00686   template<typename _CharT, typename _Traits>
    00687     typename basic_filebuf<_CharT, _Traits>::pos_type
    00688     basic_filebuf<_CharT, _Traits>::
    00689     seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode)
    00690     {
    00691       int __width = 0;
    00692       if (_M_codecvt)
    00693     __width = _M_codecvt->encoding();
    00694       if (__width < 0)
    00695     __width = 0;
    00696
    00697       pos_type __ret =  pos_type(off_type(-1));
    00698       const bool __testfail = __off != 0 && __width <= 0;
    00699       if (this->is_open() && !__testfail)
    00700     {
    00701       // Ditch any pback buffers to avoid confusion.
    00702       _M_destroy_pback();
    00703
    00704       // Correct state at destination. Note that this is the correct
    00705       // state for the current position during output, because
    00706       // codecvt::unshift() returns the state to the initial state.
    00707       // This is also the correct state at the end of the file because
    00708       // an unshift sequence should have been written at the end.
    00709       __state_type __state = _M_state_beg;
    00710       off_type __computed_off = __off * __width;
    00711       if (_M_reading && __way == ios_base::cur)
    00712         {
    00713           if (_M_codecvt->always_noconv())
    00714         __computed_off += this->gptr() - this->egptr();
    00715           else
    00716         {
    00717           // Calculate offset from _M_ext_buf that corresponds
    00718           // to gptr(). Note: uses _M_state_last, which
    00719           // corresponds to eback().
    00720           const int __gptr_off =
    00721             _M_codecvt->length(_M_state_last, _M_ext_buf, _M_ext_next,
    00722                        this->gptr() - this->eback());
    00723           __computed_off += _M_ext_buf + __gptr_off - _M_ext_end;
    00724
    00725           // _M_state_last is modified by codecvt::length() so
    00726           // it now corresponds to gptr().
    00727           __state = _M_state_last;
    00728         }
    00729         }
    00730       __ret = _M_seek(__computed_off, __way, __state);
    00731     }
    00732       return __ret;
    00733     }
    00734
    00735   // _GLIBCXX_RESOLVE_LIB_DEFECTS
    00736   // 171. Strange seekpos() semantics due to joint position
    00737   // According to the resolution of DR 171, seekpos should ignore the last
    00738   // argument (of type openmode).
    00739   template<typename _CharT, typename _Traits>
    00740     typename basic_filebuf<_CharT, _Traits>::pos_type
    00741     basic_filebuf<_CharT, _Traits>::
    00742     seekpos(pos_type __pos, ios_base::openmode)
    00743     {
    00744       pos_type __ret =  pos_type(off_type(-1));
    00745       if (this->is_open())
    00746     {
    00747       // Ditch any pback buffers to avoid confusion.
    00748       _M_destroy_pback();
    00749       __ret = _M_seek(off_type(__pos), ios_base::beg, __pos.state());
    00750     }
    00751       return __ret;
    00752     }
    00753
    00754   template<typename _CharT, typename _Traits>
    00755     typename basic_filebuf<_CharT, _Traits>::pos_type
    00756     basic_filebuf<_CharT, _Traits>::
    00757     _M_seek(off_type __off, ios_base::seekdir __way, __state_type __state)
    00758     {
    00759       pos_type __ret = pos_type(off_type(-1));
    00760       if (_M_terminate_output())
    00761     {
    00762       // Returns pos_type(off_type(-1)) in case of failure.
    00763       __ret = pos_type(_M_file.seekoff(__off, __way));
    00764       if (__ret != pos_type(off_type(-1)))
    00765         {
    00766           _M_reading = false;
    00767           _M_writing = false;
    00768           _M_ext_next = _M_ext_end = _M_ext_buf;
    00769           _M_set_buffer(-1);
    00770           _M_state_cur = __state;
    00771           __ret.state(_M_state_cur);
    00772         }
    00773     }
    00774       return __ret;
    00775     }
    00776
    00777   template<typename _CharT, typename _Traits>
    00778     bool
    00779     basic_filebuf<_CharT, _Traits>::
    00780     _M_terminate_output()
    00781     {
    00782       // Part one: update the output sequence.
    00783       bool __testvalid = true;
    00784       if (this->pbase() < this->pptr())
    00785     {
    00786       const int_type __tmp = this->overflow();
    00787       if (traits_type::eq_int_type(__tmp, traits_type::eof()))
    00788         __testvalid = false;
    00789     }
    00790
    00791       // Part two: output unshift sequence.
    00792       if (_M_writing && !__check_facet(_M_codecvt).always_noconv()
    00793       && __testvalid)
    00794     {
    00795       // Note: this value is arbitrary, since there is no way to
    00796       // get the length of the unshift sequence from codecvt,
    00797       // without calling unshift.
    00798       const size_t __blen = 128;
    00799       char __buf[__blen];
    00800       codecvt_base::result __r;
    00801       streamsize __ilen = 0;
    00802
    00803       do
    00804         {
    00805           char* __next;
    00806           __r = _M_codecvt->unshift(_M_state_cur, __buf,
    00807                     __buf + __blen, __next);
    00808           if (__r == codecvt_base::error)
    00809         __testvalid = false;
    00810           else if (__r == codecvt_base::ok ||
    00811                __r == codecvt_base::partial)
    00812         {
    00813           __ilen = __next - __buf;
    00814           if (__ilen > 0)
    00815             {
    00816               const streamsize __elen = _M_file.xsputn(__buf, __ilen);
    00817               if (__elen != __ilen)
    00818             __testvalid = false;
    00819             }
    00820         }
    00821         }
    00822       while (__r == codecvt_base::partial && __ilen > 0 && __testvalid);
    00823
    00824       if (__testvalid)
    00825         {
    00826           // This second call to overflow() is required by the standard,
    00827           // but it's not clear why it's needed, since the output buffer
    00828           // should be empty by this point (it should have been emptied
    00829           // in the first call to overflow()).
    00830           const int_type __tmp = this->overflow();
    00831           if (traits_type::eq_int_type(__tmp, traits_type::eof()))
    00832         __testvalid = false;
    00833         }
    00834     }
    00835       return __testvalid;
    00836     }
    00837
    00838   template<typename _CharT, typename _Traits>
    00839     int
    00840     basic_filebuf<_CharT, _Traits>::
    00841     sync()
    00842     {
    00843       // Make sure that the internal buffer resyncs its idea of
    00844       // the file position with the external file.
    00845       int __ret = 0;
    00846       if (this->pbase() < this->pptr())
    00847     {
    00848       const int_type __tmp = this->overflow();
    00849       if (traits_type::eq_int_type(__tmp, traits_type::eof()))
    00850         __ret = -1;
    00851     }
    00852       return __ret;
    00853     }
    00854
    00855   template<typename _CharT, typename _Traits>
    00856     void
    00857     basic_filebuf<_CharT, _Traits>::
    00858     imbue(const locale& __loc)
    00859     {
    00860       bool __testvalid = true;
    00861
    00862       const __codecvt_type* _M_codecvt_tmp = 0;
    00863       if (__builtin_expect(has_facet<__codecvt_type>(__loc), true))
    00864     _M_codecvt_tmp = &use_facet<__codecvt_type>(__loc);
    00865
    00866       if (this->is_open())
    00867     {
    00868       // encoding() == -1 is ok only at the beginning.
    00869       if ((_M_reading || _M_writing)
    00870           && __check_facet(_M_codecvt).encoding() == -1)
    00871         __testvalid = false;
    00872       else
    00873         {
    00874           if (_M_reading)
    00875         {
    00876           if (__check_facet(_M_codecvt).always_noconv())
    00877             {
    00878               if (_M_codecvt_tmp
    00879               && !__check_facet(_M_codecvt_tmp).always_noconv())
    00880             __testvalid = this->seekoff(0, ios_base::cur, _M_mode)
    00881                           != pos_type(off_type(-1));
    00882             }
    00883           else
    00884             {
    00885               // External position corresponding to gptr().
    00886               _M_ext_next = _M_ext_buf
    00887             + _M_codecvt->length(_M_state_last, _M_ext_buf, _M_ext_next,
    00888                          this->gptr() - this->eback());
    00889               const streamsize __remainder = _M_ext_end - _M_ext_next;
    00890               if (__remainder)
    00891             __builtin_memmove(_M_ext_buf, _M_ext_next, __remainder);
    00892
    00893               _M_ext_next = _M_ext_buf;
    00894               _M_ext_end = _M_ext_buf + __remainder;
    00895               _M_set_buffer(-1);
    00896               _M_state_last = _M_state_cur = _M_state_beg;
    00897             }
    00898         }
    00899           else if (_M_writing && (__testvalid = _M_terminate_output()))
    00900         _M_set_buffer(-1);
    00901         }
    00902     }
    00903
    00904       if (__testvalid)
    00905     _M_codecvt = _M_codecvt_tmp;
    00906       else
    00907     _M_codecvt = 0;
    00908     }
    00909
    00910   // Inhibit implicit instantiations for required instantiations,
    00911   // which are defined via explicit instantiations elsewhere.
    00912   // NB:  This syntax is a GNU extension.
    00913 #if _GLIBCXX_EXTERN_TEMPLATE
    00914   extern template class basic_filebuf<char>;
    00915   extern template class basic_ifstream<char>;
    00916   extern template class basic_ofstream<char>;
    00917   extern template class basic_fstream<char>;
    00918
    00919 #ifdef _GLIBCXX_USE_WCHAR_T
    00920   extern template class basic_filebuf<wchar_t>;
    00921   extern template class basic_ifstream<wchar_t>;
    00922   extern template class basic_ofstream<wchar_t>;
    00923   extern template class basic_fstream<wchar_t>;
    00924 #endif
    00925 #endif
    00926
    00927 _GLIBCXX_END_NAMESPACE
    00928
    00929 #endif