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