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