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