]>
Commit | Line | Data |
---|---|---|
725dc051 BK |
1 | // File based streams -*- C++ -*- |
2 | ||
99dee823 | 3 | // Copyright (C) 1997-2021 Free Software Foundation, Inc. |
725dc051 BK |
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 | |
748086b7 | 8 | // Free Software Foundation; either version 3, or (at your option) |
725dc051 BK |
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 | ||
748086b7 JJ |
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/>. | |
725dc051 | 24 | |
f910786b | 25 | /** @file bits/fstream.tcc |
0aa06b18 | 26 | * This is an internal header file, included by other library headers. |
f910786b | 27 | * Do not attempt to use it directly. @headername{fstream} |
0aa06b18 BK |
28 | */ |
29 | ||
725dc051 BK |
30 | // |
31 | // ISO C++ 14882: 27.8 File-based streams | |
32 | // | |
33 | ||
3d7c150e BK |
34 | #ifndef _FSTREAM_TCC |
35 | #define _FSTREAM_TCC 1 | |
725dc051 | 36 | |
3b794528 BK |
37 | #pragma GCC system_header |
38 | ||
7c3e9502 | 39 | #include <bits/cxxabi_forced.h> |
9b817548 | 40 | #include <bits/move.h> // for swap |
484e936e | 41 | #include <cerrno> |
d05f74f1 | 42 | |
12ffa228 BK |
43 | namespace std _GLIBCXX_VISIBILITY(default) |
44 | { | |
45 | _GLIBCXX_BEGIN_NAMESPACE_VERSION | |
3cbc7af0 | 46 | |
725dc051 BK |
47 | template<typename _CharT, typename _Traits> |
48 | void | |
49 | basic_filebuf<_CharT, _Traits>:: | |
990101f9 | 50 | _M_allocate_internal_buffer() |
725dc051 | 51 | { |
dfad48c6 PC |
52 | // Allocate internal buffer only if one doesn't already exist |
53 | // (either allocated or provided by the user via setbuf). | |
a8e3a00f | 54 | if (!_M_buf_allocated && !_M_buf) |
13187a45 | 55 | { |
a8e3a00f | 56 | _M_buf = new char_type[_M_buf_size]; |
5cdd50a5 | 57 | _M_buf_allocated = true; |
990101f9 BK |
58 | } |
59 | } | |
60 | ||
990101f9 BK |
61 | template<typename _CharT, typename _Traits> |
62 | void | |
63 | basic_filebuf<_CharT, _Traits>:: | |
a1796d12 | 64 | _M_destroy_internal_buffer() throw() |
990101f9 BK |
65 | { |
66 | if (_M_buf_allocated) | |
67 | { | |
a8e3a00f | 68 | delete [] _M_buf; |
8fc81078 | 69 | _M_buf = 0; |
990101f9 | 70 | _M_buf_allocated = false; |
990101f9 | 71 | } |
f1813b69 | 72 | delete [] _M_ext_buf; |
8fc81078 | 73 | _M_ext_buf = 0; |
f1813b69 | 74 | _M_ext_buf_size = 0; |
8fc81078 PC |
75 | _M_ext_next = 0; |
76 | _M_ext_end = 0; | |
725dc051 BK |
77 | } |
78 | ||
79 | template<typename _CharT, typename _Traits> | |
80 | basic_filebuf<_CharT, _Traits>:: | |
26c691a8 | 81 | basic_filebuf() : __streambuf_type(), _M_lock(), _M_file(&_M_lock), |
5e93f39f | 82 | _M_mode(ios_base::openmode(0)), _M_state_beg(), _M_state_cur(), |
0bc199fc | 83 | _M_state_last(), _M_buf(0), _M_buf_size(_GLIBCXX_BUFSIZ), |
26c691a8 | 84 | _M_buf_allocated(false), _M_reading(false), _M_writing(false), _M_pback(), |
5e93f39f PR |
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) | |
ed6814f7 | 88 | { |
46c4e5d6 | 89 | if (has_facet<__codecvt_type>(this->_M_buf_locale)) |
0cd1de6f BK |
90 | _M_codecvt = &use_facet<__codecvt_type>(this->_M_buf_locale); |
91 | } | |
725dc051 | 92 | |
9b817548 JW |
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 | ||
725dc051 | 177 | template<typename _CharT, typename _Traits> |
ed6814f7 | 178 | typename basic_filebuf<_CharT, _Traits>::__filebuf_type* |
725dc051 BK |
179 | basic_filebuf<_CharT, _Traits>:: |
180 | open(const char* __s, ios_base::openmode __mode) | |
181 | { | |
8fc81078 | 182 | __filebuf_type *__ret = 0; |
725dc051 BK |
183 | if (!this->is_open()) |
184 | { | |
d3a193e3 | 185 | _M_file.open(__s, __mode); |
13187a45 | 186 | if (this->is_open()) |
725dc051 | 187 | { |
990101f9 | 188 | _M_allocate_internal_buffer(); |
a8e3a00f | 189 | _M_mode = __mode; |
6eeb7d7a | 190 | |
71b46021 PC |
191 | // Setup initial buffer to 'uncommitted' mode. |
192 | _M_reading = false; | |
193 | _M_writing = false; | |
194 | _M_set_buffer(-1); | |
6e52332e | 195 | |
5e93f39f PR |
196 | // Reset to initial state. |
197 | _M_state_last = _M_state_cur = _M_state_beg; | |
198 | ||
cc5112c9 | 199 | // 27.8.1.3,4 |
ed6814f7 BI |
200 | if ((__mode & ios_base::ate) |
201 | && this->seekoff(0, ios_base::end, __mode) | |
4c4809c1 | 202 | == pos_type(off_type(-1))) |
cc9d1c78 PC |
203 | this->close(); |
204 | else | |
205 | __ret = this; | |
725dc051 BK |
206 | } |
207 | } | |
208 | return __ret; | |
209 | } | |
210 | ||
b0292359 JW |
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 | ||
725dc051 | 247 | template<typename _CharT, typename _Traits> |
ed6814f7 | 248 | typename basic_filebuf<_CharT, _Traits>::__filebuf_type* |
725dc051 | 249 | basic_filebuf<_CharT, _Traits>:: |
d05f74f1 | 250 | close() |
725dc051 | 251 | { |
d05f74f1 | 252 | if (!this->is_open()) |
8fc81078 | 253 | return 0; |
d05f74f1 JM |
254 | |
255 | bool __testfail = false; | |
256 | { | |
257 | // NB: Do this here so that re-opened filebufs will be cool... | |
258 | struct __close_sentry | |
725dc051 | 259 | { |
d05f74f1 JM |
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 | ||
bc2631e0 | 274 | __try |
d05f74f1 JM |
275 | { |
276 | if (!_M_terminate_output()) | |
277 | __testfail = true; | |
278 | } | |
e77497ab | 279 | __catch(...) |
d05f74f1 JM |
280 | { |
281 | _M_file.close(); | |
282 | __throw_exception_again; | |
283 | } | |
d05f74f1 JM |
284 | } |
285 | ||
286 | if (!_M_file.close()) | |
287 | __testfail = true; | |
288 | ||
289 | if (__testfail) | |
8fc81078 | 290 | return 0; |
d05f74f1 JM |
291 | else |
292 | return this; | |
725dc051 BK |
293 | } |
294 | ||
295 | template<typename _CharT, typename _Traits> | |
ed6814f7 | 296 | streamsize |
725dc051 BK |
297 | basic_filebuf<_CharT, _Traits>:: |
298 | showmanyc() | |
299 | { | |
300 | streamsize __ret = -1; | |
a8e3a00f | 301 | const bool __testin = _M_mode & ios_base::in; |
9fbcb61a | 302 | if (__testin && this->is_open()) |
bbacb998 | 303 | { |
bbacb998 PC |
304 | // For a stateful encoding (-1) the pending sequence might be just |
305 | // shift and unshift prefixes with no actual character. | |
71b46021 | 306 | __ret = this->egptr() - this->gptr(); |
1ae48358 DS |
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 | |
0cd1de6f | 314 | if (__check_facet(_M_codecvt).encoding() >= 0) |
1ae48358 | 315 | #endif |
0cd1de6f | 316 | __ret += _M_file.showmanyc() / _M_codecvt->max_length(); |
bbacb998 | 317 | } |
725dc051 BK |
318 | return __ret; |
319 | } | |
09625c16 | 320 | |
51ff8149 | 321 | template<typename _CharT, typename _Traits> |
ed6814f7 | 322 | typename basic_filebuf<_CharT, _Traits>::int_type |
6e81c6f4 | 323 | basic_filebuf<_CharT, _Traits>:: |
cd16e04b | 324 | underflow() |
51ff8149 BK |
325 | { |
326 | int_type __ret = traits_type::eof(); | |
a8e3a00f | 327 | const bool __testin = _M_mode & ios_base::in; |
3531cf5e | 328 | if (__testin) |
51ff8149 | 329 | { |
47b90d6b DK |
330 | if (_M_writing) |
331 | { | |
332 | if (overflow() == traits_type::eof()) | |
333 | return __ret; | |
334 | _M_set_buffer(-1); | |
335 | _M_writing = false; | |
336 | } | |
ee5ca789 | 337 | // Check for pback madness, and if so switch back to the |
51ff8149 BK |
338 | // normal buffers and jet outta here before expensive |
339 | // fileops happen... | |
0aef8de2 | 340 | _M_destroy_pback(); |
51ff8149 | 341 | |
71b46021 | 342 | if (this->gptr() < this->egptr()) |
cd16e04b | 343 | return traits_type::to_int_type(*this->gptr()); |
51ff8149 | 344 | |
f10eea7b | 345 | // Get and convert input sequence. |
fdeeef7f | 346 | const size_t __buflen = _M_buf_size > 1 ? _M_buf_size - 1 : 1; |
ed6814f7 | 347 | |
f1813b69 PR |
348 | // Will be set to true if ::read() returns 0 indicating EOF. |
349 | bool __got_eof = false; | |
350 | // Number of internal characters produced. | |
f10eea7b | 351 | streamsize __ilen = 0; |
ed6814f7 | 352 | codecvt_base::result __r = codecvt_base::ok; |
f10eea7b PC |
353 | if (__check_facet(_M_codecvt).always_noconv()) |
354 | { | |
ed6814f7 | 355 | __ilen = _M_file.xsgetn(reinterpret_cast<char*>(this->eback()), |
cc5112c9 | 356 | __buflen); |
f1813b69 PR |
357 | if (__ilen == 0) |
358 | __got_eof = true; | |
f10eea7b PC |
359 | } |
360 | else | |
361 | { | |
f1813b69 | 362 | // Worst-case number of external bytes. |
dfad48c6 PC |
363 | // XXX Not done encoding() == -1. |
364 | const int __enc = _M_codecvt->encoding(); | |
f1813b69 PR |
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 | |
51ff8149 | 370 | { |
f1813b69 PR |
371 | __blen = __buflen + _M_codecvt->max_length() - 1; |
372 | __rlen = __buflen; | |
51ff8149 | 373 | } |
f1813b69 PR |
374 | const streamsize __remainder = _M_ext_end - _M_ext_next; |
375 | __rlen = __rlen > __remainder ? __rlen - __remainder : 0; | |
09625c16 PC |
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; | |
ed6814f7 | 381 | |
f1813b69 PR |
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]; | |
09625c16 | 387 | if (__remainder) |
538075fe | 388 | __builtin_memcpy(__buf, _M_ext_next, __remainder); |
f1813b69 PR |
389 | |
390 | delete [] _M_ext_buf; | |
391 | _M_ext_buf = __buf; | |
392 | _M_ext_buf_size = __blen; | |
393 | } | |
09625c16 | 394 | else if (__remainder) |
538075fe | 395 | __builtin_memmove(_M_ext_buf, _M_ext_next, __remainder); |
f1813b69 PR |
396 | |
397 | _M_ext_next = _M_ext_buf; | |
398 | _M_ext_end = _M_ext_buf + __remainder; | |
5e93f39f | 399 | _M_state_last = _M_state_cur; |
f1813b69 PR |
400 | |
401 | do | |
51ff8149 | 402 | { |
f1813b69 PR |
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) | |
5e93f39f | 409 | { |
ba9119ec | 410 | __throw_ios_failure(__N("basic_filebuf::underflow " |
d78e147a | 411 | "codecvt::max_length() " |
ba9119ec | 412 | "is not valid")); |
5e93f39f | 413 | } |
f1813b69 PR |
414 | streamsize __elen = _M_file.xsgetn(_M_ext_end, __rlen); |
415 | if (__elen == 0) | |
416 | __got_eof = true; | |
3090572c PC |
417 | else if (__elen == -1) |
418 | break; | |
f1813b69 PR |
419 | _M_ext_end += __elen; |
420 | } | |
5536b61c | 421 | |
7558d810 PC |
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); | |
29342463 | 428 | if (__r == codecvt_base::noconv) |
f1813b69 PR |
429 | { |
430 | size_t __avail = _M_ext_end - _M_ext_buf; | |
431 | __ilen = std::min(__avail, __buflen); | |
432 | traits_type::copy(this->eback(), | |
7558d810 PC |
433 | reinterpret_cast<char_type*> |
434 | (_M_ext_buf), __ilen); | |
f1813b69 PR |
435 | _M_ext_next = _M_ext_buf + __ilen; |
436 | } | |
29342463 PC |
437 | else |
438 | __ilen = __iend - this->eback(); | |
5536b61c | 439 | |
29342463 PC |
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 | ||
f1813b69 | 446 | __rlen = 1; |
51ff8149 | 447 | } |
4da2b960 | 448 | while (__ilen == 0 && !__got_eof); |
46c4e5d6 | 449 | } |
f10eea7b PC |
450 | |
451 | if (__ilen > 0) | |
46c4e5d6 | 452 | { |
f10eea7b | 453 | _M_set_buffer(__ilen); |
71b46021 PC |
454 | _M_reading = true; |
455 | __ret = traits_type::to_int_type(*this->gptr()); | |
2cfe4e68 | 456 | } |
f1813b69 | 457 | else if (__got_eof) |
2cfe4e68 PC |
458 | { |
459 | // If the actual end of file is reached, set 'uncommitted' | |
ed6814f7 | 460 | // mode, thus allowing an immediate write without an |
2cfe4e68 PC |
461 | // intervening seek. |
462 | _M_set_buffer(-1); | |
463 | _M_reading = false; | |
5536b61c PC |
464 | // However, reaching it while looping on partial means that |
465 | // the file has got an incomplete character. | |
466 | if (__r == codecvt_base::partial) | |
ba9119ec PC |
467 | __throw_ios_failure(__N("basic_filebuf::underflow " |
468 | "incomplete character in file")); | |
2cfe4e68 | 469 | } |
3090572c | 470 | else if (__r == codecvt_base::error) |
ba9119ec PC |
471 | __throw_ios_failure(__N("basic_filebuf::underflow " |
472 | "invalid byte sequence in file")); | |
3090572c | 473 | else |
ba9119ec | 474 | __throw_ios_failure(__N("basic_filebuf::underflow " |
484e936e | 475 | "error reading the file"), errno); |
51ff8149 | 476 | } |
51ff8149 BK |
477 | return __ret; |
478 | } | |
479 | ||
725dc051 | 480 | template<typename _CharT, typename _Traits> |
ed6814f7 | 481 | typename basic_filebuf<_CharT, _Traits>::int_type |
725dc051 BK |
482 | basic_filebuf<_CharT, _Traits>:: |
483 | pbackfail(int_type __i) | |
484 | { | |
485 | int_type __ret = traits_type::eof(); | |
a8e3a00f | 486 | const bool __testin = _M_mode & ios_base::in; |
3531cf5e | 487 | if (__testin) |
725dc051 | 488 | { |
47b90d6b DK |
489 | if (_M_writing) |
490 | { | |
491 | if (overflow() == traits_type::eof()) | |
492 | return __ret; | |
493 | _M_set_buffer(-1); | |
494 | _M_writing = false; | |
495 | } | |
b166bded PC |
496 | // Remember whether the pback buffer is active, otherwise below |
497 | // we may try to store in it a second char (libstdc++/9761). | |
a8e3a00f | 498 | const bool __testpb = _M_pback_init; |
0b176c1a | 499 | const bool __testeof = traits_type::eq_int_type(__i, __ret); |
b166bded | 500 | int_type __tmp; |
71b46021 | 501 | if (this->eback() < this->gptr()) |
725dc051 | 502 | { |
71b46021 PC |
503 | this->gbump(-1); |
504 | __tmp = traits_type::to_int_type(*this->gptr()); | |
b166bded | 505 | } |
4c4809c1 | 506 | else if (this->seekoff(-1, ios_base::cur) != pos_type(off_type(-1))) |
f24ce7c1 BK |
507 | { |
508 | __tmp = this->underflow(); | |
509 | if (traits_type::eq_int_type(__tmp, __ret)) | |
510 | return __ret; | |
511 | } | |
512 | else | |
46c4e5d6 BK |
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 | } | |
725dc051 | 521 | |
b166bded PC |
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(); | |
71b46021 | 531 | _M_reading = true; |
ed6814f7 | 532 | *this->gptr() = traits_type::to_char_type(__i); |
b166bded | 533 | __ret = __i; |
725dc051 | 534 | } |
725dc051 | 535 | } |
725dc051 BK |
536 | return __ret; |
537 | } | |
538 | ||
539 | template<typename _CharT, typename _Traits> | |
ed6814f7 | 540 | typename basic_filebuf<_CharT, _Traits>::int_type |
725dc051 BK |
541 | basic_filebuf<_CharT, _Traits>:: |
542 | overflow(int_type __c) | |
543 | { | |
544 | int_type __ret = traits_type::eof(); | |
002bd606 | 545 | const bool __testeof = traits_type::eq_int_type(__c, __ret); |
03fd2f60 PC |
546 | const bool __testout = (_M_mode & ios_base::out |
547 | || _M_mode & ios_base::app); | |
3531cf5e | 548 | if (__testout) |
725dc051 | 549 | { |
3531cf5e DK |
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 | } | |
71b46021 | 558 | if (this->pbase() < this->pptr()) |
002bd606 | 559 | { |
002bd606 BK |
560 | // If appropriate, append the overflow char. |
561 | if (!__testeof) | |
71b46021 PC |
562 | { |
563 | *this->pptr() = traits_type::to_char_type(__c); | |
564 | this->pbump(1); | |
565 | } | |
ed6814f7 | 566 | |
002bd606 | 567 | // Convert pending sequence to external representation, |
42134429 | 568 | // and output. |
71b46021 | 569 | if (_M_convert_to_external(this->pbase(), |
ee19761d | 570 | this->pptr() - this->pbase())) |
002bd606 BK |
571 | { |
572 | _M_set_buffer(0); | |
573 | __ret = traits_type::not_eof(__c); | |
574 | } | |
575 | } | |
a8e3a00f | 576 | else if (_M_buf_size > 1) |
71b46021 PC |
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 | } | |
002bd606 | 590 | else |
725dc051 | 591 | { |
002bd606 BK |
592 | // Unbuffered. |
593 | char_type __conv = traits_type::to_char_type(__c); | |
9335d80a | 594 | if (__testeof || _M_convert_to_external(&__conv, 1)) |
ed6814f7 | 595 | { |
71b46021 PC |
596 | _M_writing = true; |
597 | __ret = traits_type::not_eof(__c); | |
598 | } | |
725dc051 | 599 | } |
725dc051 | 600 | } |
725dc051 BK |
601 | return __ret; |
602 | } | |
ed6814f7 | 603 | |
07814743 | 604 | template<typename _CharT, typename _Traits> |
6e81c6f4 | 605 | bool |
07814743 | 606 | basic_filebuf<_CharT, _Traits>:: |
6e81c6f4 | 607 | _M_convert_to_external(_CharT* __ibuf, streamsize __ilen) |
07814743 | 608 | { |
6e81c6f4 | 609 | // Sizes of external and pending output. |
ac3cadf0 PC |
610 | streamsize __elen; |
611 | streamsize __plen; | |
c5b6351b | 612 | if (__check_facet(_M_codecvt).always_noconv()) |
07814743 | 613 | { |
ac3cadf0 PC |
614 | __elen = _M_file.xsputn(reinterpret_cast<char*>(__ibuf), __ilen); |
615 | __plen = __ilen; | |
07814743 BK |
616 | } |
617 | else | |
618 | { | |
619 | // Worst-case number of external bytes needed. | |
3461133d PC |
620 | // XXX Not done encoding() == -1. |
621 | streamsize __blen = __ilen * _M_codecvt->max_length(); | |
07814743 | 622 | char* __buf = static_cast<char*>(__builtin_alloca(__blen)); |
3461133d | 623 | |
07814743 BK |
624 | char* __bend; |
625 | const char_type* __iend; | |
a1796d12 | 626 | codecvt_base::result __r; |
0cd1de6f BK |
627 | __r = _M_codecvt->out(_M_state_cur, __ibuf, __ibuf + __ilen, |
628 | __iend, __buf, __buf + __blen, __bend); | |
ed6814f7 | 629 | |
130cd3e1 | 630 | if (__r == codecvt_base::ok || __r == codecvt_base::partial) |
07814743 | 631 | __blen = __bend - __buf; |
130cd3e1 PC |
632 | else if (__r == codecvt_base::noconv) |
633 | { | |
a1796d12 | 634 | // Same as the always_noconv case above. |
130cd3e1 PC |
635 | __buf = reinterpret_cast<char*>(__ibuf); |
636 | __blen = __ilen; | |
637 | } | |
a1796d12 | 638 | else |
ac3cadf0 PC |
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; | |
ed6814f7 | 644 | |
07814743 | 645 | // Try once more for partial conversions. |
ac3cadf0 | 646 | if (__r == codecvt_base::partial && __elen == __plen) |
07814743 BK |
647 | { |
648 | const char_type* __iresume = __iend; | |
71b46021 | 649 | streamsize __rlen = this->pptr() - __iend; |
0cd1de6f | 650 | __r = _M_codecvt->out(_M_state_cur, __iresume, |
ed6814f7 | 651 | __iresume + __rlen, __iend, __buf, |
0cd1de6f | 652 | __buf + __blen, __bend); |
07814743 | 653 | if (__r != codecvt_base::error) |
07814743 | 654 | { |
a1796d12 | 655 | __rlen = __bend - __buf; |
ac3cadf0 PC |
656 | __elen = _M_file.xsputn(__buf, __rlen); |
657 | __plen = __rlen; | |
07814743 | 658 | } |
ac3cadf0 PC |
659 | else |
660 | __throw_ios_failure(__N("basic_filebuf::_M_convert_to_external " | |
661 | "conversion error")); | |
07814743 BK |
662 | } |
663 | } | |
ac3cadf0 | 664 | return __elen == __plen; |
725dc051 BK |
665 | } |
666 | ||
47b90d6b DK |
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 | { | |
e020783c JW |
687 | if (overflow() == traits_type::eof()) |
688 | return __ret; | |
689 | _M_set_buffer(-1); | |
690 | _M_writing = false; | |
691 | } | |
47b90d6b DK |
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() | |
e020783c JW |
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 | } | |
47b90d6b | 712 | |
e020783c JW |
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 " | |
484e936e | 721 | "error reading the file"), errno); |
e020783c JW |
722 | if (__len == 0) |
723 | break; | |
47b90d6b | 724 | |
e020783c JW |
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 | } | |
47b90d6b | 747 | else |
e020783c | 748 | __ret += __streambuf_type::xsgetn(__s, __n); |
47b90d6b DK |
749 | |
750 | return __ret; | |
751 | } | |
c56e3d82 | 752 | |
47b90d6b DK |
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. | |
03fd2f60 PC |
762 | const bool __testout = (_M_mode & ios_base::out |
763 | || _M_mode & ios_base::app); | |
47b90d6b | 764 | if (__check_facet(_M_codecvt).always_noconv() |
e020783c | 765 | && __testout && !_M_reading) |
bda243ec PC |
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. | |
a8e3a00f BK |
772 | if (!_M_writing && _M_buf_size > 1) |
773 | __bufavail = _M_buf_size - 1; | |
bda243ec PC |
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, | |
ed6814f7 | 781 | reinterpret_cast<const char*>(__s), |
5e93f39f | 782 | __n); |
bda243ec PC |
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 | |
ed6814f7 | 797 | __ret = __streambuf_type::xsputn(__s, __n); |
bda243ec PC |
798 | return __ret; |
799 | } | |
800 | ||
990101f9 | 801 | template<typename _CharT, typename _Traits> |
ed6814f7 | 802 | typename basic_filebuf<_CharT, _Traits>::__streambuf_type* |
990101f9 BK |
803 | basic_filebuf<_CharT, _Traits>:: |
804 | setbuf(char_type* __s, streamsize __n) | |
805 | { | |
dfad48c6 | 806 | if (!this->is_open()) |
d9cdfe6a BK |
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 | } | |
ed6814f7 | 824 | return this; |
990101f9 | 825 | } |
ed6814f7 | 826 | |
8dcaff28 | 827 | |
1a139c59 PR |
828 | // According to 27.8.1.4 p11 - 13, seekoff should ignore the last |
829 | // argument (of type openmode). | |
725dc051 | 830 | template<typename _CharT, typename _Traits> |
31bfa177 | 831 | typename basic_filebuf<_CharT, _Traits>::pos_type |
725dc051 | 832 | basic_filebuf<_CharT, _Traits>:: |
8dcaff28 | 833 | seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode) |
725dc051 | 834 | { |
a1796d12 | 835 | int __width = 0; |
0cd1de6f | 836 | if (_M_codecvt) |
b417ae14 | 837 | __width = _M_codecvt->encoding(); |
725dc051 BK |
838 | if (__width < 0) |
839 | __width = 0; | |
a1796d12 | 840 | |
3531cf5e | 841 | pos_type __ret = pos_type(off_type(-1)); |
5e93f39f | 842 | const bool __testfail = __off != 0 && __width <= 0; |
ed6814f7 | 843 | if (this->is_open() && !__testfail) |
725dc051 | 844 | { |
3531cf5e DK |
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 | ||
725dc051 | 852 | // Ditch any pback buffers to avoid confusion. |
3531cf5e DK |
853 | if (!__no_movement) |
854 | _M_destroy_pback(); | |
725dc051 | 855 | |
5e93f39f PR |
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; | |
8c8dec01 | 862 | off_type __computed_off = __off * __width; |
1a139c59 | 863 | if (_M_reading && __way == ios_base::cur) |
8c8dec01 | 864 | { |
3531cf5e DK |
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 | ||
e020783c JW |
875 | off_type __file_off = _M_file.seekoff(0, ios_base::cur); |
876 | if (__file_off != off_type(-1)) | |
8c8dec01 | 877 | { |
3531cf5e DK |
878 | __ret = __file_off + __computed_off; |
879 | __ret.state(__state); | |
8c8dec01 PR |
880 | } |
881 | } | |
725dc051 | 882 | } |
725dc051 BK |
883 | return __ret; |
884 | } | |
885 | ||
1a139c59 PR |
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). | |
725dc051 | 890 | template<typename _CharT, typename _Traits> |
31bfa177 | 891 | typename basic_filebuf<_CharT, _Traits>::pos_type |
725dc051 | 892 | basic_filebuf<_CharT, _Traits>:: |
1a139c59 | 893 | seekpos(pos_type __pos, ios_base::openmode) |
725dc051 | 894 | { |
ed6814f7 BI |
895 | pos_type __ret = pos_type(off_type(-1)); |
896 | if (this->is_open()) | |
1a139c59 PR |
897 | { |
898 | // Ditch any pback buffers to avoid confusion. | |
899 | _M_destroy_pback(); | |
5e93f39f | 900 | __ret = _M_seek(off_type(__pos), ios_base::beg, __pos.state()); |
1a139c59 | 901 | } |
1a139c59 PR |
902 | return __ret; |
903 | } | |
904 | ||
905 | template<typename _CharT, typename _Traits> | |
906 | typename basic_filebuf<_CharT, _Traits>::pos_type | |
907 | basic_filebuf<_CharT, _Traits>:: | |
5e93f39f PR |
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()) | |
ed6814f7 | 912 | { |
3531cf5e DK |
913 | off_type __file_off = _M_file.seekoff(__off, __way); |
914 | if (__file_off != off_type(-1)) | |
d4d21a01 PC |
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; | |
3531cf5e | 921 | __ret = __file_off; |
d4d21a01 PC |
922 | __ret.state(_M_state_cur); |
923 | } | |
5e93f39f PR |
924 | } |
925 | return __ret; | |
926 | } | |
927 | ||
3531cf5e DK |
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 | ||
5e93f39f PR |
949 | template<typename _CharT, typename _Traits> |
950 | bool | |
951 | basic_filebuf<_CharT, _Traits>:: | |
952 | _M_terminate_output() | |
1a139c59 | 953 | { |
5e93f39f | 954 | // Part one: update the output sequence. |
42134429 | 955 | bool __testvalid = true; |
1a139c59 PR |
956 | if (this->pbase() < this->pptr()) |
957 | { | |
5e93f39f PR |
958 | const int_type __tmp = this->overflow(); |
959 | if (traits_type::eq_int_type(__tmp, traits_type::eof())) | |
960 | __testvalid = false; | |
961 | } | |
ed6814f7 | 962 | |
5e93f39f | 963 | // Part two: output unshift sequence. |
ed6814f7 | 964 | if (_M_writing && !__check_facet(_M_codecvt).always_noconv() |
5e93f39f PR |
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; | |
5e93f39f PR |
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 | { | |
ed6814f7 | 985 | __ilen = __next - __buf; |
5e93f39f PR |
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 | } | |
1a139c59 | 1006 | } |
5e93f39f | 1007 | return __testvalid; |
725dc051 BK |
1008 | } |
1009 | ||
1010 | template<typename _CharT, typename _Traits> | |
5e93f39f | 1011 | int |
725dc051 | 1012 | basic_filebuf<_CharT, _Traits>:: |
5e93f39f PR |
1013 | sync() |
1014 | { | |
5e93f39f PR |
1015 | // Make sure that the internal buffer resyncs its idea of |
1016 | // the file position with the external file. | |
42134429 | 1017 | int __ret = 0; |
5e93f39f PR |
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; | |
ed6814f7 | 1023 | } |
5e93f39f PR |
1024 | return __ret; |
1025 | } | |
725dc051 BK |
1026 | |
1027 | template<typename _CharT, typename _Traits> | |
1028 | void | |
1029 | basic_filebuf<_CharT, _Traits>:: | |
1030 | imbue(const locale& __loc) | |
1031 | { | |
09625c16 PC |
1032 | bool __testvalid = true; |
1033 | ||
1034 | const __codecvt_type* _M_codecvt_tmp = 0; | |
ed6814f7 BI |
1035 | if (__builtin_expect(has_facet<__codecvt_type>(__loc), true)) |
1036 | _M_codecvt_tmp = &use_facet<__codecvt_type>(__loc); | |
4c4809c1 | 1037 | |
09625c16 | 1038 | if (this->is_open()) |
c03d83d4 | 1039 | { |
09625c16 PC |
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; | |
c03d83d4 | 1044 | else |
09625c16 PC |
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()) | |
a8e3a00f | 1052 | __testvalid = this->seekoff(0, ios_base::cur, _M_mode) |
09625c16 PC |
1053 | != pos_type(off_type(-1)); |
1054 | } | |
1055 | else | |
1056 | { | |
1057 | // External position corresponding to gptr(). | |
ed6814f7 | 1058 | _M_ext_next = _M_ext_buf |
47b90d6b DK |
1059 | + _M_codecvt->length(_M_state_last, _M_ext_buf, |
1060 | _M_ext_next, | |
09625c16 PC |
1061 | this->gptr() - this->eback()); |
1062 | const streamsize __remainder = _M_ext_end - _M_ext_next; | |
1063 | if (__remainder) | |
538075fe | 1064 | __builtin_memmove(_M_ext_buf, _M_ext_next, __remainder); |
09625c16 PC |
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 | } | |
0cd1de6f | 1075 | } |
09625c16 PC |
1076 | |
1077 | if (__testvalid) | |
1078 | _M_codecvt = _M_codecvt_tmp; | |
2f228199 PC |
1079 | else |
1080 | _M_codecvt = 0; | |
725dc051 | 1081 | } |
a32e3c09 BK |
1082 | |
1083 | // Inhibit implicit instantiations for required instantiations, | |
ed6814f7 | 1084 | // which are defined via explicit instantiations elsewhere. |
3d7c150e | 1085 | #if _GLIBCXX_EXTERN_TEMPLATE |
a32e3c09 | 1086 | extern template class basic_filebuf<char>; |
a32e3c09 | 1087 | extern template class basic_ifstream<char>; |
a32e3c09 | 1088 | extern template class basic_ofstream<char>; |
a32e3c09 | 1089 | extern template class basic_fstream<char>; |
5112ae3a | 1090 | |
3d7c150e | 1091 | #ifdef _GLIBCXX_USE_WCHAR_T |
5112ae3a BK |
1092 | extern template class basic_filebuf<wchar_t>; |
1093 | extern template class basic_ifstream<wchar_t>; | |
1094 | extern template class basic_ofstream<wchar_t>; | |
a32e3c09 | 1095 | extern template class basic_fstream<wchar_t>; |
5112ae3a | 1096 | #endif |
1bc8b0ad | 1097 | #endif |
3cbc7af0 | 1098 | |
12ffa228 | 1099 | _GLIBCXX_END_NAMESPACE_VERSION |
ed4f96af | 1100 | } // namespace std |
725dc051 | 1101 | |
ed6814f7 | 1102 | #endif |