1//===------------------------ strstream.cpp -------------------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is dual licensed under the MIT and the University of Illinois Open
6// Source Licenses. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "strstream"
11#include "algorithm"
12#include "climits"
13#include "cstring"
14
15_LIBCPP_BEGIN_NAMESPACE_STD
16
17strstreambuf::strstreambuf(streamsize __alsize)
18    : __strmode_(__dynamic),
19      __alsize_(__alsize),
20      __palloc_(nullptr),
21      __pfree_(nullptr)
22{
23}
24
25strstreambuf::strstreambuf(void* (*__palloc)(size_t), void (*__pfree)(void*))
26    : __strmode_(__dynamic),
27      __alsize_(__default_alsize),
28      __palloc_(__palloc),
29      __pfree_(__pfree)
30{
31}
32
33void
34strstreambuf::__init(char* __gnext, streamsize __n, char* __pbeg)
35{
36    if (__n == 0)
37        __n = static_cast<streamsize>(strlen(__gnext));
38    else if (__n < 0)
39        __n = INT_MAX;
40    if (__pbeg == nullptr)
41        setg(__gnext, __gnext, __gnext + __n);
42    else
43    {
44        setg(__gnext, __gnext, __pbeg);
45        setp(__pbeg, __pbeg + __n);
46    }
47}
48
49strstreambuf::strstreambuf(char* __gnext, streamsize __n, char* __pbeg)
50    : __strmode_(),
51      __alsize_(__default_alsize),
52      __palloc_(nullptr),
53      __pfree_(nullptr)
54{
55    __init(__gnext, __n, __pbeg);
56}
57
58strstreambuf::strstreambuf(const char* __gnext, streamsize __n)
59    : __strmode_(__constant),
60      __alsize_(__default_alsize),
61      __palloc_(nullptr),
62      __pfree_(nullptr)
63{
64    __init(const_cast<char *>(__gnext), __n, nullptr);
65}
66
67strstreambuf::strstreambuf(signed char* __gnext, streamsize __n, signed char* __pbeg)
68    : __strmode_(),
69      __alsize_(__default_alsize),
70      __palloc_(nullptr),
71      __pfree_(nullptr)
72{
73    __init(const_cast<char *>(reinterpret_cast<const char*>(__gnext)), __n, reinterpret_cast<char*>(__pbeg));
74}
75
76strstreambuf::strstreambuf(const signed char* __gnext, streamsize __n)
77    : __strmode_(__constant),
78      __alsize_(__default_alsize),
79      __palloc_(nullptr),
80      __pfree_(nullptr)
81{
82    __init(const_cast<char *>(reinterpret_cast<const char*>(__gnext)), __n, nullptr);
83}
84
85strstreambuf::strstreambuf(unsigned char* __gnext, streamsize __n, unsigned char* __pbeg)
86    : __strmode_(),
87      __alsize_(__default_alsize),
88      __palloc_(nullptr),
89      __pfree_(nullptr)
90{
91    __init(const_cast<char *>(reinterpret_cast<const char*>(__gnext)), __n, reinterpret_cast<char*>(__pbeg));
92}
93
94strstreambuf::strstreambuf(const unsigned char* __gnext, streamsize __n)
95    : __strmode_(__constant),
96      __alsize_(__default_alsize),
97      __palloc_(nullptr),
98      __pfree_(nullptr)
99{
100    __init(const_cast<char *>(reinterpret_cast<const char*>(__gnext)), __n, nullptr);
101}
102
103strstreambuf::~strstreambuf()
104{
105    if (eback() && (__strmode_ & __allocated) != 0 && (__strmode_ & __frozen) == 0)
106    {
107        if (__pfree_)
108            __pfree_(eback());
109        else
110            delete [] eback();
111    }
112}
113
114void
115strstreambuf::swap(strstreambuf& __rhs)
116{
117    streambuf::swap(__rhs);
118    _VSTD::swap(__strmode_, __rhs.__strmode_);
119    _VSTD::swap(__alsize_, __rhs.__alsize_);
120    _VSTD::swap(__palloc_, __rhs.__palloc_);
121    _VSTD::swap(__pfree_, __rhs.__pfree_);
122}
123
124void
125strstreambuf::freeze(bool __freezefl)
126{
127    if (__strmode_ & __dynamic)
128    {
129        if (__freezefl)
130            __strmode_ |= __frozen;
131        else
132            __strmode_ &= ~__frozen;
133    }
134}
135
136char*
137strstreambuf::str()
138{
139    if (__strmode_ & __dynamic)
140        __strmode_ |= __frozen;
141    return eback();
142}
143
144int
145strstreambuf::pcount() const
146{
147    return static_cast<int>(pptr() - pbase());
148}
149
150strstreambuf::int_type
151strstreambuf::overflow(int_type __c)
152{
153    if (__c == EOF)
154        return int_type(0);
155    if (pptr() == epptr())
156    {
157        if ((__strmode_ & __dynamic) == 0 || (__strmode_ & __frozen) != 0)
158            return int_type(EOF);
159        size_t old_size = static_cast<size_t> ((epptr() ? epptr() : egptr()) - eback());
160        size_t new_size = max<size_t>(static_cast<size_t>(__alsize_), 2*old_size);
161        if (new_size == 0)
162            new_size = __default_alsize;
163        char* buf = nullptr;
164        if (__palloc_)
165            buf = static_cast<char*>(__palloc_(new_size));
166        else
167            buf = new char[new_size];
168        if (buf == nullptr)
169            return int_type(EOF);
170        memcpy(buf, eback(), static_cast<size_t>(old_size));
171        ptrdiff_t ninp = gptr()  - eback();
172        ptrdiff_t einp = egptr() - eback();
173        ptrdiff_t nout = pptr()  - pbase();
174        ptrdiff_t eout = epptr() - pbase();
175        if (__strmode_ & __allocated)
176        {
177            if (__pfree_)
178                __pfree_(eback());
179            else
180                delete [] eback();
181        }
182        setg(buf, buf + ninp, buf + einp);
183        setp(buf + einp, buf + einp + eout);
184        pbump(static_cast<int>(nout));
185        __strmode_ |= __allocated;
186    }
187    *pptr() = static_cast<char>(__c);
188    pbump(1);
189    return int_type(static_cast<unsigned char>(__c));
190}
191
192strstreambuf::int_type
193strstreambuf::pbackfail(int_type __c)
194{
195    if (eback() == gptr())
196        return EOF;
197    if (__c == EOF)
198    {
199        gbump(-1);
200        return int_type(0);
201    }
202    if (__strmode_ & __constant)
203    {
204        if (gptr()[-1] == static_cast<char>(__c))
205        {
206            gbump(-1);
207            return __c;
208        }
209        return EOF;
210    }
211    gbump(-1);
212    *gptr() = static_cast<char>(__c);
213    return __c;
214}
215
216strstreambuf::int_type
217strstreambuf::underflow()
218{
219    if (gptr() == egptr())
220    {
221        if (egptr() >= pptr())
222            return EOF;
223        setg(eback(), gptr(), pptr());
224    }
225    return int_type(static_cast<unsigned char>(*gptr()));
226}
227
228strstreambuf::pos_type
229strstreambuf::seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode __which)
230{
231    off_type __p(-1);
232    bool pos_in = (__which & ios::in) != 0;
233    bool pos_out = (__which & ios::out) != 0;
234    bool legal = false;
235    switch (__way)
236    {
237    case ios::beg:
238    case ios::end:
239        if (pos_in || pos_out)
240            legal = true;
241        break;
242    case ios::cur:
243        if (pos_in != pos_out)
244            legal = true;
245        break;
246    }
247    if (pos_in && gptr() == nullptr)
248        legal = false;
249    if (pos_out && pptr() == nullptr)
250        legal = false;
251    if (legal)
252    {
253        off_type newoff;
254        char* seekhigh = epptr() ? epptr() : egptr();
255        switch (__way)
256        {
257        case ios::beg:
258            newoff = 0;
259            break;
260        case ios::cur:
261            newoff = (pos_in ? gptr() : pptr()) - eback();
262            break;
263        case ios::end:
264            newoff = seekhigh - eback();
265            break;
266        }
267        newoff += __off;
268        if (0 <= newoff && newoff <= seekhigh - eback())
269        {
270            char* newpos = eback() + newoff;
271            if (pos_in)
272                setg(eback(), newpos, _VSTD::max(newpos, egptr()));
273            if (pos_out)
274            {
275                // min(pbase, newpos), newpos, epptr()
276                __off = epptr() - newpos;
277                setp(min(pbase(), newpos), epptr());
278                pbump(static_cast<int>((epptr() - pbase()) - __off));
279            }
280            __p = newoff;
281        }
282    }
283    return pos_type(__p);
284}
285
286strstreambuf::pos_type
287strstreambuf::seekpos(pos_type __sp, ios_base::openmode __which)
288{
289    off_type __p(-1);
290    bool pos_in = (__which & ios::in) != 0;
291    bool pos_out = (__which & ios::out) != 0;
292    if (pos_in || pos_out)
293    {
294        if (!((pos_in && gptr() == nullptr) || (pos_out && pptr() == nullptr)))
295        {
296            off_type newoff = __sp;
297            char* seekhigh = epptr() ? epptr() : egptr();
298            if (0 <= newoff && newoff <= seekhigh - eback())
299            {
300                char* newpos = eback() + newoff;
301                if (pos_in)
302                    setg(eback(), newpos, _VSTD::max(newpos, egptr()));
303                if (pos_out)
304                {
305                    // min(pbase, newpos), newpos, epptr()
306                    off_type temp = epptr() - newpos;
307                    setp(min(pbase(), newpos), epptr());
308                    pbump(static_cast<int>((epptr() - pbase()) - temp));
309                }
310                __p = newoff;
311            }
312        }
313    }
314    return pos_type(__p);
315}
316
317istrstream::~istrstream()
318{
319}
320
321ostrstream::~ostrstream()
322{
323}
324
325strstream::~strstream()
326{
327}
328
329_LIBCPP_END_NAMESPACE_STD
330