1*404b540aSrobert // File based streams -*- C++ -*-
2*404b540aSrobert
3*404b540aSrobert // Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
4*404b540aSrobert // Free Software Foundation, Inc.
5*404b540aSrobert //
6*404b540aSrobert // This file is part of the GNU ISO C++ Library. This library is free
7*404b540aSrobert // software; you can redistribute it and/or modify it under the
8*404b540aSrobert // terms of the GNU General Public License as published by the
9*404b540aSrobert // Free Software Foundation; either version 2, or (at your option)
10*404b540aSrobert // any later version.
11*404b540aSrobert
12*404b540aSrobert // This library is distributed in the hope that it will be useful,
13*404b540aSrobert // but WITHOUT ANY WARRANTY; without even the implied warranty of
14*404b540aSrobert // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15*404b540aSrobert // GNU General Public License for more details.
16*404b540aSrobert
17*404b540aSrobert // You should have received a copy of the GNU General Public License along
18*404b540aSrobert // with this library; see the file COPYING. If not, write to the Free
19*404b540aSrobert // Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
20*404b540aSrobert // USA.
21*404b540aSrobert
22*404b540aSrobert // As a special exception, you may use this file as part of a free software
23*404b540aSrobert // library without restriction. Specifically, if other files instantiate
24*404b540aSrobert // templates or use macros or inline functions from this file, or you compile
25*404b540aSrobert // this file and link it with other files to produce an executable, this
26*404b540aSrobert // file does not by itself cause the resulting executable to be covered by
27*404b540aSrobert // the GNU General Public License. This exception does not however
28*404b540aSrobert // invalidate any other reasons why the executable file might be covered by
29*404b540aSrobert // the GNU General Public License.
30*404b540aSrobert
31*404b540aSrobert /** @file fstream.tcc
32*404b540aSrobert * This is an internal header file, included by other library headers.
33*404b540aSrobert * You should not attempt to use it directly.
34*404b540aSrobert */
35*404b540aSrobert
36*404b540aSrobert //
37*404b540aSrobert // ISO C++ 14882: 27.8 File-based streams
38*404b540aSrobert //
39*404b540aSrobert
40*404b540aSrobert #ifndef _FSTREAM_TCC
41*404b540aSrobert #define _FSTREAM_TCC 1
42*404b540aSrobert
43*404b540aSrobert #pragma GCC system_header
44*404b540aSrobert
_GLIBCXX_BEGIN_NAMESPACE(std)45*404b540aSrobert _GLIBCXX_BEGIN_NAMESPACE(std)
46*404b540aSrobert
47*404b540aSrobert template<typename _CharT, typename _Traits>
48*404b540aSrobert void
49*404b540aSrobert basic_filebuf<_CharT, _Traits>::
50*404b540aSrobert _M_allocate_internal_buffer()
51*404b540aSrobert {
52*404b540aSrobert // Allocate internal buffer only if one doesn't already exist
53*404b540aSrobert // (either allocated or provided by the user via setbuf).
54*404b540aSrobert if (!_M_buf_allocated && !_M_buf)
55*404b540aSrobert {
56*404b540aSrobert _M_buf = new char_type[_M_buf_size];
57*404b540aSrobert _M_buf_allocated = true;
58*404b540aSrobert }
59*404b540aSrobert }
60*404b540aSrobert
61*404b540aSrobert template<typename _CharT, typename _Traits>
62*404b540aSrobert void
63*404b540aSrobert basic_filebuf<_CharT, _Traits>::
_M_destroy_internal_buffer()64*404b540aSrobert _M_destroy_internal_buffer() throw()
65*404b540aSrobert {
66*404b540aSrobert if (_M_buf_allocated)
67*404b540aSrobert {
68*404b540aSrobert delete [] _M_buf;
69*404b540aSrobert _M_buf = NULL;
70*404b540aSrobert _M_buf_allocated = false;
71*404b540aSrobert }
72*404b540aSrobert delete [] _M_ext_buf;
73*404b540aSrobert _M_ext_buf = NULL;
74*404b540aSrobert _M_ext_buf_size = 0;
75*404b540aSrobert _M_ext_next = NULL;
76*404b540aSrobert _M_ext_end = NULL;
77*404b540aSrobert }
78*404b540aSrobert
79*404b540aSrobert template<typename _CharT, typename _Traits>
80*404b540aSrobert basic_filebuf<_CharT, _Traits>::
basic_filebuf()81*404b540aSrobert basic_filebuf() : __streambuf_type(), _M_lock(), _M_file(&_M_lock),
82*404b540aSrobert _M_mode(ios_base::openmode(0)), _M_state_beg(), _M_state_cur(),
83*404b540aSrobert _M_state_last(), _M_buf(NULL), _M_buf_size(BUFSIZ),
84*404b540aSrobert _M_buf_allocated(false), _M_reading(false), _M_writing(false), _M_pback(),
85*404b540aSrobert _M_pback_cur_save(0), _M_pback_end_save(0), _M_pback_init(false),
86*404b540aSrobert _M_codecvt(0), _M_ext_buf(0), _M_ext_buf_size(0), _M_ext_next(0),
87*404b540aSrobert _M_ext_end(0)
88*404b540aSrobert {
89*404b540aSrobert if (has_facet<__codecvt_type>(this->_M_buf_locale))
90*404b540aSrobert _M_codecvt = &use_facet<__codecvt_type>(this->_M_buf_locale);
91*404b540aSrobert }
92*404b540aSrobert
93*404b540aSrobert template<typename _CharT, typename _Traits>
94*404b540aSrobert typename basic_filebuf<_CharT, _Traits>::__filebuf_type*
95*404b540aSrobert basic_filebuf<_CharT, _Traits>::
open(const char * __s,ios_base::openmode __mode)96*404b540aSrobert open(const char* __s, ios_base::openmode __mode)
97*404b540aSrobert {
98*404b540aSrobert __filebuf_type *__ret = NULL;
99*404b540aSrobert if (!this->is_open())
100*404b540aSrobert {
101*404b540aSrobert _M_file.open(__s, __mode);
102*404b540aSrobert if (this->is_open())
103*404b540aSrobert {
104*404b540aSrobert _M_allocate_internal_buffer();
105*404b540aSrobert _M_mode = __mode;
106*404b540aSrobert
107*404b540aSrobert // Setup initial buffer to 'uncommitted' mode.
108*404b540aSrobert _M_reading = false;
109*404b540aSrobert _M_writing = false;
110*404b540aSrobert _M_set_buffer(-1);
111*404b540aSrobert
112*404b540aSrobert // Reset to initial state.
113*404b540aSrobert _M_state_last = _M_state_cur = _M_state_beg;
114*404b540aSrobert
115*404b540aSrobert // 27.8.1.3,4
116*404b540aSrobert if ((__mode & ios_base::ate)
117*404b540aSrobert && this->seekoff(0, ios_base::end, __mode)
118*404b540aSrobert == pos_type(off_type(-1)))
119*404b540aSrobert this->close();
120*404b540aSrobert else
121*404b540aSrobert __ret = this;
122*404b540aSrobert }
123*404b540aSrobert }
124*404b540aSrobert return __ret;
125*404b540aSrobert }
126*404b540aSrobert
127*404b540aSrobert template<typename _CharT, typename _Traits>
128*404b540aSrobert typename basic_filebuf<_CharT, _Traits>::__filebuf_type*
129*404b540aSrobert basic_filebuf<_CharT, _Traits>::
close()130*404b540aSrobert close() throw()
131*404b540aSrobert {
132*404b540aSrobert __filebuf_type* __ret = NULL;
133*404b540aSrobert if (this->is_open())
134*404b540aSrobert {
135*404b540aSrobert bool __testfail = false;
136*404b540aSrobert try
137*404b540aSrobert {
138*404b540aSrobert if (!_M_terminate_output())
139*404b540aSrobert __testfail = true;
140*404b540aSrobert }
141*404b540aSrobert catch(...)
142*404b540aSrobert { __testfail = true; }
143*404b540aSrobert
144*404b540aSrobert // NB: Do this here so that re-opened filebufs will be cool...
145*404b540aSrobert _M_mode = ios_base::openmode(0);
146*404b540aSrobert _M_pback_init = false;
147*404b540aSrobert _M_destroy_internal_buffer();
148*404b540aSrobert _M_reading = false;
149*404b540aSrobert _M_writing = false;
150*404b540aSrobert _M_set_buffer(-1);
151*404b540aSrobert _M_state_last = _M_state_cur = _M_state_beg;
152*404b540aSrobert
153*404b540aSrobert if (!_M_file.close())
154*404b540aSrobert __testfail = true;
155*404b540aSrobert
156*404b540aSrobert if (!__testfail)
157*404b540aSrobert __ret = this;
158*404b540aSrobert }
159*404b540aSrobert return __ret;
160*404b540aSrobert }
161*404b540aSrobert
162*404b540aSrobert template<typename _CharT, typename _Traits>
163*404b540aSrobert streamsize
164*404b540aSrobert basic_filebuf<_CharT, _Traits>::
showmanyc()165*404b540aSrobert showmanyc()
166*404b540aSrobert {
167*404b540aSrobert streamsize __ret = -1;
168*404b540aSrobert const bool __testin = _M_mode & ios_base::in;
169*404b540aSrobert if (__testin && this->is_open())
170*404b540aSrobert {
171*404b540aSrobert // For a stateful encoding (-1) the pending sequence might be just
172*404b540aSrobert // shift and unshift prefixes with no actual character.
173*404b540aSrobert __ret = this->egptr() - this->gptr();
174*404b540aSrobert
175*404b540aSrobert #if _GLIBCXX_HAVE_DOS_BASED_FILESYSTEM
176*404b540aSrobert // About this workaround, see libstdc++/20806.
177*404b540aSrobert const bool __testbinary = _M_mode & ios_base::binary;
178*404b540aSrobert if (__check_facet(_M_codecvt).encoding() >= 0
179*404b540aSrobert && __testbinary)
180*404b540aSrobert #else
181*404b540aSrobert if (__check_facet(_M_codecvt).encoding() >= 0)
182*404b540aSrobert #endif
183*404b540aSrobert __ret += _M_file.showmanyc() / _M_codecvt->max_length();
184*404b540aSrobert }
185*404b540aSrobert return __ret;
186*404b540aSrobert }
187*404b540aSrobert
188*404b540aSrobert template<typename _CharT, typename _Traits>
189*404b540aSrobert typename basic_filebuf<_CharT, _Traits>::int_type
190*404b540aSrobert basic_filebuf<_CharT, _Traits>::
underflow()191*404b540aSrobert underflow()
192*404b540aSrobert {
193*404b540aSrobert int_type __ret = traits_type::eof();
194*404b540aSrobert const bool __testin = _M_mode & ios_base::in;
195*404b540aSrobert if (__testin && !_M_writing)
196*404b540aSrobert {
197*404b540aSrobert // Check for pback madness, and if so swich back to the
198*404b540aSrobert // normal buffers and jet outta here before expensive
199*404b540aSrobert // fileops happen...
200*404b540aSrobert _M_destroy_pback();
201*404b540aSrobert
202*404b540aSrobert if (this->gptr() < this->egptr())
203*404b540aSrobert return traits_type::to_int_type(*this->gptr());
204*404b540aSrobert
205*404b540aSrobert // Get and convert input sequence.
206*404b540aSrobert const size_t __buflen = _M_buf_size > 1 ? _M_buf_size - 1 : 1;
207*404b540aSrobert
208*404b540aSrobert // Will be set to true if ::read() returns 0 indicating EOF.
209*404b540aSrobert bool __got_eof = false;
210*404b540aSrobert // Number of internal characters produced.
211*404b540aSrobert streamsize __ilen = 0;
212*404b540aSrobert codecvt_base::result __r = codecvt_base::ok;
213*404b540aSrobert if (__check_facet(_M_codecvt).always_noconv())
214*404b540aSrobert {
215*404b540aSrobert __ilen = _M_file.xsgetn(reinterpret_cast<char*>(this->eback()),
216*404b540aSrobert __buflen);
217*404b540aSrobert if (__ilen == 0)
218*404b540aSrobert __got_eof = true;
219*404b540aSrobert }
220*404b540aSrobert else
221*404b540aSrobert {
222*404b540aSrobert // Worst-case number of external bytes.
223*404b540aSrobert // XXX Not done encoding() == -1.
224*404b540aSrobert const int __enc = _M_codecvt->encoding();
225*404b540aSrobert streamsize __blen; // Minimum buffer size.
226*404b540aSrobert streamsize __rlen; // Number of chars to read.
227*404b540aSrobert if (__enc > 0)
228*404b540aSrobert __blen = __rlen = __buflen * __enc;
229*404b540aSrobert else
230*404b540aSrobert {
231*404b540aSrobert __blen = __buflen + _M_codecvt->max_length() - 1;
232*404b540aSrobert __rlen = __buflen;
233*404b540aSrobert }
234*404b540aSrobert const streamsize __remainder = _M_ext_end - _M_ext_next;
235*404b540aSrobert __rlen = __rlen > __remainder ? __rlen - __remainder : 0;
236*404b540aSrobert
237*404b540aSrobert // An imbue in 'read' mode implies first converting the external
238*404b540aSrobert // chars already present.
239*404b540aSrobert if (_M_reading && this->egptr() == this->eback() && __remainder)
240*404b540aSrobert __rlen = 0;
241*404b540aSrobert
242*404b540aSrobert // Allocate buffer if necessary and move unconverted
243*404b540aSrobert // bytes to front.
244*404b540aSrobert if (_M_ext_buf_size < __blen)
245*404b540aSrobert {
246*404b540aSrobert char* __buf = new char[__blen];
247*404b540aSrobert if (__remainder)
248*404b540aSrobert std::memcpy(__buf, _M_ext_next, __remainder);
249*404b540aSrobert
250*404b540aSrobert delete [] _M_ext_buf;
251*404b540aSrobert _M_ext_buf = __buf;
252*404b540aSrobert _M_ext_buf_size = __blen;
253*404b540aSrobert }
254*404b540aSrobert else if (__remainder)
255*404b540aSrobert std::memmove(_M_ext_buf, _M_ext_next, __remainder);
256*404b540aSrobert
257*404b540aSrobert _M_ext_next = _M_ext_buf;
258*404b540aSrobert _M_ext_end = _M_ext_buf + __remainder;
259*404b540aSrobert _M_state_last = _M_state_cur;
260*404b540aSrobert
261*404b540aSrobert do
262*404b540aSrobert {
263*404b540aSrobert if (__rlen > 0)
264*404b540aSrobert {
265*404b540aSrobert // Sanity check!
266*404b540aSrobert // This may fail if the return value of
267*404b540aSrobert // codecvt::max_length() is bogus.
268*404b540aSrobert if (_M_ext_end - _M_ext_buf + __rlen > _M_ext_buf_size)
269*404b540aSrobert {
270*404b540aSrobert __throw_ios_failure(__N("basic_filebuf::underflow "
271*404b540aSrobert "codecvt::max_length() "
272*404b540aSrobert "is not valid"));
273*404b540aSrobert }
274*404b540aSrobert streamsize __elen = _M_file.xsgetn(_M_ext_end, __rlen);
275*404b540aSrobert if (__elen == 0)
276*404b540aSrobert __got_eof = true;
277*404b540aSrobert else if (__elen == -1)
278*404b540aSrobert break;
279*404b540aSrobert _M_ext_end += __elen;
280*404b540aSrobert }
281*404b540aSrobert
282*404b540aSrobert char_type* __iend;
283*404b540aSrobert __r = _M_codecvt->in(_M_state_cur, _M_ext_next,
284*404b540aSrobert _M_ext_end, _M_ext_next, this->eback(),
285*404b540aSrobert this->eback() + __buflen, __iend);
286*404b540aSrobert if (__r == codecvt_base::noconv)
287*404b540aSrobert {
288*404b540aSrobert size_t __avail = _M_ext_end - _M_ext_buf;
289*404b540aSrobert __ilen = std::min(__avail, __buflen);
290*404b540aSrobert traits_type::copy(this->eback(),
291*404b540aSrobert reinterpret_cast<char_type*>(_M_ext_buf), __ilen);
292*404b540aSrobert _M_ext_next = _M_ext_buf + __ilen;
293*404b540aSrobert }
294*404b540aSrobert else
295*404b540aSrobert __ilen = __iend - this->eback();
296*404b540aSrobert
297*404b540aSrobert // _M_codecvt->in may return error while __ilen > 0: this is
298*404b540aSrobert // ok, and actually occurs in case of mixed encodings (e.g.,
299*404b540aSrobert // XML files).
300*404b540aSrobert if (__r == codecvt_base::error)
301*404b540aSrobert break;
302*404b540aSrobert
303*404b540aSrobert __rlen = 1;
304*404b540aSrobert }
305*404b540aSrobert while (__ilen == 0 && !__got_eof);
306*404b540aSrobert }
307*404b540aSrobert
308*404b540aSrobert if (__ilen > 0)
309*404b540aSrobert {
310*404b540aSrobert _M_set_buffer(__ilen);
311*404b540aSrobert _M_reading = true;
312*404b540aSrobert __ret = traits_type::to_int_type(*this->gptr());
313*404b540aSrobert }
314*404b540aSrobert else if (__got_eof)
315*404b540aSrobert {
316*404b540aSrobert // If the actual end of file is reached, set 'uncommitted'
317*404b540aSrobert // mode, thus allowing an immediate write without an
318*404b540aSrobert // intervening seek.
319*404b540aSrobert _M_set_buffer(-1);
320*404b540aSrobert _M_reading = false;
321*404b540aSrobert // However, reaching it while looping on partial means that
322*404b540aSrobert // the file has got an incomplete character.
323*404b540aSrobert if (__r == codecvt_base::partial)
324*404b540aSrobert __throw_ios_failure(__N("basic_filebuf::underflow "
325*404b540aSrobert "incomplete character in file"));
326*404b540aSrobert }
327*404b540aSrobert else if (__r == codecvt_base::error)
328*404b540aSrobert __throw_ios_failure(__N("basic_filebuf::underflow "
329*404b540aSrobert "invalid byte sequence in file"));
330*404b540aSrobert else
331*404b540aSrobert __throw_ios_failure(__N("basic_filebuf::underflow "
332*404b540aSrobert "error reading the file"));
333*404b540aSrobert }
334*404b540aSrobert return __ret;
335*404b540aSrobert }
336*404b540aSrobert
337*404b540aSrobert template<typename _CharT, typename _Traits>
338*404b540aSrobert typename basic_filebuf<_CharT, _Traits>::int_type
339*404b540aSrobert basic_filebuf<_CharT, _Traits>::
pbackfail(int_type __i)340*404b540aSrobert pbackfail(int_type __i)
341*404b540aSrobert {
342*404b540aSrobert int_type __ret = traits_type::eof();
343*404b540aSrobert const bool __testin = _M_mode & ios_base::in;
344*404b540aSrobert if (__testin && !_M_writing)
345*404b540aSrobert {
346*404b540aSrobert // Remember whether the pback buffer is active, otherwise below
347*404b540aSrobert // we may try to store in it a second char (libstdc++/9761).
348*404b540aSrobert const bool __testpb = _M_pback_init;
349*404b540aSrobert const bool __testeof = traits_type::eq_int_type(__i, __ret);
350*404b540aSrobert int_type __tmp;
351*404b540aSrobert if (this->eback() < this->gptr())
352*404b540aSrobert {
353*404b540aSrobert this->gbump(-1);
354*404b540aSrobert __tmp = traits_type::to_int_type(*this->gptr());
355*404b540aSrobert }
356*404b540aSrobert else if (this->seekoff(-1, ios_base::cur) != pos_type(off_type(-1)))
357*404b540aSrobert {
358*404b540aSrobert __tmp = this->underflow();
359*404b540aSrobert if (traits_type::eq_int_type(__tmp, __ret))
360*404b540aSrobert return __ret;
361*404b540aSrobert }
362*404b540aSrobert else
363*404b540aSrobert {
364*404b540aSrobert // At the beginning of the buffer, need to make a
365*404b540aSrobert // putback position available. But the seek may fail
366*404b540aSrobert // (f.i., at the beginning of a file, see
367*404b540aSrobert // libstdc++/9439) and in that case we return
368*404b540aSrobert // traits_type::eof().
369*404b540aSrobert return __ret;
370*404b540aSrobert }
371*404b540aSrobert
372*404b540aSrobert // Try to put back __i into input sequence in one of three ways.
373*404b540aSrobert // Order these tests done in is unspecified by the standard.
374*404b540aSrobert if (!__testeof && traits_type::eq_int_type(__i, __tmp))
375*404b540aSrobert __ret = __i;
376*404b540aSrobert else if (__testeof)
377*404b540aSrobert __ret = traits_type::not_eof(__i);
378*404b540aSrobert else if (!__testpb)
379*404b540aSrobert {
380*404b540aSrobert _M_create_pback();
381*404b540aSrobert _M_reading = true;
382*404b540aSrobert *this->gptr() = traits_type::to_char_type(__i);
383*404b540aSrobert __ret = __i;
384*404b540aSrobert }
385*404b540aSrobert }
386*404b540aSrobert return __ret;
387*404b540aSrobert }
388*404b540aSrobert
389*404b540aSrobert template<typename _CharT, typename _Traits>
390*404b540aSrobert typename basic_filebuf<_CharT, _Traits>::int_type
391*404b540aSrobert basic_filebuf<_CharT, _Traits>::
overflow(int_type __c)392*404b540aSrobert overflow(int_type __c)
393*404b540aSrobert {
394*404b540aSrobert int_type __ret = traits_type::eof();
395*404b540aSrobert const bool __testeof = traits_type::eq_int_type(__c, __ret);
396*404b540aSrobert const bool __testout = _M_mode & ios_base::out;
397*404b540aSrobert if (__testout && !_M_reading)
398*404b540aSrobert {
399*404b540aSrobert if (this->pbase() < this->pptr())
400*404b540aSrobert {
401*404b540aSrobert // If appropriate, append the overflow char.
402*404b540aSrobert if (!__testeof)
403*404b540aSrobert {
404*404b540aSrobert *this->pptr() = traits_type::to_char_type(__c);
405*404b540aSrobert this->pbump(1);
406*404b540aSrobert }
407*404b540aSrobert
408*404b540aSrobert // Convert pending sequence to external representation,
409*404b540aSrobert // and output.
410*404b540aSrobert if (_M_convert_to_external(this->pbase(),
411*404b540aSrobert this->pptr() - this->pbase()))
412*404b540aSrobert {
413*404b540aSrobert _M_set_buffer(0);
414*404b540aSrobert __ret = traits_type::not_eof(__c);
415*404b540aSrobert }
416*404b540aSrobert }
417*404b540aSrobert else if (_M_buf_size > 1)
418*404b540aSrobert {
419*404b540aSrobert // Overflow in 'uncommitted' mode: set _M_writing, set
420*404b540aSrobert // the buffer to the initial 'write' mode, and put __c
421*404b540aSrobert // into the buffer.
422*404b540aSrobert _M_set_buffer(0);
423*404b540aSrobert _M_writing = true;
424*404b540aSrobert if (!__testeof)
425*404b540aSrobert {
426*404b540aSrobert *this->pptr() = traits_type::to_char_type(__c);
427*404b540aSrobert this->pbump(1);
428*404b540aSrobert }
429*404b540aSrobert __ret = traits_type::not_eof(__c);
430*404b540aSrobert }
431*404b540aSrobert else
432*404b540aSrobert {
433*404b540aSrobert // Unbuffered.
434*404b540aSrobert char_type __conv = traits_type::to_char_type(__c);
435*404b540aSrobert if (__testeof || _M_convert_to_external(&__conv, 1))
436*404b540aSrobert {
437*404b540aSrobert _M_writing = true;
438*404b540aSrobert __ret = traits_type::not_eof(__c);
439*404b540aSrobert }
440*404b540aSrobert }
441*404b540aSrobert }
442*404b540aSrobert return __ret;
443*404b540aSrobert }
444*404b540aSrobert
445*404b540aSrobert template<typename _CharT, typename _Traits>
446*404b540aSrobert bool
447*404b540aSrobert basic_filebuf<_CharT, _Traits>::
_M_convert_to_external(_CharT * __ibuf,streamsize __ilen)448*404b540aSrobert _M_convert_to_external(_CharT* __ibuf, streamsize __ilen)
449*404b540aSrobert {
450*404b540aSrobert // Sizes of external and pending output.
451*404b540aSrobert streamsize __elen;
452*404b540aSrobert streamsize __plen;
453*404b540aSrobert if (__check_facet(_M_codecvt).always_noconv())
454*404b540aSrobert {
455*404b540aSrobert __elen = _M_file.xsputn(reinterpret_cast<char*>(__ibuf), __ilen);
456*404b540aSrobert __plen = __ilen;
457*404b540aSrobert }
458*404b540aSrobert else
459*404b540aSrobert {
460*404b540aSrobert // Worst-case number of external bytes needed.
461*404b540aSrobert // XXX Not done encoding() == -1.
462*404b540aSrobert streamsize __blen = __ilen * _M_codecvt->max_length();
463*404b540aSrobert char* __buf = static_cast<char*>(__builtin_alloca(__blen));
464*404b540aSrobert
465*404b540aSrobert char* __bend;
466*404b540aSrobert const char_type* __iend;
467*404b540aSrobert codecvt_base::result __r;
468*404b540aSrobert __r = _M_codecvt->out(_M_state_cur, __ibuf, __ibuf + __ilen,
469*404b540aSrobert __iend, __buf, __buf + __blen, __bend);
470*404b540aSrobert
471*404b540aSrobert if (__r == codecvt_base::ok || __r == codecvt_base::partial)
472*404b540aSrobert __blen = __bend - __buf;
473*404b540aSrobert else if (__r == codecvt_base::noconv)
474*404b540aSrobert {
475*404b540aSrobert // Same as the always_noconv case above.
476*404b540aSrobert __buf = reinterpret_cast<char*>(__ibuf);
477*404b540aSrobert __blen = __ilen;
478*404b540aSrobert }
479*404b540aSrobert else
480*404b540aSrobert __throw_ios_failure(__N("basic_filebuf::_M_convert_to_external "
481*404b540aSrobert "conversion error"));
482*404b540aSrobert
483*404b540aSrobert __elen = _M_file.xsputn(__buf, __blen);
484*404b540aSrobert __plen = __blen;
485*404b540aSrobert
486*404b540aSrobert // Try once more for partial conversions.
487*404b540aSrobert if (__r == codecvt_base::partial && __elen == __plen)
488*404b540aSrobert {
489*404b540aSrobert const char_type* __iresume = __iend;
490*404b540aSrobert streamsize __rlen = this->pptr() - __iend;
491*404b540aSrobert __r = _M_codecvt->out(_M_state_cur, __iresume,
492*404b540aSrobert __iresume + __rlen, __iend, __buf,
493*404b540aSrobert __buf + __blen, __bend);
494*404b540aSrobert if (__r != codecvt_base::error)
495*404b540aSrobert {
496*404b540aSrobert __rlen = __bend - __buf;
497*404b540aSrobert __elen = _M_file.xsputn(__buf, __rlen);
498*404b540aSrobert __plen = __rlen;
499*404b540aSrobert }
500*404b540aSrobert else
501*404b540aSrobert __throw_ios_failure(__N("basic_filebuf::_M_convert_to_external "
502*404b540aSrobert "conversion error"));
503*404b540aSrobert }
504*404b540aSrobert }
505*404b540aSrobert return __elen == __plen;
506*404b540aSrobert }
507*404b540aSrobert
508*404b540aSrobert template<typename _CharT, typename _Traits>
509*404b540aSrobert streamsize
510*404b540aSrobert basic_filebuf<_CharT, _Traits>::
xsgetn(_CharT * __s,streamsize __n)511*404b540aSrobert xsgetn(_CharT* __s, streamsize __n)
512*404b540aSrobert {
513*404b540aSrobert // Clear out pback buffer before going on to the real deal...
514*404b540aSrobert streamsize __ret = 0;
515*404b540aSrobert if (_M_pback_init)
516*404b540aSrobert {
517*404b540aSrobert if (__n > 0 && this->gptr() == this->eback())
518*404b540aSrobert {
519*404b540aSrobert *__s++ = *this->gptr();
520*404b540aSrobert this->gbump(1);
521*404b540aSrobert __ret = 1;
522*404b540aSrobert --__n;
523*404b540aSrobert }
524*404b540aSrobert _M_destroy_pback();
525*404b540aSrobert }
526*404b540aSrobert
527*404b540aSrobert // Optimization in the always_noconv() case, to be generalized in the
528*404b540aSrobert // future: when __n > __buflen we read directly instead of using the
529*404b540aSrobert // buffer repeatedly.
530*404b540aSrobert const bool __testin = _M_mode & ios_base::in;
531*404b540aSrobert const streamsize __buflen = _M_buf_size > 1 ? _M_buf_size - 1 : 1;
532*404b540aSrobert
533*404b540aSrobert if (__n > __buflen && __check_facet(_M_codecvt).always_noconv()
534*404b540aSrobert && __testin && !_M_writing)
535*404b540aSrobert {
536*404b540aSrobert // First, copy the chars already present in the buffer.
537*404b540aSrobert const streamsize __avail = this->egptr() - this->gptr();
538*404b540aSrobert if (__avail != 0)
539*404b540aSrobert {
540*404b540aSrobert if (__avail == 1)
541*404b540aSrobert *__s = *this->gptr();
542*404b540aSrobert else
543*404b540aSrobert traits_type::copy(__s, this->gptr(), __avail);
544*404b540aSrobert __s += __avail;
545*404b540aSrobert this->gbump(__avail);
546*404b540aSrobert __ret += __avail;
547*404b540aSrobert __n -= __avail;
548*404b540aSrobert }
549*404b540aSrobert
550*404b540aSrobert // Need to loop in case of short reads (relatively common
551*404b540aSrobert // with pipes).
552*404b540aSrobert streamsize __len;
553*404b540aSrobert for (;;)
554*404b540aSrobert {
555*404b540aSrobert __len = _M_file.xsgetn(reinterpret_cast<char*>(__s),
556*404b540aSrobert __n);
557*404b540aSrobert if (__len == -1)
558*404b540aSrobert __throw_ios_failure(__N("basic_filebuf::xsgetn "
559*404b540aSrobert "error reading the file"));
560*404b540aSrobert if (__len == 0)
561*404b540aSrobert break;
562*404b540aSrobert
563*404b540aSrobert __n -= __len;
564*404b540aSrobert __ret += __len;
565*404b540aSrobert if (__n == 0)
566*404b540aSrobert break;
567*404b540aSrobert
568*404b540aSrobert __s += __len;
569*404b540aSrobert }
570*404b540aSrobert
571*404b540aSrobert if (__n == 0)
572*404b540aSrobert {
573*404b540aSrobert _M_set_buffer(0);
574*404b540aSrobert _M_reading = true;
575*404b540aSrobert }
576*404b540aSrobert else if (__len == 0)
577*404b540aSrobert {
578*404b540aSrobert // If end of file is reached, set 'uncommitted'
579*404b540aSrobert // mode, thus allowing an immediate write without
580*404b540aSrobert // an intervening seek.
581*404b540aSrobert _M_set_buffer(-1);
582*404b540aSrobert _M_reading = false;
583*404b540aSrobert }
584*404b540aSrobert }
585*404b540aSrobert else
586*404b540aSrobert __ret += __streambuf_type::xsgetn(__s, __n);
587*404b540aSrobert
588*404b540aSrobert return __ret;
589*404b540aSrobert }
590*404b540aSrobert
591*404b540aSrobert template<typename _CharT, typename _Traits>
592*404b540aSrobert streamsize
593*404b540aSrobert basic_filebuf<_CharT, _Traits>::
xsputn(const _CharT * __s,streamsize __n)594*404b540aSrobert xsputn(const _CharT* __s, streamsize __n)
595*404b540aSrobert {
596*404b540aSrobert // Optimization in the always_noconv() case, to be generalized in the
597*404b540aSrobert // future: when __n is sufficiently large we write directly instead of
598*404b540aSrobert // using the buffer.
599*404b540aSrobert streamsize __ret = 0;
600*404b540aSrobert const bool __testout = _M_mode & ios_base::out;
601*404b540aSrobert if (__check_facet(_M_codecvt).always_noconv()
602*404b540aSrobert && __testout && !_M_reading)
603*404b540aSrobert {
604*404b540aSrobert // Measurement would reveal the best choice.
605*404b540aSrobert const streamsize __chunk = 1ul << 10;
606*404b540aSrobert streamsize __bufavail = this->epptr() - this->pptr();
607*404b540aSrobert
608*404b540aSrobert // Don't mistake 'uncommitted' mode buffered with unbuffered.
609*404b540aSrobert if (!_M_writing && _M_buf_size > 1)
610*404b540aSrobert __bufavail = _M_buf_size - 1;
611*404b540aSrobert
612*404b540aSrobert const streamsize __limit = std::min(__chunk, __bufavail);
613*404b540aSrobert if (__n >= __limit)
614*404b540aSrobert {
615*404b540aSrobert const streamsize __buffill = this->pptr() - this->pbase();
616*404b540aSrobert const char* __buf = reinterpret_cast<const char*>(this->pbase());
617*404b540aSrobert __ret = _M_file.xsputn_2(__buf, __buffill,
618*404b540aSrobert reinterpret_cast<const char*>(__s),
619*404b540aSrobert __n);
620*404b540aSrobert if (__ret == __buffill + __n)
621*404b540aSrobert {
622*404b540aSrobert _M_set_buffer(0);
623*404b540aSrobert _M_writing = true;
624*404b540aSrobert }
625*404b540aSrobert if (__ret > __buffill)
626*404b540aSrobert __ret -= __buffill;
627*404b540aSrobert else
628*404b540aSrobert __ret = 0;
629*404b540aSrobert }
630*404b540aSrobert else
631*404b540aSrobert __ret = __streambuf_type::xsputn(__s, __n);
632*404b540aSrobert }
633*404b540aSrobert else
634*404b540aSrobert __ret = __streambuf_type::xsputn(__s, __n);
635*404b540aSrobert return __ret;
636*404b540aSrobert }
637*404b540aSrobert
638*404b540aSrobert template<typename _CharT, typename _Traits>
639*404b540aSrobert typename basic_filebuf<_CharT, _Traits>::__streambuf_type*
640*404b540aSrobert basic_filebuf<_CharT, _Traits>::
setbuf(char_type * __s,streamsize __n)641*404b540aSrobert setbuf(char_type* __s, streamsize __n)
642*404b540aSrobert {
643*404b540aSrobert if (!this->is_open())
644*404b540aSrobert if (__s == 0 && __n == 0)
645*404b540aSrobert _M_buf_size = 1;
646*404b540aSrobert else if (__s && __n > 0)
647*404b540aSrobert {
648*404b540aSrobert // This is implementation-defined behavior, and assumes that
649*404b540aSrobert // an external char_type array of length __n exists and has
650*404b540aSrobert // been pre-allocated. If this is not the case, things will
651*404b540aSrobert // quickly blow up. When __n > 1, __n - 1 positions will be
652*404b540aSrobert // used for the get area, __n - 1 for the put area and 1
653*404b540aSrobert // position to host the overflow char of a full put area.
654*404b540aSrobert // When __n == 1, 1 position will be used for the get area
655*404b540aSrobert // and 0 for the put area, as in the unbuffered case above.
656*404b540aSrobert _M_buf = __s;
657*404b540aSrobert _M_buf_size = __n;
658*404b540aSrobert }
659*404b540aSrobert return this;
660*404b540aSrobert }
661*404b540aSrobert
662*404b540aSrobert
663*404b540aSrobert // According to 27.8.1.4 p11 - 13, seekoff should ignore the last
664*404b540aSrobert // argument (of type openmode).
665*404b540aSrobert template<typename _CharT, typename _Traits>
666*404b540aSrobert typename basic_filebuf<_CharT, _Traits>::pos_type
667*404b540aSrobert basic_filebuf<_CharT, _Traits>::
seekoff(off_type __off,ios_base::seekdir __way,ios_base::openmode)668*404b540aSrobert seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode)
669*404b540aSrobert {
670*404b540aSrobert int __width = 0;
671*404b540aSrobert if (_M_codecvt)
672*404b540aSrobert __width = _M_codecvt->encoding();
673*404b540aSrobert if (__width < 0)
674*404b540aSrobert __width = 0;
675*404b540aSrobert
676*404b540aSrobert pos_type __ret = pos_type(off_type(-1));
677*404b540aSrobert const bool __testfail = __off != 0 && __width <= 0;
678*404b540aSrobert if (this->is_open() && !__testfail)
679*404b540aSrobert {
680*404b540aSrobert // Ditch any pback buffers to avoid confusion.
681*404b540aSrobert _M_destroy_pback();
682*404b540aSrobert
683*404b540aSrobert // Correct state at destination. Note that this is the correct
684*404b540aSrobert // state for the current position during output, because
685*404b540aSrobert // codecvt::unshift() returns the state to the initial state.
686*404b540aSrobert // This is also the correct state at the end of the file because
687*404b540aSrobert // an unshift sequence should have been written at the end.
688*404b540aSrobert __state_type __state = _M_state_beg;
689*404b540aSrobert off_type __computed_off = __off * __width;
690*404b540aSrobert if (_M_reading && __way == ios_base::cur)
691*404b540aSrobert {
692*404b540aSrobert if (_M_codecvt->always_noconv())
693*404b540aSrobert __computed_off += this->gptr() - this->egptr();
694*404b540aSrobert else
695*404b540aSrobert {
696*404b540aSrobert // Calculate offset from _M_ext_buf that corresponds
697*404b540aSrobert // to gptr(). Note: uses _M_state_last, which
698*404b540aSrobert // corresponds to eback().
699*404b540aSrobert const int __gptr_off =
700*404b540aSrobert _M_codecvt->length(_M_state_last, _M_ext_buf, _M_ext_next,
701*404b540aSrobert this->gptr() - this->eback());
702*404b540aSrobert __computed_off += _M_ext_buf + __gptr_off - _M_ext_end;
703*404b540aSrobert
704*404b540aSrobert // _M_state_last is modified by codecvt::length() so
705*404b540aSrobert // it now corresponds to gptr().
706*404b540aSrobert __state = _M_state_last;
707*404b540aSrobert }
708*404b540aSrobert }
709*404b540aSrobert __ret = _M_seek(__computed_off, __way, __state);
710*404b540aSrobert }
711*404b540aSrobert return __ret;
712*404b540aSrobert }
713*404b540aSrobert
714*404b540aSrobert // _GLIBCXX_RESOLVE_LIB_DEFECTS
715*404b540aSrobert // 171. Strange seekpos() semantics due to joint position
716*404b540aSrobert // According to the resolution of DR 171, seekpos should ignore the last
717*404b540aSrobert // argument (of type openmode).
718*404b540aSrobert template<typename _CharT, typename _Traits>
719*404b540aSrobert typename basic_filebuf<_CharT, _Traits>::pos_type
720*404b540aSrobert basic_filebuf<_CharT, _Traits>::
seekpos(pos_type __pos,ios_base::openmode)721*404b540aSrobert seekpos(pos_type __pos, ios_base::openmode)
722*404b540aSrobert {
723*404b540aSrobert pos_type __ret = pos_type(off_type(-1));
724*404b540aSrobert if (this->is_open())
725*404b540aSrobert {
726*404b540aSrobert // Ditch any pback buffers to avoid confusion.
727*404b540aSrobert _M_destroy_pback();
728*404b540aSrobert __ret = _M_seek(off_type(__pos), ios_base::beg, __pos.state());
729*404b540aSrobert }
730*404b540aSrobert return __ret;
731*404b540aSrobert }
732*404b540aSrobert
733*404b540aSrobert template<typename _CharT, typename _Traits>
734*404b540aSrobert typename basic_filebuf<_CharT, _Traits>::pos_type
735*404b540aSrobert basic_filebuf<_CharT, _Traits>::
_M_seek(off_type __off,ios_base::seekdir __way,__state_type __state)736*404b540aSrobert _M_seek(off_type __off, ios_base::seekdir __way, __state_type __state)
737*404b540aSrobert {
738*404b540aSrobert pos_type __ret = pos_type(off_type(-1));
739*404b540aSrobert if (_M_terminate_output())
740*404b540aSrobert {
741*404b540aSrobert // Returns pos_type(off_type(-1)) in case of failure.
742*404b540aSrobert __ret = pos_type(_M_file.seekoff(__off, __way));
743*404b540aSrobert if (__ret != pos_type(off_type(-1)))
744*404b540aSrobert {
745*404b540aSrobert _M_reading = false;
746*404b540aSrobert _M_writing = false;
747*404b540aSrobert _M_ext_next = _M_ext_end = _M_ext_buf;
748*404b540aSrobert _M_set_buffer(-1);
749*404b540aSrobert _M_state_cur = __state;
750*404b540aSrobert __ret.state(_M_state_cur);
751*404b540aSrobert }
752*404b540aSrobert }
753*404b540aSrobert return __ret;
754*404b540aSrobert }
755*404b540aSrobert
756*404b540aSrobert template<typename _CharT, typename _Traits>
757*404b540aSrobert bool
758*404b540aSrobert basic_filebuf<_CharT, _Traits>::
_M_terminate_output()759*404b540aSrobert _M_terminate_output()
760*404b540aSrobert {
761*404b540aSrobert // Part one: update the output sequence.
762*404b540aSrobert bool __testvalid = true;
763*404b540aSrobert if (this->pbase() < this->pptr())
764*404b540aSrobert {
765*404b540aSrobert const int_type __tmp = this->overflow();
766*404b540aSrobert if (traits_type::eq_int_type(__tmp, traits_type::eof()))
767*404b540aSrobert __testvalid = false;
768*404b540aSrobert }
769*404b540aSrobert
770*404b540aSrobert // Part two: output unshift sequence.
771*404b540aSrobert if (_M_writing && !__check_facet(_M_codecvt).always_noconv()
772*404b540aSrobert && __testvalid)
773*404b540aSrobert {
774*404b540aSrobert // Note: this value is arbitrary, since there is no way to
775*404b540aSrobert // get the length of the unshift sequence from codecvt,
776*404b540aSrobert // without calling unshift.
777*404b540aSrobert const size_t __blen = 128;
778*404b540aSrobert char __buf[__blen];
779*404b540aSrobert codecvt_base::result __r;
780*404b540aSrobert streamsize __ilen = 0;
781*404b540aSrobert
782*404b540aSrobert do
783*404b540aSrobert {
784*404b540aSrobert char* __next;
785*404b540aSrobert __r = _M_codecvt->unshift(_M_state_cur, __buf,
786*404b540aSrobert __buf + __blen, __next);
787*404b540aSrobert if (__r == codecvt_base::error)
788*404b540aSrobert __testvalid = false;
789*404b540aSrobert else if (__r == codecvt_base::ok ||
790*404b540aSrobert __r == codecvt_base::partial)
791*404b540aSrobert {
792*404b540aSrobert __ilen = __next - __buf;
793*404b540aSrobert if (__ilen > 0)
794*404b540aSrobert {
795*404b540aSrobert const streamsize __elen = _M_file.xsputn(__buf, __ilen);
796*404b540aSrobert if (__elen != __ilen)
797*404b540aSrobert __testvalid = false;
798*404b540aSrobert }
799*404b540aSrobert }
800*404b540aSrobert }
801*404b540aSrobert while (__r == codecvt_base::partial && __ilen > 0 && __testvalid);
802*404b540aSrobert
803*404b540aSrobert if (__testvalid)
804*404b540aSrobert {
805*404b540aSrobert // This second call to overflow() is required by the standard,
806*404b540aSrobert // but it's not clear why it's needed, since the output buffer
807*404b540aSrobert // should be empty by this point (it should have been emptied
808*404b540aSrobert // in the first call to overflow()).
809*404b540aSrobert const int_type __tmp = this->overflow();
810*404b540aSrobert if (traits_type::eq_int_type(__tmp, traits_type::eof()))
811*404b540aSrobert __testvalid = false;
812*404b540aSrobert }
813*404b540aSrobert }
814*404b540aSrobert return __testvalid;
815*404b540aSrobert }
816*404b540aSrobert
817*404b540aSrobert template<typename _CharT, typename _Traits>
818*404b540aSrobert int
819*404b540aSrobert basic_filebuf<_CharT, _Traits>::
sync()820*404b540aSrobert sync()
821*404b540aSrobert {
822*404b540aSrobert // Make sure that the internal buffer resyncs its idea of
823*404b540aSrobert // the file position with the external file.
824*404b540aSrobert int __ret = 0;
825*404b540aSrobert if (this->pbase() < this->pptr())
826*404b540aSrobert {
827*404b540aSrobert const int_type __tmp = this->overflow();
828*404b540aSrobert if (traits_type::eq_int_type(__tmp, traits_type::eof()))
829*404b540aSrobert __ret = -1;
830*404b540aSrobert }
831*404b540aSrobert return __ret;
832*404b540aSrobert }
833*404b540aSrobert
834*404b540aSrobert template<typename _CharT, typename _Traits>
835*404b540aSrobert void
836*404b540aSrobert basic_filebuf<_CharT, _Traits>::
imbue(const locale & __loc)837*404b540aSrobert imbue(const locale& __loc)
838*404b540aSrobert {
839*404b540aSrobert bool __testvalid = true;
840*404b540aSrobert
841*404b540aSrobert const __codecvt_type* _M_codecvt_tmp = 0;
842*404b540aSrobert if (__builtin_expect(has_facet<__codecvt_type>(__loc), true))
843*404b540aSrobert _M_codecvt_tmp = &use_facet<__codecvt_type>(__loc);
844*404b540aSrobert
845*404b540aSrobert if (this->is_open())
846*404b540aSrobert {
847*404b540aSrobert // encoding() == -1 is ok only at the beginning.
848*404b540aSrobert if ((_M_reading || _M_writing)
849*404b540aSrobert && __check_facet(_M_codecvt).encoding() == -1)
850*404b540aSrobert __testvalid = false;
851*404b540aSrobert else
852*404b540aSrobert {
853*404b540aSrobert if (_M_reading)
854*404b540aSrobert {
855*404b540aSrobert if (__check_facet(_M_codecvt).always_noconv())
856*404b540aSrobert {
857*404b540aSrobert if (_M_codecvt_tmp
858*404b540aSrobert && !__check_facet(_M_codecvt_tmp).always_noconv())
859*404b540aSrobert __testvalid = this->seekoff(0, ios_base::cur, _M_mode)
860*404b540aSrobert != pos_type(off_type(-1));
861*404b540aSrobert }
862*404b540aSrobert else
863*404b540aSrobert {
864*404b540aSrobert // External position corresponding to gptr().
865*404b540aSrobert _M_ext_next = _M_ext_buf
866*404b540aSrobert + _M_codecvt->length(_M_state_last, _M_ext_buf, _M_ext_next,
867*404b540aSrobert this->gptr() - this->eback());
868*404b540aSrobert const streamsize __remainder = _M_ext_end - _M_ext_next;
869*404b540aSrobert if (__remainder)
870*404b540aSrobert std::memmove(_M_ext_buf, _M_ext_next, __remainder);
871*404b540aSrobert
872*404b540aSrobert _M_ext_next = _M_ext_buf;
873*404b540aSrobert _M_ext_end = _M_ext_buf + __remainder;
874*404b540aSrobert _M_set_buffer(-1);
875*404b540aSrobert _M_state_last = _M_state_cur = _M_state_beg;
876*404b540aSrobert }
877*404b540aSrobert }
878*404b540aSrobert else if (_M_writing && (__testvalid = _M_terminate_output()))
879*404b540aSrobert _M_set_buffer(-1);
880*404b540aSrobert }
881*404b540aSrobert }
882*404b540aSrobert
883*404b540aSrobert if (__testvalid)
884*404b540aSrobert _M_codecvt = _M_codecvt_tmp;
885*404b540aSrobert else
886*404b540aSrobert _M_codecvt = 0;
887*404b540aSrobert }
888*404b540aSrobert
889*404b540aSrobert // Inhibit implicit instantiations for required instantiations,
890*404b540aSrobert // which are defined via explicit instantiations elsewhere.
891*404b540aSrobert // NB: This syntax is a GNU extension.
892*404b540aSrobert #if _GLIBCXX_EXTERN_TEMPLATE
893*404b540aSrobert extern template class basic_filebuf<char>;
894*404b540aSrobert extern template class basic_ifstream<char>;
895*404b540aSrobert extern template class basic_ofstream<char>;
896*404b540aSrobert extern template class basic_fstream<char>;
897*404b540aSrobert
898*404b540aSrobert #ifdef _GLIBCXX_USE_WCHAR_T
899*404b540aSrobert extern template class basic_filebuf<wchar_t>;
900*404b540aSrobert extern template class basic_ifstream<wchar_t>;
901*404b540aSrobert extern template class basic_ofstream<wchar_t>;
902*404b540aSrobert extern template class basic_fstream<wchar_t>;
903*404b540aSrobert #endif
904*404b540aSrobert #endif
905*404b540aSrobert
906*404b540aSrobert _GLIBCXX_END_NAMESPACE
907*404b540aSrobert
908*404b540aSrobert #endif
909