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