197403Sobrien// strstream definitions -*- C++ -*-
297403Sobrien
3169691Skan// Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation
497403Sobrien//
5103447Skan// This file is part of the GNU ISO C++ Library.  This library is free
6103447Skan// software; you can redistribute it and/or modify it under the
7103447Skan// terms of the GNU General Public License as published by the
8103447Skan// Free Software Foundation; either version 2, or (at your option)
997403Sobrien// any later version.
10103447Skan
11103447Skan// This library is distributed in the hope that it will be useful,
1297403Sobrien// but WITHOUT ANY WARRANTY; without even the implied warranty of
1397403Sobrien// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1497403Sobrien// GNU General Public License for more details.
1597403Sobrien
16103447Skan// You should have received a copy of the GNU General Public License along
17103447Skan// with this library; see the file COPYING.  If not, write to the Free
18169691Skan// Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
19103447Skan// USA.
20103447Skan
2197403Sobrien// As a special exception, you may use this file as part of a free software
2297403Sobrien// library without restriction.  Specifically, if other files instantiate
2397403Sobrien// templates or use macros or inline functions from this file, or you compile
2497403Sobrien// this file and link it with other files to produce an executable, this
2597403Sobrien// file does not by itself cause the resulting executable to be covered by
2697403Sobrien// the GNU General Public License.  This exception does not however
2797403Sobrien// invalidate any other reasons why the executable file might be covered by
2897403Sobrien// the GNU General Public License.
2997403Sobrien
3097403Sobrien/*
3197403Sobrien * Copyright (c) 1998
3297403Sobrien * Silicon Graphics Computer Systems, Inc.
3397403Sobrien *
3497403Sobrien * Permission to use, copy, modify, distribute and sell this software
3597403Sobrien * and its documentation for any purpose is hereby granted without fee,
3697403Sobrien * provided that the above copyright notice appear in all copies and
3797403Sobrien * that both that copyright notice and this permission notice appear
3897403Sobrien * in supporting documentation.  Silicon Graphics makes no
3997403Sobrien * representations about the suitability of this software for any
4097403Sobrien * purpose.  It is provided "as is" without express or implied warranty.
4197403Sobrien */
4297403Sobrien
4397403Sobrien// Implementation of the classes in header <strstream>.
4497403Sobrien// WARNING: The classes defined in <strstream> are DEPRECATED.  This
4597403Sobrien// header is defined in section D.7.1 of the C++ standard, and it
4697403Sobrien// MAY BE REMOVED in a future standard revision.  You should use the
4797403Sobrien// header <sstream> instead.
4897403Sobrien
49102782Skan#include <strstream>
5097403Sobrien#include <algorithm>
5197403Sobrien#include <new>
5297403Sobrien#include <stdlib.h>
5397403Sobrien#include <string.h>
5497403Sobrien#include <limits.h>
5597403Sobrien
56169691Skan_GLIBCXX_BEGIN_NAMESPACE(std)
57169691Skan
58102782Skan  strstreambuf::strstreambuf(streamsize initial_capacity)
59102782Skan  : _Base(), _M_alloc_fun(0), _M_free_fun(0), _M_dynamic(true),
60102782Skan    _M_frozen(false), _M_constant(false)
61102782Skan  {
62132720Skan    streamsize n = std::max(initial_capacity, streamsize(16));
63102782Skan
64102782Skan    char* buf = _M_alloc(n);
65102782Skan    if (buf)
66102782Skan      {
67102782Skan	setp(buf, buf + n);
68102782Skan	setg(buf, buf, buf);
69102782Skan      }
7097403Sobrien  }
7197403Sobrien
72102782Skan  strstreambuf::strstreambuf(void* (*alloc_f)(size_t), void (*free_f)(void*))
73102782Skan  : _Base(), _M_alloc_fun(alloc_f), _M_free_fun(free_f), _M_dynamic(true),
74102782Skan    _M_frozen(false), _M_constant(false)
75102782Skan  {
76102782Skan    streamsize n = 16;
7797403Sobrien
78102782Skan    char* buf = _M_alloc(n);
79102782Skan    if (buf)
80102782Skan      {
81102782Skan	setp(buf, buf + n);
82102782Skan	setg(buf, buf, buf);
83102782Skan      }
8497403Sobrien  }
8597403Sobrien
86102782Skan  strstreambuf::strstreambuf(char* get, streamsize n, char* put)
87102782Skan  : _Base(), _M_alloc_fun(0), _M_free_fun(0), _M_dynamic(false),
88102782Skan    _M_frozen(false), _M_constant(false)
89102782Skan  { _M_setup(get, put, n); }
9097403Sobrien
91102782Skan  strstreambuf::strstreambuf(signed char* get, streamsize n, signed char* put)
92102782Skan  : _Base(), _M_alloc_fun(0), _M_free_fun(0), _M_dynamic(false),
93102782Skan  _M_frozen(false), _M_constant(false)
94102782Skan  { _M_setup(reinterpret_cast<char*>(get), reinterpret_cast<char*>(put), n); }
9597403Sobrien
96102782Skan  strstreambuf::strstreambuf(unsigned char* get, streamsize n,
97102782Skan			     unsigned char* put)
98102782Skan  : _Base(), _M_alloc_fun(0), _M_free_fun(0), _M_dynamic(false),
99102782Skan    _M_frozen(false), _M_constant(false)
100102782Skan  { _M_setup(reinterpret_cast<char*>(get), reinterpret_cast<char*>(put), n); }
10197403Sobrien
102102782Skan  strstreambuf::strstreambuf(const char* get, streamsize n)
103102782Skan  : _Base(), _M_alloc_fun(0), _M_free_fun(0), _M_dynamic(false),
104102782Skan    _M_frozen(false), _M_constant(true)
105102782Skan  { _M_setup(const_cast<char*>(get), 0, n); }
10697403Sobrien
107102782Skan  strstreambuf::strstreambuf(const signed char* get, streamsize n)
108102782Skan  : _Base(), _M_alloc_fun(0), _M_free_fun(0), _M_dynamic(false),
109102782Skan    _M_frozen(false), _M_constant(true)
110102782Skan  { _M_setup(reinterpret_cast<char*>(const_cast<signed char*>(get)), 0, n); }
11197403Sobrien
112102782Skan  strstreambuf::strstreambuf(const unsigned char* get, streamsize n)
113102782Skan  : _Base(), _M_alloc_fun(0), _M_free_fun(0), _M_dynamic(false),
114102782Skan    _M_frozen(false), _M_constant(true)
115102782Skan  { _M_setup(reinterpret_cast<char*>(const_cast<unsigned char*>(get)), 0, n); }
11697403Sobrien
117102782Skan  strstreambuf::~strstreambuf()
118102782Skan  {
119102782Skan    if (_M_dynamic && !_M_frozen)
120102782Skan      _M_free(eback());
121102782Skan  }
12297403Sobrien
123102782Skan  void
124102782Skan  strstreambuf::freeze(bool frozenflag)
125102782Skan  {
126102782Skan    if (_M_dynamic)
127102782Skan      _M_frozen = frozenflag;
128102782Skan  }
12997403Sobrien
130102782Skan  char*
131102782Skan  strstreambuf::str()
132102782Skan  {
133102782Skan    freeze(true);
134102782Skan    return eback();
135102782Skan  }
13697403Sobrien
137102782Skan  int
138102782Skan  strstreambuf::pcount() const
139102782Skan  { return pptr() ? pptr() - pbase() : 0; }
14097403Sobrien
141102782Skan  strstreambuf::int_type
142102782Skan  strstreambuf::overflow(int_type c)
143102782Skan  {
144102782Skan    if (c == traits_type::eof())
145102782Skan      return traits_type::not_eof(c);
146102782Skan
147102782Skan    // Try to expand the buffer.
148102782Skan    if (pptr() == epptr() && _M_dynamic && !_M_frozen && !_M_constant)
149102782Skan      {
150102782Skan	ptrdiff_t old_size = epptr() - pbase();
151132720Skan	ptrdiff_t new_size = std::max(ptrdiff_t(2 * old_size), ptrdiff_t(1));
152102782Skan
153102782Skan	char* buf = _M_alloc(new_size);
154102782Skan	if (buf)
155102782Skan	  {
156102782Skan	    memcpy(buf, pbase(), old_size);
157102782Skan	    char* old_buffer = pbase();
158102782Skan	    bool reposition_get = false;
159102782Skan	    ptrdiff_t old_get_offset;
160102782Skan	    if (gptr() != 0)
161102782Skan	      {
162102782Skan		reposition_get = true;
163102782Skan		old_get_offset = gptr() - eback();
164102782Skan	      }
165102782Skan
166102782Skan	    setp(buf, buf + new_size);
167102782Skan	    pbump(old_size);
16897403Sobrien
169102782Skan	    if (reposition_get)
170102782Skan	      setg(buf, buf + old_get_offset, buf +
171132720Skan		   std::max(old_get_offset, old_size));
17297403Sobrien
173102782Skan	    _M_free(old_buffer);
174102782Skan	  }
17597403Sobrien      }
176102782Skan
177102782Skan    if (pptr() != epptr())
178102782Skan      {
179102782Skan	*pptr() = c;
180102782Skan	pbump(1);
181102782Skan	return c;
182102782Skan      }
183102782Skan    else
184102782Skan      return traits_type::eof();
185102782Skan  }
18697403Sobrien
187102782Skan  strstreambuf::int_type
188102782Skan  strstreambuf::pbackfail(int_type c)
189102782Skan  {
190102782Skan    if (gptr() != eback())
191102782Skan      {
192102782Skan      if (c == _Traits::eof())
193102782Skan	{
194102782Skan	  gbump(-1);
195102782Skan	  return _Traits::not_eof(c);
196102782Skan	}
197132720Skan      else if (c == _Traits::to_int_type(gptr()[-1]))
198102782Skan	{  // KLUDGE
199102782Skan	  gbump(-1);
200102782Skan	  return c;
201102782Skan	}
202102782Skan      else if (!_M_constant)
203102782Skan	{
204102782Skan	  gbump(-1);
205102782Skan	  *gptr() = c;
206102782Skan	  return c;
207102782Skan	}
20897403Sobrien    }
209102782Skan    return _Traits::eof();
21097403Sobrien  }
21197403Sobrien
212102782Skan  strstreambuf::int_type
213102782Skan  strstreambuf::underflow()
214102782Skan  {
215102782Skan    if (gptr() == egptr() && pptr() && pptr() > egptr())
216102782Skan      setg(eback(), gptr(), pptr());
217102782Skan
218102782Skan    if (gptr() != egptr())
219102782Skan      return (unsigned char) *gptr();
220102782Skan    else
221102782Skan      return _Traits::eof();
22297403Sobrien  }
22397403Sobrien
224102782Skan  basic_streambuf<char, char_traits<char> >*
225102782Skan  strstreambuf::setbuf(char*, streamsize)
226102782Skan  { return this; }
22797403Sobrien
228102782Skan  strstreambuf::pos_type
229102782Skan  strstreambuf::seekoff(off_type off, ios_base::seekdir dir,
230102782Skan			ios_base::openmode mode)
231102782Skan  {
232102782Skan    bool do_get = false;
233102782Skan    bool do_put = false;
23497403Sobrien
235102782Skan    if ((mode & (ios_base::in | ios_base::out))
236102782Skan	== (ios_base::in | ios_base::out) &&
237102782Skan	(dir == ios_base::beg || dir == ios_base::end))
238102782Skan      do_get = do_put = true;
239102782Skan    else if (mode & ios_base::in)
240102782Skan      do_get = true;
241102782Skan    else if (mode & ios_base::out)
242102782Skan      do_put = true;
24397403Sobrien
244102782Skan    // !gptr() is here because, according to D.7.1 paragraph 4, the seekable
245102782Skan    // area is undefined if there is no get area.
246102782Skan    if ((!do_get && !do_put) || (do_put && !pptr()) || !gptr())
247102782Skan      return pos_type(off_type(-1));
24897403Sobrien
249102782Skan    char* seeklow  = eback();
250102782Skan    char* seekhigh = epptr() ? epptr() : egptr();
25197403Sobrien
252102782Skan    off_type newoff;
253102782Skan    switch (dir)
254102782Skan      {
255102782Skan      case ios_base::beg:
256102782Skan	newoff = 0;
257102782Skan	break;
258102782Skan      case ios_base::end:
259102782Skan	newoff = seekhigh - seeklow;
260102782Skan	break;
261102782Skan      case ios_base::cur:
262102782Skan	newoff = do_put ? pptr() - seeklow : gptr() - seeklow;
263102782Skan	break;
264102782Skan      default:
265102782Skan	return pos_type(off_type(-1));
266102782Skan      }
267102782Skan
268102782Skan    off += newoff;
269102782Skan    if (off < 0 || off > seekhigh - seeklow)
270102782Skan      return pos_type(off_type(-1));
27197403Sobrien
272102782Skan    if (do_put)
273102782Skan      {
274102782Skan	if (seeklow + off < pbase())
275102782Skan	  {
276102782Skan	    setp(seeklow, epptr());
277102782Skan	    pbump(off);
278102782Skan	  }
279102782Skan	else
280102782Skan	  {
281102782Skan	    setp(pbase(), epptr());
282102782Skan	    pbump(off - (pbase() - seeklow));
283102782Skan	  }
284102782Skan      }
285102782Skan    if (do_get)
286102782Skan      {
287102782Skan	if (off <= egptr() - seeklow)
288102782Skan	  setg(seeklow, seeklow + off, egptr());
289102782Skan	else if (off <= pptr() - seeklow)
290102782Skan	  setg(seeklow, seeklow + off, pptr());
291102782Skan	else
292102782Skan	  setg(seeklow, seeklow + off, epptr());
293102782Skan      }
294102782Skan    return pos_type(newoff);
29597403Sobrien  }
29697403Sobrien
297102782Skan  strstreambuf::pos_type
298102782Skan  strstreambuf::seekpos(pos_type pos, ios_base::openmode mode)
299102782Skan  { return seekoff(pos - pos_type(off_type(0)), ios_base::beg, mode); }
30097403Sobrien
301102782Skan  char*
302102782Skan  strstreambuf::_M_alloc(size_t n)
303102782Skan  {
304102782Skan    if (_M_alloc_fun)
305102782Skan      return static_cast<char*>(_M_alloc_fun(n));
30697403Sobrien    else
307102782Skan      return new char[n];
30897403Sobrien  }
30997403Sobrien
310102782Skan  void
311102782Skan  strstreambuf::_M_free(char* p)
312102782Skan  {
313102782Skan    if (p)
314242347Sdim      {
315242347Sdim	if (_M_free_fun)
316242347Sdim	  _M_free_fun(p);
317242347Sdim	else
318242347Sdim	  delete[] p;
319242347Sdim      }
320102782Skan  }
32197403Sobrien
322102782Skan  void
323102782Skan  strstreambuf::_M_setup(char* get, char* put, streamsize n)
324102782Skan  {
325102782Skan    if (get)
326102782Skan      {
327102782Skan	size_t N = n > 0 ? size_t(n) : n == 0 ? strlen(get) : size_t(INT_MAX);
328102782Skan
329102782Skan	if (put)
330102782Skan	  {
331102782Skan	    setg(get, get, put);
332102782Skan	    setp(put, put + N);
333102782Skan	  }
334102782Skan	else
335102782Skan	  setg(get, get, get + N);
336102782Skan      }
33797403Sobrien  }
33897403Sobrien
339102782Skan  istrstream::istrstream(char* s)
34097403Sobrien  : basic_ios<char>(), basic_istream<char>(0), _M_buf(s, 0)
341102782Skan  { basic_ios<char>::init(&_M_buf); }
34297403Sobrien
343102782Skan  istrstream::istrstream(const char* s)
34497403Sobrien  : basic_ios<char>(), basic_istream<char>(0), _M_buf(s, 0)
345102782Skan  { basic_ios<char>::init(&_M_buf); }
34697403Sobrien
347102782Skan  istrstream::istrstream(char* s, streamsize n)
34897403Sobrien  : basic_ios<char>(), basic_istream<char>(0), _M_buf(s, n)
349102782Skan  { basic_ios<char>::init(&_M_buf); }
35097403Sobrien
351102782Skan  istrstream::istrstream(const char* s, streamsize n)
35297403Sobrien  : basic_ios<char>(), basic_istream<char>(0), _M_buf(s, n)
353102782Skan  { basic_ios<char>::init(&_M_buf); }
35497403Sobrien
355102782Skan  istrstream::~istrstream() { }
35697403Sobrien
357102782Skan  strstreambuf*
358102782Skan  istrstream::rdbuf() const
359102782Skan  { return const_cast<strstreambuf*>(&_M_buf); }
36097403Sobrien
361102782Skan  char*
362102782Skan  istrstream::str()
363102782Skan  { return _M_buf.str(); }
36497403Sobrien
365102782Skan  ostrstream::ostrstream()
36697403Sobrien  : basic_ios<char>(), basic_ostream<char>(0), _M_buf()
367102782Skan  { basic_ios<char>::init(&_M_buf); }
36897403Sobrien
369102782Skan  ostrstream::ostrstream(char* s, int n, ios_base::openmode mode)
370102782Skan  : basic_ios<char>(), basic_ostream<char>(0),
37197403Sobrien    _M_buf(s, n, mode & ios_base::app ? s + strlen(s) : s)
372102782Skan  { basic_ios<char>::init(&_M_buf); }
37397403Sobrien
374102782Skan  ostrstream::~ostrstream() {}
37597403Sobrien
376102782Skan  strstreambuf*
377102782Skan  ostrstream::rdbuf() const
378102782Skan  { return const_cast<strstreambuf*>(&_M_buf); }
37997403Sobrien
380102782Skan  void
381102782Skan  ostrstream::freeze(bool freezeflag)
382102782Skan  { _M_buf.freeze(freezeflag); }
38397403Sobrien
384102782Skan  char*
385102782Skan  ostrstream::str()
386102782Skan  { return _M_buf.str(); }
38797403Sobrien
388102782Skan  int
389102782Skan  ostrstream::pcount() const
390102782Skan  { return _M_buf.pcount(); }
39197403Sobrien
392102782Skan  strstream::strstream()
39397403Sobrien  : basic_ios<char>(), basic_iostream<char>(0), _M_buf()
394102782Skan  { basic_ios<char>::init(&_M_buf); }
39597403Sobrien
396102782Skan  strstream::strstream(char* s, int n, ios_base::openmode mode)
397102782Skan  : basic_ios<char>(), basic_iostream<char>(0),
39897403Sobrien    _M_buf(s, n, mode & ios_base::app ? s + strlen(s) : s)
399102782Skan  { basic_ios<char>::init(&_M_buf); }
40097403Sobrien
401102782Skan  strstream::~strstream() { }
40297403Sobrien
403102782Skan  strstreambuf*
404102782Skan  strstream::rdbuf() const
405102782Skan  { return const_cast<strstreambuf*>(&_M_buf); }
40697403Sobrien
407102782Skan  void
408102782Skan  strstream::freeze(bool freezeflag)
409102782Skan  { _M_buf.freeze(freezeflag); }
41097403Sobrien
411102782Skan  int
412102782Skan  strstream::pcount() const
413102782Skan  { return _M_buf.pcount(); }
41497403Sobrien
415102782Skan  char*
416102782Skan  strstream::str()
417102782Skan  { return _M_buf.str(); }
418169691Skan
419169691Skan_GLIBCXX_END_NAMESPACE
420