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 // Need to loop in case of short reads (relatively common 539 // with pipes). 540 streamsize __len; 541 for (;;) 542 { 543 __len = _M_file.xsgetn(reinterpret_cast<char*>(__s), 544 __n); 545 if (__len == -1) 546 __throw_ios_failure(__N("basic_filebuf::xsgetn " 547 "error reading the file")); 548 if (__len == 0) 549 break; 550 551 __n -= __len; 552 __ret += __len; 553 if (__n == 0) 554 break; 555 556 __s += __len; 557 } 558 559 if (__n == 0) 560 { 561 _M_set_buffer(0); 562 _M_reading = true; 563 } 564 else if (__len == 0) 565 { 566 // If end of file is reached, set 'uncommitted' 567 // mode, thus allowing an immediate write without 568 // an intervening seek. 569 _M_set_buffer(-1); 570 _M_reading = false; 571 } 572 } 573 else 574 __ret += __streambuf_type::xsgetn(__s, __n); 575 576 return __ret; 577 } 578 579 template<typename _CharT, typename _Traits> 580 streamsize 581 basic_filebuf<_CharT, _Traits>:: 582 xsputn(const _CharT* __s, streamsize __n) 583 { 584 // Optimization in the always_noconv() case, to be generalized in the 585 // future: when __n is sufficiently large we write directly instead of 586 // using the buffer. 587 streamsize __ret = 0; 588 const bool __testout = this->_M_mode & ios_base::out; 589 if (__check_facet(_M_codecvt).always_noconv() 590 && __testout && !_M_reading) 591 { 592 // Measurement would reveal the best choice. 593 const streamsize __chunk = 1ul << 10; 594 streamsize __bufavail = this->epptr() - this->pptr(); 595 596 // Don't mistake 'uncommitted' mode buffered with unbuffered. 597 if (!_M_writing && this->_M_buf_size > 1) 598 __bufavail = this->_M_buf_size - 1; 599 600 const streamsize __limit = std::min(__chunk, __bufavail); 601 if (__n >= __limit) 602 { 603 const streamsize __buffill = this->pptr() - this->pbase(); 604 const char* __buf = reinterpret_cast<const char*>(this->pbase()); 605 __ret = _M_file.xsputn_2(__buf, __buffill, 606 reinterpret_cast<const char*>(__s), 607 __n); 608 if (__ret == __buffill + __n) 609 { 610 _M_set_buffer(0); 611 _M_writing = true; 612 } 613 if (__ret > __buffill) 614 __ret -= __buffill; 615 else 616 __ret = 0; 617 } 618 else 619 __ret = __streambuf_type::xsputn(__s, __n); 620 } 621 else 622 __ret = __streambuf_type::xsputn(__s, __n); 623 return __ret; 624 } 625 626 template<typename _CharT, typename _Traits> 627 typename basic_filebuf<_CharT, _Traits>::__streambuf_type* 628 basic_filebuf<_CharT, _Traits>:: 629 setbuf(char_type* __s, streamsize __n) 630 { 631 if (!this->is_open()) 632 if (__s == 0 && __n == 0) 633 this->_M_buf_size = 1; 634 else if (__s && __n > 0) 635 { 636 // This is implementation-defined behavior, and assumes that 637 // an external char_type array of length __n exists and has 638 // been pre-allocated. If this is not the case, things will 639 // quickly blow up. When __n > 1, __n - 1 positions will be 640 // used for the get area, __n - 1 for the put area and 1 641 // position to host the overflow char of a full put area. 642 // When __n == 1, 1 position will be used for the get area 643 // and 0 for the put area, as in the unbuffered case above. 644 this->_M_buf = __s; 645 this->_M_buf_size = __n; 646 } 647 return this; 648 } 649 650 651 // According to 27.8.1.4 p11 - 13, seekoff should ignore the last 652 // argument (of type openmode). 653 template<typename _CharT, typename _Traits> 654 typename basic_filebuf<_CharT, _Traits>::pos_type 655 basic_filebuf<_CharT, _Traits>:: 656 seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode) 657 { 658 int __width = 0; 659 if (_M_codecvt) 660 __width = _M_codecvt->encoding(); 661 if (__width < 0) 662 __width = 0; 663 664 pos_type __ret = pos_type(off_type(-1)); 665 const bool __testfail = __off != 0 && __width <= 0; 666 if (this->is_open() && !__testfail) 667 { 668 // Ditch any pback buffers to avoid confusion. 669 _M_destroy_pback(); 670 671 // Correct state at destination. Note that this is the correct 672 // state for the current position during output, because 673 // codecvt::unshift() returns the state to the initial state. 674 // This is also the correct state at the end of the file because 675 // an unshift sequence should have been written at the end. 676 __state_type __state = _M_state_beg; 677 off_type __computed_off = __off * __width; 678 if (_M_reading && __way == ios_base::cur) 679 { 680 if (_M_codecvt->always_noconv()) 681 __computed_off += this->gptr() - this->egptr(); 682 else 683 { 684 // Calculate offset from _M_ext_buf that corresponds 685 // to gptr(). Note: uses _M_state_last, which 686 // corresponds to eback(). 687 const int __gptr_off = 688 _M_codecvt->length(_M_state_last, _M_ext_buf, _M_ext_next, 689 this->gptr() - this->eback()); 690 __computed_off += _M_ext_buf + __gptr_off - _M_ext_end; 691 692 // _M_state_last is modified by codecvt::length() so 693 // it now corresponds to gptr(). 694 __state = _M_state_last; 695 } 696 } 697 __ret = _M_seek(__computed_off, __way, __state); 698 } 699 return __ret; 700 } 701 702 // _GLIBCXX_RESOLVE_LIB_DEFECTS 703 // 171. Strange seekpos() semantics due to joint position 704 // According to the resolution of DR 171, seekpos should ignore the last 705 // argument (of type openmode). 706 template<typename _CharT, typename _Traits> 707 typename basic_filebuf<_CharT, _Traits>::pos_type 708 basic_filebuf<_CharT, _Traits>:: 709 seekpos(pos_type __pos, ios_base::openmode) 710 { 711 pos_type __ret = pos_type(off_type(-1)); 712 if (this->is_open()) 713 { 714 // Ditch any pback buffers to avoid confusion. 715 _M_destroy_pback(); 716 __ret = _M_seek(off_type(__pos), ios_base::beg, __pos.state()); 717 } 718 return __ret; 719 } 720 721 template<typename _CharT, typename _Traits> 722 typename basic_filebuf<_CharT, _Traits>::pos_type 723 basic_filebuf<_CharT, _Traits>:: 724 _M_seek(off_type __off, ios_base::seekdir __way, __state_type __state) 725 { 726 pos_type __ret = pos_type(off_type(-1)); 727 if (_M_terminate_output()) 728 { 729 // Returns pos_type(off_type(-1)) in case of failure. 730 __ret = pos_type(_M_file.seekoff(__off, __way)); 731 _M_reading = false; 732 _M_writing = false; 733 _M_ext_next = _M_ext_end = _M_ext_buf; 734 _M_set_buffer(-1); 735 _M_state_cur = __state; 736 __ret.state(_M_state_cur); 737 } 738 return __ret; 739 } 740 741 template<typename _CharT, typename _Traits> 742 bool 743 basic_filebuf<_CharT, _Traits>:: 744 _M_terminate_output() 745 { 746 // Part one: update the output sequence. 747 bool __testvalid = true; 748 if (this->pbase() < this->pptr()) 749 { 750 const int_type __tmp = this->overflow(); 751 if (traits_type::eq_int_type(__tmp, traits_type::eof())) 752 __testvalid = false; 753 } 754 755 // Part two: output unshift sequence. 756 if (_M_writing && !__check_facet(_M_codecvt).always_noconv() 757 && __testvalid) 758 { 759 // Note: this value is arbitrary, since there is no way to 760 // get the length of the unshift sequence from codecvt, 761 // without calling unshift. 762 const size_t __blen = 128; 763 char __buf[__blen]; 764 codecvt_base::result __r; 765 streamsize __ilen = 0; 766 767 do 768 { 769 char* __next; 770 __r = _M_codecvt->unshift(_M_state_cur, __buf, 771 __buf + __blen, __next); 772 if (__r == codecvt_base::error) 773 __testvalid = false; 774 else if (__r == codecvt_base::ok || 775 __r == codecvt_base::partial) 776 { 777 __ilen = __next - __buf; 778 if (__ilen > 0) 779 { 780 const streamsize __elen = _M_file.xsputn(__buf, __ilen); 781 if (__elen != __ilen) 782 __testvalid = false; 783 } 784 } 785 } 786 while (__r == codecvt_base::partial && __ilen > 0 && __testvalid); 787 788 if (__testvalid) 789 { 790 // This second call to overflow() is required by the standard, 791 // but it's not clear why it's needed, since the output buffer 792 // should be empty by this point (it should have been emptied 793 // in the first call to overflow()). 794 const int_type __tmp = this->overflow(); 795 if (traits_type::eq_int_type(__tmp, traits_type::eof())) 796 __testvalid = false; 797 } 798 } 799 return __testvalid; 800 } 801 802 template<typename _CharT, typename _Traits> 803 int 804 basic_filebuf<_CharT, _Traits>:: 805 sync() 806 { 807 // Make sure that the internal buffer resyncs its idea of 808 // the file position with the external file. 809 int __ret = 0; 810 if (this->pbase() < this->pptr()) 811 { 812 const int_type __tmp = this->overflow(); 813 if (traits_type::eq_int_type(__tmp, traits_type::eof())) 814 __ret = -1; 815 } 816 return __ret; 817 } 818 819 template<typename _CharT, typename _Traits> 820 void 821 basic_filebuf<_CharT, _Traits>:: 822 imbue(const locale& __loc) 823 { 824 bool __testvalid = true; 825 826 const __codecvt_type* _M_codecvt_tmp = 0; 827 if (__builtin_expect(has_facet<__codecvt_type>(__loc), true)) 828 _M_codecvt_tmp = &use_facet<__codecvt_type>(__loc); 829 830 if (this->is_open()) 831 { 832 // encoding() == -1 is ok only at the beginning. 833 if ((_M_reading || _M_writing) 834 && __check_facet(_M_codecvt).encoding() == -1) 835 __testvalid = false; 836 else 837 { 838 if (_M_reading) 839 { 840 if (__check_facet(_M_codecvt).always_noconv()) 841 { 842 if (_M_codecvt_tmp 843 && !__check_facet(_M_codecvt_tmp).always_noconv()) 844 __testvalid = this->seekoff(0, ios_base::cur, this->_M_mode) 845 != pos_type(off_type(-1)); 846 } 847 else 848 { 849 // External position corresponding to gptr(). 850 _M_ext_next = _M_ext_buf 851 + _M_codecvt->length(_M_state_last, _M_ext_buf, _M_ext_next, 852 this->gptr() - this->eback()); 853 const streamsize __remainder = _M_ext_end - _M_ext_next; 854 if (__remainder) 855 std::memmove(_M_ext_buf, _M_ext_next, __remainder); 856 857 _M_ext_next = _M_ext_buf; 858 _M_ext_end = _M_ext_buf + __remainder; 859 _M_set_buffer(-1); 860 _M_state_last = _M_state_cur = _M_state_beg; 861 } 862 } 863 else if (_M_writing && (__testvalid = _M_terminate_output())) 864 _M_set_buffer(-1); 865 } 866 } 867 868 if (__testvalid) 869 _M_codecvt = _M_codecvt_tmp; 870 else 871 _M_codecvt = 0; 872 } 873 874 // Inhibit implicit instantiations for required instantiations, 875 // which are defined via explicit instantiations elsewhere. 876 // NB: This syntax is a GNU extension. 877 #if _GLIBCXX_EXTERN_TEMPLATE 878 extern template class basic_filebuf<char>; 879 extern template class basic_ifstream<char>; 880 extern template class basic_ofstream<char>; 881 extern template class basic_fstream<char>; 882 883 #ifdef _GLIBCXX_USE_WCHAR_T 884 extern template class basic_filebuf<wchar_t>; 885 extern template class basic_ifstream<wchar_t>; 886 extern template class basic_ofstream<wchar_t>; 887 extern template class basic_fstream<wchar_t>; 888 #endif 889 #endif 890 } // namespace std 891 892 #endif 893