| 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>::
|
|---|
| 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;
|
|---|
|
|---|