1 // Stream buffer classes -*- C++ -*-
2 
3 // Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002
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.5  Stream buffers
33 //
34 
35 /** @file streambuf
36  *  This is a Standard C++ Library header.  You should @c #include this header
37  *  in your programs, rather than any of the "st[dl]_*.h" implementation files.
38  */
39 
40 #ifndef _CPP_STREAMBUF
41 #define _CPP_STREAMBUF	1
42 
43 #pragma GCC system_header
44 
45 #include <bits/c++config.h>
46 #include <iosfwd>
47 #include <cstdio> 	// For SEEK_SET, SEEK_CUR, SEEK_END
48 #include <bits/localefwd.h>
49 #include <bits/ios_base.h>
50 
51 namespace std
52 {
53   template<typename _CharT, typename _Traits>
54     streamsize
55     __copy_streambufs(basic_ios<_CharT, _Traits>& _ios,
56 		      basic_streambuf<_CharT, _Traits>* __sbin,
57 		      basic_streambuf<_CharT, _Traits>* __sbout);
58 
59   // 27.5.2 Template class basic_streambuf<_CharT, _Traits>
60   template<typename _CharT, typename _Traits>
61     class basic_streambuf
62     {
63     public:
64       // Types:
65       typedef _CharT 					char_type;
66       typedef _Traits 					traits_type;
67       typedef typename traits_type::int_type 		int_type;
68       typedef typename traits_type::pos_type 		pos_type;
69       typedef typename traits_type::off_type 		off_type;
70 
71       // Non-standard Types:
72       typedef ctype<char_type>           		__ctype_type;
73       typedef basic_streambuf<char_type, traits_type>  	__streambuf_type;
74       typedef typename traits_type::state_type 		__state_type;
75 
76       friend class basic_ios<char_type, traits_type>;
77       friend class basic_istream<char_type, traits_type>;
78       friend class basic_ostream<char_type, traits_type>;
79       friend class istreambuf_iterator<char_type, traits_type>;
80       friend class ostreambuf_iterator<char_type, traits_type>;
81 
82       friend streamsize
83       __copy_streambufs<>(basic_ios<char_type, traits_type>& __ios,
84 			  __streambuf_type* __sbin,__streambuf_type* __sbout);
85 
86     protected:
87       // Pointer to the beginning of internally-allocated
88       // space. Filebuf manually allocates/deallocates this, whereas
89       // stringstreams attempt to use the built-in intelligence of the
90       // string class. If you are managing memory, set this. If not,
91       // leave it NULL.
92       char_type*		_M_buf;
93 
94       // Actual size of allocated internal buffer, in bytes.
95       size_t			_M_buf_size;
96 
97       // Optimal or preferred size of internal buffer, in bytes.
98       size_t			_M_buf_size_opt;
99 
100       // True iff _M_in_* and _M_out_* buffers should always point to
101       // the same place.  True for fstreams, false for sstreams.
102       bool 			_M_buf_unified;
103 
104       // This is based on _IO_FILE, just reordered to be more
105       // consistent, and is intended to be the most minimal abstraction
106       // for an internal buffer.
107       // get == input == read
108       // put == output == write
109       char_type* 		_M_in_beg;  	// Start of get area.
110       char_type* 		_M_in_cur;	// Current read area.
111       char_type* 		_M_in_end;	// End of get area.
112       char_type* 		_M_out_beg; 	// Start of put area.
113       char_type* 		_M_out_cur;  	// Current put area.
114       char_type* 		_M_out_end;  	// End of put area.
115 
116       // Place to stash in || out || in | out settings for current streambuf.
117       ios_base::openmode 	_M_mode;
118 
119       // Current locale setting.
120       locale 			_M_buf_locale;
121 
122       // True iff locale is initialized.
123       bool 			_M_buf_locale_init;
124 
125       // Necessary bits for putback buffer management. Only used in
126       // the basic_filebuf class, as necessary for the standard
127       // requirements. The only basic_streambuf member function that
128       // needs access to these data members is in_avail...
129       // NB: pbacks of over one character are not currently supported.
130       static const size_t   	_S_pback_size = 1;
131       char_type			_M_pback[_S_pback_size];
132       char_type*		_M_pback_cur_save;
133       char_type*		_M_pback_end_save;
134       bool			_M_pback_init;
135 
136       // Yet unused.
137       fpos<__state_type>	_M_pos;
138 
139       // Initializes pback buffers, and moves normal buffers to safety.
140       // Assumptions:
141       // _M_in_cur has already been moved back
142       void
143       _M_pback_create()
144       {
145 	if (!_M_pback_init)
146 	  {
147 	    size_t __dist = _M_in_end - _M_in_cur;
148 	    size_t __len = min(_S_pback_size, __dist);
149 	    traits_type::copy(_M_pback, _M_in_cur, __len);
150 	    _M_pback_cur_save = _M_in_cur;
151 	    _M_pback_end_save = _M_in_end;
152 	    this->setg(_M_pback, _M_pback, _M_pback + __len);
153 	    _M_pback_init = true;
154 	  }
155       }
156 
157       // Deactivates pback buffer contents, and restores normal buffer.
158       // Assumptions:
159       // The pback buffer has only moved forward.
160       void
161       _M_pback_destroy()
162       {
163 	if (_M_pback_init)
164 	  {
165 	    // Length _M_in_cur moved in the pback buffer.
166 	    size_t __off_cur = _M_in_cur - _M_pback;
167 
168 	    // For in | out buffers, the end can be pushed back...
169 	    size_t __off_end = 0;
170 	    size_t __pback_len = _M_in_end - _M_pback;
171 	    size_t __save_len = _M_pback_end_save - _M_buf;
172 	    if (__pback_len > __save_len)
173 	      __off_end = __pback_len - __save_len;
174 
175 	    this->setg(_M_buf, _M_pback_cur_save + __off_cur,
176 		       _M_pback_end_save + __off_end);
177 	    _M_pback_cur_save = NULL;
178 	    _M_pback_end_save = NULL;
179 	    _M_pback_init = false;
180 	  }
181       }
182 
183       // Correctly sets the _M_in_cur pointer, and bumps the
184       // _M_out_cur pointer as well if necessary.
185       void
186       _M_in_cur_move(off_type __n) // argument needs to be +-
187       {
188 	bool __testout = _M_out_cur;
189 	_M_in_cur += __n;
190 	if (__testout && _M_buf_unified)
191 	  _M_out_cur += __n;
192       }
193 
194       // Correctly sets the _M_out_cur pointer, and bumps the
195       // appropriate _M_*_end pointers as well. Necessary for the
196       // un-tied stringbufs, in in|out mode.
197       // Invariant:
198       // __n + _M_out_[cur, end] <= _M_buf + _M_buf_size
199       // Assuming all _M_*_[beg, cur, end] pointers are operating on
200       // the same range:
201       // _M_buf <= _M_*_ <= _M_buf + _M_buf_size
202       void
203       _M_out_cur_move(off_type __n) // argument needs to be +-
204       {
205 	bool __testin = _M_in_cur;
206 
207 	_M_out_cur += __n;
208 	if (__testin && _M_buf_unified)
209 	  _M_in_cur += __n;
210 	if (_M_out_cur > _M_out_end)
211 	  {
212 	    _M_out_end = _M_out_cur;
213 	    // NB: in | out buffers drag the _M_in_end pointer along...
214 	    if (__testin)
215 	      _M_in_end += __n;
216 	  }
217       }
218 
219       // Return the size of the output buffer.  This depends on the
220       // buffer in use: allocated buffers have a stored size in
221       // _M_buf_size and setbuf() buffers don't.
222       off_type
223       _M_out_buf_size()
224       {
225 	off_type __ret = 0;
226 	if (_M_out_cur)
227 	  {
228 	    // Using allocated buffer.
229 	    if (_M_out_beg == _M_buf)
230 	      __ret = _M_out_beg + _M_buf_size - _M_out_cur;
231 	    // Using non-allocated buffer.
232 	    else
233 	      __ret = _M_out_end - _M_out_cur;
234 	  }
235 	return __ret;
236       }
237 
238   public:
239       virtual
240       ~basic_streambuf()
241       {
242 	_M_buf_unified = false;
243 	_M_buf_size = 0;
244 	_M_buf_size_opt = 0;
245 	_M_mode = ios_base::openmode(0);
246 	_M_buf_locale_init = false;
247       }
248 
249       // Locales:
250       locale
251       pubimbue(const locale &__loc)
252       {
253 	locale __tmp(this->getloc());
254 	this->imbue(__loc);
255 	return __tmp;
256       }
257 
258       locale
259       getloc() const
260       {
261 	if (_M_buf_locale_init)
262 	  return _M_buf_locale;
263 	else
264 	  return locale();
265       }
266 
267       // Buffer and positioning:
268       __streambuf_type*
269       pubsetbuf(char_type* __s, streamsize __n)
270       { return this->setbuf(__s, __n); }
271 
272       pos_type
273       pubseekoff(off_type __off, ios_base::seekdir __way,
274 		 ios_base::openmode __mode = ios_base::in | ios_base::out)
275       { return this->seekoff(__off, __way, __mode); }
276 
277       pos_type
278       pubseekpos(pos_type __sp,
279 		 ios_base::openmode __mode = ios_base::in | ios_base::out)
280       { return this->seekpos(__sp, __mode); }
281 
282       int
283       pubsync() { return this->sync(); }
284 
285       // Get and put areas:
286       // Get area:
287       streamsize
288       in_avail()
289       {
290 	streamsize __ret;
291 	if (_M_in_cur && _M_in_cur < _M_in_end)
292 	  {
293 	    if (_M_pback_init)
294 	      {
295 		size_t __save_len =  _M_pback_end_save - _M_pback_cur_save;
296 		size_t __pback_len = _M_in_cur - _M_pback;
297 		__ret = __save_len - __pback_len;
298 	      }
299 	    else
300 	      __ret = this->egptr() - this->gptr();
301 	  }
302 	else
303 	  __ret = this->showmanyc();
304 	return __ret;
305       }
306 
307       int_type
308       snextc()
309       {
310 	int_type __eof = traits_type::eof();
311 	return (traits_type::eq_int_type(this->sbumpc(), __eof)
312 		? __eof : this->sgetc());
313       }
314 
315       int_type
316       sbumpc();
317 
318       int_type
319       sgetc()
320       {
321 	int_type __ret;
322 	if (_M_in_cur && _M_in_cur < _M_in_end)
323 	  __ret = traits_type::to_int_type(*(this->gptr()));
324 	else
325 	  __ret = this->underflow();
326 	return __ret;
327       }
328 
329       streamsize
330       sgetn(char_type* __s, streamsize __n)
331       { return this->xsgetn(__s, __n); }
332 
333       // Putback:
334       int_type
335       sputbackc(char_type __c);
336 
337       int_type
338       sungetc();
339 
340       // Put area:
341       int_type
342       sputc(char_type __c);
343 
344       streamsize
345       sputn(const char_type* __s, streamsize __n)
346       { return this->xsputn(__s, __n); }
347 
348     protected:
349       basic_streambuf()
350       : _M_buf(NULL), _M_buf_size(0), _M_buf_size_opt(BUFSIZ),
351       _M_buf_unified(false), _M_in_beg(0), _M_in_cur(0), _M_in_end(0),
352       _M_out_beg(0), _M_out_cur(0), _M_out_end(0),
353       _M_mode(ios_base::openmode(0)), _M_buf_locale(locale()),
354       _M_buf_locale_init(false), _M_pback_cur_save(0), _M_pback_end_save(0),
355       _M_pback_init(false)
356       { }
357 
358       // Get area:
359       char_type*
360       eback() const { return _M_in_beg; }
361 
362       char_type*
363       gptr()  const { return _M_in_cur;  }
364 
365       char_type*
366       egptr() const { return _M_in_end; }
367 
368       void
369       gbump(int __n) { _M_in_cur += __n; }
370 
371       void
372       setg(char_type* __gbeg, char_type* __gnext, char_type* __gend)
373       {
374 	_M_in_beg = __gbeg;
375 	_M_in_cur = __gnext;
376 	_M_in_end = __gend;
377 	if (!(_M_mode & ios_base::in) && __gbeg && __gnext && __gend)
378 	  _M_mode = _M_mode | ios_base::in;
379       }
380 
381       // Put area:
382       char_type*
383       pbase() const { return _M_out_beg; }
384 
385       char_type*
386       pptr() const { return _M_out_cur; }
387 
388       char_type*
389       epptr() const { return _M_out_end; }
390 
391       void
392       pbump(int __n) { _M_out_cur += __n; }
393 
394       void
395       setp(char_type* __pbeg, char_type* __pend)
396       {
397 	_M_out_beg = _M_out_cur = __pbeg;
398 	_M_out_end = __pend;
399 	if (!(_M_mode & ios_base::out) && __pbeg && __pend)
400 	  _M_mode = _M_mode | ios_base::out;
401       }
402 
403       // Virtual functions:
404       // Locales:
405       virtual void
406       imbue(const locale& __loc)
407       {
408 	_M_buf_locale_init = true;
409 	if (_M_buf_locale != __loc)
410 	  _M_buf_locale = __loc;
411       }
412 
413       // Buffer management and positioning:
414       virtual basic_streambuf<char_type,_Traits>*
415       setbuf(char_type*, streamsize)
416       {	return this; }
417 
418       virtual pos_type
419       seekoff(off_type, ios_base::seekdir,
420 	      ios_base::openmode /*__mode*/ = ios_base::in | ios_base::out)
421       { return pos_type(off_type(-1)); }
422 
423       virtual pos_type
424       seekpos(pos_type,
425 	      ios_base::openmode /*__mode*/ = ios_base::in | ios_base::out)
426       { return pos_type(off_type(-1)); }
427 
428       virtual int
429       sync() { return 0; }
430 
431       // Get area:
432       virtual streamsize
433       showmanyc() { return 0; }
434 
435       virtual streamsize
436       xsgetn(char_type* __s, streamsize __n);
437 
438       virtual int_type
439       underflow()
440       { return traits_type::eof(); }
441 
442       virtual int_type
443       uflow()
444       {
445 	int_type __ret = traits_type::eof();
446 	bool __testeof = traits_type::eq_int_type(this->underflow(), __ret);
447 	bool __testpending = _M_in_cur && _M_in_cur < _M_in_end;
448 	if (!__testeof && __testpending)
449 	  {
450 	    __ret = traits_type::to_int_type(*_M_in_cur);
451 	    ++_M_in_cur;
452 	    if (_M_buf_unified && _M_mode & ios_base::out)
453 	      ++_M_out_cur;
454 	  }
455 	return __ret;
456       }
457 
458       // Putback:
459       virtual int_type
460       pbackfail(int_type /* __c */  = traits_type::eof())
461       { return traits_type::eof(); }
462 
463       // Put area:
464       virtual streamsize
465       xsputn(const char_type* __s, streamsize __n);
466 
467       virtual int_type
468       overflow(int_type /* __c */ = traits_type::eof())
469       { return traits_type::eof(); }
470 
471 #ifdef _GLIBCPP_DEPRECATED
472     public:
473       void
474       stossc()
475       {
476 	if (_M_in_cur < _M_in_end)
477 	  ++_M_in_cur;
478 	else
479 	  this->uflow();
480       }
481 #endif
482 
483 #ifdef _GLIBCPP_RESOLVE_LIB_DEFECTS
484     // Side effect of DR 50.
485     private:
486       basic_streambuf(const __streambuf_type&) { };
487 
488       __streambuf_type&
489       operator=(const __streambuf_type&) { return *this; };
490 #endif
491     };
492 } // namespace std
493 
494 #ifdef _GLIBCPP_NO_TEMPLATE_EXPORT
495 # define export
496 #endif
497 #ifdef  _GLIBCPP_FULLY_COMPLIANT_HEADERS
498 #include <bits/streambuf.tcc>
499 #endif
500 
501 #endif
502