fstream.tcc revision 117397
1// File based streams -*- C++ -*- 2 3// Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003 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 _CPP_BITS_FSTREAM_TCC 36#define _CPP_BITS_FSTREAM_TCC 1 37 38#pragma GCC system_header 39 40namespace std 41{ 42 template<typename _CharT, typename _Traits> 43 void 44 basic_filebuf<_CharT, _Traits>:: 45 _M_allocate_internal_buffer() 46 { 47 if (!_M_buf && _M_buf_size_opt) 48 { 49 _M_buf_size = _M_buf_size_opt; 50 51 // Allocate internal buffer. 52 _M_buf = new char_type[_M_buf_size]; 53 _M_buf_allocated = true; 54 } 55 } 56 57 // Both close and setbuf need to deallocate internal buffers, if it exists. 58 template<typename _CharT, typename _Traits> 59 void 60 basic_filebuf<_CharT, _Traits>:: 61 _M_destroy_internal_buffer() throw() 62 { 63 if (_M_buf_allocated) 64 { 65 delete [] _M_buf; 66 _M_buf = NULL; 67 _M_buf_allocated = false; 68 this->setg(NULL, NULL, NULL); 69 this->setp(NULL, NULL); 70 } 71 } 72 73 template<typename _CharT, typename _Traits> 74 basic_filebuf<_CharT, _Traits>:: 75 basic_filebuf() : __streambuf_type(), _M_file(&_M_lock), 76 _M_state_cur(__state_type()), _M_state_beg(__state_type()), 77 _M_buf_allocated(false), _M_last_overflowed(false) 78 { _M_buf_unified = true; } 79 80 template<typename _CharT, typename _Traits> 81 typename basic_filebuf<_CharT, _Traits>::__filebuf_type* 82 basic_filebuf<_CharT, _Traits>:: 83 open(const char* __s, ios_base::openmode __mode) 84 { 85 __filebuf_type *__ret = NULL; 86 if (!this->is_open()) 87 { 88 _M_file.open(__s, __mode); 89 if (this->is_open()) 90 { 91 _M_allocate_internal_buffer(); 92 _M_mode = __mode; 93 94 // Setup initial position of buffer. 95 _M_set_indeterminate(); 96 97 if ((__mode & ios_base::ate) 98 && this->seekoff(0, ios_base::end, __mode) < 0) 99 { 100 // 27.8.1.3,4 101 this->close(); 102 return __ret; 103 } 104 105 __ret = this; 106 } 107 } 108 return __ret; 109 } 110 111 template<typename _CharT, typename _Traits> 112 typename basic_filebuf<_CharT, _Traits>::__filebuf_type* 113 basic_filebuf<_CharT, _Traits>:: 114 close() throw() 115 { 116 __filebuf_type* __ret = NULL; 117 if (this->is_open()) 118 { 119 bool __testfail = false; 120 try 121 { 122 const int_type __eof = traits_type::eof(); 123 bool __testput = _M_out_cur && _M_out_beg < _M_out_end; 124 if (__testput 125 && traits_type::eq_int_type(_M_really_overflow(__eof), 126 __eof)) 127 __testfail = true; 128 129#if 0 130 // XXX not done 131 if (_M_last_overflowed) 132 { 133 _M_output_unshift(); 134 _M_really_overflow(__eof); 135 } 136#endif 137 } 138 catch(...) 139 { 140 __testfail = true; 141 } 142 143 // NB: Do this here so that re-opened filebufs will be cool... 144 this->_M_mode = ios_base::openmode(0); 145 _M_destroy_internal_buffer(); 146 _M_pback_destroy(); 147 148 if (!_M_file.close()) 149 __testfail = true; 150 151 if (!__testfail) 152 __ret = this; 153 } 154 _M_last_overflowed = false; 155 return __ret; 156 } 157 158 template<typename _CharT, typename _Traits> 159 streamsize 160 basic_filebuf<_CharT, _Traits>:: 161 showmanyc() 162 { 163 streamsize __ret = -1; 164 bool __testin = _M_mode & ios_base::in; 165 const locale __loc = this->getloc(); 166 const __codecvt_type& __cvt = use_facet<__codecvt_type>(__loc); 167 168 if (__testin && this->is_open()) 169 { 170 __ret = _M_in_end - _M_in_cur; 171 if (__cvt.always_noconv()) 172 __ret += _M_file.showmanyc_helper(); 173 } 174 175 _M_last_overflowed = false; 176 return __ret; 177 } 178 179 template<typename _CharT, typename _Traits> 180 typename basic_filebuf<_CharT, _Traits>::int_type 181 basic_filebuf<_CharT, _Traits>:: 182 pbackfail(int_type __i) 183 { 184 int_type __ret = traits_type::eof(); 185 bool __testin = _M_mode & ios_base::in; 186 187 if (__testin) 188 { 189 bool __testpb = _M_in_beg < _M_in_cur; 190 char_type __c = traits_type::to_char_type(__i); 191 bool __testeof = traits_type::eq_int_type(__i, __ret); 192 193 if (__testpb) 194 { 195 bool __testout = _M_mode & ios_base::out; 196 bool __testeq = traits_type::eq(__c, this->gptr()[-1]); 197 198 // Try to put back __c into input sequence in one of three ways. 199 // Order these tests done in is unspecified by the standard. 200 if (!__testeof && __testeq) 201 { 202 --_M_in_cur; 203 if (__testout) 204 --_M_out_cur; 205 __ret = __i; 206 } 207 else if (__testeof) 208 { 209 --_M_in_cur; 210 if (__testout) 211 --_M_out_cur; 212 __ret = traits_type::not_eof(__i); 213 } 214 else if (!__testeof) 215 { 216 --_M_in_cur; 217 if (__testout) 218 --_M_out_cur; 219 _M_pback_create(); 220 *_M_in_cur = __c; 221 __ret = __i; 222 } 223 } 224 else 225 { 226 // At the beginning of the buffer, need to make a 227 // putback position available. 228 // But the seek may fail (f.i., at the beginning of 229 // a file, see libstdc++/9439) and in that case 230 // we return traits_type::eof() 231 if (this->seekoff(-1, ios_base::cur) >= 0) 232 { 233 this->underflow(); 234 if (!__testeof) 235 { 236 if (!traits_type::eq(__c, *_M_in_cur)) 237 { 238 _M_pback_create(); 239 *_M_in_cur = __c; 240 } 241 __ret = __i; 242 } 243 else 244 __ret = traits_type::not_eof(__i); 245 } 246 } 247 } 248 _M_last_overflowed = false; 249 return __ret; 250 } 251 252 template<typename _CharT, typename _Traits> 253 typename basic_filebuf<_CharT, _Traits>::int_type 254 basic_filebuf<_CharT, _Traits>:: 255 overflow(int_type __c) 256 { 257 int_type __ret = traits_type::eof(); 258 bool __testput = _M_out_cur && _M_out_cur < _M_buf + _M_buf_size; 259 bool __testout = _M_mode & ios_base::out; 260 261 if (__testout) 262 { 263 if (traits_type::eq_int_type(__c, traits_type::eof())) 264 __ret = traits_type::not_eof(__c); 265 else if (__testput) 266 { 267 *_M_out_cur = traits_type::to_char_type(__c); 268 _M_out_cur_move(1); 269 __ret = traits_type::not_eof(__c); 270 } 271 else 272 __ret = this->_M_really_overflow(__c); 273 } 274 275 _M_last_overflowed = false; // Set in _M_really_overflow, below. 276 return __ret; 277 } 278 279 template<typename _CharT, typename _Traits> 280 void 281 basic_filebuf<_CharT, _Traits>:: 282 _M_convert_to_external(_CharT* __ibuf, streamsize __ilen, 283 streamsize& __elen, streamsize& __plen) 284 { 285 const locale __loc = this->getloc(); 286 const __codecvt_type& __cvt = use_facet<__codecvt_type>(__loc); 287 288 if (__cvt.always_noconv() && __ilen) 289 { 290 __elen += _M_file.xsputn(reinterpret_cast<char*>(__ibuf), __ilen); 291 __plen += __ilen; 292 } 293 else 294 { 295 // Worst-case number of external bytes needed. 296 int __ext_multiplier = __cvt.encoding(); 297 if (__ext_multiplier == -1 || __ext_multiplier == 0) 298 __ext_multiplier = sizeof(char_type); 299 streamsize __blen = __ilen * __ext_multiplier; 300 char* __buf = static_cast<char*>(__builtin_alloca(__blen)); 301 char* __bend; 302 const char_type* __iend; 303 codecvt_base::result __r; 304 __r = __cvt.out(_M_state_cur, __ibuf, __ibuf + __ilen, 305 __iend, __buf, __buf + __blen, __bend); 306 307 if (__r == codecvt_base::ok || __r == codecvt_base::partial) 308 __blen = __bend - __buf; 309 else if (__r == codecvt_base::noconv) 310 { 311 // Same as the always_noconv case above. 312 __buf = reinterpret_cast<char*>(__ibuf); 313 __blen = __ilen; 314 } 315 else 316 { 317 // Result == error 318 __blen = 0; 319 } 320 321 if (__blen) 322 { 323 __elen += _M_file.xsputn(__buf, __blen); 324 __plen += __blen; 325 } 326 327 // Try once more for partial conversions. 328 if (__r == codecvt_base::partial) 329 { 330 const char_type* __iresume = __iend; 331 streamsize __rlen = _M_out_end - __iend; 332 __r = __cvt.out(_M_state_cur, __iresume, __iresume + __rlen, 333 __iend, __buf, __buf + __blen, __bend); 334 if (__r != codecvt_base::error) 335 { 336 __rlen = __bend - __buf; 337 __elen += _M_file.xsputn(__buf, __rlen); 338 __plen += __rlen; 339 } 340 } 341 } 342 } 343 344 template<typename _CharT, typename _Traits> 345 typename basic_filebuf<_CharT, _Traits>::int_type 346 basic_filebuf<_CharT, _Traits>:: 347 _M_really_overflow(int_type __c) 348 { 349 int_type __ret = traits_type::eof(); 350 bool __testput = _M_out_cur && _M_out_beg < _M_out_end; 351 bool __testunbuffered = _M_file.is_open() && !_M_buf_size; 352 353 if (__testput || __testunbuffered) 354 { 355 // Sizes of external and pending output. 356 streamsize __elen = 0; 357 streamsize __plen = 0; 358 359 // Need to restore current position. The position of the external 360 // byte sequence (_M_file) corresponds to _M_filepos, and we need 361 // to move it to _M_out_beg for the write. 362 if (_M_filepos && _M_filepos != _M_out_beg) 363 { 364 off_type __off = _M_out_beg - _M_filepos; 365 _M_file.seekoff(__off, ios_base::cur); 366 } 367 368 // Convert internal buffer to external representation, output. 369 // NB: In the unbuffered case, no internal buffer exists. 370 if (!__testunbuffered) 371 _M_convert_to_external(_M_out_beg, _M_out_end - _M_out_beg, 372 __elen, __plen); 373 374 // Checks for codecvt.out failures and _M_file.xsputn failures, 375 // respectively, inside _M_convert_to_external. 376 if (__testunbuffered || (__elen && __elen == __plen)) 377 { 378 // Convert pending sequence to external representation, output. 379 // If eof, then just attempt sync. 380 if (!traits_type::eq_int_type(__c, traits_type::eof())) 381 { 382 char_type __pending = traits_type::to_char_type(__c); 383 _M_convert_to_external(&__pending, 1, __elen, __plen); 384 385 // User code must flush when switching modes (thus 386 // don't sync). 387 if (__elen == __plen && __elen) 388 { 389 _M_set_indeterminate(); 390 __ret = traits_type::not_eof(__c); 391 } 392 } 393 else if (!_M_file.sync()) 394 { 395 _M_set_indeterminate(); 396 __ret = traits_type::not_eof(__c); 397 } 398 } 399 } 400 _M_last_overflowed = true; 401 return __ret; 402 } 403 404 template<typename _CharT, typename _Traits> 405 typename basic_filebuf<_CharT, _Traits>::__streambuf_type* 406 basic_filebuf<_CharT, _Traits>:: 407 setbuf(char_type* __s, streamsize __n) 408 { 409 if (!this->is_open() && __s == 0 && __n == 0) 410 _M_buf_size_opt = 0; 411 else if (__s && __n) 412 { 413 // This is implementation-defined behavior, and assumes 414 // that an external char_type array of length (__s + __n) 415 // exists and has been pre-allocated. If this is not the 416 // case, things will quickly blow up. 417 // Step 1: Destroy the current internal array. 418 _M_destroy_internal_buffer(); 419 420 // Step 2: Use the external array. 421 _M_buf = __s; 422 _M_buf_size_opt = _M_buf_size = __n; 423 _M_set_indeterminate(); 424 } 425 _M_last_overflowed = false; 426 return this; 427 } 428 429 template<typename _CharT, typename _Traits> 430 typename basic_filebuf<_CharT, _Traits>::pos_type 431 basic_filebuf<_CharT, _Traits>:: 432 seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode __mode) 433 { 434 pos_type __ret = pos_type(off_type(-1)); 435 bool __testin = (ios_base::in & _M_mode & __mode) != 0; 436 bool __testout = (ios_base::out & _M_mode & __mode) != 0; 437 438 int __width = 0; 439 if (has_facet<__codecvt_type>(this->_M_buf_locale)) 440 __width = use_facet<__codecvt_type>(this->_M_buf_locale).encoding(); 441 if (__width < 0) 442 __width = 0; 443 444 bool __testfail = __off != 0 && __width <= 0; 445 if (this->is_open() && !__testfail && (__testin || __testout)) 446 { 447 // Ditch any pback buffers to avoid confusion. 448 _M_pback_destroy(); 449 450 if (__way != ios_base::cur || __off != 0) 451 { 452 off_type __computed_off = __width * __off; 453 454 bool __testget = _M_in_cur && _M_in_beg < _M_in_end; 455 bool __testput = _M_out_cur && _M_out_beg < _M_out_end; 456 // Sync the internal and external streams. 457 // out 458 if (__testput || _M_last_overflowed) 459 { 460 // Part one: update the output sequence. 461 this->sync(); 462 // Part two: output unshift sequence. 463 _M_output_unshift(); 464 } 465 //in 466 else if (__testget && __way == ios_base::cur) 467 __computed_off += _M_in_cur - _M_filepos; 468 469 // Return pos_type(off_type(-1)) in case of failure. 470 __ret = _M_file.seekoff(__computed_off, __way, __mode); 471 _M_set_indeterminate(); 472 } 473 // NB: Need to do this in case _M_file in indeterminate 474 // state, ie _M_file._offset == -1 475 else 476 { 477 pos_type __tmp = 478 _M_file.seekoff(__off, ios_base::cur, __mode); 479 if (__tmp >= 0) 480 { 481 // Seek successful. 482 __ret = __tmp; 483 __ret += max(_M_out_cur, _M_in_cur) - _M_filepos; 484 } 485 } 486 } 487 _M_last_overflowed = false; 488 return __ret; 489 } 490 491 template<typename _CharT, typename _Traits> 492 typename basic_filebuf<_CharT, _Traits>::pos_type 493 basic_filebuf<_CharT, _Traits>:: 494 seekpos(pos_type __pos, ios_base::openmode __mode) 495 { 496#ifdef _GLIBCPP_RESOLVE_LIB_DEFECTS 497// 171. Strange seekpos() semantics due to joint position 498 return this->seekoff(off_type(__pos), ios_base::beg, __mode); 499#endif 500 } 501 502 template<typename _CharT, typename _Traits> 503 void 504 basic_filebuf<_CharT, _Traits>:: 505 _M_output_unshift() 506 { } 507 508 template<typename _CharT, typename _Traits> 509 void 510 basic_filebuf<_CharT, _Traits>:: 511 imbue(const locale& __loc) 512 { 513 bool __testbeg = gptr() == eback() && pptr() == pbase(); 514 515 if (__testbeg && _M_buf_locale != __loc) 516 _M_buf_locale = __loc; 517 518 // NB this may require the reconversion of previously 519 // converted chars. This in turn may cause the reconstruction 520 // of the original file. YIKES!! 521 // XXX The part in the above comment is not done. 522 _M_last_overflowed = false; 523 } 524 525 // Inhibit implicit instantiations for required instantiations, 526 // which are defined via explicit instantiations elsewhere. 527 // NB: This syntax is a GNU extension. 528#if _GLIBCPP_EXTERN_TEMPLATE 529 extern template class basic_filebuf<char>; 530 extern template class basic_ifstream<char>; 531 extern template class basic_ofstream<char>; 532 extern template class basic_fstream<char>; 533 534#ifdef _GLIBCPP_USE_WCHAR_T 535 extern template class basic_filebuf<wchar_t>; 536 extern template class basic_ifstream<wchar_t>; 537 extern template class basic_ofstream<wchar_t>; 538 extern template class basic_fstream<wchar_t>; 539#endif 540#endif 541} // namespace std 542 543#endif 544