xref: /freebsd/contrib/llvm-project/libcxx/src/strstream.cpp (revision 1db9f3b21e39176dd5b67cf8ac378633b172463e)
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), __alsize_(__alsize), __palloc_(nullptr), __pfree_(nullptr) {}
24 
25 strstreambuf::strstreambuf(void* (*__palloc)(size_t), void (*__pfree)(void*))
26     : __strmode_(__dynamic), __alsize_(__default_alsize), __palloc_(__palloc), __pfree_(__pfree) {}
27 
28 void strstreambuf::__init(char* __gnext, streamsize __n, char* __pbeg) {
29   if (__n == 0)
30     __n = static_cast<streamsize>(strlen(__gnext));
31   else if (__n < 0)
32     __n = INT_MAX;
33   if (__pbeg == nullptr)
34     setg(__gnext, __gnext, __gnext + __n);
35   else {
36     setg(__gnext, __gnext, __pbeg);
37     setp(__pbeg, __pbeg + __n);
38   }
39 }
40 
41 strstreambuf::strstreambuf(char* __gnext, streamsize __n, char* __pbeg)
42     : __strmode_(), __alsize_(__default_alsize), __palloc_(nullptr), __pfree_(nullptr) {
43   __init(__gnext, __n, __pbeg);
44 }
45 
46 strstreambuf::strstreambuf(const char* __gnext, streamsize __n)
47     : __strmode_(__constant), __alsize_(__default_alsize), __palloc_(nullptr), __pfree_(nullptr) {
48   __init(const_cast<char*>(__gnext), __n, nullptr);
49 }
50 
51 strstreambuf::strstreambuf(signed char* __gnext, streamsize __n, signed char* __pbeg)
52     : __strmode_(), __alsize_(__default_alsize), __palloc_(nullptr), __pfree_(nullptr) {
53   __init(const_cast<char*>(reinterpret_cast<const char*>(__gnext)), __n, reinterpret_cast<char*>(__pbeg));
54 }
55 
56 strstreambuf::strstreambuf(const signed char* __gnext, streamsize __n)
57     : __strmode_(__constant), __alsize_(__default_alsize), __palloc_(nullptr), __pfree_(nullptr) {
58   __init(const_cast<char*>(reinterpret_cast<const char*>(__gnext)), __n, nullptr);
59 }
60 
61 strstreambuf::strstreambuf(unsigned char* __gnext, streamsize __n, unsigned char* __pbeg)
62     : __strmode_(), __alsize_(__default_alsize), __palloc_(nullptr), __pfree_(nullptr) {
63   __init(const_cast<char*>(reinterpret_cast<const char*>(__gnext)), __n, reinterpret_cast<char*>(__pbeg));
64 }
65 
66 strstreambuf::strstreambuf(const unsigned char* __gnext, streamsize __n)
67     : __strmode_(__constant), __alsize_(__default_alsize), __palloc_(nullptr), __pfree_(nullptr) {
68   __init(const_cast<char*>(reinterpret_cast<const char*>(__gnext)), __n, nullptr);
69 }
70 
71 strstreambuf::~strstreambuf() {
72   if (eback() && (__strmode_ & __allocated) != 0 && (__strmode_ & __frozen) == 0) {
73     if (__pfree_)
74       __pfree_(eback());
75     else
76       delete[] eback();
77   }
78 }
79 
80 void strstreambuf::swap(strstreambuf& __rhs) {
81   streambuf::swap(__rhs);
82   std::swap(__strmode_, __rhs.__strmode_);
83   std::swap(__alsize_, __rhs.__alsize_);
84   std::swap(__palloc_, __rhs.__palloc_);
85   std::swap(__pfree_, __rhs.__pfree_);
86 }
87 
88 void strstreambuf::freeze(bool __freezefl) {
89   if (__strmode_ & __dynamic) {
90     if (__freezefl)
91       __strmode_ |= __frozen;
92     else
93       __strmode_ &= ~__frozen;
94   }
95 }
96 
97 char* strstreambuf::str() {
98   if (__strmode_ & __dynamic)
99     __strmode_ |= __frozen;
100   return eback();
101 }
102 
103 int strstreambuf::pcount() const { return static_cast<int>(pptr() - pbase()); }
104 
105 strstreambuf::int_type strstreambuf::overflow(int_type __c) {
106   if (__c == EOF)
107     return int_type(0);
108   if (pptr() == epptr()) {
109     if ((__strmode_ & __dynamic) == 0 || (__strmode_ & __frozen) != 0)
110       return int_type(EOF);
111     size_t old_size = static_cast<size_t>((epptr() ? epptr() : egptr()) - eback());
112     size_t new_size = max<size_t>(static_cast<size_t>(__alsize_), 2 * old_size);
113     if (new_size == 0)
114       new_size = __default_alsize;
115     char* buf = nullptr;
116     if (__palloc_)
117       buf = static_cast<char*>(__palloc_(new_size));
118     else
119       buf = new char[new_size];
120     if (buf == nullptr)
121       return int_type(EOF);
122     if (old_size != 0) {
123       _LIBCPP_ASSERT_INTERNAL(eback(), "strstreambuf::overflow reallocating but the get area is a null pointer");
124       memcpy(buf, eback(), static_cast<size_t>(old_size));
125     }
126     ptrdiff_t ninp = gptr() - eback();
127     ptrdiff_t einp = egptr() - eback();
128     ptrdiff_t nout = pptr() - pbase();
129     if (__strmode_ & __allocated) {
130       if (__pfree_)
131         __pfree_(eback());
132       else
133         delete[] eback();
134     }
135     setg(buf, buf + ninp, buf + einp);
136     setp(buf + einp, buf + new_size);
137     __pbump(nout);
138     __strmode_ |= __allocated;
139   }
140   *pptr() = static_cast<char>(__c);
141   pbump(1);
142   return int_type(static_cast<unsigned char>(__c));
143 }
144 
145 strstreambuf::int_type strstreambuf::pbackfail(int_type __c) {
146   if (eback() == gptr())
147     return EOF;
148   if (__c == EOF) {
149     gbump(-1);
150     return int_type(0);
151   }
152   if (__strmode_ & __constant) {
153     if (gptr()[-1] == static_cast<char>(__c)) {
154       gbump(-1);
155       return __c;
156     }
157     return EOF;
158   }
159   gbump(-1);
160   *gptr() = static_cast<char>(__c);
161   return __c;
162 }
163 
164 strstreambuf::int_type strstreambuf::underflow() {
165   if (gptr() == egptr()) {
166     if (egptr() >= pptr())
167       return EOF;
168     setg(eback(), gptr(), pptr());
169   }
170   return int_type(static_cast<unsigned char>(*gptr()));
171 }
172 
173 strstreambuf::pos_type strstreambuf::seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode __which) {
174   bool pos_in  = (__which & ios::in) != 0;
175   bool pos_out = (__which & ios::out) != 0;
176   switch (__way) {
177   case ios::beg:
178   case ios::end:
179     if (!pos_in && !pos_out)
180       return pos_type(off_type(-1));
181     break;
182   case ios::cur:
183     if (pos_in == pos_out)
184       return pos_type(off_type(-1));
185     break;
186   }
187 
188   if (pos_in && gptr() == nullptr)
189     return pos_type(off_type(-1));
190   if (pos_out && pptr() == nullptr)
191     return pos_type(off_type(-1));
192 
193   off_type newoff;
194   char* seekhigh = epptr() ? epptr() : egptr();
195   switch (__way) {
196   case ios::beg:
197     newoff = 0;
198     break;
199   case ios::cur:
200     newoff = (pos_in ? gptr() : pptr()) - eback();
201     break;
202   case ios::end:
203     newoff = seekhigh - eback();
204     break;
205   default:
206     __libcpp_unreachable();
207   }
208   newoff += __off;
209   if (newoff < 0 || newoff > seekhigh - eback())
210     return pos_type(off_type(-1));
211 
212   char* newpos = eback() + newoff;
213   if (pos_in)
214     setg(eback(), newpos, std::max(newpos, egptr()));
215   if (pos_out) {
216     // min(pbase, newpos), newpos, epptr()
217     __off = epptr() - newpos;
218     setp(min(pbase(), newpos), epptr());
219     __pbump((epptr() - pbase()) - __off);
220   }
221   return pos_type(newoff);
222 }
223 
224 strstreambuf::pos_type strstreambuf::seekpos(pos_type __sp, ios_base::openmode __which) {
225   bool pos_in  = (__which & ios::in) != 0;
226   bool pos_out = (__which & ios::out) != 0;
227   if (!pos_in && !pos_out)
228     return pos_type(off_type(-1));
229 
230   if ((pos_in && gptr() == nullptr) || (pos_out && pptr() == nullptr))
231     return pos_type(off_type(-1));
232 
233   off_type newoff = __sp;
234   char* seekhigh  = epptr() ? epptr() : egptr();
235   if (newoff < 0 || newoff > seekhigh - eback())
236     return pos_type(off_type(-1));
237 
238   char* newpos = eback() + newoff;
239   if (pos_in)
240     setg(eback(), newpos, std::max(newpos, egptr()));
241   if (pos_out) {
242     // min(pbase, newpos), newpos, epptr()
243     off_type temp = epptr() - newpos;
244     setp(min(pbase(), newpos), epptr());
245     __pbump((epptr() - pbase()) - temp);
246   }
247   return pos_type(newoff);
248 }
249 
250 istrstream::~istrstream() {}
251 
252 ostrstream::~ostrstream() {}
253 
254 strstream::~strstream() {}
255 
256 _LIBCPP_END_NAMESPACE_STD
257 
258 _LIBCPP_POP_MACROS
259