OSDN Git Service

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