basic_file.h (__basic_file::fd): New function.
[official-gcc.git] / libstdc++-v3 / include / bits / fstream.tcc
blob7f90f2a383e2df0fd611fb001099d16434d889f0
1 // File based streams -*- C++ -*-
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.
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.
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.
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.
31 // ISO C++ 14882: 27.8  File-based streams
34 #ifndef _CPP_BITS_FSTREAM_TCC
35 #define _CPP_BITS_FSTREAM_TCC 1
37 namespace std
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     }
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;
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     }
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     }
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     }
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     { }
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     }
141   template<typename _CharT, typename _Traits>
142     int
143     basic_filebuf<_CharT, _Traits>::
144     fd()
145     {
146       return _M_file->fd();
147     }
149   template<typename _CharT, typename _Traits>
150     typename basic_filebuf<_CharT, _Traits>::__filebuf_type* 
151     basic_filebuf<_CharT, _Traits>::
152     open(const char* __s, ios_base::openmode __mode)
153     {
154       __filebuf_type *__ret = NULL;
155       if (!this->is_open())
156         {
157           _M_allocate_file();
158           _M_file->open(__s, __mode);
159           if (this->is_open())
160             {
161               _M_allocate_internal_buffer();
162               _M_allocate_pback_buffer();
163               _M_mode = __mode;
164               
165               // For time being, set both (in/out) sets  of pointers.
166               _M_set_indeterminate();
167               if (__mode & ios_base::ate
168                   && this->seekoff(0, ios_base::end, __mode) < 0)
169                 this->close();
170               __ret = this;
171             }
172         }
173       return __ret;
174     }
176   template<typename _CharT, typename _Traits>
177     typename basic_filebuf<_CharT, _Traits>::__filebuf_type* 
178     basic_filebuf<_CharT, _Traits>::
179     close()
180     {
181       __filebuf_type *__ret = NULL;
182       if (this->is_open())
183         {
184           bool __testput = _M_out_cur && _M_out_beg < _M_out_end;
185           if (__testput)
186             _M_really_overflow(traits_type::eof());
188           // NB: Do this here so that re-opened filebufs will be cool...
189           _M_pback_destroy();
191 #if 0
192           // XXX not done
193           if (_M_last_overflowed)
194             {
195               _M_output_unshift();
196               _M_really_overflow(traits_type::eof());
197             }
198 #endif
200           _M_mode = ios_base::openmode(0);
201           _M_destroy_internal_buffer();
203           if (_M_pback)
204             {
205               delete [] _M_pback;
206               _M_pback = NULL;
207             }
208           __ret = this;
209         }
211       // Can actually allocate this file as part of an open and never
212       // have it be opened.....
213       if (_M_file)
214         {
215           delete _M_file;
216           _M_file = NULL;
217         }
218       _M_last_overflowed = false;       
219       return __ret;
220     }
222   template<typename _CharT, typename _Traits>
223     streamsize 
224     basic_filebuf<_CharT, _Traits>::
225     showmanyc()
226     {
227       streamsize __ret = -1;
228       bool __testin = _M_mode & ios_base::in;
230       if (__testin)
231         {
232           if (_M_in_cur < _M_in_end)
233             __ret = _M_in_end - _M_in_cur;
234           else
235             __ret = 0;
236         }
237       _M_last_overflowed = false;       
238       return __ret;
239     }
241   template<typename _CharT, typename _Traits>
242     typename basic_filebuf<_CharT, _Traits>::int_type 
243     basic_filebuf<_CharT, _Traits>::
244     underflow()
245     {
246       int_type __ret = traits_type::eof();
247       bool __testin = _M_mode & ios_base::in;
248       bool __testout = _M_mode & ios_base::out;
250       // XXX Should re-enable codecvt bits disabled after 2.90.8.
251       if (__testin)
252         {
253           // Check for pback madness, and if so swich back to the
254           // normal buffers and jet outta here before expensive
255           // fileops happen...
256           if (_M_pback_init)
257             {
258               _M_pback_destroy();
259               if (_M_in_cur < _M_in_end)
260                 return traits_type::to_int_type(*_M_in_cur);
261             }
263           bool __testget = _M_in_cur && _M_in_beg < _M_in_cur;
264           bool __testinit = _M_is_indeterminate();
265           // Sync internal and external buffers.
266           // NB: __testget -> __testput as _M_buf_unified here.
267           if (__testget)
268             {
269               if (__testout)
270                 _M_really_overflow();
271 #if _GLIBCPP_AVOID_FSEEK
272               else if ((_M_in_cur - _M_in_beg) == 1)
273                 _M_file->sys_getc();
274 #endif
275               else 
276                 _M_file->seekoff(_M_in_cur - _M_in_beg, 
277                                  ios_base::cur, ios_base::in);
278             }
280           if (__testinit || __testget)
281             {
282               // Assume buffered case, need to refill internal buffers.
283               streamsize __size = _M_file->xsgetn(_M_in_beg, _M_buf_size);
284               if (0 < __size)
285                 {
286                   _M_set_determinate(__size);
287                   if (__testout)
288                     _M_out_cur = _M_in_cur;
289                   __ret = traits_type::to_int_type(*_M_in_cur);
290 #if _GLIBCPP_AVOID_FSEEK
291                   if (__size == 1)
292                     _M_file->sys_ungetc(*_M_in_cur);
293                   else
294                     {
295 #endif
296                   streamoff __p = _M_file->seekoff(0 - __size, ios_base::cur, 
297                                                    ios_base::in);
298                   if (__p == -1)
299                     {
300                       // XXX Something is wrong, do error checking.
301                     }
302 #if _GLIBCPP_AVOID_FSEEK
303                     }
304 #endif
305                 }          
306             }
307         }
308       _M_last_overflowed = false;       
309       return __ret;
310     }
311   
312   template<typename _CharT, typename _Traits>
313     typename 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;
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);
326           if (__testpb)
327             {
328               bool __testout = _M_mode & ios_base::out;
329               bool __testeq = traits_type::eq(__c, this->gptr()[-1]);
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     }
380   template<typename _CharT, typename _Traits>
381     typename 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 __testput = _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 (__testput)
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         }
401       _M_last_overflowed = false;    // Set in _M_really_overflow, below.
402       return __ret;
403     }
404   
405   template<typename _CharT, typename _Traits>
406     typename 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       bool __testunbuffered = _M_file && !_M_buf_size;
414       if (__testput || __testunbuffered)
415         {
416 #if 1
417           int __plen = _M_out_end - _M_out_beg;
418           streamsize __len = 0;
420           if (__plen)
421             __len = _M_file->xsputn(_M_out_beg, __plen);
423           if (__c !=traits_type::eof())
424             {
425               char_type __pending = traits_type::to_char_type(__c);
426               __len += _M_file->xsputn(&__pending, 1);
427               ++__plen;
428             }
430           // NB: Need this so that external byte sequence reflects
431           // internal buffer.
432           _M_file->sync();
433           if (__len == __plen)
434             {
435               _M_set_indeterminate();
436               __ret = traits_type::not_eof(__c);
437             }
438 #else
439           // Part one: Allocate temporary conversion buffer on
440           // stack. Convert internal buffer plus __c (ie,
441           // "pending sequence") to temporary conversion buffer.
442           int __plen = _M_out_end - _M_out_beg;
443           char_type* __pbuf = static_cast<char_type*>(__builtin_alloca(sizeof(char_type) * __plen + 1));
444           traits_type::copy(__pbuf, this->pbase(), __plen);
445           if (!__testeof)
446             {
447               __pbuf[__plen] = traits_type::to_char_type(__c);
448               ++__plen;
449             }
451           char_type* __pend;
452           char* __conv_buf = static_cast<char*>(__builtin_alloca(__plen));
453           char* __conv_end;
454           _M_state_beg = _M_state_cur;
456           __res_type __r = _M_fcvt->out(_M_state_cur, 
457                                         __pbuf, __pbuf + __plen,
458                                         const_cast<const char_type*&>(__pend),
459                                         __conv_buf, __conv_buf + __plen,
460                                         __conv_end);
461           
462           // Part two: (Re)spill converted "pending sequence"
463           // contents (now in temporary conversion buffer) to
464           // external buffer (_M_file->_IO_*) using
465           // _M_file->sys_write(), and do error (minimal) checking.
466           if (__r != codecvt_base::error)
467             {
468               streamsize __len = _M_file->xsputn(__conv_buf, __plen);
469               // NB: Need this so that external byte sequence reflects
470               // internal buffer.
471               _M_file->sync();
472               if (__len == __plen)
473                 {
474                   _M_set_indeterminate();
475                   __ret = traits_type::not_eof(__c);
476                 }
477             }
478 #endif
479         }             
480       _M_last_overflowed = true;        
481       return __ret;
482     }
484   template<typename _CharT, typename _Traits>
485     typename basic_filebuf<_CharT, _Traits>::__streambuf_type* 
486     basic_filebuf<_CharT, _Traits>::
487     setbuf(char_type* __s, streamsize __n)
488     {
489       if (!this->is_open() && __s == 0 && __n == 0)
490         _M_buf_size_opt = 0;
491       else if (__s && __n)
492         {
493           // This is implementation-defined behavior, and assumes
494           // that an external char_type array of length (__s + __n)
495           // exists and has been pre-allocated. If this is not the
496           // case, things will quickly blow up.
497           // Step 1: Destroy the current internal array.
498           _M_destroy_internal_buffer();
499           
500           // Step 2: Use the external array.
501           _M_buf = __s;
502           _M_buf_size_opt = _M_buf_size = __n;
503           _M_set_indeterminate();
504           
505         // Step 3: Make sure a pback buffer is allocated.
506           _M_allocate_pback_buffer();
507         }
508       _M_last_overflowed = false;       
509       return this; 
510     }
511   
512   template<typename _CharT, typename _Traits>
513     typename basic_filebuf<_CharT, _Traits>::pos_type
514     basic_filebuf<_CharT, _Traits>::
515     seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode __mode)
516     {
517       pos_type __ret =  pos_type(off_type(-1)); 
518       bool __testopen = this->is_open();
519       bool __testin = __mode & ios_base::in && _M_mode & ios_base::in;
520       bool __testout = __mode & ios_base::out && _M_mode & ios_base::out;
522       // Should probably do has_facet checks here.
523       int __width = use_facet<__codecvt_type>(_M_buf_locale).encoding();
524       if (__width < 0)
525         __width = 0;
526       bool __testfail = __off != 0  && __width <= 0;
527       
528       if (__testopen && !__testfail && (__testin || __testout))
529         {
530           // Ditch any pback buffers to avoid confusion.
531           _M_pback_destroy();
533           if (__way != ios_base::cur || __off != 0)
534             { 
535               off_type __computed_off = __width * __off;
536               
537               bool __testget = _M_in_cur && _M_in_beg < _M_in_end;
538               bool __testput = _M_out_cur && _M_out_beg < _M_out_end;
539               // Sync the internal and external streams.
540               // out
541               if (__testput || _M_last_overflowed)
542                 {
543                   // Part one: update the output sequence.
544                   this->sync();
545                   // Part two: output unshift sequence.
546                   _M_output_unshift();
547                 }
548               //in
549               // NB: underflow() rewinds the external buffer.
550               else if (__testget && __way == ios_base::cur)
551                 __computed_off += _M_in_cur - _M_in_beg;
552           
553               __ret = _M_file->seekoff(__computed_off, __way, __mode);
554               _M_set_indeterminate();
555             }
556           // NB: Need to do this in case _M_file in indeterminate
557           // state, ie _M_file->_offset == -1
558           else
559             {
560               __ret = _M_file->seekoff(__off, ios_base::cur, __mode);
561               __ret += max(_M_out_cur, _M_in_cur) - _M_buf;
562             }
563         }
564       _M_last_overflowed = false;       
565       return __ret;
566     }
568   template<typename _CharT, typename _Traits>
569     typename basic_filebuf<_CharT, _Traits>::pos_type
570     basic_filebuf<_CharT, _Traits>::
571     seekpos(pos_type __pos, ios_base::openmode __mode)
572     {
573       pos_type __ret;
574       off_type __off = __pos;
576       __ret = this->seekoff(__off, ios_base::beg, __mode); 
578       _M_last_overflowed = false;       
579       return __ret;
580     }
582   template<typename _CharT, typename _Traits>
583     void 
584     basic_filebuf<_CharT, _Traits>::
585     _M_output_unshift()
586     { }
588   template<typename _CharT, typename _Traits>
589     void
590     basic_filebuf<_CharT, _Traits>::
591     imbue(const locale& __loc)
592     {
593       bool __testbeg = gptr() == eback() && pptr() == pbase();
595       if (__testbeg && _M_buf_locale != __loc)
596         {
597           _M_buf_locale = __loc;
598           _M_buf_locale_init = true;
599         }
601       // NB this may require the reconversion of previously
602       // converted chars. This in turn may cause the reconstruction
603       // of the original file. YIKES!!
604       // XXX The part in the above comment is not done.
605       _M_last_overflowed = false;       
606     }
607   
608 } // namespace std
610 #endif // _CPP_BITS_FSTREAM_TCC