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