blob: 423e2937b0897de0a1b4508b709ded951e802b43 [file] [log] [blame]
/***************************************************************************
*
* sstream.cc - Declarations for the Standard Library basic strings
*
* $Id$
*
***************************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
* Copyright 1994-2006 Rogue Wave Software.
*
**************************************************************************/
_RWSTD_NAMESPACE (std) {
template<class _CharT, class _Traits, class _Allocator>
basic_stringbuf<_CharT, _Traits, _Allocator>::
basic_stringbuf (const _C_string_type& __str, ios_base::openmode __mode)
: basic_streambuf<_CharT, _Traits>(__mode)
{
str (__str);
}
// extension
template<class _CharT, class _Traits, class _Allocator>
basic_stringbuf<_CharT, _Traits, _Allocator>::
basic_stringbuf (const char_type *__s, ios_base::openmode __mode)
: basic_streambuf<_CharT, _Traits>(__mode)
{
_RWSTD_ASSERT (0 != __s);
str (__s, traits_type::length (__s));
}
template <class _CharT, class _Traits, class _Allocator>
/* virtual */
basic_stringbuf<_CharT, _Traits, _Allocator>::
~basic_stringbuf ()
{
typedef _RWSTD_ALLOC_TYPE (allocator_type, char_type) _ValueAlloc;
if (this->_C_own_buf ())
_ValueAlloc ().deallocate (this->_C_buffer, this->_C_bufsize);
}
// extension
template<class _CharT, class _Traits, class _Allocator>
void
basic_stringbuf<_CharT, _Traits, _Allocator>::
str (const char_type *__s, _RWSTD_SIZE_T __slen)
{
_RWSTD_ASSERT (this->_C_is_valid ());
typedef _RWSTD_ALLOC_TYPE (allocator_type, char_type) _ValueAlloc;
typedef _RWSTD_STREAMSIZE _Streamsize;
// compute the lenth if not specified
if (_RWSTD_SIZE_MAX == __slen)
__slen = traits_type::length (__s);
_ValueAlloc __alloc;
// new buffer and size
char_type *__buf;
_RWSTD_SIZE_T __bufsize = __slen;
if (__s == this->_C_buffer) {
// special case: str(_C_buffer, _C_bufsize + N) called
// to increase the capacity of buffer
_C_catchup (this->eback ());
// set `slen' to the number of initialized characters
// in the buffer
__slen = this->egptr () - this->pbase ();
}
if (this->_C_bufsize < __bufsize) {
// requested capacity is greater than the current capacity
// allocate a new buffer of sufficient size
__bufsize = _C_grow (__bufsize);
if (__s != this->_C_buffer && this->_C_own_buf ()) {
// deallocate the existing buffer here only if the string
// is not the same as the buffer itself; otherwise, copy
// it to the newly allocated buffer first and deallocate
// it later
__alloc.deallocate (this->_C_buffer, this->_C_bufsize);
this->_C_buffer = 0;
}
__buf = __alloc.allocate (__bufsize);
}
else if (0 < __bufsize) {
// requested capacity is the same or less than the current one
__buf = this->_C_buffer;
__bufsize = this->_C_bufsize;
}
else {
// zero size and capacity, deallocate and reset all pointers
__buf = 0;
__bufsize = 0;
_RWSTD_ASSERT (0 == __slen);
}
// compute the "high mark" (see lwg issue 432)
char_type* const __egptr = __buf + __slen;
if (__s != __buf) {
// copy the provided string to buffer
traits_type::copy (__buf, __s, __slen);
if (this->_C_buffer != __buf) {
if (this->_C_buffer && this->_C_own_buf ())
__alloc.deallocate (this->_C_buffer, this->_C_bufsize);
// take ownership of the allocated buffer
this->_C_own_buf (true);
this->_C_buffer = __buf;
this->_C_bufsize = __bufsize;
}
}
if (this->_C_is_in ())
this->setg (this->_C_buffer, this->_C_buffer, __egptr);
else {
// when not in in mode set all get pointers to the same
// value and use egptr() as the "high mark" (see lwg
// issue 432)
this->setg (__egptr, __egptr, __egptr);
}
if (this->_C_is_out ()) {
this->setp (this->_C_buffer, this->_C_buffer + this->_C_bufsize);
if ( __s != __buf && this->_C_state & ios_base::in
|| this->_C_state & (ios_base::app | ios_base::ate)) {
// in input or append/ate modes seek to end
// (see also lwg issue 562 for clarification)
this->pbump (__slen);
}
}
_RWSTD_ASSERT (this->_C_is_valid ());
}
template <class _CharT, class _Traits, class _Allocator>
streamsize
basic_stringbuf<_CharT, _Traits, _Allocator>::
xsputn (const char_type* __s, streamsize __n)
{
_RWSTD_ASSERT (0 != __s || 0 == __n);
_RWSTD_ASSERT (this->_C_is_valid ());
if (__n <= 0 || !this->_C_is_out ())
return 0;
if (this->epptr () - this->pptr () < __n) {
// compute the total amount of space necessary
const _RWSTD_SIZE_T __bufsize =
__n + (this->pptr () - this->pbase ());
_RWSTD_PTRDIFF_T __off = -1;
if (this->pbase () <= __s && this->pptr () > __s) {
// __s is a part of the buffer
_RWSTD_ASSERT (this->epptr () >= __s + __n);
// save the offset from pbase()
__off = this->pbase () - __s;
}
// preserve current pptr() since str() would seek to end
const streamsize __cur = this->pptr () - this->pbase ();
// grow the buffer if necessary to accommodate the whole
// string plus the contents of the buffer up to pptr()
str (this->_C_buffer, __bufsize);
// restore pptr()
this->pbump (__cur - (this->pptr () - this->pbase ()));
_RWSTD_ASSERT (__n <= this->epptr () - this->pptr ());
if (0 <= __off) {
// correct __s after the buffer reallocation
__s = this->pbase () + __off;
}
}
// copy the whole string
traits_type::copy (this->pptr (), __s, __n);
this->pbump (__n);
_C_catchup (this->eback ());
return __n;
}
template <class _CharT, class _Traits, class _Allocator>
/* virtual */ streamsize
basic_stringbuf<_CharT, _Traits, _Allocator>::
showmanyc ()
{
_RWSTD_ASSERT (this->_C_is_valid ());
// get egptr() caught up with pptr()
_C_catchup (this->eback ());
return streamsize (this->egptr () - this->gptr ());
}
template <class _CharT, class _Traits, class _Allocator>
/* virtual */ _TYPENAME basic_stringbuf<_CharT, _Traits, _Allocator>::int_type
basic_stringbuf<_CharT, _Traits, _Allocator>::
underflow ()
{
_RWSTD_ASSERT (this->_C_is_valid ());
if (this->gptr () < this->egptr ()) {
_RWSTD_ASSERT (0 != this->gptr ());
return traits_type::to_int_type (*this->gptr ());
}
else if (this->gptr () < this->pptr ()) {
// get egptr() caught up with pptr()
_C_catchup (this->eback ());
if (this->gptr () < this->egptr ())
return traits_type::to_int_type (*this->gptr ());
}
return traits_type::eof ();
}
template<class _CharT, class _Traits, class _Allocator>
_TYPENAME basic_stringbuf<_CharT, _Traits, _Allocator>::int_type
basic_stringbuf<_CharT, _Traits, _Allocator>::
overflow (int_type __c)
{
_RWSTD_ASSERT (this->_C_is_valid ());
// 27.7.1.3, p5, bullet 2 of C++ '03: when (c == eof)
// indicate success even when not in out mode
if (this->_C_is_eof (__c))
return traits_type::not_eof (__c);
if (!this->_C_is_out ())
return traits_type::eof ();
char_type* const __bufend = this->_C_buffer + this->_C_bufsize;
if (this->pptr () == this->epptr ()) {
// reallocate buffer
str (this->_C_buffer, this->_C_bufsize + 1);
}
else if (this->epptr () < __bufend) {
// bump up epptr() keeping pbase() and pptr() unchanged
const _RWSTD_STREAMSIZE __off = this->pptr () - this->pbase ();
this->setp (this->pbase (), __bufend);
this->pbump (__off);
}
const int_type __retval = this->sputc (traits_type::to_char_type (__c));
// get egptr() caught up with the value of pptr() after the call
_C_catchup (this->_C_buffer);
return __retval;
}
template<class _CharT, class _Traits, class _Allocator>
/* virtual */ _TYPENAME basic_stringbuf<_CharT, _Traits, _Allocator>::int_type
basic_stringbuf<_CharT, _Traits, _Allocator>::
pbackfail (int_type __c)
{
_RWSTD_ASSERT (this->_C_is_valid ());
if (!this->_C_putback_avail ())
return traits_type::eof ();
int_type __retval;
const char_type __ch = traits_type::to_char_type (__c);
if (traits_type::eq (__ch, *(this->gptr () - 1)) || this->_C_is_eof (__c)) {
// "put back" original value
this->gbump (-1);
__retval = traits_type::not_eof (__c);
}
else if (this->_C_is_out ()) {
// overwrite existing value with new value
this->gbump (-1);
traits_type::assign (*this->gptr (), __ch);
__retval = __c;
}
else
__retval = traits_type::eof ();
return __retval;
}
template<class _CharT, class _Traits, class _Allocator>
/* virtual */ basic_streambuf<_CharT, _Traits>*
basic_stringbuf<_CharT, _Traits, _Allocator>::
setbuf (char_type* __buf, _RWSTD_STREAMSIZE __n)
{
_RWSTD_ASSERT (this->_C_is_valid ());
if (!__buf && !__n) // 27.7.1.3, p16
return this;
const _RWSTD_STREAMSIZE __slen = (this->egptr () < this->pptr () ?
this->pptr () : this->egptr ()) - this->pbase ();
if (__n < __slen || !this->_C_is_out())
return 0; // failure
// compute the gptr and pptr offsets so the pointers can be restored
const _RWSTD_STREAMSIZE __goff = this->gptr () - this->eback ();
const _RWSTD_STREAMSIZE __poff = this->pptr () - this->pbase ();
const bool __own_old_buf = this->_C_own_buf ();
typedef _RWSTD_ALLOC_TYPE (allocator_type, char_type) _ValueAlloc;
if (0 == __buf) {
// allocate a new buffer of the specified size
__buf = _ValueAlloc ().allocate (__n);
this->_C_own_buf (true);
}
else
this->_C_own_buf (false);
// copy the contents of the existing buffer to the new one
traits_type::copy (__buf, this->_C_buffer, __slen);
if (__own_old_buf)
_ValueAlloc ().deallocate (this->_C_buffer, this->_C_bufsize);
this->_C_buffer = __buf;
this->_C_bufsize = __n;
// reset the output and input sequences within the new buffer
this->setp (this->_C_buffer, this->_C_buffer + this->_C_bufsize);
this->pbump (__poff); // ... and restore it
char_type* const __egptr = this->_C_buffer + __slen;
if (this->_C_is_in ())
this->setg (this->_C_buffer, this->_C_buffer + __goff, __egptr);
else {
// use egptr as the "high mark" (see lwg issue 432)
this->setg (__egptr, __egptr, __egptr);
}
return this;
}
template<class _CharT, class _Traits, class _Allocator>
/* virtual */ _TYPENAME basic_stringbuf<_CharT, _Traits, _Allocator>::pos_type
basic_stringbuf<_CharT, _Traits, _Allocator>::
seekoff (off_type __off, ios_base::seekdir __way, ios_base::openmode __which)
{
_RWSTD_ASSERT (this->_C_is_valid ());
// should implicitly hold as long as ios::seekdir is an enum
_RWSTD_ASSERT ( ios_base::beg == __way
|| ios_base::cur == __way
|| ios_base::end == __way);
_RWSTD_STREAMSIZE __newoff = -1;
// get egptr() caught up with pptr()
_C_catchup (this->eback ());
if (__which & ios_base::in) {
// LWG issue 453: the operation fails if either gptr() or pptr()
// is a null pointer and the new offset newoff is nonzero
if (!this->_C_is_in () || __off && !this->gptr ())
return pos_type (off_type (-1));
// do the checks for in|out mode here
if ( __which & ios_base::out
&& (ios_base::cur == __way || !this->_C_is_out ()))
return pos_type (off_type (-1));
switch (__way) {
case ios_base::beg: __newoff = 0; break;
case ios_base::cur: __newoff = this->gptr () - this->eback (); break;
case ios_base::end: __newoff = this->egptr () - this->eback (); break;
}
__newoff += __off;
if (__newoff < 0 || this->egptr () - this->eback () < __newoff)
return pos_type (off_type (-1));
this->setg (this->eback (), this->eback () + __newoff, this->egptr ());
}
if (__which & ios_base::out) {
// LWG issue 453: the operation fails if either gptr() or pptr()
// is a null pointer and the new offset newoff is nonzero
if (!this->_C_is_out () || __off && !this->pptr ())
return pos_type (off_type (-1));
// egptr() is used as the "high mark" even when not in "in" mode
_RWSTD_ASSERT (0 == this->pbase () || 0 != this->egptr ());
// compute the number of initialized characters in the buffer
// (see LWG issue 432)
const _RWSTD_STREAMSIZE __high = this->egptr () - this->pbase ();
const _RWSTD_STREAMSIZE __cur = this->pptr () - this->pbase ();
switch (__way) {
case ios_base::beg: __newoff = 0; break;
case ios_base::cur: __newoff = __cur; break;
case ios_base::end: __newoff = __high; break;
}
__newoff += __off;
if (__newoff < 0 || __high < __newoff)
return pos_type (off_type (-1));
// bump pptr up (or down) to the new position
this->pbump (__newoff - __cur);
}
_RWSTD_ASSERT (this->_C_is_valid ());
return __newoff < 0 ? pos_type (off_type (-1)) : pos_type (__newoff);
}
template<class _CharT, class _Traits, class _Allocator>
/* virtual */ _TYPENAME basic_stringbuf<_CharT, _Traits, _Allocator>::pos_type
basic_stringbuf<_CharT, _Traits, _Allocator>::
seekpos (pos_type __pos, ios_base::openmode __which)
{
_RWSTD_ASSERT (this->_C_is_valid ());
// typedef helps HP aCC 3.27
typedef basic_stringbuf _StringBuf;
return pos_type (_StringBuf::seekoff (__pos, ios_base::beg, __which));
}
} // namespace std