Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

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