fstream.tcc revision 97403
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	  try { _M_buf = new char_type[_M_buf_size]; }
53	  catch(...) 
54	    {
55	      delete [] _M_buf;
56	      __throw_exception_again;
57	    }
58	  _M_buf_allocated = true;
59	}
60    }
61
62  // Both close and setbuf need to deallocate internal buffers, if it exists.
63  template<typename _CharT, typename _Traits>
64    void
65    basic_filebuf<_CharT, _Traits>::
66    _M_destroy_internal_buffer()
67    {
68      if (_M_buf_allocated)
69	{
70	  delete [] _M_buf;
71	  _M_buf = NULL;
72	  _M_buf_allocated = false;
73	  this->setg(NULL, NULL, NULL);
74	  this->setp(NULL, NULL);
75	}
76    }
77
78  template<typename _CharT, typename _Traits>
79    basic_filebuf<_CharT, _Traits>::
80    basic_filebuf() : __streambuf_type(), _M_file(&_M_lock), 
81    _M_state_cur(__state_type()), _M_state_beg(__state_type()), 
82    _M_buf_allocated(false), _M_last_overflowed(false)
83    { _M_buf_unified = true; }
84
85  template<typename _CharT, typename _Traits>
86    typename basic_filebuf<_CharT, _Traits>::__filebuf_type* 
87    basic_filebuf<_CharT, _Traits>::
88    open(const char* __s, ios_base::openmode __mode)
89    {
90      __filebuf_type *__ret = NULL;
91      if (!this->is_open())
92	{
93	  _M_file.open(__s, __mode);
94	  if (this->is_open())
95	    {
96	      _M_allocate_internal_buffer();
97	      _M_mode = __mode;
98	      
99	      // For time being, set both (in/out) sets  of pointers.
100	      _M_set_indeterminate();
101	      if ((__mode & ios_base::ate)
102		  && this->seekoff(0, ios_base::end, __mode) < 0)
103		this->close();
104	      __ret = this;
105	    }
106	}
107      return __ret;
108    }
109
110  template<typename _CharT, typename _Traits>
111    typename basic_filebuf<_CharT, _Traits>::__filebuf_type* 
112    basic_filebuf<_CharT, _Traits>::
113    close()
114    {
115      __filebuf_type *__ret = NULL;
116      if (this->is_open())
117	{
118	  const int_type __eof = traits_type::eof();
119	  bool __testput = _M_out_cur && _M_out_beg < _M_out_end;
120	  if (__testput && _M_really_overflow(__eof) == __eof)
121	    return __ret;
122
123	  // NB: Do this here so that re-opened filebufs will be cool...
124	  _M_mode = ios_base::openmode(0);
125	  _M_destroy_internal_buffer();
126	  _M_pback_destroy();
127	  
128#if 0
129	  // XXX not done
130	  if (_M_last_overflowed)
131	    {
132	      _M_output_unshift();
133	      _M_really_overflow(__eof);
134	    }
135#endif
136
137	  if (_M_file.close())
138	    __ret = this;
139	}
140
141      _M_last_overflowed = false;	
142      return __ret;
143    }
144
145  template<typename _CharT, typename _Traits>
146    streamsize 
147    basic_filebuf<_CharT, _Traits>::
148    showmanyc()
149    {
150      streamsize __ret = -1;
151      bool __testin = _M_mode & ios_base::in;
152
153      if (__testin && this->is_open())
154	{
155	  if (_M_in_cur < _M_in_end)
156	    __ret = _M_in_end - _M_in_cur;
157	  else
158	    __ret = 0;
159	}
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    _M_underflow_common(bool __bump)
168    {
169      int_type __ret = traits_type::eof();
170      bool __testin = _M_mode & ios_base::in;
171      bool __testout = _M_mode & ios_base::out;
172
173      if (__testin)
174	{
175	  // Check for pback madness, and if so swich back to the
176	  // normal buffers and jet outta here before expensive
177	  // fileops happen...
178	  if (_M_pback_init)
179	    {
180	      _M_pback_destroy();
181	      if (_M_in_cur < _M_in_end)
182		return traits_type::to_int_type(*_M_in_cur);
183	    }
184
185	  // Sync internal and external buffers.
186	  // NB: __testget -> __testput as _M_buf_unified here.
187	  bool __testget = _M_in_cur && _M_in_beg < _M_in_cur;
188	  bool __testinit = _M_is_indeterminate();
189	  if (__testget)
190	    {
191	      if (__testout)
192		_M_really_overflow();
193	      else if (_M_in_cur != _M_filepos)
194		_M_file.seekoff(_M_in_cur - _M_filepos,
195				ios_base::cur, ios_base::in);
196	    }
197
198	  if (__testinit || __testget)
199	    {
200	      const locale __loc = this->getloc();
201	      const __codecvt_type& __cvt = use_facet<__codecvt_type>(__loc); 
202
203	      streamsize __elen = 0;
204	      streamsize __ilen = 0;
205	      if (__cvt.always_noconv())
206		{
207		  __elen = _M_file.xsgetn(reinterpret_cast<char*>(_M_in_beg), 
208					  _M_buf_size);
209		  __ilen = __elen;
210		}
211	      else
212		{
213		  char* __buf = static_cast<char*>(__builtin_alloca(_M_buf_size));
214		  __elen = _M_file.xsgetn(__buf, _M_buf_size);
215
216		  const char* __eend;
217		  char_type* __iend;
218		  __res_type __r = __cvt.in(_M_state_cur, __buf, 
219					    __buf + __elen, __eend, _M_in_beg, 
220					    _M_in_beg + _M_buf_size, __iend);
221		  if (__r == codecvt_base::ok)
222		    __ilen = __iend - _M_in_beg;
223		  else 
224		    {
225		      // Unwind.
226		      __ilen = 0;
227		      _M_file.seekoff(-__elen, ios_base::cur, ios_base::in);
228		    }
229		}
230
231	      if (0 < __ilen)
232		{
233		  _M_set_determinate(__ilen);
234		  if (__testout)
235		    _M_out_cur = _M_in_cur;
236		  __ret = traits_type::to_int_type(*_M_in_cur);
237		  if (__bump)
238		    _M_in_cur_move(1);
239		  else if (_M_buf_size == 1)
240		    {
241		      // If we are synced with stdio, we have to unget the
242		      // character we just read so that the file pointer
243		      // doesn't move.
244		      _M_file.sys_ungetc(*_M_in_cur);
245		      _M_set_indeterminate();
246		    }
247		}	   
248	    }
249	}
250      _M_last_overflowed = false;	
251      return __ret;
252    }
253  
254  template<typename _CharT, typename _Traits>
255    typename basic_filebuf<_CharT, _Traits>::int_type 
256    basic_filebuf<_CharT, _Traits>::
257    pbackfail(int_type __i)
258    {
259      int_type __ret = traits_type::eof();
260      bool __testin = _M_mode & ios_base::in;
261
262      if (__testin)
263	{
264	  bool __testpb = _M_in_beg < _M_in_cur;
265	  char_type __c = traits_type::to_char_type(__i);
266	  bool __testeof = traits_type::eq_int_type(__i, __ret);
267
268	  if (__testpb)
269	    {
270	      bool __testout = _M_mode & ios_base::out;
271	      bool __testeq = traits_type::eq(__c, this->gptr()[-1]);
272
273	      // Try to put back __c into input sequence in one of three ways.
274	      // Order these tests done in is unspecified by the standard.
275	      if (!__testeof && __testeq)
276		{
277		  --_M_in_cur;
278		  if (__testout)
279		    --_M_out_cur;
280		  __ret = __i;
281		}
282	      else if (__testeof)
283		{
284		  --_M_in_cur;
285		  if (__testout)
286		    --_M_out_cur;
287		  __ret = traits_type::not_eof(__i);
288		}
289	      else if (!__testeof)
290		{
291		  --_M_in_cur;
292		  if (__testout)
293		    --_M_out_cur;
294		  _M_pback_create();
295		  *_M_in_cur = __c; 
296		  __ret = __i;
297		}
298	    }
299	  else
300	    {	 
301 	      // At the beginning of the buffer, need to make a
302	      // putback position available.
303	      this->seekoff(-1, ios_base::cur);
304	      this->underflow();
305 	      if (!__testeof)
306 		{
307		  if (!traits_type::eq(__c, *_M_in_cur))
308		    {
309		      _M_pback_create();
310		      *_M_in_cur = __c;
311		    }
312 		  __ret = __i;
313 		}
314 	      else
315 		__ret = traits_type::not_eof(__i);
316 	    }
317	}
318      _M_last_overflowed = false;	
319      return __ret;
320    }
321
322  template<typename _CharT, typename _Traits>
323    typename basic_filebuf<_CharT, _Traits>::int_type 
324    basic_filebuf<_CharT, _Traits>::
325    overflow(int_type __c)
326    {
327      int_type __ret = traits_type::eof();
328      bool __testput = _M_out_cur && _M_out_cur < _M_buf + _M_buf_size;
329      bool __testout = _M_mode & ios_base::out;
330      
331      if (__testout)
332	{
333	  if (__testput)
334	    {
335	      *_M_out_cur = traits_type::to_char_type(__c);
336	      _M_out_cur_move(1);
337	      __ret = traits_type::not_eof(__c);
338	    }
339	  else 
340	    __ret = this->_M_really_overflow(__c);
341	}
342
343      _M_last_overflowed = false;    // Set in _M_really_overflow, below.
344      return __ret;
345    }
346  
347  template<typename _CharT, typename _Traits>
348    void
349    basic_filebuf<_CharT, _Traits>::
350    _M_convert_to_external(_CharT* __ibuf, streamsize __ilen,
351			   streamsize& __elen, streamsize& __plen)
352    {
353      const locale __loc = this->getloc();
354      const __codecvt_type& __cvt = use_facet<__codecvt_type>(__loc);
355      
356      if (__cvt.always_noconv() && __ilen)
357	{
358	  __elen += _M_file.xsputn(reinterpret_cast<char*>(__ibuf), __ilen);
359	  __plen += __ilen;
360	}
361      else
362	{
363	  // Worst-case number of external bytes needed.
364	  int __ext_multiplier = __cvt.encoding();
365	  if (__ext_multiplier ==  -1 || __ext_multiplier == 0)
366	    __ext_multiplier = sizeof(char_type);
367	  streamsize __blen = __ilen * __ext_multiplier;
368	  char* __buf = static_cast<char*>(__builtin_alloca(__blen));
369	  char* __bend;
370	  const char_type* __iend;
371	  __res_type __r = __cvt.out(_M_state_cur, __ibuf, __ibuf + __ilen, 
372		 		     __iend, __buf, __buf + __blen, __bend);
373	  // Result == ok, partial, noconv
374	  if (__r != codecvt_base::error)
375	    __blen = __bend - __buf;
376	  // Result == error
377	  else 
378	    __blen = 0;
379	  
380	  if (__blen)
381	    {
382	      __elen += _M_file.xsputn(__buf, __blen);
383	      __plen += __blen;
384	    }
385
386	  // Try once more for partial conversions.
387	  if (__r == codecvt_base::partial)
388	    {
389	      const char_type* __iresume = __iend;
390	      streamsize __rlen = _M_out_end - __iend;
391	      __r = __cvt.out(_M_state_cur, __iresume, __iresume + __rlen, 
392			      __iend, __buf, __buf + __blen, __bend);
393	      if (__r != codecvt_base::error)
394		__rlen = __bend - __buf;
395	      else 
396		__rlen = 0;
397	      if (__rlen)
398		{
399		  __elen += _M_file.xsputn(__buf, __rlen);
400		  __plen += __rlen;
401		}
402	    }
403	}
404    }
405
406  template<typename _CharT, typename _Traits>
407    typename basic_filebuf<_CharT, _Traits>::int_type 
408    basic_filebuf<_CharT, _Traits>::
409    _M_really_overflow(int_type __c)
410    {
411      int_type __ret = traits_type::eof();
412      bool __testput = _M_out_cur && _M_out_beg < _M_out_end;
413      bool __testunbuffered = _M_file.is_open() && !_M_buf_size;
414
415      if (__testput || __testunbuffered)
416	{
417	  // Sizes of external and pending output.
418	  streamsize __elen = 0;
419	  streamsize __plen = 0;
420
421	  // Need to restore current position. The position of the external
422	  // byte sequence (_M_file) corresponds to _M_filepos, and we need
423	  // to move it to _M_out_beg for the write.
424	  if (_M_filepos && _M_filepos != _M_out_beg)
425	    {
426	      off_type __off = _M_out_beg - _M_filepos;
427	      _M_file.seekoff(__off, ios_base::cur);
428	    }
429
430	  // Convert internal buffer to external representation, output.
431	  // NB: In the unbuffered case, no internal buffer exists. 
432	  if (!__testunbuffered)
433	    _M_convert_to_external(_M_out_beg,  _M_out_end - _M_out_beg, 
434				   __elen, __plen);
435
436	  // Convert pending sequence to external representation, output.
437	  // If eof, then just attempt sync.
438	  if (!traits_type::eq_int_type(__c, traits_type::eof()))
439	    {
440	      char_type __pending = traits_type::to_char_type(__c);
441	      _M_convert_to_external(&__pending, 1, __elen, __plen);
442
443	      // User code must flush when switching modes (thus don't sync).
444	      if (__elen == __plen)
445		{
446		  _M_set_indeterminate();
447		  __ret = traits_type::not_eof(__c);
448		}
449	    }
450	  else if (!_M_file.sync())
451	    {
452	      _M_set_indeterminate();
453	      __ret = traits_type::not_eof(__c);
454	    }
455	}	      
456      _M_last_overflowed = true;	
457      return __ret;
458    }
459
460  template<typename _CharT, typename _Traits>
461    typename basic_filebuf<_CharT, _Traits>::__streambuf_type* 
462    basic_filebuf<_CharT, _Traits>::
463    setbuf(char_type* __s, streamsize __n)
464    {
465      if (!this->is_open() && __s == 0 && __n == 0)
466	_M_buf_size_opt = 0;
467      else if (__s && __n)
468	{
469	  // This is implementation-defined behavior, and assumes
470	  // that an external char_type array of length (__s + __n)
471	  // exists and has been pre-allocated. If this is not the
472	  // case, things will quickly blow up.
473	  // Step 1: Destroy the current internal array.
474	  _M_destroy_internal_buffer();
475	  
476	  // Step 2: Use the external array.
477	  _M_buf = __s;
478	  _M_buf_size_opt = _M_buf_size = __n;
479	  _M_set_indeterminate();
480	}
481      _M_last_overflowed = false;	
482      return this; 
483    }
484  
485  template<typename _CharT, typename _Traits>
486    typename basic_filebuf<_CharT, _Traits>::pos_type
487    basic_filebuf<_CharT, _Traits>::
488    seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode __mode)
489    {
490      pos_type __ret =  pos_type(off_type(-1)); 
491      bool __testin = (ios_base::in & _M_mode & __mode) != 0;
492      bool __testout = (ios_base::out & _M_mode & __mode) != 0;
493
494      // Should probably do has_facet checks here.
495      int __width = use_facet<__codecvt_type>(_M_buf_locale).encoding();
496      if (__width < 0)
497	__width = 0;
498      bool __testfail = __off != 0 && __width <= 0;
499      
500      if (this->is_open() && !__testfail && (__testin || __testout)) 
501	{
502	  // Ditch any pback buffers to avoid confusion.
503	  _M_pback_destroy();
504
505	  if (__way != ios_base::cur || __off != 0)
506	    { 
507	      off_type __computed_off = __width * __off;
508	      
509	      bool __testget = _M_in_cur && _M_in_beg < _M_in_end;
510	      bool __testput = _M_out_cur && _M_out_beg < _M_out_end;
511	      // Sync the internal and external streams.
512	      // out
513	      if (__testput || _M_last_overflowed)
514		{
515		  // Part one: update the output sequence.
516		  this->sync();
517		  // Part two: output unshift sequence.
518		  _M_output_unshift();
519		}
520	      //in
521	      else if (__testget && __way == ios_base::cur)
522		__computed_off += _M_in_cur - _M_filepos;
523	  
524	      __ret = _M_file.seekoff(__computed_off, __way, __mode);
525	      _M_set_indeterminate();
526	    }
527	  // NB: Need to do this in case _M_file in indeterminate
528	  // state, ie _M_file._offset == -1
529	  else
530	    {
531	      __ret = _M_file.seekoff(__off, ios_base::cur, __mode);
532	      __ret += max(_M_out_cur, _M_in_cur) - _M_filepos;
533	    }
534	}
535      _M_last_overflowed = false;	
536      return __ret;
537    }
538
539  template<typename _CharT, typename _Traits>
540    typename basic_filebuf<_CharT, _Traits>::pos_type
541    basic_filebuf<_CharT, _Traits>::
542    seekpos(pos_type __pos, ios_base::openmode __mode)
543    {
544#ifdef _GLIBCPP_RESOLVE_LIB_DEFECTS
545// 171. Strange seekpos() semantics due to joint position
546      return this->seekoff(off_type(__pos), ios_base::beg, __mode);
547#endif
548    }
549
550  template<typename _CharT, typename _Traits>
551    void 
552    basic_filebuf<_CharT, _Traits>::
553    _M_output_unshift()
554    { }
555
556  template<typename _CharT, typename _Traits>
557    void
558    basic_filebuf<_CharT, _Traits>::
559    imbue(const locale& __loc)
560    {
561      bool __testbeg = gptr() == eback() && pptr() == pbase();
562
563      if (__testbeg && _M_buf_locale != __loc)
564	{
565	  _M_buf_locale = __loc;
566	  _M_buf_locale_init = true;
567	}
568
569      // NB this may require the reconversion of previously
570      // converted chars. This in turn may cause the reconstruction
571      // of the original file. YIKES!!
572      // XXX The part in the above comment is not done.
573      _M_last_overflowed = false;	
574    }
575
576  // Inhibit implicit instantiations for required instantiations,
577  // which are defined via explicit instantiations elsewhere.  
578  // NB:  This syntax is a GNU extension.
579  extern template class basic_filebuf<char>;
580  extern template class basic_filebuf<wchar_t>;
581  extern template class basic_ifstream<char>;
582  extern template class basic_ifstream<wchar_t>;
583  extern template class basic_ofstream<char>;
584  extern template class basic_ofstream<wchar_t>;
585  extern template class basic_fstream<char>;
586  extern template class basic_fstream<wchar_t>;
587} // namespace std
588
589#endif 
590