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