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 && (!__testeof || !_M_file.sync())) 401 { 402 _M_set_buffer(0); 403 __ret = traits_type::not_eof(__c); 404 } 405 } 406 else if (this->_M_buf_size > 1) 407 { 408 // Overflow in 'uncommitted' mode: set _M_writing, set 409 // the buffer to the initial 'write' mode, and put __c 410 // into the buffer. 411 _M_set_buffer(0); 412 _M_writing = true; 413 if (!__testeof) 414 { 415 *this->pptr() = traits_type::to_char_type(__c); 416 this->pbump(1); 417 } 418 __ret = traits_type::not_eof(__c); 419 } 420 else 421 { 422 // Unbuffered. 423 char_type __conv = traits_type::to_char_type(__c); 424 if (__testeof || _M_convert_to_external(&__conv, 1)) 425 { 426 _M_writing = true; 427 __ret = traits_type::not_eof(__c); 428 } 429 } 430 } 431 return __ret; 432 } 433 434 template<typename _CharT, typename _Traits> 435 bool 436 basic_filebuf<_CharT, _Traits>:: 437 _M_convert_to_external(_CharT* __ibuf, streamsize __ilen) 438 { 439 // Sizes of external and pending output. 440 streamsize __elen; 441 streamsize __plen; 442 if (__check_facet(_M_codecvt).always_noconv()) 443 { 444 __elen = _M_file.xsputn(reinterpret_cast<char*>(__ibuf), __ilen); 445 __plen = __ilen; 446 } 447 else 448 { 449 // Worst-case number of external bytes needed. 450 // XXX Not done encoding() == -1. 451 streamsize __blen = __ilen * _M_codecvt->max_length(); 452 char* __buf = static_cast<char*>(__builtin_alloca(__blen)); 453 454 char* __bend; 455 const char_type* __iend; 456 codecvt_base::result __r; 457 __r = _M_codecvt->out(_M_state_cur, __ibuf, __ibuf + __ilen, 458 __iend, __buf, __buf + __blen, __bend); 459 460 if (__r == codecvt_base::ok || __r == codecvt_base::partial) 461 __blen = __bend - __buf; 462 else if (__r == codecvt_base::noconv) 463 { 464 // Same as the always_noconv case above. 465 __buf = reinterpret_cast<char*>(__ibuf); 466 __blen = __ilen; 467 } 468 else 469 __throw_ios_failure(__N("basic_filebuf::_M_convert_to_external " 470 "conversion error")); 471 472 __elen = _M_file.xsputn(__buf, __blen); 473 __plen = __blen; 474 475 // Try once more for partial conversions. 476 if (__r == codecvt_base::partial && __elen == __plen) 477 { 478 const char_type* __iresume = __iend; 479 streamsize __rlen = this->pptr() - __iend; 480 __r = _M_codecvt->out(_M_state_cur, __iresume, 481 __iresume + __rlen, __iend, __buf, 482 __buf + __blen, __bend); 483 if (__r != codecvt_base::error) 484 { 485 __rlen = __bend - __buf; 486 __elen = _M_file.xsputn(__buf, __rlen); 487 __plen = __rlen; 488 } 489 else 490 __throw_ios_failure(__N("basic_filebuf::_M_convert_to_external " 491 "conversion error")); 492 } 493 } 494 return __elen == __plen; 495 } 496 497 template<typename _CharT, typename _Traits> 498 streamsize 499 basic_filebuf<_CharT, _Traits>:: 500 xsputn(const _CharT* __s, streamsize __n) 501 { 502 // Optimization in the always_noconv() case, to be generalized in the 503 // future: when __n is sufficiently large we write directly instead of 504 // using the buffer. 505 streamsize __ret = 0; 506 const bool __testout = this->_M_mode & ios_base::out; 507 if (__testout && !_M_reading 508 && __check_facet(_M_codecvt).always_noconv()) 509 { 510 // Measurement would reveal the best choice. 511 const streamsize __chunk = 1ul << 10; 512 streamsize __bufavail = this->epptr() - this->pptr(); 513 514 // Don't mistake 'uncommitted' mode buffered with unbuffered. 515 if (!_M_writing && this->_M_buf_size > 1) 516 __bufavail = this->_M_buf_size - 1; 517 518 const streamsize __limit = std::min(__chunk, __bufavail); 519 if (__n >= __limit) 520 { 521 const streamsize __buffill = this->pptr() - this->pbase(); 522 const char* __buf = reinterpret_cast<const char*>(this->pbase()); 523 __ret = _M_file.xsputn_2(__buf, __buffill, 524 reinterpret_cast<const char*>(__s), 525 __n); 526 if (__ret == __buffill + __n) 527 { 528 _M_set_buffer(0); 529 _M_writing = true; 530 } 531 if (__ret > __buffill) 532 __ret -= __buffill; 533 else 534 __ret = 0; 535 } 536 else 537 __ret = __streambuf_type::xsputn(__s, __n); 538 } 539 else 540 __ret = __streambuf_type::xsputn(__s, __n); 541 return __ret; 542 } 543 544 template<typename _CharT, typename _Traits> 545 typename basic_filebuf<_CharT, _Traits>::__streambuf_type* 546 basic_filebuf<_CharT, _Traits>:: 547 setbuf(char_type* __s, streamsize __n) 548 { 549 if (!this->is_open()) 550 if (__s == 0 && __n == 0) 551 this->_M_buf_size = 1; 552 else if (__s && __n > 0) 553 { 554 // This is implementation-defined behavior, and assumes that 555 // an external char_type array of length __n exists and has 556 // been pre-allocated. If this is not the case, things will 557 // quickly blow up. When __n > 1, __n - 1 positions will be 558 // used for the get area, __n - 1 for the put area and 1 559 // position to host the overflow char of a full put area. 560 // When __n == 1, 1 position will be used for the get area 561 // and 0 for the put area, as in the unbuffered case above. 562 this->_M_buf = __s; 563 this->_M_buf_size = __n; 564 } 565 return this; 566 } 567 568 569 // According to 27.8.1.4 p11 - 13, seekoff should ignore the last 570 // argument (of type openmode). 571 template<typename _CharT, typename _Traits> 572 typename basic_filebuf<_CharT, _Traits>::pos_type 573 basic_filebuf<_CharT, _Traits>:: 574 seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode) 575 { 576 int __width = 0; 577 if (_M_codecvt) 578 __width = _M_codecvt->encoding(); 579 if (__width < 0) 580 __width = 0; 581 582 pos_type __ret = pos_type(off_type(-1)); 583 const bool __testfail = __off != 0 && __width <= 0; 584 if (this->is_open() && !__testfail) 585 { 586 // Ditch any pback buffers to avoid confusion. 587 _M_destroy_pback(); 588 589 // Correct state at destination. Note that this is the correct 590 // state for the current position during output, because 591 // codecvt::unshift() returns the state to the initial state. 592 // This is also the correct state at the end of the file because 593 // an unshift sequence should have been written at the end. 594 __state_type __state = _M_state_beg; 595 off_type __computed_off = __off * __width; 596 if (_M_reading && __way == ios_base::cur) 597 { 598 if (_M_codecvt->always_noconv()) 599 __computed_off += this->gptr() - this->egptr(); 600 else 601 { 602 // Calculate offset from _M_ext_buf that corresponds 603 // to gptr(). Note: uses _M_state_last, which 604 // corresponds to eback(). 605 const int __gptr_off = 606 _M_codecvt->length(_M_state_last, _M_ext_buf, _M_ext_next, 607 this->gptr() - this->eback()); 608 __computed_off += _M_ext_buf + __gptr_off - _M_ext_end; 609 610 // _M_state_last is modified by codecvt::length() so 611 // it now corresponds to gptr(). 612 __state = _M_state_last; 613 } 614 } 615 __ret = _M_seek(__computed_off, __way, __state); 616 } 617 return __ret; 618 } 619 620 // _GLIBCXX_RESOLVE_LIB_DEFECTS 621 // 171. Strange seekpos() semantics due to joint position 622 // According to the resolution of DR 171, seekpos should ignore the last 623 // argument (of type openmode). 624 template<typename _CharT, typename _Traits> 625 typename basic_filebuf<_CharT, _Traits>::pos_type 626 basic_filebuf<_CharT, _Traits>:: 627 seekpos(pos_type __pos, ios_base::openmode) 628 { 629 pos_type __ret = pos_type(off_type(-1)); 630 if (this->is_open()) 631 { 632 // Ditch any pback buffers to avoid confusion. 633 _M_destroy_pback(); 634 __ret = _M_seek(off_type(__pos), ios_base::beg, __pos.state()); 635 } 636 return __ret; 637 } 638 639 template<typename _CharT, typename _Traits> 640 typename basic_filebuf<_CharT, _Traits>::pos_type 641 basic_filebuf<_CharT, _Traits>:: 642 _M_seek(off_type __off, ios_base::seekdir __way, __state_type __state) 643 { 644 pos_type __ret = pos_type(off_type(-1)); 645 if (_M_terminate_output()) 646 { 647 // Returns pos_type(off_type(-1)) in case of failure. 648 __ret = pos_type(_M_file.seekoff(__off, __way)); 649 _M_reading = false; 650 _M_writing = false; 651 _M_ext_next = _M_ext_end = _M_ext_buf; 652 _M_set_buffer(-1); 653 _M_state_cur = __state; 654 __ret.state(_M_state_cur); 655 } 656 return __ret; 657 } 658 659 template<typename _CharT, typename _Traits> 660 bool 661 basic_filebuf<_CharT, _Traits>:: 662 _M_terminate_output() 663 { 664 // Part one: update the output sequence. 665 bool __testvalid = true; 666 if (this->pbase() < this->pptr()) 667 { 668 const int_type __tmp = this->overflow(); 669 if (traits_type::eq_int_type(__tmp, traits_type::eof())) 670 __testvalid = false; 671 } 672 673 // Part two: output unshift sequence. 674 if (_M_writing && !__check_facet(_M_codecvt).always_noconv() 675 && __testvalid) 676 { 677 // Note: this value is arbitrary, since there is no way to 678 // get the length of the unshift sequence from codecvt, 679 // without calling unshift. 680 const size_t __blen = 128; 681 char __buf[__blen]; 682 codecvt_base::result __r; 683 streamsize __ilen = 0; 684 685 do 686 { 687 char* __next; 688 __r = _M_codecvt->unshift(_M_state_cur, __buf, 689 __buf + __blen, __next); 690 if (__r == codecvt_base::error) 691 __testvalid = false; 692 else if (__r == codecvt_base::ok || 693 __r == codecvt_base::partial) 694 { 695 __ilen = __next - __buf; 696 if (__ilen > 0) 697 { 698 const streamsize __elen = _M_file.xsputn(__buf, __ilen); 699 if (__elen != __ilen) 700 __testvalid = false; 701 } 702 } 703 } 704 while (__r == codecvt_base::partial && __ilen > 0 && __testvalid); 705 706 if (__testvalid) 707 { 708 // This second call to overflow() is required by the standard, 709 // but it's not clear why it's needed, since the output buffer 710 // should be empty by this point (it should have been emptied 711 // in the first call to overflow()). 712 const int_type __tmp = this->overflow(); 713 if (traits_type::eq_int_type(__tmp, traits_type::eof())) 714 __testvalid = false; 715 } 716 } 717 return __testvalid; 718 } 719 720 template<typename _CharT, typename _Traits> 721 int 722 basic_filebuf<_CharT, _Traits>:: 723 sync() 724 { 725 // Make sure that the internal buffer resyncs its idea of 726 // the file position with the external file. 727 // NB: _M_file.sync() will be called within. 728 int __ret = 0; 729 if (this->pbase() < this->pptr()) 730 { 731 const int_type __tmp = this->overflow(); 732 if (traits_type::eq_int_type(__tmp, traits_type::eof())) 733 __ret = -1; 734 } 735 return __ret; 736 } 737 738 template<typename _CharT, typename _Traits> 739 void 740 basic_filebuf<_CharT, _Traits>:: 741 imbue(const locale& __loc) 742 { 743 bool __testvalid = true; 744 745 const __codecvt_type* _M_codecvt_tmp = 0; 746 if (__builtin_expect(has_facet<__codecvt_type>(__loc), true)) 747 _M_codecvt_tmp = &use_facet<__codecvt_type>(__loc); 748 749 if (this->is_open()) 750 { 751 // encoding() == -1 is ok only at the beginning. 752 if ((_M_reading || _M_writing) 753 && __check_facet(_M_codecvt).encoding() == -1) 754 __testvalid = false; 755 else 756 { 757 if (_M_reading) 758 { 759 if (__check_facet(_M_codecvt).always_noconv()) 760 { 761 if (_M_codecvt_tmp 762 && !__check_facet(_M_codecvt_tmp).always_noconv()) 763 __testvalid = this->seekoff(0, ios_base::cur, this->_M_mode) 764 != pos_type(off_type(-1)); 765 } 766 else 767 { 768 // External position corresponding to gptr(). 769 _M_ext_next = _M_ext_buf 770 + _M_codecvt->length(_M_state_last, _M_ext_buf, _M_ext_next, 771 this->gptr() - this->eback()); 772 const streamsize __remainder = _M_ext_end - _M_ext_next; 773 if (__remainder) 774 std::memmove(_M_ext_buf, _M_ext_next, __remainder); 775 776 _M_ext_next = _M_ext_buf; 777 _M_ext_end = _M_ext_buf + __remainder; 778 _M_set_buffer(-1); 779 _M_state_last = _M_state_cur = _M_state_beg; 780 } 781 } 782 else if (_M_writing && (__testvalid = _M_terminate_output())) 783 _M_set_buffer(-1); 784 } 785 } 786 787 if (__testvalid) 788 _M_codecvt = _M_codecvt_tmp; 789 else 790 _M_codecvt = 0; 791 } 792 793 // Inhibit implicit instantiations for required instantiations, 794 // which are defined via explicit instantiations elsewhere. 795 // NB: This syntax is a GNU extension. 796 #if _GLIBCXX_EXTERN_TEMPLATE 797 extern template class basic_filebuf<char>; 798 extern template class basic_ifstream<char>; 799 extern template class basic_ofstream<char>; 800 extern template class basic_fstream<char>; 801 802 #ifdef _GLIBCXX_USE_WCHAR_T 803 extern template class basic_filebuf<wchar_t>; 804 extern template class basic_ifstream<wchar_t>; 805 extern template class basic_ofstream<wchar_t>; 806 extern template class basic_fstream<wchar_t>; 807 #endif 808 #endif 809 } // namespace std 810 811 #endif 812