fstream.tcc revision 102782
1// File based streams -*- C++ -*-
2
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.
11
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.
16
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.
21
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.
30
31//
32// ISO C++ 14882: 27.8  File-based streams
33//
34
35#ifndef _CPP_BITS_FSTREAM_TCC
36#define _CPP_BITS_FSTREAM_TCC 1
37
38#pragma GCC system_header
39
40namespace std
41{
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;
50
51	  // Allocate internal buffer.
52	  _M_buf = new char_type[_M_buf_size]; 
53	  _M_buf_allocated = true;
54	}
55    }
56
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    }
72
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; }
79
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;
93	      _M_set_indeterminate();
94
95	      if ((__mode & ios_base::ate)
96		  && this->seekoff(0, ios_base::end, __mode) < 0)
97		this->close();
98	      __ret = this;
99	    }
100	}
101      return __ret;
102    }
103
104  template<typename _CharT, typename _Traits>
105    typename basic_filebuf<_CharT, _Traits>::__filebuf_type* 
106    basic_filebuf<_CharT, _Traits>::
107    close()
108    {
109      __filebuf_type *__ret = NULL;
110      if (this->is_open())
111	{
112	  const int_type __eof = traits_type::eof();
113	  bool __testput = _M_out_cur && _M_out_beg < _M_out_end;
114	  if (__testput 
115	      && traits_type::eq_int_type(_M_really_overflow(__eof), __eof))
116	    return __ret;
117
118	  // NB: Do this here so that re-opened filebufs will be cool...
119	  _M_mode = ios_base::openmode(0);
120	  _M_destroy_internal_buffer();
121	  _M_pback_destroy();
122	  
123#if 0
124	  // XXX not done
125	  if (_M_last_overflowed)
126	    {
127	      _M_output_unshift();
128	      _M_really_overflow(__eof);
129	    }
130#endif
131
132	  if (_M_file.close())
133	    __ret = this;
134	}
135
136      _M_last_overflowed = false;	
137      return __ret;
138    }
139
140  template<typename _CharT, typename _Traits>
141    streamsize 
142    basic_filebuf<_CharT, _Traits>::
143    showmanyc()
144    {
145      streamsize __ret = -1;
146      bool __testin = _M_mode & ios_base::in;
147
148      if (__testin && this->is_open())
149	__ret = _M_in_end - _M_in_cur;
150      _M_last_overflowed = false;	
151      return __ret;
152    }
153  
154  template<typename _CharT, typename _Traits>
155    typename basic_filebuf<_CharT, _Traits>::int_type 
156    basic_filebuf<_CharT, _Traits>::
157    pbackfail(int_type __i)
158    {
159      int_type __ret = traits_type::eof();
160      bool __testin = _M_mode & ios_base::in;
161
162      if (__testin)
163	{
164	  bool __testpb = _M_in_beg < _M_in_cur;
165	  char_type __c = traits_type::to_char_type(__i);
166	  bool __testeof = traits_type::eq_int_type(__i, __ret);
167
168	  if (__testpb)
169	    {
170	      bool __testout = _M_mode & ios_base::out;
171	      bool __testeq = traits_type::eq(__c, this->gptr()[-1]);
172
173	      // Try to put back __c into input sequence in one of three ways.
174	      // Order these tests done in is unspecified by the standard.
175	      if (!__testeof && __testeq)
176		{
177		  --_M_in_cur;
178		  if (__testout)
179		    --_M_out_cur;
180		  __ret = __i;
181		}
182	      else if (__testeof)
183		{
184		  --_M_in_cur;
185		  if (__testout)
186		    --_M_out_cur;
187		  __ret = traits_type::not_eof(__i);
188		}
189	      else if (!__testeof)
190		{
191		  --_M_in_cur;
192		  if (__testout)
193		    --_M_out_cur;
194		  _M_pback_create();
195		  *_M_in_cur = __c; 
196		  __ret = __i;
197		}
198	    }
199	  else
200	    {	 
201 	      // At the beginning of the buffer, need to make a
202	      // putback position available.
203	      this->seekoff(-1, ios_base::cur);
204	      this->underflow();
205 	      if (!__testeof)
206 		{
207		  if (!traits_type::eq(__c, *_M_in_cur))
208		    {
209		      _M_pback_create();
210		      *_M_in_cur = __c;
211		    }
212 		  __ret = __i;
213 		}
214 	      else
215 		__ret = traits_type::not_eof(__i);
216 	    }
217	}
218      _M_last_overflowed = false;	
219      return __ret;
220    }
221
222  template<typename _CharT, typename _Traits>
223    typename basic_filebuf<_CharT, _Traits>::int_type 
224    basic_filebuf<_CharT, _Traits>::
225    overflow(int_type __c)
226    {
227      int_type __ret = traits_type::eof();
228      bool __testput = _M_out_cur && _M_out_cur < _M_buf + _M_buf_size;
229      bool __testout = _M_mode & ios_base::out;
230      
231      if (__testout)
232	{
233	  if (__testput)
234	    {
235	      *_M_out_cur = traits_type::to_char_type(__c);
236	      _M_out_cur_move(1);
237	      __ret = traits_type::not_eof(__c);
238	    }
239	  else 
240	    __ret = this->_M_really_overflow(__c);
241	}
242
243      _M_last_overflowed = false;    // Set in _M_really_overflow, below.
244      return __ret;
245    }
246  
247  template<typename _CharT, typename _Traits>
248    void
249    basic_filebuf<_CharT, _Traits>::
250    _M_convert_to_external(_CharT* __ibuf, streamsize __ilen,
251			   streamsize& __elen, streamsize& __plen)
252    {
253      const locale __loc = this->getloc();
254      const __codecvt_type& __cvt = use_facet<__codecvt_type>(__loc);
255      
256      if (__cvt.always_noconv() && __ilen)
257	{
258	  __elen += _M_file.xsputn(reinterpret_cast<char*>(__ibuf), __ilen);
259	  __plen += __ilen;
260	}
261      else
262	{
263	  // Worst-case number of external bytes needed.
264	  int __ext_multiplier = __cvt.encoding();
265	  if (__ext_multiplier ==  -1 || __ext_multiplier == 0)
266	    __ext_multiplier = sizeof(char_type);
267	  streamsize __blen = __ilen * __ext_multiplier;
268	  char* __buf = static_cast<char*>(__builtin_alloca(__blen));
269	  char* __bend;
270	  const char_type* __iend;
271	  __res_type __r = __cvt.out(_M_state_cur, __ibuf, __ibuf + __ilen, 
272		 		     __iend, __buf, __buf + __blen, __bend);
273	  // Result == ok, partial, noconv
274	  if (__r != codecvt_base::error)
275	    __blen = __bend - __buf;
276	  // Result == error
277	  else 
278	    __blen = 0;
279	  
280	  if (__blen)
281	    {
282	      __elen += _M_file.xsputn(__buf, __blen);
283	      __plen += __blen;
284	    }
285
286	  // Try once more for partial conversions.
287	  if (__r == codecvt_base::partial)
288	    {
289	      const char_type* __iresume = __iend;
290	      streamsize __rlen = _M_out_end - __iend;
291	      __r = __cvt.out(_M_state_cur, __iresume, __iresume + __rlen, 
292			      __iend, __buf, __buf + __blen, __bend);
293	      if (__r != codecvt_base::error)
294		__rlen = __bend - __buf;
295	      else 
296		__rlen = 0;
297	      if (__rlen)
298		{
299		  __elen += _M_file.xsputn(__buf, __rlen);
300		  __plen += __rlen;
301		}
302	    }
303	}
304    }
305
306  template<typename _CharT, typename _Traits>
307    typename basic_filebuf<_CharT, _Traits>::int_type 
308    basic_filebuf<_CharT, _Traits>::
309    _M_really_overflow(int_type __c)
310    {
311      int_type __ret = traits_type::eof();
312      bool __testput = _M_out_cur && _M_out_beg < _M_out_end;
313      bool __testunbuffered = _M_file.is_open() && !_M_buf_size_opt;
314
315      if (__testput || __testunbuffered)
316	{
317	  // Sizes of external and pending output.
318	  streamsize __elen = 0;
319	  streamsize __plen = 0;
320
321	  // Need to restore current position. The position of the external
322	  // byte sequence (_M_file) corresponds to _M_filepos, and we need
323	  // to move it to _M_out_beg for the write.
324	  if (_M_filepos && _M_filepos != _M_out_beg)
325	    {
326	      off_type __off = _M_out_beg - _M_filepos;
327	      _M_file.seekoff(__off, ios_base::cur);
328	    }
329
330	  // Convert internal buffer to external representation, output.
331	  // NB: In the unbuffered case, no internal buffer exists. 
332	  if (!__testunbuffered)
333	    _M_convert_to_external(_M_out_beg,  _M_out_end - _M_out_beg, 
334				   __elen, __plen);
335
336	  // Convert pending sequence to external representation, output.
337	  // If eof, then just attempt sync.
338	  if (!traits_type::eq_int_type(__c, traits_type::eof()))
339	    {
340	      char_type __pending = traits_type::to_char_type(__c);
341	      _M_convert_to_external(&__pending, 1, __elen, __plen);
342
343	      // User code must flush when switching modes (thus don't sync).
344	      if (__elen == __plen)
345		{
346		  _M_set_indeterminate();
347		  __ret = traits_type::not_eof(__c);
348		}
349	    }
350	  else if (!_M_file.sync())
351	    {
352	      _M_set_indeterminate();
353	      __ret = traits_type::not_eof(__c);
354	    }
355	}	      
356      _M_last_overflowed = true;	
357      return __ret;
358    }
359
360  template<typename _CharT, typename _Traits>
361    typename basic_filebuf<_CharT, _Traits>::__streambuf_type* 
362    basic_filebuf<_CharT, _Traits>::
363    setbuf(char_type* __s, streamsize __n)
364    {
365      if (!this->is_open() && __s == 0 && __n == 0)
366	_M_buf_size_opt = 0;
367      else if (__s && __n)
368	{
369	  // This is implementation-defined behavior, and assumes
370	  // that an external char_type array of length (__s + __n)
371	  // exists and has been pre-allocated. If this is not the
372	  // case, things will quickly blow up.
373	  // Step 1: Destroy the current internal array.
374	  _M_destroy_internal_buffer();
375	  
376	  // Step 2: Use the external array.
377	  _M_buf = __s;
378	  _M_buf_size_opt = _M_buf_size = __n;
379	  _M_set_indeterminate();
380	}
381      _M_last_overflowed = false;	
382      return this; 
383    }
384  
385  template<typename _CharT, typename _Traits>
386    typename basic_filebuf<_CharT, _Traits>::pos_type
387    basic_filebuf<_CharT, _Traits>::
388    seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode __mode)
389    {
390      pos_type __ret =  pos_type(off_type(-1)); 
391      bool __testin = (ios_base::in & _M_mode & __mode) != 0;
392      bool __testout = (ios_base::out & _M_mode & __mode) != 0;
393
394      // Should probably do has_facet checks here.
395      int __width = use_facet<__codecvt_type>(_M_buf_locale).encoding();
396      if (__width < 0)
397	__width = 0;
398      bool __testfail = __off != 0 && __width <= 0;
399      
400      if (this->is_open() && !__testfail && (__testin || __testout)) 
401	{
402	  // Ditch any pback buffers to avoid confusion.
403	  _M_pback_destroy();
404
405	  if (__way != ios_base::cur || __off != 0)
406	    { 
407	      off_type __computed_off = __width * __off;
408	      
409	      bool __testget = _M_in_cur && _M_in_beg < _M_in_end;
410	      bool __testput = _M_out_cur && _M_out_beg < _M_out_end;
411	      // Sync the internal and external streams.
412	      // out
413	      if (__testput || _M_last_overflowed)
414		{
415		  // Part one: update the output sequence.
416		  this->sync();
417		  // Part two: output unshift sequence.
418		  _M_output_unshift();
419		}
420	      //in
421	      else if (__testget && __way == ios_base::cur)
422		__computed_off += _M_in_cur - _M_filepos;
423	  
424	      __ret = _M_file.seekoff(__computed_off, __way, __mode);
425	      _M_set_indeterminate();
426	    }
427	  // NB: Need to do this in case _M_file in indeterminate
428	  // state, ie _M_file._offset == -1
429	  else
430	    {
431	      __ret = _M_file.seekoff(__off, ios_base::cur, __mode);
432	      __ret += max(_M_out_cur, _M_in_cur) - _M_filepos;
433	    }
434	}
435      _M_last_overflowed = false;	
436      return __ret;
437    }
438
439  template<typename _CharT, typename _Traits>
440    typename basic_filebuf<_CharT, _Traits>::pos_type
441    basic_filebuf<_CharT, _Traits>::
442    seekpos(pos_type __pos, ios_base::openmode __mode)
443    {
444#ifdef _GLIBCPP_RESOLVE_LIB_DEFECTS
445// 171. Strange seekpos() semantics due to joint position
446      return this->seekoff(off_type(__pos), ios_base::beg, __mode);
447#endif
448    }
449
450  template<typename _CharT, typename _Traits>
451    void 
452    basic_filebuf<_CharT, _Traits>::
453    _M_output_unshift()
454    { }
455
456  template<typename _CharT, typename _Traits>
457    void
458    basic_filebuf<_CharT, _Traits>::
459    imbue(const locale& __loc)
460    {
461      bool __testbeg = gptr() == eback() && pptr() == pbase();
462
463      if (__testbeg && _M_buf_locale != __loc)
464	{
465	  _M_buf_locale = __loc;
466	  _M_buf_locale_init = true;
467	}
468
469      // NB this may require the reconversion of previously
470      // converted chars. This in turn may cause the reconstruction
471      // of the original file. YIKES!!
472      // XXX The part in the above comment is not done.
473      _M_last_overflowed = false;	
474    }
475
476  // Inhibit implicit instantiations for required instantiations,
477  // which are defined via explicit instantiations elsewhere.  
478  // NB:  This syntax is a GNU extension.
479  extern template class basic_filebuf<char>;
480  extern template class basic_filebuf<wchar_t>;
481  extern template class basic_ifstream<char>;
482  extern template class basic_ifstream<wchar_t>;
483  extern template class basic_ofstream<char>;
484  extern template class basic_ofstream<wchar_t>;
485  extern template class basic_fstream<char>;
486  extern template class basic_fstream<wchar_t>;
487} // namespace std
488
489#endif 
490