OSDN Git Service

2001-06-18 Benjamin Kosnik <bkoz@redhat.com>
[pf3gnuchains/gcc-fork.git] / libstdc++-v3 / include / bits / fstream.tcc
1 // File based streams -*- C++ -*-
2
3 // Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
4 //
5 // This file is part of the GNU ISO C++ Library.  This library is free
6 // software; you can redistribute it and/or modify it under the
7 // terms of the GNU General Public License as published by the
8 // Free Software Foundation; either version 2, or (at your option)
9 // any later version.
10
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
15
16 // You should have received a copy of the GNU General Public License along
17 // with this library; see the file COPYING.  If not, write to the Free
18 // Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
19 // USA.
20
21 // As a special exception, you may use this file as part of a free software
22 // library without restriction.  Specifically, if other files instantiate
23 // templates or use macros or inline functions from this file, or you compile
24 // this file and link it with other files to produce an executable, this
25 // file does not by itself cause the resulting executable to be covered by
26 // the GNU General Public License.  This exception does not however
27 // invalidate any other reasons why the executable file might be covered by
28 // the GNU General Public License.
29
30 //
31 // ISO C++ 14882: 27.8  File-based streams
32 //
33
34 #ifndef _CPP_BITS_FSTREAM_TCC
35 #define _CPP_BITS_FSTREAM_TCC 1
36
37 namespace std
38 {
39   template<typename _CharT, typename _Traits>
40     void
41     basic_filebuf<_CharT, _Traits>::
42     _M_allocate_file()
43     {
44       if (!_M_file)
45         {
46           _M_buf_unified = true; // Tie input to output for basic_filebuf.
47           try 
48             { _M_file = new __file_type(&_M_lock); }
49           catch(...) 
50             {
51               delete _M_file;
52               __throw_exception_again;
53             }
54         }
55     }
56
57   template<typename _CharT, typename _Traits>
58     void
59     basic_filebuf<_CharT, _Traits>::
60     _M_allocate_internal_buffer()
61     {
62       if (!_M_buf && _M_buf_size_opt)
63         {
64           _M_buf_size = _M_buf_size_opt;
65
66           // Allocate internal buffer.
67           try { _M_buf = new char_type[_M_buf_size]; }
68           catch(...) 
69             {
70               delete [] _M_buf;
71               __throw_exception_again;
72             }
73           _M_buf_allocated = true;
74         }
75     }
76
77   // Both close and setbuf need to deallocate internal buffers, if it exists.
78   template<typename _CharT, typename _Traits>
79     void
80     basic_filebuf<_CharT, _Traits>::
81     _M_destroy_internal_buffer()
82     {
83       if (_M_buf_allocated)
84         {
85           delete [] _M_buf;
86           _M_buf = NULL;
87           _M_buf_allocated = false;
88           this->setg(NULL, NULL, NULL);
89           this->setp(NULL, NULL);
90         }
91     }
92
93  template<typename _CharT, typename _Traits>
94     void
95     basic_filebuf<_CharT, _Traits>::
96     _M_allocate_pback_buffer()
97     {
98       if (!_M_pback && _M_pback_size)
99         {
100           // Allocate pback buffer.
101           try 
102             { _M_pback = new char_type[_M_pback_size]; }
103           catch(...) 
104             {
105               delete [] _M_pback;
106               __throw_exception_again;
107             }
108         }
109     }
110
111   template<typename _CharT, typename _Traits>
112     basic_filebuf<_CharT, _Traits>::
113     basic_filebuf() 
114     : __streambuf_type(), _M_file(NULL), _M_state_cur(__state_type()), 
115     _M_state_beg(__state_type()), _M_buf_allocated(false), 
116     _M_last_overflowed(false)
117     { }
118
119   template<typename _CharT, typename _Traits>
120     basic_filebuf<_CharT, _Traits>::
121     basic_filebuf(__c_file_type* __f, ios_base::openmode __mode, int_type __s)
122     : __streambuf_type(),  _M_file(NULL), _M_state_cur(__state_type()), 
123     _M_state_beg(__state_type()), _M_buf_allocated(false), 
124     _M_last_overflowed(false)
125     {
126       _M_allocate_file();
127       _M_file->sys_open(__f, __mode);
128       if (this->is_open())
129         {
130           _M_mode = __mode;
131           if (__s)
132             {
133               _M_buf_size_opt = __s;
134               _M_allocate_internal_buffer();
135               _M_set_indeterminate();
136             }
137           _M_allocate_pback_buffer();
138         }
139     }
140
141   template<typename _CharT, typename _Traits>
142     basic_filebuf<_CharT, _Traits>::__filebuf_type* 
143     basic_filebuf<_CharT, _Traits>::
144     open(const char* __s, ios_base::openmode __mode)
145     {
146       __filebuf_type *__ret = NULL;
147       if (!this->is_open())
148         {
149           _M_allocate_file();
150           _M_file->open(__s, __mode);
151           if (this->is_open())
152             {
153               _M_allocate_internal_buffer();
154               _M_allocate_pback_buffer();
155               _M_mode = __mode;
156               
157               // For time being, set both (in/out) sets  of pointers.
158               _M_set_indeterminate();
159               if (__mode & ios_base::ate
160                   && this->seekoff(0, ios_base::end, __mode) < 0)
161                 this->close();
162               __ret = this;
163             }
164         }
165       return __ret;
166     }
167
168   template<typename _CharT, typename _Traits>
169     basic_filebuf<_CharT, _Traits>::__filebuf_type* 
170     basic_filebuf<_CharT, _Traits>::
171     close()
172     {
173       __filebuf_type *__ret = NULL;
174       if (this->is_open())
175         {
176           bool __testput = _M_out_cur && _M_out_beg < _M_out_end;
177           if (__testput)
178             _M_really_overflow(traits_type::eof());
179
180           // NB: Do this here so that re-opened filebufs will be cool...
181           _M_pback_destroy();
182
183 #if 0
184           // XXX not done
185           if (_M_last_overflowed)
186             {
187               _M_output_unshift();
188               _M_really_overflow(traits_type::eof());
189             }
190 #endif
191
192           _M_mode = ios_base::openmode(0);
193           _M_destroy_internal_buffer();
194
195           if (_M_pback)
196             {
197               delete [] _M_pback;
198               _M_pback = NULL;
199             }
200           __ret = this;
201         }
202
203       // Can actually allocate this file as part of an open and never
204       // have it be opened.....
205       if (_M_file)
206         {
207           delete _M_file;
208           _M_file = NULL;
209         }
210       _M_last_overflowed = false;       
211       return __ret;
212     }
213
214   template<typename _CharT, typename _Traits>
215     streamsize 
216     basic_filebuf<_CharT, _Traits>::
217     showmanyc()
218     {
219       streamsize __ret = -1;
220       bool __testin = _M_mode & ios_base::in;
221
222       if (__testin)
223         {
224           bool __testeof = false;
225           if (_M_in_cur >= _M_in_end)
226             __testeof = this->underflow() == traits_type::eof();
227           if (!__testeof)
228             __ret = _M_in_end - _M_in_cur;
229         }
230       _M_last_overflowed = false;       
231       return __ret;
232     }
233
234   template<typename _CharT, typename _Traits>
235     basic_filebuf<_CharT, _Traits>::int_type 
236     basic_filebuf<_CharT, _Traits>::
237     underflow()
238     {
239       int_type __ret = traits_type::eof();
240       bool __testin = _M_mode & ios_base::in;
241       bool __testout = _M_mode & ios_base::out;
242
243       // XXX Should re-enable codecvt bits disabled after 2.90.8.
244       if (__testin)
245         {
246           // Check for pback madness, and if so swich back to the
247           // normal buffers and jet outta here before expensive
248           // fileops happen...
249           if (_M_pback_init)
250             {
251               _M_pback_destroy();
252               if (_M_in_cur < _M_in_end)
253                 return traits_type::to_int_type(*_M_in_cur);
254             }
255
256           bool __testget = _M_in_cur && _M_in_beg < _M_in_cur;
257           bool __testinit = _M_is_indeterminate();
258           // Sync internal and external buffers.
259           // NB: __testget -> __testput as _M_buf_unified here.
260           if (__testget)
261             {
262               if (__testout)
263                 _M_really_overflow();
264 #if _GLIBCPP_AVOID_FSEEK
265               else if ((_M_in_cur - _M_in_beg) == 1)
266                 _M_file->sys_getc();
267 #endif
268               else 
269                 _M_file->seekoff(_M_in_cur - _M_in_beg, 
270                                  ios_base::cur, ios_base::in);
271             }
272
273           if (__testinit || __testget)
274             {
275               // Assume buffered case, need to refill internal buffers.
276               streamsize __size = _M_file->xsgetn(_M_in_beg, _M_buf_size);
277               if (0 < __size)
278                 {
279                   _M_set_determinate(__size);
280                   if (__testout)
281                     _M_out_cur = _M_in_cur;
282                   __ret = traits_type::to_int_type(*_M_in_cur);
283 #if _GLIBCPP_AVOID_FSEEK
284                   if (__size == 1)
285                     _M_file->sys_ungetc(*_M_in_cur);
286                   else
287                     {
288 #endif
289                   streamoff __p = _M_file->seekoff(0 - __size, ios_base::cur, 
290                                                    ios_base::in);
291                   if (__p == -1)
292                     {
293                       // XXX Something is wrong, do error checking.
294                     }
295 #if _GLIBCPP_AVOID_FSEEK
296                     }
297 #endif
298                 }          
299             }
300         }
301       _M_last_overflowed = false;       
302       return __ret;
303     }
304   
305   template<typename _CharT, typename _Traits>
306     basic_filebuf<_CharT, _Traits>::int_type 
307     basic_filebuf<_CharT, _Traits>::
308     pbackfail(int_type __i)
309     {
310       int_type __ret = traits_type::eof();
311       bool __testin = _M_mode & ios_base::in;
312
313       if (__testin)
314         {
315           bool __testpb = _M_in_beg < _M_in_cur;
316           char_type __c = traits_type::to_char_type(__i);
317           bool __testeof = traits_type::eq_int_type(__i, __ret);
318
319           if (__testpb)
320             {
321               bool __testout = _M_mode & ios_base::out;
322               bool __testeq = traits_type::eq(__c, this->gptr()[-1]);
323
324               // Try to put back __c into input sequence in one of three ways.
325               // Order these tests done in is unspecified by the standard.
326               if (!__testeof && __testeq)
327                 {
328                   --_M_in_cur;
329                   if (__testout)
330                     --_M_out_cur;
331                   __ret = __i;
332                 }
333               else if (__testeof)
334                 {
335                   --_M_in_cur;
336                   if (__testout)
337                     --_M_out_cur;
338                   __ret = traits_type::not_eof(__i);
339                 }
340               else if (!__testeof)
341                 {
342                   --_M_in_cur;
343                   if (__testout)
344                     --_M_out_cur;
345                   _M_pback_create();
346                   *_M_in_cur = __c; 
347                   __ret = __i;
348                 }
349             }
350           else
351             {    
352               // At the beginning of the buffer, need to make a
353               // putback position available.
354               this->seekoff(-1, ios_base::cur);
355               this->underflow();
356               if (!__testeof)
357                 {
358                   if (!traits_type::eq(__c, *_M_in_cur))
359                     {
360                       _M_pback_create();
361                       *_M_in_cur = __c;
362                     }
363                   __ret = __i;
364                 }
365               else
366                 __ret = traits_type::not_eof(__i);
367             }
368         }
369       _M_last_overflowed = false;       
370       return __ret;
371     }
372
373   template<typename _CharT, typename _Traits>
374     basic_filebuf<_CharT, _Traits>::int_type 
375     basic_filebuf<_CharT, _Traits>::
376     overflow(int_type __c)
377     {
378       int_type __ret = traits_type::eof();
379       bool __testput = _M_out_cur && _M_out_cur < _M_buf + _M_buf_size;
380       bool __testout = _M_mode & ios_base::out;
381       
382       if (__testout)
383         {
384           if (__testput)
385             {
386               *_M_out_cur = traits_type::to_char_type(__c);
387               _M_out_cur_move(1);
388               __ret = traits_type::not_eof(__c);
389             }
390           else 
391             __ret = this->_M_really_overflow(__c);
392         }
393
394       _M_last_overflowed = false;    // Set in _M_really_overflow, below.
395       return __ret;
396     }
397   
398   template<typename _CharT, typename _Traits>
399     basic_filebuf<_CharT, _Traits>::int_type 
400     basic_filebuf<_CharT, _Traits>::
401     _M_really_overflow(int_type __c)
402     {
403       int_type __ret = traits_type::eof();
404       bool __testput = _M_out_cur && _M_out_beg < _M_out_end;
405       bool __testunbuffered = _M_file && !_M_buf_size;
406
407       if (__testput || __testunbuffered)
408         {
409 #if 1
410           int __plen = _M_out_end - _M_out_beg;
411           streamsize __len = 0;
412
413           if (__plen)
414             __len = _M_file->xsputn(_M_out_beg, __plen);
415
416           if (__c !=traits_type::eof())
417             {
418               char_type __pending = traits_type::to_char_type(__c);
419               __len += _M_file->xsputn(&__pending, 1);
420               ++__plen;
421             }
422
423           // NB: Need this so that external byte sequence reflects
424           // internal buffer.
425           _M_file->sync();
426           if (__len == __plen)
427             {
428               _M_set_indeterminate();
429               __ret = traits_type::not_eof(__c);
430             }
431 #else
432           // Part one: Allocate temporary conversion buffer on
433           // stack. Convert internal buffer plus __c (ie,
434           // "pending sequence") to temporary conversion buffer.
435           int __plen = _M_out_end - _M_out_beg;
436           char_type* __pbuf = static_cast<char_type*>(__builtin_alloca(sizeof(char_type) * __plen + 1));
437           traits_type::copy(__pbuf, this->pbase(), __plen);
438           if (!__testeof)
439             {
440               __pbuf[__plen] = traits_type::to_char_type(__c);
441               ++__plen;
442             }
443
444           char_type* __pend;
445           char* __conv_buf = static_cast<char*>(__builtin_alloca(__plen));
446           char* __conv_end;
447           _M_state_beg = _M_state_cur;
448
449           __res_type __r = _M_fcvt->out(_M_state_cur, 
450                                         __pbuf, __pbuf + __plen,
451                                         const_cast<const char_type*&>(__pend),
452                                         __conv_buf, __conv_buf + __plen,
453                                         __conv_end);
454           
455           // Part two: (Re)spill converted "pending sequence"
456           // contents (now in temporary conversion buffer) to
457           // external buffer (_M_file->_IO_*) using
458           // _M_file->sys_write(), and do error (minimal) checking.
459           if (__r != codecvt_base::error)
460             {
461               streamsize __len = _M_file->xsputn(__conv_buf, __plen);
462               // NB: Need this so that external byte sequence reflects
463               // internal buffer.
464               _M_file->sync();
465               if (__len == __plen)
466                 {
467                   _M_set_indeterminate();
468                   __ret = traits_type::not_eof(__c);
469                 }
470             }
471 #endif
472         }             
473       _M_last_overflowed = true;        
474       return __ret;
475     }
476
477   template<typename _CharT, typename _Traits>
478     basic_filebuf<_CharT, _Traits>::__streambuf_type* 
479     basic_filebuf<_CharT, _Traits>::
480     setbuf(char_type* __s, streamsize __n)
481     {
482       if (!this->is_open() && __s == 0 && __n == 0)
483         _M_buf_size_opt = 0;
484       else if (__s && __n)
485         {
486           // This is implementation-defined behavior, and assumes
487           // that an external char_type array of length (__s + __n)
488           // exists and has been pre-allocated. If this is not the
489           // case, things will quickly blow up.
490           // Step 1: Destroy the current internal array.
491           _M_destroy_internal_buffer();
492           
493           // Step 2: Use the external array.
494           _M_buf = __s;
495           _M_buf_size_opt = _M_buf_size = __n;
496           _M_set_indeterminate();
497           
498         // Step 3: Make sure a pback buffer is allocated.
499           _M_allocate_pback_buffer();
500         }
501       _M_last_overflowed = false;       
502       return this; 
503     }
504   
505   template<typename _CharT, typename _Traits>
506     basic_filebuf<_CharT, _Traits>::pos_type
507     basic_filebuf<_CharT, _Traits>::
508     seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode __mode)
509     {
510       pos_type __ret =  pos_type(off_type(-1)); 
511       bool __testopen = this->is_open();
512       bool __testin = __mode & ios_base::in && _M_mode & ios_base::in;
513       bool __testout = __mode & ios_base::out && _M_mode & ios_base::out;
514
515       // Should probably do has_facet checks here.
516       int __width = use_facet<__codecvt_type>(_M_buf_locale).encoding();
517       if (__width < 0)
518         __width = 0;
519       bool __testfail = __off != 0  && __width <= 0;
520       
521       if (__testopen && !__testfail && (__testin || __testout))
522         {
523           // Ditch any pback buffers to avoid confusion.
524           _M_pback_destroy();
525
526           if (__way != ios_base::cur || __off != 0)
527             { 
528               off_type __computed_off = __width * __off;
529               
530               bool __testget = _M_in_cur && _M_in_beg < _M_in_end;
531               bool __testput = _M_out_cur && _M_out_beg < _M_out_end;
532               // Sync the internal and external streams.
533               // out
534               if (__testput || _M_last_overflowed)
535                 {
536                   // Part one: update the output sequence.
537                   this->sync();
538                   // Part two: output unshift sequence.
539                   _M_output_unshift();
540                 }
541               //in
542               // NB: underflow() rewinds the external buffer.
543               else if (__testget && __way == ios_base::cur)
544                 __computed_off += _M_in_cur - _M_in_beg;
545           
546               __ret = _M_file->seekoff(__computed_off, __way, __mode);
547               _M_set_indeterminate();
548             }
549           // NB: Need to do this in case _M_file in indeterminate
550           // state, ie _M_file->_offset == -1
551           else
552             {
553               __ret = _M_file->seekoff(__off, ios_base::cur, __mode);
554               __ret += max(_M_out_cur, _M_in_cur) - _M_buf;
555             }
556         }
557       _M_last_overflowed = false;       
558       return __ret;
559     }
560
561   template<typename _CharT, typename _Traits>
562     basic_filebuf<_CharT, _Traits>::pos_type
563     basic_filebuf<_CharT, _Traits>::
564     seekpos(pos_type __pos, ios_base::openmode __mode)
565     {
566       pos_type __ret;
567       off_type __off = __pos;
568
569       __ret = this->seekoff(__off, ios_base::beg, __mode); 
570
571       _M_last_overflowed = false;       
572       return __ret;
573     }
574
575   template<typename _CharT, typename _Traits>
576     void 
577     basic_filebuf<_CharT, _Traits>::
578     _M_output_unshift()
579     { }
580
581   template<typename _CharT, typename _Traits>
582     void
583     basic_filebuf<_CharT, _Traits>::
584     imbue(const locale& __loc)
585     {
586       bool __testbeg = gptr() == eback() && pptr() == pbase();
587
588       if (__testbeg && _M_buf_locale != __loc)
589         {
590           _M_buf_locale = __loc;
591           _M_buf_locale_init = true;
592         }
593
594       // NB this may require the reconversion of previously
595       // converted chars. This in turn may cause the reconstruction
596       // of the original file. YIKES!!
597       // XXX The part in the above comment is not done.
598       _M_last_overflowed = false;       
599     }
600   
601 } // namespace std
602
603 #endif // _CPP_BITS_FSTREAM_TCC
604
605