OSDN Git Service

2002-04-30 Benjamin Kosnik <bkoz@redhat.com>
[pf3gnuchains/gcc-fork.git] / libstdc++-v3 / include / bits / fstream.tcc
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
40 namespace 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           // Check for unbuffered stream.
186           if (_M_buf_size == 1)
187             {
188               int_type __c = _M_file.sys_getc();
189               if (__c != __ret)
190                 {
191                   __ret = __c;
192                   *_M_in_cur = traits_type::to_char_type(__c);
193                   _M_set_determinate(1);
194                   if (__testout)
195                     _M_out_cur = _M_in_cur;
196                 }
197               return __ret;
198             }
199
200           // Sync internal and external buffers.
201           // NB: __testget -> __testput as _M_buf_unified here.
202           bool __testget = _M_in_cur && _M_in_beg < _M_in_cur;
203           bool __testinit = _M_is_indeterminate();
204           if (__testget)
205             {
206               if (__testout)
207                 _M_really_overflow();
208               else if (_M_in_cur != _M_filepos)
209                 _M_file.seekoff(_M_in_cur - _M_filepos,
210                                 ios_base::cur, ios_base::in);
211             }
212
213           if (__testinit || __testget)
214             {
215               const locale __loc = this->getloc();
216               const __codecvt_type& __cvt = use_facet<__codecvt_type>(__loc); 
217
218               streamsize __elen = 0;
219               streamsize __ilen = 0;
220               if (__cvt.always_noconv())
221                 {
222                   __elen = _M_file.xsgetn(reinterpret_cast<char*>(_M_in_beg), 
223                                           _M_buf_size);
224                   __ilen = __elen;
225                 }
226               else
227                 {
228                   char* __buf = static_cast<char*>(__builtin_alloca(_M_buf_size));
229                   __elen = _M_file.xsgetn(__buf, _M_buf_size);
230
231                   const char* __eend;
232                   char_type* __iend;
233                   __res_type __r = __cvt.in(_M_state_cur, __buf, 
234                                             __buf + __elen, __eend, _M_in_beg, 
235                                             _M_in_beg + _M_buf_size, __iend);
236                   if (__r == codecvt_base::ok)
237                     __ilen = __iend - _M_in_beg;
238                   else 
239                     {
240                       // Unwind.
241                       __ilen = 0;
242                       _M_file.seekoff(-__elen, ios_base::cur, ios_base::in);
243                     }
244                 }
245
246               if (0 < __ilen)
247                 {
248                   _M_set_determinate(__ilen);
249                   if (__testout)
250                     _M_out_cur = _M_in_cur;
251                   __ret = traits_type::to_int_type(*_M_in_cur);
252                   if (__bump)
253                     _M_in_cur_move(1);
254                 }          
255             }
256         }
257       _M_last_overflowed = false;       
258       return __ret;
259     }
260   
261   template<typename _CharT, typename _Traits>
262     typename basic_filebuf<_CharT, _Traits>::int_type 
263     basic_filebuf<_CharT, _Traits>::
264     pbackfail(int_type __i)
265     {
266       int_type __ret = traits_type::eof();
267       bool __testin = _M_mode & ios_base::in;
268
269       if (__testin)
270         {
271           bool __testpb = _M_in_beg < _M_in_cur;
272           char_type __c = traits_type::to_char_type(__i);
273           bool __testeof = traits_type::eq_int_type(__i, __ret);
274
275           if (__testpb)
276             {
277               bool __testout = _M_mode & ios_base::out;
278               bool __testeq = traits_type::eq(__c, this->gptr()[-1]);
279
280               // Try to put back __c into input sequence in one of three ways.
281               // Order these tests done in is unspecified by the standard.
282               if (!__testeof && __testeq)
283                 {
284                   --_M_in_cur;
285                   if (__testout)
286                     --_M_out_cur;
287                   __ret = __i;
288                 }
289               else if (__testeof)
290                 {
291                   --_M_in_cur;
292                   if (__testout)
293                     --_M_out_cur;
294                   __ret = traits_type::not_eof(__i);
295                 }
296               else if (!__testeof)
297                 {
298                   --_M_in_cur;
299                   if (__testout)
300                     --_M_out_cur;
301                   _M_pback_create();
302                   *_M_in_cur = __c; 
303                   __ret = __i;
304                 }
305             }
306           else
307             {    
308               // At the beginning of the buffer, need to make a
309               // putback position available.
310               this->seekoff(-1, ios_base::cur);
311               this->underflow();
312               if (!__testeof)
313                 {
314                   if (!traits_type::eq(__c, *_M_in_cur))
315                     {
316                       _M_pback_create();
317                       *_M_in_cur = __c;
318                     }
319                   __ret = __i;
320                 }
321               else
322                 __ret = traits_type::not_eof(__i);
323             }
324         }
325       _M_last_overflowed = false;       
326       return __ret;
327     }
328
329   template<typename _CharT, typename _Traits>
330     typename basic_filebuf<_CharT, _Traits>::int_type 
331     basic_filebuf<_CharT, _Traits>::
332     overflow(int_type __c)
333     {
334       int_type __ret = traits_type::eof();
335       bool __testput = _M_out_cur && _M_out_cur < _M_buf + _M_buf_size;
336       bool __testout = _M_mode & ios_base::out;
337       
338       if (__testout)
339         {
340           if (__testput)
341             {
342               *_M_out_cur = traits_type::to_char_type(__c);
343               _M_out_cur_move(1);
344               __ret = traits_type::not_eof(__c);
345             }
346           else 
347             __ret = this->_M_really_overflow(__c);
348         }
349
350       _M_last_overflowed = false;    // Set in _M_really_overflow, below.
351       return __ret;
352     }
353   
354   template<typename _CharT, typename _Traits>
355     void
356     basic_filebuf<_CharT, _Traits>::
357     _M_convert_to_external(_CharT* __ibuf, streamsize __ilen,
358                            streamsize& __elen, streamsize& __plen)
359     {
360       const locale __loc = this->getloc();
361       const __codecvt_type& __cvt = use_facet<__codecvt_type>(__loc);
362       
363       if (__cvt.always_noconv() && __ilen)
364         {
365           __elen += _M_file.xsputn(reinterpret_cast<char*>(__ibuf), __ilen);
366           __plen += __ilen;
367         }
368       else
369         {
370           // Worst-case number of external bytes needed.
371           int __ext_multiplier = __cvt.encoding();
372           if (__ext_multiplier ==  -1 || __ext_multiplier == 0)
373             __ext_multiplier = sizeof(char_type);
374           streamsize __blen = __ilen * __ext_multiplier;
375           char* __buf = static_cast<char*>(__builtin_alloca(__blen));
376           char* __bend;
377           const char_type* __iend;
378           __res_type __r = __cvt.out(_M_state_cur, __ibuf, __ibuf + __ilen, 
379                                      __iend, __buf, __buf + __blen, __bend);
380           // Result == ok, partial, noconv
381           if (__r != codecvt_base::error)
382             __blen = __bend - __buf;
383           // Result == error
384           else 
385             __blen = 0;
386           
387           if (__blen)
388             {
389               __elen += _M_file.xsputn(__buf, __blen);
390               __plen += __blen;
391             }
392
393           // Try once more for partial conversions.
394           if (__r == codecvt_base::partial)
395             {
396               const char_type* __iresume = __iend;
397               streamsize __rlen = _M_out_end - __iend;
398               __r = __cvt.out(_M_state_cur, __iresume, __iresume + __rlen, 
399                               __iend, __buf, __buf + __blen, __bend);
400               if (__r != codecvt_base::error)
401                 __rlen = __bend - __buf;
402               else 
403                 __rlen = 0;
404               if (__rlen)
405                 {
406                   __elen += _M_file.xsputn(__buf, __rlen);
407                   __plen += __rlen;
408                 }
409             }
410         }
411     }
412
413   template<typename _CharT, typename _Traits>
414     typename basic_filebuf<_CharT, _Traits>::int_type 
415     basic_filebuf<_CharT, _Traits>::
416     _M_really_overflow(int_type __c)
417     {
418       int_type __ret = traits_type::eof();
419       bool __testput = _M_out_cur && _M_out_beg < _M_out_end;
420       bool __testunbuffered = _M_file.is_open() && !_M_buf_size;
421
422       if (__testput || __testunbuffered)
423         {
424           // Sizes of external and pending output.
425           streamsize __elen = 0;
426           streamsize __plen = 0;
427
428           // Need to restore current position. The position of the external
429           // byte sequence (_M_file) corresponds to _M_filepos, and we need
430           // to move it to _M_out_beg for the write.
431           if (_M_filepos && _M_filepos != _M_out_beg)
432             {
433               off_type __off = _M_out_beg - _M_filepos;
434               _M_file.seekoff(__off, ios_base::cur);
435             }
436
437           // Convert internal buffer to external representation, output.
438           // NB: In the unbuffered case, no internal buffer exists. 
439           if (!__testunbuffered)
440             _M_convert_to_external(_M_out_beg,  _M_out_end - _M_out_beg, 
441                                    __elen, __plen);
442
443           // Convert pending sequence to external representation, output.
444           // If eof, then just attempt sync.
445           if (!traits_type::eq_int_type(__c, traits_type::eof()))
446             {
447               char_type __pending = traits_type::to_char_type(__c);
448               _M_convert_to_external(&__pending, 1, __elen, __plen);
449
450               // User code must flush when switching modes (thus don't sync).
451               if (__elen == __plen)
452                 {
453                   _M_set_indeterminate();
454                   __ret = traits_type::not_eof(__c);
455                 }
456             }
457           else if (!_M_file.sync())
458             {
459               _M_set_indeterminate();
460               __ret = traits_type::not_eof(__c);
461             }
462         }             
463       _M_last_overflowed = true;        
464       return __ret;
465     }
466
467   template<typename _CharT, typename _Traits>
468     typename basic_filebuf<_CharT, _Traits>::__streambuf_type* 
469     basic_filebuf<_CharT, _Traits>::
470     setbuf(char_type* __s, streamsize __n)
471     {
472       if (!this->is_open() && __s == 0 && __n == 0)
473         _M_buf_size_opt = 0;
474       else if (__s && __n)
475         {
476           // This is implementation-defined behavior, and assumes
477           // that an external char_type array of length (__s + __n)
478           // exists and has been pre-allocated. If this is not the
479           // case, things will quickly blow up.
480           // Step 1: Destroy the current internal array.
481           _M_destroy_internal_buffer();
482           
483           // Step 2: Use the external array.
484           _M_buf = __s;
485           _M_buf_size_opt = _M_buf_size = __n;
486           _M_set_indeterminate();
487         }
488       _M_last_overflowed = false;       
489       return this; 
490     }
491   
492   template<typename _CharT, typename _Traits>
493     typename basic_filebuf<_CharT, _Traits>::pos_type
494     basic_filebuf<_CharT, _Traits>::
495     seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode __mode)
496     {
497       pos_type __ret =  pos_type(off_type(-1)); 
498       bool __testin = (ios_base::in & _M_mode & __mode) != 0;
499       bool __testout = (ios_base::out & _M_mode & __mode) != 0;
500
501       // Should probably do has_facet checks here.
502       int __width = use_facet<__codecvt_type>(_M_buf_locale).encoding();
503       if (__width < 0)
504         __width = 0;
505       bool __testfail = __off != 0 && __width <= 0;
506       
507       if (this->is_open() && !__testfail && (__testin || __testout)) 
508         {
509           // Ditch any pback buffers to avoid confusion.
510           _M_pback_destroy();
511
512           if (__way != ios_base::cur || __off != 0)
513             { 
514               off_type __computed_off = __width * __off;
515               
516               bool __testget = _M_in_cur && _M_in_beg < _M_in_end;
517               bool __testput = _M_out_cur && _M_out_beg < _M_out_end;
518               // Sync the internal and external streams.
519               // out
520               if (__testput || _M_last_overflowed)
521                 {
522                   // Part one: update the output sequence.
523                   this->sync();
524                   // Part two: output unshift sequence.
525                   _M_output_unshift();
526                 }
527               //in
528               else if (__testget && __way == ios_base::cur)
529                 __computed_off += _M_in_cur - _M_filepos;
530           
531               __ret = _M_file.seekoff(__computed_off, __way, __mode);
532               _M_set_indeterminate();
533             }
534           // NB: Need to do this in case _M_file in indeterminate
535           // state, ie _M_file._offset == -1
536           else
537             {
538               __ret = _M_file.seekoff(__off, ios_base::cur, __mode);
539               __ret += max(_M_out_cur, _M_in_cur) - _M_filepos;
540             }
541         }
542       _M_last_overflowed = false;       
543       return __ret;
544     }
545
546   template<typename _CharT, typename _Traits>
547     typename basic_filebuf<_CharT, _Traits>::pos_type
548     basic_filebuf<_CharT, _Traits>::
549     seekpos(pos_type __pos, ios_base::openmode __mode)
550     {
551 #ifdef _GLIBCPP_RESOLVE_LIB_DEFECTS
552 // 171. Strange seekpos() semantics due to joint position
553       return this->seekoff(off_type(__pos), ios_base::beg, __mode);
554 #endif
555     }
556
557   template<typename _CharT, typename _Traits>
558     void 
559     basic_filebuf<_CharT, _Traits>::
560     _M_output_unshift()
561     { }
562
563   template<typename _CharT, typename _Traits>
564     void
565     basic_filebuf<_CharT, _Traits>::
566     imbue(const locale& __loc)
567     {
568       bool __testbeg = gptr() == eback() && pptr() == pbase();
569
570       if (__testbeg && _M_buf_locale != __loc)
571         {
572           _M_buf_locale = __loc;
573           _M_buf_locale_init = true;
574         }
575
576       // NB this may require the reconversion of previously
577       // converted chars. This in turn may cause the reconstruction
578       // of the original file. YIKES!!
579       // XXX The part in the above comment is not done.
580       _M_last_overflowed = false;       
581     }
582
583   // Inhibit implicit instantiations for required instantiations,
584   // which are defined via explicit instantiations elsewhere.  
585   // NB:  This syntax is a GNU extension.
586   extern template class basic_filebuf<char>;
587   extern template class basic_filebuf<wchar_t>;
588   extern template class basic_ifstream<char>;
589   extern template class basic_ifstream<wchar_t>;
590   extern template class basic_ofstream<char>;
591   extern template class basic_ofstream<wchar_t>;
592   extern template class basic_fstream<char>;
593   extern template class basic_fstream<wchar_t>;
594 } // namespace std
595
596 #endif