1 // File based streams -*- C++ -*-
3 // Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
5 // Free Software Foundation, Inc.
7 // This file is part of the GNU ISO C++ Library. This library is free
8 // software; you can redistribute it and/or modify it under the
9 // terms of the GNU General Public License as published by the
10 // Free Software Foundation; either version 2, or (at your option)
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
18 // You should have received a copy of the GNU General Public License along
19 // with this library; see the file COPYING. If not, write to the Free
20 // Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
23 // As a special exception, you may use this file as part of a free software
24 // library without restriction. Specifically, if other files instantiate
25 // templates or use macros or inline functions from this file, or you compile
26 // this file and link it with other files to produce an executable, this
27 // file does not by itself cause the resulting executable to be covered by
28 // the GNU General Public License. This exception does not however
29 // invalidate any other reasons why the executable file might be covered by
30 // the GNU General Public License.
33 * This is an internal header file, included by other library headers.
34 * You should not attempt to use it directly.
38 // ISO C++ 14882: 27.8 File-based streams
42 #define _FSTREAM_TCC 1
44 #pragma GCC system_header
46 #include <cxxabi-forced.h>
48 _GLIBCXX_BEGIN_NAMESPACE(std)
50 template<typename _CharT, typename _Traits>
52 basic_filebuf<_CharT, _Traits>::
53 _M_allocate_internal_buffer()
55 // Allocate internal buffer only if one doesn't already exist
56 // (either allocated or provided by the user via setbuf).
57 if (!_M_buf_allocated && !_M_buf)
59 _M_buf = new char_type[_M_buf_size];
60 _M_buf_allocated = true;
64 template<typename _CharT, typename _Traits>
66 basic_filebuf<_CharT, _Traits>::
67 _M_destroy_internal_buffer() throw()
73 _M_buf_allocated = false;
82 template<typename _CharT, typename _Traits>
83 basic_filebuf<_CharT, _Traits>::
84 basic_filebuf() : __streambuf_type(), _M_lock(), _M_file(&_M_lock),
85 _M_mode(ios_base::openmode(0)), _M_state_beg(), _M_state_cur(),
86 _M_state_last(), _M_buf(NULL), _M_buf_size(BUFSIZ),
87 _M_buf_allocated(false), _M_reading(false), _M_writing(false), _M_pback(),
88 _M_pback_cur_save(0), _M_pback_end_save(0), _M_pback_init(false),
89 _M_codecvt(0), _M_ext_buf(0), _M_ext_buf_size(0), _M_ext_next(0),
92 if (has_facet<__codecvt_type>(this->_M_buf_locale))
93 _M_codecvt = &use_facet<__codecvt_type>(this->_M_buf_locale);
96 template<typename _CharT, typename _Traits>
97 typename basic_filebuf<_CharT, _Traits>::__filebuf_type*
98 basic_filebuf<_CharT, _Traits>::
99 open(const char* __s, ios_base::openmode __mode)
101 __filebuf_type *__ret = NULL;
102 if (!this->is_open())
104 _M_file.open(__s, __mode);
107 _M_allocate_internal_buffer();
110 // Setup initial buffer to 'uncommitted' mode.
115 // Reset to initial state.
116 _M_state_last = _M_state_cur = _M_state_beg;
119 if ((__mode & ios_base::ate)
120 && this->seekoff(0, ios_base::end, __mode)
121 == pos_type(off_type(-1)))
130 template<typename _CharT, typename _Traits>
131 typename basic_filebuf<_CharT, _Traits>::__filebuf_type*
132 basic_filebuf<_CharT, _Traits>::
135 if (!this->is_open())
138 bool __testfail = false;
140 // NB: Do this here so that re-opened filebufs will be cool...
141 struct __close_sentry
144 __close_sentry (basic_filebuf *__fbi): __fb(__fbi) { }
147 __fb->_M_mode = ios_base::openmode(0);
148 __fb->_M_pback_init = false;
149 __fb->_M_destroy_internal_buffer();
150 __fb->_M_reading = false;
151 __fb->_M_writing = false;
152 __fb->_M_set_buffer(-1);
153 __fb->_M_state_last = __fb->_M_state_cur = __fb->_M_state_beg;
159 if (!_M_terminate_output())
162 catch(__cxxabiv1::__forced_unwind&)
165 __throw_exception_again;
168 { __testfail = true; }
171 if (!_M_file.close())
180 template<typename _CharT, typename _Traits>
182 basic_filebuf<_CharT, _Traits>::
185 streamsize __ret = -1;
186 const bool __testin = _M_mode & ios_base::in;
187 if (__testin && this->is_open())
189 // For a stateful encoding (-1) the pending sequence might be just
190 // shift and unshift prefixes with no actual character.
191 __ret = this->egptr() - this->gptr();
193 #if _GLIBCXX_HAVE_DOS_BASED_FILESYSTEM
194 // About this workaround, see libstdc++/20806.
195 const bool __testbinary = _M_mode & ios_base::binary;
196 if (__check_facet(_M_codecvt).encoding() >= 0
199 if (__check_facet(_M_codecvt).encoding() >= 0)
201 __ret += _M_file.showmanyc() / _M_codecvt->max_length();
206 template<typename _CharT, typename _Traits>
207 typename basic_filebuf<_CharT, _Traits>::int_type
208 basic_filebuf<_CharT, _Traits>::
211 int_type __ret = traits_type::eof();
212 const bool __testin = _M_mode & ios_base::in;
213 if (__testin && !_M_writing)
215 // Check for pback madness, and if so swich back to the
216 // normal buffers and jet outta here before expensive
220 if (this->gptr() < this->egptr())
221 return traits_type::to_int_type(*this->gptr());
223 // Get and convert input sequence.
224 const size_t __buflen = _M_buf_size > 1 ? _M_buf_size - 1 : 1;
226 // Will be set to true if ::read() returns 0 indicating EOF.
227 bool __got_eof = false;
228 // Number of internal characters produced.
229 streamsize __ilen = 0;
230 codecvt_base::result __r = codecvt_base::ok;
231 if (__check_facet(_M_codecvt).always_noconv())
233 __ilen = _M_file.xsgetn(reinterpret_cast<char*>(this->eback()),
240 // Worst-case number of external bytes.
241 // XXX Not done encoding() == -1.
242 const int __enc = _M_codecvt->encoding();
243 streamsize __blen; // Minimum buffer size.
244 streamsize __rlen; // Number of chars to read.
246 __blen = __rlen = __buflen * __enc;
249 __blen = __buflen + _M_codecvt->max_length() - 1;
252 const streamsize __remainder = _M_ext_end - _M_ext_next;
253 __rlen = __rlen > __remainder ? __rlen - __remainder : 0;
255 // An imbue in 'read' mode implies first converting the external
256 // chars already present.
257 if (_M_reading && this->egptr() == this->eback() && __remainder)
260 // Allocate buffer if necessary and move unconverted
262 if (_M_ext_buf_size < __blen)
264 char* __buf = new char[__blen];
266 std::memcpy(__buf, _M_ext_next, __remainder);
268 delete [] _M_ext_buf;
270 _M_ext_buf_size = __blen;
272 else if (__remainder)
273 std::memmove(_M_ext_buf, _M_ext_next, __remainder);
275 _M_ext_next = _M_ext_buf;
276 _M_ext_end = _M_ext_buf + __remainder;
277 _M_state_last = _M_state_cur;
284 // This may fail if the return value of
285 // codecvt::max_length() is bogus.
286 if (_M_ext_end - _M_ext_buf + __rlen > _M_ext_buf_size)
288 __throw_ios_failure(__N("basic_filebuf::underflow "
289 "codecvt::max_length() "
292 streamsize __elen = _M_file.xsgetn(_M_ext_end, __rlen);
295 else if (__elen == -1)
297 _M_ext_end += __elen;
300 char_type* __iend = this->eback();
301 if (_M_ext_next < _M_ext_end)
302 __r = _M_codecvt->in(_M_state_cur, _M_ext_next,
303 _M_ext_end, _M_ext_next,
305 this->eback() + __buflen, __iend);
306 if (__r == codecvt_base::noconv)
308 size_t __avail = _M_ext_end - _M_ext_buf;
309 __ilen = std::min(__avail, __buflen);
310 traits_type::copy(this->eback(),
311 reinterpret_cast<char_type*>
312 (_M_ext_buf), __ilen);
313 _M_ext_next = _M_ext_buf + __ilen;
316 __ilen = __iend - this->eback();
318 // _M_codecvt->in may return error while __ilen > 0: this is
319 // ok, and actually occurs in case of mixed encodings (e.g.,
321 if (__r == codecvt_base::error)
326 while (__ilen == 0 && !__got_eof);
331 _M_set_buffer(__ilen);
333 __ret = traits_type::to_int_type(*this->gptr());
337 // If the actual end of file is reached, set 'uncommitted'
338 // mode, thus allowing an immediate write without an
342 // However, reaching it while looping on partial means that
343 // the file has got an incomplete character.
344 if (__r == codecvt_base::partial)
345 __throw_ios_failure(__N("basic_filebuf::underflow "
346 "incomplete character in file"));
348 else if (__r == codecvt_base::error)
349 __throw_ios_failure(__N("basic_filebuf::underflow "
350 "invalid byte sequence in file"));
352 __throw_ios_failure(__N("basic_filebuf::underflow "
353 "error reading the file"));
358 template<typename _CharT, typename _Traits>
359 typename basic_filebuf<_CharT, _Traits>::int_type
360 basic_filebuf<_CharT, _Traits>::
361 pbackfail(int_type __i)
363 int_type __ret = traits_type::eof();
364 const bool __testin = _M_mode & ios_base::in;
365 if (__testin && !_M_writing)
367 // Remember whether the pback buffer is active, otherwise below
368 // we may try to store in it a second char (libstdc++/9761).
369 const bool __testpb = _M_pback_init;
370 const bool __testeof = traits_type::eq_int_type(__i, __ret);
372 if (this->eback() < this->gptr())
375 __tmp = traits_type::to_int_type(*this->gptr());
377 else if (this->seekoff(-1, ios_base::cur) != pos_type(off_type(-1)))
379 __tmp = this->underflow();
380 if (traits_type::eq_int_type(__tmp, __ret))
385 // At the beginning of the buffer, need to make a
386 // putback position available. But the seek may fail
387 // (f.i., at the beginning of a file, see
388 // libstdc++/9439) and in that case we return
389 // traits_type::eof().
393 // Try to put back __i into input sequence in one of three ways.
394 // Order these tests done in is unspecified by the standard.
395 if (!__testeof && traits_type::eq_int_type(__i, __tmp))
398 __ret = traits_type::not_eof(__i);
403 *this->gptr() = traits_type::to_char_type(__i);
410 template<typename _CharT, typename _Traits>
411 typename basic_filebuf<_CharT, _Traits>::int_type
412 basic_filebuf<_CharT, _Traits>::
413 overflow(int_type __c)
415 int_type __ret = traits_type::eof();
416 const bool __testeof = traits_type::eq_int_type(__c, __ret);
417 const bool __testout = _M_mode & ios_base::out;
418 if (__testout && !_M_reading)
420 if (this->pbase() < this->pptr())
422 // If appropriate, append the overflow char.
425 *this->pptr() = traits_type::to_char_type(__c);
429 // Convert pending sequence to external representation,
431 if (_M_convert_to_external(this->pbase(),
432 this->pptr() - this->pbase()))
435 __ret = traits_type::not_eof(__c);
438 else if (_M_buf_size > 1)
440 // Overflow in 'uncommitted' mode: set _M_writing, set
441 // the buffer to the initial 'write' mode, and put __c
447 *this->pptr() = traits_type::to_char_type(__c);
450 __ret = traits_type::not_eof(__c);
455 char_type __conv = traits_type::to_char_type(__c);
456 if (__testeof || _M_convert_to_external(&__conv, 1))
459 __ret = traits_type::not_eof(__c);
466 template<typename _CharT, typename _Traits>
468 basic_filebuf<_CharT, _Traits>::
469 _M_convert_to_external(_CharT* __ibuf, streamsize __ilen)
471 // Sizes of external and pending output.
474 if (__check_facet(_M_codecvt).always_noconv())
476 __elen = _M_file.xsputn(reinterpret_cast<char*>(__ibuf), __ilen);
481 // Worst-case number of external bytes needed.
482 // XXX Not done encoding() == -1.
483 streamsize __blen = __ilen * _M_codecvt->max_length();
484 char* __buf = static_cast<char*>(__builtin_alloca(__blen));
487 const char_type* __iend;
488 codecvt_base::result __r;
489 __r = _M_codecvt->out(_M_state_cur, __ibuf, __ibuf + __ilen,
490 __iend, __buf, __buf + __blen, __bend);
492 if (__r == codecvt_base::ok || __r == codecvt_base::partial)
493 __blen = __bend - __buf;
494 else if (__r == codecvt_base::noconv)
496 // Same as the always_noconv case above.
497 __buf = reinterpret_cast<char*>(__ibuf);
501 __throw_ios_failure(__N("basic_filebuf::_M_convert_to_external "
502 "conversion error"));
504 __elen = _M_file.xsputn(__buf, __blen);
507 // Try once more for partial conversions.
508 if (__r == codecvt_base::partial && __elen == __plen)
510 const char_type* __iresume = __iend;
511 streamsize __rlen = this->pptr() - __iend;
512 __r = _M_codecvt->out(_M_state_cur, __iresume,
513 __iresume + __rlen, __iend, __buf,
514 __buf + __blen, __bend);
515 if (__r != codecvt_base::error)
517 __rlen = __bend - __buf;
518 __elen = _M_file.xsputn(__buf, __rlen);
522 __throw_ios_failure(__N("basic_filebuf::_M_convert_to_external "
523 "conversion error"));
526 return __elen == __plen;
529 template<typename _CharT, typename _Traits>
531 basic_filebuf<_CharT, _Traits>::
532 xsgetn(_CharT* __s, streamsize __n)
534 // Clear out pback buffer before going on to the real deal...
535 streamsize __ret = 0;
538 if (__n > 0 && this->gptr() == this->eback())
540 *__s++ = *this->gptr();
548 // Optimization in the always_noconv() case, to be generalized in the
549 // future: when __n > __buflen we read directly instead of using the
550 // buffer repeatedly.
551 const bool __testin = _M_mode & ios_base::in;
552 const streamsize __buflen = _M_buf_size > 1 ? _M_buf_size - 1 : 1;
554 if (__n > __buflen && __check_facet(_M_codecvt).always_noconv()
555 && __testin && !_M_writing)
557 // First, copy the chars already present in the buffer.
558 const streamsize __avail = this->egptr() - this->gptr();
562 *__s = *this->gptr();
564 traits_type::copy(__s, this->gptr(), __avail);
566 this->gbump(__avail);
571 // Need to loop in case of short reads (relatively common
576 __len = _M_file.xsgetn(reinterpret_cast<char*>(__s),
579 __throw_ios_failure(__N("basic_filebuf::xsgetn "
580 "error reading the file"));
599 // If end of file is reached, set 'uncommitted'
600 // mode, thus allowing an immediate write without
601 // an intervening seek.
607 __ret += __streambuf_type::xsgetn(__s, __n);
612 template<typename _CharT, typename _Traits>
614 basic_filebuf<_CharT, _Traits>::
615 xsputn(const _CharT* __s, streamsize __n)
617 // Optimization in the always_noconv() case, to be generalized in the
618 // future: when __n is sufficiently large we write directly instead of
620 streamsize __ret = 0;
621 const bool __testout = _M_mode & ios_base::out;
622 if (__check_facet(_M_codecvt).always_noconv()
623 && __testout && !_M_reading)
625 // Measurement would reveal the best choice.
626 const streamsize __chunk = 1ul << 10;
627 streamsize __bufavail = this->epptr() - this->pptr();
629 // Don't mistake 'uncommitted' mode buffered with unbuffered.
630 if (!_M_writing && _M_buf_size > 1)
631 __bufavail = _M_buf_size - 1;
633 const streamsize __limit = std::min(__chunk, __bufavail);
636 const streamsize __buffill = this->pptr() - this->pbase();
637 const char* __buf = reinterpret_cast<const char*>(this->pbase());
638 __ret = _M_file.xsputn_2(__buf, __buffill,
639 reinterpret_cast<const char*>(__s),
641 if (__ret == __buffill + __n)
646 if (__ret > __buffill)
652 __ret = __streambuf_type::xsputn(__s, __n);
655 __ret = __streambuf_type::xsputn(__s, __n);
659 template<typename _CharT, typename _Traits>
660 typename basic_filebuf<_CharT, _Traits>::__streambuf_type*
661 basic_filebuf<_CharT, _Traits>::
662 setbuf(char_type* __s, streamsize __n)
664 if (!this->is_open())
665 if (__s == 0 && __n == 0)
667 else if (__s && __n > 0)
669 // This is implementation-defined behavior, and assumes that
670 // an external char_type array of length __n exists and has
671 // been pre-allocated. If this is not the case, things will
672 // quickly blow up. When __n > 1, __n - 1 positions will be
673 // used for the get area, __n - 1 for the put area and 1
674 // position to host the overflow char of a full put area.
675 // When __n == 1, 1 position will be used for the get area
676 // and 0 for the put area, as in the unbuffered case above.
684 // According to 27.8.1.4 p11 - 13, seekoff should ignore the last
685 // argument (of type openmode).
686 template<typename _CharT, typename _Traits>
687 typename basic_filebuf<_CharT, _Traits>::pos_type
688 basic_filebuf<_CharT, _Traits>::
689 seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode)
693 __width = _M_codecvt->encoding();
697 pos_type __ret = pos_type(off_type(-1));
698 const bool __testfail = __off != 0 && __width <= 0;
699 if (this->is_open() && !__testfail)
701 // Ditch any pback buffers to avoid confusion.
704 // Correct state at destination. Note that this is the correct
705 // state for the current position during output, because
706 // codecvt::unshift() returns the state to the initial state.
707 // This is also the correct state at the end of the file because
708 // an unshift sequence should have been written at the end.
709 __state_type __state = _M_state_beg;
710 off_type __computed_off = __off * __width;
711 if (_M_reading && __way == ios_base::cur)
713 if (_M_codecvt->always_noconv())
714 __computed_off += this->gptr() - this->egptr();
717 // Calculate offset from _M_ext_buf that corresponds
718 // to gptr(). Note: uses _M_state_last, which
719 // corresponds to eback().
720 const int __gptr_off =
721 _M_codecvt->length(_M_state_last, _M_ext_buf, _M_ext_next,
722 this->gptr() - this->eback());
723 __computed_off += _M_ext_buf + __gptr_off - _M_ext_end;
725 // _M_state_last is modified by codecvt::length() so
726 // it now corresponds to gptr().
727 __state = _M_state_last;
730 __ret = _M_seek(__computed_off, __way, __state);
735 // _GLIBCXX_RESOLVE_LIB_DEFECTS
736 // 171. Strange seekpos() semantics due to joint position
737 // According to the resolution of DR 171, seekpos should ignore the last
738 // argument (of type openmode).
739 template<typename _CharT, typename _Traits>
740 typename basic_filebuf<_CharT, _Traits>::pos_type
741 basic_filebuf<_CharT, _Traits>::
742 seekpos(pos_type __pos, ios_base::openmode)
744 pos_type __ret = pos_type(off_type(-1));
747 // Ditch any pback buffers to avoid confusion.
749 __ret = _M_seek(off_type(__pos), ios_base::beg, __pos.state());
754 template<typename _CharT, typename _Traits>
755 typename basic_filebuf<_CharT, _Traits>::pos_type
756 basic_filebuf<_CharT, _Traits>::
757 _M_seek(off_type __off, ios_base::seekdir __way, __state_type __state)
759 pos_type __ret = pos_type(off_type(-1));
760 if (_M_terminate_output())
762 // Returns pos_type(off_type(-1)) in case of failure.
763 __ret = pos_type(_M_file.seekoff(__off, __way));
764 if (__ret != pos_type(off_type(-1)))
768 _M_ext_next = _M_ext_end = _M_ext_buf;
770 _M_state_cur = __state;
771 __ret.state(_M_state_cur);
777 template<typename _CharT, typename _Traits>
779 basic_filebuf<_CharT, _Traits>::
780 _M_terminate_output()
782 // Part one: update the output sequence.
783 bool __testvalid = true;
784 if (this->pbase() < this->pptr())
786 const int_type __tmp = this->overflow();
787 if (traits_type::eq_int_type(__tmp, traits_type::eof()))
791 // Part two: output unshift sequence.
792 if (_M_writing && !__check_facet(_M_codecvt).always_noconv()
795 // Note: this value is arbitrary, since there is no way to
796 // get the length of the unshift sequence from codecvt,
797 // without calling unshift.
798 const size_t __blen = 128;
800 codecvt_base::result __r;
801 streamsize __ilen = 0;
806 __r = _M_codecvt->unshift(_M_state_cur, __buf,
807 __buf + __blen, __next);
808 if (__r == codecvt_base::error)
810 else if (__r == codecvt_base::ok ||
811 __r == codecvt_base::partial)
813 __ilen = __next - __buf;
816 const streamsize __elen = _M_file.xsputn(__buf, __ilen);
817 if (__elen != __ilen)
822 while (__r == codecvt_base::partial && __ilen > 0 && __testvalid);
826 // This second call to overflow() is required by the standard,
827 // but it's not clear why it's needed, since the output buffer
828 // should be empty by this point (it should have been emptied
829 // in the first call to overflow()).
830 const int_type __tmp = this->overflow();
831 if (traits_type::eq_int_type(__tmp, traits_type::eof()))
838 template<typename _CharT, typename _Traits>
840 basic_filebuf<_CharT, _Traits>::
843 // Make sure that the internal buffer resyncs its idea of
844 // the file position with the external file.
846 if (this->pbase() < this->pptr())
848 const int_type __tmp = this->overflow();
849 if (traits_type::eq_int_type(__tmp, traits_type::eof()))
855 template<typename _CharT, typename _Traits>
857 basic_filebuf<_CharT, _Traits>::
858 imbue(const locale& __loc)
860 bool __testvalid = true;
862 const __codecvt_type* _M_codecvt_tmp = 0;
863 if (__builtin_expect(has_facet<__codecvt_type>(__loc), true))
864 _M_codecvt_tmp = &use_facet<__codecvt_type>(__loc);
868 // encoding() == -1 is ok only at the beginning.
869 if ((_M_reading || _M_writing)
870 && __check_facet(_M_codecvt).encoding() == -1)
876 if (__check_facet(_M_codecvt).always_noconv())
879 && !__check_facet(_M_codecvt_tmp).always_noconv())
880 __testvalid = this->seekoff(0, ios_base::cur, _M_mode)
881 != pos_type(off_type(-1));
885 // External position corresponding to gptr().
886 _M_ext_next = _M_ext_buf
887 + _M_codecvt->length(_M_state_last, _M_ext_buf, _M_ext_next,
888 this->gptr() - this->eback());
889 const streamsize __remainder = _M_ext_end - _M_ext_next;
891 std::memmove(_M_ext_buf, _M_ext_next, __remainder);
893 _M_ext_next = _M_ext_buf;
894 _M_ext_end = _M_ext_buf + __remainder;
896 _M_state_last = _M_state_cur = _M_state_beg;
899 else if (_M_writing && (__testvalid = _M_terminate_output()))
905 _M_codecvt = _M_codecvt_tmp;
910 // Inhibit implicit instantiations for required instantiations,
911 // which are defined via explicit instantiations elsewhere.
912 // NB: This syntax is a GNU extension.
913 #if _GLIBCXX_EXTERN_TEMPLATE
914 extern template class basic_filebuf<char>;
915 extern template class basic_ifstream<char>;
916 extern template class basic_ofstream<char>;
917 extern template class basic_fstream<char>;
919 #ifdef _GLIBCXX_USE_WCHAR_T
920 extern template class basic_filebuf<wchar_t>;
921 extern template class basic_ifstream<wchar_t>;
922 extern template class basic_ofstream<wchar_t>;
923 extern template class basic_fstream<wchar_t>;
927 _GLIBCXX_END_NAMESPACE