OSDN Git Service

2003-06-24 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               char* __buf = static_cast<char*>(__builtin_alloca(__buflen));
217               __elen = _M_file.xsgetn(__buf, __buflen);
218               
219               const char* __eend;
220               char_type* __iend;
221               codecvt_base::result __r;
222               __r = _M_codecvt->in(_M_state_cur, __buf, __buf + __elen, 
223                                    __eend, this->eback(), 
224                                    this->eback() + __buflen, __iend);
225               if (__r == codecvt_base::ok)
226                 __ilen = __iend - this->eback();
227               else if (__r == codecvt_base::noconv)
228                 {
229                   traits_type::copy(this->eback(),
230                                     reinterpret_cast<char_type*>(__buf), 
231                                     __elen);
232                   __ilen = __elen;
233                 }
234               else 
235                 {
236                   // Unwind.
237                   __ilen = 0;
238                   _M_file.seekoff(-__elen, ios_base::cur, ios_base::in);
239                 }
240             }
241
242           if (__ilen > 0)
243             {
244               _M_set_buffer(__ilen);
245               _M_reading = true;
246               __ret = traits_type::to_int_type(*this->gptr());
247               if (__bump)
248                 this->gbump(1);
249             }               
250         }
251       _M_last_overflowed = false;       
252       return __ret;
253     }
254
255   template<typename _CharT, typename _Traits>
256     typename basic_filebuf<_CharT, _Traits>::int_type 
257     basic_filebuf<_CharT, _Traits>::
258     pbackfail(int_type __i)
259     {
260       int_type __ret = traits_type::eof();
261       const bool __testin = this->_M_mode & ios_base::in;
262
263       if (__testin && !_M_writing)
264         {
265           // Remember whether the pback buffer is active, otherwise below
266           // we may try to store in it a second char (libstdc++/9761).
267           const bool __testpb = this->_M_pback_init;       
268           const bool __testeof = traits_type::eq_int_type(__i, __ret);
269           
270           int_type __tmp;
271           if (this->eback() < this->gptr())
272             {
273               this->gbump(-1);
274               __tmp = traits_type::to_int_type(*this->gptr());
275             }
276           else if (this->seekoff(-1, ios_base::cur) >= 0)
277             {
278               __tmp = this->underflow();
279               if (traits_type::eq_int_type(__tmp, __ret))
280                 return __ret;
281             }
282           else
283             {
284               // At the beginning of the buffer, need to make a
285               // putback position available.  But the seek may fail
286               // (f.i., at the beginning of a file, see
287               // libstdc++/9439) and in that case we return
288               // traits_type::eof().
289               return __ret;
290             }
291
292           // Try to put back __i into input sequence in one of three ways.
293           // Order these tests done in is unspecified by the standard.
294           if (!__testeof && traits_type::eq_int_type(__i, __tmp))
295             __ret = __i;
296           else if (__testeof)
297             __ret = traits_type::not_eof(__i);
298           else if (!__testpb)
299             {
300               _M_create_pback();
301               _M_reading = true;
302               *this->gptr() = traits_type::to_char_type(__i); 
303               __ret = __i;
304             }
305         }
306       _M_last_overflowed = false;       
307       return __ret;
308     }
309
310   template<typename _CharT, typename _Traits>
311     typename basic_filebuf<_CharT, _Traits>::int_type 
312     basic_filebuf<_CharT, _Traits>::
313     overflow(int_type __c)
314     {
315       int_type __ret = traits_type::eof();
316       const bool __testeof = traits_type::eq_int_type(__c, __ret);
317       const bool __testout = this->_M_mode & ios_base::out;
318       
319       if (__testout && !_M_reading)
320         {
321           if (this->pbase() < this->pptr())
322             {
323               // If appropriate, append the overflow char.
324               if (!__testeof)
325                 {
326                   *this->pptr() = traits_type::to_char_type(__c);
327                   this->pbump(1);
328                 }
329               
330               // Convert pending sequence to external representation,
331               // output.
332               if (_M_convert_to_external(this->pbase(),
333                                          this->pptr() - this->pbase())
334                   && (!__testeof || (__testeof && !_M_file.sync())))
335                 {
336                   _M_set_buffer(0);
337                   __ret = traits_type::not_eof(__c);
338                 }
339             }
340           else if (this->_M_buf_size > 1)
341             {
342               // Overflow in 'uncommitted' mode: set _M_writing, set
343               // the buffer to the initial 'write' mode, and put __c
344               // into the buffer.
345               _M_set_buffer(0);
346               _M_writing = true;
347               if (!__testeof)
348                 {
349                   *this->pptr() = traits_type::to_char_type(__c);
350                   this->pbump(1);
351                 }
352               __ret = traits_type::not_eof(__c);
353             }
354           else
355             {
356               // Unbuffered.
357               char_type __conv = traits_type::to_char_type(__c);
358               if (__testeof || _M_convert_to_external(&__conv, 1))
359                 {                 
360                   _M_writing = true;
361                   __ret = traits_type::not_eof(__c);
362                 }
363             }
364         }
365       _M_last_overflowed = true;        
366       return __ret;
367     }
368   
369   template<typename _CharT, typename _Traits>
370     bool
371     basic_filebuf<_CharT, _Traits>::
372     _M_convert_to_external(_CharT* __ibuf, streamsize __ilen)
373     {
374       // Sizes of external and pending output.
375       streamsize __elen = 0;
376       streamsize __plen = 0;
377
378       if (__check_facet(_M_codecvt).always_noconv())
379         {
380           __elen += _M_file.xsputn(reinterpret_cast<char*>(__ibuf), __ilen);
381           __plen += __ilen;
382         }
383       else
384         {
385           // Worst-case number of external bytes needed.
386           int __ext_multiplier = _M_codecvt->encoding();
387           if (__ext_multiplier ==  -1 || __ext_multiplier == 0)
388             __ext_multiplier = sizeof(char_type);
389           streamsize __blen = __ilen * __ext_multiplier;
390           char* __buf = static_cast<char*>(__builtin_alloca(__blen));
391           char* __bend;
392           const char_type* __iend;
393           codecvt_base::result __r;
394           __r = _M_codecvt->out(_M_state_cur, __ibuf, __ibuf + __ilen,
395                                 __iend, __buf, __buf + __blen, __bend);
396           
397           if (__r == codecvt_base::ok || __r == codecvt_base::partial)
398             __blen = __bend - __buf;
399           else if (__r == codecvt_base::noconv)
400             {
401               // Same as the always_noconv case above.
402               __buf = reinterpret_cast<char*>(__ibuf);
403               __blen = __ilen;
404             }
405           else
406             {
407               // Result == error.
408               __blen = 0;
409             }
410           
411           if (__blen)
412             {
413               __elen += _M_file.xsputn(__buf, __blen);
414               __plen += __blen;
415             }
416           
417           // Try once more for partial conversions.
418           if (__r == codecvt_base::partial)
419             {
420               const char_type* __iresume = __iend;
421               streamsize __rlen = this->pptr() - __iend;
422               __r = _M_codecvt->out(_M_state_cur, __iresume,
423                                     __iresume + __rlen, __iend, __buf, 
424                                     __buf + __blen, __bend);
425               if (__r != codecvt_base::error)
426                 {
427                   __rlen = __bend - __buf;
428                   __elen += _M_file.xsputn(__buf, __rlen);
429                   __plen += __rlen;
430                 }
431             }
432         }
433       return __elen && __elen == __plen;
434     }
435
436   template<typename _CharT, typename _Traits>
437     typename basic_filebuf<_CharT, _Traits>::__streambuf_type* 
438     basic_filebuf<_CharT, _Traits>::
439     setbuf(char_type* __s, streamsize __n)
440     {
441       if (!this->is_open() && __s == 0 && __n == 0)
442         this->_M_buf_size = 1;
443       else if (__s && __n > 0)
444         {
445           // This is implementation-defined behavior, and assumes that
446           // an external char_type array of length __n exists and has
447           // been pre-allocated. If this is not the case, things will
448           // quickly blow up. When __n > 1, __n - 1 positions will be
449           // used for the get area, __n - 1 for the put area and 1
450           // position to host the overflow char of a full put area.
451           // When __n == 1, 1 position will be used for the get area
452           // and 0 for the put area, as in the unbuffered case above.
453
454           // Step 1: Destroy the current internal array.
455           _M_destroy_internal_buffer();
456           
457           // Step 2: Use the external array.
458           this->_M_buf = __s;
459           this->_M_buf_size = __n;
460           _M_reading = false;
461           _M_writing = false;
462           _M_set_buffer(-1);
463         }
464       _M_last_overflowed = false;       
465       return this; 
466     }
467   
468   template<typename _CharT, typename _Traits>
469     typename basic_filebuf<_CharT, _Traits>::pos_type
470     basic_filebuf<_CharT, _Traits>::
471     seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode __mode)
472     {
473       pos_type __ret =  pos_type(off_type(-1)); 
474       const bool __testin = (ios_base::in & this->_M_mode & __mode) != 0;
475       const bool __testout = (ios_base::out & this->_M_mode & __mode) != 0;
476       
477       int __width = 0;
478       if (_M_codecvt)
479           __width = _M_codecvt->encoding();
480       if (__width < 0)
481         __width = 0;
482
483       const bool __testfail = __off != 0 && __width <= 0;      
484       if (this->is_open() && !__testfail && (__testin || __testout)) 
485         {
486           // Ditch any pback buffers to avoid confusion.
487           _M_destroy_pback();
488
489           // Sync the internal and external streams.          
490           off_type __computed_off = __width * __off;
491           
492           if (this->pbase() < this->pptr()
493               || _M_last_overflowed)
494             {
495               // Part one: update the output sequence.
496               this->sync();
497               
498               // Part two: output unshift sequence.
499               _M_output_unshift();
500             }
501           else if (_M_reading && __way == ios_base::cur)
502             __computed_off += this->gptr() - this->egptr();
503           
504           // Return pos_type(off_type(-1)) in case of failure.
505           __ret = _M_file.seekoff(__computed_off, __way, __mode);
506           _M_reading = false;
507           _M_writing = false;
508           _M_set_buffer(-1);
509         }
510       _M_last_overflowed = false;       
511       return __ret;
512     }
513
514   template<typename _CharT, typename _Traits>
515     typename basic_filebuf<_CharT, _Traits>::pos_type
516     basic_filebuf<_CharT, _Traits>::
517     seekpos(pos_type __pos, ios_base::openmode __mode)
518     {
519 #ifdef _GLIBCPP_RESOLVE_LIB_DEFECTS
520 // 171. Strange seekpos() semantics due to joint position
521       return this->seekoff(off_type(__pos), ios_base::beg, __mode);
522 #endif
523     }
524
525   template<typename _CharT, typename _Traits>
526     void 
527     basic_filebuf<_CharT, _Traits>::
528     _M_output_unshift()
529     { }
530
531   template<typename _CharT, typename _Traits>
532     void
533     basic_filebuf<_CharT, _Traits>::
534     imbue(const locale& __loc)
535     {
536       const bool __testbeg = !this->seekoff(0, ios_base::cur, this->_M_mode);
537       const bool __teststate = __check_facet(_M_codecvt).encoding() == -1;
538
539       if (this->_M_buf_locale != __loc 
540           && (!this->is_open() || (__testbeg && !__teststate)))
541         {
542           this->_M_buf_locale = __loc;
543           if (__builtin_expect(has_facet<__codecvt_type>(__loc), true))
544             _M_codecvt = &use_facet<__codecvt_type>(__loc);
545
546           // NB This may require the reconversion of previously
547           // converted chars. This in turn may cause the
548           // reconstruction of the original file. YIKES!!  This
549           // implementation interprets this requirement as requiring
550           // the file position be at the beginning, and a stateless
551           // encoding, or that the filebuf be closed. Opinions may differ.
552         }
553       _M_last_overflowed = false;       
554     }
555
556   // Inhibit implicit instantiations for required instantiations,
557   // which are defined via explicit instantiations elsewhere.  
558   // NB:  This syntax is a GNU extension.
559 #if _GLIBCPP_EXTERN_TEMPLATE
560   extern template class basic_filebuf<char>;
561   extern template class basic_ifstream<char>;
562   extern template class basic_ofstream<char>;
563   extern template class basic_fstream<char>;
564
565 #ifdef _GLIBCPP_USE_WCHAR_T
566   extern template class basic_filebuf<wchar_t>;
567   extern template class basic_ifstream<wchar_t>;
568   extern template class basic_ofstream<wchar_t>;
569   extern template class basic_fstream<wchar_t>;
570 #endif
571 #endif
572 } // namespace std
573
574 #endif