streambuf.tcc (basic_streambuf::sputbackc): Prefix "this->" to call to pbackfail.
[official-gcc.git] / libstdc++-v3 / include / bits / fstream.tcc
blob387f099ae983d0c7319a412a4edc7f651ac1f6fc
1 // File based streams -*- C++ -*-
3 // Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002
4 // Free Software Foundation, Inc.
5 //
6 // This file is part of the GNU ISO C++ Library.  This library is free
7 // software; you can redistribute it and/or modify it under the
8 // terms of the GNU General Public License as published by the
9 // Free Software Foundation; either version 2, or (at your option)
10 // any later version.
12 // This library is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 // GNU General Public License for more details.
17 // You should have received a copy of the GNU General Public License along
18 // with this library; see the file COPYING.  If not, write to the Free
19 // Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
20 // USA.
22 // As a special exception, you may use this file as part of a free software
23 // library without restriction.  Specifically, if other files instantiate
24 // templates or use macros or inline functions from this file, or you compile
25 // this file and link it with other files to produce an executable, this
26 // file does not by itself cause the resulting executable to be covered by
27 // the GNU General Public License.  This exception does not however
28 // invalidate any other reasons why the executable file might be covered by
29 // the GNU General Public License.
32 // ISO C++ 14882: 27.8  File-based streams
35 #ifndef _CPP_BITS_FSTREAM_TCC
36 #define _CPP_BITS_FSTREAM_TCC 1
38 #pragma GCC system_header
40 namespace std
42   template<typename _CharT, typename _Traits>
43     void
44     basic_filebuf<_CharT, _Traits>::
45     _M_allocate_internal_buffer()
46     {
47       if (!_M_buf && _M_buf_size_opt)
48         {
49           _M_buf_size = _M_buf_size_opt;
51           // Allocate internal buffer.
52           _M_buf = new char_type[_M_buf_size]; 
53           _M_buf_allocated = true;
54         }
55     }
57   // Both close and setbuf need to deallocate internal buffers, if it exists.
58   template<typename _CharT, typename _Traits>
59     void
60     basic_filebuf<_CharT, _Traits>::
61     _M_destroy_internal_buffer()
62     {
63       if (_M_buf_allocated)
64         {
65           delete [] _M_buf;
66           _M_buf = NULL;
67           _M_buf_allocated = false;
68           this->setg(NULL, NULL, NULL);
69           this->setp(NULL, NULL);
70         }
71     }
73   template<typename _CharT, typename _Traits>
74     basic_filebuf<_CharT, _Traits>::
75     basic_filebuf() : __streambuf_type(), _M_file(&_M_lock), 
76     _M_state_cur(__state_type()), _M_state_beg(__state_type()), 
77     _M_buf_allocated(false), _M_last_overflowed(false)
78     { _M_buf_unified = true; }
80   template<typename _CharT, typename _Traits>
81     typename basic_filebuf<_CharT, _Traits>::__filebuf_type* 
82     basic_filebuf<_CharT, _Traits>::
83     open(const char* __s, ios_base::openmode __mode)
84     {
85       __filebuf_type *__ret = NULL;
86       if (!this->is_open())
87         {
88           _M_file.open(__s, __mode);
89           if (this->is_open())
90             {
91               _M_allocate_internal_buffer();
92               _M_mode = __mode;
94               // Setup initial position of buffer.
95               _M_set_indeterminate();
97               // Set input buffer to something real.
98               // NB: Must open in non-blocking way to do this, or must
99               // set the initial position in a different manner than
100               // using underflow.
101               if (__mode & ios_base::in && _M_buf_allocated)
102                 this->underflow();
103               
104               if ((__mode & ios_base::ate)
105                   && this->seekoff(0, ios_base::end, __mode) < 0)
106                 this->close();
108               __ret = this;
109             }
110         }
111       return __ret;
112     }
114   template<typename _CharT, typename _Traits>
115     typename basic_filebuf<_CharT, _Traits>::__filebuf_type* 
116     basic_filebuf<_CharT, _Traits>::
117     close()
118     {
119       __filebuf_type *__ret = NULL;
120       if (this->is_open())
121         {
122           const int_type __eof = traits_type::eof();
123           bool __testput = _M_out_cur && _M_out_beg < _M_out_end;
124           if (__testput 
125               && traits_type::eq_int_type(_M_really_overflow(__eof), __eof))
126             return __ret;
128           // NB: Do this here so that re-opened filebufs will be cool...
129           _M_mode = ios_base::openmode(0);
130           _M_destroy_internal_buffer();
131           _M_pback_destroy();
132           
133 #if 0
134           // XXX not done
135           if (_M_last_overflowed)
136             {
137               _M_output_unshift();
138               _M_really_overflow(__eof);
139             }
140 #endif
142           if (_M_file.close())
143             __ret = this;
144         }
146       _M_last_overflowed = false;       
147       return __ret;
148     }
150   template<typename _CharT, typename _Traits>
151     streamsize 
152     basic_filebuf<_CharT, _Traits>::
153     showmanyc()
154     {
155       streamsize __ret = -1;
156       bool __testin = _M_mode & ios_base::in;
158       if (__testin && this->is_open())
159         __ret = _M_in_end - _M_in_cur;
160       _M_last_overflowed = false;       
161       return __ret;
162     }
163   
164   template<typename _CharT, typename _Traits>
165     typename basic_filebuf<_CharT, _Traits>::int_type 
166     basic_filebuf<_CharT, _Traits>::
167     pbackfail(int_type __i)
168     {
169       int_type __ret = traits_type::eof();
170       bool __testin = _M_mode & ios_base::in;
172       if (__testin)
173         {
174           bool __testpb = _M_in_beg < _M_in_cur;
175           char_type __c = traits_type::to_char_type(__i);
176           bool __testeof = traits_type::eq_int_type(__i, __ret);
178           if (__testpb)
179             {
180               bool __testout = _M_mode & ios_base::out;
181               bool __testeq = traits_type::eq(__c, this->gptr()[-1]);
183               // Try to put back __c into input sequence in one of three ways.
184               // Order these tests done in is unspecified by the standard.
185               if (!__testeof && __testeq)
186                 {
187                   --_M_in_cur;
188                   if (__testout)
189                     --_M_out_cur;
190                   __ret = __i;
191                 }
192               else if (__testeof)
193                 {
194                   --_M_in_cur;
195                   if (__testout)
196                     --_M_out_cur;
197                   __ret = traits_type::not_eof(__i);
198                 }
199               else if (!__testeof)
200                 {
201                   --_M_in_cur;
202                   if (__testout)
203                     --_M_out_cur;
204                   _M_pback_create();
205                   *_M_in_cur = __c; 
206                   __ret = __i;
207                 }
208             }
209           else
210             {    
211               // At the beginning of the buffer, need to make a
212               // putback position available.
213               this->seekoff(-1, ios_base::cur);
214               this->underflow();
215               if (!__testeof)
216                 {
217                   if (!traits_type::eq(__c, *_M_in_cur))
218                     {
219                       _M_pback_create();
220                       *_M_in_cur = __c;
221                     }
222                   __ret = __i;
223                 }
224               else
225                 __ret = traits_type::not_eof(__i);
226             }
227         }
228       _M_last_overflowed = false;       
229       return __ret;
230     }
232   template<typename _CharT, typename _Traits>
233     typename basic_filebuf<_CharT, _Traits>::int_type 
234     basic_filebuf<_CharT, _Traits>::
235     overflow(int_type __c)
236     {
237       int_type __ret = traits_type::eof();
238       bool __testput = _M_out_cur && _M_out_cur < _M_buf + _M_buf_size;
239       bool __testout = _M_mode & ios_base::out;
240       
241       if (__testout)
242         {
243           if (__testput)
244             {
245               *_M_out_cur = traits_type::to_char_type(__c);
246               _M_out_cur_move(1);
247               __ret = traits_type::not_eof(__c);
248             }
249           else 
250             __ret = this->_M_really_overflow(__c);
251         }
253       _M_last_overflowed = false;    // Set in _M_really_overflow, below.
254       return __ret;
255     }
256   
257   template<typename _CharT, typename _Traits>
258     void
259     basic_filebuf<_CharT, _Traits>::
260     _M_convert_to_external(_CharT* __ibuf, streamsize __ilen,
261                            streamsize& __elen, streamsize& __plen)
262     {
263       const locale __loc = this->getloc();
264       const __codecvt_type& __cvt = use_facet<__codecvt_type>(__loc);
265       
266       if (__cvt.always_noconv() && __ilen)
267         {
268           __elen += _M_file.xsputn(reinterpret_cast<char*>(__ibuf), __ilen);
269           __plen += __ilen;
270         }
271       else
272         {
273           // Worst-case number of external bytes needed.
274           int __ext_multiplier = __cvt.encoding();
275           if (__ext_multiplier ==  -1 || __ext_multiplier == 0)
276             __ext_multiplier = sizeof(char_type);
277           streamsize __blen = __ilen * __ext_multiplier;
278           char* __buf = static_cast<char*>(__builtin_alloca(__blen));
279           char* __bend;
280           const char_type* __iend;
281           __res_type __r = __cvt.out(_M_state_cur, __ibuf, __ibuf + __ilen, 
282                                      __iend, __buf, __buf + __blen, __bend);
283           // Result == ok, partial, noconv
284           if (__r != codecvt_base::error)
285             __blen = __bend - __buf;
286           // Result == error
287           else 
288             __blen = 0;
289           
290           if (__blen)
291             {
292               __elen += _M_file.xsputn(__buf, __blen);
293               __plen += __blen;
294             }
296           // Try once more for partial conversions.
297           if (__r == codecvt_base::partial)
298             {
299               const char_type* __iresume = __iend;
300               streamsize __rlen = _M_out_end - __iend;
301               __r = __cvt.out(_M_state_cur, __iresume, __iresume + __rlen, 
302                               __iend, __buf, __buf + __blen, __bend);
303               if (__r != codecvt_base::error)
304                 __rlen = __bend - __buf;
305               else 
306                 __rlen = 0;
307               if (__rlen)
308                 {
309                   __elen += _M_file.xsputn(__buf, __rlen);
310                   __plen += __rlen;
311                 }
312             }
313         }
314     }
316   template<typename _CharT, typename _Traits>
317     typename basic_filebuf<_CharT, _Traits>::int_type 
318     basic_filebuf<_CharT, _Traits>::
319     _M_really_overflow(int_type __c)
320     {
321       int_type __ret = traits_type::eof();
322       bool __testput = _M_out_cur && _M_out_beg < _M_out_end;
323       bool __testunbuffered = _M_file.is_open() && !_M_buf_size_opt;
325       if (__testput || __testunbuffered)
326         {
327           // Sizes of external and pending output.
328           streamsize __elen = 0;
329           streamsize __plen = 0;
331           // Need to restore current position. The position of the external
332           // byte sequence (_M_file) corresponds to _M_filepos, and we need
333           // to move it to _M_out_beg for the write.
334           if (_M_filepos && _M_filepos != _M_out_beg)
335             {
336               off_type __off = _M_out_beg - _M_filepos;
337               _M_file.seekoff(__off, ios_base::cur);
338             }
340           // Convert internal buffer to external representation, output.
341           // NB: In the unbuffered case, no internal buffer exists. 
342           if (!__testunbuffered)
343             _M_convert_to_external(_M_out_beg,  _M_out_end - _M_out_beg, 
344                                    __elen, __plen);
346           // Convert pending sequence to external representation, output.
347           // If eof, then just attempt sync.
348           if (!traits_type::eq_int_type(__c, traits_type::eof()))
349             {
350               char_type __pending = traits_type::to_char_type(__c);
351               _M_convert_to_external(&__pending, 1, __elen, __plen);
353               // User code must flush when switching modes (thus don't sync).
354               if (__elen == __plen)
355                 {
356                   _M_set_indeterminate();
357                   __ret = traits_type::not_eof(__c);
358                 }
359             }
360           else if (!_M_file.sync())
361             {
362               _M_set_indeterminate();
363               __ret = traits_type::not_eof(__c);
364             }
365         }             
366       _M_last_overflowed = true;        
367       return __ret;
368     }
370   template<typename _CharT, typename _Traits>
371     typename basic_filebuf<_CharT, _Traits>::__streambuf_type* 
372     basic_filebuf<_CharT, _Traits>::
373     setbuf(char_type* __s, streamsize __n)
374     {
375       if (!this->is_open() && __s == 0 && __n == 0)
376         _M_buf_size_opt = 0;
377       else if (__s && __n)
378         {
379           // This is implementation-defined behavior, and assumes
380           // that an external char_type array of length (__s + __n)
381           // exists and has been pre-allocated. If this is not the
382           // case, things will quickly blow up.
383           // Step 1: Destroy the current internal array.
384           _M_destroy_internal_buffer();
385           
386           // Step 2: Use the external array.
387           _M_buf = __s;
388           _M_buf_size_opt = _M_buf_size = __n;
389           _M_set_indeterminate();
390         }
391       _M_last_overflowed = false;       
392       return this; 
393     }
394   
395   template<typename _CharT, typename _Traits>
396     typename basic_filebuf<_CharT, _Traits>::pos_type
397     basic_filebuf<_CharT, _Traits>::
398     seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode __mode)
399     {
400       pos_type __ret =  pos_type(off_type(-1)); 
401       bool __testin = (ios_base::in & _M_mode & __mode) != 0;
402       bool __testout = (ios_base::out & _M_mode & __mode) != 0;
404       // Should probably do has_facet checks here.
405       int __width = use_facet<__codecvt_type>(_M_buf_locale).encoding();
406       if (__width < 0)
407         __width = 0;
408       bool __testfail = __off != 0 && __width <= 0;
409       
410       if (this->is_open() && !__testfail && (__testin || __testout)) 
411         {
412           // Ditch any pback buffers to avoid confusion.
413           _M_pback_destroy();
415           if (__way != ios_base::cur || __off != 0)
416             { 
417               off_type __computed_off = __width * __off;
418               
419               bool __testget = _M_in_cur && _M_in_beg < _M_in_end;
420               bool __testput = _M_out_cur && _M_out_beg < _M_out_end;
421               // Sync the internal and external streams.
422               // out
423               if (__testput || _M_last_overflowed)
424                 {
425                   // Part one: update the output sequence.
426                   this->sync();
427                   // Part two: output unshift sequence.
428                   _M_output_unshift();
429                 }
430               //in
431               else if (__testget && __way == ios_base::cur)
432                 __computed_off += _M_in_cur - _M_filepos;
433           
434               __ret = _M_file.seekoff(__computed_off, __way, __mode);
435               _M_set_indeterminate();
436             }
437           // NB: Need to do this in case _M_file in indeterminate
438           // state, ie _M_file._offset == -1
439           else
440             {
441               __ret = _M_file.seekoff(__off, ios_base::cur, __mode);
442               __ret += max(_M_out_cur, _M_in_cur) - _M_filepos;
443             }
444         }
445       _M_last_overflowed = false;       
446       return __ret;
447     }
449   template<typename _CharT, typename _Traits>
450     typename basic_filebuf<_CharT, _Traits>::pos_type
451     basic_filebuf<_CharT, _Traits>::
452     seekpos(pos_type __pos, ios_base::openmode __mode)
453     {
454 #ifdef _GLIBCPP_RESOLVE_LIB_DEFECTS
455 // 171. Strange seekpos() semantics due to joint position
456       return this->seekoff(off_type(__pos), ios_base::beg, __mode);
457 #endif
458     }
460   template<typename _CharT, typename _Traits>
461     void 
462     basic_filebuf<_CharT, _Traits>::
463     _M_output_unshift()
464     { }
466   template<typename _CharT, typename _Traits>
467     void
468     basic_filebuf<_CharT, _Traits>::
469     imbue(const locale& __loc)
470     {
471       bool __testbeg = gptr() == eback() && pptr() == pbase();
473       if (__testbeg && _M_buf_locale != __loc)
474         {
475           _M_buf_locale = __loc;
476           _M_buf_locale_init = true;
477         }
479       // NB this may require the reconversion of previously
480       // converted chars. This in turn may cause the reconstruction
481       // of the original file. YIKES!!
482       // XXX The part in the above comment is not done.
483       _M_last_overflowed = false;       
484     }
486   // Inhibit implicit instantiations for required instantiations,
487   // which are defined via explicit instantiations elsewhere.  
488   // NB:  This syntax is a GNU extension.
489   extern template class basic_filebuf<char>;
490   extern template class basic_ifstream<char>;
491   extern template class basic_ofstream<char>;
492   extern template class basic_fstream<char>;
494 #ifdef _GLIBCPP_USE_WCHAR_T
495   extern template class basic_filebuf<wchar_t>;
496   extern template class basic_ifstream<wchar_t>;
497   extern template class basic_ofstream<wchar_t>;
498   extern template class basic_fstream<wchar_t>;
499 #endif
500 } // namespace std
502 #endif