blob: eaf506ea55154df0549cd971fd374a12c9f3a4cf [file] [log] [blame]
/***************************************************************************
*
* sstream.cc - Declarations for the Standard Library basic strings
*
* $Id: //stdlib/dev/include/sstream.cc#31 $
*
***************************************************************************
*
* Copyright (c) 1994-2005 Quovadx, Inc., acting through its Rogue Wave
* Software division. Licensed 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.
*
**************************************************************************/
_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)
{
typedef _RWSTD_STREAMSIZE _Streamsize;
this->_C_own_buf (true);
const _Streamsize __slen = _Streamsize (__str.length ());
if (__slen != 0) {
typedef _RWSTD_ALLOC_TYPE (allocator_type, char_type) _ValueAlloc;
this->_C_bufsize = __slen;
this->_C_buffer = _ValueAlloc ().allocate (this->_C_bufsize);
traits_type::copy (this->_C_buffer, __str.data (), __slen);
if (this->_C_is_in ())
this->setg (this->_C_buffer, this->_C_buffer, this->_C_buf_end ());
if (this->_C_is_out ())
this->setp (this->_C_buffer, this->_C_buf_end ());
if (__mode & (ios_base::app | ios_base::ate))
this->pbump (__slen); // "seek" to end
}
}
template<class _CharT, class _Traits, class _Allocator>
void
basic_stringbuf<_CharT, _Traits, _Allocator>::
str (const _C_string_type& __str)
{
_RWSTD_ASSERT (this->_C_is_valid ());
typedef _RWSTD_ALLOC_TYPE (allocator_type, char_type) _ValueAlloc;
typedef _RWSTD_STREAMSIZE _Streamsize;
const _Streamsize __slen = _Streamsize (__str.length ());
if (0 == __slen) {
if (this->_C_own_buf ())
_ValueAlloc ().deallocate (this->_C_buffer, this->_C_bufsize);
this->setg(0, 0, 0);
this->setp(0, 0);
this->_C_buffer = 0;
this->_C_bufsize = 0;
}
else {
if (__slen > this->_C_bufsize) {
// buffer too small - need to reallocate
if (this->_C_own_buf ())
_ValueAlloc ().deallocate (this->_C_buffer, this->_C_bufsize);
this->_C_bufsize = _C_grow (this->_C_bufsize, __slen);
this->_C_buffer = _ValueAlloc ().allocate (this->_C_bufsize);
this->_C_own_buf (true);
}
traits_type::copy (this->_C_buffer, __str.data (), __slen);
if (this->_C_is_in ())
this->setg (this->_C_buffer, this->_C_buffer,
this->_C_buffer + __slen);
if (this->_C_is_out ()) {
this->setp (this->_C_buffer, this->_C_buffer + __slen);
if ( (this->_C_state & ios_base::app)
|| (this->_C_state & ios_base::ate))
this->pbump (__slen); // seek to end
}
}
}
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 ());
if (!this->_C_is_out ())
return traits_type::eof ();
if (this->_C_is_eof (__c))
return traits_type::not_eof (__c);
typedef _RWSTD_STREAMSIZE _Streamsize;
const _Streamsize __slen = _C_strlen ();
// reallocate space if necessary
if (!(this->epptr () < this->_C_buf_end ())) {
typedef _RWSTD_ALLOC_TYPE (allocator_type, char_type) _ValueAlloc;
// calculate size of buffer to allocate
const _Streamsize __new_size =
_C_grow (this->_C_bufsize + 1, this->_C_bufsize);
char_type* __new_buf = _ValueAlloc ().allocate (__new_size);
if (this->_C_buffer) { // need to copy the old buffer to new buffer
traits_type::copy (__new_buf, this->_C_buffer, __slen);
if (this->_C_own_buf ())
_ValueAlloc ().deallocate (this->_C_buffer, this->_C_bufsize);
}
this->_C_own_buf (true);
this->_C_bufsize = __new_size;
this->_C_buffer = __new_buf;
}
// increment the end put pointer by one position
this->setp (this->_C_buffer, this->_C_buffer + __slen + 1);
this->pbump (__slen);
// set get area if in in|out mode
if (this->_C_is_inout ()) {
// use the relative offset of gptr () from eback() to set the new gptr
// although they are invalid, the offset is still valid
char_type* __gptr_new = this->_C_buffer
+ (this->gptr () - this->eback ());
// N.B. pptr() has already been incremented
this->setg (this->_C_buffer, __gptr_new, this->epptr());
}
return this->sputc (traits_type::to_char_type (__c));
}
template<class _CharT, class _Traits, class _Allocator>
_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>
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;
if (__n < _C_strlen() || !this->_C_is_out())
return 0; // failure
bool __own_old_buf = this->_C_own_buf ();
typedef _RWSTD_STREAMSIZE _Streamsize;
const _Streamsize __slen = _C_strlen ();
typedef _RWSTD_ALLOC_TYPE (allocator_type, char_type) _ValueAlloc;
if (0 == __buf) {
__buf = _ValueAlloc ().allocate (__n);
this->_C_own_buf (true);
}
else
this->_C_own_buf (false);
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;
const _Streamsize __pptr_off = _Streamsize(this->pptr () - this->pbase ());
this->setp (this->_C_buffer, this->_C_buffer + __slen);
this->pbump (__pptr_off); // ... and restore it
// set get area if in in|out mode
if (this->_C_is_inout()) {
// use the relative offset of gptr () from eback() to set the new gptr
// (although the pointers are invalid, the offset is still valid)
char_type* const __gptr_new =
this->_C_buffer + (this->gptr () - this->eback ());
this->setg (this->_C_buffer, __gptr_new, this->epptr());
}
return this;
}
template<class _CharT, class _Traits, class _Allocator>
_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);
typedef _RWSTD_STREAMSIZE _Streamsize;
_Streamsize __newoff = 0;
if (__which & ios_base::in) {
if (!this->_C_is_in () || !this->gptr ())
return pos_type (off_type (-1));
// do the checks for in|out mode here
if (__which & ios_base::out) {
if ((__way & ios_base::cur) || !this->_C_is_out ())
return pos_type (off_type (-1));
}
switch (__way) {
case ios_base::beg:
__newoff = 0;
break;
case ios_base::cur:
__newoff = _Streamsize (this->gptr () - this->eback ());
break;
case ios_base::end:
__newoff = _Streamsize (this->egptr () - this->eback ());
}
if ( (__newoff + __off) < 0
|| (this->egptr () - this->eback ()) < (__newoff + __off))
return pos_type (off_type (-1));
this->setg (this->eback (),
this->eback () + __newoff + __off,
this->egptr ());
}
if (__which & ios_base::out) {
if (!this->_C_is_out () || !this->pptr ())
return pos_type (off_type (-1));
switch (__way) {
case ios_base::beg:
__newoff = 0;
break;
case ios_base::cur:
__newoff = _Streamsize (this->pptr () - this->pbase ());
break;
case ios_base::end:
__newoff = _Streamsize (this->epptr () - this->pbase ());
break;
}
if ( (__newoff + __off) < 0
|| (this->epptr () - this->pbase ()) < (__newoff + __off))
return pos_type (off_type (-1));
this->setp (this->pbase (), this->epptr ());
this->pbump (__newoff + __off);
}
return pos_type (__newoff + __off);
}
template<class _CharT, class _Traits, class _Allocator>
_TYPENAME basic_stringbuf<_CharT, _Traits, _Allocator>::pos_type
basic_stringbuf<_CharT, _Traits, _Allocator>::
seekpos (pos_type __sp, ios_base::openmode __which)
{
_RWSTD_ASSERT (this->_C_is_valid ());
#if !defined (__GNUG__) || __GNUG__ != 4 || __GNUC_MINOR__ != 0
const _RWSTD_STREAMSIZE __newoff = off_type (__sp);
#else // !gcc 4.0
// work around gcc 4.0.0 bug #454
_RWSTD_STREAMSIZE __newoff = off_type (__sp);
#endif // gcc 4.0
// return invalid pos if no positioning operation succeeds
pos_type __retval = pos_type (off_type (-1));
if (__newoff < 0)
return __retval;
// see 27.7.1.3 p.11 for required conditions
if ((__which & ios_base::in) && this->_C_is_in () && this->gptr()) {
if ((this->eback () + __newoff) > this->egptr ())
return pos_type (off_type (-1));
this->setg (this->eback (),
this->eback () + __newoff,
this->egptr ());
__retval = __sp;
}
if ((__which & ios_base::out) && this->_C_is_out () && this->pptr()) {
if ((this->pbase () + __newoff) > this->epptr ())
return pos_type (off_type (-1));
this->setp (this->pbase (), this->epptr ());
this->pbump (__newoff);
__retval = __sp;
}
return __retval;
}
} // namespace std