OSDN Git Service

2001-02-15 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_filebuf_init()
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_buffers()
61     {
62       if (!_M_buf)
63         {
64           _M_buf_size = _M_buf_size_opt;
65           // Allocate internal buffer.
66           try { _M_buf = new char_type[_M_buf_size]; }
67           catch(...) 
68             {
69               delete [] _M_buf;
70               __throw_exception_again;
71             }
72           
73           // Allocate pback buffer.
74           try 
75             { _M_pback = new char_type[_M_pback_size]; }
76           catch(...) 
77             {
78               delete [] _M_pback;
79               __throw_exception_again;
80             }
81         }
82     }
83
84   template<typename _CharT, typename _Traits>
85     basic_filebuf<_CharT, _Traits>::
86     basic_filebuf() 
87     : __streambuf_type(), _M_file(NULL), _M_state_cur(__state_type()), 
88     _M_state_beg(__state_type()), _M_last_overflowed(false)
89     { _M_fcvt = &use_facet<__codecvt_type>(this->getloc()); }
90
91   template<typename _CharT, typename _Traits>
92     basic_filebuf<_CharT, _Traits>::
93     basic_filebuf(int __fd, const char* /*__name*/, ios_base::openmode __mode)
94     : __streambuf_type(),  _M_file(NULL), _M_state_cur(__state_type()), 
95     _M_state_beg(__state_type()), _M_last_overflowed(false)
96     {
97       _M_fcvt = &use_facet<__codecvt_type>(this->getloc());
98       _M_filebuf_init();
99       _M_file->sys_open(__fd, __mode);
100       if (this->is_open())
101         {
102           _M_allocate_buffers();
103           _M_mode = __mode;
104
105           // XXX So that istream::getc() will only need to get 1 char,
106           // as opposed to BUF_SIZE.
107           if (__fd == 0)
108             _M_buf_size = 1;
109
110           this->_M_set_indeterminate();
111         }
112    }
113
114   template<typename _CharT, typename _Traits>
115     basic_filebuf<_CharT, _Traits>::__filebuf_type* 
116     basic_filebuf<_CharT, _Traits>::
117     open(const char* __s, ios_base::openmode __mode)
118     {
119       __filebuf_type *__ret = NULL;
120       if (!this->is_open())
121         {
122           _M_filebuf_init();
123           _M_file->open(__s, __mode);
124           if (this->is_open())
125             {
126               _M_allocate_buffers();
127               _M_mode = __mode;
128               
129               // For time being, set both (in/out) sets  of pointers.
130               _M_set_indeterminate();
131               if (__mode & ios_base::ate
132                   && this->seekoff(0, ios_base::end, __mode) < 0)
133                 this->close();
134               __ret = this;
135             }
136         }
137       return __ret;
138     }
139
140   template<typename _CharT, typename _Traits>
141     basic_filebuf<_CharT, _Traits>::__filebuf_type* 
142     basic_filebuf<_CharT, _Traits>::
143     close()
144     {
145       __filebuf_type *__ret = NULL;
146       if (this->is_open())
147         {
148           bool __testput = _M_out_cur && _M_out_beg < _M_out_end;
149           if (__testput)
150             _M_really_overflow(traits_type::eof());
151
152           // NB: Do this here so that re-opened filebufs will be cool...
153           _M_pback_destroy();
154
155 #if 0
156           // XXX not done
157           if (_M_last_overflowed)
158             {
159               _M_output_unshift();
160               _M_really_overflow(traits_type::eof());
161             }
162 #endif
163
164           _M_mode = ios_base::openmode(0);
165           if (_M_buf)
166             {
167               delete [] _M_buf;
168               _M_buf = NULL;
169               delete [] _M_pback;
170               _M_pback = NULL;
171               this->setg(NULL, NULL, NULL);
172               this->setp(NULL, NULL);
173             }
174           __ret = this;
175         }
176
177       // Can actually allocate this file as part of an open and never
178       // have it be opened.....
179       if (_M_file)
180         {
181           delete _M_file;
182           _M_file = NULL;
183         }
184       _M_last_overflowed = false;       
185       return __ret;
186     }
187
188   template<typename _CharT, typename _Traits>
189     streamsize 
190     basic_filebuf<_CharT, _Traits>::
191     showmanyc()
192     {
193       streamsize __ret = -1;
194       bool __testin = _M_mode & ios_base::in;
195
196       if (__testin)
197         {
198           bool __testeof = false;
199           if (_M_in_cur >= _M_in_end)
200             __testeof = this->underflow() == traits_type::eof();
201           if (!__testeof)
202             __ret = _M_in_end - _M_in_cur;
203         }
204       _M_last_overflowed = false;       
205       return __ret;
206     }
207
208   template<typename _CharT, typename _Traits>
209     basic_filebuf<_CharT, _Traits>::int_type 
210     basic_filebuf<_CharT, _Traits>::
211     underflow()
212     {
213       int_type __ret = traits_type::eof();
214       bool __testin = _M_mode & ios_base::in;
215       
216       if (__testin)
217         {
218           // Check for pback madness, and if so swich back to the
219           // normal buffers and jet outta here before expensive
220           // fileops happen...
221           if (_M_pback_init)
222             {
223               _M_pback_destroy();
224               if (_M_in_cur < _M_in_end)
225                 return traits_type::to_int_type(*_M_in_cur);
226             }
227
228           bool __testget = _M_in_cur && _M_in_beg < _M_in_cur;
229           bool __testinit = _M_is_indeterminate();
230           bool __testout = _M_mode & ios_base::out;
231
232           // Sync internal and external buffers.
233           // NB: __testget -> __testput as _M_buf_unified here.
234           if (__testget)
235             {
236               if (__testout)
237                 _M_really_overflow();
238               else 
239                 _M_file->seekoff(_M_in_cur - _M_in_beg, 
240                                  ios_base::cur, ios_base::in);
241             }
242
243           if (__testinit || __testget)
244             {
245 #if 1
246               streamsize __size = _M_file->xsgetn(_M_in_beg, _M_buf_size);
247               if (0 < __size)
248                 {
249                   _M_set_determinate(__size);
250                   if (__testout)
251                     _M_out_cur = _M_in_cur;
252                   __ret = traits_type::to_int_type(*_M_in_cur);
253                   streamoff __p = _M_file->seekoff(0 - __size, ios_base::cur, 
254                                                    ios_base::in);
255                   if (__p == -1)
256                     {
257                       // XXX Something is wrong, do error checking.
258                     }
259                 }
260 #else
261               // 2000-08-04 bkoz disable
262               // Part one: (Re)fill external buf (_M_file->_IO_*) from
263               // external byte sequence (whatever physical byte sink or
264               // FILE actually is.)
265               char_type __conv_buf[_M_buf_size];
266               streamsize __size = _M_file->xsgetn(__conv_buf, _M_buf_size);
267               
268               // Part two: (Re)fill internal buf contents from external buf.
269               if (0 < __size)
270                 {
271                   _M_set_determinate(__size);
272                   
273                   char* __conv_cur = __conv_buf;
274                   _M_state_beg = _M_state_cur;
275                   __res_type __r = _M_fcvt->in(_M_state_cur, 
276                                                __conv_buf,
277                                                __conv_buf + __size,
278                                          const_cast<const char*&>(__conv_cur), 
279                                               _M_in_beg, _M_in_end, _M_in_cur);
280               
281                   if (__r == codecvt_base::partial)
282                     {
283                       // XXX Retry with larger _M_buf size.
284                     }
285                   
286                   // Set pointers to internal and external buffers
287                   // correctly. . .
288                   if (__r != codecvt_base::error)
289                     {
290                       if (__testout)
291                         _M_out_cur = _M_in_cur;
292                       __ret = traits_type::to_int_type(*_M_in_cur);
293                     }
294
295                   // Part three: Sync the current internal buffer
296                   // position with the (now overshot) external buffer
297                   // position.  
298                   streamoff __p = _M_file->seekoff(0 - __size, ios_base::cur, 
299                                                   ios_base::in);
300                   if (__p == -1)
301                     {
302                       // XXX Something is wrong, do error checking.
303                     }
304                 }
305 #endif        
306             }
307         }
308       _M_last_overflowed = false;       
309       return __ret;
310     }
311   
312   template<typename _CharT, typename _Traits>
313     basic_filebuf<_CharT, _Traits>::int_type 
314     basic_filebuf<_CharT, _Traits>::
315     pbackfail(int_type __i)
316     {
317       int_type __ret = traits_type::eof();
318       bool __testin = _M_mode & ios_base::in;
319
320       if (__testin)
321         {
322           bool __testpb = _M_in_beg < _M_in_cur;
323           char_type __c = traits_type::to_char_type(__i);
324           bool __testeof = traits_type::eq_int_type(__i, __ret);
325
326           if (__testpb)
327             {
328               bool __testout = _M_mode & ios_base::out;
329               bool __testeq = traits_type::eq(__c, this->gptr()[-1]);
330
331               // Try to put back __c into input sequence in one of three ways.
332               // Order these tests done in is unspecified by the standard.
333               if (!__testeof && __testeq)
334                 {
335                   --_M_in_cur;
336                   if (__testout)
337                     --_M_out_cur;
338                   __ret = __i;
339                 }
340               else if (__testeof)
341                 {
342                   --_M_in_cur;
343                   if (__testout)
344                     --_M_out_cur;
345                   __ret = traits_type::not_eof(__i);
346                 }
347               else if (!__testeof)
348                 {
349                   --_M_in_cur;
350                   if (__testout)
351                     --_M_out_cur;
352                   _M_pback_create();
353                   *_M_in_cur = __c; 
354                   __ret = __i;
355                 }
356             }
357           else
358             {    
359               // At the beginning of the buffer, need to make a
360               // putback position available.
361               this->seekoff(-1, ios_base::cur);
362               this->underflow();
363               if (!__testeof)
364                 {
365                   if (!traits_type::eq(__c, *_M_in_cur))
366                     {
367                       _M_pback_create();
368                       *_M_in_cur = __c;
369                     }
370                   __ret = __i;
371                 }
372               else
373                 __ret = traits_type::not_eof(__i);
374             }
375         }
376       _M_last_overflowed = false;       
377       return __ret;
378     }
379
380   template<typename _CharT, typename _Traits>
381     basic_filebuf<_CharT, _Traits>::int_type 
382     basic_filebuf<_CharT, _Traits>::
383     overflow(int_type __c)
384     {
385       int_type __ret = traits_type::eof();
386       bool __testpos = _M_out_cur && _M_out_cur >= _M_buf + _M_buf_size;
387       bool __testout = _M_mode & ios_base::out;
388       
389       if (__testout)
390         {
391           if (!__testpos)
392             {
393               *_M_out_cur = traits_type::to_char_type(__c);
394               _M_out_cur_move(1);
395               __ret = traits_type::not_eof(__c);
396             }
397           else 
398             __ret = this->_M_really_overflow(__c);
399         }
400
401       _M_last_overflowed = false;    // Set in _M_really_overflow, below.
402       return __ret;
403     }
404   
405   template<typename _CharT, typename _Traits>
406     basic_filebuf<_CharT, _Traits>::int_type 
407     basic_filebuf<_CharT, _Traits>::
408     _M_really_overflow(int_type __c)
409     {
410       int_type __ret = traits_type::eof();
411       bool __testput = _M_out_cur && _M_out_beg < _M_out_end;
412       
413       if (__testput)
414         {
415           bool __testeof = traits_type::eq_int_type(__c, traits_type::eof());
416 #if 1
417           int __plen = _M_out_end - _M_out_beg;
418           streamsize __len = _M_file->xsputn(_M_out_beg, __plen);
419           if (!__testeof)
420             {
421               char_type __pending = traits_type::to_char_type(__c);
422               __len += _M_file->xsputn(&__pending, 1);
423               ++__plen;
424             }
425           traits_type::to_char_type(__c);
426           // NB: Need this so that external byte sequence reflects
427           // internal buffer.
428           _M_file->sync();
429           if (__len == __plen)
430             {
431               _M_set_indeterminate();
432               __ret = traits_type::not_eof(__c);
433             }
434 #else
435           // Part one: Allocate temporary conversion buffer on
436           // stack. Convert internal buffer plus __c (ie,
437           // "pending sequence") to temporary conversion buffer.
438           int __plen = _M_out_end - _M_out_beg;
439           char_type __pbuf[__plen + 1];       
440           traits_type::copy(__pbuf, this->pbase(), __plen);
441           if (!__testeof)
442             {
443               __pbuf[__plen] = traits_type::to_char_type(__c);
444               ++__plen;
445             }
446
447           char_type* __pend;
448           char __conv_buf[__plen];
449           char* __conv_end;
450           _M_state_beg = _M_state_cur;
451
452           __res_type __r = _M_fcvt->out(_M_state_cur, 
453                                         __pbuf, __pbuf + __plen,
454                                         const_cast<const char_type*&>(__pend),
455                                         __conv_buf, __conv_buf + __plen,
456                                         __conv_end);
457           
458           // Part two: (Re)spill converted "pending sequence"
459           // contents (now in temporary conversion buffer) to
460           // external buffer (_M_file->_IO_*) using
461           // _M_file->sys_write(), and do error (minimal) checking.
462           if (__r != codecvt_base::error)
463             {
464               streamsize __len = _M_file->xsputn(__conv_buf, __plen);
465               // NB: Need this so that external byte sequence reflects
466               // internal buffer.
467               _M_file->sync();
468               if (__len == __plen)
469                 {
470                   _M_set_indeterminate();
471                   __ret = traits_type::not_eof(__c);
472                 }
473             }
474 #endif
475         }             
476       _M_last_overflowed = true;        
477       return __ret;
478     }
479
480   template<typename _CharT, typename _Traits>
481     basic_filebuf<_CharT, _Traits>::pos_type
482     basic_filebuf<_CharT, _Traits>::
483     seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode __mode)
484     {
485       pos_type __ret =  pos_type(off_type(-1)); 
486       bool __testopen = this->is_open();
487       bool __testin = __mode & ios_base::in && _M_mode & ios_base::in;
488       bool __testout = __mode & ios_base::out && _M_mode & ios_base::out;
489       int __width = _M_fcvt->encoding();
490       if (__width < 0)
491         __width = 0;
492       bool __testfail = __off != 0  && __width <= 0;
493       
494       if (__testopen && !__testfail && (__testin || __testout))
495         {
496           // Ditch any pback buffers to avoid confusion.
497           _M_pback_destroy();
498
499           if (__way != ios_base::cur || __off != 0)
500             { 
501               off_type __computed_off = __width * __off;
502               
503               bool __testget = _M_in_cur && _M_in_beg < _M_in_end;
504               bool __testput = _M_out_cur && _M_out_beg < _M_out_end;
505               // Sync the internal and external streams.
506               // out
507               if (__testput || _M_last_overflowed)
508                 {
509                   // Part one: update the output sequence.
510                   this->sync();
511                   // Part two: output unshift sequence.
512                   _M_output_unshift();
513                 }
514               //in
515               // NB: underflow() rewinds the external buffer.
516               else if (__testget && __way == ios_base::cur)
517                 __computed_off += _M_in_cur - _M_in_beg;
518           
519               __ret = _M_file->seekoff(__computed_off, __way, __mode);
520               _M_set_indeterminate();
521             }
522           // NB: Need to do this in case _M_file in indeterminate
523           // state, ie _M_file->_offset == -1
524           else
525             {
526               __ret = _M_file->seekoff(__off, ios_base::cur, __mode);
527               __ret += max(_M_out_cur, _M_in_cur) - _M_buf;
528             }
529         }
530       _M_last_overflowed = false;       
531       return __ret;
532     }
533
534   template<typename _CharT, typename _Traits>
535     basic_filebuf<_CharT, _Traits>::pos_type
536     basic_filebuf<_CharT, _Traits>::
537     seekpos(pos_type __pos, ios_base::openmode __mode)
538     {
539       pos_type __ret;
540       off_type __off = __pos;
541
542       __ret = this->seekoff(__off, ios_base::beg, __mode); 
543
544       _M_last_overflowed = false;       
545       return __ret;
546     }
547
548   template<typename _CharT, typename _Traits>
549     void 
550     basic_filebuf<_CharT, _Traits>::
551     _M_output_unshift()
552     { }
553
554   template<typename _CharT, typename _Traits>
555     void
556     basic_filebuf<_CharT, _Traits>::
557     imbue(const locale& __loc)
558     {
559       bool __testbeg = gptr() == eback() && pptr() == pbase();
560       bool __teststate = _M_fcvt->encoding() == -1;
561       
562       _M_buf_locale_init = true;
563       if (__testbeg && !__teststate && _M_buf_locale != __loc)
564         {
565           // XXX Will need to save these older values.
566           _M_buf_locale = __loc;
567           _M_fcvt = &use_facet<__codecvt_type>(_M_buf_locale);
568           // XXX Necessary?
569           _M_buf_fctype = &use_facet<__ctype_type>(_M_buf_locale); 
570         }
571       // NB this may require the reconversion of previously
572       // converted chars. This in turn may cause the reconstruction
573       // of the original file. YIKES!!
574       // XXX The part in the above comment is not done.
575       _M_last_overflowed = false;       
576     }
577   
578 } // namespace std
579
580 #endif // _CPP_BITS_FSTREAM_TCC
581
582
583
584
585
586
587
588
589
590