]>
Commit | Line | Data |
---|---|---|
725dc051 BK |
1 | // File based streams -*- C++ -*- |
2 | ||
e6705174 BK |
3 | // Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 |
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 | ||
35 | #ifndef _CPP_BITS_FSTREAM_TCC | |
36 | #define _CPP_BITS_FSTREAM_TCC 1 | |
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 | { |
990101f9 | 47 | if (!_M_buf && _M_buf_size_opt) |
13187a45 BK |
48 | { |
49 | _M_buf_size = _M_buf_size_opt; | |
990101f9 | 50 | |
5cdd50a5 | 51 | // Allocate internal buffer. |
540f5c9b | 52 | _M_buf = new char_type[_M_buf_size]; |
5cdd50a5 | 53 | _M_buf_allocated = true; |
990101f9 BK |
54 | } |
55 | } | |
56 | ||
57 | // Both close and setbuf need to deallocate internal buffers, if it exists. | |
58 | template<typename _CharT, typename _Traits> | |
59 | void | |
60 | basic_filebuf<_CharT, _Traits>:: | |
61 | _M_destroy_internal_buffer() | |
62 | { | |
63 | if (_M_buf_allocated) | |
64 | { | |
65 | delete [] _M_buf; | |
66 | _M_buf = NULL; | |
67 | _M_buf_allocated = false; | |
68 | this->setg(NULL, NULL, NULL); | |
69 | this->setp(NULL, NULL); | |
70 | } | |
725dc051 BK |
71 | } |
72 | ||
73 | template<typename _CharT, typename _Traits> | |
74 | basic_filebuf<_CharT, _Traits>:: | |
5cdd50a5 BK |
75 | basic_filebuf() : __streambuf_type(), _M_file(&_M_lock), |
76 | _M_state_cur(__state_type()), _M_state_beg(__state_type()), | |
77 | _M_buf_allocated(false), _M_last_overflowed(false) | |
d3a193e3 | 78 | { _M_buf_unified = true; } |
725dc051 | 79 | |
725dc051 | 80 | template<typename _CharT, typename _Traits> |
31bfa177 | 81 | typename basic_filebuf<_CharT, _Traits>::__filebuf_type* |
725dc051 BK |
82 | basic_filebuf<_CharT, _Traits>:: |
83 | open(const char* __s, ios_base::openmode __mode) | |
84 | { | |
85 | __filebuf_type *__ret = NULL; | |
86 | if (!this->is_open()) | |
87 | { | |
d3a193e3 | 88 | _M_file.open(__s, __mode); |
13187a45 | 89 | if (this->is_open()) |
725dc051 | 90 | { |
990101f9 | 91 | _M_allocate_internal_buffer(); |
725dc051 | 92 | _M_mode = __mode; |
6eeb7d7a BK |
93 | |
94 | // Setup initial position of buffer. | |
725dc051 | 95 | _M_set_indeterminate(); |
6e52332e | 96 | |
6eeb7d7a BK |
97 | // Set input buffer to something real. |
98 | // NB: Must open in non-blocking way to do this, or must | |
99 | // set the initial position in a different manner than | |
100 | // using underflow. | |
101 | if (__mode & ios_base::in && _M_buf_allocated) | |
102 | this->underflow(); | |
103 | ||
b7737230 | 104 | if ((__mode & ios_base::ate) |
725dc051 BK |
105 | && this->seekoff(0, ios_base::end, __mode) < 0) |
106 | this->close(); | |
6eeb7d7a | 107 | |
725dc051 BK |
108 | __ret = this; |
109 | } | |
110 | } | |
111 | return __ret; | |
112 | } | |
113 | ||
114 | template<typename _CharT, typename _Traits> | |
31bfa177 | 115 | typename basic_filebuf<_CharT, _Traits>::__filebuf_type* |
725dc051 BK |
116 | basic_filebuf<_CharT, _Traits>:: |
117 | close() | |
118 | { | |
119 | __filebuf_type *__ret = NULL; | |
120 | if (this->is_open()) | |
121 | { | |
e6705174 | 122 | const int_type __eof = traits_type::eof(); |
725dc051 | 123 | bool __testput = _M_out_cur && _M_out_beg < _M_out_end; |
f13a69ec BK |
124 | if (__testput |
125 | && traits_type::eq_int_type(_M_really_overflow(__eof), __eof)) | |
e6705174 | 126 | return __ret; |
725dc051 | 127 | |
e6705174 BK |
128 | // NB: Do this here so that re-opened filebufs will be cool... |
129 | _M_mode = ios_base::openmode(0); | |
130 | _M_destroy_internal_buffer(); | |
e6705174 | 131 | _M_pback_destroy(); |
e6705174 | 132 | |
725dc051 BK |
133 | #if 0 |
134 | // XXX not done | |
135 | if (_M_last_overflowed) | |
136 | { | |
137 | _M_output_unshift(); | |
e6705174 | 138 | _M_really_overflow(__eof); |
725dc051 BK |
139 | } |
140 | #endif | |
725dc051 | 141 | |
d3a193e3 BK |
142 | if (_M_file.close()) |
143 | __ret = this; | |
725dc051 | 144 | } |
d3a193e3 | 145 | |
725dc051 BK |
146 | _M_last_overflowed = false; |
147 | return __ret; | |
148 | } | |
149 | ||
150 | template<typename _CharT, typename _Traits> | |
151 | streamsize | |
152 | basic_filebuf<_CharT, _Traits>:: | |
153 | showmanyc() | |
154 | { | |
155 | streamsize __ret = -1; | |
156 | bool __testin = _M_mode & ios_base::in; | |
157 | ||
9fbcb61a | 158 | if (__testin && this->is_open()) |
6e52332e | 159 | __ret = _M_in_end - _M_in_cur; |
725dc051 BK |
160 | _M_last_overflowed = false; |
161 | return __ret; | |
162 | } | |
725dc051 BK |
163 | |
164 | template<typename _CharT, typename _Traits> | |
31bfa177 | 165 | typename basic_filebuf<_CharT, _Traits>::int_type |
725dc051 BK |
166 | basic_filebuf<_CharT, _Traits>:: |
167 | pbackfail(int_type __i) | |
168 | { | |
169 | int_type __ret = traits_type::eof(); | |
170 | bool __testin = _M_mode & ios_base::in; | |
171 | ||
172 | if (__testin) | |
173 | { | |
174 | bool __testpb = _M_in_beg < _M_in_cur; | |
175 | char_type __c = traits_type::to_char_type(__i); | |
176 | bool __testeof = traits_type::eq_int_type(__i, __ret); | |
177 | ||
178 | if (__testpb) | |
179 | { | |
180 | bool __testout = _M_mode & ios_base::out; | |
181 | bool __testeq = traits_type::eq(__c, this->gptr()[-1]); | |
182 | ||
183 | // Try to put back __c into input sequence in one of three ways. | |
184 | // Order these tests done in is unspecified by the standard. | |
185 | if (!__testeof && __testeq) | |
186 | { | |
187 | --_M_in_cur; | |
188 | if (__testout) | |
189 | --_M_out_cur; | |
190 | __ret = __i; | |
191 | } | |
192 | else if (__testeof) | |
193 | { | |
194 | --_M_in_cur; | |
195 | if (__testout) | |
196 | --_M_out_cur; | |
197 | __ret = traits_type::not_eof(__i); | |
198 | } | |
199 | else if (!__testeof) | |
200 | { | |
201 | --_M_in_cur; | |
202 | if (__testout) | |
203 | --_M_out_cur; | |
204 | _M_pback_create(); | |
205 | *_M_in_cur = __c; | |
206 | __ret = __i; | |
207 | } | |
208 | } | |
209 | else | |
210 | { | |
211 | // At the beginning of the buffer, need to make a | |
212 | // putback position available. | |
213 | this->seekoff(-1, ios_base::cur); | |
214 | this->underflow(); | |
215 | if (!__testeof) | |
216 | { | |
217 | if (!traits_type::eq(__c, *_M_in_cur)) | |
218 | { | |
219 | _M_pback_create(); | |
220 | *_M_in_cur = __c; | |
221 | } | |
222 | __ret = __i; | |
223 | } | |
224 | else | |
225 | __ret = traits_type::not_eof(__i); | |
226 | } | |
227 | } | |
228 | _M_last_overflowed = false; | |
229 | return __ret; | |
230 | } | |
231 | ||
232 | template<typename _CharT, typename _Traits> | |
31bfa177 | 233 | typename basic_filebuf<_CharT, _Traits>::int_type |
725dc051 BK |
234 | basic_filebuf<_CharT, _Traits>:: |
235 | overflow(int_type __c) | |
236 | { | |
237 | int_type __ret = traits_type::eof(); | |
5fa9abc3 | 238 | bool __testput = _M_out_cur && _M_out_cur < _M_buf + _M_buf_size; |
725dc051 BK |
239 | bool __testout = _M_mode & ios_base::out; |
240 | ||
241 | if (__testout) | |
242 | { | |
5fa9abc3 | 243 | if (__testput) |
725dc051 BK |
244 | { |
245 | *_M_out_cur = traits_type::to_char_type(__c); | |
246 | _M_out_cur_move(1); | |
247 | __ret = traits_type::not_eof(__c); | |
248 | } | |
249 | else | |
250 | __ret = this->_M_really_overflow(__c); | |
251 | } | |
252 | ||
253 | _M_last_overflowed = false; // Set in _M_really_overflow, below. | |
254 | return __ret; | |
255 | } | |
256 | ||
07814743 BK |
257 | template<typename _CharT, typename _Traits> |
258 | void | |
259 | basic_filebuf<_CharT, _Traits>:: | |
260 | _M_convert_to_external(_CharT* __ibuf, streamsize __ilen, | |
261 | streamsize& __elen, streamsize& __plen) | |
262 | { | |
07814743 BK |
263 | const locale __loc = this->getloc(); |
264 | const __codecvt_type& __cvt = use_facet<__codecvt_type>(__loc); | |
265 | ||
266 | if (__cvt.always_noconv() && __ilen) | |
267 | { | |
d3a193e3 | 268 | __elen += _M_file.xsputn(reinterpret_cast<char*>(__ibuf), __ilen); |
07814743 BK |
269 | __plen += __ilen; |
270 | } | |
271 | else | |
272 | { | |
273 | // Worst-case number of external bytes needed. | |
274 | int __ext_multiplier = __cvt.encoding(); | |
275 | if (__ext_multiplier == -1 || __ext_multiplier == 0) | |
276 | __ext_multiplier = sizeof(char_type); | |
277 | streamsize __blen = __ilen * __ext_multiplier; | |
278 | char* __buf = static_cast<char*>(__builtin_alloca(__blen)); | |
279 | char* __bend; | |
280 | const char_type* __iend; | |
281 | __res_type __r = __cvt.out(_M_state_cur, __ibuf, __ibuf + __ilen, | |
282 | __iend, __buf, __buf + __blen, __bend); | |
283 | // Result == ok, partial, noconv | |
284 | if (__r != codecvt_base::error) | |
285 | __blen = __bend - __buf; | |
286 | // Result == error | |
287 | else | |
288 | __blen = 0; | |
289 | ||
290 | if (__blen) | |
291 | { | |
d3a193e3 | 292 | __elen += _M_file.xsputn(__buf, __blen); |
07814743 BK |
293 | __plen += __blen; |
294 | } | |
295 | ||
296 | // Try once more for partial conversions. | |
297 | if (__r == codecvt_base::partial) | |
298 | { | |
299 | const char_type* __iresume = __iend; | |
300 | streamsize __rlen = _M_out_end - __iend; | |
301 | __r = __cvt.out(_M_state_cur, __iresume, __iresume + __rlen, | |
302 | __iend, __buf, __buf + __blen, __bend); | |
303 | if (__r != codecvt_base::error) | |
304 | __rlen = __bend - __buf; | |
305 | else | |
306 | __rlen = 0; | |
307 | if (__rlen) | |
308 | { | |
d3a193e3 | 309 | __elen += _M_file.xsputn(__buf, __rlen); |
07814743 BK |
310 | __plen += __rlen; |
311 | } | |
312 | } | |
313 | } | |
314 | } | |
315 | ||
725dc051 | 316 | template<typename _CharT, typename _Traits> |
31bfa177 | 317 | typename basic_filebuf<_CharT, _Traits>::int_type |
725dc051 BK |
318 | basic_filebuf<_CharT, _Traits>:: |
319 | _M_really_overflow(int_type __c) | |
320 | { | |
321 | int_type __ret = traits_type::eof(); | |
322 | bool __testput = _M_out_cur && _M_out_beg < _M_out_end; | |
6e52332e | 323 | bool __testunbuffered = _M_file.is_open() && !_M_buf_size_opt; |
5fa9abc3 BK |
324 | |
325 | if (__testput || __testunbuffered) | |
725dc051 | 326 | { |
07814743 BK |
327 | // Sizes of external and pending output. |
328 | streamsize __elen = 0; | |
329 | streamsize __plen = 0; | |
330 | ||
5066927d JM |
331 | // Need to restore current position. The position of the external |
332 | // byte sequence (_M_file) corresponds to _M_filepos, and we need | |
333 | // to move it to _M_out_beg for the write. | |
334 | if (_M_filepos && _M_filepos != _M_out_beg) | |
335 | { | |
336 | off_type __off = _M_out_beg - _M_filepos; | |
337 | _M_file.seekoff(__off, ios_base::cur); | |
338 | } | |
339 | ||
07814743 BK |
340 | // Convert internal buffer to external representation, output. |
341 | // NB: In the unbuffered case, no internal buffer exists. | |
342 | if (!__testunbuffered) | |
343 | _M_convert_to_external(_M_out_beg, _M_out_end - _M_out_beg, | |
344 | __elen, __plen); | |
345 | ||
346 | // Convert pending sequence to external representation, output. | |
9385d9cb | 347 | // If eof, then just attempt sync. |
07814743 | 348 | if (!traits_type::eq_int_type(__c, traits_type::eof())) |
725dc051 | 349 | { |
07814743 BK |
350 | char_type __pending = traits_type::to_char_type(__c); |
351 | _M_convert_to_external(&__pending, 1, __elen, __plen); | |
5fa9abc3 | 352 | |
9385d9cb LR |
353 | // User code must flush when switching modes (thus don't sync). |
354 | if (__elen == __plen) | |
355 | { | |
356 | _M_set_indeterminate(); | |
357 | __ret = traits_type::not_eof(__c); | |
358 | } | |
359 | } | |
360 | else if (!_M_file.sync()) | |
e6705174 BK |
361 | { |
362 | _M_set_indeterminate(); | |
363 | __ret = traits_type::not_eof(__c); | |
364 | } | |
725dc051 BK |
365 | } |
366 | _M_last_overflowed = true; | |
367 | return __ret; | |
368 | } | |
369 | ||
990101f9 | 370 | template<typename _CharT, typename _Traits> |
31bfa177 | 371 | typename basic_filebuf<_CharT, _Traits>::__streambuf_type* |
990101f9 BK |
372 | basic_filebuf<_CharT, _Traits>:: |
373 | setbuf(char_type* __s, streamsize __n) | |
374 | { | |
375 | if (!this->is_open() && __s == 0 && __n == 0) | |
376 | _M_buf_size_opt = 0; | |
377 | else if (__s && __n) | |
378 | { | |
379 | // This is implementation-defined behavior, and assumes | |
380 | // that an external char_type array of length (__s + __n) | |
381 | // exists and has been pre-allocated. If this is not the | |
382 | // case, things will quickly blow up. | |
383 | // Step 1: Destroy the current internal array. | |
384 | _M_destroy_internal_buffer(); | |
385 | ||
386 | // Step 2: Use the external array. | |
387 | _M_buf = __s; | |
388 | _M_buf_size_opt = _M_buf_size = __n; | |
389 | _M_set_indeterminate(); | |
990101f9 BK |
390 | } |
391 | _M_last_overflowed = false; | |
392 | return this; | |
393 | } | |
394 | ||
725dc051 | 395 | template<typename _CharT, typename _Traits> |
31bfa177 | 396 | typename basic_filebuf<_CharT, _Traits>::pos_type |
725dc051 BK |
397 | basic_filebuf<_CharT, _Traits>:: |
398 | seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode __mode) | |
399 | { | |
400 | pos_type __ret = pos_type(off_type(-1)); | |
dcf5a5de BK |
401 | bool __testin = (ios_base::in & _M_mode & __mode) != 0; |
402 | bool __testout = (ios_base::out & _M_mode & __mode) != 0; | |
69302d8b BK |
403 | |
404 | // Should probably do has_facet checks here. | |
405 | int __width = use_facet<__codecvt_type>(_M_buf_locale).encoding(); | |
725dc051 BK |
406 | if (__width < 0) |
407 | __width = 0; | |
b988dfc5 | 408 | bool __testfail = __off != 0 && __width <= 0; |
725dc051 | 409 | |
dcf5a5de | 410 | if (this->is_open() && !__testfail && (__testin || __testout)) |
725dc051 BK |
411 | { |
412 | // Ditch any pback buffers to avoid confusion. | |
413 | _M_pback_destroy(); | |
414 | ||
415 | if (__way != ios_base::cur || __off != 0) | |
416 | { | |
417 | off_type __computed_off = __width * __off; | |
418 | ||
419 | bool __testget = _M_in_cur && _M_in_beg < _M_in_end; | |
420 | bool __testput = _M_out_cur && _M_out_beg < _M_out_end; | |
421 | // Sync the internal and external streams. | |
422 | // out | |
423 | if (__testput || _M_last_overflowed) | |
424 | { | |
425 | // Part one: update the output sequence. | |
426 | this->sync(); | |
427 | // Part two: output unshift sequence. | |
428 | _M_output_unshift(); | |
429 | } | |
430 | //in | |
725dc051 | 431 | else if (__testget && __way == ios_base::cur) |
5066927d | 432 | __computed_off += _M_in_cur - _M_filepos; |
725dc051 | 433 | |
d3a193e3 | 434 | __ret = _M_file.seekoff(__computed_off, __way, __mode); |
725dc051 BK |
435 | _M_set_indeterminate(); |
436 | } | |
437 | // NB: Need to do this in case _M_file in indeterminate | |
d3a193e3 | 438 | // state, ie _M_file._offset == -1 |
725dc051 BK |
439 | else |
440 | { | |
d3a193e3 | 441 | __ret = _M_file.seekoff(__off, ios_base::cur, __mode); |
4977bab6 | 442 | __ret += std::max(_M_out_cur, _M_in_cur) - _M_filepos; |
725dc051 BK |
443 | } |
444 | } | |
445 | _M_last_overflowed = false; | |
446 | return __ret; | |
447 | } | |
448 | ||
449 | template<typename _CharT, typename _Traits> | |
31bfa177 | 450 | typename basic_filebuf<_CharT, _Traits>::pos_type |
725dc051 BK |
451 | basic_filebuf<_CharT, _Traits>:: |
452 | seekpos(pos_type __pos, ios_base::openmode __mode) | |
453 | { | |
b988dfc5 BK |
454 | #ifdef _GLIBCPP_RESOLVE_LIB_DEFECTS |
455 | // 171. Strange seekpos() semantics due to joint position | |
456 | return this->seekoff(off_type(__pos), ios_base::beg, __mode); | |
457 | #endif | |
725dc051 BK |
458 | } |
459 | ||
460 | template<typename _CharT, typename _Traits> | |
461 | void | |
462 | basic_filebuf<_CharT, _Traits>:: | |
463 | _M_output_unshift() | |
464 | { } | |
465 | ||
466 | template<typename _CharT, typename _Traits> | |
467 | void | |
468 | basic_filebuf<_CharT, _Traits>:: | |
469 | imbue(const locale& __loc) | |
470 | { | |
471 | bool __testbeg = gptr() == eback() && pptr() == pbase(); | |
69302d8b BK |
472 | |
473 | if (__testbeg && _M_buf_locale != __loc) | |
725dc051 | 474 | { |
725dc051 | 475 | _M_buf_locale = __loc; |
69302d8b | 476 | _M_buf_locale_init = true; |
725dc051 | 477 | } |
69302d8b | 478 | |
725dc051 BK |
479 | // NB this may require the reconversion of previously |
480 | // converted chars. This in turn may cause the reconstruction | |
481 | // of the original file. YIKES!! | |
482 | // XXX The part in the above comment is not done. | |
483 | _M_last_overflowed = false; | |
484 | } | |
a32e3c09 BK |
485 | |
486 | // Inhibit implicit instantiations for required instantiations, | |
487 | // which are defined via explicit instantiations elsewhere. | |
488 | // NB: This syntax is a GNU extension. | |
489 | extern template class basic_filebuf<char>; | |
a32e3c09 | 490 | extern template class basic_ifstream<char>; |
a32e3c09 | 491 | extern template class basic_ofstream<char>; |
a32e3c09 | 492 | extern template class basic_fstream<char>; |
5112ae3a BK |
493 | |
494 | #ifdef _GLIBCPP_USE_WCHAR_T | |
495 | extern template class basic_filebuf<wchar_t>; | |
496 | extern template class basic_ifstream<wchar_t>; | |
497 | extern template class basic_ofstream<wchar_t>; | |
a32e3c09 | 498 | extern template class basic_fstream<wchar_t>; |
5112ae3a | 499 | #endif |
725dc051 BK |
500 | } // namespace std |
501 | ||
6f48900c | 502 | #endif |