]>
Commit | Line | Data |
---|---|---|
725dc051 BK |
1 | // File based streams -*- C++ -*- |
2 | ||
8fbc5ae7 | 3 | // Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003 |
e6705174 | 4 | // Free Software Foundation, Inc. |
725dc051 BK |
5 | // |
6 | // This file is part of the GNU ISO C++ Library. This library is free | |
7 | // software; you can redistribute it and/or modify it under the | |
8 | // terms of the GNU General Public License as published by the | |
9 | // Free Software Foundation; either version 2, or (at your option) | |
10 | // any later version. | |
11 | ||
12 | // This library is distributed in the hope that it will be useful, | |
13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | // GNU General Public License for more details. | |
16 | ||
17 | // You should have received a copy of the GNU General Public License along | |
18 | // with this library; see the file COPYING. If not, write to the Free | |
19 | // Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, | |
20 | // USA. | |
21 | ||
22 | // As a special exception, you may use this file as part of a free software | |
23 | // library without restriction. Specifically, if other files instantiate | |
24 | // templates or use macros or inline functions from this file, or you compile | |
25 | // this file and link it with other files to produce an executable, this | |
26 | // file does not by itself cause the resulting executable to be covered by | |
27 | // the GNU General Public License. This exception does not however | |
28 | // invalidate any other reasons why the executable file might be covered by | |
29 | // the GNU General Public License. | |
30 | ||
31 | // | |
32 | // ISO C++ 14882: 27.8 File-based streams | |
33 | // | |
34 | ||
3d7c150e BK |
35 | #ifndef _FSTREAM_TCC |
36 | #define _FSTREAM_TCC 1 | |
725dc051 | 37 | |
3b794528 BK |
38 | #pragma GCC system_header |
39 | ||
725dc051 BK |
40 | namespace std |
41 | { | |
725dc051 BK |
42 | template<typename _CharT, typename _Traits> |
43 | void | |
44 | basic_filebuf<_CharT, _Traits>:: | |
990101f9 | 45 | _M_allocate_internal_buffer() |
725dc051 | 46 | { |
e3033a22 | 47 | if (!_M_buf_allocated && this->_M_buf_size) |
13187a45 | 48 | { |
eb98bd16 | 49 | // Allocate internal buffer. |
391cd095 | 50 | this->_M_buf = new char_type[this->_M_buf_size]; |
5cdd50a5 | 51 | _M_buf_allocated = true; |
990101f9 BK |
52 | } |
53 | } | |
54 | ||
55 | // Both close and setbuf need to deallocate internal buffers, if it exists. | |
56 | template<typename _CharT, typename _Traits> | |
57 | void | |
58 | basic_filebuf<_CharT, _Traits>:: | |
a1796d12 | 59 | _M_destroy_internal_buffer() throw() |
990101f9 BK |
60 | { |
61 | if (_M_buf_allocated) | |
62 | { | |
8fbc5ae7 MM |
63 | delete [] this->_M_buf; |
64 | this->_M_buf = NULL; | |
990101f9 | 65 | _M_buf_allocated = false; |
990101f9 | 66 | } |
f1813b69 PR |
67 | delete [] _M_ext_buf; |
68 | _M_ext_buf = NULL; | |
69 | _M_ext_buf_size = 0; | |
70 | _M_ext_next = NULL; | |
71 | _M_ext_end = NULL; | |
725dc051 BK |
72 | } |
73 | ||
74 | template<typename _CharT, typename _Traits> | |
75 | basic_filebuf<_CharT, _Traits>:: | |
5cdd50a5 | 76 | basic_filebuf() : __streambuf_type(), _M_file(&_M_lock), |
cd16e04b PC |
77 | _M_mode(ios_base::openmode(0)), _M_state_cur(__state_type()), |
78 | _M_state_beg(__state_type()), _M_buf(NULL), _M_buf_size(BUFSIZ), | |
79 | _M_buf_allocated(false), _M_reading(false), _M_writing(false), | |
80 | _M_last_overflowed(false), _M_pback_cur_save(0), _M_pback_end_save(0), | |
f1813b69 PR |
81 | _M_pback_init(false), _M_codecvt(0), _M_ext_buf(0), _M_ext_buf_size(0), |
82 | _M_ext_next(0), _M_ext_end(0) | |
0cd1de6f | 83 | { |
46c4e5d6 | 84 | if (has_facet<__codecvt_type>(this->_M_buf_locale)) |
0cd1de6f BK |
85 | _M_codecvt = &use_facet<__codecvt_type>(this->_M_buf_locale); |
86 | } | |
725dc051 | 87 | |
725dc051 | 88 | template<typename _CharT, typename _Traits> |
31bfa177 | 89 | typename basic_filebuf<_CharT, _Traits>::__filebuf_type* |
725dc051 BK |
90 | basic_filebuf<_CharT, _Traits>:: |
91 | open(const char* __s, ios_base::openmode __mode) | |
92 | { | |
93 | __filebuf_type *__ret = NULL; | |
94 | if (!this->is_open()) | |
95 | { | |
d3a193e3 | 96 | _M_file.open(__s, __mode); |
13187a45 | 97 | if (this->is_open()) |
725dc051 | 98 | { |
990101f9 | 99 | _M_allocate_internal_buffer(); |
8fbc5ae7 | 100 | this->_M_mode = __mode; |
6eeb7d7a | 101 | |
71b46021 PC |
102 | // Setup initial buffer to 'uncommitted' mode. |
103 | _M_reading = false; | |
104 | _M_writing = false; | |
105 | _M_set_buffer(-1); | |
6e52332e | 106 | |
cc5112c9 | 107 | // 27.8.1.3,4 |
e3033a22 | 108 | if ((__mode & ios_base::ate) |
725dc051 | 109 | && this->seekoff(0, ios_base::end, __mode) < 0) |
cc9d1c78 PC |
110 | this->close(); |
111 | else | |
112 | __ret = this; | |
725dc051 BK |
113 | } |
114 | } | |
115 | return __ret; | |
116 | } | |
117 | ||
118 | template<typename _CharT, typename _Traits> | |
31bfa177 | 119 | typename basic_filebuf<_CharT, _Traits>::__filebuf_type* |
725dc051 | 120 | basic_filebuf<_CharT, _Traits>:: |
a1796d12 | 121 | close() throw() |
725dc051 | 122 | { |
0c45b8e0 | 123 | __filebuf_type* __ret = NULL; |
725dc051 BK |
124 | if (this->is_open()) |
125 | { | |
0c45b8e0 | 126 | bool __testfail = false; |
a1796d12 BK |
127 | try |
128 | { | |
71b46021 | 129 | if (this->pbase() < this->pptr() |
1f0ef651 PC |
130 | && traits_type::eq_int_type(this->overflow(), |
131 | traits_type::eof())) | |
a1796d12 | 132 | __testfail = true; |
725dc051 | 133 | #if 0 |
a1796d12 BK |
134 | // XXX not done |
135 | if (_M_last_overflowed) | |
136 | { | |
137 | _M_output_unshift(); | |
002bd606 | 138 | this->overflow(); |
a1796d12 BK |
139 | } |
140 | #endif | |
141 | } | |
142 | catch(...) | |
725dc051 | 143 | { |
a1796d12 | 144 | __testfail = true; |
725dc051 | 145 | } |
a1796d12 | 146 | |
0c45b8e0 BK |
147 | // NB: Do this here so that re-opened filebufs will be cool... |
148 | this->_M_mode = ios_base::openmode(0); | |
cd96b185 | 149 | this->_M_pback_init = false; |
0c45b8e0 | 150 | _M_destroy_internal_buffer(); |
71b46021 PC |
151 | _M_reading = false; |
152 | _M_writing = false; | |
153 | _M_set_buffer(-1); | |
a1796d12 | 154 | |
0c45b8e0 BK |
155 | if (!_M_file.close()) |
156 | __testfail = true; | |
157 | ||
158 | if (!__testfail) | |
d3a193e3 | 159 | __ret = this; |
725dc051 | 160 | } |
a1796d12 | 161 | _M_last_overflowed = false; |
725dc051 BK |
162 | return __ret; |
163 | } | |
164 | ||
165 | template<typename _CharT, typename _Traits> | |
166 | streamsize | |
167 | basic_filebuf<_CharT, _Traits>:: | |
168 | showmanyc() | |
169 | { | |
170 | streamsize __ret = -1; | |
0b176c1a | 171 | const bool __testin = this->_M_mode & ios_base::in; |
725dc051 | 172 | |
9fbcb61a | 173 | if (__testin && this->is_open()) |
bbacb998 | 174 | { |
bbacb998 PC |
175 | // For a stateful encoding (-1) the pending sequence might be just |
176 | // shift and unshift prefixes with no actual character. | |
71b46021 | 177 | __ret = this->egptr() - this->gptr(); |
0cd1de6f BK |
178 | if (__check_facet(_M_codecvt).encoding() >= 0) |
179 | __ret += _M_file.showmanyc() / _M_codecvt->max_length(); | |
bbacb998 PC |
180 | } |
181 | ||
725dc051 BK |
182 | _M_last_overflowed = false; |
183 | return __ret; | |
184 | } | |
725dc051 | 185 | |
51ff8149 BK |
186 | template<typename _CharT, typename _Traits> |
187 | typename basic_filebuf<_CharT, _Traits>::int_type | |
6e81c6f4 | 188 | basic_filebuf<_CharT, _Traits>:: |
cd16e04b | 189 | underflow() |
51ff8149 BK |
190 | { |
191 | int_type __ret = traits_type::eof(); | |
192 | const bool __testin = this->_M_mode & ios_base::in; | |
193 | const bool __testout = this->_M_mode & ios_base::out; | |
194 | ||
71b46021 | 195 | if (__testin && !_M_writing) |
51ff8149 BK |
196 | { |
197 | // Check for pback madness, and if so swich back to the | |
198 | // normal buffers and jet outta here before expensive | |
199 | // fileops happen... | |
0aef8de2 | 200 | _M_destroy_pback(); |
51ff8149 | 201 | |
71b46021 | 202 | if (this->gptr() < this->egptr()) |
cd16e04b | 203 | return traits_type::to_int_type(*this->gptr()); |
51ff8149 | 204 | |
f10eea7b | 205 | // Get and convert input sequence. |
9335d80a PC |
206 | const size_t __buflen = this->_M_buf_size > 1 |
207 | ? this->_M_buf_size - 1 : 1; | |
f1813b69 PR |
208 | |
209 | // Will be set to true if ::read() returns 0 indicating EOF. | |
210 | bool __got_eof = false; | |
211 | // Number of internal characters produced. | |
f10eea7b PC |
212 | streamsize __ilen = 0; |
213 | if (__check_facet(_M_codecvt).always_noconv()) | |
214 | { | |
f1813b69 | 215 | __ilen = _M_file.xsgetn(reinterpret_cast<char*>(this->eback()), |
cc5112c9 | 216 | __buflen); |
f1813b69 PR |
217 | if (__ilen == 0) |
218 | __got_eof = true; | |
f10eea7b PC |
219 | } |
220 | else | |
221 | { | |
f1813b69 PR |
222 | // Worst-case number of external bytes. |
223 | // XXX Not done encoding() == -1. | |
224 | const int __enc = _M_codecvt->encoding(); | |
225 | streamsize __blen; // Minimum buffer size. | |
226 | streamsize __rlen; // Number of chars to read. | |
227 | if (__enc > 0) | |
228 | __blen = __rlen = __buflen * __enc; | |
229 | else | |
51ff8149 | 230 | { |
f1813b69 PR |
231 | __blen = __buflen + _M_codecvt->max_length() - 1; |
232 | __rlen = __buflen; | |
51ff8149 | 233 | } |
f1813b69 PR |
234 | const streamsize __remainder = _M_ext_end - _M_ext_next; |
235 | __rlen = __rlen > __remainder ? __rlen - __remainder : 0; | |
236 | ||
237 | // Allocate buffer if necessary and move unconverted | |
238 | // bytes to front. | |
239 | if (_M_ext_buf_size < __blen) | |
240 | { | |
241 | char* __buf = new char[__blen]; | |
242 | if (__remainder > 0) | |
243 | std::memcpy(__buf, _M_ext_next, __remainder); | |
244 | ||
245 | delete [] _M_ext_buf; | |
246 | _M_ext_buf = __buf; | |
247 | _M_ext_buf_size = __blen; | |
248 | } | |
249 | else if (__remainder > 0) | |
250 | std::memmove(_M_ext_buf, _M_ext_next, __remainder); | |
251 | ||
252 | _M_ext_next = _M_ext_buf; | |
253 | _M_ext_end = _M_ext_buf + __remainder; | |
254 | ||
255 | do | |
51ff8149 | 256 | { |
f1813b69 PR |
257 | if (__rlen > 0) |
258 | { | |
259 | // Sanity check! | |
260 | // This may fail if the return value of | |
261 | // codecvt::max_length() is bogus. | |
262 | if (_M_ext_end - _M_ext_buf + __rlen > _M_ext_buf_size) | |
263 | std::abort(); | |
264 | streamsize __elen = _M_file.xsgetn(_M_ext_end, __rlen); | |
265 | if (__elen == 0) | |
266 | __got_eof = true; | |
267 | _M_ext_end += __elen; | |
268 | } | |
269 | ||
270 | char_type* __iend; | |
271 | codecvt_base::result __r; | |
272 | __r = _M_codecvt->in(_M_state_cur, _M_ext_next, | |
273 | _M_ext_end, _M_ext_next, this->eback(), | |
274 | this->eback() + __buflen, __iend); | |
275 | if (__r == codecvt_base::ok || __r == codecvt_base::partial) | |
276 | __ilen = __iend - this->eback(); | |
277 | else if (__r == codecvt_base::noconv) | |
278 | { | |
279 | size_t __avail = _M_ext_end - _M_ext_buf; | |
280 | __ilen = std::min(__avail, __buflen); | |
281 | traits_type::copy(this->eback(), | |
282 | reinterpret_cast<char_type*>(_M_ext_buf), | |
283 | __ilen); | |
284 | _M_ext_next = _M_ext_buf + __ilen; | |
285 | } | |
286 | else | |
287 | { | |
288 | __ilen = 0; | |
289 | break; | |
290 | } | |
291 | __rlen = 1; | |
51ff8149 | 292 | } |
f1813b69 | 293 | while (!__got_eof && __ilen == 0); |
46c4e5d6 | 294 | } |
f10eea7b PC |
295 | |
296 | if (__ilen > 0) | |
46c4e5d6 | 297 | { |
f10eea7b | 298 | _M_set_buffer(__ilen); |
71b46021 PC |
299 | _M_reading = true; |
300 | __ret = traits_type::to_int_type(*this->gptr()); | |
2cfe4e68 | 301 | } |
f1813b69 | 302 | else if (__got_eof) |
2cfe4e68 PC |
303 | { |
304 | // If the actual end of file is reached, set 'uncommitted' | |
305 | // mode, thus allowing an immediate write without an | |
306 | // intervening seek. | |
307 | _M_set_buffer(-1); | |
308 | _M_reading = false; | |
309 | } | |
51ff8149 BK |
310 | } |
311 | _M_last_overflowed = false; | |
312 | return __ret; | |
313 | } | |
314 | ||
725dc051 | 315 | template<typename _CharT, typename _Traits> |
31bfa177 | 316 | typename basic_filebuf<_CharT, _Traits>::int_type |
725dc051 BK |
317 | basic_filebuf<_CharT, _Traits>:: |
318 | pbackfail(int_type __i) | |
319 | { | |
320 | int_type __ret = traits_type::eof(); | |
0b176c1a | 321 | const bool __testin = this->_M_mode & ios_base::in; |
725dc051 | 322 | |
71b46021 | 323 | if (__testin && !_M_writing) |
725dc051 | 324 | { |
b166bded PC |
325 | // Remember whether the pback buffer is active, otherwise below |
326 | // we may try to store in it a second char (libstdc++/9761). | |
327 | const bool __testpb = this->_M_pback_init; | |
0b176c1a | 328 | const bool __testeof = traits_type::eq_int_type(__i, __ret); |
b166bded PC |
329 | |
330 | int_type __tmp; | |
71b46021 | 331 | if (this->eback() < this->gptr()) |
725dc051 | 332 | { |
71b46021 PC |
333 | this->gbump(-1); |
334 | __tmp = traits_type::to_int_type(*this->gptr()); | |
b166bded | 335 | } |
f24ce7c1 BK |
336 | else if (this->seekoff(-1, ios_base::cur) >= 0) |
337 | { | |
338 | __tmp = this->underflow(); | |
339 | if (traits_type::eq_int_type(__tmp, __ret)) | |
340 | return __ret; | |
341 | } | |
342 | else | |
46c4e5d6 BK |
343 | { |
344 | // At the beginning of the buffer, need to make a | |
345 | // putback position available. But the seek may fail | |
346 | // (f.i., at the beginning of a file, see | |
347 | // libstdc++/9439) and in that case we return | |
348 | // traits_type::eof(). | |
349 | return __ret; | |
350 | } | |
725dc051 | 351 | |
b166bded PC |
352 | // Try to put back __i into input sequence in one of three ways. |
353 | // Order these tests done in is unspecified by the standard. | |
354 | if (!__testeof && traits_type::eq_int_type(__i, __tmp)) | |
355 | __ret = __i; | |
356 | else if (__testeof) | |
357 | __ret = traits_type::not_eof(__i); | |
358 | else if (!__testpb) | |
359 | { | |
360 | _M_create_pback(); | |
71b46021 PC |
361 | _M_reading = true; |
362 | *this->gptr() = traits_type::to_char_type(__i); | |
b166bded | 363 | __ret = __i; |
725dc051 | 364 | } |
725dc051 BK |
365 | } |
366 | _M_last_overflowed = false; | |
367 | return __ret; | |
368 | } | |
369 | ||
370 | template<typename _CharT, typename _Traits> | |
31bfa177 | 371 | typename basic_filebuf<_CharT, _Traits>::int_type |
725dc051 BK |
372 | basic_filebuf<_CharT, _Traits>:: |
373 | overflow(int_type __c) | |
374 | { | |
375 | int_type __ret = traits_type::eof(); | |
002bd606 | 376 | const bool __testeof = traits_type::eq_int_type(__c, __ret); |
0b176c1a | 377 | const bool __testout = this->_M_mode & ios_base::out; |
725dc051 | 378 | |
71b46021 | 379 | if (__testout && !_M_reading) |
725dc051 | 380 | { |
71b46021 | 381 | if (this->pbase() < this->pptr()) |
002bd606 | 382 | { |
002bd606 BK |
383 | // If appropriate, append the overflow char. |
384 | if (!__testeof) | |
71b46021 PC |
385 | { |
386 | *this->pptr() = traits_type::to_char_type(__c); | |
387 | this->pbump(1); | |
388 | } | |
002bd606 BK |
389 | |
390 | // Convert pending sequence to external representation, | |
391 | // output. | |
71b46021 PC |
392 | if (_M_convert_to_external(this->pbase(), |
393 | this->pptr() - this->pbase()) | |
002bd606 BK |
394 | && (!__testeof || (__testeof && !_M_file.sync()))) |
395 | { | |
396 | _M_set_buffer(0); | |
397 | __ret = traits_type::not_eof(__c); | |
398 | } | |
399 | } | |
71b46021 PC |
400 | else if (this->_M_buf_size > 1) |
401 | { | |
402 | // Overflow in 'uncommitted' mode: set _M_writing, set | |
403 | // the buffer to the initial 'write' mode, and put __c | |
404 | // into the buffer. | |
405 | _M_set_buffer(0); | |
406 | _M_writing = true; | |
407 | if (!__testeof) | |
408 | { | |
409 | *this->pptr() = traits_type::to_char_type(__c); | |
410 | this->pbump(1); | |
411 | } | |
412 | __ret = traits_type::not_eof(__c); | |
413 | } | |
002bd606 | 414 | else |
725dc051 | 415 | { |
002bd606 BK |
416 | // Unbuffered. |
417 | char_type __conv = traits_type::to_char_type(__c); | |
9335d80a | 418 | if (__testeof || _M_convert_to_external(&__conv, 1)) |
71b46021 PC |
419 | { |
420 | _M_writing = true; | |
421 | __ret = traits_type::not_eof(__c); | |
422 | } | |
725dc051 | 423 | } |
725dc051 | 424 | } |
002bd606 | 425 | _M_last_overflowed = true; |
725dc051 BK |
426 | return __ret; |
427 | } | |
428 | ||
07814743 | 429 | template<typename _CharT, typename _Traits> |
6e81c6f4 | 430 | bool |
07814743 | 431 | basic_filebuf<_CharT, _Traits>:: |
6e81c6f4 | 432 | _M_convert_to_external(_CharT* __ibuf, streamsize __ilen) |
07814743 | 433 | { |
6e81c6f4 BK |
434 | // Sizes of external and pending output. |
435 | streamsize __elen = 0; | |
436 | streamsize __plen = 0; | |
437 | ||
c5b6351b | 438 | if (__check_facet(_M_codecvt).always_noconv()) |
07814743 | 439 | { |
51ff8149 | 440 | __elen += _M_file.xsputn(reinterpret_cast<char*>(__ibuf), __ilen); |
07814743 BK |
441 | __plen += __ilen; |
442 | } | |
443 | else | |
444 | { | |
445 | // Worst-case number of external bytes needed. | |
3461133d PC |
446 | // XXX Not done encoding() == -1. |
447 | streamsize __blen = __ilen * _M_codecvt->max_length(); | |
07814743 | 448 | char* __buf = static_cast<char*>(__builtin_alloca(__blen)); |
3461133d | 449 | |
07814743 BK |
450 | char* __bend; |
451 | const char_type* __iend; | |
a1796d12 | 452 | codecvt_base::result __r; |
0cd1de6f BK |
453 | __r = _M_codecvt->out(_M_state_cur, __ibuf, __ibuf + __ilen, |
454 | __iend, __buf, __buf + __blen, __bend); | |
a1796d12 | 455 | |
130cd3e1 | 456 | if (__r == codecvt_base::ok || __r == codecvt_base::partial) |
07814743 | 457 | __blen = __bend - __buf; |
130cd3e1 PC |
458 | else if (__r == codecvt_base::noconv) |
459 | { | |
a1796d12 | 460 | // Same as the always_noconv case above. |
130cd3e1 PC |
461 | __buf = reinterpret_cast<char*>(__ibuf); |
462 | __blen = __ilen; | |
463 | } | |
a1796d12 BK |
464 | else |
465 | { | |
71b46021 | 466 | // Result == error. |
a1796d12 BK |
467 | __blen = 0; |
468 | } | |
07814743 BK |
469 | |
470 | if (__blen) | |
471 | { | |
51ff8149 | 472 | __elen += _M_file.xsputn(__buf, __blen); |
07814743 BK |
473 | __plen += __blen; |
474 | } | |
a1796d12 | 475 | |
07814743 BK |
476 | // Try once more for partial conversions. |
477 | if (__r == codecvt_base::partial) | |
478 | { | |
479 | const char_type* __iresume = __iend; | |
71b46021 | 480 | streamsize __rlen = this->pptr() - __iend; |
0cd1de6f BK |
481 | __r = _M_codecvt->out(_M_state_cur, __iresume, |
482 | __iresume + __rlen, __iend, __buf, | |
483 | __buf + __blen, __bend); | |
07814743 | 484 | if (__r != codecvt_base::error) |
07814743 | 485 | { |
a1796d12 | 486 | __rlen = __bend - __buf; |
51ff8149 | 487 | __elen += _M_file.xsputn(__buf, __rlen); |
07814743 BK |
488 | __plen += __rlen; |
489 | } | |
490 | } | |
491 | } | |
6e81c6f4 | 492 | return __elen && __elen == __plen; |
725dc051 BK |
493 | } |
494 | ||
bda243ec PC |
495 | template<typename _CharT, typename _Traits> |
496 | streamsize | |
497 | basic_filebuf<_CharT, _Traits>:: | |
498 | xsputn(const _CharT* __s, streamsize __n) | |
499 | { | |
500 | streamsize __ret = 0; | |
501 | ||
502 | // Optimization in the always_noconv() case, to be generalized in the | |
503 | // future: when __n is sufficiently large we write directly instead of | |
504 | // using the buffer. | |
505 | const bool __testout = this->_M_mode & ios_base::out; | |
506 | if (__testout && !_M_reading | |
507 | && __check_facet(_M_codecvt).always_noconv()) | |
508 | { | |
509 | // Measurement would reveal the best choice. | |
510 | const streamsize __chunk = 1ul << 10; | |
511 | streamsize __bufavail = this->epptr() - this->pptr(); | |
512 | ||
513 | // Don't mistake 'uncommitted' mode buffered with unbuffered. | |
514 | if (!_M_writing && this->_M_buf_size > 1) | |
515 | __bufavail = this->_M_buf_size - 1; | |
516 | ||
517 | const streamsize __limit = std::min(__chunk, __bufavail); | |
518 | if (__n >= __limit) | |
519 | { | |
520 | const streamsize __buffill = this->pptr() - this->pbase(); | |
521 | const char* __buf = reinterpret_cast<const char*>(this->pbase()); | |
522 | __ret = _M_file.xsputn_2(__buf, __buffill, | |
523 | reinterpret_cast<const char*>(__s), __n); | |
524 | if (__ret == __buffill + __n) | |
525 | { | |
526 | _M_set_buffer(0); | |
527 | _M_writing = true; | |
528 | } | |
529 | if (__ret > __buffill) | |
530 | __ret -= __buffill; | |
531 | else | |
532 | __ret = 0; | |
533 | } | |
534 | else | |
535 | __ret = __streambuf_type::xsputn(__s, __n); | |
536 | } | |
537 | else | |
538 | __ret = __streambuf_type::xsputn(__s, __n); | |
539 | ||
540 | return __ret; | |
541 | } | |
542 | ||
990101f9 | 543 | template<typename _CharT, typename _Traits> |
31bfa177 | 544 | typename basic_filebuf<_CharT, _Traits>::__streambuf_type* |
990101f9 BK |
545 | basic_filebuf<_CharT, _Traits>:: |
546 | setbuf(char_type* __s, streamsize __n) | |
547 | { | |
548 | if (!this->is_open() && __s == 0 && __n == 0) | |
f10eea7b | 549 | this->_M_buf_size = 1; |
b82a33d2 | 550 | else if (__s && __n > 0) |
990101f9 | 551 | { |
e3033a22 | 552 | // This is implementation-defined behavior, and assumes that |
c1b74c21 NM |
553 | // an external char_type array of length __n exists and has |
554 | // been pre-allocated. If this is not the case, things will | |
555 | // quickly blow up. When __n > 1, __n - 1 positions will be | |
556 | // used for the get area, __n - 1 for the put area and 1 | |
557 | // position to host the overflow char of a full put area. | |
558 | // When __n == 1, 1 position will be used for the get area | |
559 | // and 0 for the put area, as in the unbuffered case above. | |
391cd095 | 560 | |
990101f9 BK |
561 | // Step 1: Destroy the current internal array. |
562 | _M_destroy_internal_buffer(); | |
563 | ||
564 | // Step 2: Use the external array. | |
8fbc5ae7 | 565 | this->_M_buf = __s; |
7ef9fd85 | 566 | this->_M_buf_size = __n; |
71b46021 PC |
567 | _M_reading = false; |
568 | _M_writing = false; | |
569 | _M_set_buffer(-1); | |
990101f9 BK |
570 | } |
571 | _M_last_overflowed = false; | |
572 | return this; | |
573 | } | |
574 | ||
725dc051 | 575 | template<typename _CharT, typename _Traits> |
31bfa177 | 576 | typename basic_filebuf<_CharT, _Traits>::pos_type |
725dc051 BK |
577 | basic_filebuf<_CharT, _Traits>:: |
578 | seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode __mode) | |
579 | { | |
580 | pos_type __ret = pos_type(off_type(-1)); | |
0b176c1a PC |
581 | const bool __testin = (ios_base::in & this->_M_mode & __mode) != 0; |
582 | const bool __testout = (ios_base::out & this->_M_mode & __mode) != 0; | |
95dca20c | 583 | |
a1796d12 | 584 | int __width = 0; |
0cd1de6f | 585 | if (_M_codecvt) |
b417ae14 | 586 | __width = _M_codecvt->encoding(); |
725dc051 BK |
587 | if (__width < 0) |
588 | __width = 0; | |
a1796d12 BK |
589 | |
590 | const bool __testfail = __off != 0 && __width <= 0; | |
dcf5a5de | 591 | if (this->is_open() && !__testfail && (__testin || __testout)) |
725dc051 BK |
592 | { |
593 | // Ditch any pback buffers to avoid confusion. | |
aa438e8f | 594 | _M_destroy_pback(); |
725dc051 | 595 | |
8c8dec01 | 596 | off_type __computed_off = __off * __width; |
cc5112c9 | 597 | if (this->pbase() < this->pptr()) |
725dc051 | 598 | { |
71b46021 PC |
599 | // Part one: update the output sequence. |
600 | this->sync(); | |
601 | ||
602 | // Part two: output unshift sequence. | |
603 | _M_output_unshift(); | |
725dc051 | 604 | } |
71b46021 | 605 | else if (_M_reading && __way == ios_base::cur) |
8c8dec01 PR |
606 | { |
607 | if (_M_codecvt->always_noconv()) | |
608 | __computed_off += this->gptr() - this->egptr(); | |
609 | else | |
610 | { | |
611 | // Calculate offset from _M_ext_buf that corresponds | |
612 | // to gptr(). | |
613 | const int __gptr_off = | |
614 | _M_codecvt->length(_M_state_cur, _M_ext_buf, _M_ext_next, | |
615 | this->gptr() - this->eback()); | |
616 | __computed_off += _M_ext_buf + __gptr_off - _M_ext_end; | |
617 | } | |
618 | } | |
71b46021 | 619 | |
cc5112c9 | 620 | // Returns pos_type(off_type(-1)) in case of failure. |
8c8dec01 | 621 | __ret = _M_file.seekoff(__computed_off, __way, __mode); |
b417ae14 | 622 | |
71b46021 PC |
623 | _M_reading = false; |
624 | _M_writing = false; | |
8c8dec01 | 625 | _M_ext_next = _M_ext_end = _M_ext_buf; |
71b46021 | 626 | _M_set_buffer(-1); |
725dc051 BK |
627 | } |
628 | _M_last_overflowed = false; | |
629 | return __ret; | |
630 | } | |
631 | ||
632 | template<typename _CharT, typename _Traits> | |
31bfa177 | 633 | typename basic_filebuf<_CharT, _Traits>::pos_type |
725dc051 BK |
634 | basic_filebuf<_CharT, _Traits>:: |
635 | seekpos(pos_type __pos, ios_base::openmode __mode) | |
636 | { | |
3d7c150e | 637 | #ifdef _GLIBCXX_RESOLVE_LIB_DEFECTS |
b988dfc5 | 638 | // 171. Strange seekpos() semantics due to joint position |
b417ae14 PC |
639 | pos_type __ret = pos_type(off_type(-1)); |
640 | ||
641 | int __width = 0; | |
642 | if (_M_codecvt) | |
643 | __width = _M_codecvt->encoding(); | |
644 | if (__width > 0) | |
645 | __ret = this->seekoff(off_type(__pos) / __width, ios_base::beg, __mode); | |
646 | ||
647 | return __ret; | |
b988dfc5 | 648 | #endif |
725dc051 BK |
649 | } |
650 | ||
651 | template<typename _CharT, typename _Traits> | |
652 | void | |
653 | basic_filebuf<_CharT, _Traits>:: | |
654 | _M_output_unshift() | |
655 | { } | |
656 | ||
657 | template<typename _CharT, typename _Traits> | |
658 | void | |
659 | basic_filebuf<_CharT, _Traits>:: | |
660 | imbue(const locale& __loc) | |
661 | { | |
0cd1de6f BK |
662 | const bool __testbeg = !this->seekoff(0, ios_base::cur, this->_M_mode); |
663 | const bool __teststate = __check_facet(_M_codecvt).encoding() == -1; | |
69302d8b | 664 | |
0cd1de6f BK |
665 | if (this->_M_buf_locale != __loc |
666 | && (!this->is_open() || (__testbeg && !__teststate))) | |
667 | { | |
668 | this->_M_buf_locale = __loc; | |
669 | if (__builtin_expect(has_facet<__codecvt_type>(__loc), true)) | |
670 | _M_codecvt = &use_facet<__codecvt_type>(__loc); | |
671 | ||
672 | // NB This may require the reconversion of previously | |
673 | // converted chars. This in turn may cause the | |
674 | // reconstruction of the original file. YIKES!! This | |
675 | // implementation interprets this requirement as requiring | |
676 | // the file position be at the beginning, and a stateless | |
677 | // encoding, or that the filebuf be closed. Opinions may differ. | |
678 | } | |
725dc051 BK |
679 | _M_last_overflowed = false; |
680 | } | |
a32e3c09 BK |
681 | |
682 | // Inhibit implicit instantiations for required instantiations, | |
683 | // which are defined via explicit instantiations elsewhere. | |
684 | // NB: This syntax is a GNU extension. | |
3d7c150e | 685 | #if _GLIBCXX_EXTERN_TEMPLATE |
a32e3c09 | 686 | extern template class basic_filebuf<char>; |
a32e3c09 | 687 | extern template class basic_ifstream<char>; |
a32e3c09 | 688 | extern template class basic_ofstream<char>; |
a32e3c09 | 689 | extern template class basic_fstream<char>; |
5112ae3a | 690 | |
3d7c150e | 691 | #ifdef _GLIBCXX_USE_WCHAR_T |
5112ae3a BK |
692 | extern template class basic_filebuf<wchar_t>; |
693 | extern template class basic_ifstream<wchar_t>; | |
694 | extern template class basic_ofstream<wchar_t>; | |
a32e3c09 | 695 | extern template class basic_fstream<wchar_t>; |
5112ae3a | 696 | #endif |
1bc8b0ad | 697 | #endif |
725dc051 BK |
698 | } // namespace std |
699 | ||
6f48900c | 700 | #endif |