Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. // File based streams -*- C++ -*-
  2.  
  3. // Copyright (C) 1997-2015 Free Software Foundation, Inc.
  4. //
  5. // This file is part of the GNU ISO C++ Library.  This library is free
  6. // software; you can redistribute it and/or modify it under the
  7. // terms of the GNU General Public License as published by the
  8. // Free Software Foundation; either version 3, or (at your option)
  9. // any later version.
  10.  
  11. // This library is distributed in the hope that it will be useful,
  12. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. // GNU General Public License for more details.
  15.  
  16. // Under Section 7 of GPL version 3, you are granted additional
  17. // permissions described in the GCC Runtime Library Exception, version
  18. // 3.1, as published by the Free Software Foundation.
  19.  
  20. // You should have received a copy of the GNU General Public License and
  21. // a copy of the GCC Runtime Library Exception along with this program;
  22. // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
  23. // <http://www.gnu.org/licenses/>.
  24.  
  25. /** @file bits/fstream.tcc
  26.  *  This is an internal header file, included by other library headers.
  27.  *  Do not attempt to use it directly. @headername{fstream}
  28.  */
  29.  
  30. //
  31. // ISO C++ 14882: 27.8  File-based streams
  32. //
  33.  
  34. #ifndef _FSTREAM_TCC
  35. #define _FSTREAM_TCC 1
  36.  
  37. #pragma GCC system_header
  38.  
  39. #include <bits/cxxabi_forced.h>
  40. #include <bits/move.h>   // for swap
  41.  
  42. namespace std _GLIBCXX_VISIBILITY(default)
  43. {
  44. _GLIBCXX_BEGIN_NAMESPACE_VERSION
  45.  
  46.   template<typename _CharT, typename _Traits>
  47.     void
  48.     basic_filebuf<_CharT, _Traits>::
  49.     _M_allocate_internal_buffer()
  50.     {
  51.       // Allocate internal buffer only if one doesn't already exist
  52.       // (either allocated or provided by the user via setbuf).
  53.       if (!_M_buf_allocated && !_M_buf)
  54.         {
  55.           _M_buf = new char_type[_M_buf_size];
  56.           _M_buf_allocated = true;
  57.         }
  58.     }
  59.  
  60.   template<typename _CharT, typename _Traits>
  61.     void
  62.     basic_filebuf<_CharT, _Traits>::
  63.     _M_destroy_internal_buffer() throw()
  64.     {
  65.       if (_M_buf_allocated)
  66.         {
  67.           delete [] _M_buf;
  68.           _M_buf = 0;
  69.           _M_buf_allocated = false;
  70.         }
  71.       delete [] _M_ext_buf;
  72.       _M_ext_buf = 0;
  73.       _M_ext_buf_size = 0;
  74.       _M_ext_next = 0;
  75.       _M_ext_end = 0;
  76.     }
  77.  
  78.   template<typename _CharT, typename _Traits>
  79.     basic_filebuf<_CharT, _Traits>::
  80.     basic_filebuf() : __streambuf_type(), _M_lock(), _M_file(&_M_lock),
  81.     _M_mode(ios_base::openmode(0)), _M_state_beg(), _M_state_cur(),
  82.     _M_state_last(), _M_buf(0), _M_buf_size(BUFSIZ),
  83.     _M_buf_allocated(false), _M_reading(false), _M_writing(false), _M_pback(),
  84.     _M_pback_cur_save(0), _M_pback_end_save(0), _M_pback_init(false),
  85.     _M_codecvt(0), _M_ext_buf(0), _M_ext_buf_size(0), _M_ext_next(0),
  86.     _M_ext_end(0)
  87.     {
  88.       if (has_facet<__codecvt_type>(this->_M_buf_locale))
  89.         _M_codecvt = &use_facet<__codecvt_type>(this->_M_buf_locale);
  90.     }
  91.  
  92. #if __cplusplus >= 201103L
  93.   template<typename _CharT, typename _Traits>
  94.     basic_filebuf<_CharT, _Traits>::
  95.     basic_filebuf(basic_filebuf&& __rhs)
  96.     : __streambuf_type(__rhs),
  97.     _M_lock(), _M_file(std::move(__rhs._M_file), &_M_lock),
  98.     _M_mode(std::__exchange(__rhs._M_mode, ios_base::openmode(0))),
  99.     _M_state_beg(std::move(__rhs._M_state_beg)),
  100.     _M_state_cur(std::move(__rhs._M_state_cur)),
  101.     _M_state_last(std::move(__rhs._M_state_last)),
  102.     _M_buf(std::__exchange(__rhs._M_buf, nullptr)),
  103.     _M_buf_size(std::__exchange(__rhs._M_buf_size, 1)),
  104.     _M_buf_allocated(std::__exchange(__rhs._M_buf_allocated, false)),
  105.     _M_reading(std::__exchange(__rhs._M_reading, false)),
  106.     _M_writing(std::__exchange(__rhs._M_writing, false)),
  107.     _M_pback(__rhs._M_pback),
  108.     _M_pback_cur_save(std::__exchange(__rhs._M_pback_cur_save, nullptr)),
  109.     _M_pback_end_save(std::__exchange(__rhs._M_pback_end_save, nullptr)),
  110.     _M_pback_init(std::__exchange(__rhs._M_pback_init, false)),
  111.     _M_codecvt(__rhs._M_codecvt),
  112.     _M_ext_buf(std::__exchange(__rhs._M_ext_buf, nullptr)),
  113.     _M_ext_buf_size(std::__exchange(__rhs._M_ext_buf_size, 0)),
  114.     _M_ext_next(std::__exchange(__rhs._M_ext_next, nullptr)),
  115.     _M_ext_end(std::__exchange(__rhs._M_ext_end, nullptr))
  116.     {
  117.       __rhs._M_set_buffer(-1);
  118.       __rhs._M_state_last = __rhs._M_state_cur = __rhs._M_state_beg;
  119.     }
  120.  
  121.   template<typename _CharT, typename _Traits>
  122.     basic_filebuf<_CharT, _Traits>&
  123.     basic_filebuf<_CharT, _Traits>::
  124.     operator=(basic_filebuf&& __rhs)
  125.     {
  126.       this->close();
  127.       __streambuf_type::operator=(__rhs);
  128.       _M_file.swap(__rhs._M_file);
  129.       _M_mode = std::__exchange(__rhs._M_mode, ios_base::openmode(0));
  130.       _M_state_beg = std::move(__rhs._M_state_beg);
  131.       _M_state_cur = std::move(__rhs._M_state_cur);
  132.       _M_state_last = std::move(__rhs._M_state_last);
  133.       _M_buf = std::__exchange(__rhs._M_buf, nullptr);
  134.       _M_buf_size = std::__exchange(__rhs._M_buf_size, 1);
  135.       _M_buf_allocated = std::__exchange(__rhs._M_buf_allocated, false);
  136.       _M_ext_buf = std::__exchange(__rhs._M_ext_buf, nullptr);
  137.       _M_ext_buf_size = std::__exchange(__rhs._M_ext_buf_size, 0);
  138.       _M_ext_next = std::__exchange(__rhs._M_ext_next, nullptr);
  139.       _M_ext_end = std::__exchange(__rhs._M_ext_end, nullptr);
  140.       _M_reading = std::__exchange(__rhs._M_reading, false);
  141.       _M_writing = std::__exchange(__rhs._M_writing, false);
  142.       _M_pback_cur_save = std::__exchange(__rhs._M_pback_cur_save, nullptr);
  143.       _M_pback_end_save = std::__exchange(__rhs._M_pback_end_save, nullptr);
  144.       _M_pback_init = std::__exchange(__rhs._M_pback_init, false);
  145.       __rhs._M_set_buffer(-1);
  146.       __rhs._M_state_last = __rhs._M_state_cur = __rhs._M_state_beg;
  147.       return *this;
  148.     }
  149.  
  150.   template<typename _CharT, typename _Traits>
  151.     void
  152.     basic_filebuf<_CharT, _Traits>::
  153.     swap(basic_filebuf& __rhs)
  154.     {
  155.       __streambuf_type::swap(__rhs);
  156.       _M_file.swap(__rhs._M_file);
  157.       std::swap(_M_mode, __rhs._M_mode);
  158.       std::swap(_M_state_beg, __rhs._M_state_beg);
  159.       std::swap(_M_state_cur, __rhs._M_state_cur);
  160.       std::swap(_M_state_last, __rhs._M_state_last);
  161.       std::swap(_M_buf, __rhs._M_buf);
  162.       std::swap(_M_buf_size, __rhs._M_buf_size);
  163.       std::swap(_M_buf_allocated, __rhs._M_buf_allocated);
  164.       std::swap(_M_ext_buf, __rhs._M_ext_buf);
  165.       std::swap(_M_ext_buf_size, __rhs._M_ext_buf_size);
  166.       std::swap(_M_ext_next, __rhs._M_ext_next);
  167.       std::swap(_M_ext_end, __rhs._M_ext_end);
  168.       std::swap(_M_reading, __rhs._M_reading);
  169.       std::swap(_M_writing, __rhs._M_writing);
  170.       std::swap(_M_pback_cur_save, __rhs._M_pback_cur_save);
  171.       std::swap(_M_pback_end_save, __rhs._M_pback_end_save);
  172.       std::swap(_M_pback_init, __rhs._M_pback_init);
  173.     }
  174. #endif
  175.  
  176.   template<typename _CharT, typename _Traits>
  177.     typename basic_filebuf<_CharT, _Traits>::__filebuf_type*
  178.     basic_filebuf<_CharT, _Traits>::
  179.     open(const char* __s, ios_base::openmode __mode)
  180.     {
  181.       __filebuf_type *__ret = 0;
  182.       if (!this->is_open())
  183.         {
  184.           _M_file.open(__s, __mode);
  185.           if (this->is_open())
  186.             {
  187.               _M_allocate_internal_buffer();
  188.               _M_mode = __mode;
  189.  
  190.               // Setup initial buffer to 'uncommitted' mode.
  191.               _M_reading = false;
  192.               _M_writing = false;
  193.               _M_set_buffer(-1);
  194.  
  195.               // Reset to initial state.
  196.               _M_state_last = _M_state_cur = _M_state_beg;
  197.  
  198.               // 27.8.1.3,4
  199.               if ((__mode & ios_base::ate)
  200.                   && this->seekoff(0, ios_base::end, __mode)
  201.                   == pos_type(off_type(-1)))
  202.                 this->close();
  203.               else
  204.                 __ret = this;
  205.             }
  206.         }
  207.       return __ret;
  208.     }
  209.  
  210.   template<typename _CharT, typename _Traits>
  211.     typename basic_filebuf<_CharT, _Traits>::__filebuf_type*
  212.     basic_filebuf<_CharT, _Traits>::
  213.     close()
  214.     {
  215.       if (!this->is_open())
  216.         return 0;
  217.  
  218.       bool __testfail = false;
  219.       {
  220.         // NB: Do this here so that re-opened filebufs will be cool...
  221.         struct __close_sentry
  222.         {
  223.           basic_filebuf *__fb;
  224.           __close_sentry (basic_filebuf *__fbi): __fb(__fbi) { }
  225.           ~__close_sentry ()
  226.           {
  227.             __fb->_M_mode = ios_base::openmode(0);
  228.             __fb->_M_pback_init = false;
  229.             __fb->_M_destroy_internal_buffer();
  230.             __fb->_M_reading = false;
  231.             __fb->_M_writing = false;
  232.             __fb->_M_set_buffer(-1);
  233.             __fb->_M_state_last = __fb->_M_state_cur = __fb->_M_state_beg;
  234.           }
  235.         } __cs (this);
  236.  
  237.         __try
  238.           {
  239.             if (!_M_terminate_output())
  240.               __testfail = true;
  241.           }
  242.         __catch(__cxxabiv1::__forced_unwind&)
  243.           {
  244.             _M_file.close();
  245.             __throw_exception_again;
  246.           }
  247.         __catch(...)
  248.           { __testfail = true; }
  249.       }
  250.  
  251.       if (!_M_file.close())
  252.         __testfail = true;
  253.  
  254.       if (__testfail)
  255.         return 0;
  256.       else
  257.         return this;
  258.     }
  259.  
  260.   template<typename _CharT, typename _Traits>
  261.     streamsize
  262.     basic_filebuf<_CharT, _Traits>::
  263.     showmanyc()
  264.     {
  265.       streamsize __ret = -1;
  266.       const bool __testin = _M_mode & ios_base::in;
  267.       if (__testin && this->is_open())
  268.         {
  269.           // For a stateful encoding (-1) the pending sequence might be just
  270.           // shift and unshift prefixes with no actual character.
  271.           __ret = this->egptr() - this->gptr();
  272.  
  273. #if _GLIBCXX_HAVE_DOS_BASED_FILESYSTEM
  274.           // About this workaround, see libstdc++/20806.
  275.           const bool __testbinary = _M_mode & ios_base::binary;
  276.           if (__check_facet(_M_codecvt).encoding() >= 0
  277.               && __testbinary)
  278. #else
  279.           if (__check_facet(_M_codecvt).encoding() >= 0)
  280. #endif
  281.             __ret += _M_file.showmanyc() / _M_codecvt->max_length();
  282.         }
  283.       return __ret;
  284.     }
  285.  
  286.   template<typename _CharT, typename _Traits>
  287.     typename basic_filebuf<_CharT, _Traits>::int_type
  288.     basic_filebuf<_CharT, _Traits>::
  289.     underflow()
  290.     {
  291.       int_type __ret = traits_type::eof();
  292.       const bool __testin = _M_mode & ios_base::in;
  293.       if (__testin)
  294.         {
  295.           if (_M_writing)
  296.             {
  297.               if (overflow() == traits_type::eof())
  298.                 return __ret;
  299.               _M_set_buffer(-1);
  300.               _M_writing = false;
  301.             }
  302.           // Check for pback madness, and if so switch back to the
  303.           // normal buffers and jet outta here before expensive
  304.           // fileops happen...
  305.           _M_destroy_pback();
  306.  
  307.           if (this->gptr() < this->egptr())
  308.             return traits_type::to_int_type(*this->gptr());
  309.  
  310.           // Get and convert input sequence.
  311.           const size_t __buflen = _M_buf_size > 1 ? _M_buf_size - 1 : 1;
  312.  
  313.           // Will be set to true if ::read() returns 0 indicating EOF.
  314.           bool __got_eof = false;
  315.           // Number of internal characters produced.
  316.           streamsize __ilen = 0;
  317.           codecvt_base::result __r = codecvt_base::ok;
  318.           if (__check_facet(_M_codecvt).always_noconv())
  319.             {
  320.               __ilen = _M_file.xsgetn(reinterpret_cast<char*>(this->eback()),
  321.                                       __buflen);
  322.               if (__ilen == 0)
  323.                 __got_eof = true;
  324.             }
  325.           else
  326.             {
  327.               // Worst-case number of external bytes.
  328.               // XXX Not done encoding() == -1.
  329.               const int __enc = _M_codecvt->encoding();
  330.               streamsize __blen; // Minimum buffer size.
  331.               streamsize __rlen; // Number of chars to read.
  332.               if (__enc > 0)
  333.                 __blen = __rlen = __buflen * __enc;
  334.               else
  335.                 {
  336.                   __blen = __buflen + _M_codecvt->max_length() - 1;
  337.                   __rlen = __buflen;
  338.                 }
  339.               const streamsize __remainder = _M_ext_end - _M_ext_next;
  340.               __rlen = __rlen > __remainder ? __rlen - __remainder : 0;
  341.  
  342.               // An imbue in 'read' mode implies first converting the external
  343.               // chars already present.
  344.               if (_M_reading && this->egptr() == this->eback() && __remainder)
  345.                 __rlen = 0;
  346.  
  347.               // Allocate buffer if necessary and move unconverted
  348.               // bytes to front.
  349.               if (_M_ext_buf_size < __blen)
  350.                 {
  351.                   char* __buf = new char[__blen];
  352.                   if (__remainder)
  353.                     __builtin_memcpy(__buf, _M_ext_next, __remainder);
  354.  
  355.                   delete [] _M_ext_buf;
  356.                   _M_ext_buf = __buf;
  357.                   _M_ext_buf_size = __blen;
  358.                 }
  359.               else if (__remainder)
  360.                 __builtin_memmove(_M_ext_buf, _M_ext_next, __remainder);
  361.  
  362.               _M_ext_next = _M_ext_buf;
  363.               _M_ext_end = _M_ext_buf + __remainder;
  364.               _M_state_last = _M_state_cur;
  365.  
  366.               do
  367.                 {
  368.                   if (__rlen > 0)
  369.                     {
  370.                       // Sanity check!
  371.                       // This may fail if the return value of
  372.                       // codecvt::max_length() is bogus.
  373.                       if (_M_ext_end - _M_ext_buf + __rlen > _M_ext_buf_size)
  374.                         {
  375.                           __throw_ios_failure(__N("basic_filebuf::underflow "
  376.                                               "codecvt::max_length() "
  377.                                               "is not valid"));
  378.                         }
  379.                       streamsize __elen = _M_file.xsgetn(_M_ext_end, __rlen);
  380.                       if (__elen == 0)
  381.                         __got_eof = true;
  382.                       else if (__elen == -1)
  383.                         break;
  384.                       _M_ext_end += __elen;
  385.                     }
  386.  
  387.                   char_type* __iend = this->eback();
  388.                   if (_M_ext_next < _M_ext_end)
  389.                     __r = _M_codecvt->in(_M_state_cur, _M_ext_next,
  390.                                          _M_ext_end, _M_ext_next,
  391.                                          this->eback(),
  392.                                          this->eback() + __buflen, __iend);
  393.                   if (__r == codecvt_base::noconv)
  394.                     {
  395.                       size_t __avail = _M_ext_end - _M_ext_buf;
  396.                       __ilen = std::min(__avail, __buflen);
  397.                       traits_type::copy(this->eback(),
  398.                                         reinterpret_cast<char_type*>
  399.                                         (_M_ext_buf), __ilen);
  400.                       _M_ext_next = _M_ext_buf + __ilen;
  401.                     }
  402.                   else
  403.                     __ilen = __iend - this->eback();
  404.  
  405.                   // _M_codecvt->in may return error while __ilen > 0: this is
  406.                   // ok, and actually occurs in case of mixed encodings (e.g.,
  407.                   // XML files).
  408.                   if (__r == codecvt_base::error)
  409.                     break;
  410.  
  411.                   __rlen = 1;
  412.                 }
  413.               while (__ilen == 0 && !__got_eof);
  414.             }
  415.  
  416.           if (__ilen > 0)
  417.             {
  418.               _M_set_buffer(__ilen);
  419.               _M_reading = true;
  420.               __ret = traits_type::to_int_type(*this->gptr());
  421.             }
  422.           else if (__got_eof)
  423.             {
  424.               // If the actual end of file is reached, set 'uncommitted'
  425.               // mode, thus allowing an immediate write without an
  426.               // intervening seek.
  427.               _M_set_buffer(-1);
  428.               _M_reading = false;
  429.               // However, reaching it while looping on partial means that
  430.               // the file has got an incomplete character.
  431.               if (__r == codecvt_base::partial)
  432.                 __throw_ios_failure(__N("basic_filebuf::underflow "
  433.                                     "incomplete character in file"));
  434.             }
  435.           else if (__r == codecvt_base::error)
  436.             __throw_ios_failure(__N("basic_filebuf::underflow "
  437.                                 "invalid byte sequence in file"));
  438.           else
  439.             __throw_ios_failure(__N("basic_filebuf::underflow "
  440.                                 "error reading the file"));
  441.         }
  442.       return __ret;
  443.     }
  444.  
  445.   template<typename _CharT, typename _Traits>
  446.     typename basic_filebuf<_CharT, _Traits>::int_type
  447.     basic_filebuf<_CharT, _Traits>::
  448.     pbackfail(int_type __i)
  449.     {
  450.       int_type __ret = traits_type::eof();
  451.       const bool __testin = _M_mode & ios_base::in;
  452.       if (__testin)
  453.         {
  454.           if (_M_writing)
  455.             {
  456.               if (overflow() == traits_type::eof())
  457.                 return __ret;
  458.               _M_set_buffer(-1);
  459.               _M_writing = false;
  460.             }
  461.           // Remember whether the pback buffer is active, otherwise below
  462.           // we may try to store in it a second char (libstdc++/9761).
  463.           const bool __testpb = _M_pback_init;
  464.           const bool __testeof = traits_type::eq_int_type(__i, __ret);
  465.           int_type __tmp;
  466.           if (this->eback() < this->gptr())
  467.             {
  468.               this->gbump(-1);
  469.               __tmp = traits_type::to_int_type(*this->gptr());
  470.             }
  471.           else if (this->seekoff(-1, ios_base::cur) != pos_type(off_type(-1)))
  472.             {
  473.               __tmp = this->underflow();
  474.               if (traits_type::eq_int_type(__tmp, __ret))
  475.                 return __ret;
  476.             }
  477.           else
  478.             {
  479.               // At the beginning of the buffer, need to make a
  480.               // putback position available.  But the seek may fail
  481.               // (f.i., at the beginning of a file, see
  482.               // libstdc++/9439) and in that case we return
  483.               // traits_type::eof().
  484.               return __ret;
  485.             }
  486.  
  487.           // Try to put back __i into input sequence in one of three ways.
  488.           // Order these tests done in is unspecified by the standard.
  489.           if (!__testeof && traits_type::eq_int_type(__i, __tmp))
  490.             __ret = __i;
  491.           else if (__testeof)
  492.             __ret = traits_type::not_eof(__i);
  493.           else if (!__testpb)
  494.             {
  495.               _M_create_pback();
  496.               _M_reading = true;
  497.               *this->gptr() = traits_type::to_char_type(__i);
  498.               __ret = __i;
  499.             }
  500.         }
  501.       return __ret;
  502.     }
  503.  
  504.   template<typename _CharT, typename _Traits>
  505.     typename basic_filebuf<_CharT, _Traits>::int_type
  506.     basic_filebuf<_CharT, _Traits>::
  507.     overflow(int_type __c)
  508.     {
  509.       int_type __ret = traits_type::eof();
  510.       const bool __testeof = traits_type::eq_int_type(__c, __ret);
  511.       const bool __testout = (_M_mode & ios_base::out
  512.                               || _M_mode & ios_base::app);
  513.       if (__testout)
  514.         {
  515.           if (_M_reading)
  516.             {
  517.               _M_destroy_pback();
  518.               const int __gptr_off = _M_get_ext_pos(_M_state_last);
  519.               if (_M_seek(__gptr_off, ios_base::cur, _M_state_last)
  520.                   == pos_type(off_type(-1)))
  521.                 return __ret;
  522.             }
  523.           if (this->pbase() < this->pptr())
  524.             {
  525.               // If appropriate, append the overflow char.
  526.               if (!__testeof)
  527.                 {
  528.                   *this->pptr() = traits_type::to_char_type(__c);
  529.                   this->pbump(1);
  530.                 }
  531.  
  532.               // Convert pending sequence to external representation,
  533.               // and output.
  534.               if (_M_convert_to_external(this->pbase(),
  535.                                          this->pptr() - this->pbase()))
  536.                 {
  537.                   _M_set_buffer(0);
  538.                   __ret = traits_type::not_eof(__c);
  539.                 }
  540.             }
  541.           else if (_M_buf_size > 1)
  542.             {
  543.               // Overflow in 'uncommitted' mode: set _M_writing, set
  544.               // the buffer to the initial 'write' mode, and put __c
  545.               // into the buffer.
  546.               _M_set_buffer(0);
  547.               _M_writing = true;
  548.               if (!__testeof)
  549.                 {
  550.                   *this->pptr() = traits_type::to_char_type(__c);
  551.                   this->pbump(1);
  552.                 }
  553.               __ret = traits_type::not_eof(__c);
  554.             }
  555.           else
  556.             {
  557.               // Unbuffered.
  558.               char_type __conv = traits_type::to_char_type(__c);
  559.               if (__testeof || _M_convert_to_external(&__conv, 1))
  560.                 {
  561.                   _M_writing = true;
  562.                   __ret = traits_type::not_eof(__c);
  563.                 }
  564.             }
  565.         }
  566.       return __ret;
  567.     }
  568.  
  569.   template<typename _CharT, typename _Traits>
  570.     bool
  571.     basic_filebuf<_CharT, _Traits>::
  572.     _M_convert_to_external(_CharT* __ibuf, streamsize __ilen)
  573.     {
  574.       // Sizes of external and pending output.
  575.       streamsize __elen;
  576.       streamsize __plen;
  577.       if (__check_facet(_M_codecvt).always_noconv())
  578.         {
  579.           __elen = _M_file.xsputn(reinterpret_cast<char*>(__ibuf), __ilen);
  580.           __plen = __ilen;
  581.         }
  582.       else
  583.         {
  584.           // Worst-case number of external bytes needed.
  585.           // XXX Not done encoding() == -1.
  586.           streamsize __blen = __ilen * _M_codecvt->max_length();
  587.           char* __buf = static_cast<char*>(__builtin_alloca(__blen));
  588.  
  589.           char* __bend;
  590.           const char_type* __iend;
  591.           codecvt_base::result __r;
  592.           __r = _M_codecvt->out(_M_state_cur, __ibuf, __ibuf + __ilen,
  593.                                 __iend, __buf, __buf + __blen, __bend);
  594.  
  595.           if (__r == codecvt_base::ok || __r == codecvt_base::partial)
  596.             __blen = __bend - __buf;
  597.           else if (__r == codecvt_base::noconv)
  598.             {
  599.               // Same as the always_noconv case above.
  600.               __buf = reinterpret_cast<char*>(__ibuf);
  601.               __blen = __ilen;
  602.             }
  603.           else
  604.             __throw_ios_failure(__N("basic_filebuf::_M_convert_to_external "
  605.                                     "conversion error"));
  606.  
  607.           __elen = _M_file.xsputn(__buf, __blen);
  608.           __plen = __blen;
  609.  
  610.           // Try once more for partial conversions.
  611.           if (__r == codecvt_base::partial && __elen == __plen)
  612.             {
  613.               const char_type* __iresume = __iend;
  614.               streamsize __rlen = this->pptr() - __iend;
  615.               __r = _M_codecvt->out(_M_state_cur, __iresume,
  616.                                     __iresume + __rlen, __iend, __buf,
  617.                                     __buf + __blen, __bend);
  618.               if (__r != codecvt_base::error)
  619.                 {
  620.                   __rlen = __bend - __buf;
  621.                   __elen = _M_file.xsputn(__buf, __rlen);
  622.                   __plen = __rlen;
  623.                 }
  624.               else
  625.                 __throw_ios_failure(__N("basic_filebuf::_M_convert_to_external "
  626.                                         "conversion error"));
  627.             }
  628.         }
  629.       return __elen == __plen;
  630.     }
  631.  
  632.   template<typename _CharT, typename _Traits>
  633.     streamsize
  634.     basic_filebuf<_CharT, _Traits>::
  635.     xsgetn(_CharT* __s, streamsize __n)
  636.     {
  637.       // Clear out pback buffer before going on to the real deal...
  638.       streamsize __ret = 0;
  639.       if (_M_pback_init)
  640.         {
  641.           if (__n > 0 && this->gptr() == this->eback())
  642.             {
  643.               *__s++ = *this->gptr(); // emulate non-underflowing sbumpc
  644.               this->gbump(1);
  645.               __ret = 1;
  646.               --__n;
  647.             }
  648.           _M_destroy_pback();
  649.         }
  650.       else if (_M_writing)
  651.         {
  652.           if (overflow() == traits_type::eof())
  653.             return __ret;
  654.           _M_set_buffer(-1);
  655.           _M_writing = false;
  656.         }
  657.  
  658.       // Optimization in the always_noconv() case, to be generalized in the
  659.       // future: when __n > __buflen we read directly instead of using the
  660.       // buffer repeatedly.
  661.       const bool __testin = _M_mode & ios_base::in;
  662.       const streamsize __buflen = _M_buf_size > 1 ? _M_buf_size - 1 : 1;
  663.  
  664.       if (__n > __buflen && __check_facet(_M_codecvt).always_noconv()
  665.            && __testin)
  666.          {
  667.            // First, copy the chars already present in the buffer.
  668.            const streamsize __avail = this->egptr() - this->gptr();
  669.            if (__avail != 0)
  670.              {
  671.                traits_type::copy(__s, this->gptr(), __avail);
  672.                __s += __avail;
  673.                this->setg(this->eback(), this->gptr() + __avail,
  674.                           this->egptr());
  675.                __ret += __avail;
  676.                __n -= __avail;
  677.              }
  678.  
  679.            // Need to loop in case of short reads (relatively common
  680.            // with pipes).
  681.            streamsize __len;
  682.            for (;;)
  683.              {
  684.                __len = _M_file.xsgetn(reinterpret_cast<char*>(__s),
  685.                                       __n);
  686.                if (__len == -1)
  687.                  __throw_ios_failure(__N("basic_filebuf::xsgetn "
  688.                                          "error reading the file"));
  689.                if (__len == 0)
  690.                  break;
  691.  
  692.                __n -= __len;
  693.                __ret += __len;
  694.                if (__n == 0)
  695.                  break;
  696.  
  697.                __s += __len;
  698.              }
  699.  
  700.            if (__n == 0)
  701.              {
  702.                _M_set_buffer(0);
  703.                _M_reading = true;
  704.              }
  705.            else if (__len == 0)
  706.              {
  707.                // If end of file is reached, set 'uncommitted'
  708.                // mode, thus allowing an immediate write without
  709.                // an intervening seek.
  710.                _M_set_buffer(-1);
  711.                _M_reading = false;
  712.              }
  713.          }
  714.       else
  715.          __ret += __streambuf_type::xsgetn(__s, __n);
  716.  
  717.       return __ret;
  718.     }
  719.  
  720.   template<typename _CharT, typename _Traits>
  721.     streamsize
  722.     basic_filebuf<_CharT, _Traits>::
  723.     xsputn(const _CharT* __s, streamsize __n)
  724.     {
  725.       streamsize __ret = 0;
  726.       // Optimization in the always_noconv() case, to be generalized in the
  727.       // future: when __n is sufficiently large we write directly instead of
  728.       // using the buffer.
  729.       const bool __testout = (_M_mode & ios_base::out
  730.                               || _M_mode & ios_base::app);
  731.       if (__check_facet(_M_codecvt).always_noconv()
  732.            && __testout && !_M_reading)
  733.         {
  734.           // Measurement would reveal the best choice.
  735.           const streamsize __chunk = 1ul << 10;
  736.           streamsize __bufavail = this->epptr() - this->pptr();
  737.  
  738.           // Don't mistake 'uncommitted' mode buffered with unbuffered.
  739.           if (!_M_writing && _M_buf_size > 1)
  740.             __bufavail = _M_buf_size - 1;
  741.  
  742.           const streamsize __limit = std::min(__chunk, __bufavail);
  743.           if (__n >= __limit)
  744.             {
  745.               const streamsize __buffill = this->pptr() - this->pbase();
  746.               const char* __buf = reinterpret_cast<const char*>(this->pbase());
  747.               __ret = _M_file.xsputn_2(__buf, __buffill,
  748.                                        reinterpret_cast<const char*>(__s),
  749.                                        __n);
  750.               if (__ret == __buffill + __n)
  751.                 {
  752.                   _M_set_buffer(0);
  753.                   _M_writing = true;
  754.                 }
  755.               if (__ret > __buffill)
  756.                 __ret -= __buffill;
  757.               else
  758.                 __ret = 0;
  759.             }
  760.           else
  761.             __ret = __streambuf_type::xsputn(__s, __n);
  762.         }
  763.        else
  764.          __ret = __streambuf_type::xsputn(__s, __n);
  765.        return __ret;
  766.     }
  767.  
  768.   template<typename _CharT, typename _Traits>
  769.     typename basic_filebuf<_CharT, _Traits>::__streambuf_type*
  770.     basic_filebuf<_CharT, _Traits>::
  771.     setbuf(char_type* __s, streamsize __n)
  772.     {
  773.       if (!this->is_open())
  774.         {
  775.           if (__s == 0 && __n == 0)
  776.             _M_buf_size = 1;
  777.           else if (__s && __n > 0)
  778.             {
  779.               // This is implementation-defined behavior, and assumes that
  780.               // an external char_type array of length __n exists and has
  781.               // been pre-allocated. If this is not the case, things will
  782.               // quickly blow up. When __n > 1, __n - 1 positions will be
  783.               // used for the get area, __n - 1 for the put area and 1
  784.               // position to host the overflow char of a full put area.
  785.               // When __n == 1, 1 position will be used for the get area
  786.               // and 0 for the put area, as in the unbuffered case above.
  787.               _M_buf = __s;
  788.               _M_buf_size = __n;
  789.             }
  790.         }
  791.       return this;
  792.     }
  793.  
  794.  
  795.   // According to 27.8.1.4 p11 - 13, seekoff should ignore the last
  796.   // argument (of type openmode).
  797.   template<typename _CharT, typename _Traits>
  798.     typename basic_filebuf<_CharT, _Traits>::pos_type
  799.     basic_filebuf<_CharT, _Traits>::
  800.     seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode)
  801.     {
  802.       int __width = 0;
  803.       if (_M_codecvt)
  804.         __width = _M_codecvt->encoding();
  805.       if (__width < 0)
  806.         __width = 0;
  807.  
  808.       pos_type __ret = pos_type(off_type(-1));
  809.       const bool __testfail = __off != 0 && __width <= 0;
  810.       if (this->is_open() && !__testfail)
  811.         {
  812.           // tellg and tellp queries do not affect any state, unless
  813.           // ! always_noconv and the put sequence is not empty.
  814.           // In that case, determining the position requires converting the
  815.           // put sequence. That doesn't use ext_buf, so requires a flush.
  816.           bool __no_movement = __way == ios_base::cur && __off == 0
  817.             && (!_M_writing || _M_codecvt->always_noconv());
  818.  
  819.           // Ditch any pback buffers to avoid confusion.
  820.           if (!__no_movement)
  821.             _M_destroy_pback();
  822.  
  823.           // Correct state at destination. Note that this is the correct
  824.           // state for the current position during output, because
  825.           // codecvt::unshift() returns the state to the initial state.
  826.           // This is also the correct state at the end of the file because
  827.           // an unshift sequence should have been written at the end.
  828.           __state_type __state = _M_state_beg;
  829.           off_type __computed_off = __off * __width;
  830.           if (_M_reading && __way == ios_base::cur)
  831.             {
  832.               __state = _M_state_last;
  833.               __computed_off += _M_get_ext_pos(__state);
  834.             }
  835.           if (!__no_movement)
  836.             __ret = _M_seek(__computed_off, __way, __state);
  837.           else
  838.             {
  839.               if (_M_writing)
  840.                 __computed_off = this->pptr() - this->pbase();
  841.              
  842.               off_type __file_off = _M_file.seekoff(0, ios_base::cur);
  843.               if (__file_off != off_type(-1))
  844.                 {
  845.                   __ret = __file_off + __computed_off;
  846.                   __ret.state(__state);
  847.                 }
  848.             }
  849.         }
  850.       return __ret;
  851.     }
  852.  
  853.   // _GLIBCXX_RESOLVE_LIB_DEFECTS
  854.   // 171. Strange seekpos() semantics due to joint position
  855.   // According to the resolution of DR 171, seekpos should ignore the last
  856.   // argument (of type openmode).
  857.   template<typename _CharT, typename _Traits>
  858.     typename basic_filebuf<_CharT, _Traits>::pos_type
  859.     basic_filebuf<_CharT, _Traits>::
  860.     seekpos(pos_type __pos, ios_base::openmode)
  861.     {
  862.       pos_type __ret =  pos_type(off_type(-1));
  863.       if (this->is_open())
  864.         {
  865.           // Ditch any pback buffers to avoid confusion.
  866.           _M_destroy_pback();
  867.           __ret = _M_seek(off_type(__pos), ios_base::beg, __pos.state());
  868.         }
  869.       return __ret;
  870.     }
  871.  
  872.   template<typename _CharT, typename _Traits>
  873.     typename basic_filebuf<_CharT, _Traits>::pos_type
  874.     basic_filebuf<_CharT, _Traits>::
  875.     _M_seek(off_type __off, ios_base::seekdir __way, __state_type __state)
  876.     {
  877.       pos_type __ret = pos_type(off_type(-1));
  878.       if (_M_terminate_output())
  879.         {
  880.           off_type __file_off = _M_file.seekoff(__off, __way);
  881.           if (__file_off != off_type(-1))
  882.             {
  883.               _M_reading = false;
  884.               _M_writing = false;
  885.               _M_ext_next = _M_ext_end = _M_ext_buf;
  886.               _M_set_buffer(-1);
  887.               _M_state_cur = __state;
  888.               __ret = __file_off;
  889.               __ret.state(_M_state_cur);
  890.             }
  891.         }
  892.       return __ret;
  893.     }
  894.  
  895.   // Returns the distance from the end of the ext buffer to the point
  896.   // corresponding to gptr(). This is a negative value. Updates __state
  897.   // from eback() correspondence to gptr().
  898.   template<typename _CharT, typename _Traits>
  899.     int basic_filebuf<_CharT, _Traits>::
  900.     _M_get_ext_pos(__state_type& __state)
  901.     {
  902.       if (_M_codecvt->always_noconv())
  903.         return this->gptr() - this->egptr();
  904.       else
  905.         {
  906.           // Calculate offset from _M_ext_buf that corresponds to
  907.           // gptr(). Precondition: __state == _M_state_last, which
  908.           // corresponds to eback().
  909.           const int __gptr_off =
  910.             _M_codecvt->length(__state, _M_ext_buf, _M_ext_next,
  911.                                this->gptr() - this->eback());
  912.           return _M_ext_buf + __gptr_off - _M_ext_end;
  913.         }
  914.     }
  915.    
  916.   template<typename _CharT, typename _Traits>
  917.     bool
  918.     basic_filebuf<_CharT, _Traits>::
  919.     _M_terminate_output()
  920.     {
  921.       // Part one: update the output sequence.
  922.       bool __testvalid = true;
  923.       if (this->pbase() < this->pptr())
  924.         {
  925.           const int_type __tmp = this->overflow();
  926.           if (traits_type::eq_int_type(__tmp, traits_type::eof()))
  927.             __testvalid = false;
  928.         }
  929.  
  930.       // Part two: output unshift sequence.
  931.       if (_M_writing && !__check_facet(_M_codecvt).always_noconv()
  932.           && __testvalid)
  933.         {
  934.           // Note: this value is arbitrary, since there is no way to
  935.           // get the length of the unshift sequence from codecvt,
  936.           // without calling unshift.
  937.           const size_t __blen = 128;
  938.           char __buf[__blen];
  939.           codecvt_base::result __r;
  940.           streamsize __ilen = 0;
  941.  
  942.           do
  943.             {
  944.               char* __next;
  945.               __r = _M_codecvt->unshift(_M_state_cur, __buf,
  946.                                         __buf + __blen, __next);
  947.               if (__r == codecvt_base::error)
  948.                 __testvalid = false;
  949.               else if (__r == codecvt_base::ok ||
  950.                        __r == codecvt_base::partial)
  951.                 {
  952.                   __ilen = __next - __buf;
  953.                   if (__ilen > 0)
  954.                     {
  955.                       const streamsize __elen = _M_file.xsputn(__buf, __ilen);
  956.                       if (__elen != __ilen)
  957.                         __testvalid = false;
  958.                     }
  959.                 }
  960.             }
  961.           while (__r == codecvt_base::partial && __ilen > 0 && __testvalid);
  962.  
  963.           if (__testvalid)
  964.             {
  965.               // This second call to overflow() is required by the standard,
  966.               // but it's not clear why it's needed, since the output buffer
  967.               // should be empty by this point (it should have been emptied
  968.               // in the first call to overflow()).
  969.               const int_type __tmp = this->overflow();
  970.               if (traits_type::eq_int_type(__tmp, traits_type::eof()))
  971.                 __testvalid = false;
  972.             }
  973.         }
  974.       return __testvalid;
  975.     }
  976.  
  977.   template<typename _CharT, typename _Traits>
  978.     int
  979.     basic_filebuf<_CharT, _Traits>::
  980.     sync()
  981.     {
  982.       // Make sure that the internal buffer resyncs its idea of
  983.       // the file position with the external file.
  984.       int __ret = 0;
  985.       if (this->pbase() < this->pptr())
  986.         {
  987.           const int_type __tmp = this->overflow();
  988.           if (traits_type::eq_int_type(__tmp, traits_type::eof()))
  989.             __ret = -1;
  990.         }
  991.       return __ret;
  992.     }
  993.  
  994.   template<typename _CharT, typename _Traits>
  995.     void
  996.     basic_filebuf<_CharT, _Traits>::
  997.     imbue(const locale& __loc)
  998.     {
  999.       bool __testvalid = true;
  1000.  
  1001.       const __codecvt_type* _M_codecvt_tmp = 0;
  1002.       if (__builtin_expect(has_facet<__codecvt_type>(__loc), true))
  1003.         _M_codecvt_tmp = &use_facet<__codecvt_type>(__loc);
  1004.  
  1005.       if (this->is_open())
  1006.         {
  1007.           // encoding() == -1 is ok only at the beginning.
  1008.           if ((_M_reading || _M_writing)
  1009.               && __check_facet(_M_codecvt).encoding() == -1)
  1010.             __testvalid = false;
  1011.           else
  1012.             {
  1013.               if (_M_reading)
  1014.                 {
  1015.                   if (__check_facet(_M_codecvt).always_noconv())
  1016.                     {
  1017.                       if (_M_codecvt_tmp
  1018.                           && !__check_facet(_M_codecvt_tmp).always_noconv())
  1019.                         __testvalid = this->seekoff(0, ios_base::cur, _M_mode)
  1020.                                       != pos_type(off_type(-1));
  1021.                     }
  1022.                   else
  1023.                     {
  1024.                       // External position corresponding to gptr().
  1025.                       _M_ext_next = _M_ext_buf
  1026.                         + _M_codecvt->length(_M_state_last, _M_ext_buf,
  1027.                                              _M_ext_next,
  1028.                                              this->gptr() - this->eback());
  1029.                       const streamsize __remainder = _M_ext_end - _M_ext_next;
  1030.                       if (__remainder)
  1031.                         __builtin_memmove(_M_ext_buf, _M_ext_next, __remainder);
  1032.  
  1033.                       _M_ext_next = _M_ext_buf;
  1034.                       _M_ext_end = _M_ext_buf + __remainder;
  1035.                       _M_set_buffer(-1);
  1036.                       _M_state_last = _M_state_cur = _M_state_beg;
  1037.                     }
  1038.                 }
  1039.               else if (_M_writing && (__testvalid = _M_terminate_output()))
  1040.                 _M_set_buffer(-1);
  1041.             }
  1042.         }
  1043.  
  1044.       if (__testvalid)
  1045.         _M_codecvt = _M_codecvt_tmp;
  1046.       else
  1047.         _M_codecvt = 0;
  1048.     }
  1049.  
  1050.   // Inhibit implicit instantiations for required instantiations,
  1051.   // which are defined via explicit instantiations elsewhere.
  1052. #if _GLIBCXX_EXTERN_TEMPLATE
  1053.   extern template class basic_filebuf<char>;
  1054.   extern template class basic_ifstream<char>;
  1055.   extern template class basic_ofstream<char>;
  1056.   extern template class basic_fstream<char>;
  1057.  
  1058. #ifdef _GLIBCXX_USE_WCHAR_T
  1059.   extern template class basic_filebuf<wchar_t>;
  1060.   extern template class basic_ifstream<wchar_t>;
  1061.   extern template class basic_ofstream<wchar_t>;
  1062.   extern template class basic_fstream<wchar_t>;
  1063. #endif
  1064. #endif
  1065.  
  1066. _GLIBCXX_END_NAMESPACE_VERSION
  1067. } // namespace std
  1068.  
  1069. #endif
  1070.