home *** CD-ROM | disk | FTP | other *** search
/ Beginning C++ Through Gam…rogramming (2nd Edition) / BCGP2E.ISO / bloodshed / devcpp-4.9.9.2_setup.exe / fstream.tcc < prev    next >
Text File  |  2005-01-29  |  27KB  |  880 lines

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