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