OSDN Git Service

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