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