1/*
2 * Copyright (c) 1999
3 * Silicon Graphics Computer Systems, Inc.
4 *
5 * Copyright (c) 1999
6 * Boris Fomitchev
7 *
8 * This material is provided "as is", with absolutely no warranty expressed
9 * or implied. Any use is at your own risk.
10 *
11 * Permission to use or copy this software for any purpose is hereby granted
12 * without fee, provided the above notices are retained on all copies.
13 * Permission to modify the code and to distribute modified code is granted,
14 * provided the above notices are retained, and a notice that the code was
15 * modified is included with the above copyright notice.
16 *
17 */
18
19#ifndef _STLP_SSTREAM_C
20#define _STLP_SSTREAM_C
21
22#ifndef _STLP_INTERNAL_SSTREAM
23#  include <stl/_sstream.h>
24#endif
25
26#if defined ( _STLP_NESTED_TYPE_PARAM_BUG )
27// no wint_t is supported for this mode
28#  define __BSB_int_type__ int
29#  define __BSB_pos_type__ streampos
30#else
31#  define __BSB_int_type__ _STLP_TYPENAME_ON_RETURN_TYPE basic_stringbuf<_CharT, _Traits, _Alloc>::int_type
32#  define __BSB_pos_type__ _STLP_TYPENAME_ON_RETURN_TYPE basic_stringbuf<_CharT, _Traits, _Alloc>::pos_type
33#endif
34
35_STLP_BEGIN_NAMESPACE
36
37//----------------------------------------------------------------------
38// Non-inline stringbuf member functions.
39
40// Constructors.  Note that the base class constructor sets all of the
41// get and area pointers to null.
42
43template <class _CharT, class _Traits, class _Alloc>
44basic_stringbuf<_CharT, _Traits, _Alloc>
45  ::basic_stringbuf(ios_base::openmode __mode)
46    : basic_streambuf<_CharT, _Traits>(), _M_mode(__mode), _M_str()
47{}
48
49template <class _CharT, class _Traits, class _Alloc>
50basic_stringbuf<_CharT, _Traits, _Alloc>
51  ::basic_stringbuf(const basic_string<_CharT, _Traits, _Alloc>& __s, ios_base::openmode __mode)
52    : basic_streambuf<_CharT, _Traits>(), _M_mode(__mode), _M_str(__s)
53{
54  _M_set_ptrs();
55}
56
57template <class _CharT, class _Traits, class _Alloc>
58basic_stringbuf<_CharT, _Traits, _Alloc>::~basic_stringbuf()
59{}
60
61// Set the underlying string to a new value.
62template <class _CharT, class _Traits, class _Alloc>
63void
64basic_stringbuf<_CharT, _Traits, _Alloc>::str(const basic_string<_CharT, _Traits, _Alloc>& __s)
65{
66  _M_str = __s;
67  _M_set_ptrs();
68}
69
70template <class _CharT, class _Traits, class _Alloc>
71void
72basic_stringbuf<_CharT, _Traits, _Alloc>::_M_set_ptrs()
73{
74  _CharT* __data_ptr = _S_start(_M_str);
75  _CharT* __data_end = _S_finish(_M_str);
76  // The initial read position is the beginning of the string.
77  if (_M_mode & ios_base::in) {
78    this->setg(__data_ptr, (_M_mode & ios_base::ate) ? __data_end : __data_ptr, __data_end);
79  }
80
81  // The initial write position is the beginning of the string.
82  if (_M_mode & ios_base::out) {
83    if ( _M_mode & (ios_base::app | ios_base::ate) ) {
84      this->setp( __data_end, __data_end );
85    } else {
86      this->setp( __data_ptr, __data_end );
87      this->pbump((int)_M_str.size()); // initial write position, if we initialized with string
88    }
89    // this->setp((_M_mode & (ios_base::app | ios_base::ate))? __data_end : __data_ptr, __data_end);
90  }
91}
92
93// Precondition: gptr() >= egptr().  Returns a character, if one is available.
94template <class _CharT, class _Traits, class _Alloc>
95__BSB_int_type__
96basic_stringbuf<_CharT, _Traits, _Alloc>::underflow() {
97  return this->gptr() != this->egptr()
98    ? _Traits::to_int_type(*this->gptr())
99    : _Traits::eof();
100}
101
102// Precondition: gptr() >= egptr().
103template <class _CharT, class _Traits, class _Alloc>
104__BSB_int_type__
105basic_stringbuf<_CharT, _Traits, _Alloc>::uflow() {
106  if (this->gptr() != this->egptr()) {
107    int_type __c = _Traits::to_int_type(*this->gptr());
108    this->gbump(1);
109    return __c;
110  }
111  else
112    return _Traits::eof();
113}
114
115template <class _CharT, class _Traits, class _Alloc>
116__BSB_int_type__
117basic_stringbuf<_CharT, _Traits, _Alloc>::pbackfail(int_type __c) {
118  if (this->gptr() != this->eback()) {
119    if (!_Traits::eq_int_type(__c, _Traits::eof())) {
120      if (_Traits::eq(_Traits::to_char_type(__c), this->gptr()[-1])) {
121        this->gbump(-1);
122        return __c;
123      }
124      else if (_M_mode & ios_base::out) {
125        this->gbump(-1);
126        *this->gptr() = _Traits::to_char_type(__c);
127        return __c;
128      }
129      else
130        return _Traits::eof();
131    }
132    else {
133      this->gbump(-1);
134      return _Traits::not_eof(__c);
135    }
136  }
137  else
138    return _Traits::eof();
139}
140
141template <class _CharT, class _Traits, class _Alloc>
142__BSB_int_type__ basic_stringbuf<_CharT, _Traits, _Alloc>::overflow(int_type __c)
143{
144  if (!_Traits::eq_int_type(__c, _Traits::eof())) {
145    if (_M_mode & ios_base::out) {
146      if ( this->pptr() < this->epptr() ) { // just put back in any case
147        _M_str.push_back( _Traits::to_char_type(__c) );
148        this->pbump(1);
149      } else if ( _M_mode & ios_base::in ) {
150        ptrdiff_t __offset = this->gptr() - this->eback();
151        _M_str.push_back(_Traits::to_char_type(__c));
152        _CharT* __data_ptr = _S_start(_M_str);
153        this->setg(__data_ptr, __data_ptr + __offset, _S_finish(_M_str));
154        this->setp(__data_ptr, _S_finish(_M_str));
155        this->pbump((int)_M_str.size());
156      } else {
157        _M_str.push_back( _Traits::to_char_type(__c) );
158        this->setp(_S_start(_M_str), _S_finish(_M_str));
159        this->pbump((int)_M_str.size());
160      }
161      return __c;
162    }
163    return _Traits::eof(); // Overflow always fails if it's read-only
164  }
165  return _Traits::not_eof(__c); // __c is EOF, so we don't have to do anything
166}
167
168template <class _CharT, class _Traits, class _Alloc>
169streamsize
170basic_stringbuf<_CharT, _Traits, _Alloc>::xsputn(const char_type* __s,
171                                                 streamsize __n) {
172  streamsize __nwritten = 0;
173
174  if ((_M_mode & ios_base::out) && __n > 0) {
175    // If the put pointer is somewhere in the middle of the string,
176    // then overwrite instead of append.
177    if ( !_M_str.empty() && this->pbase() == _S_start(_M_str)) {
178      ptrdiff_t __avail = _S_finish(_M_str) - this->pptr();
179      if (__avail > __n) {
180        _Traits::copy(this->pptr(), __s, __STATIC_CAST(size_t, __n));
181        this->pbump((int)__n);
182        return __n;
183      } else {
184        _Traits::copy(this->pptr(), __s, __avail);
185        __nwritten += __avail;
186        __n -= __avail;
187        __s += __avail;
188      }
189    }
190
191    // At this point we know we're appending.
192    _CharT* __data_ptr;
193    if (_M_mode & ios_base::in) {
194      ptrdiff_t __get_offset = this->gptr() - this->eback();
195      _M_str.append(__s, __s + __STATIC_CAST(ptrdiff_t, __n));
196      __data_ptr = _S_start(_M_str);
197      this->setg(__data_ptr, __data_ptr + __get_offset, _S_finish(_M_str));
198    } else {
199      _M_str.append(__s, __s + __STATIC_CAST(ptrdiff_t, __n));
200      __data_ptr = _S_start(_M_str);
201    }
202
203    this->setp(__data_ptr, _S_finish(_M_str));
204    this->pbump((int)_M_str.size());
205    __nwritten += __n;
206  }
207
208  return __nwritten;
209}
210
211template <class _CharT, class _Traits, class _Alloc>
212streamsize
213basic_stringbuf<_CharT, _Traits, _Alloc>::_M_xsputnc(char_type __c,
214                                                     streamsize __n) {
215  streamsize __nwritten = 0;
216
217  if ((_M_mode & ios_base::out) && __n > 0) {
218    // If the put pointer is somewhere in the middle of the string,
219    // then overwrite instead of append.
220    if (this->pbase() == _S_start(_M_str)) {
221      ptrdiff_t __avail = _S_finish(_M_str) - this->pptr();
222      if (__avail > __n) {
223        _Traits::assign(this->pptr(), __STATIC_CAST(size_t, __n), __c);
224        this->pbump(__STATIC_CAST(int, __n));
225        return __n;
226      }
227      else {
228        _Traits::assign(this->pptr(), __avail, __c);
229        __nwritten += __avail;
230        __n -= __avail;
231      }
232    }
233
234    // At this point we know we're appending.
235    size_t __app_size = sizeof(streamsize) > sizeof(size_t) ? __STATIC_CAST(size_t, (min)(__n, __STATIC_CAST(streamsize, _M_str.max_size())))
236                                                            : __STATIC_CAST(size_t, __n);
237    _CharT* __data_ptr;
238    if (this->_M_mode & ios_base::in) {
239      ptrdiff_t __get_offset = this->gptr() - this->eback();
240      _M_str.append(__app_size, __c);
241      __data_ptr = _S_start(_M_str);
242      this->setg(__data_ptr, __data_ptr + __get_offset, _S_finish(_M_str));
243    } else {
244      _M_str.append(__app_size, __c);
245      __data_ptr = _S_start(_M_str);
246    }
247
248    this->setp(__data_ptr, _S_finish(_M_str));
249    this->pbump((int)_M_str.size());
250    __nwritten += __app_size;
251  }
252
253  return __nwritten;
254}
255
256// According to the C++ standard the effects of setbuf are implementation
257// defined, except that setbuf(0, 0) has no effect.  In this implementation,
258// setbuf(<anything>, n), for n > 0, calls reserve(n) on the underlying
259// string.
260template <class _CharT, class _Traits, class _Alloc>
261basic_streambuf<_CharT, _Traits>*
262basic_stringbuf<_CharT, _Traits, _Alloc>::setbuf(_CharT*, streamsize __n) {
263  if (__n > 0) {
264    bool __do_get_area = false;
265    bool __do_put_area = false;
266    ptrdiff_t __offg = 0;
267    ptrdiff_t __offp = 0;
268
269    if (this->pbase() == _S_start(_M_str)) {
270      __do_put_area = true;
271      __offp = this->pptr() - this->pbase();
272    }
273
274    if (this->eback() == _S_start(_M_str)) {
275      __do_get_area = true;
276      __offg = this->gptr() - this->eback();
277    }
278
279    _M_str.reserve(sizeof(streamsize) > sizeof(size_t) ? __STATIC_CAST(size_t, (min)(__n, __STATIC_CAST(streamsize, _M_str.max_size())))
280                                                       : __STATIC_CAST(size_t, __n));
281
282    _CharT* __data_ptr = _S_start(_M_str);
283
284    if (__do_get_area) {
285      this->setg(__data_ptr, __data_ptr + __offg, _S_finish(_M_str));
286    }
287
288    if (__do_put_area) {
289      this->setp(__data_ptr, _S_finish(_M_str));
290      this->pbump((int)__offp);
291    }
292  }
293
294  return this;
295}
296
297template <class _CharT, class _Traits, class _Alloc>
298__BSB_pos_type__
299basic_stringbuf<_CharT, _Traits, _Alloc>
300  ::seekoff(off_type __off,
301            ios_base::seekdir __dir,
302            ios_base::openmode __mode) {
303  __mode &= _M_mode;
304
305  bool __imode  = (__mode & ios_base::in) != 0;
306  bool __omode = (__mode & ios_base::out) != 0;
307
308  if ( !(__imode || __omode) )
309    return pos_type(off_type(-1));
310
311  if ( (__imode && (this->gptr() == 0)) || (__omode && (this->pptr() == 0)) )
312    return pos_type(off_type(-1));
313
314  streamoff __newoff;
315  switch(__dir) {
316    case ios_base::beg:
317      __newoff = 0;
318      break;
319    case ios_base::end:
320      __newoff = _M_str.size();
321      break;
322    case ios_base::cur:
323      __newoff = __imode ? this->gptr() - this->eback() : this->pptr() - this->pbase();
324      if ( __off == 0 ) {
325        return pos_type(__newoff);
326      }
327      break;
328    default:
329      return pos_type(off_type(-1));
330  }
331
332  __off += __newoff;
333
334  if (__imode) {
335    ptrdiff_t __n = this->egptr() - this->eback();
336
337    if (__off < 0 || __off > __n)
338      return pos_type(off_type(-1));
339    this->setg(this->eback(), this->eback() + __STATIC_CAST(ptrdiff_t, __off),
340                              this->eback() + __STATIC_CAST(ptrdiff_t, __n));
341  }
342
343  if (__omode) {
344    ptrdiff_t __n = this->epptr() - this->pbase();
345
346    if (__off < 0 || __off > __n)
347      return pos_type(off_type(-1));
348    this->setp(this->pbase(), this->pbase() + __n);
349    this->pbump((int)__off);
350  }
351
352  return pos_type(__off);
353}
354
355template <class _CharT, class _Traits, class _Alloc>
356__BSB_pos_type__
357basic_stringbuf<_CharT, _Traits, _Alloc>
358  ::seekpos(pos_type __pos, ios_base::openmode __mode) {
359  __mode &= _M_mode;
360
361  bool __imode = (__mode & ios_base::in) != 0;
362  bool __omode = (__mode & ios_base::out) != 0;
363
364  if ( !(__imode || __omode) )
365    return pos_type(off_type(-1));
366
367  if ( (__imode && (this->gptr() == 0)) || (__omode && (this->pptr() == 0)) )
368    return pos_type(off_type(-1));
369
370  const off_type __n = __pos - pos_type(off_type(0));
371
372  if (__imode) {
373    if (__n < 0 || __n > this->egptr() - this->eback())
374      return pos_type(off_type(-1));
375    this->setg(this->eback(), this->eback() + __STATIC_CAST(ptrdiff_t, __n), this->egptr());
376  }
377
378  if (__omode) {
379    if (__n < 0 || size_t(__n) > _M_str.size())
380      return pos_type(off_type(-1));
381
382    this->setp(_S_start(_M_str), _S_finish(_M_str));
383    this->pbump((int)__n);
384  }
385
386  return __pos;
387}
388
389//----------------------------------------------------------------------
390// Non-inline istringstream member functions.
391
392template <class _CharT, class _Traits, class _Alloc>
393basic_istringstream<_CharT, _Traits, _Alloc>
394  ::basic_istringstream(ios_base::openmode __mode)
395    : basic_istream<_CharT, _Traits>(0),
396      _M_buf(__mode | ios_base::in) {
397  this->init(&_M_buf);
398}
399
400template <class _CharT, class _Traits, class _Alloc>
401basic_istringstream<_CharT, _Traits, _Alloc>
402  ::basic_istringstream(const _String& __str,ios_base::openmode __mode)
403    : basic_istream<_CharT, _Traits>(0),
404      _M_buf(__str, __mode | ios_base::in) {
405  this->init(&_M_buf);
406}
407
408template <class _CharT, class _Traits, class _Alloc>
409basic_istringstream<_CharT, _Traits, _Alloc>::~basic_istringstream()
410{}
411
412//----------------------------------------------------------------------
413// Non-inline ostringstream member functions.
414
415template <class _CharT, class _Traits, class _Alloc>
416basic_ostringstream<_CharT, _Traits, _Alloc>
417  ::basic_ostringstream(ios_base::openmode __mode)
418    : basic_ostream<_CharT, _Traits>(0),
419      _M_buf(__mode | ios_base::out) {
420  this->init(&_M_buf);
421}
422
423template <class _CharT, class _Traits, class _Alloc>
424basic_ostringstream<_CharT, _Traits, _Alloc>
425  ::basic_ostringstream(const _String& __str, ios_base::openmode __mode)
426    : basic_ostream<_CharT, _Traits>(0),
427      _M_buf(__str, __mode | ios_base::out) {
428  this->init(&_M_buf);
429}
430
431template <class _CharT, class _Traits, class _Alloc>
432basic_ostringstream<_CharT, _Traits, _Alloc>::~basic_ostringstream()
433{}
434
435//----------------------------------------------------------------------
436// Non-inline stringstream member functions.
437
438template <class _CharT, class _Traits, class _Alloc>
439basic_stringstream<_CharT, _Traits, _Alloc>
440  ::basic_stringstream(ios_base::openmode __mode)
441    : basic_iostream<_CharT, _Traits>(0), _M_buf(__mode) {
442   this->init(&_M_buf);
443}
444
445template <class _CharT, class _Traits, class _Alloc>
446basic_stringstream<_CharT, _Traits, _Alloc>
447  ::basic_stringstream(const _String& __str, ios_base::openmode __mode)
448    : basic_iostream<_CharT, _Traits>(0), _M_buf(__str, __mode) {
449  this->init(&_M_buf);
450}
451
452template <class _CharT, class _Traits, class _Alloc>
453basic_stringstream<_CharT, _Traits, _Alloc>::~basic_stringstream()
454{}
455
456_STLP_END_NAMESPACE
457
458# undef __BSB_int_type__
459# undef __BSB_pos_type__
460
461#endif /* _STLP_SSTREAM_C */
462
463// Local Variables:
464// mode:C++
465// End:
466