OSDN Git Service

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