OSDN Git Service

2001-10-29 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     typename 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     typename 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           if (_M_in_cur < _M_in_end)
225             __ret = _M_in_end - _M_in_cur;
226           else
227             __ret = 0;
228         }
229       _M_last_overflowed = false;       
230       return __ret;
231     }
232
233   template<typename _CharT, typename _Traits>
234     typename basic_filebuf<_CharT, _Traits>::int_type 
235     basic_filebuf<_CharT, _Traits>::
236     underflow()
237     {
238       int_type __ret = traits_type::eof();
239       bool __testin = _M_mode & ios_base::in;
240       bool __testout = _M_mode & ios_base::out;
241
242       // XXX Should re-enable codecvt bits disabled after 2.90.8.
243       if (__testin)
244         {
245           // Check for pback madness, and if so swich back to the
246           // normal buffers and jet outta here before expensive
247           // fileops happen...
248           if (_M_pback_init)
249             {
250               _M_pback_destroy();
251               if (_M_in_cur < _M_in_end)
252                 return traits_type::to_int_type(*_M_in_cur);
253             }
254
255           bool __testget = _M_in_cur && _M_in_beg < _M_in_cur;
256           bool __testinit = _M_is_indeterminate();
257           // Sync internal and external buffers.
258           // NB: __testget -> __testput as _M_buf_unified here.
259           if (__testget)
260             {
261               if (__testout)
262                 _M_really_overflow();
263 #if _GLIBCPP_AVOID_FSEEK
264               else if ((_M_in_cur - _M_in_beg) == 1)
265                 _M_file->sys_getc();
266 #endif
267               else 
268                 _M_file->seekoff(_M_in_cur - _M_in_beg, 
269                                  ios_base::cur, ios_base::in);
270             }
271
272           if (__testinit || __testget)
273             {
274               // Assume buffered case, need to refill internal buffers.
275               streamsize __size = _M_file->xsgetn(_M_in_beg, _M_buf_size);
276               if (0 < __size)
277                 {
278                   _M_set_determinate(__size);
279                   if (__testout)
280                     _M_out_cur = _M_in_cur;
281                   __ret = traits_type::to_int_type(*_M_in_cur);
282 #if _GLIBCPP_AVOID_FSEEK
283                   if (__size == 1)
284                     _M_file->sys_ungetc(*_M_in_cur);
285                   else
286                     {
287 #endif
288                   streamoff __p = _M_file->seekoff(0 - __size, ios_base::cur, 
289                                                    ios_base::in);
290                   if (__p == -1)
291                     {
292                       // XXX Something is wrong, do error checking.
293                     }
294 #if _GLIBCPP_AVOID_FSEEK
295                     }
296 #endif
297                 }          
298             }
299         }
300       _M_last_overflowed = false;       
301       return __ret;
302     }
303   
304   template<typename _CharT, typename _Traits>
305     typename basic_filebuf<_CharT, _Traits>::int_type 
306     basic_filebuf<_CharT, _Traits>::
307     pbackfail(int_type __i)
308     {
309       int_type __ret = traits_type::eof();
310       bool __testin = _M_mode & ios_base::in;
311
312       if (__testin)
313         {
314           bool __testpb = _M_in_beg < _M_in_cur;
315           char_type __c = traits_type::to_char_type(__i);
316           bool __testeof = traits_type::eq_int_type(__i, __ret);
317
318           if (__testpb)
319             {
320               bool __testout = _M_mode & ios_base::out;
321               bool __testeq = traits_type::eq(__c, this->gptr()[-1]);
322
323               // Try to put back __c into input sequence in one of three ways.
324               // Order these tests done in is unspecified by the standard.
325               if (!__testeof && __testeq)
326                 {
327                   --_M_in_cur;
328                   if (__testout)
329                     --_M_out_cur;
330                   __ret = __i;
331                 }
332               else if (__testeof)
333                 {
334                   --_M_in_cur;
335                   if (__testout)
336                     --_M_out_cur;
337                   __ret = traits_type::not_eof(__i);
338                 }
339               else if (!__testeof)
340                 {
341                   --_M_in_cur;
342                   if (__testout)
343                     --_M_out_cur;
344                   _M_pback_create();
345                   *_M_in_cur = __c; 
346                   __ret = __i;
347                 }
348             }
349           else
350             {    
351               // At the beginning of the buffer, need to make a
352               // putback position available.
353               this->seekoff(-1, ios_base::cur);
354               this->underflow();
355               if (!__testeof)
356                 {
357                   if (!traits_type::eq(__c, *_M_in_cur))
358                     {
359                       _M_pback_create();
360                       *_M_in_cur = __c;
361                     }
362                   __ret = __i;
363                 }
364               else
365                 __ret = traits_type::not_eof(__i);
366             }
367         }
368       _M_last_overflowed = false;       
369       return __ret;
370     }
371
372   template<typename _CharT, typename _Traits>
373     typename basic_filebuf<_CharT, _Traits>::int_type 
374     basic_filebuf<_CharT, _Traits>::
375     overflow(int_type __c)
376     {
377       int_type __ret = traits_type::eof();
378       bool __testput = _M_out_cur && _M_out_cur < _M_buf + _M_buf_size;
379       bool __testout = _M_mode & ios_base::out;
380       
381       if (__testout)
382         {
383           if (__testput)
384             {
385               *_M_out_cur = traits_type::to_char_type(__c);
386               _M_out_cur_move(1);
387               __ret = traits_type::not_eof(__c);
388             }
389           else 
390             __ret = this->_M_really_overflow(__c);
391         }
392
393       _M_last_overflowed = false;    // Set in _M_really_overflow, below.
394       return __ret;
395     }
396   
397   template<typename _CharT, typename _Traits>
398     typename basic_filebuf<_CharT, _Traits>::int_type 
399     basic_filebuf<_CharT, _Traits>::
400     _M_really_overflow(int_type __c)
401     {
402       int_type __ret = traits_type::eof();
403       bool __testput = _M_out_cur && _M_out_beg < _M_out_end;
404       bool __testunbuffered = _M_file && !_M_buf_size;
405
406       if (__testput || __testunbuffered)
407         {
408 #if 1
409           int __plen = _M_out_end - _M_out_beg;
410           streamsize __len = 0;
411
412           if (__plen)
413             __len = _M_file->xsputn(_M_out_beg, __plen);
414
415           if (__c !=traits_type::eof())
416             {
417               char_type __pending = traits_type::to_char_type(__c);
418               __len += _M_file->xsputn(&__pending, 1);
419               ++__plen;
420             }
421
422           // NB: Need this so that external byte sequence reflects
423           // internal buffer.
424           _M_file->sync();
425           if (__len == __plen)
426             {
427               _M_set_indeterminate();
428               __ret = traits_type::not_eof(__c);
429             }
430 #else
431           // Part one: Allocate temporary conversion buffer on
432           // stack. Convert internal buffer plus __c (ie,
433           // "pending sequence") to temporary conversion buffer.
434           int __plen = _M_out_end - _M_out_beg;
435           char_type* __pbuf = static_cast<char_type*>(__builtin_alloca(sizeof(char_type) * __plen + 1));
436           traits_type::copy(__pbuf, this->pbase(), __plen);
437           if (!__testeof)
438             {
439               __pbuf[__plen] = traits_type::to_char_type(__c);
440               ++__plen;
441             }
442
443           char_type* __pend;
444           char* __conv_buf = static_cast<char*>(__builtin_alloca(__plen));
445           char* __conv_end;
446           _M_state_beg = _M_state_cur;
447
448           __res_type __r = _M_fcvt->out(_M_state_cur, 
449                                         __pbuf, __pbuf + __plen,
450                                         const_cast<const char_type*&>(__pend),
451                                         __conv_buf, __conv_buf + __plen,
452                                         __conv_end);
453           
454           // Part two: (Re)spill converted "pending sequence"
455           // contents (now in temporary conversion buffer) to
456           // external buffer (_M_file->_IO_*) using
457           // _M_file->sys_write(), and do error (minimal) checking.
458           if (__r != codecvt_base::error)
459             {
460               streamsize __len = _M_file->xsputn(__conv_buf, __plen);
461               // NB: Need this so that external byte sequence reflects
462               // internal buffer.
463               _M_file->sync();
464               if (__len == __plen)
465                 {
466                   _M_set_indeterminate();
467                   __ret = traits_type::not_eof(__c);
468                 }
469             }
470 #endif
471         }             
472       _M_last_overflowed = true;        
473       return __ret;
474     }
475
476   template<typename _CharT, typename _Traits>
477     typename basic_filebuf<_CharT, _Traits>::__streambuf_type* 
478     basic_filebuf<_CharT, _Traits>::
479     setbuf(char_type* __s, streamsize __n)
480     {
481       if (!this->is_open() && __s == 0 && __n == 0)
482         _M_buf_size_opt = 0;
483       else if (__s && __n)
484         {
485           // This is implementation-defined behavior, and assumes
486           // that an external char_type array of length (__s + __n)
487           // exists and has been pre-allocated. If this is not the
488           // case, things will quickly blow up.
489           // Step 1: Destroy the current internal array.
490           _M_destroy_internal_buffer();
491           
492           // Step 2: Use the external array.
493           _M_buf = __s;
494           _M_buf_size_opt = _M_buf_size = __n;
495           _M_set_indeterminate();
496           
497         // Step 3: Make sure a pback buffer is allocated.
498           _M_allocate_pback_buffer();
499         }
500       _M_last_overflowed = false;       
501       return this; 
502     }
503   
504   template<typename _CharT, typename _Traits>
505     typename basic_filebuf<_CharT, _Traits>::pos_type
506     basic_filebuf<_CharT, _Traits>::
507     seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode __mode)
508     {
509       pos_type __ret =  pos_type(off_type(-1)); 
510       bool __testopen = this->is_open();
511       bool __testin = __mode & ios_base::in && _M_mode & ios_base::in;
512       bool __testout = __mode & ios_base::out && _M_mode & ios_base::out;
513
514       // Should probably do has_facet checks here.
515       int __width = use_facet<__codecvt_type>(_M_buf_locale).encoding();
516       if (__width < 0)
517         __width = 0;
518       bool __testfail = __off != 0  && __width <= 0;
519       
520       if (__testopen && !__testfail && (__testin || __testout))
521         {
522           // Ditch any pback buffers to avoid confusion.
523           _M_pback_destroy();
524
525           if (__way != ios_base::cur || __off != 0)
526             { 
527               off_type __computed_off = __width * __off;
528               
529               bool __testget = _M_in_cur && _M_in_beg < _M_in_end;
530               bool __testput = _M_out_cur && _M_out_beg < _M_out_end;
531               // Sync the internal and external streams.
532               // out
533               if (__testput || _M_last_overflowed)
534                 {
535                   // Part one: update the output sequence.
536                   this->sync();
537                   // Part two: output unshift sequence.
538                   _M_output_unshift();
539                 }
540               //in
541               // NB: underflow() rewinds the external buffer.
542               else if (__testget && __way == ios_base::cur)
543                 __computed_off += _M_in_cur - _M_in_beg;
544           
545               __ret = _M_file->seekoff(__computed_off, __way, __mode);
546               _M_set_indeterminate();
547             }
548           // NB: Need to do this in case _M_file in indeterminate
549           // state, ie _M_file->_offset == -1
550           else
551             {
552               __ret = _M_file->seekoff(__off, ios_base::cur, __mode);
553               __ret += max(_M_out_cur, _M_in_cur) - _M_buf;
554             }
555         }
556       _M_last_overflowed = false;       
557       return __ret;
558     }
559
560   template<typename _CharT, typename _Traits>
561     typename basic_filebuf<_CharT, _Traits>::pos_type
562     basic_filebuf<_CharT, _Traits>::
563     seekpos(pos_type __pos, ios_base::openmode __mode)
564     {
565       pos_type __ret;
566       off_type __off = __pos;
567
568       __ret = this->seekoff(__off, ios_base::beg, __mode); 
569
570       _M_last_overflowed = false;       
571       return __ret;
572     }
573
574   template<typename _CharT, typename _Traits>
575     void 
576     basic_filebuf<_CharT, _Traits>::
577     _M_output_unshift()
578     { }
579
580   template<typename _CharT, typename _Traits>
581     void
582     basic_filebuf<_CharT, _Traits>::
583     imbue(const locale& __loc)
584     {
585       bool __testbeg = gptr() == eback() && pptr() == pbase();
586
587       if (__testbeg && _M_buf_locale != __loc)
588         {
589           _M_buf_locale = __loc;
590           _M_buf_locale_init = true;
591         }
592
593       // NB this may require the reconversion of previously
594       // converted chars. This in turn may cause the reconstruction
595       // of the original file. YIKES!!
596       // XXX The part in the above comment is not done.
597       _M_last_overflowed = false;       
598     }
599   
600 } // namespace std
601
602 #endif // _CPP_BITS_FSTREAM_TCC
603
604