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