| 1 | // File based streams -*- C++ -*- | 
| 2 |  | 
| 3 | // Copyright (C) 1997-2019 Free Software Foundation, Inc. | 
| 4 | // | 
| 5 | // This file is part of the GNU ISO C++ Library.  This library is free | 
| 6 | // software; you can redistribute it and/or modify it under the | 
| 7 | // terms of the GNU General Public License as published by the | 
| 8 | // Free Software Foundation; either version 3, or (at your option) | 
| 9 | // any later version. | 
| 10 |  | 
| 11 | // This library is distributed in the hope that it will be useful, | 
| 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
| 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
| 14 | // GNU General Public License for more details. | 
| 15 |  | 
| 16 | // Under Section 7 of GPL version 3, you are granted additional | 
| 17 | // permissions described in the GCC Runtime Library Exception, version | 
| 18 | // 3.1, as published by the Free Software Foundation. | 
| 19 |  | 
| 20 | // You should have received a copy of the GNU General Public License and | 
| 21 | // a copy of the GCC Runtime Library Exception along with this program; | 
| 22 | // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see | 
| 23 | // <http://www.gnu.org/licenses/>. | 
| 24 |  | 
| 25 | /** @file bits/fstream.tcc | 
| 26 |  *  This is an internal header file, included by other library headers. | 
| 27 |  *  Do not attempt to use it directly. @headername{fstream} | 
| 28 |  */ | 
| 29 |  | 
| 30 | // | 
| 31 | // ISO C++ 14882: 27.8  File-based streams | 
| 32 | // | 
| 33 |  | 
| 34 | #ifndef _FSTREAM_TCC | 
| 35 | #define _FSTREAM_TCC 1 | 
| 36 |  | 
| 37 | #pragma GCC system_header | 
| 38 |  | 
| 39 | #include <bits/cxxabi_forced.h> | 
| 40 | #include <bits/move.h>   // for swap | 
| 41 | #include <cerrno> | 
| 42 |  | 
| 43 | namespace std _GLIBCXX_VISIBILITY(default) | 
| 44 | { | 
| 45 | _GLIBCXX_BEGIN_NAMESPACE_VERSION | 
| 46 |  | 
| 47 |   template<typename _CharT, typename _Traits> | 
| 48 |     void | 
| 49 |     basic_filebuf<_CharT, _Traits>:: | 
| 50 |     _M_allocate_internal_buffer() | 
| 51 |     { | 
| 52 |       // Allocate internal buffer only if one doesn't already exist | 
| 53 |       // (either allocated or provided by the user via setbuf). | 
| 54 |       if (!_M_buf_allocated && !_M_buf) | 
| 55 | 	{ | 
| 56 | 	  _M_buf = new char_type[_M_buf_size]; | 
| 57 | 	  _M_buf_allocated = true; | 
| 58 | 	} | 
| 59 |     } | 
| 60 |  | 
| 61 |   template<typename _CharT, typename _Traits> | 
| 62 |     void | 
| 63 |     basic_filebuf<_CharT, _Traits>:: | 
| 64 |     _M_destroy_internal_buffer() throw() | 
| 65 |     { | 
| 66 |       if (_M_buf_allocated) | 
| 67 | 	{ | 
| 68 | 	  delete [] _M_buf; | 
| 69 | 	  _M_buf = 0; | 
| 70 | 	  _M_buf_allocated = false; | 
| 71 | 	} | 
| 72 |       delete [] _M_ext_buf; | 
| 73 |       _M_ext_buf = 0; | 
| 74 |       _M_ext_buf_size = 0; | 
| 75 |       _M_ext_next = 0; | 
| 76 |       _M_ext_end = 0; | 
| 77 |     } | 
| 78 |  | 
| 79 |   template<typename _CharT, typename _Traits> | 
| 80 |     basic_filebuf<_CharT, _Traits>:: | 
| 81 |     basic_filebuf() : __streambuf_type(), _M_lock(), _M_file(&_M_lock), | 
| 82 |     _M_mode(ios_base::openmode(0)), _M_state_beg(), _M_state_cur(), | 
| 83 |     _M_state_last(), _M_buf(0), _M_buf_size(BUFSIZ), | 
| 84 |     _M_buf_allocated(false), _M_reading(false), _M_writing(false), _M_pback(),  | 
| 85 |     _M_pback_cur_save(0), _M_pback_end_save(0), _M_pback_init(false), | 
| 86 |     _M_codecvt(0), _M_ext_buf(0), _M_ext_buf_size(0), _M_ext_next(0), | 
| 87 |     _M_ext_end(0) | 
| 88 |     { | 
| 89 |       if (has_facet<__codecvt_type>(this->_M_buf_locale)) | 
| 90 | 	_M_codecvt = &use_facet<__codecvt_type>(this->_M_buf_locale); | 
| 91 |     } | 
| 92 |  | 
| 93 | #if __cplusplus >= 201103L | 
| 94 |   template<typename _CharT, typename _Traits> | 
| 95 |     basic_filebuf<_CharT, _Traits>:: | 
| 96 |     basic_filebuf(basic_filebuf&& __rhs) | 
| 97 |     : __streambuf_type(__rhs), | 
| 98 |     _M_lock(), _M_file(std::move(__rhs._M_file), &_M_lock), | 
| 99 |     _M_mode(std::__exchange(__rhs._M_mode, ios_base::openmode(0))), | 
| 100 |     _M_state_beg(std::move(__rhs._M_state_beg)), | 
| 101 |     _M_state_cur(std::move(__rhs._M_state_cur)), | 
| 102 |     _M_state_last(std::move(__rhs._M_state_last)), | 
| 103 |     _M_buf(std::__exchange(__rhs._M_buf, nullptr)), | 
| 104 |     _M_buf_size(std::__exchange(__rhs._M_buf_size, 1)), | 
| 105 |     _M_buf_allocated(std::__exchange(__rhs._M_buf_allocated, false)), | 
| 106 |     _M_reading(std::__exchange(__rhs._M_reading, false)), | 
| 107 |     _M_writing(std::__exchange(__rhs._M_writing, false)), | 
| 108 |     _M_pback(__rhs._M_pback), | 
| 109 |     _M_pback_cur_save(std::__exchange(__rhs._M_pback_cur_save, nullptr)), | 
| 110 |     _M_pback_end_save(std::__exchange(__rhs._M_pback_end_save, nullptr)), | 
| 111 |     _M_pback_init(std::__exchange(__rhs._M_pback_init, false)), | 
| 112 |     _M_codecvt(__rhs._M_codecvt), | 
| 113 |     _M_ext_buf(std::__exchange(__rhs._M_ext_buf, nullptr)), | 
| 114 |     _M_ext_buf_size(std::__exchange(__rhs._M_ext_buf_size, 0)), | 
| 115 |     _M_ext_next(std::__exchange(__rhs._M_ext_next, nullptr)), | 
| 116 |     _M_ext_end(std::__exchange(__rhs._M_ext_end, nullptr)) | 
| 117 |     { | 
| 118 |       __rhs._M_set_buffer(-1); | 
| 119 |       __rhs._M_state_last = __rhs._M_state_cur = __rhs._M_state_beg; | 
| 120 |     } | 
| 121 |  | 
| 122 |   template<typename _CharT, typename _Traits> | 
| 123 |     basic_filebuf<_CharT, _Traits>& | 
| 124 |     basic_filebuf<_CharT, _Traits>:: | 
| 125 |     operator=(basic_filebuf&& __rhs) | 
| 126 |     { | 
| 127 |       this->close(); | 
| 128 |       __streambuf_type::operator=(__rhs); | 
| 129 |       _M_file.swap(__rhs._M_file); | 
| 130 |       _M_mode = std::__exchange(__rhs._M_mode, ios_base::openmode(0)); | 
| 131 |       _M_state_beg = std::move(__rhs._M_state_beg); | 
| 132 |       _M_state_cur = std::move(__rhs._M_state_cur); | 
| 133 |       _M_state_last = std::move(__rhs._M_state_last); | 
| 134 |       _M_buf = std::__exchange(__rhs._M_buf, nullptr); | 
| 135 |       _M_buf_size = std::__exchange(__rhs._M_buf_size, 1); | 
| 136 |       _M_buf_allocated = std::__exchange(__rhs._M_buf_allocated, false); | 
| 137 |       _M_ext_buf = std::__exchange(__rhs._M_ext_buf, nullptr); | 
| 138 |       _M_ext_buf_size = std::__exchange(__rhs._M_ext_buf_size, 0); | 
| 139 |       _M_ext_next = std::__exchange(__rhs._M_ext_next, nullptr); | 
| 140 |       _M_ext_end = std::__exchange(__rhs._M_ext_end, nullptr); | 
| 141 |       _M_reading = std::__exchange(__rhs._M_reading, false); | 
| 142 |       _M_writing = std::__exchange(__rhs._M_writing, false); | 
| 143 |       _M_pback_cur_save = std::__exchange(__rhs._M_pback_cur_save, nullptr); | 
| 144 |       _M_pback_end_save = std::__exchange(__rhs._M_pback_end_save, nullptr); | 
| 145 |       _M_pback_init = std::__exchange(__rhs._M_pback_init, false); | 
| 146 |       __rhs._M_set_buffer(-1); | 
| 147 |       __rhs._M_state_last = __rhs._M_state_cur = __rhs._M_state_beg; | 
| 148 |       return *this; | 
| 149 |     } | 
| 150 |  | 
| 151 |   template<typename _CharT, typename _Traits> | 
| 152 |     void | 
| 153 |     basic_filebuf<_CharT, _Traits>:: | 
| 154 |     swap(basic_filebuf& __rhs) | 
| 155 |     { | 
| 156 |       __streambuf_type::swap(__rhs); | 
| 157 |       _M_file.swap(__rhs._M_file); | 
| 158 |       std::swap(_M_mode, __rhs._M_mode); | 
| 159 |       std::swap(_M_state_beg, __rhs._M_state_beg); | 
| 160 |       std::swap(_M_state_cur, __rhs._M_state_cur); | 
| 161 |       std::swap(_M_state_last, __rhs._M_state_last); | 
| 162 |       std::swap(_M_buf, __rhs._M_buf); | 
| 163 |       std::swap(_M_buf_size, __rhs._M_buf_size); | 
| 164 |       std::swap(_M_buf_allocated, __rhs._M_buf_allocated); | 
| 165 |       std::swap(_M_ext_buf, __rhs._M_ext_buf); | 
| 166 |       std::swap(_M_ext_buf_size, __rhs._M_ext_buf_size); | 
| 167 |       std::swap(_M_ext_next, __rhs._M_ext_next); | 
| 168 |       std::swap(_M_ext_end, __rhs._M_ext_end); | 
| 169 |       std::swap(_M_reading, __rhs._M_reading); | 
| 170 |       std::swap(_M_writing, __rhs._M_writing); | 
| 171 |       std::swap(_M_pback_cur_save, __rhs._M_pback_cur_save); | 
| 172 |       std::swap(_M_pback_end_save, __rhs._M_pback_end_save); | 
| 173 |       std::swap(_M_pback_init, __rhs._M_pback_init); | 
| 174 |     } | 
| 175 | #endif | 
| 176 |  | 
| 177 |   template<typename _CharT, typename _Traits> | 
| 178 |     typename basic_filebuf<_CharT, _Traits>::__filebuf_type* | 
| 179 |     basic_filebuf<_CharT, _Traits>:: | 
| 180 |     open(const char* __s, ios_base::openmode __mode) | 
| 181 |     { | 
| 182 |       __filebuf_type *__ret = 0; | 
| 183 |       if (!this->is_open()) | 
| 184 | 	{ | 
| 185 | 	  _M_file.open(__s, __mode); | 
| 186 | 	  if (this->is_open()) | 
| 187 | 	    { | 
| 188 | 	      _M_allocate_internal_buffer(); | 
| 189 | 	      _M_mode = __mode; | 
| 190 |  | 
| 191 | 	      // Setup initial buffer to 'uncommitted' mode. | 
| 192 | 	      _M_reading = false; | 
| 193 | 	      _M_writing = false; | 
| 194 | 	      _M_set_buffer(-1); | 
| 195 |  | 
| 196 | 	      // Reset to initial state. | 
| 197 | 	      _M_state_last = _M_state_cur = _M_state_beg; | 
| 198 |  | 
| 199 | 	      // 27.8.1.3,4 | 
| 200 | 	      if ((__mode & ios_base::ate) | 
| 201 | 		  && this->seekoff(0, ios_base::end, __mode) | 
| 202 | 		  == pos_type(off_type(-1))) | 
| 203 | 		this->close(); | 
| 204 | 	      else | 
| 205 | 		__ret = this; | 
| 206 | 	    } | 
| 207 | 	} | 
| 208 |       return __ret; | 
| 209 |     } | 
| 210 |  | 
| 211 | #if _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T | 
| 212 |   template<typename _CharT, typename _Traits> | 
| 213 |     basic_filebuf<_CharT, _Traits>* | 
| 214 |     basic_filebuf<_CharT, _Traits>:: | 
| 215 |     open(const wchar_t* __s, ios_base::openmode __mode) | 
| 216 |     { | 
| 217 |       __filebuf_type *__ret = 0; | 
| 218 |       if (!this->is_open()) | 
| 219 | 	{ | 
| 220 | 	  _M_file.open(__s, __mode); | 
| 221 | 	  if (this->is_open()) | 
| 222 | 	    { | 
| 223 | 	      _M_allocate_internal_buffer(); | 
| 224 | 	      _M_mode = __mode; | 
| 225 |  | 
| 226 | 	      // Setup initial buffer to 'uncommitted' mode. | 
| 227 | 	      _M_reading = false; | 
| 228 | 	      _M_writing = false; | 
| 229 | 	      _M_set_buffer(-1); | 
| 230 |  | 
| 231 | 	      // Reset to initial state. | 
| 232 | 	      _M_state_last = _M_state_cur = _M_state_beg; | 
| 233 |  | 
| 234 | 	      // 27.8.1.3,4 | 
| 235 | 	      if ((__mode & ios_base::ate) | 
| 236 | 		  && this->seekoff(0, ios_base::end, __mode) | 
| 237 | 		  == pos_type(off_type(-1))) | 
| 238 | 		this->close(); | 
| 239 | 	      else | 
| 240 | 		__ret = this; | 
| 241 | 	    } | 
| 242 | 	} | 
| 243 |       return __ret; | 
| 244 |     } | 
| 245 | #endif // HAVE__WFOPEN && USE_WCHAR_T | 
| 246 |  | 
| 247 |   template<typename _CharT, typename _Traits> | 
| 248 |     typename basic_filebuf<_CharT, _Traits>::__filebuf_type* | 
| 249 |     basic_filebuf<_CharT, _Traits>:: | 
| 250 |     close() | 
| 251 |     { | 
| 252 |       if (!this->is_open()) | 
| 253 | 	return 0; | 
| 254 |  | 
| 255 |       bool __testfail = false; | 
| 256 |       { | 
| 257 | 	// NB: Do this here so that re-opened filebufs will be cool... | 
| 258 | 	struct __close_sentry | 
| 259 | 	{ | 
| 260 | 	  basic_filebuf *__fb; | 
| 261 | 	  __close_sentry (basic_filebuf *__fbi): __fb(__fbi) { } | 
| 262 | 	  ~__close_sentry () | 
| 263 | 	  { | 
| 264 | 	    __fb->_M_mode = ios_base::openmode(0); | 
| 265 | 	    __fb->_M_pback_init = false; | 
| 266 | 	    __fb->_M_destroy_internal_buffer(); | 
| 267 | 	    __fb->_M_reading = false; | 
| 268 | 	    __fb->_M_writing = false; | 
| 269 | 	    __fb->_M_set_buffer(-1); | 
| 270 | 	    __fb->_M_state_last = __fb->_M_state_cur = __fb->_M_state_beg; | 
| 271 | 	  } | 
| 272 | 	} __cs (this); | 
| 273 |  | 
| 274 | 	__try | 
| 275 | 	  { | 
| 276 | 	    if (!_M_terminate_output()) | 
| 277 | 	      __testfail = true; | 
| 278 | 	  } | 
| 279 | 	__catch(...) | 
| 280 | 	  { | 
| 281 | 	    _M_file.close(); | 
| 282 | 	    __throw_exception_again; | 
| 283 | 	  } | 
| 284 |       } | 
| 285 |  | 
| 286 |       if (!_M_file.close()) | 
| 287 | 	__testfail = true; | 
| 288 |  | 
| 289 |       if (__testfail) | 
| 290 | 	return 0; | 
| 291 |       else | 
| 292 | 	return this; | 
| 293 |     } | 
| 294 |  | 
| 295 |   template<typename _CharT, typename _Traits> | 
| 296 |     streamsize | 
| 297 |     basic_filebuf<_CharT, _Traits>:: | 
| 298 |     showmanyc() | 
| 299 |     { | 
| 300 |       streamsize __ret = -1; | 
| 301 |       const bool __testin = _M_mode & ios_base::in; | 
| 302 |       if (__testin && this->is_open()) | 
| 303 | 	{ | 
| 304 | 	  // For a stateful encoding (-1) the pending sequence might be just | 
| 305 | 	  // shift and unshift prefixes with no actual character. | 
| 306 | 	  __ret = this->egptr() - this->gptr(); | 
| 307 |  | 
| 308 | #if _GLIBCXX_HAVE_DOS_BASED_FILESYSTEM | 
| 309 | 	  // About this workaround, see libstdc++/20806. | 
| 310 | 	  const bool __testbinary = _M_mode & ios_base::binary; | 
| 311 | 	  if (__check_facet(_M_codecvt).encoding() >= 0 | 
| 312 | 	      && __testbinary) | 
| 313 | #else | 
| 314 | 	  if (__check_facet(_M_codecvt).encoding() >= 0) | 
| 315 | #endif | 
| 316 | 	    __ret += _M_file.showmanyc() / _M_codecvt->max_length(); | 
| 317 | 	} | 
| 318 |       return __ret; | 
| 319 |     } | 
| 320 |  | 
| 321 |   template<typename _CharT, typename _Traits> | 
| 322 |     typename basic_filebuf<_CharT, _Traits>::int_type | 
| 323 |     basic_filebuf<_CharT, _Traits>:: | 
| 324 |     underflow() | 
| 325 |     { | 
| 326 |       int_type __ret = traits_type::eof(); | 
| 327 |       const bool __testin = _M_mode & ios_base::in; | 
| 328 |       if (__testin) | 
| 329 | 	{ | 
| 330 | 	  if (_M_writing) | 
| 331 | 	    { | 
| 332 | 	      if (overflow() == traits_type::eof()) | 
| 333 | 		return __ret; | 
| 334 | 	      _M_set_buffer(-1); | 
| 335 | 	      _M_writing = false; | 
| 336 | 	    } | 
| 337 | 	  // Check for pback madness, and if so switch back to the | 
| 338 | 	  // normal buffers and jet outta here before expensive | 
| 339 | 	  // fileops happen... | 
| 340 | 	  _M_destroy_pback(); | 
| 341 |  | 
| 342 | 	  if (this->gptr() < this->egptr()) | 
| 343 | 	    return traits_type::to_int_type(*this->gptr()); | 
| 344 |  | 
| 345 | 	  // Get and convert input sequence. | 
| 346 | 	  const size_t __buflen = _M_buf_size > 1 ? _M_buf_size - 1 : 1; | 
| 347 |  | 
| 348 | 	  // Will be set to true if ::read() returns 0 indicating EOF. | 
| 349 | 	  bool __got_eof = false; | 
| 350 | 	  // Number of internal characters produced. | 
| 351 | 	  streamsize __ilen = 0; | 
| 352 | 	  codecvt_base::result __r = codecvt_base::ok; | 
| 353 | 	  if (__check_facet(_M_codecvt).always_noconv()) | 
| 354 | 	    { | 
| 355 | 	      __ilen = _M_file.xsgetn(reinterpret_cast<char*>(this->eback()), | 
| 356 | 				      __buflen); | 
| 357 | 	      if (__ilen == 0) | 
| 358 | 		__got_eof = true; | 
| 359 | 	    } | 
| 360 | 	  else | 
| 361 | 	    { | 
| 362 |               // Worst-case number of external bytes. | 
| 363 | 	      // XXX Not done encoding() == -1. | 
| 364 | 	      const int __enc = _M_codecvt->encoding(); | 
| 365 | 	      streamsize __blen; // Minimum buffer size. | 
| 366 | 	      streamsize __rlen; // Number of chars to read. | 
| 367 | 	      if (__enc > 0) | 
| 368 | 		__blen = __rlen = __buflen * __enc; | 
| 369 | 	      else | 
| 370 | 		{ | 
| 371 | 		  __blen = __buflen + _M_codecvt->max_length() - 1; | 
| 372 | 		  __rlen = __buflen; | 
| 373 | 		} | 
| 374 | 	      const streamsize __remainder = _M_ext_end - _M_ext_next; | 
| 375 | 	      __rlen = __rlen > __remainder ? __rlen - __remainder : 0; | 
| 376 |  | 
| 377 | 	      // An imbue in 'read' mode implies first converting the external | 
| 378 | 	      // chars already present. | 
| 379 | 	      if (_M_reading && this->egptr() == this->eback() && __remainder) | 
| 380 | 		__rlen = 0; | 
| 381 |  | 
| 382 | 	      // Allocate buffer if necessary and move unconverted | 
| 383 | 	      // bytes to front. | 
| 384 | 	      if (_M_ext_buf_size < __blen) | 
| 385 | 		{ | 
| 386 | 		  char* __buf = new char[__blen]; | 
| 387 | 		  if (__remainder) | 
| 388 | 		    __builtin_memcpy(__buf, _M_ext_next, __remainder); | 
| 389 |  | 
| 390 | 		  delete [] _M_ext_buf; | 
| 391 | 		  _M_ext_buf = __buf; | 
| 392 | 		  _M_ext_buf_size = __blen; | 
| 393 | 		} | 
| 394 | 	      else if (__remainder) | 
| 395 | 		__builtin_memmove(_M_ext_buf, _M_ext_next, __remainder); | 
| 396 |  | 
| 397 | 	      _M_ext_next = _M_ext_buf; | 
| 398 | 	      _M_ext_end = _M_ext_buf + __remainder; | 
| 399 | 	      _M_state_last = _M_state_cur; | 
| 400 |  | 
| 401 | 	      do | 
| 402 | 		{ | 
| 403 | 		  if (__rlen > 0) | 
| 404 | 		    { | 
| 405 | 		      // Sanity check! | 
| 406 | 		      // This may fail if the return value of | 
| 407 | 		      // codecvt::max_length() is bogus. | 
| 408 | 		      if (_M_ext_end - _M_ext_buf + __rlen > _M_ext_buf_size) | 
| 409 | 			{ | 
| 410 | 			  __throw_ios_failure(__N("basic_filebuf::underflow "  | 
| 411 | 					      "codecvt::max_length() "  | 
| 412 | 					      "is not valid" )); | 
| 413 | 			} | 
| 414 | 		      streamsize __elen = _M_file.xsgetn(_M_ext_end, __rlen); | 
| 415 | 		      if (__elen == 0) | 
| 416 | 			__got_eof = true; | 
| 417 | 		      else if (__elen == -1) | 
| 418 | 			break; | 
| 419 | 		      _M_ext_end += __elen; | 
| 420 | 		    } | 
| 421 |  | 
| 422 | 		  char_type* __iend = this->eback(); | 
| 423 | 		  if (_M_ext_next < _M_ext_end) | 
| 424 | 		    __r = _M_codecvt->in(_M_state_cur, _M_ext_next, | 
| 425 | 					 _M_ext_end, _M_ext_next, | 
| 426 | 					 this->eback(), | 
| 427 | 					 this->eback() + __buflen, __iend); | 
| 428 | 		  if (__r == codecvt_base::noconv) | 
| 429 | 		    { | 
| 430 | 		      size_t __avail = _M_ext_end - _M_ext_buf; | 
| 431 | 		      __ilen = std::min(__avail, __buflen); | 
| 432 | 		      traits_type::copy(this->eback(), | 
| 433 | 					reinterpret_cast<char_type*> | 
| 434 | 					(_M_ext_buf), __ilen); | 
| 435 | 		      _M_ext_next = _M_ext_buf + __ilen; | 
| 436 | 		    } | 
| 437 | 		  else | 
| 438 | 		    __ilen = __iend - this->eback(); | 
| 439 |  | 
| 440 | 		  // _M_codecvt->in may return error while __ilen > 0: this is | 
| 441 | 		  // ok, and actually occurs in case of mixed encodings (e.g., | 
| 442 | 		  // XML files). | 
| 443 | 		  if (__r == codecvt_base::error) | 
| 444 | 		    break; | 
| 445 |  | 
| 446 | 		  __rlen = 1; | 
| 447 | 		} | 
| 448 | 	      while (__ilen == 0 && !__got_eof); | 
| 449 | 	    } | 
| 450 |  | 
| 451 | 	  if (__ilen > 0) | 
| 452 | 	    { | 
| 453 | 	      _M_set_buffer(__ilen); | 
| 454 | 	      _M_reading = true; | 
| 455 | 	      __ret = traits_type::to_int_type(*this->gptr()); | 
| 456 | 	    } | 
| 457 | 	  else if (__got_eof) | 
| 458 | 	    { | 
| 459 | 	      // If the actual end of file is reached, set 'uncommitted' | 
| 460 | 	      // mode, thus allowing an immediate write without an | 
| 461 | 	      // intervening seek. | 
| 462 | 	      _M_set_buffer(-1); | 
| 463 | 	      _M_reading = false; | 
| 464 | 	      // However, reaching it while looping on partial means that | 
| 465 | 	      // the file has got an incomplete character. | 
| 466 | 	      if (__r == codecvt_base::partial) | 
| 467 | 		__throw_ios_failure(__N("basic_filebuf::underflow "  | 
| 468 | 				    "incomplete character in file" )); | 
| 469 | 	    } | 
| 470 | 	  else if (__r == codecvt_base::error) | 
| 471 | 	    __throw_ios_failure(__N("basic_filebuf::underflow "  | 
| 472 | 				"invalid byte sequence in file" )); | 
| 473 | 	  else | 
| 474 | 	    __throw_ios_failure(__N("basic_filebuf::underflow "  | 
| 475 | 				"error reading the file" ), errno); | 
| 476 | 	} | 
| 477 |       return __ret; | 
| 478 |     } | 
| 479 |  | 
| 480 |   template<typename _CharT, typename _Traits> | 
| 481 |     typename basic_filebuf<_CharT, _Traits>::int_type | 
| 482 |     basic_filebuf<_CharT, _Traits>:: | 
| 483 |     pbackfail(int_type __i) | 
| 484 |     { | 
| 485 |       int_type __ret = traits_type::eof(); | 
| 486 |       const bool __testin = _M_mode & ios_base::in; | 
| 487 |       if (__testin) | 
| 488 | 	{ | 
| 489 | 	  if (_M_writing) | 
| 490 | 	    { | 
| 491 | 	      if (overflow() == traits_type::eof()) | 
| 492 | 		return __ret; | 
| 493 | 	      _M_set_buffer(-1); | 
| 494 | 	      _M_writing = false; | 
| 495 | 	    } | 
| 496 | 	  // Remember whether the pback buffer is active, otherwise below | 
| 497 | 	  // we may try to store in it a second char (libstdc++/9761). | 
| 498 | 	  const bool __testpb = _M_pback_init; | 
| 499 | 	  const bool __testeof = traits_type::eq_int_type(__i, __ret); | 
| 500 | 	  int_type __tmp; | 
| 501 | 	  if (this->eback() < this->gptr()) | 
| 502 | 	    { | 
| 503 | 	      this->gbump(-1); | 
| 504 | 	      __tmp = traits_type::to_int_type(*this->gptr()); | 
| 505 | 	    } | 
| 506 | 	  else if (this->seekoff(-1, ios_base::cur) != pos_type(off_type(-1))) | 
| 507 | 	    { | 
| 508 | 	      __tmp = this->underflow(); | 
| 509 | 	      if (traits_type::eq_int_type(__tmp, __ret)) | 
| 510 | 		return __ret; | 
| 511 | 	    } | 
| 512 | 	  else | 
| 513 | 	    { | 
| 514 | 	      // At the beginning of the buffer, need to make a | 
| 515 | 	      // putback position available.  But the seek may fail | 
| 516 | 	      // (f.i., at the beginning of a file, see | 
| 517 | 	      // libstdc++/9439) and in that case we return | 
| 518 | 	      // traits_type::eof(). | 
| 519 | 	      return __ret; | 
| 520 | 	    } | 
| 521 |  | 
| 522 | 	  // Try to put back __i into input sequence in one of three ways. | 
| 523 | 	  // Order these tests done in is unspecified by the standard. | 
| 524 | 	  if (!__testeof && traits_type::eq_int_type(__i, __tmp)) | 
| 525 | 	    __ret = __i; | 
| 526 | 	  else if (__testeof) | 
| 527 | 	    __ret = traits_type::not_eof(__i); | 
| 528 | 	  else if (!__testpb) | 
| 529 | 	    { | 
| 530 | 	      _M_create_pback(); | 
| 531 | 	      _M_reading = true; | 
| 532 | 	      *this->gptr() = traits_type::to_char_type(__i); | 
| 533 | 	      __ret = __i; | 
| 534 | 	    } | 
| 535 | 	} | 
| 536 |       return __ret; | 
| 537 |     } | 
| 538 |  | 
| 539 |   template<typename _CharT, typename _Traits> | 
| 540 |     typename basic_filebuf<_CharT, _Traits>::int_type | 
| 541 |     basic_filebuf<_CharT, _Traits>:: | 
| 542 |     overflow(int_type __c) | 
| 543 |     { | 
| 544 |       int_type __ret = traits_type::eof(); | 
| 545 |       const bool __testeof = traits_type::eq_int_type(__c, __ret); | 
| 546 |       const bool __testout = (_M_mode & ios_base::out | 
| 547 | 			      || _M_mode & ios_base::app); | 
| 548 |       if (__testout) | 
| 549 | 	{ | 
| 550 |           if (_M_reading) | 
| 551 |             { | 
| 552 |               _M_destroy_pback(); | 
| 553 |               const int __gptr_off = _M_get_ext_pos(_M_state_last); | 
| 554 |               if (_M_seek(__gptr_off, ios_base::cur, _M_state_last) | 
| 555 |                   == pos_type(off_type(-1))) | 
| 556 |                 return __ret; | 
| 557 |             } | 
| 558 | 	  if (this->pbase() < this->pptr()) | 
| 559 | 	    { | 
| 560 | 	      // If appropriate, append the overflow char. | 
| 561 | 	      if (!__testeof) | 
| 562 | 		{ | 
| 563 | 		  *this->pptr() = traits_type::to_char_type(__c); | 
| 564 | 		  this->pbump(1); | 
| 565 | 		} | 
| 566 |  | 
| 567 | 	      // Convert pending sequence to external representation, | 
| 568 | 	      // and output. | 
| 569 | 	      if (_M_convert_to_external(this->pbase(), | 
| 570 | 					 this->pptr() - this->pbase())) | 
| 571 | 		{ | 
| 572 | 		  _M_set_buffer(0); | 
| 573 | 		  __ret = traits_type::not_eof(__c); | 
| 574 | 		} | 
| 575 | 	    } | 
| 576 | 	  else if (_M_buf_size > 1) | 
| 577 | 	    { | 
| 578 | 	      // Overflow in 'uncommitted' mode: set _M_writing, set | 
| 579 | 	      // the buffer to the initial 'write' mode, and put __c | 
| 580 | 	      // into the buffer. | 
| 581 | 	      _M_set_buffer(0); | 
| 582 | 	      _M_writing = true; | 
| 583 | 	      if (!__testeof) | 
| 584 | 		{ | 
| 585 | 		  *this->pptr() = traits_type::to_char_type(__c); | 
| 586 | 		  this->pbump(1); | 
| 587 | 		} | 
| 588 | 	      __ret = traits_type::not_eof(__c); | 
| 589 | 	    } | 
| 590 | 	  else | 
| 591 | 	    { | 
| 592 | 	      // Unbuffered. | 
| 593 | 	      char_type __conv = traits_type::to_char_type(__c); | 
| 594 | 	      if (__testeof || _M_convert_to_external(&__conv, 1)) | 
| 595 | 		{ | 
| 596 | 		  _M_writing = true; | 
| 597 | 		  __ret = traits_type::not_eof(__c); | 
| 598 | 		} | 
| 599 | 	    } | 
| 600 | 	} | 
| 601 |       return __ret; | 
| 602 |     } | 
| 603 |  | 
| 604 |   template<typename _CharT, typename _Traits> | 
| 605 |     bool | 
| 606 |     basic_filebuf<_CharT, _Traits>:: | 
| 607 |     _M_convert_to_external(_CharT* __ibuf, streamsize __ilen) | 
| 608 |     { | 
| 609 |       // Sizes of external and pending output. | 
| 610 |       streamsize __elen; | 
| 611 |       streamsize __plen; | 
| 612 |       if (__check_facet(_M_codecvt).always_noconv()) | 
| 613 | 	{ | 
| 614 | 	  __elen = _M_file.xsputn(reinterpret_cast<char*>(__ibuf), __ilen); | 
| 615 | 	  __plen = __ilen; | 
| 616 | 	} | 
| 617 |       else | 
| 618 | 	{ | 
| 619 | 	  // Worst-case number of external bytes needed. | 
| 620 | 	  // XXX Not done encoding() == -1. | 
| 621 | 	  streamsize __blen = __ilen * _M_codecvt->max_length(); | 
| 622 | 	  char* __buf = static_cast<char*>(__builtin_alloca(__blen)); | 
| 623 |  | 
| 624 | 	  char* __bend; | 
| 625 | 	  const char_type* __iend; | 
| 626 | 	  codecvt_base::result __r; | 
| 627 | 	  __r = _M_codecvt->out(_M_state_cur, __ibuf, __ibuf + __ilen, | 
| 628 | 				__iend, __buf, __buf + __blen, __bend); | 
| 629 |  | 
| 630 | 	  if (__r == codecvt_base::ok || __r == codecvt_base::partial) | 
| 631 | 	    __blen = __bend - __buf; | 
| 632 | 	  else if (__r == codecvt_base::noconv) | 
| 633 | 	    { | 
| 634 | 	      // Same as the always_noconv case above. | 
| 635 | 	      __buf = reinterpret_cast<char*>(__ibuf); | 
| 636 | 	      __blen = __ilen; | 
| 637 | 	    } | 
| 638 | 	  else | 
| 639 | 	    __throw_ios_failure(__N("basic_filebuf::_M_convert_to_external "  | 
| 640 | 				    "conversion error" )); | 
| 641 |    | 
| 642 | 	  __elen = _M_file.xsputn(__buf, __blen); | 
| 643 | 	  __plen = __blen; | 
| 644 |  | 
| 645 | 	  // Try once more for partial conversions. | 
| 646 | 	  if (__r == codecvt_base::partial && __elen == __plen) | 
| 647 | 	    { | 
| 648 | 	      const char_type* __iresume = __iend; | 
| 649 | 	      streamsize __rlen = this->pptr() - __iend; | 
| 650 | 	      __r = _M_codecvt->out(_M_state_cur, __iresume, | 
| 651 | 				    __iresume + __rlen, __iend, __buf, | 
| 652 | 				    __buf + __blen, __bend); | 
| 653 | 	      if (__r != codecvt_base::error) | 
| 654 | 		{ | 
| 655 | 		  __rlen = __bend - __buf; | 
| 656 | 		  __elen = _M_file.xsputn(__buf, __rlen); | 
| 657 | 		  __plen = __rlen; | 
| 658 | 		} | 
| 659 | 	      else | 
| 660 | 		__throw_ios_failure(__N("basic_filebuf::_M_convert_to_external "  | 
| 661 | 					"conversion error" )); | 
| 662 | 	    } | 
| 663 | 	} | 
| 664 |       return __elen == __plen; | 
| 665 |     } | 
| 666 |  | 
| 667 |   template<typename _CharT, typename _Traits> | 
| 668 |     streamsize | 
| 669 |     basic_filebuf<_CharT, _Traits>:: | 
| 670 |     xsgetn(_CharT* __s, streamsize __n) | 
| 671 |     { | 
| 672 |       // Clear out pback buffer before going on to the real deal... | 
| 673 |       streamsize __ret = 0; | 
| 674 |       if (_M_pback_init) | 
| 675 | 	{ | 
| 676 | 	  if (__n > 0 && this->gptr() == this->eback()) | 
| 677 | 	    { | 
| 678 | 	      *__s++ = *this->gptr(); // emulate non-underflowing sbumpc | 
| 679 | 	      this->gbump(1); | 
| 680 | 	      __ret = 1; | 
| 681 | 	      --__n; | 
| 682 | 	    } | 
| 683 | 	  _M_destroy_pback(); | 
| 684 | 	} | 
| 685 |       else if (_M_writing) | 
| 686 | 	{ | 
| 687 | 	  if (overflow() == traits_type::eof()) | 
| 688 | 	    return __ret; | 
| 689 | 	  _M_set_buffer(-1); | 
| 690 | 	  _M_writing = false; | 
| 691 | 	} | 
| 692 |   | 
| 693 |       // Optimization in the always_noconv() case, to be generalized in the | 
| 694 |       // future: when __n > __buflen we read directly instead of using the | 
| 695 |       // buffer repeatedly. | 
| 696 |       const bool __testin = _M_mode & ios_base::in; | 
| 697 |       const streamsize __buflen = _M_buf_size > 1 ? _M_buf_size - 1 : 1; | 
| 698 |   | 
| 699 |       if (__n > __buflen && __check_facet(_M_codecvt).always_noconv() | 
| 700 | 	  && __testin) | 
| 701 | 	{ | 
| 702 | 	  // First, copy the chars already present in the buffer. | 
| 703 | 	  const streamsize __avail = this->egptr() - this->gptr(); | 
| 704 | 	  if (__avail != 0) | 
| 705 | 	    { | 
| 706 | 	      traits_type::copy(__s, this->gptr(), __avail); | 
| 707 | 	      __s += __avail; | 
| 708 | 	      this->setg(this->eback(), this->gptr() + __avail, this->egptr()); | 
| 709 | 	      __ret += __avail; | 
| 710 | 	      __n -= __avail; | 
| 711 | 	    } | 
| 712 |   | 
| 713 | 	  // Need to loop in case of short reads (relatively common | 
| 714 | 	  // with pipes). | 
| 715 | 	  streamsize __len; | 
| 716 | 	  for (;;) | 
| 717 | 	    { | 
| 718 | 	      __len = _M_file.xsgetn(reinterpret_cast<char*>(__s), __n); | 
| 719 | 	      if (__len == -1) | 
| 720 | 		__throw_ios_failure(__N("basic_filebuf::xsgetn "  | 
| 721 | 					"error reading the file" ), errno); | 
| 722 | 	      if (__len == 0) | 
| 723 | 		break; | 
| 724 |   | 
| 725 | 	      __n -= __len; | 
| 726 | 	      __ret += __len; | 
| 727 | 	      if (__n == 0) | 
| 728 | 		break; | 
| 729 |  | 
| 730 | 	      __s += __len; | 
| 731 | 	    } | 
| 732 |  | 
| 733 | 	  if (__n == 0) | 
| 734 | 	    { | 
| 735 | 	      // Set _M_reading. Buffer is already in initial 'read' mode. | 
| 736 | 	      _M_reading = true; | 
| 737 | 	    } | 
| 738 | 	  else if (__len == 0) | 
| 739 | 	    { | 
| 740 | 	      // If end of file is reached, set 'uncommitted' | 
| 741 | 	      // mode, thus allowing an immediate write without | 
| 742 | 	      // an intervening seek. | 
| 743 | 	      _M_set_buffer(-1); | 
| 744 | 	      _M_reading = false; | 
| 745 | 	    } | 
| 746 | 	} | 
| 747 |       else | 
| 748 | 	__ret += __streambuf_type::xsgetn(__s, __n); | 
| 749 |   | 
| 750 |       return __ret; | 
| 751 |     } | 
| 752 |  | 
| 753 |   template<typename _CharT, typename _Traits> | 
| 754 |     streamsize | 
| 755 |     basic_filebuf<_CharT, _Traits>:: | 
| 756 |     xsputn(const _CharT* __s, streamsize __n) | 
| 757 |     { | 
| 758 |       streamsize __ret = 0; | 
| 759 |       // Optimization in the always_noconv() case, to be generalized in the | 
| 760 |       // future: when __n is sufficiently large we write directly instead of | 
| 761 |       // using the buffer. | 
| 762 |       const bool __testout = (_M_mode & ios_base::out | 
| 763 | 			      || _M_mode & ios_base::app); | 
| 764 |       if (__check_facet(_M_codecvt).always_noconv() | 
| 765 | 	  && __testout && !_M_reading) | 
| 766 | 	{ | 
| 767 | 	  // Measurement would reveal the best choice. | 
| 768 | 	  const streamsize __chunk = 1ul << 10; | 
| 769 | 	  streamsize __bufavail = this->epptr() - this->pptr(); | 
| 770 |  | 
| 771 | 	  // Don't mistake 'uncommitted' mode buffered with unbuffered. | 
| 772 | 	  if (!_M_writing && _M_buf_size > 1) | 
| 773 | 	    __bufavail = _M_buf_size - 1; | 
| 774 |  | 
| 775 | 	  const streamsize __limit = std::min(__chunk, __bufavail); | 
| 776 | 	  if (__n >= __limit) | 
| 777 | 	    { | 
| 778 | 	      const streamsize __buffill = this->pptr() - this->pbase(); | 
| 779 | 	      const char* __buf = reinterpret_cast<const char*>(this->pbase()); | 
| 780 | 	      __ret = _M_file.xsputn_2(__buf, __buffill, | 
| 781 | 				       reinterpret_cast<const char*>(__s), | 
| 782 | 				       __n); | 
| 783 | 	      if (__ret == __buffill + __n) | 
| 784 | 		{ | 
| 785 | 		  _M_set_buffer(0); | 
| 786 | 		  _M_writing = true; | 
| 787 | 		} | 
| 788 | 	      if (__ret > __buffill) | 
| 789 | 		__ret -= __buffill; | 
| 790 | 	      else | 
| 791 | 		__ret = 0; | 
| 792 | 	    } | 
| 793 | 	  else | 
| 794 | 	    __ret = __streambuf_type::xsputn(__s, __n); | 
| 795 | 	} | 
| 796 |        else | 
| 797 | 	 __ret = __streambuf_type::xsputn(__s, __n); | 
| 798 |        return __ret; | 
| 799 |     } | 
| 800 |  | 
| 801 |   template<typename _CharT, typename _Traits> | 
| 802 |     typename basic_filebuf<_CharT, _Traits>::__streambuf_type* | 
| 803 |     basic_filebuf<_CharT, _Traits>:: | 
| 804 |     setbuf(char_type* __s, streamsize __n) | 
| 805 |     { | 
| 806 |       if (!this->is_open()) | 
| 807 | 	{ | 
| 808 | 	  if (__s == 0 && __n == 0) | 
| 809 | 	    _M_buf_size = 1; | 
| 810 | 	  else if (__s && __n > 0) | 
| 811 | 	    { | 
| 812 | 	      // This is implementation-defined behavior, and assumes that | 
| 813 | 	      // an external char_type array of length __n exists and has | 
| 814 | 	      // been pre-allocated. If this is not the case, things will | 
| 815 | 	      // quickly blow up. When __n > 1, __n - 1 positions will be | 
| 816 | 	      // used for the get area, __n - 1 for the put area and 1 | 
| 817 | 	      // position to host the overflow char of a full put area. | 
| 818 | 	      // When __n == 1, 1 position will be used for the get area | 
| 819 | 	      // and 0 for the put area, as in the unbuffered case above. | 
| 820 | 	      _M_buf = __s; | 
| 821 | 	      _M_buf_size = __n; | 
| 822 | 	    } | 
| 823 | 	} | 
| 824 |       return this; | 
| 825 |     } | 
| 826 |  | 
| 827 |  | 
| 828 |   // According to 27.8.1.4 p11 - 13, seekoff should ignore the last | 
| 829 |   // argument (of type openmode). | 
| 830 |   template<typename _CharT, typename _Traits> | 
| 831 |     typename basic_filebuf<_CharT, _Traits>::pos_type | 
| 832 |     basic_filebuf<_CharT, _Traits>:: | 
| 833 |     seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode) | 
| 834 |     { | 
| 835 |       int __width = 0; | 
| 836 |       if (_M_codecvt) | 
| 837 | 	__width = _M_codecvt->encoding(); | 
| 838 |       if (__width < 0) | 
| 839 | 	__width = 0; | 
| 840 |  | 
| 841 |       pos_type __ret = pos_type(off_type(-1)); | 
| 842 |       const bool __testfail = __off != 0 && __width <= 0; | 
| 843 |       if (this->is_open() && !__testfail) | 
| 844 | 	{ | 
| 845 | 	  // tellg and tellp queries do not affect any state, unless | 
| 846 | 	  // ! always_noconv and the put sequence is not empty. | 
| 847 | 	  // In that case, determining the position requires converting the | 
| 848 | 	  // put sequence. That doesn't use ext_buf, so requires a flush. | 
| 849 | 	  bool __no_movement = __way == ios_base::cur && __off == 0 | 
| 850 | 	    && (!_M_writing || _M_codecvt->always_noconv()); | 
| 851 |  | 
| 852 | 	  // Ditch any pback buffers to avoid confusion. | 
| 853 | 	  if (!__no_movement) | 
| 854 | 	    _M_destroy_pback(); | 
| 855 |  | 
| 856 | 	  // Correct state at destination. Note that this is the correct | 
| 857 | 	  // state for the current position during output, because | 
| 858 | 	  // codecvt::unshift() returns the state to the initial state. | 
| 859 | 	  // This is also the correct state at the end of the file because | 
| 860 | 	  // an unshift sequence should have been written at the end. | 
| 861 | 	  __state_type __state = _M_state_beg; | 
| 862 | 	  off_type __computed_off = __off * __width; | 
| 863 | 	  if (_M_reading && __way == ios_base::cur) | 
| 864 | 	    { | 
| 865 | 	      __state = _M_state_last; | 
| 866 | 	      __computed_off += _M_get_ext_pos(__state); | 
| 867 | 	    } | 
| 868 | 	  if (!__no_movement) | 
| 869 | 	    __ret = _M_seek(__computed_off, __way, __state); | 
| 870 | 	  else | 
| 871 | 	    { | 
| 872 | 	      if (_M_writing) | 
| 873 | 		__computed_off = this->pptr() - this->pbase(); | 
| 874 | 	       | 
| 875 | 	      off_type __file_off = _M_file.seekoff(0, ios_base::cur); | 
| 876 | 	      if (__file_off != off_type(-1)) | 
| 877 | 		{ | 
| 878 | 		  __ret = __file_off + __computed_off; | 
| 879 | 		  __ret.state(__state); | 
| 880 | 		} | 
| 881 | 	    } | 
| 882 | 	} | 
| 883 |       return __ret; | 
| 884 |     } | 
| 885 |  | 
| 886 |   // _GLIBCXX_RESOLVE_LIB_DEFECTS | 
| 887 |   // 171. Strange seekpos() semantics due to joint position | 
| 888 |   // According to the resolution of DR 171, seekpos should ignore the last | 
| 889 |   // argument (of type openmode). | 
| 890 |   template<typename _CharT, typename _Traits> | 
| 891 |     typename basic_filebuf<_CharT, _Traits>::pos_type | 
| 892 |     basic_filebuf<_CharT, _Traits>:: | 
| 893 |     seekpos(pos_type __pos, ios_base::openmode) | 
| 894 |     { | 
| 895 |       pos_type __ret =  pos_type(off_type(-1)); | 
| 896 |       if (this->is_open()) | 
| 897 | 	{ | 
| 898 | 	  // Ditch any pback buffers to avoid confusion. | 
| 899 | 	  _M_destroy_pback(); | 
| 900 | 	  __ret = _M_seek(off_type(__pos), ios_base::beg, __pos.state()); | 
| 901 | 	} | 
| 902 |       return __ret; | 
| 903 |     } | 
| 904 |  | 
| 905 |   template<typename _CharT, typename _Traits> | 
| 906 |     typename basic_filebuf<_CharT, _Traits>::pos_type | 
| 907 |     basic_filebuf<_CharT, _Traits>:: | 
| 908 |     _M_seek(off_type __off, ios_base::seekdir __way, __state_type __state) | 
| 909 |     { | 
| 910 |       pos_type __ret = pos_type(off_type(-1)); | 
| 911 |       if (_M_terminate_output()) | 
| 912 | 	{ | 
| 913 | 	  off_type __file_off = _M_file.seekoff(__off, __way); | 
| 914 | 	  if (__file_off != off_type(-1)) | 
| 915 | 	    { | 
| 916 | 	      _M_reading = false; | 
| 917 | 	      _M_writing = false; | 
| 918 | 	      _M_ext_next = _M_ext_end = _M_ext_buf; | 
| 919 | 	      _M_set_buffer(-1); | 
| 920 | 	      _M_state_cur = __state; | 
| 921 | 	      __ret = __file_off; | 
| 922 | 	      __ret.state(_M_state_cur); | 
| 923 | 	    } | 
| 924 | 	} | 
| 925 |       return __ret; | 
| 926 |     } | 
| 927 |  | 
| 928 |   // Returns the distance from the end of the ext buffer to the point | 
| 929 |   // corresponding to gptr(). This is a negative value. Updates __state | 
| 930 |   // from eback() correspondence to gptr(). | 
| 931 |   template<typename _CharT, typename _Traits> | 
| 932 |     int basic_filebuf<_CharT, _Traits>:: | 
| 933 |     _M_get_ext_pos(__state_type& __state) | 
| 934 |     { | 
| 935 |       if (_M_codecvt->always_noconv()) | 
| 936 |         return this->gptr() - this->egptr(); | 
| 937 |       else | 
| 938 |         { | 
| 939 |           // Calculate offset from _M_ext_buf that corresponds to | 
| 940 |           // gptr(). Precondition: __state == _M_state_last, which | 
| 941 |           // corresponds to eback(). | 
| 942 |           const int __gptr_off = | 
| 943 |             _M_codecvt->length(__state, _M_ext_buf, _M_ext_next, | 
| 944 |                                this->gptr() - this->eback()); | 
| 945 |           return _M_ext_buf + __gptr_off - _M_ext_end; | 
| 946 |         } | 
| 947 |     } | 
| 948 |      | 
| 949 |   template<typename _CharT, typename _Traits> | 
| 950 |     bool | 
| 951 |     basic_filebuf<_CharT, _Traits>:: | 
| 952 |     _M_terminate_output() | 
| 953 |     { | 
| 954 |       // Part one: update the output sequence. | 
| 955 |       bool __testvalid = true; | 
| 956 |       if (this->pbase() < this->pptr()) | 
| 957 | 	{ | 
| 958 | 	  const int_type __tmp = this->overflow(); | 
| 959 | 	  if (traits_type::eq_int_type(__tmp, traits_type::eof())) | 
| 960 | 	    __testvalid = false; | 
| 961 | 	} | 
| 962 |  | 
| 963 |       // Part two: output unshift sequence. | 
| 964 |       if (_M_writing && !__check_facet(_M_codecvt).always_noconv() | 
| 965 | 	  && __testvalid) | 
| 966 | 	{ | 
| 967 | 	  // Note: this value is arbitrary, since there is no way to | 
| 968 | 	  // get the length of the unshift sequence from codecvt, | 
| 969 | 	  // without calling unshift. | 
| 970 | 	  const size_t __blen = 128; | 
| 971 | 	  char __buf[__blen]; | 
| 972 | 	  codecvt_base::result __r; | 
| 973 | 	  streamsize __ilen = 0; | 
| 974 |  | 
| 975 | 	  do | 
| 976 | 	    { | 
| 977 | 	      char* __next; | 
| 978 | 	      __r = _M_codecvt->unshift(_M_state_cur, __buf, | 
| 979 | 					__buf + __blen, __next); | 
| 980 | 	      if (__r == codecvt_base::error) | 
| 981 | 		__testvalid = false; | 
| 982 | 	      else if (__r == codecvt_base::ok || | 
| 983 | 		       __r == codecvt_base::partial) | 
| 984 | 		{ | 
| 985 | 		  __ilen = __next - __buf; | 
| 986 | 		  if (__ilen > 0) | 
| 987 | 		    { | 
| 988 | 		      const streamsize __elen = _M_file.xsputn(__buf, __ilen); | 
| 989 | 		      if (__elen != __ilen) | 
| 990 | 			__testvalid = false; | 
| 991 | 		    } | 
| 992 | 		} | 
| 993 | 	    } | 
| 994 | 	  while (__r == codecvt_base::partial && __ilen > 0 && __testvalid); | 
| 995 |  | 
| 996 | 	  if (__testvalid) | 
| 997 | 	    { | 
| 998 | 	      // This second call to overflow() is required by the standard, | 
| 999 | 	      // but it's not clear why it's needed, since the output buffer | 
| 1000 | 	      // should be empty by this point (it should have been emptied | 
| 1001 | 	      // in the first call to overflow()). | 
| 1002 | 	      const int_type __tmp = this->overflow(); | 
| 1003 | 	      if (traits_type::eq_int_type(__tmp, traits_type::eof())) | 
| 1004 | 		__testvalid = false; | 
| 1005 | 	    } | 
| 1006 | 	} | 
| 1007 |       return __testvalid; | 
| 1008 |     } | 
| 1009 |  | 
| 1010 |   template<typename _CharT, typename _Traits> | 
| 1011 |     int | 
| 1012 |     basic_filebuf<_CharT, _Traits>:: | 
| 1013 |     sync() | 
| 1014 |     { | 
| 1015 |       // Make sure that the internal buffer resyncs its idea of | 
| 1016 |       // the file position with the external file. | 
| 1017 |       int __ret = 0; | 
| 1018 |       if (this->pbase() < this->pptr()) | 
| 1019 | 	{ | 
| 1020 | 	  const int_type __tmp = this->overflow(); | 
| 1021 | 	  if (traits_type::eq_int_type(__tmp, traits_type::eof())) | 
| 1022 | 	    __ret = -1; | 
| 1023 | 	} | 
| 1024 |       return __ret; | 
| 1025 |     } | 
| 1026 |  | 
| 1027 |   template<typename _CharT, typename _Traits> | 
| 1028 |     void | 
| 1029 |     basic_filebuf<_CharT, _Traits>:: | 
| 1030 |     imbue(const locale& __loc) | 
| 1031 |     { | 
| 1032 |       bool __testvalid = true; | 
| 1033 |  | 
| 1034 |       const __codecvt_type* _M_codecvt_tmp = 0; | 
| 1035 |       if (__builtin_expect(has_facet<__codecvt_type>(__loc), true)) | 
| 1036 | 	_M_codecvt_tmp = &use_facet<__codecvt_type>(__loc); | 
| 1037 |  | 
| 1038 |       if (this->is_open()) | 
| 1039 | 	{ | 
| 1040 | 	  // encoding() == -1 is ok only at the beginning. | 
| 1041 | 	  if ((_M_reading || _M_writing) | 
| 1042 | 	      && __check_facet(_M_codecvt).encoding() == -1) | 
| 1043 | 	    __testvalid = false; | 
| 1044 | 	  else | 
| 1045 | 	    { | 
| 1046 | 	      if (_M_reading) | 
| 1047 | 		{ | 
| 1048 | 		  if (__check_facet(_M_codecvt).always_noconv()) | 
| 1049 | 		    { | 
| 1050 | 		      if (_M_codecvt_tmp | 
| 1051 | 			  && !__check_facet(_M_codecvt_tmp).always_noconv()) | 
| 1052 | 			__testvalid = this->seekoff(0, ios_base::cur, _M_mode) | 
| 1053 | 			              != pos_type(off_type(-1)); | 
| 1054 | 		    } | 
| 1055 | 		  else | 
| 1056 | 		    { | 
| 1057 | 		      // External position corresponding to gptr(). | 
| 1058 | 		      _M_ext_next = _M_ext_buf | 
| 1059 | 			+ _M_codecvt->length(_M_state_last, _M_ext_buf, | 
| 1060 | 					     _M_ext_next, | 
| 1061 | 					     this->gptr() - this->eback()); | 
| 1062 | 		      const streamsize __remainder = _M_ext_end - _M_ext_next; | 
| 1063 | 		      if (__remainder) | 
| 1064 | 			__builtin_memmove(_M_ext_buf, _M_ext_next, __remainder); | 
| 1065 |  | 
| 1066 | 		      _M_ext_next = _M_ext_buf; | 
| 1067 | 		      _M_ext_end = _M_ext_buf + __remainder; | 
| 1068 | 		      _M_set_buffer(-1); | 
| 1069 | 		      _M_state_last = _M_state_cur = _M_state_beg; | 
| 1070 | 		    } | 
| 1071 | 		} | 
| 1072 | 	      else if (_M_writing && (__testvalid = _M_terminate_output())) | 
| 1073 | 		_M_set_buffer(-1); | 
| 1074 | 	    } | 
| 1075 | 	} | 
| 1076 |  | 
| 1077 |       if (__testvalid) | 
| 1078 | 	_M_codecvt = _M_codecvt_tmp; | 
| 1079 |       else | 
| 1080 | 	_M_codecvt = 0; | 
| 1081 |     } | 
| 1082 |  | 
| 1083 |   // Inhibit implicit instantiations for required instantiations, | 
| 1084 |   // which are defined via explicit instantiations elsewhere. | 
| 1085 | #if _GLIBCXX_EXTERN_TEMPLATE | 
| 1086 |   extern template class basic_filebuf<char>; | 
| 1087 |   extern template class basic_ifstream<char>; | 
| 1088 |   extern template class basic_ofstream<char>; | 
| 1089 |   extern template class basic_fstream<char>; | 
| 1090 |  | 
| 1091 | #ifdef _GLIBCXX_USE_WCHAR_T | 
| 1092 |   extern template class basic_filebuf<wchar_t>; | 
| 1093 |   extern template class basic_ifstream<wchar_t>; | 
| 1094 |   extern template class basic_ofstream<wchar_t>; | 
| 1095 |   extern template class basic_fstream<wchar_t>; | 
| 1096 | #endif | 
| 1097 | #endif | 
| 1098 |  | 
| 1099 | _GLIBCXX_END_NAMESPACE_VERSION | 
| 1100 | } // namespace std | 
| 1101 |  | 
| 1102 | #endif | 
| 1103 |  |