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