1227825Stheraven//===------------------------ strstream.cpp -------------------------------===//
2227825Stheraven//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6227825Stheraven//
7227825Stheraven//===----------------------------------------------------------------------===//
8227825Stheraven
9227825Stheraven#include "strstream"
10227825Stheraven#include "algorithm"
11227825Stheraven#include "climits"
12227825Stheraven#include "cstring"
13314564Sdim#include "cstdlib"
14309124Sdim#include "__debug"
15321369Sdim#include "__undef_macros"
16227825Stheraven
17227825Stheraven_LIBCPP_BEGIN_NAMESPACE_STD
18227825Stheraven
19227825Stheravenstrstreambuf::strstreambuf(streamsize __alsize)
20227825Stheraven    : __strmode_(__dynamic),
21227825Stheraven      __alsize_(__alsize),
22227825Stheraven      __palloc_(nullptr),
23227825Stheraven      __pfree_(nullptr)
24227825Stheraven{
25227825Stheraven}
26227825Stheraven
27227825Stheravenstrstreambuf::strstreambuf(void* (*__palloc)(size_t), void (*__pfree)(void*))
28227825Stheraven    : __strmode_(__dynamic),
29227825Stheraven      __alsize_(__default_alsize),
30227825Stheraven      __palloc_(__palloc),
31227825Stheraven      __pfree_(__pfree)
32227825Stheraven{
33227825Stheraven}
34227825Stheraven
35227825Stheravenvoid
36227825Stheravenstrstreambuf::__init(char* __gnext, streamsize __n, char* __pbeg)
37227825Stheraven{
38227825Stheraven    if (__n == 0)
39232924Stheraven        __n = static_cast<streamsize>(strlen(__gnext));
40227825Stheraven    else if (__n < 0)
41227825Stheraven        __n = INT_MAX;
42227825Stheraven    if (__pbeg == nullptr)
43227825Stheraven        setg(__gnext, __gnext, __gnext + __n);
44227825Stheraven    else
45227825Stheraven    {
46227825Stheraven        setg(__gnext, __gnext, __pbeg);
47227825Stheraven        setp(__pbeg, __pbeg + __n);
48227825Stheraven    }
49227825Stheraven}
50227825Stheraven
51227825Stheravenstrstreambuf::strstreambuf(char* __gnext, streamsize __n, char* __pbeg)
52227825Stheraven    : __strmode_(),
53227825Stheraven      __alsize_(__default_alsize),
54227825Stheraven      __palloc_(nullptr),
55227825Stheraven      __pfree_(nullptr)
56227825Stheraven{
57227825Stheraven    __init(__gnext, __n, __pbeg);
58227825Stheraven}
59227825Stheraven
60227825Stheravenstrstreambuf::strstreambuf(const char* __gnext, streamsize __n)
61227825Stheraven    : __strmode_(__constant),
62227825Stheraven      __alsize_(__default_alsize),
63227825Stheraven      __palloc_(nullptr),
64227825Stheraven      __pfree_(nullptr)
65227825Stheraven{
66276792Sdim    __init(const_cast<char *>(__gnext), __n, nullptr);
67227825Stheraven}
68227825Stheraven
69227825Stheravenstrstreambuf::strstreambuf(signed char* __gnext, streamsize __n, signed char* __pbeg)
70227825Stheraven    : __strmode_(),
71227825Stheraven      __alsize_(__default_alsize),
72227825Stheraven      __palloc_(nullptr),
73227825Stheraven      __pfree_(nullptr)
74227825Stheraven{
75276792Sdim    __init(const_cast<char *>(reinterpret_cast<const char*>(__gnext)), __n, reinterpret_cast<char*>(__pbeg));
76227825Stheraven}
77227825Stheraven
78227825Stheravenstrstreambuf::strstreambuf(const signed char* __gnext, streamsize __n)
79227825Stheraven    : __strmode_(__constant),
80227825Stheraven      __alsize_(__default_alsize),
81227825Stheraven      __palloc_(nullptr),
82227825Stheraven      __pfree_(nullptr)
83227825Stheraven{
84276792Sdim    __init(const_cast<char *>(reinterpret_cast<const char*>(__gnext)), __n, nullptr);
85227825Stheraven}
86227825Stheraven
87227825Stheravenstrstreambuf::strstreambuf(unsigned char* __gnext, streamsize __n, unsigned char* __pbeg)
88227825Stheraven    : __strmode_(),
89227825Stheraven      __alsize_(__default_alsize),
90227825Stheraven      __palloc_(nullptr),
91227825Stheraven      __pfree_(nullptr)
92227825Stheraven{
93276792Sdim    __init(const_cast<char *>(reinterpret_cast<const char*>(__gnext)), __n, reinterpret_cast<char*>(__pbeg));
94227825Stheraven}
95227825Stheraven
96227825Stheravenstrstreambuf::strstreambuf(const unsigned char* __gnext, streamsize __n)
97227825Stheraven    : __strmode_(__constant),
98227825Stheraven      __alsize_(__default_alsize),
99227825Stheraven      __palloc_(nullptr),
100227825Stheraven      __pfree_(nullptr)
101227825Stheraven{
102276792Sdim    __init(const_cast<char *>(reinterpret_cast<const char*>(__gnext)), __n, nullptr);
103227825Stheraven}
104227825Stheraven
105227825Stheravenstrstreambuf::~strstreambuf()
106227825Stheraven{
107227825Stheraven    if (eback() && (__strmode_ & __allocated) != 0 && (__strmode_ & __frozen) == 0)
108227825Stheraven    {
109227825Stheraven        if (__pfree_)
110227825Stheraven            __pfree_(eback());
111227825Stheraven        else
112227825Stheraven            delete [] eback();
113227825Stheraven    }
114227825Stheraven}
115227825Stheraven
116227825Stheravenvoid
117227825Stheravenstrstreambuf::swap(strstreambuf& __rhs)
118227825Stheraven{
119227825Stheraven    streambuf::swap(__rhs);
120227825Stheraven    _VSTD::swap(__strmode_, __rhs.__strmode_);
121227825Stheraven    _VSTD::swap(__alsize_, __rhs.__alsize_);
122227825Stheraven    _VSTD::swap(__palloc_, __rhs.__palloc_);
123227825Stheraven    _VSTD::swap(__pfree_, __rhs.__pfree_);
124227825Stheraven}
125227825Stheraven
126227825Stheravenvoid
127227825Stheravenstrstreambuf::freeze(bool __freezefl)
128227825Stheraven{
129227825Stheraven    if (__strmode_ & __dynamic)
130227825Stheraven    {
131227825Stheraven        if (__freezefl)
132227825Stheraven            __strmode_ |= __frozen;
133227825Stheraven        else
134227825Stheraven            __strmode_ &= ~__frozen;
135227825Stheraven    }
136227825Stheraven}
137227825Stheraven
138227825Stheravenchar*
139227825Stheravenstrstreambuf::str()
140227825Stheraven{
141227825Stheraven    if (__strmode_ & __dynamic)
142227825Stheraven        __strmode_ |= __frozen;
143227825Stheraven    return eback();
144227825Stheraven}
145227825Stheraven
146227825Stheravenint
147227825Stheravenstrstreambuf::pcount() const
148227825Stheraven{
149227825Stheraven    return static_cast<int>(pptr() - pbase());
150227825Stheraven}
151227825Stheraven
152227825Stheravenstrstreambuf::int_type
153227825Stheravenstrstreambuf::overflow(int_type __c)
154227825Stheraven{
155227825Stheraven    if (__c == EOF)
156227825Stheraven        return int_type(0);
157227825Stheraven    if (pptr() == epptr())
158227825Stheraven    {
159227825Stheraven        if ((__strmode_ & __dynamic) == 0 || (__strmode_ & __frozen) != 0)
160227825Stheraven            return int_type(EOF);
161261272Sdim        size_t old_size = static_cast<size_t> ((epptr() ? epptr() : egptr()) - eback());
162261272Sdim        size_t new_size = max<size_t>(static_cast<size_t>(__alsize_), 2*old_size);
163249989Sdim        if (new_size == 0)
164249989Sdim            new_size = __default_alsize;
165227825Stheraven        char* buf = nullptr;
166227825Stheraven        if (__palloc_)
167261272Sdim            buf = static_cast<char*>(__palloc_(new_size));
168227825Stheraven        else
169227825Stheraven            buf = new char[new_size];
170227825Stheraven        if (buf == nullptr)
171227825Stheraven            return int_type(EOF);
172309124Sdim        if (old_size != 0) {
173309124Sdim            _LIBCPP_ASSERT(eback(), "overflow copying from NULL");
174309124Sdim            memcpy(buf, eback(), static_cast<size_t>(old_size));
175309124Sdim        }
176227825Stheraven        ptrdiff_t ninp = gptr()  - eback();
177227825Stheraven        ptrdiff_t einp = egptr() - eback();
178227825Stheraven        ptrdiff_t nout = pptr()  - pbase();
179227825Stheraven        if (__strmode_ & __allocated)
180227825Stheraven        {
181227825Stheraven            if (__pfree_)
182227825Stheraven                __pfree_(eback());
183227825Stheraven            else
184227825Stheraven                delete [] eback();
185227825Stheraven        }
186227825Stheraven        setg(buf, buf + ninp, buf + einp);
187309124Sdim        setp(buf + einp, buf + new_size);
188327952Sdim        __pbump(nout);
189227825Stheraven        __strmode_ |= __allocated;
190227825Stheraven    }
191227825Stheraven    *pptr() = static_cast<char>(__c);
192227825Stheraven    pbump(1);
193276792Sdim    return int_type(static_cast<unsigned char>(__c));
194227825Stheraven}
195227825Stheraven
196227825Stheravenstrstreambuf::int_type
197227825Stheravenstrstreambuf::pbackfail(int_type __c)
198227825Stheraven{
199227825Stheraven    if (eback() == gptr())
200227825Stheraven        return EOF;
201227825Stheraven    if (__c == EOF)
202227825Stheraven    {
203227825Stheraven        gbump(-1);
204227825Stheraven        return int_type(0);
205227825Stheraven    }
206227825Stheraven    if (__strmode_ & __constant)
207227825Stheraven    {
208227825Stheraven        if (gptr()[-1] == static_cast<char>(__c))
209227825Stheraven        {
210227825Stheraven            gbump(-1);
211227825Stheraven            return __c;
212227825Stheraven        }
213227825Stheraven        return EOF;
214227825Stheraven    }
215227825Stheraven    gbump(-1);
216227825Stheraven    *gptr() = static_cast<char>(__c);
217227825Stheraven    return __c;
218227825Stheraven}
219227825Stheraven
220227825Stheravenstrstreambuf::int_type
221227825Stheravenstrstreambuf::underflow()
222227825Stheraven{
223227825Stheraven    if (gptr() == egptr())
224227825Stheraven    {
225227825Stheraven        if (egptr() >= pptr())
226227825Stheraven            return EOF;
227227825Stheraven        setg(eback(), gptr(), pptr());
228227825Stheraven    }
229276792Sdim    return int_type(static_cast<unsigned char>(*gptr()));
230227825Stheraven}
231227825Stheraven
232227825Stheravenstrstreambuf::pos_type
233227825Stheravenstrstreambuf::seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode __which)
234227825Stheraven{
235227825Stheraven    off_type __p(-1);
236261272Sdim    bool pos_in = (__which & ios::in) != 0;
237261272Sdim    bool pos_out = (__which & ios::out) != 0;
238227825Stheraven    bool legal = false;
239227825Stheraven    switch (__way)
240227825Stheraven    {
241227825Stheraven    case ios::beg:
242227825Stheraven    case ios::end:
243227825Stheraven        if (pos_in || pos_out)
244227825Stheraven            legal = true;
245227825Stheraven        break;
246227825Stheraven    case ios::cur:
247227825Stheraven        if (pos_in != pos_out)
248227825Stheraven            legal = true;
249227825Stheraven        break;
250227825Stheraven    }
251227825Stheraven    if (pos_in && gptr() == nullptr)
252227825Stheraven        legal = false;
253227825Stheraven    if (pos_out && pptr() == nullptr)
254227825Stheraven        legal = false;
255227825Stheraven    if (legal)
256227825Stheraven    {
257227825Stheraven        off_type newoff;
258227825Stheraven        char* seekhigh = epptr() ? epptr() : egptr();
259227825Stheraven        switch (__way)
260227825Stheraven        {
261227825Stheraven        case ios::beg:
262227825Stheraven            newoff = 0;
263227825Stheraven            break;
264227825Stheraven        case ios::cur:
265227825Stheraven            newoff = (pos_in ? gptr() : pptr()) - eback();
266227825Stheraven            break;
267227825Stheraven        case ios::end:
268227825Stheraven            newoff = seekhigh - eback();
269227825Stheraven            break;
270314564Sdim        default:
271314564Sdim            _LIBCPP_UNREACHABLE();
272227825Stheraven        }
273227825Stheraven        newoff += __off;
274227825Stheraven        if (0 <= newoff && newoff <= seekhigh - eback())
275227825Stheraven        {
276227825Stheraven            char* newpos = eback() + newoff;
277227825Stheraven            if (pos_in)
278227825Stheraven                setg(eback(), newpos, _VSTD::max(newpos, egptr()));
279227825Stheraven            if (pos_out)
280227825Stheraven            {
281227825Stheraven                // min(pbase, newpos), newpos, epptr()
282227825Stheraven                __off = epptr() - newpos;
283227825Stheraven                setp(min(pbase(), newpos), epptr());
284327952Sdim                __pbump((epptr() - pbase()) - __off);
285227825Stheraven            }
286227825Stheraven            __p = newoff;
287227825Stheraven        }
288227825Stheraven    }
289227825Stheraven    return pos_type(__p);
290227825Stheraven}
291227825Stheraven
292227825Stheravenstrstreambuf::pos_type
293227825Stheravenstrstreambuf::seekpos(pos_type __sp, ios_base::openmode __which)
294227825Stheraven{
295227825Stheraven    off_type __p(-1);
296261272Sdim    bool pos_in = (__which & ios::in) != 0;
297261272Sdim    bool pos_out = (__which & ios::out) != 0;
298227825Stheraven    if (pos_in || pos_out)
299227825Stheraven    {
300227825Stheraven        if (!((pos_in && gptr() == nullptr) || (pos_out && pptr() == nullptr)))
301227825Stheraven        {
302227825Stheraven            off_type newoff = __sp;
303227825Stheraven            char* seekhigh = epptr() ? epptr() : egptr();
304227825Stheraven            if (0 <= newoff && newoff <= seekhigh - eback())
305227825Stheraven            {
306227825Stheraven                char* newpos = eback() + newoff;
307227825Stheraven                if (pos_in)
308227825Stheraven                    setg(eback(), newpos, _VSTD::max(newpos, egptr()));
309227825Stheraven                if (pos_out)
310227825Stheraven                {
311227825Stheraven                    // min(pbase, newpos), newpos, epptr()
312227825Stheraven                    off_type temp = epptr() - newpos;
313227825Stheraven                    setp(min(pbase(), newpos), epptr());
314327952Sdim                    __pbump((epptr() - pbase()) - temp);
315227825Stheraven                }
316227825Stheraven                __p = newoff;
317227825Stheraven            }
318227825Stheraven        }
319227825Stheraven    }
320227825Stheraven    return pos_type(__p);
321227825Stheraven}
322227825Stheraven
323227825Stheravenistrstream::~istrstream()
324227825Stheraven{
325227825Stheraven}
326227825Stheraven
327227825Stheravenostrstream::~ostrstream()
328227825Stheraven{
329227825Stheraven}
330227825Stheraven
331227825Stheravenstrstream::~strstream()
332227825Stheraven{
333227825Stheraven}
334227825Stheraven
335227825Stheraven_LIBCPP_END_NAMESPACE_STD
336