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