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