234 return _M_base._M_open(__id, _Init_mode) ? this : 0; |
247 return _M_base._M_open(__id, _Init_mode) ? this : 0; |
235 } |
248 } |
236 |
249 |
237 _Self* close(); |
250 _Self* close(); |
238 |
251 |
239 protected: // Virtual functions from basic_streambuf. |
252 protected: // Virtual functions from basic_streambuf. |
240 virtual streamsize showmanyc(); |
253 |
241 virtual int_type underflow(); |
254 virtual streamsize showmanyc() { |
242 |
255 |
243 virtual int_type pbackfail(int_type = traits_type::eof()); |
256 // Is there any possibility that reads can succeed? |
244 virtual int_type overflow(int_type = traits_type::eof()); |
257 if (!this->is_open() || _M_in_output_mode || _M_in_error_mode) |
245 |
258 return -1; |
246 virtual basic_streambuf<_CharT, _Traits>* setbuf(char_type*, streamsize); |
259 else if (_M_in_putback_mode) |
247 virtual pos_type seekoff(off_type, ios_base::seekdir, |
260 return this->egptr() - this->gptr(); |
248 ios_base::openmode = ios_base::in | ios_base::out); |
261 else if (_M_constant_width) { |
249 virtual pos_type seekpos(pos_type, |
262 streamoff __pos = _M_base._M_seek(0, ios_base::cur); |
250 ios_base::openmode = ios_base::in | ios_base::out); |
263 streamoff __size = _M_base._M_file_size(); |
251 |
264 return __pos >= 0 && __size > __pos ? __size - __pos : 0; |
252 virtual int sync(); |
265 } |
253 virtual void imbue(const locale&); |
266 else |
254 |
267 return 0; |
|
268 |
|
269 } |
|
270 virtual int_type underflow() { |
|
271 |
|
272 return _Underflow<_CharT, _Traits>::_M_doit(this); |
|
273 |
|
274 } |
|
275 |
|
276 virtual int_type pbackfail(int_type __c= traits_type::eof()) { |
|
277 |
|
278 const int_type __eof = traits_type::eof(); |
|
279 |
|
280 // If we aren't already in input mode, pushback is impossible. |
|
281 if (!_M_in_input_mode) |
|
282 return __eof; |
|
283 |
|
284 // We can use the ordinary get buffer if there's enough space, and |
|
285 // if it's a buffer that we're allowed to write to. |
|
286 if (this->gptr() != this->eback() && |
|
287 (traits_type::eq_int_type(__c, __eof) || |
|
288 traits_type::eq(traits_type::to_char_type(__c), this->gptr()[-1]) || |
|
289 !_M_mmap_base)) { |
|
290 this->gbump(-1); |
|
291 if (traits_type::eq_int_type(__c, __eof) || |
|
292 traits_type::eq(traits_type::to_char_type(__c), *this->gptr())) |
|
293 return traits_type::to_int_type(*this->gptr()); |
|
294 } |
|
295 else if (!traits_type::eq_int_type(__c, __eof)) { |
|
296 // Are we in the putback buffer already? |
|
297 _CharT* __pback_end = _M_pback_buf + __STATIC_CAST(int,_S_pback_buf_size); |
|
298 if (_M_in_putback_mode) { |
|
299 // Do we have more room in the putback buffer? |
|
300 if (this->eback() != _M_pback_buf) |
|
301 this->setg(this->egptr() - 1, this->egptr() - 1, __pback_end); |
|
302 else |
|
303 return __eof; // No more room in the buffer, so fail. |
|
304 } |
|
305 else { // We're not yet in the putback buffer. |
|
306 _M_saved_eback = this->eback(); |
|
307 _M_saved_gptr = this->gptr(); |
|
308 _M_saved_egptr = this->egptr(); |
|
309 this->setg(__pback_end - 1, __pback_end - 1, __pback_end); |
|
310 _M_in_putback_mode = true; |
|
311 } |
|
312 } |
|
313 else |
|
314 return __eof; |
|
315 |
|
316 // We have made a putback position available. Assign to it, and return. |
|
317 *this->gptr() = traits_type::to_char_type(__c); |
|
318 return __c; |
|
319 |
|
320 } |
|
321 |
|
322 virtual int_type overflow(int_type __c) { |
|
323 |
|
324 // Switch to output mode, if necessary. |
|
325 if (!_M_in_output_mode) |
|
326 if (!_M_switch_to_output_mode()) |
|
327 return traits_type::eof(); |
|
328 |
|
329 _CharT* __ibegin = this->_M_int_buf; |
|
330 _CharT* __iend = this->pptr(); |
|
331 this->setp(_M_int_buf, _M_int_buf_EOS - 1); |
|
332 |
|
333 // Put __c at the end of the internal buffer. |
|
334 if (!traits_type::eq_int_type(__c, traits_type::eof())) |
|
335 *__iend++ = _Traits::to_char_type(__c); |
|
336 |
|
337 // For variable-width encodings, output may take more than one pass. |
|
338 while (__ibegin != __iend) { |
|
339 const _CharT* __inext = __ibegin; |
|
340 char* __enext = _M_ext_buf; |
|
341 typename _Codecvt::result __status |
|
342 = _M_codecvt->out(_M_state, __ibegin, __iend, __inext, |
|
343 _M_ext_buf, _M_ext_buf_EOS, __enext); |
|
344 if (__status == _Codecvt::noconv) { |
|
345 return _Noconv_output<_Traits>::_M_doit(this, __ibegin, __iend) |
|
346 ? traits_type::not_eof(__c) |
|
347 : _M_output_error(); |
|
348 } |
|
349 |
|
350 // For a constant-width encoding we know that the external buffer |
|
351 // is large enough, so failure to consume the entire internal buffer |
|
352 // or to produce the correct number of external characters, is an error. |
|
353 // For a variable-width encoding, however, we require only that we |
|
354 // consume at least one internal character |
|
355 else if (__status != _Codecvt::error && |
|
356 (((__inext == __iend) && |
|
357 (__enext - _M_ext_buf == _M_width * (__iend - __ibegin))) || |
|
358 (!_M_constant_width && __inext != __ibegin))) { |
|
359 // We successfully converted part or all of the internal buffer. |
|
360 ptrdiff_t __n = __enext - _M_ext_buf; |
|
361 if (_M_write(_M_ext_buf, __n)) |
|
362 __ibegin += __inext - __ibegin; |
|
363 else |
|
364 return _M_output_error(); |
|
365 } |
|
366 else |
|
367 return _M_output_error(); |
|
368 } |
|
369 |
|
370 return traits_type::not_eof(__c); |
|
371 |
|
372 } |
|
373 |
|
374 virtual basic_streambuf<_CharT, _Traits>* setbuf(_CharT* __buf, streamsize __n) { |
|
375 |
|
376 if (!_M_in_input_mode &&! _M_in_output_mode && !_M_in_error_mode && |
|
377 _M_int_buf == 0) { |
|
378 if (__buf == 0 && __n == 0) |
|
379 _M_allocate_buffers(0, 1); |
|
380 else if (__buf != 0 && __n > 0) |
|
381 _M_allocate_buffers(__buf, __n); |
|
382 } |
|
383 return this; |
|
384 |
|
385 } |
|
386 |
|
387 virtual pos_type seekoff(off_type __off, |
|
388 ios_base::seekdir __whence, |
|
389 ios_base::openmode /* dummy */) { |
|
390 |
|
391 if (this->is_open() && |
|
392 (__off == 0 || (_M_constant_width && this->_M_base._M_in_binary_mode()))) { |
|
393 |
|
394 if (!_M_seek_init(__off != 0 || __whence != ios_base::cur)) |
|
395 return pos_type(-1); |
|
396 |
|
397 // Seek to beginning or end, regardless of whether we're in input mode. |
|
398 if (__whence == ios_base::beg || __whence == ios_base::end) |
|
399 return _M_seek_return(_M_base._M_seek(_M_width * __off, __whence), |
|
400 _State_type()); |
|
401 |
|
402 // Seek relative to current position. Complicated if we're in input mode. |
|
403 else if (__whence == ios_base::cur) { |
|
404 if (!_M_in_input_mode) |
|
405 return _M_seek_return(_M_base._M_seek(_M_width * __off, __whence), |
|
406 _State_type()); |
|
407 else if (_M_mmap_base != 0) { |
|
408 // __off is relative to gptr(). We need to do a bit of arithmetic |
|
409 // to get an offset relative to the external file pointer. |
|
410 streamoff __adjust = _M_mmap_len - (this->gptr() - (_CharT*) _M_mmap_base); |
|
411 |
|
412 // if __off == 0, we do not need to exit input mode and to shift file pointer |
|
413 return __off == 0 ? pos_type(_M_base._M_seek(0, ios_base::cur) - __adjust) |
|
414 : _M_seek_return(_M_base._M_seek(__off - __adjust, ios_base::cur), _State_type()); |
|
415 } |
|
416 else if (_M_constant_width) { // Get or set the position. |
|
417 streamoff __iadj = _M_width * (this->gptr() - this->eback()); |
|
418 |
|
419 // Compensate for offset relative to gptr versus offset relative |
|
420 // to external pointer. For a text-oriented stream, where the |
|
421 // compensation is more than just pointer arithmetic, we may get |
|
422 // but not set the current position. |
|
423 |
|
424 if (__iadj <= _M_ext_buf_end - _M_ext_buf) { |
|
425 streamoff __eadj = _M_base._M_get_offset(_M_ext_buf + __STATIC_CAST(ptrdiff_t, __iadj), _M_ext_buf_end); |
|
426 |
|
427 return __off == 0 ? pos_type(_M_base._M_seek(0, ios_base::cur) - __eadj) |
|
428 : _M_seek_return(_M_base._M_seek(__off - __eadj, ios_base::cur), _State_type()); |
|
429 } |
|
430 } else { // Get the position. Encoding is var width. |
|
431 // Get position in internal buffer. |
|
432 ptrdiff_t __ipos = this->gptr() - this->eback(); |
|
433 |
|
434 // Get corresponding position in external buffer. |
|
435 _State_type __state = _M_state; |
|
436 int __epos = _M_codecvt->length(__state, _M_ext_buf, _M_ext_buf_end, |
|
437 __ipos); |
|
438 |
|
439 if (__epos >= 0) { |
|
440 // Sanity check (expensive): make sure __epos is the right answer. |
|
441 _State_type __tmp_state = _M_state; |
|
442 _Filebuf_Tmp_Buf<_CharT> __buf(__ipos); |
|
443 _CharT* __ibegin = __buf._M_ptr; |
|
444 _CharT* __inext = __ibegin; |
|
445 |
|
446 const char* __dummy; |
|
447 typename _Codecvt::result __status |
|
448 = _M_codecvt->in(__tmp_state, |
|
449 _M_ext_buf, _M_ext_buf + __epos, __dummy, |
|
450 __ibegin, __ibegin + __ipos, __inext); |
|
451 if (__status != _Codecvt::error && |
|
452 (__status == _Codecvt::noconv || |
|
453 (__inext == __ibegin + __ipos && |
|
454 equal(this->eback(), this->gptr(), __ibegin, _STLP_PRIV _Eq_traits<traits_type>())))) { |
|
455 // Get the current position (at the end of the external buffer), |
|
456 // then adjust it. Again, it might be a text-oriented stream. |
|
457 streamoff __cur = _M_base._M_seek(0, ios_base::cur); |
|
458 streamoff __adj = |
|
459 _M_base._M_get_offset(_M_ext_buf, _M_ext_buf + __epos) - |
|
460 _M_base._M_get_offset(_M_ext_buf, _M_ext_buf_end); |
|
461 if (__cur != -1 && __cur + __adj >= 0) |
|
462 return __off == 0 ? pos_type(__cur + __adj) |
|
463 : _M_seek_return(__cur + __adj, __state); |
|
464 //return _M_seek_return(__cur + __adj, __state); |
|
465 } |
|
466 // We failed the sanity check here. |
|
467 } |
|
468 } |
|
469 } |
|
470 // Unrecognized value for __whence here. |
|
471 } |
|
472 |
|
473 return pos_type(-1); |
|
474 |
|
475 } |
|
476 |
|
477 virtual pos_type seekpos(pos_type __pos, |
|
478 ios_base::openmode /* dummy */) { |
|
479 |
|
480 if (this->is_open()) { |
|
481 if (!_M_seek_init(true)) |
|
482 return pos_type(-1); |
|
483 |
|
484 streamoff __off = off_type(__pos); |
|
485 if (__off != -1 && _M_base._M_seek(__off, ios_base::beg) != -1) { |
|
486 _M_state = __pos.state(); |
|
487 return _M_seek_return(__off, __pos.state()); |
|
488 } |
|
489 } |
|
490 |
|
491 return pos_type(-1); |
|
492 |
|
493 } |
|
494 |
|
495 virtual int sync() { |
|
496 |
|
497 if (_M_in_output_mode) |
|
498 return traits_type::eq_int_type(this->overflow(traits_type::eof()), |
|
499 traits_type::eof()) ? -1 : 0; |
|
500 return 0; |
|
501 |
|
502 } |
|
503 |
|
504 virtual void imbue(const locale& __loc) { |
|
505 |
|
506 if (!_M_in_input_mode && !_M_in_output_mode && !_M_in_error_mode) { |
|
507 this->_M_setup_codecvt(__loc); |
|
508 } |
|
509 |
|
510 } |
|
511 |
|
512 |
255 private: // Helper functions. |
513 private: // Helper functions. |
256 |
514 |
257 // Precondition: we are currently in putback input mode. Effect: |
515 // Precondition: we are currently in putback input mode. Effect: |
258 // switches back to ordinary input mode. |
516 // switches back to ordinary input mode. |
259 void _M_exit_putback_mode() { |
517 void _M_exit_putback_mode() { |