genericopenlibs/cppstdlib/stl/stlport/stl/_fstream.c
changeset 31 ce057bb09d0b
child 45 4b03adbd26ca
equal deleted inserted replaced
30:e20de85af2ee 31:ce057bb09d0b
       
     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 
       
    67 template <class _CharT, class _Traits>
       
    68 basic_filebuf<_CharT, _Traits>*
       
    69 basic_filebuf<_CharT, _Traits>::close() {
       
    70   bool __ok = this->is_open();
       
    71 
       
    72   if (_M_in_output_mode) {
       
    73     __ok = __ok && !_Traits::eq_int_type(this->overflow(traits_type::eof()),
       
    74                                          traits_type::eof());
       
    75     __ok == __ok && this->_M_unshift();
       
    76   }
       
    77   else if (_M_in_input_mode)
       
    78       this->_M_exit_input_mode();
       
    79 
       
    80   // Note order of arguments.  We close the file even if __ok is false.
       
    81   __ok = _M_base._M_close() && __ok;
       
    82 
       
    83   // Restore the initial state, except that we don't deallocate the buffer
       
    84   // or mess with the cached codecvt information.
       
    85   _M_state = _M_end_state = _State_type();
       
    86   _M_ext_buf_converted = _M_ext_buf_end = 0;
       
    87 
       
    88   _M_mmap_base = 0;
       
    89   _M_mmap_len = 0;
       
    90 
       
    91   this->setg(0, 0, 0);
       
    92   this->setp(0, 0);
       
    93 
       
    94   _M_saved_eback = _M_saved_gptr = _M_saved_egptr = 0;
       
    95 
       
    96   _M_in_input_mode = _M_in_output_mode = _M_in_error_mode = _M_in_putback_mode
       
    97     = false;
       
    98 
       
    99   return __ok ? this : 0;
       
   100 }
       
   101 
       
   102 // This member function is called whenever we exit input mode.
       
   103 // It unmaps the memory-mapped file, if any, and sets
       
   104 // _M_in_input_mode to false.
       
   105 template <class _CharT, class _Traits>
       
   106 void basic_filebuf<_CharT, _Traits>::_M_exit_input_mode() {
       
   107    if (_M_mmap_base != 0)
       
   108      _M_base._M_unmap(_M_mmap_base, _M_mmap_len);
       
   109    _M_in_input_mode = false;
       
   110    _M_mmap_base = 0;
       
   111 }
       
   112 
       
   113 
       
   114 
       
   115 //----------------------------------------------------------------------
       
   116 // basic_filebuf<> helper functions.
       
   117 
       
   118 //----------------------------------------
       
   119 // Helper functions for switching between modes.
       
   120 
       
   121 // This member function is called if we're performing the first I/O
       
   122 // operation on a filebuf, or if we're performing an input operation
       
   123 // immediately after a seek.
       
   124 template <class _CharT, class _Traits>
       
   125 bool basic_filebuf<_CharT, _Traits>::_M_switch_to_input_mode() {
       
   126   if (this->is_open() && (((int)_M_base.__o_mode() & (int)ios_base::in) != 0)
       
   127       && (_M_in_output_mode == 0) && (_M_in_error_mode == 0)) {
       
   128     if (!_M_int_buf && !_M_allocate_buffers())
       
   129       return false;
       
   130 
       
   131     _M_ext_buf_converted = _M_ext_buf;
       
   132     _M_ext_buf_end       = _M_ext_buf;
       
   133 
       
   134     _M_end_state    = _M_state;
       
   135 
       
   136     _M_in_input_mode = true;
       
   137     return true;
       
   138   }
       
   139 
       
   140   return false;
       
   141 }
       
   142 
       
   143 
       
   144 // This member function is called if we're performing the first I/O
       
   145 // operation on a filebuf, or if we're performing an output operation
       
   146 // immediately after a seek.
       
   147 template <class _CharT, class _Traits>
       
   148 bool basic_filebuf<_CharT, _Traits>::_M_switch_to_output_mode() {
       
   149   if (this->is_open() && (_M_base.__o_mode() & (int)ios_base::out) &&
       
   150       _M_in_input_mode == 0 && _M_in_error_mode == 0) {
       
   151 
       
   152     if (!_M_int_buf && !_M_allocate_buffers())
       
   153       return false;
       
   154 
       
   155     // In append mode, every write does an implicit seek to the end
       
   156     // of the file.  Whenever leaving output mode, the end of file
       
   157     // get put in the initial shift state.
       
   158     if (_M_base.__o_mode() & ios_base::app)
       
   159       _M_state = _State_type();
       
   160 
       
   161     this->setp(_M_int_buf, _M_int_buf_EOS - 1);
       
   162     _M_in_output_mode = true;
       
   163     return true;
       
   164   }
       
   165 
       
   166   return false;
       
   167 }
       
   168 
       
   169 
       
   170 //----------------------------------------
       
   171 // Helper functions for input
       
   172 
       
   173 // This member function is called if there is an error during input.
       
   174 // It puts the filebuf in error mode, clear the get area buffer, and
       
   175 // returns eof.
       
   176 // returns eof.  Error mode is sticky; it is cleared only by close or
       
   177 // seek.
       
   178 
       
   179 template <class _CharT, class _Traits>
       
   180 __BF_int_type__
       
   181 basic_filebuf<_CharT, _Traits>::_M_input_error() {
       
   182    this->_M_exit_input_mode();
       
   183   _M_in_output_mode = false;
       
   184   _M_in_error_mode = true;
       
   185   this->setg(0, 0, 0);
       
   186   return traits_type::eof();
       
   187 }
       
   188 
       
   189 template <class _CharT, class _Traits>
       
   190 __BF_int_type__
       
   191 basic_filebuf<_CharT, _Traits>::_M_underflow_aux() {
       
   192   // We have the state and file position from the end of the internal
       
   193   // buffer.  This round, they become the beginning of the internal buffer.
       
   194   _M_state    = _M_end_state;
       
   195 
       
   196   // Fill the external buffer.  Start with any leftover characters that
       
   197   // didn't get converted last time.
       
   198   if (_M_ext_buf_end > _M_ext_buf_converted)
       
   199 
       
   200     _M_ext_buf_end = copy(_M_ext_buf_converted, _M_ext_buf_end, _M_ext_buf);
       
   201     // boris : copy_backward did not work
       
   202     //_M_ext_buf_end = copy_backward(_M_ext_buf_converted, _M_ext_buf_end,
       
   203     //_M_ext_buf+ (_M_ext_buf_end - _M_ext_buf_converted));
       
   204   else
       
   205     _M_ext_buf_end = _M_ext_buf;
       
   206 
       
   207   // Now fill the external buffer with characters from the file.  This is
       
   208   // a loop because occasionally we don't get enough external characters
       
   209   // to make progress.
       
   210   for (;;) {
       
   211     ptrdiff_t __n = _M_base._M_read(_M_ext_buf_end, _M_ext_buf_EOS - _M_ext_buf_end);
       
   212 
       
   213     // Don't enter error mode for a failed read.  Error mode is sticky,
       
   214     // and we might succeed if we try again.
       
   215     if (__n <= 0)
       
   216       return traits_type::eof();
       
   217 
       
   218     // Convert the external buffer to internal characters.
       
   219     _M_ext_buf_end += __n;
       
   220     const char*   __enext;
       
   221     _CharT* __inext;
       
   222 
       
   223     typename _Codecvt::result __status
       
   224       = _M_codecvt->in(_M_end_state,
       
   225                        _M_ext_buf, _M_ext_buf_end, __enext,
       
   226                        _M_int_buf, _M_int_buf_EOS, __inext);
       
   227 
       
   228     // Error conditions: (1) Return value of error.  (2) Producing internal
       
   229     // characters without consuming external characters.  (3) In fixed-width
       
   230     // encodings, producing an internal sequence whose length is inconsistent
       
   231     // with that of the internal sequence.  (4) Failure to produce any
       
   232     // characters if we have enough characters in the external buffer, where
       
   233     // "enough" means the largest possible width of a single character.
       
   234     if (__status == _Codecvt::noconv)
       
   235       return _Noconv_input<_Traits>::_M_doit(this);
       
   236     else if (__status == _Codecvt::error ||
       
   237              (__inext != _M_int_buf && __enext == _M_ext_buf) ||
       
   238              (_M_constant_width &&
       
   239               //         __inext - _M_int_buf != _M_width * (__enext - _M_ext_buf)) ||
       
   240               (__inext - _M_int_buf) *  _M_width != (__enext - _M_ext_buf)) ||
       
   241              (__inext == _M_int_buf && __enext - _M_ext_buf >= _M_max_width))
       
   242       return _M_input_error();
       
   243     else if (__inext != _M_int_buf) {
       
   244       _M_ext_buf_converted = _M_ext_buf + (__enext - _M_ext_buf);
       
   245       this->setg(_M_int_buf, _M_int_buf, __inext);
       
   246       return traits_type::to_int_type(*_M_int_buf);
       
   247     }
       
   248     // We need to go around the loop again to get more external characters.
       
   249   }
       
   250 }
       
   251 
       
   252 //----------------------------------------
       
   253 // Helper functions for output
       
   254 
       
   255 // This member function is called if there is an error during output.
       
   256 // It puts the filebuf in error mode, clear the put area buffer, and
       
   257 // returns eof.  Error mode is sticky; it is cleared only by close or
       
   258 // seek.
       
   259 template <class _CharT, class _Traits>
       
   260 __BF_int_type__
       
   261 basic_filebuf<_CharT, _Traits>::_M_output_error() {
       
   262   _M_in_output_mode = false;
       
   263   _M_in_input_mode = false;
       
   264   _M_in_error_mode = true;
       
   265   this->setp(0, 0);
       
   266   return traits_type::eof();
       
   267 }
       
   268 
       
   269 
       
   270 // Write whatever sequence of characters is necessary to get back to
       
   271 // the initial shift state.  This function overwrites the external
       
   272 // buffer, changes the external file position, and changes the state.
       
   273 // Precondition: the internal buffer is empty.
       
   274 template <class _CharT, class _Traits>
       
   275 bool basic_filebuf<_CharT, _Traits>::_M_unshift() {
       
   276   if (_M_in_output_mode && !_M_constant_width) {
       
   277     typename _Codecvt::result __status;
       
   278     do {
       
   279       char* __enext = _M_ext_buf;
       
   280       __status = _M_codecvt->unshift(_M_state,
       
   281                                      _M_ext_buf, _M_ext_buf_EOS, __enext);
       
   282       if (__status == _Codecvt::noconv ||
       
   283           (__enext == _M_ext_buf && __status == _Codecvt::ok))
       
   284         return true;
       
   285       else if (__status == _Codecvt::error)
       
   286         return false;
       
   287       else if (!_M_write(_M_ext_buf, __enext - _M_ext_buf))
       
   288         return false;
       
   289     } while (__status == _Codecvt::partial);
       
   290   }
       
   291 
       
   292   return true;
       
   293 }
       
   294 
       
   295 
       
   296 //----------------------------------------
       
   297 // Helper functions for buffer allocation and deallocation
       
   298 
       
   299 // This member function is called when we're initializing a filebuf's
       
   300 // internal and external buffers.  The argument is the size of the
       
   301 // internal buffer; the external buffer is sized using the character
       
   302 // width in the current encoding.  Preconditions: the buffers are currently
       
   303 // null.  __n >= 1.  __buf is either a null pointer or a pointer to an
       
   304 // array show size is at least __n.
       
   305 
       
   306 // We need __n >= 1 for two different reasons.  For input, the base
       
   307 // class always needs a buffer because of the semantics of underflow().
       
   308 // For output, we want to have an internal buffer that's larger by one
       
   309 // element than the buffer that the base class knows about.  (See
       
   310 // basic_filebuf<>::overflow() for the reason.)
       
   311 template <class _CharT, class _Traits>
       
   312 bool basic_filebuf<_CharT, _Traits>::_M_allocate_buffers(_CharT* __buf, streamsize __n) {
       
   313   //The major hypothesis in the following implementation is that size_t is unsigned.
       
   314   //We also need streamsize byte representation to be larger or equal to the int
       
   315   //representation to correctly store the encoding information.
       
   316   _STLP_STATIC_ASSERT(!numeric_limits<size_t>::is_signed &&
       
   317                       sizeof(streamsize) >= sizeof(int))
       
   318 
       
   319   if (__buf == 0) {
       
   320     streamsize __bufsize = __n * sizeof(_CharT);
       
   321     //We first check that the streamsize representation can't overflow a size_t one.
       
   322     //If it can, we check that __bufsize is not higher than the size_t max value.
       
   323     if ((sizeof(streamsize) > sizeof(size_t)) &&
       
   324         (__bufsize > __STATIC_CAST(streamsize, (numeric_limits<size_t>::max)())))
       
   325       return false;
       
   326     _M_int_buf = __STATIC_CAST(_CharT*, malloc(__STATIC_CAST(size_t, __bufsize)));
       
   327     if (!_M_int_buf)
       
   328       return false;
       
   329     _M_int_buf_dynamic = true;
       
   330   }
       
   331   else {
       
   332     _M_int_buf = __buf;
       
   333     _M_int_buf_dynamic = false;
       
   334   }
       
   335 
       
   336   streamsize __ebufsiz = (max)(__n * __STATIC_CAST(streamsize, _M_width),
       
   337                                __STATIC_CAST(streamsize, _M_codecvt->max_length()));
       
   338   _M_ext_buf = 0;
       
   339   if ((sizeof(streamsize) < sizeof(size_t)) ||
       
   340       ((sizeof(streamsize) == sizeof(size_t)) && numeric_limits<streamsize>::is_signed) ||
       
   341       (__ebufsiz <= __STATIC_CAST(streamsize, (numeric_limits<size_t>::max)()))) {
       
   342     _M_ext_buf = __STATIC_CAST(char*, malloc(__STATIC_CAST(size_t, __ebufsiz)));
       
   343   }
       
   344 
       
   345   if (!_M_ext_buf) {
       
   346     _M_deallocate_buffers();
       
   347     return false;
       
   348   }
       
   349 
       
   350   _M_int_buf_EOS = _M_int_buf + __STATIC_CAST(ptrdiff_t, __n);
       
   351   _M_ext_buf_EOS = _M_ext_buf + __STATIC_CAST(ptrdiff_t, __ebufsiz);
       
   352   return true;
       
   353 }
       
   354 
       
   355 // Abbreviation for the most common case.
       
   356 template <class _CharT, class _Traits>
       
   357 bool basic_filebuf<_CharT, _Traits>::_M_allocate_buffers() {
       
   358   // Choose a buffer that's at least 4096 characters long and that's a
       
   359   // multiple of the page size.
       
   360   streamsize __default_bufsiz =
       
   361     ((_M_base.__page_size() + 4095UL) / _M_base.__page_size()) * _M_base.__page_size();
       
   362   return _M_allocate_buffers(0, __default_bufsiz);
       
   363 }
       
   364 
       
   365 template <class _CharT, class _Traits>
       
   366 void basic_filebuf<_CharT, _Traits>::_M_deallocate_buffers() {
       
   367   if (_M_int_buf_dynamic)
       
   368     free(_M_int_buf);
       
   369   free(_M_ext_buf);
       
   370   _M_int_buf     = 0;
       
   371   _M_int_buf_EOS = 0;
       
   372   _M_ext_buf     = 0;
       
   373   _M_ext_buf_EOS = 0;
       
   374 }
       
   375 
       
   376 
       
   377 //----------------------------------------
       
   378 // Helper functiosn for seek and imbue
       
   379 
       
   380 template <class _CharT, class _Traits>
       
   381 bool basic_filebuf<_CharT, _Traits>::_M_seek_init(bool __do_unshift) {
       
   382   // If we're in error mode, leave it.
       
   383    _M_in_error_mode = false;
       
   384 
       
   385   // Flush the output buffer if we're in output mode, and (conditionally)
       
   386   // emit an unshift sequence.
       
   387   if (_M_in_output_mode) {
       
   388     bool __ok = !traits_type::eq_int_type(this->overflow(traits_type::eof()),
       
   389                                           traits_type::eof());
       
   390     if (__do_unshift)
       
   391       __ok = __ok && this->_M_unshift();
       
   392     if (!__ok) {
       
   393       _M_in_output_mode = false;
       
   394       _M_in_error_mode = true;
       
   395       this->setp(0, 0);
       
   396       return false;
       
   397     }
       
   398   }
       
   399 
       
   400   // Discard putback characters, if any.
       
   401   if (_M_in_input_mode && _M_in_putback_mode)
       
   402     _M_exit_putback_mode();
       
   403 
       
   404   return true;
       
   405 }
       
   406 
       
   407 
       
   408 /* Change the filebuf's locale.  This member function has no effect
       
   409  * unless it is called before any I/O is performed on the stream.
       
   410  * This function is called on construction and on an imbue call. In the
       
   411  * case of the construction the codecvt facet might be a custom one if
       
   412  * the basic_filebuf user has instanciate it with a custom char_traits.
       
   413  * The user will have to call imbue before any I/O operation.
       
   414  */
       
   415 template <class _CharT, class _Traits>
       
   416 void basic_filebuf<_CharT, _Traits>::_M_setup_codecvt(const locale& __loc, bool __on_imbue) {
       
   417   if (has_facet<_Codecvt>(__loc)) {
       
   418     _M_codecvt = &use_facet<_Codecvt>(__loc) ;
       
   419     int __encoding    = _M_codecvt->encoding();
       
   420 
       
   421     _M_width          = (max)(__encoding, 1);
       
   422     _M_max_width      = _M_codecvt->max_length();
       
   423     _M_constant_width = __encoding > 0;
       
   424     _M_always_noconv  = _M_codecvt->always_noconv();
       
   425   }
       
   426   else {
       
   427     _M_codecvt = 0;
       
   428     _M_width = _M_max_width = 1;
       
   429     _M_constant_width = _M_always_noconv  = false;
       
   430     if (__on_imbue) {
       
   431       //This call will generate an exception reporting the problem.
       
   432       use_facet<_Codecvt>(__loc);
       
   433     }
       
   434   }
       
   435 }
       
   436 
       
   437 _STLP_END_NAMESPACE
       
   438 
       
   439 # undef __BF_int_type__
       
   440 # undef __BF_pos_type__
       
   441 # undef __BF_off_type__
       
   442 
       
   443 #endif /* _STLP_FSTREAM_C */
       
   444 
       
   445 // Local Variables:
       
   446 // mode:C++
       
   447 // End: