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