]>
Commit | Line | Data |
---|---|---|
b2dad0e3 BK |
1 | // File based streams -*- C++ -*- |
2 | ||
d207c3f7 | 3 | // Copyright (C) 1997-1999, 2000 Free Software Foundation, Inc. |
b2dad0e3 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 | |
8 | // Free Software Foundation; either version 2, or (at your option) | |
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 | ||
16 | // You should have received a copy of the GNU General Public License along | |
17 | // with this library; see the file COPYING. If not, write to the Free | |
18 | // Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, | |
19 | // USA. | |
20 | ||
21 | // As a special exception, you may use this file as part of a free software | |
22 | // library without restriction. Specifically, if other files instantiate | |
23 | // templates or use macros or inline functions from this file, or you compile | |
24 | // this file and link it with other files to produce an executable, this | |
25 | // file does not by itself cause the resulting executable to be covered by | |
26 | // the GNU General Public License. This exception does not however | |
27 | // invalidate any other reasons why the executable file might be covered by | |
28 | // the GNU General Public License. | |
29 | ||
30 | // | |
31 | // ISO C++ 14882: 27.8 File-based streams | |
32 | // | |
33 | ||
34 | #ifndef _CPP_BITS_FSTREAM_TCC | |
35 | #define _CPP_BITS_FSTREAM_TCC 1 | |
36 | ||
37 | namespace std | |
38 | { | |
39 | template<typename _CharT, typename _Traits> | |
40 | void | |
41 | basic_filebuf<_CharT, _Traits>:: | |
42 | _M_init_filebuf(void) | |
43 | { | |
44 | _M_buf_unified = true; // Tie input to output for basic_filebuf. | |
d207c3f7 | 45 | _M_buf_size = _M_buf_size_opt; |
b2dad0e3 BK |
46 | try { |
47 | _M_file = new __file_type(&_M_lock); | |
48 | } | |
49 | catch(...) { | |
50 | delete _M_file; | |
51 | throw; | |
52 | } | |
53 | } | |
54 | ||
55 | template<typename _CharT, typename _Traits> | |
56 | basic_filebuf<_CharT, _Traits>:: | |
57 | basic_filebuf() | |
81ef1479 | 58 | : __streambuf_type(), _M_file(NULL), _M_state_cur(), _M_state_beg(), |
ab30ba5c | 59 | _M_last_overflowed(false) |
b2dad0e3 BK |
60 | { _M_fcvt = &use_facet<__codecvt_type>(this->getloc()); } |
61 | ||
b2dad0e3 BK |
62 | template<typename _CharT, typename _Traits> |
63 | basic_filebuf<_CharT, _Traits>:: | |
64 | basic_filebuf(int __fd, const char* /*__name*/, ios_base::openmode __mode) | |
81ef1479 BK |
65 | : __streambuf_type(), _M_state_cur(), _M_state_beg(), |
66 | _M_last_overflowed(false) | |
b2dad0e3 BK |
67 | { |
68 | _M_fcvt = &use_facet<__codecvt_type>(this->getloc()); | |
69 | _M_init_filebuf(); | |
70 | _M_file->sys_open(__fd, __mode); | |
71 | if (this->is_open() && _M_buf_size) | |
72 | { | |
73 | _M_mode = __mode; | |
74 | // XXX So that istream::getc() will only need to get 1 char, | |
75 | // as opposed to BUF_SIZE. | |
76 | if (__fd == 0) | |
77 | _M_buf_size = 1; | |
78 | ||
79 | try { | |
80 | _M_buf = new char_type[_M_buf_size]; | |
81 | } | |
82 | catch(...) { | |
83 | delete [] _M_buf; | |
84 | throw; | |
85 | } | |
86 | ||
87 | this->_M_set_indeterminate(); | |
88 | } | |
89 | } | |
90 | ||
91 | template<typename _CharT, typename _Traits> | |
92 | basic_filebuf<_CharT, _Traits>::__filebuf_type* | |
93 | basic_filebuf<_CharT, _Traits>:: | |
94 | open(const char* __s, ios_base::openmode __mode) | |
95 | { | |
96 | __filebuf_type *__retval = NULL; | |
97 | if (!this->is_open()) | |
98 | { | |
99 | _M_init_filebuf(); | |
100 | _M_file->open(__s, __mode); | |
101 | if (this->is_open() && _M_buf_size) | |
102 | { | |
103 | _M_mode = __mode; | |
104 | ||
105 | try { | |
106 | _M_buf = new char_type[_M_buf_size]; | |
107 | } | |
108 | catch(...) { | |
109 | delete [] _M_buf; | |
110 | throw; | |
111 | } | |
112 | ||
113 | // For time being, set both (in/out) sets of pointers. | |
114 | _M_set_indeterminate(); | |
115 | if (__mode & ios_base::ate | |
116 | && this->seekoff(0, ios_base::end, __mode) < 0) | |
117 | this->close(); | |
118 | __retval = this; | |
119 | } | |
120 | } | |
121 | return __retval; | |
122 | } | |
123 | ||
124 | template<typename _CharT, typename _Traits> | |
125 | basic_filebuf<_CharT, _Traits>::__filebuf_type* | |
126 | basic_filebuf<_CharT, _Traits>:: | |
127 | close() | |
128 | { | |
129 | __filebuf_type *__retval = NULL; | |
130 | if (this->is_open()) | |
131 | { | |
132 | bool __testput = _M_out_cur && _M_out_beg < _M_out_end; | |
133 | if (__testput) | |
134 | _M_really_overflow(traits_type::eof()); | |
135 | ||
136 | #if 0 | |
137 | // XXX not done | |
138 | if (_M_last_overflowed) | |
139 | { | |
140 | _M_output_unshift(); | |
141 | _M_really_overflow(traits_type::eof()); | |
142 | } | |
143 | #endif | |
81ef1479 | 144 | |
ab30ba5c | 145 | if (_M_file) |
b2dad0e3 | 146 | { |
ab30ba5c BK |
147 | delete _M_file; |
148 | _M_file = NULL; | |
b2dad0e3 BK |
149 | _M_mode = ios_base::openmode(0); |
150 | if (_M_buf_size) | |
151 | delete [] _M_buf; | |
152 | _M_buf = NULL; | |
153 | this->setg(NULL, NULL, NULL); | |
154 | this->setp(NULL, NULL); | |
155 | __retval = this; | |
156 | } | |
157 | } | |
158 | _M_last_overflowed = false; | |
159 | return __retval; | |
160 | } | |
161 | ||
162 | template<typename _CharT, typename _Traits> | |
163 | streamsize | |
164 | basic_filebuf<_CharT, _Traits>:: | |
165 | showmanyc() | |
166 | { | |
167 | streamsize __retval = -1; | |
168 | bool __testin = _M_mode & ios_base::in; | |
169 | ||
170 | if (__testin) | |
171 | { | |
172 | bool __testeof = false; | |
173 | if (_M_in_cur >= _M_in_end) | |
174 | __testeof = this->underflow() == traits_type::eof(); | |
175 | if (!__testeof) | |
176 | __retval = (_M_in_end - _M_in_cur) / sizeof(char_type); | |
177 | } | |
178 | _M_last_overflowed = false; | |
179 | return __retval; | |
180 | } | |
181 | ||
182 | template<typename _CharT, typename _Traits> | |
183 | basic_filebuf<_CharT, _Traits>::int_type | |
184 | basic_filebuf<_CharT, _Traits>:: | |
185 | underflow() | |
186 | { | |
187 | int_type __retval = traits_type::eof(); | |
188 | bool __testget = _M_in_cur && _M_in_beg < _M_in_cur; | |
189 | bool __testinit = _M_is_indeterminate(); | |
190 | bool __testout = _M_mode & ios_base::out; | |
191 | bool __testin = _M_mode & ios_base::in; | |
192 | ||
193 | if (__testin) | |
194 | { | |
195 | // Sync internal and external buffers. | |
196 | // NB: __testget -> __testput as _M_buf_unified here. | |
197 | if (__testget) | |
198 | { | |
199 | if (__testout) | |
200 | _M_really_overflow(); | |
201 | else | |
f3b004d8 BK |
202 | _M_file->seekoff(_M_in_cur - _M_in_beg, |
203 | ios_base::cur, ios_base::in); | |
b2dad0e3 BK |
204 | } |
205 | ||
206 | if (__testinit || __testget) | |
207 | { | |
208 | // Part one: (Re)fill external buf (_M_file->_IO_*) from | |
209 | // external byte sequence (whatever physical byte sink or | |
210 | // FILE actually is.) | |
211 | char __conv_buf[_M_buf_size]; | |
f3b004d8 | 212 | streamsize __size = _M_file->xsgetn(__conv_buf, _M_buf_size); |
b2dad0e3 BK |
213 | |
214 | // Part two: (Re)fill internal buf contents from external buf. | |
215 | if (0 < __size) | |
216 | { | |
217 | _M_set_determinate(__size); | |
218 | ||
219 | char* __conv_cur = __conv_buf; | |
220 | _M_state_beg = _M_state_cur; | |
221 | __res_type __r = _M_fcvt->in(_M_state_cur, | |
222 | __conv_buf, | |
223 | __conv_buf + __size, | |
224 | const_cast<const char*&>(__conv_cur), | |
225 | _M_in_beg, _M_in_end, _M_in_cur); | |
226 | ||
227 | if (__r == codecvt_base::partial) | |
228 | { | |
229 | // XXX Retry with larger _M_buf size. | |
230 | } | |
231 | ||
232 | // Set pointers to internal and external buffers | |
233 | // correctly. . . | |
234 | if (__r != codecvt_base::error) | |
235 | { | |
236 | if (__testout) | |
237 | _M_out_cur = _M_in_cur; | |
238 | __retval = traits_type::to_int_type(*_M_in_cur); | |
239 | } | |
240 | ||
241 | // Part three: Sync the current internal buffer | |
242 | // position with the (now overshot) external buffer | |
243 | // position. | |
f3b004d8 | 244 | streamoff __p = _M_file->seekoff(0 - __size, ios_base::cur, |
b2dad0e3 | 245 | ios_base::in); |
f3b004d8 | 246 | if (__p == -1) |
b2dad0e3 BK |
247 | { |
248 | // XXX Something is wrong, do error checking. | |
249 | } | |
250 | } | |
251 | } | |
252 | } | |
253 | _M_last_overflowed = false; | |
254 | return __retval; | |
255 | } | |
256 | ||
257 | template<typename _CharT, typename _Traits> | |
258 | basic_filebuf<_CharT, _Traits>::int_type | |
259 | basic_filebuf<_CharT, _Traits>:: | |
260 | pbackfail(int_type __i) | |
261 | { | |
262 | int_type __retval = traits_type::eof(); | |
263 | char_type __c = traits_type::to_char_type(__i); | |
264 | bool __testeof = traits_type::eq_int_type(__i, traits_type::eof()); | |
265 | bool __testout = _M_mode & ios_base::out; | |
266 | bool __testin = _M_mode & ios_base::in; | |
267 | ||
268 | if (__testin) | |
269 | { | |
270 | if (!_M_is_indeterminate()) | |
271 | { | |
272 | bool __testpb = _M_in_beg < _M_in_cur; | |
273 | bool __testeq = traits_type::eq(__c, this->gptr()[-1]); | |
274 | ||
275 | // Try to put back __c into input sequence in one of three ways. | |
276 | // Order these tests done in is unspecified by the standard. | |
277 | if (!__testeof && __testpb && __testeq) | |
278 | { | |
279 | --_M_in_cur; | |
280 | if (__testout) | |
281 | --_M_out_cur; | |
282 | __retval = __i; | |
283 | } | |
284 | else if (!__testeof && __testpb && __testout) | |
285 | { | |
286 | --_M_in_cur; | |
287 | if (__testout) | |
288 | --_M_out_cur; | |
289 | *_M_in_cur = __c; | |
290 | __retval = __i; | |
291 | } | |
292 | else if (__testeof && __testpb) | |
293 | { | |
294 | --_M_in_cur; | |
295 | if (__testout) | |
296 | --_M_out_cur; | |
297 | __retval = traits_type::not_eof(__i); | |
298 | } | |
299 | } | |
300 | else | |
301 | { | |
302 | // Need to make a putback position available. | |
303 | this->seekoff(-1, ios_base::cur); | |
304 | this->underflow(); | |
305 | if (!__testeof) | |
306 | { | |
307 | *_M_in_cur = __c; | |
308 | __retval = __c; | |
309 | } | |
310 | else | |
311 | __retval = traits_type::not_eof(__i); | |
312 | } | |
313 | } | |
314 | _M_last_overflowed = false; | |
315 | return __retval; | |
316 | } | |
317 | ||
318 | template<typename _CharT, typename _Traits> | |
319 | basic_filebuf<_CharT, _Traits>::int_type | |
320 | basic_filebuf<_CharT, _Traits>:: | |
321 | overflow(int_type __c) | |
322 | { | |
323 | int_type __retval = traits_type::eof(); | |
324 | bool __testpos = _M_out_cur && _M_out_cur >= _M_buf + _M_buf_size; | |
325 | bool __testout = _M_mode & ios_base::out; | |
326 | ||
327 | if (__testout) | |
328 | { | |
329 | if (!__testpos) | |
330 | { | |
331 | *_M_out_cur = traits_type::to_char_type(__c); | |
332 | _M_buf_bump(1); | |
333 | __retval = traits_type::not_eof(__c); | |
334 | } | |
335 | else | |
336 | __retval = this->_M_really_overflow(__c); | |
337 | } | |
338 | ||
339 | _M_last_overflowed = false; // Set in _M_really_overflow, below. | |
340 | return __retval; | |
341 | } | |
342 | ||
343 | template<typename _CharT, typename _Traits> | |
344 | basic_filebuf<_CharT, _Traits>::int_type | |
345 | basic_filebuf<_CharT, _Traits>:: | |
346 | _M_really_overflow(int_type __c) | |
347 | { | |
348 | int_type __retval = traits_type::eof(); | |
349 | bool __testput = _M_out_cur && _M_out_beg < _M_out_end; | |
350 | bool __testeof = traits_type::eq_int_type(__c, traits_type::eof()); | |
351 | ||
352 | if (__testput) | |
353 | { | |
354 | // Part one: Allocate temporary conversion buffer on | |
355 | // stack. Convert internal buffer plus __c (ie, | |
356 | // "pending sequence") to temporary conversion buffer. | |
357 | int __plen = _M_out_end - _M_out_beg; | |
358 | char_type __pbuf[__plen + sizeof(char_type)]; | |
359 | traits_type::copy(__pbuf, this->pbase(), __plen); | |
360 | if (!__testeof) | |
361 | { | |
362 | __pbuf[__plen] = traits_type::to_char_type(__c); | |
363 | ++__plen; | |
364 | } | |
365 | ||
366 | char_type* __pend; | |
367 | char __conv_buf[__plen]; | |
368 | char* __conv_end; | |
369 | _M_state_beg = _M_state_cur; | |
370 | ||
371 | __res_type __r = _M_fcvt->out(_M_state_cur, | |
372 | __pbuf, __pbuf + __plen, | |
373 | const_cast<const char_type*&>(__pend), | |
374 | __conv_buf, __conv_buf + __plen, | |
375 | __conv_end); | |
376 | ||
377 | // Part two: (Re)spill converted "pending sequence" | |
378 | // contents (now in temporary conversion buffer) to | |
379 | // external buffer (_M_file->_IO_*) using | |
380 | // _M_file->sys_write(), and do error (minimal) checking. | |
381 | if (__r != codecvt_base::error) | |
382 | { | |
f3b004d8 | 383 | streamsize __len = _M_file->xsputn(__conv_buf, __plen); |
b2dad0e3 BK |
384 | // NB: Need this so that external byte sequence reflects |
385 | // internal buffer. | |
386 | _M_file->sync(); | |
f3b004d8 | 387 | if (__len == __plen) |
b2dad0e3 BK |
388 | { |
389 | _M_set_indeterminate(); | |
390 | __retval = traits_type::not_eof(__c); | |
391 | } | |
392 | } | |
393 | } | |
394 | _M_last_overflowed = true; | |
395 | return __retval; | |
396 | } | |
397 | ||
398 | template<typename _CharT, typename _Traits> | |
399 | basic_filebuf<_CharT, _Traits>::pos_type | |
400 | basic_filebuf<_CharT, _Traits>:: | |
401 | seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode __mode) | |
402 | { | |
403 | pos_type __retval = pos_type(off_type(-1)); | |
404 | bool __testopen = this->is_open(); | |
405 | bool __testin = __mode & ios_base::in && _M_mode & ios_base::in; | |
406 | bool __testout = __mode & ios_base::out && _M_mode & ios_base::out; | |
407 | int __width = _M_fcvt->encoding(); | |
408 | if (__width < 0) | |
409 | __width = 0; | |
410 | bool __testfail = __off != 0 && __width <= 0; | |
411 | ||
412 | if (__testopen && !__testfail && (__testin || __testout)) | |
413 | { | |
414 | if (__way != ios_base::cur || __off != 0) | |
415 | { | |
416 | off_type __computed_off = __width * __off; | |
417 | ||
418 | bool __testget = _M_in_cur && _M_in_beg < _M_in_end; | |
419 | bool __testput = _M_out_cur && _M_out_beg < _M_out_end; | |
420 | // Sync the internal and external streams. | |
421 | // out | |
422 | if (__testput || _M_last_overflowed) | |
423 | { | |
424 | // Part one: update the output sequence. | |
425 | this->sync(); | |
426 | // Part two: output unshift sequence. | |
427 | _M_output_unshift(); | |
428 | } | |
429 | //in | |
430 | // NB: underflow() rewinds the external buffer. | |
431 | else if (__testget && __way == ios_base::cur) | |
432 | __computed_off += _M_in_cur - _M_in_beg; | |
433 | ||
434 | __retval = _M_file->seekoff(__computed_off, __way, __mode); | |
b2dad0e3 BK |
435 | _M_set_indeterminate(); |
436 | } | |
437 | // NB: Need to do this in case _M_file in indeterminate | |
438 | // state, ie _M_file->_offset == -1 | |
439 | else | |
440 | { | |
441 | __retval = _M_file->seekoff(__off, ios_base::cur, __mode); | |
442 | __retval += max(_M_out_cur, _M_in_cur) - _M_buf; | |
443 | } | |
444 | } | |
445 | _M_last_overflowed = false; | |
446 | return __retval; | |
447 | } | |
448 | ||
449 | template<typename _CharT, typename _Traits> | |
450 | basic_filebuf<_CharT, _Traits>::pos_type | |
451 | basic_filebuf<_CharT, _Traits>:: | |
452 | seekpos(pos_type __pos, ios_base::openmode __mode) | |
453 | { | |
454 | pos_type __retval; | |
455 | off_type __off = __pos; | |
456 | ||
457 | __retval = this->seekoff(__off, ios_base::beg, __mode); | |
458 | ||
459 | _M_last_overflowed = false; | |
460 | return __retval; | |
461 | } | |
462 | ||
463 | template<typename _CharT, typename _Traits> | |
464 | void | |
465 | basic_filebuf<_CharT, _Traits>:: | |
466 | _M_output_unshift() | |
467 | { | |
468 | #if 0 | |
469 | // XXX Not complete, or correct. | |
470 | int __width = _M_fcvt->encoding(); | |
471 | ||
472 | if (__width < 0) | |
473 | { | |
474 | // Part one: call codecvt::unshift | |
475 | int __unsft_len = 0; | |
476 | char_type __unsft_buf[_M_buf_size]; | |
477 | char_type* __unsft_cur; // XXX Set to external buf. | |
478 | _M_state_beg = _M_state_cur; | |
479 | __res_type __r = _M_fcvt->unshift(_M_state_cur, | |
480 | __unsft_buf, | |
481 | __unsft_buf + _M_buf_size, | |
482 | __unsft_cur); | |
483 | ||
484 | // Note, for char_type == char, wchar_t unshift | |
485 | // should store no charachers. | |
486 | if (__r == codecvt_base::ok || __r == codecvt_base::noconv) | |
487 | __unsft_len = __unsft_cur - __unsft_buf; | |
488 | ||
489 | // "Output the resulting sequence." | |
490 | if (__unsft_len) | |
491 | { | |
492 | int __plen = _M_out_cur - _M_out_beg; | |
493 | int __rlen = __plen + __unsft_len; | |
494 | char_type __rbuf[__rlen]; | |
495 | char_type* __rend; | |
496 | traits_type::copy(__rbuf, this->pbase(), __plen); | |
497 | traits_type::copy(__rbuf + __plen, __unsft_buf, | |
498 | __unsft_len); | |
499 | ||
500 | char __conv_buf[__rlen]; | |
501 | char* __conv_end; | |
502 | ||
503 | _M_state_beg = _M_state_cur; // XXX Needed? | |
504 | __r = _M_fcvt->out(_M_state_cur, | |
505 | __rbuf, __rbuf + __rlen, | |
506 | const_cast<const char_type*&>(__rend), | |
507 | __conv_buf, | |
508 | __conv_buf + __rlen, | |
509 | __conv_end); | |
510 | ||
511 | if (__r != codecvt_base::error) | |
512 | { | |
f3b004d8 | 513 | streamsize __r = _M_file->xsputn(__conv_buf, __rlen); |
b2dad0e3 BK |
514 | if (__r == __rlen) |
515 | { | |
516 | _M_out_cur = _M_out_beg; | |
517 | if (_M_mode & ios_base::in) | |
518 | _M_in_cur = _M_out_cur; | |
519 | } | |
520 | else | |
521 | { | |
522 | // XXX Throw "wig out and die exception?" | |
523 | } | |
524 | } | |
525 | } | |
526 | } | |
527 | #endif | |
528 | } | |
529 | ||
530 | template<typename _CharT, typename _Traits> | |
531 | void | |
532 | basic_filebuf<_CharT, _Traits>:: | |
533 | imbue(const locale& __loc) | |
534 | { | |
535 | bool __testbeg = gptr() == eback() && pptr() == pbase(); | |
536 | bool __teststate = _M_fcvt->encoding() == -1; | |
537 | ||
538 | _M_locale_set = true; | |
539 | if (__testbeg && !__teststate && _M_locale_buf != __loc) | |
540 | { | |
541 | // XXX Will need to save these older values. | |
542 | _M_locale_buf = __loc; | |
543 | _M_fcvt = &use_facet<__codecvt_type>(_M_locale_buf); | |
544 | // XXX Necessary? | |
545 | _M_fctype_buf = &use_facet<__ctype_type>(_M_locale_buf); | |
546 | } | |
547 | // NB this may require the reconversion of previously | |
548 | // converted chars. This in turn may cause the reconstruction | |
549 | // of the original file. YIKES!! | |
550 | // XXX The part in the above comment is not done. | |
551 | _M_last_overflowed = false; | |
552 | } | |
553 | ||
554 | } // namespace std | |
555 | ||
556 | #endif // _CPP_BITS_FSTREAM_TCC | |
557 | ||
558 | ||
559 | ||
560 | ||
561 | ||
562 | ||
563 | ||
564 | ||
565 | ||
566 |