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     return *this;
134 }
135 
136 #endif  // _LIBCPP_HAS_NO_RVALUE_REFERENCES
137 
138 strstreambuf::~strstreambuf()
139 {
140     if (eback() && (__strmode_ & __allocated) != 0 && (__strmode_ & __frozen) == 0)
141     {
142         if (__pfree_)
143             __pfree_(eback());
144         else
145             delete [] eback();
146     }
147 }
148 
149 void
150 strstreambuf::swap(strstreambuf& __rhs)
151 {
152     streambuf::swap(__rhs);
153     _STD::swap(__strmode_, __rhs.__strmode_);
154     _STD::swap(__alsize_, __rhs.__alsize_);
155     _STD::swap(__palloc_, __rhs.__palloc_);
156     _STD::swap(__pfree_, __rhs.__pfree_);
157 }
158 
159 void
160 strstreambuf::freeze(bool __freezefl)
161 {
162     if (__strmode_ & __dynamic)
163     {
164         if (__freezefl)
165             __strmode_ |= __frozen;
166         else
167             __strmode_ &= ~__frozen;
168     }
169 }
170 
171 char*
172 strstreambuf::str()
173 {
174     if (__strmode_ & __dynamic)
175         __strmode_ |= __frozen;
176     return eback();
177 }
178 
179 int
180 strstreambuf::pcount() const
181 {
182     return static_cast<int>(pptr() - pbase());
183 }
184 
185 strstreambuf::int_type
186 strstreambuf::overflow(int_type __c)
187 {
188     if (__c == EOF)
189         return int_type(0);
190     if (pptr() == epptr())
191     {
192         if ((__strmode_ & __dynamic) == 0 || (__strmode_ & __frozen) != 0)
193             return int_type(EOF);
194         streamsize old_size = (epptr() ? epptr() : egptr()) - eback();
195         streamsize new_size = max<streamsize>(__alsize_, 2*old_size);
196         char* buf = nullptr;
197         if (__palloc_)
198             buf = static_cast<char*>(__palloc_(new_size));
199         else
200             buf = new char[new_size];
201         if (buf == nullptr)
202             return int_type(EOF);
203         memcpy(buf, eback(), old_size);
204         ptrdiff_t ninp = gptr()  - eback();
205         ptrdiff_t einp = egptr() - eback();
206         ptrdiff_t nout = pptr()  - pbase();
207         ptrdiff_t eout = epptr() - pbase();
208         if (__strmode_ & __allocated)
209         {
210             if (__pfree_)
211                 __pfree_(eback());
212             else
213                 delete [] eback();
214         }
215         setg(buf, buf + ninp, buf + einp);
216         setp(buf + einp, buf + einp + eout);
217         pbump(nout);
218         __strmode_ |= __allocated;
219     }
220     *pptr() = static_cast<char>(__c);
221     pbump(1);
222     return int_type((unsigned char)__c);
223 }
224 
225 strstreambuf::int_type
226 strstreambuf::pbackfail(int_type __c)
227 {
228     if (eback() == gptr())
229         return EOF;
230     if (__c == EOF)
231     {
232         gbump(-1);
233         return int_type(0);
234     }
235     if (__strmode_ & __constant)
236     {
237         if (gptr()[-1] == static_cast<char>(__c))
238         {
239             gbump(-1);
240             return __c;
241         }
242         return EOF;
243     }
244     gbump(-1);
245     *gptr() = static_cast<char>(__c);
246     return __c;
247 }
248 
249 strstreambuf::int_type
250 strstreambuf::underflow()
251 {
252     if (gptr() == egptr())
253     {
254         if (egptr() >= pptr())
255             return EOF;
256         setg(eback(), gptr(), pptr());
257     }
258     return int_type((unsigned char)*gptr());
259 }
260 
261 strstreambuf::pos_type
262 strstreambuf::seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode __which)
263 {
264     off_type __p(-1);
265     bool pos_in = __which & ios::in;
266     bool pos_out = __which & ios::out;
267     bool legal = false;
268     switch (__way)
269     {
270     case ios::beg:
271     case ios::end:
272         if (pos_in || pos_out)
273             legal = true;
274         break;
275     case ios::cur:
276         if (pos_in != pos_out)
277             legal = true;
278         break;
279     }
280     if (pos_in && gptr() == nullptr)
281         legal = false;
282     if (pos_out && pptr() == nullptr)
283         legal = false;
284     if (legal)
285     {
286         off_type newoff;
287         char* seekhigh = epptr() ? epptr() : egptr();
288         switch (__way)
289         {
290         case ios::beg:
291             newoff = 0;
292             break;
293         case ios::cur:
294             newoff = (pos_in ? gptr() : pptr()) - eback();
295             break;
296         case ios::end:
297             newoff = seekhigh - eback();
298             break;
299         }
300         newoff += __off;
301         if (0 <= newoff && newoff <= seekhigh - eback())
302         {
303             char* newpos = eback() + newoff;
304             if (pos_in)
305                 setg(eback(), newpos, _STD::max(newpos, egptr()));
306             if (pos_out)
307             {
308                 // min(pbase, newpos), newpos, epptr()
309                 __off = epptr() - newpos;
310                 setp(min(pbase(), newpos), epptr());
311                 pbump(static_cast<int>((epptr() - pbase()) - __off));
312             }
313             __p = newoff;
314         }
315     }
316     return pos_type(__p);
317 }
318 
319 strstreambuf::pos_type
320 strstreambuf::seekpos(pos_type __sp, ios_base::openmode __which)
321 {
322     off_type __p(-1);
323     bool pos_in = __which & ios::in;
324     bool pos_out = __which & ios::out;
325     if (pos_in || pos_out)
326     {
327         if (!((pos_in && gptr() == nullptr) || (pos_out && pptr() == nullptr)))
328         {
329             off_type newoff = __sp;
330             char* seekhigh = epptr() ? epptr() : egptr();
331             if (0 <= newoff && newoff <= seekhigh - eback())
332             {
333                 char* newpos = eback() + newoff;
334                 if (pos_in)
335                     setg(eback(), newpos, _STD::max(newpos, egptr()));
336                 if (pos_out)
337                 {
338                     // min(pbase, newpos), newpos, epptr()
339                     off_type temp = epptr() - newpos;
340                     setp(min(pbase(), newpos), epptr());
341                     pbump(static_cast<int>((epptr() - pbase()) - temp));
342                 }
343                 __p = newoff;
344             }
345         }
346     }
347     return pos_type(__p);
348 }
349 
350 istrstream::~istrstream()
351 {
352 }
353 
354 ostrstream::~ostrstream()
355 {
356 }
357 
358 strstream::~strstream()
359 {
360 }
361 
362 _LIBCPP_END_NAMESPACE_STD
363