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