fstream.tcc

00001 // File based streams -*- C++ -*- 00002 00003 // Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 00004 // Free Software Foundation, Inc. 00005 // 00006 // This file is part of the GNU ISO C++ Library. This library is free 00007 // software; you can redistribute it and/or modify it under the 00008 // terms of the GNU General Public License as published by the 00009 // Free Software Foundation; either version 2, or (at your option) 00010 // any later version. 00011 00012 // This library is distributed in the hope that it will be useful, 00013 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 // GNU General Public License for more details. 00016 00017 // You should have received a copy of the GNU General Public License along 00018 // with this library; see the file COPYING. If not, write to the Free 00019 // Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, 00020 // USA. 00021 00022 // As a special exception, you may use this file as part of a free software 00023 // library without restriction. Specifically, if other files instantiate 00024 // templates or use macros or inline functions from this file, or you compile 00025 // this file and link it with other files to produce an executable, this 00026 // file does not by itself cause the resulting executable to be covered by 00027 // the GNU General Public License. This exception does not however 00028 // invalidate any other reasons why the executable file might be covered by 00029 // the GNU General Public License. 00030 00031 // 00032 // ISO C++ 14882: 27.8 File-based streams 00033 // 00034 00035 #ifndef _FSTREAM_TCC 00036 #define _FSTREAM_TCC 1 00037 00038 #pragma GCC system_header 00039 00040 namespace std 00041 { 00042 template<typename _CharT, typename _Traits> 00043 void 00044 basic_filebuf<_CharT, _Traits>:: 00045 _M_allocate_internal_buffer() 00046 { 00047 // Allocate internal buffer only if one doesn't already exist 00048 // (either allocated or provided by the user via setbuf). 00049 if (!_M_buf_allocated && !this->_M_buf) 00050 { 00051 this->_M_buf = new char_type[this->_M_buf_size]; 00052 _M_buf_allocated = true; 00053 } 00054 } 00055 00056 template<typename _CharT, typename _Traits> 00057 void 00058 basic_filebuf<_CharT, _Traits>:: 00059 _M_destroy_internal_buffer() throw() 00060 { 00061 if (_M_buf_allocated) 00062 { 00063 delete [] this->_M_buf; 00064 this->_M_buf = NULL; 00065 _M_buf_allocated = false; 00066 } 00067 delete [] _M_ext_buf; 00068 _M_ext_buf = NULL; 00069 _M_ext_buf_size = 0; 00070 _M_ext_next = NULL; 00071 _M_ext_end = NULL; 00072 } 00073 00074 template<typename _CharT, typename _Traits> 00075 basic_filebuf<_CharT, _Traits>:: 00076 basic_filebuf() : __streambuf_type(), _M_lock(), _M_file(&_M_lock), 00077 _M_mode(ios_base::openmode(0)), _M_state_beg(), _M_state_cur(), 00078 _M_state_last(), _M_buf(NULL), _M_buf_size(BUFSIZ), 00079 _M_buf_allocated(false), _M_reading(false), _M_writing(false), _M_pback(), 00080 _M_pback_cur_save(0), _M_pback_end_save(0), _M_pback_init(false), 00081 _M_codecvt(0), _M_ext_buf(0), _M_ext_buf_size(0), _M_ext_next(0), 00082 _M_ext_end(0) 00083 { 00084 if (has_facet<__codecvt_type>(this->_M_buf_locale)) 00085 _M_codecvt = &use_facet<__codecvt_type>(this->_M_buf_locale); 00086 } 00087 00088 template<typename _CharT, typename _Traits> 00089 typename basic_filebuf<_CharT, _Traits>::__filebuf_type* 00090 basic_filebuf<_CharT, _Traits>:: 00091 open(const char* __s, ios_base::openmode __mode) 00092 { 00093 __filebuf_type *__ret = NULL; 00094 if (!this->is_open()) 00095 { 00096 _M_file.open(__s, __mode); 00097 if (this->is_open()) 00098 { 00099 _M_allocate_internal_buffer(); 00100 this->_M_mode = __mode; 00101 00102 // Setup initial buffer to 'uncommitted' mode. 00103 _M_reading = false; 00104 _M_writing = false; 00105 _M_set_buffer(-1); 00106 00107 // Reset to initial state. 00108 _M_state_last = _M_state_cur = _M_state_beg; 00109 00110 // 27.8.1.3,4 00111 if ((__mode & ios_base::ate) 00112 && this->seekoff(0, ios_base::end, __mode) 00113 == pos_type(off_type(-1))) 00114 this->close(); 00115 else 00116 __ret = this; 00117 } 00118 } 00119 return __ret; 00120 } 00121 00122 template<typename _CharT, typename _Traits> 00123 typename basic_filebuf<_CharT, _Traits>::__filebuf_type* 00124 basic_filebuf<_CharT, _Traits>:: 00125 close() throw() 00126 { 00127 __filebuf_type* __ret = NULL; 00128 if (this->is_open()) 00129 { 00130 bool __testfail = false; 00131 try 00132 { 00133 if (!_M_terminate_output()) 00134 __testfail = true; 00135 } 00136 catch(...) 00137 { __testfail = true; } 00138 00139 // NB: Do this here so that re-opened filebufs will be cool... 00140 this->_M_mode = ios_base::openmode(0); 00141 this->_M_pback_init = false; 00142 _M_destroy_internal_buffer(); 00143 _M_reading = false; 00144 _M_writing = false; 00145 _M_set_buffer(-1); 00146 _M_state_last = _M_state_cur = _M_state_beg; 00147 00148 if (!_M_file.close()) 00149 __testfail = true; 00150 00151 if (!__testfail) 00152 __ret = this; 00153 } 00154 return __ret; 00155 } 00156 00157 template<typename _CharT, typename _Traits> 00158 streamsize 00159 basic_filebuf<_CharT, _Traits>:: 00160 showmanyc() 00161 { 00162 streamsize __ret = -1; 00163 const bool __testin = this->_M_mode & ios_base::in; 00164 if (__testin && this->is_open()) 00165 { 00166 // For a stateful encoding (-1) the pending sequence might be just 00167 // shift and unshift prefixes with no actual character. 00168 __ret = this->egptr() - this->gptr(); 00169 if (__check_facet(_M_codecvt).encoding() >= 0) 00170 __ret += _M_file.showmanyc() / _M_codecvt->max_length(); 00171 } 00172 return __ret; 00173 } 00174 00175 template<typename _CharT, typename _Traits> 00176 typename basic_filebuf<_CharT, _Traits>::int_type 00177 basic_filebuf<_CharT, _Traits>:: 00178 underflow() 00179 { 00180 int_type __ret = traits_type::eof(); 00181 const bool __testin = this->_M_mode & ios_base::in; 00182 if (__testin && !_M_writing) 00183 { 00184 // Check for pback madness, and if so swich back to the 00185 // normal buffers and jet outta here before expensive 00186 // fileops happen... 00187 _M_destroy_pback(); 00188 00189 if (this->gptr() < this->egptr()) 00190 return traits_type::to_int_type(*this->gptr()); 00191 00192 // Get and convert input sequence. 00193 const size_t __buflen = this->_M_buf_size > 1 00194 ? this->_M_buf_size - 1 : 1; 00195 00196 // Will be set to true if ::read() returns 0 indicating EOF. 00197 bool __got_eof = false; 00198 // Number of internal characters produced. 00199 streamsize __ilen = 0; 00200 codecvt_base::result __r = codecvt_base::ok; 00201 if (__check_facet(_M_codecvt).always_noconv()) 00202 { 00203 __ilen = _M_file.xsgetn(reinterpret_cast<char*>(this->eback()), 00204 __buflen); 00205 if (__ilen == 0) 00206 __got_eof = true; 00207 } 00208 else 00209 { 00210 // Worst-case number of external bytes. 00211 // XXX Not done encoding() == -1. 00212 const int __enc = _M_codecvt->encoding(); 00213 streamsize __blen; // Minimum buffer size. 00214 streamsize __rlen; // Number of chars to read. 00215 if (__enc > 0) 00216 __blen = __rlen = __buflen * __enc; 00217 else 00218 { 00219 __blen = __buflen + _M_codecvt->max_length() - 1; 00220 __rlen = __buflen; 00221 } 00222 const streamsize __remainder = _M_ext_end - _M_ext_next; 00223 __rlen = __rlen > __remainder ? __rlen - __remainder : 0; 00224 00225 // An imbue in 'read' mode implies first converting the external 00226 // chars already present. 00227 if (_M_reading && this->egptr() == this->eback() && __remainder) 00228 __rlen = 0; 00229 00230 // Allocate buffer if necessary and move unconverted 00231 // bytes to front. 00232 if (_M_ext_buf_size < __blen) 00233 { 00234 char* __buf = new char[__blen]; 00235 if (__remainder) 00236 std::memcpy(__buf, _M_ext_next, __remainder); 00237 00238 delete [] _M_ext_buf; 00239 _M_ext_buf = __buf; 00240 _M_ext_buf_size = __blen; 00241 } 00242 else if (__remainder) 00243 std::memmove(_M_ext_buf, _M_ext_next, __remainder); 00244 00245 _M_ext_next = _M_ext_buf; 00246 _M_ext_end = _M_ext_buf + __remainder; 00247 _M_state_last = _M_state_cur; 00248 00249 do 00250 { 00251 if (__rlen > 0) 00252 { 00253 // Sanity check! 00254 // This may fail if the return value of 00255 // codecvt::max_length() is bogus. 00256 if (_M_ext_end - _M_ext_buf + __rlen > _M_ext_buf_size) 00257 { 00258 __throw_ios_failure(__N("basic_filebuf::underflow " 00259 "codecvt::max_length() " 00260 "is not valid")); 00261 } 00262 streamsize __elen = _M_file.xsgetn(_M_ext_end, __rlen); 00263 if (__elen == 0) 00264 __got_eof = true; 00265 else if (__elen == -1) 00266 break; 00267 _M_ext_end += __elen; 00268 } 00269 00270 char_type* __iend; 00271 __r = _M_codecvt->in(_M_state_cur, _M_ext_next, 00272 _M_ext_end, _M_ext_next, this->eback(), 00273 this->eback() + __buflen, __iend); 00274 if (__r == codecvt_base::noconv) 00275 { 00276 size_t __avail = _M_ext_end - _M_ext_buf; 00277 __ilen = std::min(__avail, __buflen); 00278 traits_type::copy(this->eback(), 00279 reinterpret_cast<char_type*>(_M_ext_buf), __ilen); 00280 _M_ext_next = _M_ext_buf + __ilen; 00281 } 00282 else 00283 __ilen = __iend - this->eback(); 00284 00285 // _M_codecvt->in may return error while __ilen > 0: this is 00286 // ok, and actually occurs in case of mixed encodings (e.g., 00287 // XML files). 00288 if (__r == codecvt_base::error) 00289 break; 00290 00291 __rlen = 1; 00292 } 00293 while (__ilen == 0 && !__got_eof); 00294 } 00295 00296 if (__ilen > 0) 00297 { 00298 _M_set_buffer(__ilen); 00299 _M_reading = true; 00300 __ret = traits_type::to_int_type(*this->gptr()); 00301 } 00302 else if (__got_eof) 00303 { 00304 // If the actual end of file is reached, set 'uncommitted' 00305 // mode, thus allowing an immediate write without an 00306 // intervening seek. 00307 _M_set_buffer(-1); 00308 _M_reading = false; 00309 // However, reaching it while looping on partial means that 00310 // the file has got an incomplete character. 00311 if (__r == codecvt_base::partial) 00312 __throw_ios_failure(__N("basic_filebuf::underflow " 00313 "incomplete character in file")); 00314 } 00315 else if (__r == codecvt_base::error) 00316 __throw_ios_failure(__N("basic_filebuf::underflow " 00317 "invalid byte sequence in file")); 00318 else 00319 __throw_ios_failure(__N("basic_filebuf::underflow " 00320 "error reading the file")); 00321 } 00322 return __ret; 00323 } 00324 00325 template<typename _CharT, typename _Traits> 00326 typename basic_filebuf<_CharT, _Traits>::int_type 00327 basic_filebuf<_CharT, _Traits>:: 00328 pbackfail(int_type __i) 00329 { 00330 int_type __ret = traits_type::eof(); 00331 const bool __testin = this->_M_mode & ios_base::in; 00332 if (__testin && !_M_writing) 00333 { 00334 // Remember whether the pback buffer is active, otherwise below 00335 // we may try to store in it a second char (libstdc++/9761). 00336 const bool __testpb = this->_M_pback_init; 00337 const bool __testeof = traits_type::eq_int_type(__i, __ret); 00338 int_type __tmp; 00339 if (this->eback() < this->gptr()) 00340 { 00341 this->gbump(-1); 00342 __tmp = traits_type::to_int_type(*this->gptr()); 00343 } 00344 else if (this->seekoff(-1, ios_base::cur) != pos_type(off_type(-1))) 00345 { 00346 __tmp = this->underflow(); 00347 if (traits_type::eq_int_type(__tmp, __ret)) 00348 return __ret; 00349 } 00350 else 00351 { 00352 // At the beginning of the buffer, need to make a 00353 // putback position available. But the seek may fail 00354 // (f.i., at the beginning of a file, see 00355 // libstdc++/9439) and in that case we return 00356 // traits_type::eof(). 00357 return __ret; 00358 } 00359 00360 // Try to put back __i into input sequence in one of three ways. 00361 // Order these tests done in is unspecified by the standard. 00362 if (!__testeof && traits_type::eq_int_type(__i, __tmp)) 00363 __ret = __i; 00364 else if (__testeof) 00365 __ret = traits_type::not_eof(__i); 00366 else if (!__testpb) 00367 { 00368 _M_create_pback(); 00369 _M_reading = true; 00370 *this->gptr() = traits_type::to_char_type(__i); 00371 __ret = __i; 00372 } 00373 } 00374 return __ret; 00375 } 00376 00377 template<typename _CharT, typename _Traits> 00378 typename basic_filebuf<_CharT, _Traits>::int_type 00379 basic_filebuf<_CharT, _Traits>:: 00380 overflow(int_type __c) 00381 { 00382 int_type __ret = traits_type::eof(); 00383 const bool __testeof = traits_type::eq_int_type(__c, __ret); 00384 const bool __testout = this->_M_mode & ios_base::out; 00385 if (__testout && !_M_reading) 00386 { 00387 if (this->pbase() < this->pptr()) 00388 { 00389 // If appropriate, append the overflow char. 00390 if (!__testeof) 00391 { 00392 *this->pptr() = traits_type::to_char_type(__c); 00393 this->pbump(1); 00394 } 00395 00396 // Convert pending sequence to external representation, 00397 // and output. 00398 if (_M_convert_to_external(this->pbase(), 00399 this->pptr() - this->pbase()) 00400 && (!__testeof || !_M_file.sync())) 00401 { 00402 _M_set_buffer(0); 00403 __ret = traits_type::not_eof(__c); 00404 } 00405 } 00406 else if (this->_M_buf_size > 1) 00407 { 00408 // Overflow in 'uncommitted' mode: set _M_writing, set 00409 // the buffer to the initial 'write' mode, and put __c 00410 // into the buffer. 00411 _M_set_buffer(0); 00412 _M_writing = true; 00413 if (!__testeof) 00414 { 00415 *this->pptr() = traits_type::to_char_type(__c); 00416 this->pbump(1); 00417 } 00418 __ret = traits_type::not_eof(__c); 00419 } 00420 else 00421 { 00422 // Unbuffered. 00423 char_type __conv = traits_type::to_char_type(__c); 00424 if (__testeof || _M_convert_to_external(&__conv, 1)) 00425 { 00426 _M_writing = true; 00427 __ret = traits_type::not_eof(__c); 00428 } 00429 } 00430 } 00431 return __ret; 00432 } 00433 00434 template<typename _CharT, typename _Traits> 00435 bool 00436 basic_filebuf<_CharT, _Traits>:: 00437 _M_convert_to_external(_CharT* __ibuf, streamsize __ilen) 00438 { 00439 // Sizes of external and pending output. 00440 streamsize __elen; 00441 streamsize __plen; 00442 if (__check_facet(_M_codecvt).always_noconv()) 00443 { 00444 __elen = _M_file.xsputn(reinterpret_cast<char*>(__ibuf), __ilen); 00445 __plen = __ilen; 00446 } 00447 else 00448 { 00449 // Worst-case number of external bytes needed. 00450 // XXX Not done encoding() == -1. 00451 streamsize __blen = __ilen * _M_codecvt->max_length(); 00452 char* __buf = static_cast<char*>(__builtin_alloca(__blen)); 00453 00454 char* __bend; 00455 const char_type* __iend; 00456 codecvt_base::result __r; 00457 __r = _M_codecvt->out(_M_state_cur, __ibuf, __ibuf + __ilen, 00458 __iend, __buf, __buf + __blen, __bend); 00459 00460 if (__r == codecvt_base::ok || __r == codecvt_base::partial) 00461 __blen = __bend - __buf; 00462 else if (__r == codecvt_base::noconv) 00463 { 00464 // Same as the always_noconv case above. 00465 __buf = reinterpret_cast<char*>(__ibuf); 00466 __blen = __ilen; 00467 } 00468 else 00469 __throw_ios_failure(__N("basic_filebuf::_M_convert_to_external " 00470 "conversion error")); 00471 00472 __elen = _M_file.xsputn(__buf, __blen); 00473 __plen = __blen; 00474 00475 // Try once more for partial conversions. 00476 if (__r == codecvt_base::partial && __elen == __plen) 00477 { 00478 const char_type* __iresume = __iend; 00479 streamsize __rlen = this->pptr() - __iend; 00480 __r = _M_codecvt->out(_M_state_cur, __iresume, 00481 __iresume + __rlen, __iend, __buf, 00482 __buf + __blen, __bend); 00483 if (__r != codecvt_base::error) 00484 { 00485 __rlen = __bend - __buf; 00486 __elen = _M_file.xsputn(__buf, __rlen); 00487 __plen = __rlen; 00488 } 00489 else 00490 __throw_ios_failure(__N("basic_filebuf::_M_convert_to_external " 00491 "conversion error")); 00492 } 00493 } 00494 return __elen == __plen; 00495 } 00496 00497 template<typename _CharT, typename _Traits> 00498 streamsize 00499 basic_filebuf<_CharT, _Traits>:: 00500 xsputn(const _CharT* __s, streamsize __n) 00501 { 00502 // Optimization in the always_noconv() case, to be generalized in the 00503 // future: when __n is sufficiently large we write directly instead of 00504 // using the buffer. 00505 streamsize __ret = 0; 00506 const bool __testout = this->_M_mode & ios_base::out; 00507 if (__testout && !_M_reading 00508 && __check_facet(_M_codecvt).always_noconv()) 00509 { 00510 // Measurement would reveal the best choice. 00511 const streamsize __chunk = 1ul << 10; 00512 streamsize __bufavail = this->epptr() - this->pptr(); 00513 00514 // Don't mistake 'uncommitted' mode buffered with unbuffered. 00515 if (!_M_writing && this->_M_buf_size > 1) 00516 __bufavail = this->_M_buf_size - 1; 00517 00518 const streamsize __limit = std::min(__chunk, __bufavail); 00519 if (__n >= __limit) 00520 { 00521 const streamsize __buffill = this->pptr() - this->pbase(); 00522 const char* __buf = reinterpret_cast<const char*>(this->pbase()); 00523 __ret = _M_file.xsputn_2(__buf, __buffill, 00524 reinterpret_cast<const char*>(__s), 00525 __n); 00526 if (__ret == __buffill + __n) 00527 { 00528 _M_set_buffer(0); 00529 _M_writing = true; 00530 } 00531 if (__ret > __buffill) 00532 __ret -= __buffill; 00533 else 00534 __ret = 0; 00535 } 00536 else 00537 __ret = __streambuf_type::xsputn(__s, __n); 00538 } 00539 else 00540 __ret = __streambuf_type::xsputn(__s, __n); 00541 return __ret; 00542 } 00543 00544 template<typename _CharT, typename _Traits> 00545 typename basic_filebuf<_CharT, _Traits>::__streambuf_type* 00546 basic_filebuf<_CharT, _Traits>:: 00547 setbuf(char_type* __s, streamsize __n) 00548 { 00549 if (!this->is_open()) 00550 if (__s == 0 && __n == 0) 00551 this->_M_buf_size = 1; 00552 else if (__s && __n > 0) 00553 { 00554 // This is implementation-defined behavior, and assumes that 00555 // an external char_type array of length __n exists and has 00556 // been pre-allocated. If this is not the case, things will 00557 // quickly blow up. When __n > 1, __n - 1 positions will be 00558 // used for the get area, __n - 1 for the put area and 1 00559 // position to host the overflow char of a full put area. 00560 // When __n == 1, 1 position will be used for the get area 00561 // and 0 for the put area, as in the unbuffered case above. 00562 this->_M_buf = __s; 00563 this->_M_buf_size = __n; 00564 } 00565 return this; 00566 } 00567 00568 00569 // According to 27.8.1.4 p11 - 13, seekoff should ignore the last 00570 // argument (of type openmode). 00571 template<typename _CharT, typename _Traits> 00572 typename basic_filebuf<_CharT, _Traits>::pos_type 00573 basic_filebuf<_CharT, _Traits>:: 00574 seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode) 00575 { 00576 int __width = 0; 00577 if (_M_codecvt) 00578 __width = _M_codecvt->encoding(); 00579 if (__width < 0) 00580 __width = 0; 00581 00582 pos_type __ret = pos_type(off_type(-1)); 00583 const bool __testfail = __off != 0 && __width <= 0; 00584 if (this->is_open() && !__testfail) 00585 { 00586 // Ditch any pback buffers to avoid confusion. 00587 _M_destroy_pback(); 00588 00589 // Correct state at destination. Note that this is the correct 00590 // state for the current position during output, because 00591 // codecvt::unshift() returns the state to the initial state. 00592 // This is also the correct state at the end of the file because 00593 // an unshift sequence should have been written at the end. 00594 __state_type __state = _M_state_beg; 00595 off_type __computed_off = __off * __width; 00596 if (_M_reading && __way == ios_base::cur) 00597 { 00598 if (_M_codecvt->always_noconv()) 00599 __computed_off += this->gptr() - this->egptr(); 00600 else 00601 { 00602 // Calculate offset from _M_ext_buf that corresponds 00603 // to gptr(). Note: uses _M_state_last, which 00604 // corresponds to eback(). 00605 const int __gptr_off = 00606 _M_codecvt->length(_M_state_last, _M_ext_buf, _M_ext_next, 00607 this->gptr() - this->eback()); 00608 __computed_off += _M_ext_buf + __gptr_off - _M_ext_end; 00609 00610 // _M_state_last is modified by codecvt::length() so 00611 // it now corresponds to gptr(). 00612 __state = _M_state_last; 00613 } 00614 } 00615 __ret = _M_seek(__computed_off, __way, __state); 00616 } 00617 return __ret; 00618 } 00619 00620 // _GLIBCXX_RESOLVE_LIB_DEFECTS 00621 // 171. Strange seekpos() semantics due to joint position 00622 // According to the resolution of DR 171, seekpos should ignore the last 00623 // argument (of type openmode). 00624 template<typename _CharT, typename _Traits> 00625 typename basic_filebuf<_CharT, _Traits>::pos_type 00626 basic_filebuf<_CharT, _Traits>:: 00627 seekpos(pos_type __pos, ios_base::openmode) 00628 { 00629 pos_type __ret = pos_type(off_type(-1)); 00630 if (this->is_open()) 00631 { 00632 // Ditch any pback buffers to avoid confusion. 00633 _M_destroy_pback(); 00634 __ret = _M_seek(off_type(__pos), ios_base::beg, __pos.state()); 00635 } 00636 return __ret; 00637 } 00638 00639 template<typename _CharT, typename _Traits> 00640 typename basic_filebuf<_CharT, _Traits>::pos_type 00641 basic_filebuf<_CharT, _Traits>:: 00642 _M_seek(off_type __off, ios_base::seekdir __way, __state_type __state) 00643 { 00644 pos_type __ret = pos_type(off_type(-1)); 00645 if (_M_terminate_output()) 00646 { 00647 // Returns pos_type(off_type(-1)) in case of failure. 00648 __ret = pos_type(_M_file.seekoff(__off, __way)); 00649 _M_reading = false; 00650 _M_writing = false; 00651 _M_ext_next = _M_ext_end = _M_ext_buf; 00652 _M_set_buffer(-1); 00653 _M_state_cur = __state; 00654 __ret.state(_M_state_cur); 00655 } 00656 return __ret; 00657 } 00658 00659 template<typename _CharT, typename _Traits> 00660 bool 00661 basic_filebuf<_CharT, _Traits>:: 00662 _M_terminate_output() 00663 { 00664 // Part one: update the output sequence. 00665 bool __testvalid = true; 00666 if (this->pbase() < this->pptr()) 00667 { 00668 const int_type __tmp = this->overflow(); 00669 if (traits_type::eq_int_type(__tmp, traits_type::eof())) 00670 __testvalid = false; 00671 } 00672 00673 // Part two: output unshift sequence. 00674 if (_M_writing && !__check_facet(_M_codecvt).always_noconv() 00675 && __testvalid) 00676 { 00677 // Note: this value is arbitrary, since there is no way to 00678 // get the length of the unshift sequence from codecvt, 00679 // without calling unshift. 00680 const size_t __blen = 128; 00681 char __buf[__blen]; 00682 codecvt_base::result __r; 00683 streamsize __ilen = 0; 00684 00685 do 00686 { 00687 char* __next; 00688 __r = _M_codecvt->unshift(_M_state_cur, __buf, 00689 __buf + __blen, __next); 00690 if (__r == codecvt_base::error) 00691 __testvalid = false; 00692 else if (__r == codecvt_base::ok || 00693 __r == codecvt_base::partial) 00694 { 00695 __ilen = __next - __buf; 00696 if (__ilen > 0) 00697 { 00698 const streamsize __elen = _M_file.xsputn(__buf, __ilen); 00699 if (__elen != __ilen) 00700 __testvalid = false; 00701 } 00702 } 00703 } 00704 while (__r == codecvt_base::partial && __ilen > 0 && __testvalid); 00705 00706 if (__testvalid) 00707 { 00708 // This second call to overflow() is required by the standard, 00709 // but it's not clear why it's needed, since the output buffer 00710 // should be empty by this point (it should have been emptied 00711 // in the first call to overflow()). 00712 const int_type __tmp = this->overflow(); 00713 if (traits_type::eq_int_type(__tmp, traits_type::eof())) 00714 __testvalid = false; 00715 } 00716 } 00717 return __testvalid; 00718 } 00719 00720 template<typename _CharT, typename _Traits> 00721 int 00722 basic_filebuf<_CharT, _Traits>:: 00723 sync() 00724 { 00725 // Make sure that the internal buffer resyncs its idea of 00726 // the file position with the external file. 00727 // NB: _M_file.sync() will be called within. 00728 int __ret = 0; 00729 if (this->pbase() < this->pptr()) 00730 { 00731 const int_type __tmp = this->overflow(); 00732 if (traits_type::eq_int_type(__tmp, traits_type::eof())) 00733 __ret = -1; 00734 } 00735 return __ret; 00736 } 00737 00738 template<typename _CharT, typename _Traits> 00739 void 00740 basic_filebuf<_CharT, _Traits>:: 00741 imbue(const locale& __loc) 00742 { 00743 bool __testvalid = true; 00744 00745 const __codecvt_type* _M_codecvt_tmp = 0; 00746 if (__builtin_expect(has_facet<__codecvt_type>(__loc), true)) 00747 _M_codecvt_tmp = &use_facet<__codecvt_type>(__loc); 00748 00749 if (this->is_open()) 00750 { 00751 // encoding() == -1 is ok only at the beginning. 00752 if ((_M_reading || _M_writing) 00753 && __check_facet(_M_codecvt).encoding() == -1) 00754 __testvalid = false; 00755 else 00756 { 00757 if (_M_reading) 00758 { 00759 if (__check_facet(_M_codecvt).always_noconv()) 00760 { 00761 if (_M_codecvt_tmp 00762 && !__check_facet(_M_codecvt_tmp).always_noconv()) 00763 __testvalid = this->seekoff(0, ios_base::cur, this->_M_mode) 00764 != pos_type(off_type(-1)); 00765 } 00766 else 00767 { 00768 // External position corresponding to gptr(). 00769 _M_ext_next = _M_ext_buf 00770 + _M_codecvt->length(_M_state_last, _M_ext_buf, _M_ext_next, 00771 this->gptr() - this->eback()); 00772 const streamsize __remainder = _M_ext_end - _M_ext_next; 00773 if (__remainder) 00774 std::memmove(_M_ext_buf, _M_ext_next, __remainder); 00775 00776 _M_ext_next = _M_ext_buf; 00777 _M_ext_end = _M_ext_buf + __remainder; 00778 _M_set_buffer(-1); 00779 _M_state_last = _M_state_cur = _M_state_beg; 00780 } 00781 } 00782 else if (_M_writing && (__testvalid = _M_terminate_output())) 00783 _M_set_buffer(-1); 00784 } 00785 } 00786 00787 if (__testvalid) 00788 _M_codecvt = _M_codecvt_tmp; 00789 else 00790 _M_codecvt = 0; 00791 } 00792 00793 // Inhibit implicit instantiations for required instantiations, 00794 // which are defined via explicit instantiations elsewhere. 00795 // NB: This syntax is a GNU extension. 00796 #if _GLIBCXX_EXTERN_TEMPLATE 00797 extern template class basic_filebuf<char>; 00798 extern template class basic_ifstream<char>; 00799 extern template class basic_ofstream<char>; 00800 extern template class basic_fstream<char>; 00801 00802 #ifdef _GLIBCXX_USE_WCHAR_T 00803 extern template class basic_filebuf<wchar_t>; 00804 extern template class basic_ifstream<wchar_t>; 00805 extern template class basic_ofstream<wchar_t>; 00806 extern template class basic_fstream<wchar_t>; 00807 #endif 00808 #endif 00809 } // namespace std 00810 00811 #endif

Generated on Wed Jun 9 11:18:26 2004 for libstdc++-v3 Source by doxygen 1.3.7