Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. // File based streams -*- C++ -*-
  2.  
  3. // Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
  4. //
  5. // This file is part of the GNU ISO C++ Library.  This library is free
  6. // software; you can redistribute it and/or modify it under the
  7. // terms of the GNU General Public License as published by the
  8. // Free Software Foundation; either version 2, or (at your option)
  9. // any later version.
  10.  
  11. // This library is distributed in the hope that it will be useful,
  12. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. // GNU General Public License for more details.
  15.  
  16. // You should have received a copy of the GNU General Public License along
  17. // with this library; see the file COPYING.  If not, write to the Free
  18. // Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  19. // USA.
  20.  
  21. // As a special exception, you may use this file as part of a free software
  22. // library without restriction.  Specifically, if other files instantiate
  23. // templates or use macros or inline functions from this file, or you compile
  24. // this file and link it with other files to produce an executable, this
  25. // file does not by itself cause the resulting executable to be covered by
  26. // the GNU General Public License.  This exception does not however
  27. // invalidate any other reasons why the executable file might be covered by
  28. // the GNU General Public License.
  29.  
  30. //
  31. // ISO C++ 14882: 27.8  File-based streams
  32. //
  33.  
  34. #ifndef _CPP_BITS_FSTREAM_TCC
  35. #define _CPP_BITS_FSTREAM_TCC 1
  36.  
  37. namespace std
  38. {
  39.   template<typename _CharT, typename _Traits>
  40.     void
  41.     basic_filebuf<_CharT, _Traits>::
  42.     _M_allocate_file()
  43.     {
  44.       if (!_M_file)
  45.         {
  46.           _M_buf_unified = true; // Tie input to output for basic_filebuf.
  47.           try
  48.             { _M_file = new __file_type(&_M_lock); }
  49.           catch(...)
  50.             {
  51.               delete _M_file;
  52.               __throw_exception_again;
  53.             }
  54.         }
  55.     }
  56.  
  57.   template<typename _CharT, typename _Traits>
  58.     void
  59.     basic_filebuf<_CharT, _Traits>::
  60.     _M_allocate_internal_buffer()
  61.     {
  62.       if (!_M_buf && _M_buf_size_opt)
  63.         {
  64.           _M_buf_size = _M_buf_size_opt;
  65.  
  66.           // Allocate internal buffer.
  67.           try { _M_buf = new char_type[_M_buf_size]; }
  68.           catch(...)
  69.             {
  70.               delete [] _M_buf;
  71.               __throw_exception_again;
  72.             }
  73.           _M_buf_allocated = true;
  74.         }
  75.     }
  76.  
  77.   // Both close and setbuf need to deallocate internal buffers, if it exists.
  78.   template<typename _CharT, typename _Traits>
  79.     void
  80.     basic_filebuf<_CharT, _Traits>::
  81.     _M_destroy_internal_buffer()
  82.     {
  83.       if (_M_buf_allocated)
  84.         {
  85.           delete [] _M_buf;
  86.           _M_buf = NULL;
  87.           _M_buf_allocated = false;
  88.           this->setg(NULL, NULL, NULL);
  89.           this->setp(NULL, NULL);
  90.         }
  91.     }
  92.  
  93.  template<typename _CharT, typename _Traits>
  94.     void
  95.     basic_filebuf<_CharT, _Traits>::
  96.     _M_allocate_pback_buffer()
  97.     {
  98.       if (!_M_pback && _M_pback_size)
  99.         {
  100.           // Allocate pback buffer.
  101.           try
  102.             { _M_pback = new char_type[_M_pback_size]; }
  103.           catch(...)
  104.             {
  105.               delete [] _M_pback;
  106.               __throw_exception_again;
  107.             }
  108.         }
  109.     }
  110.  
  111.   template<typename _CharT, typename _Traits>
  112.     basic_filebuf<_CharT, _Traits>::
  113.     basic_filebuf()
  114.     : __streambuf_type(), _M_file(NULL), _M_state_cur(__state_type()),
  115.     _M_state_beg(__state_type()), _M_buf_allocated(false),
  116.     _M_last_overflowed(false)
  117.     { }
  118.  
  119.   template<typename _CharT, typename _Traits>
  120.     basic_filebuf<_CharT, _Traits>::
  121.     basic_filebuf(__c_file_type* __f, ios_base::openmode __mode, int_type __s)
  122.     : __streambuf_type(),  _M_file(NULL), _M_state_cur(__state_type()),
  123.     _M_state_beg(__state_type()), _M_buf_allocated(false),
  124.     _M_last_overflowed(false)
  125.     {
  126.       _M_allocate_file();
  127.       _M_file->sys_open(__f, __mode);
  128.       if (this->is_open())
  129.         {
  130.           _M_mode = __mode;
  131.           if (__s)
  132.             {
  133.               _M_buf_size_opt = __s;
  134.               _M_allocate_internal_buffer();
  135.               _M_set_indeterminate();
  136.             }
  137.           _M_allocate_pback_buffer();
  138.         }
  139.     }
  140.  
  141.   template<typename _CharT, typename _Traits>
  142.     basic_filebuf<_CharT, _Traits>::__filebuf_type*
  143.     basic_filebuf<_CharT, _Traits>::
  144.     open(const char* __s, ios_base::openmode __mode)
  145.     {
  146.       __filebuf_type *__ret = NULL;
  147.       if (!this->is_open())
  148.         {
  149.           _M_allocate_file();
  150.           _M_file->open(__s, __mode);
  151.           if (this->is_open())
  152.             {
  153.               _M_allocate_internal_buffer();
  154.               _M_allocate_pback_buffer();
  155.               _M_mode = __mode;
  156.              
  157.               // For time being, set both (in/out) sets  of pointers.
  158.               _M_set_indeterminate();
  159.               if (__mode & ios_base::ate
  160.                   && this->seekoff(0, ios_base::end, __mode) < 0)
  161.                 this->close();
  162.               __ret = this;
  163.             }
  164.         }
  165.       return __ret;
  166.     }
  167.  
  168.   template<typename _CharT, typename _Traits>
  169.     basic_filebuf<_CharT, _Traits>::__filebuf_type*
  170.     basic_filebuf<_CharT, _Traits>::
  171.     close()
  172.     {
  173.       __filebuf_type *__ret = NULL;
  174.       if (this->is_open())
  175.         {
  176.           bool __testput = _M_out_cur && _M_out_beg < _M_out_end;
  177.           if (__testput)
  178.             _M_really_overflow(traits_type::eof());
  179.  
  180.           // NB: Do this here so that re-opened filebufs will be cool...
  181.           _M_pback_destroy();
  182.  
  183. #if 0
  184.           // XXX not done
  185.           if (_M_last_overflowed)
  186.             {
  187.               _M_output_unshift();
  188.               _M_really_overflow(traits_type::eof());
  189.             }
  190. #endif
  191.  
  192.           _M_mode = ios_base::openmode(0);
  193.           _M_destroy_internal_buffer();
  194.  
  195.           if (_M_pback)
  196.             {
  197.               delete [] _M_pback;
  198.               _M_pback = NULL;
  199.             }
  200.           __ret = this;
  201.         }
  202.  
  203.       // Can actually allocate this file as part of an open and never
  204.       // have it be opened.....
  205.       if (_M_file)
  206.         {
  207.           delete _M_file;
  208.           _M_file = NULL;
  209.         }
  210.       _M_last_overflowed = false;      
  211.       return __ret;
  212.     }
  213.  
  214.   template<typename _CharT, typename _Traits>
  215.     streamsize
  216.     basic_filebuf<_CharT, _Traits>::
  217.     showmanyc()
  218.     {
  219.       streamsize __ret = -1;
  220.       bool __testin = _M_mode & ios_base::in;
  221.  
  222.       if (__testin)
  223.         {
  224.           bool __testeof = false;
  225.           if (_M_in_cur >= _M_in_end)
  226.             __testeof = this->underflow() == traits_type::eof();
  227.           if (!__testeof)
  228.             __ret = _M_in_end - _M_in_cur;
  229.         }
  230.       _M_last_overflowed = false;      
  231.       return __ret;
  232.     }
  233.  
  234.   template<typename _CharT, typename _Traits>
  235.     basic_filebuf<_CharT, _Traits>::int_type
  236.     basic_filebuf<_CharT, _Traits>::
  237.     underflow()
  238.     {
  239.       int_type __ret = traits_type::eof();
  240.       bool __testin = _M_mode & ios_base::in;
  241.       bool __testout = _M_mode & ios_base::out;
  242.  
  243.       // XXX Should re-enable codecvt bits disabled after 2.90.8.
  244.       if (__testin)
  245.         {
  246.           // Check for pback madness, and if so swich back to the
  247.           // normal buffers and jet outta here before expensive
  248.           // fileops happen...
  249.           if (_M_pback_init)
  250.             {
  251.               _M_pback_destroy();
  252.               if (_M_in_cur < _M_in_end)
  253.                 return traits_type::to_int_type(*_M_in_cur);
  254.             }
  255.  
  256.           bool __testget = _M_in_cur && _M_in_beg < _M_in_cur;
  257.           bool __testinit = _M_is_indeterminate();
  258.           // Sync internal and external buffers.
  259.           // NB: __testget -> __testput as _M_buf_unified here.
  260.           if (__testget)
  261.             {
  262.               if (__testout)
  263.                 _M_really_overflow();
  264. #if _GLIBCPP_AVOID_FSEEK
  265.               else if ((_M_in_cur - _M_in_beg) == 1)
  266.                 _M_file->sys_getc();
  267. #endif
  268.               else
  269.                 _M_file->seekoff(_M_in_cur - _M_in_beg,
  270.                                  ios_base::cur, ios_base::in);
  271.             }
  272.  
  273.           if (__testinit || __testget)
  274.             {
  275.               // Assume buffered case, need to refill internal buffers.
  276.               streamsize __size = _M_file->xsgetn(_M_in_beg, _M_buf_size);
  277.               if (0 < __size)
  278.                 {
  279.                   _M_set_determinate(__size);
  280.                   if (__testout)
  281.                     _M_out_cur = _M_in_cur;
  282.                   __ret = traits_type::to_int_type(*_M_in_cur);
  283. #if _GLIBCPP_AVOID_FSEEK
  284.                   if (__size == 1)
  285.                     _M_file->sys_ungetc(*_M_in_cur);
  286.                   else
  287.                     {
  288. #endif
  289.                   streamoff __p = _M_file->seekoff(0 - __size, ios_base::cur,
  290.                                                    ios_base::in);
  291.                   if (__p == -1)
  292.                     {
  293.                       // XXX Something is wrong, do error checking.
  294.                     }
  295. #if _GLIBCPP_AVOID_FSEEK
  296.                     }
  297. #endif
  298.                 }          
  299.             }
  300.         }
  301.       _M_last_overflowed = false;      
  302.       return __ret;
  303.     }
  304.  
  305.   template<typename _CharT, typename _Traits>
  306.     basic_filebuf<_CharT, _Traits>::int_type
  307.     basic_filebuf<_CharT, _Traits>::
  308.     pbackfail(int_type __i)
  309.     {
  310.       int_type __ret = traits_type::eof();
  311.       bool __testin = _M_mode & ios_base::in;
  312.  
  313.       if (__testin)
  314.         {
  315.           bool __testpb = _M_in_beg < _M_in_cur;
  316.           char_type __c = traits_type::to_char_type(__i);
  317.           bool __testeof = traits_type::eq_int_type(__i, __ret);
  318.  
  319.           if (__testpb)
  320.             {
  321.               bool __testout = _M_mode & ios_base::out;
  322.               bool __testeq = traits_type::eq(__c, this->gptr()[-1]);
  323.  
  324.               // Try to put back __c into input sequence in one of three ways.
  325.               // Order these tests done in is unspecified by the standard.
  326.               if (!__testeof && __testeq)
  327.                 {
  328.                   --_M_in_cur;
  329.                   if (__testout)
  330.                     --_M_out_cur;
  331.                   __ret = __i;
  332.                 }
  333.               else if (__testeof)
  334.                 {
  335.                   --_M_in_cur;
  336.                   if (__testout)
  337.                     --_M_out_cur;
  338.                   __ret = traits_type::not_eof(__i);
  339.                 }
  340.               else if (!__testeof)
  341.                 {
  342.                   --_M_in_cur;
  343.                   if (__testout)
  344.                     --_M_out_cur;
  345.                   _M_pback_create();
  346.                   *_M_in_cur = __c;
  347.                   __ret = __i;
  348.                 }
  349.             }
  350.           else
  351.             {    
  352.               // At the beginning of the buffer, need to make a
  353.               // putback position available.
  354.               this->seekoff(-1, ios_base::cur);
  355.               this->underflow();
  356.               if (!__testeof)
  357.                 {
  358.                   if (!traits_type::eq(__c, *_M_in_cur))
  359.                     {
  360.                       _M_pback_create();
  361.                       *_M_in_cur = __c;
  362.                     }
  363.                   __ret = __i;
  364.                 }
  365.               else
  366.                 __ret = traits_type::not_eof(__i);
  367.             }
  368.         }
  369.       _M_last_overflowed = false;      
  370.       return __ret;
  371.     }
  372.  
  373.   template<typename _CharT, typename _Traits>
  374.     basic_filebuf<_CharT, _Traits>::int_type
  375.     basic_filebuf<_CharT, _Traits>::
  376.     overflow(int_type __c)
  377.     {
  378.       int_type __ret = traits_type::eof();
  379.       bool __testput = _M_out_cur && _M_out_cur < _M_buf + _M_buf_size;
  380.       bool __testout = _M_mode & ios_base::out;
  381.      
  382.       if (__testout)
  383.         {
  384.           if (__testput)
  385.             {
  386.               *_M_out_cur = traits_type::to_char_type(__c);
  387.               _M_out_cur_move(1);
  388.               __ret = traits_type::not_eof(__c);
  389.             }
  390.           else
  391.             __ret = this->_M_really_overflow(__c);
  392.         }
  393.  
  394.       _M_last_overflowed = false;    // Set in _M_really_overflow, below.
  395.       return __ret;
  396.     }
  397.  
  398.   template<typename _CharT, typename _Traits>
  399.     basic_filebuf<_CharT, _Traits>::int_type
  400.     basic_filebuf<_CharT, _Traits>::
  401.     _M_really_overflow(int_type __c)
  402.     {
  403.       int_type __ret = traits_type::eof();
  404.       bool __testput = _M_out_cur && _M_out_beg < _M_out_end;
  405.       bool __testunbuffered = _M_file && !_M_buf_size;
  406.  
  407.       if (__testput || __testunbuffered)
  408.         {
  409. #if 1
  410.           int __plen = _M_out_end - _M_out_beg;
  411.           streamsize __len = 0;
  412.  
  413.           if (__plen)
  414.             __len = _M_file->xsputn(_M_out_beg, __plen);
  415.  
  416.           if (__c !=traits_type::eof())
  417.             {
  418.               char_type __pending = traits_type::to_char_type(__c);
  419.               __len += _M_file->xsputn(&__pending, 1);
  420.               ++__plen;
  421.             }
  422.  
  423.           // NB: Need this so that external byte sequence reflects
  424.           // internal buffer.
  425.           _M_file->sync();
  426.           if (__len == __plen)
  427.             {
  428.               _M_set_indeterminate();
  429.               __ret = traits_type::not_eof(__c);
  430.             }
  431. #else
  432.           // Part one: Allocate temporary conversion buffer on
  433.           // stack. Convert internal buffer plus __c (ie,
  434.           // "pending sequence") to temporary conversion buffer.
  435.           int __plen = _M_out_end - _M_out_beg;
  436.           char_type* __pbuf = static_cast<char_type*>(__builtin_alloca(sizeof(char_type) * __plen + 1));
  437.           traits_type::copy(__pbuf, this->pbase(), __plen);
  438.           if (!__testeof)
  439.             {
  440.               __pbuf[__plen] = traits_type::to_char_type(__c);
  441.               ++__plen;
  442.             }
  443.  
  444.           char_type* __pend;
  445.           char* __conv_buf = static_cast<char*>(__builtin_alloca(__plen));
  446.           char* __conv_end;
  447.           _M_state_beg = _M_state_cur;
  448.  
  449.           __res_type __r = _M_fcvt->out(_M_state_cur,
  450.                                         __pbuf, __pbuf + __plen,
  451.                                         const_cast<const char_type*&>(__pend),
  452.                                         __conv_buf, __conv_buf + __plen,
  453.                                         __conv_end);
  454.          
  455.           // Part two: (Re)spill converted "pending sequence"
  456.           // contents (now in temporary conversion buffer) to
  457.           // external buffer (_M_file->_IO_*) using
  458.           // _M_file->sys_write(), and do error (minimal) checking.
  459.           if (__r != codecvt_base::error)
  460.             {
  461.               streamsize __len = _M_file->xsputn(__conv_buf, __plen);
  462.               // NB: Need this so that external byte sequence reflects
  463.               // internal buffer.
  464.               _M_file->sync();
  465.               if (__len == __plen)
  466.                 {
  467.                   _M_set_indeterminate();
  468.                   __ret = traits_type::not_eof(__c);
  469.                 }
  470.             }
  471. #endif
  472.         }            
  473.       _M_last_overflowed = true;       
  474.       return __ret;
  475.     }
  476.  
  477.   template<typename _CharT, typename _Traits>
  478.     basic_filebuf<_CharT, _Traits>::__streambuf_type*
  479.     basic_filebuf<_CharT, _Traits>::
  480.     setbuf(char_type* __s, streamsize __n)
  481.     {
  482.       if (!this->is_open() && __s == 0 && __n == 0)
  483.         _M_buf_size_opt = 0;
  484.       else if (__s && __n)
  485.         {
  486.           // This is implementation-defined behavior, and assumes
  487.           // that an external char_type array of length (__s + __n)
  488.           // exists and has been pre-allocated. If this is not the
  489.           // case, things will quickly blow up.
  490.           // Step 1: Destroy the current internal array.
  491.           _M_destroy_internal_buffer();
  492.          
  493.           // Step 2: Use the external array.
  494.           _M_buf = __s;
  495.           _M_buf_size_opt = _M_buf_size = __n;
  496.           _M_set_indeterminate();
  497.          
  498.         // Step 3: Make sure a pback buffer is allocated.
  499.           _M_allocate_pback_buffer();
  500.         }
  501.       _M_last_overflowed = false;      
  502.       return this;
  503.     }
  504.  
  505.   template<typename _CharT, typename _Traits>
  506.     basic_filebuf<_CharT, _Traits>::pos_type
  507.     basic_filebuf<_CharT, _Traits>::
  508.     seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode __mode)
  509.     {
  510.       pos_type __ret =  pos_type(off_type(-1));
  511.       bool __testopen = this->is_open();
  512.       bool __testin = __mode & ios_base::in && _M_mode & ios_base::in;
  513.       bool __testout = __mode & ios_base::out && _M_mode & ios_base::out;
  514.  
  515.       // Should probably do has_facet checks here.
  516.       int __width = use_facet<__codecvt_type>(_M_buf_locale).encoding();
  517.       if (__width < 0)
  518.         __width = 0;
  519.       bool __testfail = __off != 0  && __width <= 0;
  520.      
  521.       if (__testopen && !__testfail && (__testin || __testout))
  522.         {
  523.           // Ditch any pback buffers to avoid confusion.
  524.           _M_pback_destroy();
  525.  
  526.           if (__way != ios_base::cur || __off != 0)
  527.             {
  528.               off_type __computed_off = __width * __off;
  529.              
  530.               bool __testget = _M_in_cur && _M_in_beg < _M_in_end;
  531.               bool __testput = _M_out_cur && _M_out_beg < _M_out_end;
  532.               // Sync the internal and external streams.
  533.               // out
  534.               if (__testput || _M_last_overflowed)
  535.                 {
  536.                   // Part one: update the output sequence.
  537.                   this->sync();
  538.                   // Part two: output unshift sequence.
  539.                   _M_output_unshift();
  540.                 }
  541.               //in
  542.               // NB: underflow() rewinds the external buffer.
  543.               else if (__testget && __way == ios_base::cur)
  544.                 __computed_off += _M_in_cur - _M_in_beg;
  545.          
  546.               __ret = _M_file->seekoff(__computed_off, __way, __mode);
  547.               _M_set_indeterminate();
  548.             }
  549.           // NB: Need to do this in case _M_file in indeterminate
  550.           // state, ie _M_file->_offset == -1
  551.           else
  552.             {
  553.               __ret = _M_file->seekoff(__off, ios_base::cur, __mode);
  554.               __ret += max(_M_out_cur, _M_in_cur) - _M_buf;
  555.             }
  556.         }
  557.       _M_last_overflowed = false;      
  558.       return __ret;
  559.     }
  560.  
  561.   template<typename _CharT, typename _Traits>
  562.     basic_filebuf<_CharT, _Traits>::pos_type
  563.     basic_filebuf<_CharT, _Traits>::
  564.     seekpos(pos_type __pos, ios_base::openmode __mode)
  565.     {
  566.       pos_type __ret;
  567.       off_type __off = __pos;
  568.  
  569.       __ret = this->seekoff(__off, ios_base::beg, __mode);
  570.  
  571.       _M_last_overflowed = false;      
  572.       return __ret;
  573.     }
  574.  
  575.   template<typename _CharT, typename _Traits>
  576.     void
  577.     basic_filebuf<_CharT, _Traits>::
  578.     _M_output_unshift()
  579.     { }
  580.  
  581.   template<typename _CharT, typename _Traits>
  582.     void
  583.     basic_filebuf<_CharT, _Traits>::
  584.     imbue(const locale& __loc)
  585.     {
  586.       bool __testbeg = gptr() == eback() && pptr() == pbase();
  587.  
  588.       if (__testbeg && _M_buf_locale != __loc)
  589.         {
  590.           _M_buf_locale = __loc;
  591.           _M_buf_locale_init = true;
  592.         }
  593.  
  594.       // NB this may require the reconversion of previously
  595.       // converted chars. This in turn may cause the reconstruction
  596.       // of the original file. YIKES!!
  597.       // XXX The part in the above comment is not done.
  598.       _M_last_overflowed = false;      
  599.     }
  600.  
  601. } // namespace std
  602.  
  603. #endif // _CPP_BITS_FSTREAM_TCC
  604.  
  605.  
  606.