OSDN Git Service

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