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