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