home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / stlpt453.zip / STLport-4.5.3 / stlport / stl / _fstream.c < prev    next >
C/C++ Source or Header  |  2002-02-02  |  26KB  |  750 lines

  1. /*
  2.  * Copyright (c) 1996,1997
  3.  * Silicon Graphics Computer Systems, Inc.
  4.  *
  5.  * Copyright (c) 1999 
  6.  * Boris Fomitchev
  7.  *
  8.  * This material is provided "as is", with absolutely no warranty expressed
  9.  * or implied. Any use is at your own risk.
  10.  *
  11.  * Permission to use or copy this software for any purpose is hereby granted 
  12.  * without fee, provided the above notices are retained on all copies.
  13.  * Permission to modify the code and to distribute modified code is granted,
  14.  * provided the above notices are retained, and a notice that the code was
  15.  * modified is included with the above copyright notice.
  16.  *
  17.  */
  18. #ifndef _STLP_FSTREAM_C
  19. #define _STLP_FSTREAM_C
  20.  
  21. # ifndef _STLP_INTERNAL_FSTREAM_H
  22. #  include <stl/_fstream.h>
  23. # endif
  24.  
  25. # if defined (_STLP_EXPOSE_STREAM_IMPLEMENTATION)
  26.  
  27. _STLP_BEGIN_NAMESPACE
  28.  
  29. # if defined ( _STLP_NESTED_TYPE_PARAM_BUG )
  30. // no wchar_t is supported for this mode
  31. # define __BF_int_type__ int
  32. # define __BF_pos_type__ streampos
  33. # define __BF_off_type__ streamoff
  34. # else
  35. # define __BF_int_type__ _STLP_TYPENAME_ON_RETURN_TYPE basic_filebuf<_CharT, _Traits>::int_type
  36. # define __BF_pos_type__ _STLP_TYPENAME_ON_RETURN_TYPE basic_filebuf<_CharT, _Traits>::pos_type
  37. # define __BF_off_type__ _STLP_TYPENAME_ON_RETURN_TYPE basic_filebuf<_CharT, _Traits>::off_type
  38. # endif
  39.  
  40.  
  41. //----------------------------------------------------------------------
  42. // Public basic_filebuf<> member functions
  43.  
  44. template <class _CharT, class _Traits>
  45. basic_filebuf<_CharT, _Traits>::basic_filebuf()
  46.      :  basic_streambuf<_CharT, _Traits>(), _M_base(),
  47.     _M_constant_width(false), _M_always_noconv(false),
  48.     _M_int_buf_dynamic(false),
  49.     _M_in_input_mode(false), _M_in_output_mode(false),
  50.     _M_in_error_mode(false), _M_in_putback_mode(false),
  51.     _M_int_buf(0), _M_int_buf_EOS(0),
  52.     _M_ext_buf(0), _M_ext_buf_EOS(0),
  53.     _M_ext_buf_converted(0), _M_ext_buf_end(0),
  54.     _M_state(_STLP_DEFAULT_CONSTRUCTED(_State_type)),
  55.     _M_end_state(_STLP_DEFAULT_CONSTRUCTED(_State_type)),
  56.     _M_mmap_base(0), _M_mmap_len(0),
  57.     _M_saved_eback(0), _M_saved_gptr(0), _M_saved_egptr(0),
  58.     _M_codecvt(0),
  59.     _M_width(1), _M_max_width(1)
  60. {
  61.   this->_M_setup_codecvt(locale());
  62. }
  63.  
  64. template <class _CharT, class _Traits>
  65. basic_filebuf<_CharT, _Traits>::~basic_filebuf() {
  66.   this->close();
  67.   _M_deallocate_buffers();
  68. }
  69.  
  70.  
  71. template <class _CharT, class _Traits>
  72. _STLP_TYPENAME_ON_RETURN_TYPE basic_filebuf<_CharT, _Traits>::int_type 
  73. basic_filebuf<_CharT, _Traits>::underflow() 
  74. {
  75.   return _Underflow<_CharT, _Traits>::_M_doit(this);
  76. }
  77.  
  78. template <class _CharT, class _Traits>
  79. basic_filebuf<_CharT, _Traits>* 
  80. basic_filebuf<_CharT, _Traits>::close()
  81. {
  82.   bool __ok = this->is_open();
  83.  
  84.   if (_M_in_output_mode) {
  85.     __ok = __ok && !_Traits::eq_int_type(this->overflow(traits_type::eof()),
  86.                                          traits_type::eof());
  87.     __ok == __ok && this->_M_unshift();
  88.   }
  89.   else if (_M_in_input_mode)
  90.       this->_M_exit_input_mode();
  91.  
  92.   // Note order of arguments.  We close the file even if __ok is false.
  93.   __ok = _M_base._M_close() && __ok;
  94.  
  95.   // Restore the initial state, except that we don't deallocate the buffer
  96.   // or mess with the cached codecvt information.
  97.   _M_state = _M_end_state = _State_type();
  98.   _M_ext_buf_converted = _M_ext_buf_end = 0;
  99.  
  100.   _M_mmap_base = 0;
  101.   _M_mmap_len = 0;
  102.  
  103.   this->setg(0, 0, 0);
  104.   this->setp(0, 0);
  105.  
  106.   _M_saved_eback = _M_saved_gptr = _M_saved_egptr = 0;
  107.  
  108.   _M_in_input_mode = _M_in_output_mode = _M_in_error_mode = _M_in_putback_mode
  109.     = false;
  110.  
  111.   return __ok ? this : 0;
  112. }
  113.  
  114. // This member function is called whenever we exit input mode.
  115. // It unmaps the memory-mapped file, if any, and sets
  116. // _M_in_input_mode to false.  
  117. template <class _CharT, class _Traits>
  118. void basic_filebuf<_CharT, _Traits>::_M_exit_input_mode()
  119. {
  120.    if (_M_mmap_base != 0)
  121.      _M_base._M_unmap(_M_mmap_base, _M_mmap_len); 
  122.    _M_in_input_mode = false;
  123.    _M_mmap_base = 0;
  124. }
  125.  
  126.  
  127. //----------------------------------------------------------------------
  128. // basic_filebuf<> overridden protected virtual member functions
  129.  
  130. template <class _CharT, class _Traits>
  131. streamsize basic_filebuf<_CharT, _Traits>::showmanyc()
  132. {
  133.   // Is there any possibility that reads can succeed?
  134.   if (!this->is_open() || _M_in_output_mode || _M_in_error_mode)
  135.     return -1;
  136.  
  137.   else if (_M_in_putback_mode)
  138.     return this->egptr() - this->gptr();
  139.  
  140.   else if (_M_constant_width) {
  141.     streamoff __pos  = _M_base._M_seek(0, ios_base::cur);
  142.     streamoff __size = _M_base._M_file_size();
  143.     return __pos >= 0 && __size > __pos ? __size - __pos : 0;
  144.   }
  145.  
  146.   else 
  147.     return 0;
  148. }
  149.  
  150.  
  151. // Make a putback position available, if necessary, by switching to a 
  152. // special internal buffer used only for putback.  The buffer is
  153. // [_M_pback_buf, _M_pback_buf + _S_pback_buf_size), but the base
  154. // class only sees a piece of it at a time.  (We want to make sure
  155. // that we don't try to read a character that hasn't been initialized.)
  156. // The end of the putback buffer is always _M_pback_buf + _S_pback_buf_size,
  157. // but the beginning is usually not _M_pback_buf.
  158. template <class _CharT, class _Traits>
  159. __BF_int_type__ 
  160. basic_filebuf<_CharT, _Traits>::pbackfail(int_type __c)
  161. {
  162.   const int_type __eof = traits_type::eof();
  163.  
  164.   // If we aren't already in input mode, pushback is impossible.
  165.   if (!_M_in_input_mode)
  166.     return __eof;
  167.  
  168.   // We can use the ordinary get buffer if there's enough space, and
  169.   // if it's a buffer that we're allowed to write to.
  170.   if (this->gptr() != this->eback() &&
  171.       (traits_type::eq_int_type(__c, __eof) ||
  172.        traits_type::eq(traits_type::to_char_type(__c), this->gptr()[-1]) ||
  173.        !_M_mmap_base)) {
  174.     this->gbump(-1);
  175.     if (traits_type::eq_int_type(__c, __eof) ||
  176.         traits_type::eq(traits_type::to_char_type(__c), *this->gptr()))
  177.       return traits_type::to_int_type(*this->gptr());
  178.   }
  179.   else if (!traits_type::eq_int_type(__c, __eof)) {
  180.     // Are we in the putback buffer already?
  181.     _CharT* __pback_end = _M_pback_buf + __STATIC_CAST(int,_S_pback_buf_size);
  182.     if (_M_in_putback_mode) {
  183.       // Do we have more room in the putback buffer?
  184.       if (this->eback() != _M_pback_buf) 
  185.         this->setg(this->egptr() - 1, this->egptr() - 1, __pback_end);
  186.       else
  187.         return __eof;           // No more room in the buffer, so fail.
  188.     }
  189.     else {                      // We're not yet in the putback buffer.
  190.       _M_saved_eback = this->eback();
  191.       _M_saved_gptr  = this->gptr();
  192.       _M_saved_egptr = this->egptr();
  193.       this->setg(__pback_end - 1, __pback_end - 1, __pback_end);
  194.       _M_in_putback_mode = true;
  195.     }
  196.   }
  197.   else
  198.     return __eof;
  199.  
  200.   // We have made a putback position available.  Assign to it, and return.
  201.   *this->gptr() = traits_type::to_char_type(__c);
  202.   return __c;
  203. }
  204.  
  205. // This member function flushes the put area, and also outputs the
  206. // character __c (unless __c is eof).  Invariant: we always leave room
  207. // in the internal buffer for one character more than the base class knows
  208. // about.  We see the internal buffer as [_M_int_buf, _M_int_buf_EOS), but
  209. // the base class only sees [_M_int_buf, _M_int_buf_EOS - 1).
  210. template <class _CharT, class _Traits>
  211. __BF_int_type__
  212. basic_filebuf<_CharT, _Traits>::overflow(int_type __c)
  213. {
  214.   // Switch to output mode, if necessary.
  215.   if (!_M_in_output_mode)
  216.     if (!_M_switch_to_output_mode())
  217.       return traits_type::eof();
  218.  
  219.   _CharT* __ibegin = this->_M_int_buf;
  220.   _CharT* __iend   = this->pptr();
  221.   this->setp(_M_int_buf, _M_int_buf_EOS - 1);
  222.  
  223.   // Put __c at the end of the internal buffer.
  224.   if (!traits_type::eq_int_type(__c, traits_type::eof()))
  225.     *__iend++ = __c;
  226.  
  227.   // For variable-width encodings, output may take more than one pass.
  228.   while (__ibegin != __iend) {
  229.     const _CharT* __inext = __ibegin;
  230.     char* __enext         = _M_ext_buf;
  231.     typename _Codecvt::result __status
  232.       = _M_codecvt->out(_M_state, __ibegin, __iend, __inext,
  233.                                   _M_ext_buf, _M_ext_buf_EOS, __enext);
  234.     if (__status == _Codecvt::noconv)
  235.       return _Noconv_output<_Traits>::_M_doit(this, __ibegin, __iend)
  236.         ? traits_type::not_eof(__c)
  237.         : _M_output_error();
  238.  
  239.     // For a constant-width encoding we know that the external buffer
  240.     // is large enough, so failure to consume the entire internal buffer
  241.     // or to produce the correct number of external characters, is an error.
  242.     // For a variable-width encoding, however, we require only that we 
  243.     // consume at least one internal character
  244.     else if (__status != _Codecvt::error && 
  245.              ((__inext == __iend && (__enext - _M_ext_buf == 
  246.                                      _M_width * (__iend - __ibegin))) ||
  247.               (!_M_constant_width && __inext != __ibegin))) {
  248.         // We successfully converted part or all of the internal buffer.
  249.       ptrdiff_t __n = __enext - _M_ext_buf;
  250.       if (_M_write(_M_ext_buf, __n))
  251.         __ibegin += __inext - __ibegin;
  252.       else
  253.         return _M_output_error();
  254.     }
  255.     else
  256.       return _M_output_error();
  257.   }
  258.  
  259.   return traits_type::not_eof(__c);
  260. }
  261.  
  262. // This member function must be called before any I/O has been
  263. // performed on the stream, otherwise it has no effect.
  264. //
  265. // __buf == 0 && __n == 0 means to make ths stream unbuffered.
  266. // __buf != 0 && __n > 0 means to use __buf as the stream's internal
  267. // buffer, rather than the buffer that would otherwise be allocated
  268. // automatically.  __buf must be a pointer to an array of _CharT whose
  269. // size is at least __n.
  270. template <class _CharT, class _Traits>
  271. basic_streambuf<_CharT, _Traits>*
  272. basic_filebuf<_CharT, _Traits>::setbuf(_CharT* __buf, streamsize __n)
  273. {
  274.   if (!_M_in_input_mode &&! _M_in_output_mode && !_M_in_error_mode &&
  275.       _M_int_buf == 0) {
  276.     if (__buf == 0 && __n == 0)
  277.       _M_allocate_buffers(0, 1);
  278.     else if (__buf != 0 && __n > 0)
  279.       _M_allocate_buffers(__buf, __n);
  280.   }
  281.   return this;
  282. }
  283.  
  284. template <class _CharT, class _Traits>
  285. __BF_pos_type__
  286. basic_filebuf<_CharT, _Traits>::seekoff(off_type __off,
  287.                                         ios_base::seekdir __whence,
  288.                                         ios_base::openmode /* dummy */)
  289. {
  290.   if (this->is_open() &&
  291.       (__off == 0 || (_M_constant_width && this->_M_base._M_in_binary_mode()))) {
  292.  
  293.     if (!_M_seek_init(__off != 0 || __whence != ios_base::cur))
  294.       return pos_type(-1);
  295.  
  296.     // Seek to beginning or end, regardless of whether we're in input mode.
  297.     if (__whence == ios_base::beg || __whence == ios_base::end)
  298.       return _M_seek_return(_M_base._M_seek(_M_width * __off, __whence),
  299.                             _State_type());
  300.  
  301.     // Seek relative to current position.  Complicated if we're in input mode.
  302.     else if (__whence == ios_base::cur) {
  303.  
  304.       if (!_M_in_input_mode)
  305.         return _M_seek_return(_M_base._M_seek(_M_width * __off, __whence),
  306.                               _State_type());
  307.       else if (_M_mmap_base != 0) {
  308.         // __off is relative to gptr().  We need to do a bit of arithmetic
  309.         // to get an offset relative to the external file pointer.
  310.         streamoff __adjust = _M_mmap_len - (this->gptr() - (_CharT*) _M_mmap_base);
  311.  
  312.         // if __off == 0, we do not need to exit input mode and to shift file pointer
  313.         if (__off == 0) {
  314.           return pos_type(_M_base._M_seek(0, ios_base::cur) - __adjust);
  315.         }
  316.         else
  317.           return _M_seek_return(_M_base._M_seek(__off - __adjust, ios_base::cur), _State_type());
  318.       }
  319.       else if (_M_constant_width) { // Get or set the position.  
  320.  
  321.         streamoff __iadj = _M_width * (this->gptr() - this->eback());
  322.         
  323.         // Compensate for offset relative to gptr versus offset relative
  324.         // to external pointer.  For a text-oriented stream, where the 
  325.         // compensation is more than just pointer arithmetic, we may get
  326.         // but not set the current position.
  327.         
  328.         if (__iadj <= _M_ext_buf_end - _M_ext_buf) {
  329.           
  330.           streamoff __eadj =  _M_base._M_get_offset(_M_ext_buf + __iadj, _M_ext_buf_end);
  331.  
  332.           if (__off == 0) {
  333.             return pos_type(_M_base._M_seek(0, ios_base::cur) - __eadj);
  334.           }  else {
  335.             return _M_seek_return(_M_base._M_seek(__off - __eadj, ios_base::cur), _State_type());
  336.           }
  337.         }
  338.         else
  339.           return pos_type(-1);
  340.       }
  341.       else {                    // Get the position.  Encoding is var width.
  342.         // Get position in internal buffer.
  343.         ptrdiff_t __ipos = this->gptr() - this->eback();
  344.         
  345.         // Get corresponding position in external buffer.
  346.         _State_type __state = _M_state;
  347.         int __epos = _M_codecvt->length(__state, _M_ext_buf, _M_ext_buf_end,
  348.                                         __ipos);
  349.  
  350.         // Sanity check (expensive): make sure __epos is the right answer.
  351.         _State_type __tmp_state = _M_state;
  352.         _Filebuf_Tmp_Buf<_CharT> __buf(__ipos);
  353.         _CharT* __ibegin = __buf._M_ptr;
  354.         _CharT* __inext  = __ibegin;
  355.  
  356.         const char* __dummy;
  357.         typename _Codecvt::result __status
  358.           = _M_codecvt->in(__tmp_state,
  359.                            _M_ext_buf, _M_ext_buf + __epos, __dummy,
  360.                            __ibegin, __ibegin + __ipos, __inext);
  361.         if (__status != _Codecvt::error &&
  362.             (__status == _Codecvt::noconv ||
  363.              (__inext == __ibegin + __ipos &&
  364.               equal(this->gptr(), this->eback(), __ibegin,
  365.                     _Eq_traits<traits_type>())))) {
  366.           // Get the current position (at the end of the external buffer),
  367.           // then adjust it.  Again, it might be a text-oriented stream.
  368.           streamoff __cur = _M_base._M_seek(0, ios_base::cur);
  369.           streamoff __adj =
  370.             _M_base._M_get_offset(_M_ext_buf, _M_ext_buf + __epos) -
  371.             _M_base._M_get_offset(_M_ext_buf, _M_ext_buf_end);
  372.           if (__cur != -1 && __cur + __adj >= 0)
  373.             return _M_seek_return(__cur + __adj, __state);
  374.           else
  375.             return pos_type(-1);
  376.         }
  377.         else                    // We failed the sanity check.
  378.           return pos_type(-1);
  379.       }
  380.     }
  381.     else                        // Unrecognized value for __whence.
  382.       return pos_type(-1);
  383.   }
  384.   else
  385.     return pos_type(-1);
  386. }
  387.  
  388.  
  389. template <class _CharT, class _Traits>
  390. __BF_pos_type__
  391. basic_filebuf<_CharT, _Traits>::seekpos(pos_type __pos,
  392.                                         ios_base::openmode /* dummy */)
  393. {
  394.   if (this->is_open()) {
  395.     if (!_M_seek_init(true))
  396.       return pos_type(-1);
  397.  
  398.     streamoff __off = off_type(__pos);
  399.     if (__off != -1 && _M_base._M_seek(__off, ios_base::beg) != -1) {
  400.       _M_state = __pos.state();
  401.       return _M_seek_return(__off, __pos.state());
  402.     }
  403.     else
  404.       return pos_type(-1);
  405.   }
  406.   else
  407.     return pos_type(-1);
  408. }
  409.  
  410.  
  411. template <class _CharT, class _Traits>
  412. int basic_filebuf<_CharT, _Traits>::sync()
  413. {
  414.   if (_M_in_output_mode)
  415.     return traits_type::eq_int_type(this->overflow(traits_type::eof()),
  416.                                     traits_type::eof())
  417.       ? -1
  418.       : 0;
  419.   else
  420.     return 0;
  421. }
  422.  
  423.  
  424. // Change the filebuf's locale.  This member function has no effect
  425. // unless it is called before any I/O is performed on the stream.
  426. template <class _CharT, class _Traits>
  427. void basic_filebuf<_CharT, _Traits>::imbue(const locale& __loc)
  428. {
  429.   if (!_M_in_input_mode &&! _M_in_output_mode && !_M_in_error_mode) {
  430.     this->_M_setup_codecvt(__loc);
  431.   }
  432. }
  433.  
  434. //----------------------------------------------------------------------
  435. // basic_filebuf<> helper functions.
  436.  
  437. //----------------------------------------
  438. // Helper functions for switching between modes.
  439.  
  440. // This member function is called if we're performing the first I/O
  441. // operation on a filebuf, or if we're performing an input operation 
  442. // immediately after a seek.
  443. template <class _CharT, class _Traits>
  444. bool basic_filebuf<_CharT, _Traits>::_M_switch_to_input_mode()
  445. {
  446.  
  447.   if (this->is_open() && (((int)_M_base.__o_mode() & (int)ios_base::in) !=0)
  448.       && (_M_in_output_mode == 0) && (_M_in_error_mode == 0)) {
  449.     if (!_M_int_buf && !_M_allocate_buffers())
  450.       return false;
  451.  
  452.     _M_ext_buf_converted = _M_ext_buf;
  453.     _M_ext_buf_end       = _M_ext_buf;
  454.  
  455.     _M_end_state    = _M_state;
  456.  
  457.     _M_in_input_mode = true;
  458.     return true;
  459.   }
  460.   else
  461.  
  462.     return false;
  463. }
  464.  
  465.  
  466. // This member function is called if we're performing the first I/O
  467. // operation on a filebuf, or if we're performing an output operation 
  468. // immediately after a seek.
  469. template <class _CharT, class _Traits>
  470. bool basic_filebuf<_CharT, _Traits>::_M_switch_to_output_mode()
  471. {
  472.   if (this->is_open() && (_M_base.__o_mode() & (int)ios_base::out) &&
  473.       _M_in_input_mode == 0 && _M_in_error_mode == 0) {
  474.  
  475.     if (!_M_int_buf && !_M_allocate_buffers())
  476.       return false;
  477.  
  478.     // In append mode, every write does an implicit seek to the end
  479.     // of the file.  Whenever leaving output mode, the end of file
  480.     // get put in the initial shift state.
  481.     if (_M_base.__o_mode() & ios_base::app)
  482.       _M_state = _State_type();
  483.  
  484.     this->setp(_M_int_buf, _M_int_buf_EOS - 1);
  485.     _M_in_output_mode = true;
  486.  
  487.     return true;
  488.   }
  489.   else
  490.     return false;
  491. }
  492.  
  493.  
  494. //----------------------------------------
  495. // Helper functions for input
  496.  
  497. // This member function is called if there is an error during input.
  498. // It puts the filebuf in error mode, clear the get area buffer, and
  499. // returns eof.
  500. // returns eof.  Error mode is sticky; it is cleared only by close or
  501. // seek.
  502.  
  503. template <class _CharT, class _Traits>
  504. __BF_int_type__
  505. basic_filebuf<_CharT, _Traits>::_M_input_error()
  506. {
  507.    this->_M_exit_input_mode();   
  508.   _M_in_output_mode = false;
  509.   _M_in_error_mode = true;
  510.   this->setg(0, 0, 0);
  511.   return traits_type::eof();
  512. }
  513.  
  514. template <class _CharT, class _Traits>
  515. __BF_int_type__ 
  516. basic_filebuf<_CharT, _Traits>::_M_underflow_aux() 
  517. {
  518.   // We have the state and file position from the end of the internal
  519.   // buffer.  This round, they become the beginning of the internal buffer.
  520.   _M_state    = _M_end_state;
  521.  
  522.   // Fill the external buffer.  Start with any leftover characters that
  523.   // didn't get converted last time.
  524.   if (_M_ext_buf_end > _M_ext_buf_converted)
  525.  
  526.     _M_ext_buf_end = copy(_M_ext_buf_converted, _M_ext_buf_end, _M_ext_buf);
  527.     // boris : copy_backward did not work
  528.     //_M_ext_buf_end = copy_backward(_M_ext_buf_converted, _M_ext_buf_end, 
  529.     //_M_ext_buf+ (_M_ext_buf_end - _M_ext_buf_converted));
  530.   else
  531.     _M_ext_buf_end = _M_ext_buf;
  532.  
  533.   // Now fill the external buffer with characters from the file.  This is
  534.   // a loop because occasonally we don't get enough external characters
  535.   // to make progress.
  536.   while (true) {
  537.     ptrdiff_t __n = _M_base._M_read(_M_ext_buf_end, _M_ext_buf_EOS - _M_ext_buf_end);
  538.  
  539.     // Don't enter error mode for a failed read.  Error mode is sticky,
  540.     // and we might succeed if we try again.
  541.     if (__n <= 0)
  542.       return traits_type::eof();
  543.  
  544.     // Convert the external buffer to internal characters.  
  545.     _M_ext_buf_end += __n;
  546.     const char*   __enext;
  547.     _CharT* __inext;
  548.  
  549.     typename _Codecvt::result __status
  550.       = _M_codecvt->in(_M_end_state,
  551.                        _M_ext_buf, _M_ext_buf_end, __enext,
  552.                        _M_int_buf, _M_int_buf_EOS, __inext);
  553.  
  554.     // Error conditions: (1) Return value of error.  (2) Producing internal
  555.     // characters without consuming external characters.  (3) In fixed-width
  556.     // encodings, producing an internal sequence whose length is inconsistent
  557.     // with that of the internal sequence.  (4) Failure to produce any 
  558.     // characters if we have enough characters in the external buffer, where
  559.     // "enough" means the largest possible width of a single character.
  560.     if (__status == _Codecvt::noconv)
  561.       return _Noconv_input<_Traits>::_M_doit(this);
  562.  
  563.     else if (__status == _Codecvt::error ||
  564.              (__inext != _M_int_buf && __enext == _M_ext_buf) ||
  565.              (_M_constant_width &&
  566.               //         __inext - _M_int_buf != _M_width * (__enext - _M_ext_buf)) ||
  567.               (__inext - _M_int_buf) *  _M_width != (__enext - _M_ext_buf)) ||
  568.              (__inext == _M_int_buf && __enext - _M_ext_buf >= _M_max_width))
  569.       return _M_input_error();
  570.     
  571.     else if (__inext != _M_int_buf) {
  572.       _M_ext_buf_converted = _M_ext_buf + (__enext - _M_ext_buf);
  573.       this->setg(_M_int_buf, _M_int_buf, __inext);
  574.       return traits_type::to_int_type(*_M_int_buf);
  575.     }
  576.     // We need to go around the loop again to get more external characters.
  577.   } 
  578. }
  579.  
  580. //----------------------------------------
  581. // Helper functions for output
  582.  
  583. // This member function is called if there is an error during output.
  584. // It puts the filebuf in error mode, clear the put area buffer, and
  585. // returns eof.  Error mode is sticky; it is cleared only by close or
  586. // seek.
  587. template <class _CharT, class _Traits>
  588. __BF_int_type__
  589. basic_filebuf<_CharT, _Traits>::_M_output_error()
  590. {
  591.   _M_in_output_mode = false;
  592.   _M_in_input_mode = false;
  593.   _M_in_error_mode = true;
  594.   this->setp(0, 0);
  595.   return traits_type::eof();
  596. }
  597.  
  598.  
  599. // Write whatever sequence of characters is necessary to get back to
  600. // the initial shift state.  This function overwrites the external
  601. // buffer, changes the external file position, and changes the state.
  602. // Precondition: the internal buffer is empty.
  603. template <class _CharT, class _Traits>
  604. bool basic_filebuf<_CharT, _Traits>::_M_unshift()
  605. {
  606.   if (_M_in_output_mode && !_M_constant_width) {
  607.     typename _Codecvt::result __status;
  608.     do {
  609.       char* __enext = _M_ext_buf;
  610.       __status = _M_codecvt->unshift(_M_state,
  611.                                      _M_ext_buf, _M_ext_buf_EOS, __enext);
  612.       if (__status == _Codecvt::noconv ||
  613.           (__enext == _M_ext_buf && __status == _Codecvt::ok))
  614.         return true;
  615.       else if (__status == _Codecvt::error)
  616.         return false;
  617.       else if (!_M_write(_M_ext_buf, __enext - _M_ext_buf))
  618.         return false;
  619.     } while(__status == _Codecvt::partial);
  620.   }
  621.  
  622.   return true;
  623. }
  624.  
  625.  
  626. //----------------------------------------
  627. // Helper functions for buffer allocation and deallocation
  628.  
  629. // This member function is called when we're initializing a filebuf's
  630. // internal and external buffers.  The argument is the size of the
  631. // internal buffer; the external buffer is sized using the character
  632. // width in the current encoding.  Preconditions: the buffers are currently
  633. // null.  __n >= 1.  __buf is either a null pointer or a pointer to an 
  634. // array show size is at least __n.
  635.  
  636. // We need __n >= 1 for two different reasons.  For input, the base
  637. // class always needs a buffer because of the sementics of underflow().
  638. // For output, we want to have an internal buffer that's larger by one
  639. // element than the buffer that the base class knows about.  (See 
  640. // basic_filebuf<>::overflow() for the reason.)
  641. template <class _CharT, class _Traits>
  642. bool 
  643. basic_filebuf<_CharT, _Traits>::_M_allocate_buffers(_CharT* __buf, streamsize __n)
  644. {
  645.  
  646.   if (__buf == 0) {
  647.     _M_int_buf = __STATIC_CAST(_CharT*,malloc(__n * sizeof(_CharT)));
  648.     if (! _M_int_buf)
  649.       return false;
  650.     _M_int_buf_dynamic = true;
  651.   }
  652.   else {
  653.     _M_int_buf = __buf;
  654.     _M_int_buf_dynamic = false;
  655.   }
  656.   
  657.   size_t __ebufsiz = (max)(__n * (max)(_M_codecvt->encoding(), 1),
  658.                       streamsize(_M_codecvt->max_length()));
  659.  
  660.   _M_ext_buf = __STATIC_CAST(char*,malloc(__ebufsiz));
  661.   if (!_M_ext_buf) {
  662.     _M_deallocate_buffers();
  663.     return false;
  664.   }
  665.  
  666.   _M_int_buf_EOS = _M_int_buf + __n;
  667.   _M_ext_buf_EOS = _M_ext_buf + __ebufsiz;
  668.   return true;
  669. }
  670.  
  671. // Abbreviation for the most common case.
  672. template <class _CharT, class _Traits>
  673. bool basic_filebuf<_CharT, _Traits>::_M_allocate_buffers()
  674. {
  675.   // Choose a buffer that's at least 4096 characters long and that's a
  676.   // multiple of the page size.
  677.   streamsize __default_bufsiz =
  678.     ((_M_base.__page_size() + 4095UL) / _M_base.__page_size()) * _M_base.__page_size();
  679.   return _M_allocate_buffers(0, __default_bufsiz);
  680. }
  681.  
  682. template <class _CharT, class _Traits>
  683. void basic_filebuf<_CharT, _Traits>::_M_deallocate_buffers()
  684. {
  685.   if (_M_int_buf_dynamic)
  686.     free(_M_int_buf);
  687.   free(_M_ext_buf);
  688.   _M_int_buf     = 0;
  689.   _M_int_buf_EOS = 0;
  690.   _M_ext_buf     = 0;
  691.   _M_ext_buf_EOS = 0;
  692. }
  693.  
  694.  
  695. //----------------------------------------
  696. // Helper functiosn for seek and imbue
  697.  
  698. template <class _CharT, class _Traits>
  699. bool basic_filebuf<_CharT, _Traits>::_M_seek_init(bool __do_unshift) {
  700.   // If we're in error mode, leave it.
  701.    _M_in_error_mode = false;
  702.    
  703.   // Flush the output buffer if we're in output mode, and (conditionally)
  704.   // emit an unshift sequence.
  705.   if (_M_in_output_mode) {
  706.     bool __ok = !traits_type::eq_int_type(this->overflow(traits_type::eof()),
  707.                                           traits_type::eof());
  708.     if (__do_unshift)
  709.       __ok = __ok && this->_M_unshift();
  710.     if (!__ok) {
  711.       _M_in_output_mode = false;
  712.       _M_in_error_mode = true;
  713.       this->setp(0, 0);
  714.       return false;
  715.     }
  716.   }
  717.  
  718.   // Discard putback characters, if any.
  719.   if (_M_in_input_mode && _M_in_putback_mode)
  720.     _M_exit_putback_mode();
  721.  
  722.   return true;
  723. }
  724.  
  725.  
  726. // Change the filebuf's locale.  This member function has no effect
  727. // unless it is called before any I/O is performed on the stream.
  728. template <class _CharT, class _Traits>
  729. void basic_filebuf<_CharT, _Traits>::_M_setup_codecvt(const locale& __loc)
  730. {
  731.   _M_codecvt = &use_facet<_Codecvt>(__loc) ;
  732.   int __encoding    = _M_codecvt->encoding();
  733.  
  734.   _M_width          = (max)(__encoding, 1);
  735.   _M_max_width      = _M_codecvt->max_length();
  736.   _M_constant_width = __encoding > 0;
  737.   _M_always_noconv  = _M_codecvt->always_noconv();
  738. }
  739.  
  740. _STLP_END_NAMESPACE
  741.  
  742. # undef __BF_int_type__
  743. # undef __BF_pos_type__
  744. # undef __BF_off_type__
  745.  
  746. # endif /* defined (_STLP_EXPOSE_STREAM_IMPLEMENTATION) */
  747.  
  748. #endif /* _STLP_FSTREAM_C */
  749.  
  750.