]>
Commit | Line | Data |
---|---|---|
725dc051 BK |
1 | // Stream buffer classes -*- C++ -*- |
2 | ||
13187a45 | 3 | // Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. |
725dc051 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.5 Stream buffers | |
32 | // | |
33 | ||
729e3d3f PE |
34 | /** @file std_streambuf.h |
35 | * This is an internal header file, included by other library headers. | |
36 | * You should not attempt to use it directly. | |
37 | */ | |
38 | ||
725dc051 BK |
39 | #ifndef _CPP_STREAMBUF |
40 | #define _CPP_STREAMBUF 1 | |
41 | ||
b0a85b86 GDR |
42 | #pragma GCC system_header |
43 | ||
725dc051 BK |
44 | #include <bits/c++config.h> |
45 | #include <bits/std_iosfwd.h> | |
46 | #include <bits/std_cstdio.h> // For SEEK_SET, SEEK_CUR, SEEK_END | |
47 | #include <bits/localefwd.h> | |
48 | #include <bits/ios_base.h> | |
49 | ||
d53d7f6e PE |
50 | namespace std |
51 | { | |
725dc051 | 52 | template<typename _CharT, typename _Traits> |
bf6adbe2 | 53 | streamsize |
72ed2836 BK |
54 | __copy_streambufs(basic_ios<_CharT, _Traits>& _ios, |
55 | basic_streambuf<_CharT, _Traits>* __sbin, | |
56 | basic_streambuf<_CharT, _Traits>* __sbout); | |
725dc051 BK |
57 | |
58 | // 27.5.2 Template class basic_streambuf<_CharT, _Traits> | |
59 | template<typename _CharT, typename _Traits> | |
60 | class basic_streambuf | |
61 | { | |
62 | public: | |
63 | // Types: | |
64 | typedef _CharT char_type; | |
65 | typedef _Traits traits_type; | |
66 | typedef typename traits_type::int_type int_type; | |
67 | typedef typename traits_type::pos_type pos_type; | |
68 | typedef typename traits_type::off_type off_type; | |
69 | ||
70 | // Non-standard Types: | |
71 | typedef ctype<char_type> __ctype_type; | |
72 | typedef basic_streambuf<char_type, traits_type> __streambuf_type; | |
73 | ||
74 | friend class basic_ios<char_type, traits_type>; | |
75 | friend class basic_istream<char_type, traits_type>; | |
76 | friend class basic_ostream<char_type, traits_type>; | |
77 | friend class istreambuf_iterator<char_type, traits_type>; | |
78 | friend class ostreambuf_iterator<char_type, traits_type>; | |
79 | ||
80 | friend streamsize | |
72ed2836 BK |
81 | __copy_streambufs<>(basic_ios<char_type, traits_type>& __ios, |
82 | __streambuf_type* __sbin,__streambuf_type* __sbout); | |
725dc051 BK |
83 | |
84 | protected: | |
85 | ||
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 | ||
13187a45 | 93 | // Actual size of allocated internal buffer, in bytes. |
725dc051 BK |
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 | ||
729e3d3f | 103 | // This is based on _IO_FILE, just reordered to be more |
725dc051 BK |
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 | ||
725dc051 BK |
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 | int_type _M_pback_size; | |
130 | char_type* _M_pback; | |
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(_M_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 | ||
13187a45 BK |
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 | ||
725dc051 BK |
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 | { | |
13187a45 | 201 | bool __testin = _M_in_cur; |
725dc051 BK |
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 | ||
13187a45 BK |
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 | ||
725dc051 BK |
234 | // These three functions are used to clarify internal buffer |
235 | // maintenance. After an overflow, or after a seekoff call that | |
236 | // started at beg or end, or possibly when the stream becomes | |
237 | // unbuffered, and a myrid other obscure corner cases, the | |
238 | // internal buffer does not truly reflect the contents of the | |
239 | // external buffer. At this point, for whatever reason, it is in | |
240 | // an indeterminate state. | |
241 | void | |
242 | _M_set_indeterminate(void) | |
243 | { | |
244 | if (_M_mode & ios_base::in) | |
245 | this->setg(_M_buf, _M_buf, _M_buf); | |
246 | if (_M_mode & ios_base::out) | |
247 | this->setp(_M_buf, _M_buf); | |
248 | } | |
249 | ||
250 | void | |
251 | _M_set_determinate(off_type __off) | |
252 | { | |
253 | bool __testin = _M_mode & ios_base::in; | |
254 | bool __testout = _M_mode & ios_base::out; | |
255 | if (__testin) | |
13187a45 | 256 | this->setg(_M_buf, _M_buf, _M_buf + __off); |
725dc051 BK |
257 | if (__testout) |
258 | this->setp(_M_buf, _M_buf + __off); | |
725dc051 BK |
259 | } |
260 | ||
261 | bool | |
262 | _M_is_indeterminate(void) | |
263 | { | |
264 | bool __ret = false; | |
39003c99 BK |
265 | // Don't return true if unbuffered. |
266 | if (_M_buf) | |
267 | { | |
268 | if (_M_mode & ios_base::in) | |
269 | __ret = _M_in_beg == _M_in_cur && _M_in_cur == _M_in_end; | |
270 | if (_M_mode & ios_base::out) | |
271 | __ret = _M_out_beg == _M_out_cur && _M_out_cur == _M_out_end; | |
272 | } | |
725dc051 BK |
273 | return __ret; |
274 | } | |
275 | ||
276 | public: | |
277 | virtual | |
278 | ~basic_streambuf() | |
279 | { | |
280 | _M_buf_unified = false; | |
281 | _M_buf_size = 0; | |
282 | _M_buf_size_opt = 0; | |
283 | _M_mode = ios_base::openmode(0); | |
725dc051 | 284 | _M_buf_locale_init = false; |
725dc051 BK |
285 | } |
286 | ||
287 | // Locales: | |
288 | locale | |
289 | pubimbue(const locale &__loc) | |
290 | { | |
291 | locale __tmp(this->getloc()); | |
292 | this->imbue(__loc); | |
293 | return __tmp; | |
294 | } | |
295 | ||
296 | locale | |
297 | getloc() const | |
298 | { | |
299 | if (_M_buf_locale_init) | |
300 | return _M_buf_locale; | |
301 | else | |
302 | return locale(); | |
303 | } | |
304 | ||
305 | // Buffer and positioning: | |
306 | __streambuf_type* | |
307 | pubsetbuf(char_type* __s, streamsize __n) | |
308 | { return this->setbuf(__s, __n); } | |
309 | ||
310 | pos_type | |
311 | pubseekoff(off_type __off, ios_base::seekdir __way, | |
312 | ios_base::openmode __mode = ios_base::in | ios_base::out) | |
313 | { return this->seekoff(__off, __way, __mode); } | |
314 | ||
315 | pos_type | |
316 | pubseekpos(pos_type __sp, | |
317 | ios_base::openmode __mode = ios_base::in | ios_base::out) | |
318 | { return this->seekpos(__sp, __mode); } | |
319 | ||
320 | int | |
321 | pubsync() { return this->sync(); } | |
322 | ||
323 | // Get and put areas: | |
324 | // Get area: | |
325 | streamsize | |
326 | in_avail() | |
327 | { | |
328 | streamsize __ret; | |
329 | if (_M_in_cur && _M_in_cur < _M_in_end) | |
330 | { | |
331 | if (_M_pback_init) | |
332 | { | |
333 | int_type __save_len = _M_pback_end_save - _M_pback_cur_save; | |
334 | int_type __pback_len = _M_in_cur - _M_pback; | |
335 | __ret = __save_len - __pback_len; | |
336 | } | |
337 | else | |
338 | __ret = this->egptr() - this->gptr(); | |
339 | } | |
340 | else | |
341 | __ret = this->showmanyc(); | |
342 | return __ret; | |
343 | } | |
344 | ||
345 | int_type | |
346 | snextc() | |
347 | { | |
348 | int_type __eof = traits_type::eof(); | |
349 | return (this->sbumpc() == __eof ? __eof : this->sgetc()); | |
350 | } | |
351 | ||
352 | int_type | |
353 | sbumpc(); | |
354 | ||
355 | int_type | |
356 | sgetc() | |
357 | { | |
358 | int_type __ret; | |
359 | if (_M_in_cur && _M_in_cur < _M_in_end) | |
39003c99 | 360 | __ret = traits_type::to_int_type(*(this->gptr())); |
725dc051 BK |
361 | else |
362 | __ret = this->underflow(); | |
363 | return __ret; | |
364 | } | |
365 | ||
366 | streamsize | |
367 | sgetn(char_type* __s, streamsize __n) | |
368 | { return this->xsgetn(__s, __n); } | |
369 | ||
370 | // Putback: | |
371 | int_type | |
372 | sputbackc(char_type __c); | |
373 | ||
374 | int_type | |
375 | sungetc(); | |
376 | ||
377 | // Put area: | |
378 | int_type | |
379 | sputc(char_type __c); | |
380 | ||
381 | streamsize | |
382 | sputn(const char_type* __s, streamsize __n) | |
383 | { return this->xsputn(__s, __n); } | |
384 | ||
385 | protected: | |
386 | basic_streambuf() | |
387 | : _M_buf(NULL), _M_buf_size(0), | |
388 | _M_buf_size_opt(static_cast<int_type>(BUFSIZ)), _M_buf_unified(false), | |
389 | _M_in_beg(0), _M_in_cur(0), _M_in_end(0), _M_out_beg(0), _M_out_cur(0), | |
390 | _M_out_end(0), _M_mode(ios_base::openmode(0)), _M_buf_locale(locale()), | |
391 | _M_buf_locale_init(false), _M_pback_size(1), _M_pback(NULL), | |
392 | _M_pback_cur_save(NULL), _M_pback_end_save(NULL), _M_pback_init(false) | |
69302d8b | 393 | { } |
725dc051 BK |
394 | |
395 | // Get area: | |
396 | char_type* | |
397 | eback() const { return _M_in_beg; } | |
398 | ||
399 | char_type* | |
400 | gptr() const { return _M_in_cur; } | |
401 | ||
402 | char_type* | |
403 | egptr() const { return _M_in_end; } | |
404 | ||
405 | void | |
406 | gbump(int __n) { _M_in_cur += __n; } | |
407 | ||
408 | void | |
409 | setg(char_type* __gbeg, char_type* __gnext, char_type* __gend) | |
410 | { | |
411 | _M_in_beg = __gbeg; | |
412 | _M_in_cur = __gnext; | |
413 | _M_in_end = __gend; | |
414 | if (!(_M_mode & ios_base::in) && __gbeg && __gnext && __gend) | |
415 | _M_mode = _M_mode | ios_base::in; | |
416 | } | |
417 | ||
418 | // Put area: | |
419 | char_type* | |
420 | pbase() const { return _M_out_beg; } | |
421 | ||
422 | char_type* | |
423 | pptr() const { return _M_out_cur; } | |
424 | ||
425 | char_type* | |
426 | epptr() const { return _M_out_end; } | |
427 | ||
428 | void | |
429 | pbump(int __n) { _M_out_cur += __n; } | |
430 | ||
431 | void | |
432 | setp(char_type* __pbeg, char_type* __pend) | |
433 | { | |
434 | _M_out_beg = _M_out_cur = __pbeg; | |
435 | _M_out_end = __pend; | |
436 | if (!(_M_mode & ios_base::out) && __pbeg && __pend) | |
437 | _M_mode = _M_mode | ios_base::out; | |
725dc051 BK |
438 | } |
439 | ||
440 | // Virtual functions: | |
441 | // Locales: | |
442 | virtual void | |
443 | imbue(const locale& __loc) | |
444 | { | |
445 | _M_buf_locale_init = true; | |
446 | if (_M_buf_locale != __loc) | |
69302d8b | 447 | _M_buf_locale = __loc; |
725dc051 BK |
448 | } |
449 | ||
450 | // Buffer management and positioning: | |
451 | virtual basic_streambuf<char_type,_Traits>* | |
452 | setbuf(char_type*, streamsize) | |
453 | { return this; } | |
454 | ||
455 | virtual pos_type | |
456 | seekoff(off_type, ios_base::seekdir, | |
457 | ios_base::openmode /*__mode*/ = ios_base::in | ios_base::out) | |
458 | { return pos_type(off_type(-1)); } | |
459 | ||
460 | virtual pos_type | |
461 | seekpos(pos_type, | |
462 | ios_base::openmode /*__mode*/ = ios_base::in | ios_base::out) | |
463 | { return pos_type(off_type(-1)); } | |
464 | ||
465 | virtual int | |
466 | sync() { return 0; } | |
467 | ||
468 | // Get area: | |
469 | virtual streamsize | |
470 | showmanyc() { return 0; } | |
471 | ||
472 | virtual streamsize | |
473 | xsgetn(char_type* __s, streamsize __n); | |
474 | ||
475 | virtual int_type | |
476 | underflow() | |
477 | { return traits_type::eof(); } | |
478 | ||
479 | virtual int_type | |
480 | uflow() | |
481 | { | |
482 | int_type __ret = traits_type::eof(); | |
483 | bool __testeof = this->underflow() == __ret; | |
484 | bool __testpending = _M_in_cur && _M_in_cur < _M_in_end; | |
725dc051 BK |
485 | if (!__testeof && __testpending) |
486 | { | |
487 | __ret = traits_type::to_int_type(*_M_in_cur); | |
488 | ++_M_in_cur; | |
489 | if (_M_buf_unified && _M_mode & ios_base::out) | |
490 | ++_M_out_cur; | |
491 | } | |
492 | return __ret; | |
493 | } | |
494 | ||
495 | // Putback: | |
496 | virtual int_type | |
497 | pbackfail(int_type /* __c */ = traits_type::eof()) | |
498 | { return traits_type::eof(); } | |
499 | ||
500 | // Put area: | |
501 | virtual streamsize | |
502 | xsputn(const char_type* __s, streamsize __n); | |
503 | ||
504 | virtual int_type | |
505 | overflow(int_type /* __c */ = traits_type::eof()) | |
506 | { return traits_type::eof(); } | |
507 | ||
78d58962 | 508 | #ifdef _GLIBCPP_DEPRECATED |
725dc051 BK |
509 | public: |
510 | void | |
511 | stossc() | |
512 | { | |
513 | if (_M_in_cur < _M_in_end) | |
514 | ++_M_in_cur; | |
515 | else | |
516 | this->uflow(); | |
517 | } | |
518 | #endif | |
519 | ||
520 | #ifdef _GLIBCPP_RESOLVE_LIB_DEFECTS | |
77cd227e | 521 | // Side effect of DR 50. |
725dc051 BK |
522 | private: |
523 | basic_streambuf(const __streambuf_type&); | |
524 | ||
525 | __streambuf_type& | |
526 | operator=(const __streambuf_type&); | |
527 | #endif | |
528 | }; | |
529 | ||
530 | } // namespace std | |
531 | ||
532 | #ifdef _GLIBCPP_NO_TEMPLATE_EXPORT | |
533 | # define export | |
534 | #ifdef _GLIBCPP_FULLY_COMPLIANT_HEADERS | |
535 | #include <bits/streambuf.tcc> | |
536 | #endif | |
537 | #endif | |
538 | ||
539 | #endif /* _CPP_STREAMBUF */ | |
540 |