1/* This is part of libio/iostream, providing -*- C++ -*- input/output.
2Copyright (C) 2000 Free Software Foundation
3
4This file is part of the GNU IO Library.  This library is free
5software; you can redistribute it and/or modify it under the
6terms of the GNU General Public License as published by the
7Free Software Foundation; either version 2, or (at your option)
8any later version.
9
10This library is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this library; see the file COPYING.  If not, write to the Free
17Software Foundation, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19As a special exception, if you link this library with files
20compiled with a GNU compiler to produce an executable, this does not cause
21the resulting executable to be covered by the GNU General Public License.
22This exception does not however invalidate any other reasons why
23the executable file might be covered by the GNU General Public License. */
24
25/* Written by Magnus Fromreide (magfr@lysator.liu.se). */
26/* seekoff and ideas for overflow is largely borrowed from libstdc++-v3 */
27
28#ifndef __SSTREAM__
29#define __SSTREAM__
30
31#include <iostream.h>
32#include <streambuf.h>
33#include <string>
34
35namespace std
36{
37  class stringbuf : public streambuf
38  {
39  public:
40    typedef char	char_type;
41    typedef int		int_type;
42    typedef streampos	pos_type;
43    typedef streamoff	off_type;
44
45    explicit
46    stringbuf(int which=ios::in|ios::out)
47      : streambuf(), mode(static_cast<ios::open_mode>(which)),
48	stream(NULL), stream_len(0)
49    {
50      stringbuf_init();
51    }
52
53    explicit
54    stringbuf(const string &str, int which=ios::in|ios::out)
55      : streambuf(), mode(static_cast<ios::open_mode>(which)),
56	stream(NULL), stream_len(0)
57    {
58      if (mode & (ios::in|ios::out))
59	{
60	  stream_len = str.size();
61	  stream = new char_type[stream_len];
62	  str.copy(stream, stream_len);
63	}
64      stringbuf_init();
65    }
66
67    virtual
68    ~stringbuf()
69    {
70      delete[] stream;
71    }
72
73    string
74    str() const
75    {
76      if (pbase() != 0)
77	return string(stream, pptr()-pbase());
78      else
79	return string();
80    }
81
82    void
83    str(const string& str)
84    {
85      delete[] stream;
86      stream_len = str.size();
87      stream = new char_type[stream_len];
88      str.copy(stream, stream_len);
89      stringbuf_init();
90    }
91
92  protected:
93    // The buffer is already in gptr, so if it ends then it is out of data.
94    virtual int
95    underflow()
96    {
97      return EOF;
98    }
99
100    virtual int
101    overflow(int c = EOF)
102    {
103      int res;
104      if (mode & ios::out)
105	{
106	  if (c != EOF)
107	    {
108	      streamsize old_stream_len = stream_len;
109	      stream_len += 1;
110	      char_type* new_stream = new char_type[stream_len];
111	      memcpy(new_stream, stream, old_stream_len);
112	      delete[] stream;
113	      stream = new_stream;
114	      stringbuf_sync(gptr()-eback(), pptr()-pbase());
115	      sputc(c);
116	      res = c;
117	    }
118	  else
119	    res = EOF;
120	}
121      else
122	res = 0;
123      return res;
124    }
125
126    virtual streambuf*
127    setbuf(char_type* s, streamsize n)
128    {
129      if (n != 0)
130	{
131	  delete[] stream;
132	  stream = new char_type[n];
133	  memcpy(stream, s, n);
134	  stream_len = n;
135	  stringbuf_sync(0, 0);
136	}
137      return this;
138    }
139
140    virtual pos_type
141    seekoff(off_type off, ios::seek_dir way, int which = ios::in | ios::out)
142    {
143      pos_type ret =  pos_type(off_type(-1));
144      bool testin = which & ios::in && mode & ios::in;
145      bool testout = which & ios::out && mode & ios::out;
146      bool testboth = testin && testout && way != ios::cur;
147
148      if (stream_len && ((testin != testout) || testboth))
149	{
150	  char_type* beg = stream;
151	  char_type* curi = NULL;
152	  char_type* curo = NULL;
153	  char_type* endi = NULL;
154	  char_type* endo = NULL;
155
156	  if (testin)
157	    {
158	      curi = gptr();
159	      endi = egptr();
160	    }
161	  if (testout)
162	    {
163	      curo = pptr();
164	      endo = epptr();
165	    }
166
167	  off_type newoffi = 0;
168	  off_type newoffo = 0;
169	  if (way == ios::beg)
170	    {
171	      newoffi = beg - curi;
172	      newoffo = beg - curo;
173	    }
174	  else if (way == ios::end)
175	    {
176	      newoffi = endi - curi;
177	      newoffo = endo - curo;
178	    }
179
180	  if (testin && newoffi + off + curi - beg >= 0 &&
181	      endi - beg >= newoffi + off + curi - beg)
182	    {
183	      gbump(newoffi + off);
184	      ret = pos_type(newoffi + off + curi);
185	    }
186	  if (testout && newoffo + off + curo - beg >= 0 &&
187	      endo - beg >= newoffo + off + curo - beg)
188	    {
189	      pbump(newoffo + off);
190	      ret = pos_type(newoffo + off + curo);
191	    }
192	}
193      return ret;
194    }
195
196    virtual pos_type
197    seekpos(pos_type sp, int which = ios::in | ios::out)
198    {
199      pos_type ret = seekoff(sp, ios::beg, which);
200      return ret;
201    }
202
203  private:
204    void
205    stringbuf_sync(streamsize i, streamsize o)
206    {
207      if (mode & ios::in)
208	setg(stream, stream + i, stream + stream_len);
209      if (mode & ios::out)
210	{
211	  setp(stream, stream + stream_len);
212	  pbump(o);
213	}
214    }
215    void
216    stringbuf_init()
217    {
218      if (mode & ios::ate)
219	stringbuf_sync(0, stream_len);
220      else
221	stringbuf_sync(0, 0);
222    }
223
224  private:
225    ios::open_mode	mode;
226    char_type*		stream;
227    streamsize		stream_len;
228  };
229
230  class istringstream : public istream {
231  public:
232    typedef char	char_type;
233    typedef int		int_type;
234    typedef streampos	pos_type;
235    typedef streamoff	off_type;
236
237    explicit
238    istringstream(int which=ios::in)
239      : istream(&sb), sb(which | ios::in)
240    { }
241
242    explicit
243    istringstream(const string& str, int which=ios::in)
244      : istream(&sb), sb(str, which | ios::in)
245    { }
246
247    stringbuf*
248    rdbuf() const
249    {
250      return const_cast<stringbuf*>(&sb);
251    }
252
253    string
254    str() const
255    {
256      return rdbuf()->str();
257    }
258    void
259    str(const string& s)
260    {
261      rdbuf()->str(s);
262    }
263  private:
264    stringbuf sb;
265  };
266
267  class ostringstream : public ostream {
268  public:
269    typedef char	char_type;
270    typedef int		int_type;
271    typedef streampos	pos_type;
272    typedef streamoff	off_type;
273
274    explicit
275    ostringstream(int which=ios::out)
276      : ostream(&sb), sb(which | ios::out)
277    { }
278
279    explicit
280    ostringstream(const string& str, int which=ios::out)
281      : ostream(&sb), sb(str, which | ios::out)
282    { }
283
284    stringbuf*
285    rdbuf() const
286    {
287      return const_cast<stringbuf*>(&sb);
288    }
289
290    string
291    str() const
292    {
293      return rdbuf()->str();
294    }
295
296    void str(const string& s)
297    {
298      rdbuf()->str(s);
299    }
300  private:
301    stringbuf sb;
302  };
303
304  class stringstream : public iostream {
305  public:
306    typedef char	char_type;
307    typedef int		int_type;
308    typedef streampos	pos_type;
309    typedef streamoff	off_type;
310
311    explicit
312    stringstream(int which=ios::out|ios::in)
313      : iostream(&sb), sb(which)
314    { }
315
316    explicit
317    stringstream(const string& str, int which=ios::out|ios::in)
318      : iostream(&sb), sb(str, which)
319    { }
320
321    stringbuf*
322    rdbuf() const
323    {
324      return const_cast<stringbuf*>(&sb);
325    }
326
327    string
328    str() const
329    {
330      return rdbuf()->str();
331    }
332
333    void
334    str(const string& s)
335    {
336      rdbuf()->str(s);
337    }
338  private:
339    stringbuf sb;
340  };
341};
342
343#endif /* not __STRSTREAM__ */
344