OSDN Git Service

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