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