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