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