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