]> gcc.gnu.org Git - gcc.git/blame - libstdc++-v3/include/bits/fstream.tcc
include: New directory.
[gcc.git] / libstdc++-v3 / include / bits / fstream.tcc
CommitLineData
725dc051
BK
1// File based streams -*- C++ -*-
2
3// Copyright (C) 1997-1999, 2000 Free Software Foundation, Inc.
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
37namespace std
38{
39 template<typename _CharT, typename _Traits>
40 void
41 basic_filebuf<_CharT, _Traits>::
42 _M_filebuf_init()
43 {
44 _M_buf_unified = true; // Tie input to output for basic_filebuf.
45 _M_buf_size = _M_buf_size_opt;
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 void
57 basic_filebuf<_CharT, _Traits>::
58 _M_allocate_buffers()
59 {
60 // Allocate internal buffer.
61 try {
62 _M_buf = new char_type[_M_buf_size];
63 }
64 catch(...) {
65 delete [] _M_buf;
66 throw;
67 }
68
69 // Allocate pback buffer.
70 try {
71 _M_pback = new char_type[_M_pback_size];
72 }
73 catch(...) {
74 delete [] _M_pback;
75 throw;
76 }
77 }
78
79 template<typename _CharT, typename _Traits>
80 basic_filebuf<_CharT, _Traits>::
81 basic_filebuf()
82 : __streambuf_type(), _M_file(NULL), _M_state_cur(), _M_state_beg(),
83 _M_last_overflowed(false)
84 { _M_fcvt = &use_facet<__codecvt_type>(this->getloc()); }
85
86 template<typename _CharT, typename _Traits>
87 basic_filebuf<_CharT, _Traits>::
88 basic_filebuf(int __fd, const char* /*__name*/, ios_base::openmode __mode)
89 : __streambuf_type(), _M_state_cur(), _M_state_beg(),
90 _M_last_overflowed(false)
91 {
92 _M_fcvt = &use_facet<__codecvt_type>(this->getloc());
93 _M_filebuf_init();
94 _M_file->sys_open(__fd, __mode);
95 if (this->is_open() && _M_buf_size)
96 {
97 _M_allocate_buffers();
98 _M_mode = __mode;
99
100 // XXX So that istream::getc() will only need to get 1 char,
101 // as opposed to BUF_SIZE.
102 if (__fd == 0)
103 _M_buf_size = 1;
104
105 this->_M_set_indeterminate();
106 }
107 }
108
109 template<typename _CharT, typename _Traits>
110 basic_filebuf<_CharT, _Traits>::__filebuf_type*
111 basic_filebuf<_CharT, _Traits>::
112 open(const char* __s, ios_base::openmode __mode)
113 {
114 __filebuf_type *__ret = NULL;
115 if (!this->is_open())
116 {
117 _M_filebuf_init();
118 _M_file->open(__s, __mode);
119 if (this->is_open() && _M_buf_size)
120 {
121 _M_allocate_buffers();
122 _M_mode = __mode;
123
124 // For time being, set both (in/out) sets of pointers.
125 _M_set_indeterminate();
126 if (__mode & ios_base::ate
127 && this->seekoff(0, ios_base::end, __mode) < 0)
128 this->close();
129 __ret = this;
130 }
131 }
132 return __ret;
133 }
134
135 template<typename _CharT, typename _Traits>
136 basic_filebuf<_CharT, _Traits>::__filebuf_type*
137 basic_filebuf<_CharT, _Traits>::
138 close()
139 {
140 __filebuf_type *__ret = NULL;
141 if (this->is_open())
142 {
143 bool __testput = _M_out_cur && _M_out_beg < _M_out_end;
144 if (__testput)
145 _M_really_overflow(traits_type::eof());
146
147 // NB: Do this here so that re-opened filebufs will be cool...
148 _M_pback_destroy();
149
150#if 0
151 // XXX not done
152 if (_M_last_overflowed)
153 {
154 _M_output_unshift();
155 _M_really_overflow(traits_type::eof());
156 }
157#endif
158
159 _M_mode = ios_base::openmode(0);
160 if (_M_buf_size)
161 delete [] _M_buf;
162 _M_buf = NULL;
163 delete [] _M_pback;
164 _M_pback = NULL;
165 this->setg(NULL, NULL, NULL);
166 this->setp(NULL, NULL);
167 __ret = this;
168 }
169
170 // Can actually allocate this file as part of an open and never
171 // have it be opened.....
172 if (_M_file)
173 {
174 delete _M_file;
175 _M_file = NULL;
176 }
177 _M_last_overflowed = false;
178 return __ret;
179 }
180
181 template<typename _CharT, typename _Traits>
182 streamsize
183 basic_filebuf<_CharT, _Traits>::
184 showmanyc()
185 {
186 streamsize __ret = -1;
187 bool __testin = _M_mode & ios_base::in;
188
189 if (__testin)
190 {
191 bool __testeof = false;
192 if (_M_in_cur >= _M_in_end)
193 __testeof = this->underflow() == traits_type::eof();
194 if (!__testeof)
195 __ret = _M_in_end - _M_in_cur;
196 }
197 _M_last_overflowed = false;
198 return __ret;
199 }
200
201 template<typename _CharT, typename _Traits>
202 basic_filebuf<_CharT, _Traits>::int_type
203 basic_filebuf<_CharT, _Traits>::
204 underflow()
205 {
206 int_type __ret = traits_type::eof();
207 bool __testin = _M_mode & ios_base::in;
208
209 if (__testin)
210 {
211 // Check for pback madness, and if so swich back to the
212 // normal buffers and jet outta here before expensive
213 // fileops happen...
214 if (_M_pback_init)
215 {
216 _M_pback_destroy();
217 if (_M_in_cur < _M_in_end)
218 return traits_type::to_int_type(*_M_in_cur);
219 }
220
221 bool __testget = _M_in_cur && _M_in_beg < _M_in_cur;
222 bool __testinit = _M_is_indeterminate();
223 bool __testout = _M_mode & ios_base::out;
224
225 // Sync internal and external buffers.
226 // NB: __testget -> __testput as _M_buf_unified here.
227 if (__testget)
228 {
229 if (__testout)
230 _M_really_overflow();
231 else
232 _M_file->seekoff(_M_in_cur - _M_in_beg,
233 ios_base::cur, ios_base::in);
234 }
235
236 if (__testinit || __testget)
237 {
238#if 1
239 streamsize __size = _M_file->xsgetn(_M_in_beg, _M_buf_size);
240 if (0 < __size)
241 {
242 _M_set_determinate(__size);
243 streamoff __p = _M_file->seekoff(0 - __size, ios_base::cur,
244 ios_base::in);
245 if (__p == -1)
246 {
247 // XXX Something is wrong, do error checking.
248 }
249 else
250 {
251 if (__testout)
252 _M_out_cur = _M_in_cur;
253 __ret = traits_type::to_int_type(*_M_in_cur);
254 }
255 }
256#else
257 // 2000-08-04 bkoz disable
258 // Part one: (Re)fill external buf (_M_file->_IO_*) from
259 // external byte sequence (whatever physical byte sink or
260 // FILE actually is.)
261 char_type __conv_buf[_M_buf_size];
262 streamsize __size = _M_file->xsgetn(__conv_buf, _M_buf_size);
263
264 // Part two: (Re)fill internal buf contents from external buf.
265 if (0 < __size)
266 {
267 _M_set_determinate(__size);
268
269 char* __conv_cur = __conv_buf;
270 _M_state_beg = _M_state_cur;
271 __res_type __r = _M_fcvt->in(_M_state_cur,
272 __conv_buf,
273 __conv_buf + __size,
274 const_cast<const char*&>(__conv_cur),
275 _M_in_beg, _M_in_end, _M_in_cur);
276
277 if (__r == codecvt_base::partial)
278 {
279 // XXX Retry with larger _M_buf size.
280 }
281
282 // Set pointers to internal and external buffers
283 // correctly. . .
284 if (__r != codecvt_base::error)
285 {
286 if (__testout)
287 _M_out_cur = _M_in_cur;
288 __ret = traits_type::to_int_type(*_M_in_cur);
289 }
290
291 // Part three: Sync the current internal buffer
292 // position with the (now overshot) external buffer
293 // position.
294 streamoff __p = _M_file->seekoff(0 - __size, ios_base::cur,
295 ios_base::in);
296 if (__p == -1)
297 {
298 // XXX Something is wrong, do error checking.
299 }
300 }
301#endif
302 }
303 }
304 _M_last_overflowed = false;
305 return __ret;
306 }
307
308 template<typename _CharT, typename _Traits>
309 basic_filebuf<_CharT, _Traits>::int_type
310 basic_filebuf<_CharT, _Traits>::
311 pbackfail(int_type __i)
312 {
313 int_type __ret = traits_type::eof();
314 bool __testin = _M_mode & ios_base::in;
315
316 if (__testin)
317 {
318 bool __testpb = _M_in_beg < _M_in_cur;
319 char_type __c = traits_type::to_char_type(__i);
320 bool __testeof = traits_type::eq_int_type(__i, __ret);
321
322 if (__testpb)
323 {
324 bool __testout = _M_mode & ios_base::out;
325 bool __testeq = traits_type::eq(__c, this->gptr()[-1]);
326
327 // Try to put back __c into input sequence in one of three ways.
328 // Order these tests done in is unspecified by the standard.
329 if (!__testeof && __testeq)
330 {
331 --_M_in_cur;
332 if (__testout)
333 --_M_out_cur;
334 __ret = __i;
335 }
336 else if (__testeof)
337 {
338 --_M_in_cur;
339 if (__testout)
340 --_M_out_cur;
341 __ret = traits_type::not_eof(__i);
342 }
343 else if (!__testeof)
344 {
345 --_M_in_cur;
346 if (__testout)
347 --_M_out_cur;
348 _M_pback_create();
349 *_M_in_cur = __c;
350 __ret = __i;
351 }
352 }
353 else
354 {
355 // At the beginning of the buffer, need to make a
356 // putback position available.
357 this->seekoff(-1, ios_base::cur);
358 this->underflow();
359 if (!__testeof)
360 {
361 if (!traits_type::eq(__c, *_M_in_cur))
362 {
363 _M_pback_create();
364 *_M_in_cur = __c;
365 }
366 __ret = __i;
367 }
368 else
369 __ret = traits_type::not_eof(__i);
370 }
371 }
372 _M_last_overflowed = false;
373 return __ret;
374 }
375
376 template<typename _CharT, typename _Traits>
377 basic_filebuf<_CharT, _Traits>::int_type
378 basic_filebuf<_CharT, _Traits>::
379 overflow(int_type __c)
380 {
381 int_type __ret = traits_type::eof();
382 bool __testpos = _M_out_cur && _M_out_cur >= _M_buf + _M_buf_size;
383 bool __testout = _M_mode & ios_base::out;
384
385 if (__testout)
386 {
387 if (!__testpos)
388 {
389 *_M_out_cur = traits_type::to_char_type(__c);
390 _M_out_cur_move(1);
391 __ret = traits_type::not_eof(__c);
392 }
393 else
394 __ret = this->_M_really_overflow(__c);
395 }
396
397 _M_last_overflowed = false; // Set in _M_really_overflow, below.
398 return __ret;
399 }
400
401 template<typename _CharT, typename _Traits>
402 basic_filebuf<_CharT, _Traits>::int_type
403 basic_filebuf<_CharT, _Traits>::
404 _M_really_overflow(int_type __c)
405 {
406 int_type __ret = traits_type::eof();
407 bool __testput = _M_out_cur && _M_out_beg < _M_out_end;
408
409 if (__testput)
410 {
411 bool __testeof = traits_type::eq_int_type(__c, traits_type::eof());
412#if 1
413 int __plen = _M_out_end - _M_out_beg;
414 streamsize __len = _M_file->xsputn(_M_out_beg, __plen);
415 if (!__testeof)
416 {
417 char_type __pending = traits_type::to_char_type(__c);
418 __len += _M_file->xsputn(&__pending, 1);
419 ++__plen;
420 }
421 traits_type::to_char_type(__c);
422 // NB: Need this so that external byte sequence reflects
423 // internal buffer.
424 _M_file->sync();
425 if (__len == __plen)
426 {
427 _M_set_indeterminate();
428 __ret = traits_type::not_eof(__c);
429 }
430#else
431 // Part one: Allocate temporary conversion buffer on
432 // stack. Convert internal buffer plus __c (ie,
433 // "pending sequence") to temporary conversion buffer.
434 int __plen = _M_out_end - _M_out_beg;
435 char_type __pbuf[__plen + 1];
436 traits_type::copy(__pbuf, this->pbase(), __plen);
437 if (!__testeof)
438 {
439 __pbuf[__plen] = traits_type::to_char_type(__c);
440 ++__plen;
441 }
442
443 char_type* __pend;
444 char __conv_buf[__plen];
445 char* __conv_end;
446 _M_state_beg = _M_state_cur;
447
448 __res_type __r = _M_fcvt->out(_M_state_cur,
449 __pbuf, __pbuf + __plen,
450 const_cast<const char_type*&>(__pend),
451 __conv_buf, __conv_buf + __plen,
452 __conv_end);
453
454 // Part two: (Re)spill converted "pending sequence"
455 // contents (now in temporary conversion buffer) to
456 // external buffer (_M_file->_IO_*) using
457 // _M_file->sys_write(), and do error (minimal) checking.
458 if (__r != codecvt_base::error)
459 {
460 streamsize __len = _M_file->xsputn(__conv_buf, __plen);
461 // NB: Need this so that external byte sequence reflects
462 // internal buffer.
463 _M_file->sync();
464 if (__len == __plen)
465 {
466 _M_set_indeterminate();
467 __ret = traits_type::not_eof(__c);
468 }
469 }
470#endif
471 }
472 _M_last_overflowed = true;
473 return __ret;
474 }
475
476 template<typename _CharT, typename _Traits>
477 basic_filebuf<_CharT, _Traits>::pos_type
478 basic_filebuf<_CharT, _Traits>::
479 seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode __mode)
480 {
481 pos_type __ret = pos_type(off_type(-1));
482 bool __testopen = this->is_open();
483 bool __testin = __mode & ios_base::in && _M_mode & ios_base::in;
484 bool __testout = __mode & ios_base::out && _M_mode & ios_base::out;
485 int __width = _M_fcvt->encoding();
486 if (__width < 0)
487 __width = 0;
488 bool __testfail = __off != 0 && __width <= 0;
489
490 if (__testopen && !__testfail && (__testin || __testout))
491 {
492 // Ditch any pback buffers to avoid confusion.
493 _M_pback_destroy();
494
495 if (__way != ios_base::cur || __off != 0)
496 {
497 off_type __computed_off = __width * __off;
498
499 bool __testget = _M_in_cur && _M_in_beg < _M_in_end;
500 bool __testput = _M_out_cur && _M_out_beg < _M_out_end;
501 // Sync the internal and external streams.
502 // out
503 if (__testput || _M_last_overflowed)
504 {
505 // Part one: update the output sequence.
506 this->sync();
507 // Part two: output unshift sequence.
508 _M_output_unshift();
509 }
510 //in
511 // NB: underflow() rewinds the external buffer.
512 else if (__testget && __way == ios_base::cur)
513 __computed_off += _M_in_cur - _M_in_beg;
514
515 __ret = _M_file->seekoff(__computed_off, __way, __mode);
516 _M_set_indeterminate();
517 }
518 // NB: Need to do this in case _M_file in indeterminate
519 // state, ie _M_file->_offset == -1
520 else
521 {
522 __ret = _M_file->seekoff(__off, ios_base::cur, __mode);
523 __ret += max(_M_out_cur, _M_in_cur) - _M_buf;
524 }
525 }
526 _M_last_overflowed = false;
527 return __ret;
528 }
529
530 template<typename _CharT, typename _Traits>
531 basic_filebuf<_CharT, _Traits>::pos_type
532 basic_filebuf<_CharT, _Traits>::
533 seekpos(pos_type __pos, ios_base::openmode __mode)
534 {
535 pos_type __ret;
536 off_type __off = __pos;
537
538 __ret = this->seekoff(__off, ios_base::beg, __mode);
539
540 _M_last_overflowed = false;
541 return __ret;
542 }
543
544 template<typename _CharT, typename _Traits>
545 void
546 basic_filebuf<_CharT, _Traits>::
547 _M_output_unshift()
548 { }
549
550 template<typename _CharT, typename _Traits>
551 void
552 basic_filebuf<_CharT, _Traits>::
553 imbue(const locale& __loc)
554 {
555 bool __testbeg = gptr() == eback() && pptr() == pbase();
556 bool __teststate = _M_fcvt->encoding() == -1;
557
558 _M_buf_locale_init = true;
559 if (__testbeg && !__teststate && _M_buf_locale != __loc)
560 {
561 // XXX Will need to save these older values.
562 _M_buf_locale = __loc;
563 _M_fcvt = &use_facet<__codecvt_type>(_M_buf_locale);
564 // XXX Necessary?
565 _M_buf_fctype = &use_facet<__ctype_type>(_M_buf_locale);
566 }
567 // NB this may require the reconversion of previously
568 // converted chars. This in turn may cause the reconstruction
569 // of the original file. YIKES!!
570 // XXX The part in the above comment is not done.
571 _M_last_overflowed = false;
572 }
573
574} // namespace std
575
576#endif // _CPP_BITS_FSTREAM_TCC
577
578
579
580
581
582
583
584
585
586
This page took 0.086845 seconds and 5 git commands to generate.