/*************************************************************************** * * sstream.cc - Declarations for the Standard Library basic strings * * $Id: sstream.cc 648752 2008-04-16 17:01:56Z faridz $ * *************************************************************************** * * 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 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 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 /* 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 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; // saved offset of pptr _RWSTD_STREAMSIZE __off = -1; 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 (); // save the offset of pptr __off = this->pptr () - 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 (0 <= __off) { // restore the pptr this->pbump (__off); } else if ( 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 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; } // grow the buffer if necessary to accommodate the whole // string plus the contents of the buffer up to pptr() str (this->_C_buffer, __bufsize); _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 /* 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 /* 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 _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 /* 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 /* 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 /* 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 /* 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