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
22strstreambuf::strstreambuf(streamsize __alsize)
23 : __strmode_(__dynamic), __alsize_(__alsize), __palloc_(nullptr), __pfree_(nullptr) {}
24
25strstreambuf::strstreambuf(void* (*__palloc)(size_t), void (*__pfree)(void*))
26 : __strmode_(__dynamic), __alsize_(__default_alsize), __palloc_(__palloc), __pfree_(__pfree) {}
27
28void 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(gbeg: __gnext, __gnext, gend: __gnext + __n);
35 else {
36 setg(gbeg: __gnext, __gnext, gend: __pbeg);
37 setp(__pbeg, pend: __pbeg + __n);
38 }
39}
40
41strstreambuf::strstreambuf(char* __gnext, streamsize __n, char* __pbeg)
42 : __strmode_(), __alsize_(__default_alsize), __palloc_(nullptr), __pfree_(nullptr) {
43 __init(__gnext, __n, __pbeg);
44}
45
46strstreambuf::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
51strstreambuf::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
56strstreambuf::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
61strstreambuf::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
66strstreambuf::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
71strstreambuf::~strstreambuf() {
72 if (eback() && (__strmode_ & __allocated) != 0 && (__strmode_ & __frozen) == 0) {
73 if (__pfree_)
74 __pfree_(eback());
75 else
76 delete[] eback();
77 }
78}
79
80void 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
88void strstreambuf::freeze(bool __freezefl) {
89 if (__strmode_ & __dynamic) {
90 if (__freezefl)
91 __strmode_ |= __frozen;
92 else
93 __strmode_ &= ~__frozen;
94 }
95}
96
97char* strstreambuf::str() {
98 if (__strmode_ & __dynamic)
99 __strmode_ |= __frozen;
100 return eback();
101}
102
103int strstreambuf::pcount() const { return static_cast<int>(pptr() - pbase()); }
104
105strstreambuf::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
145strstreambuf::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
164strstreambuf::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
173strstreambuf::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
224strstreambuf::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
250istrstream::~istrstream() {}
251
252ostrstream::~ostrstream() {}
253
254strstream::~strstream() {}
255
256_LIBCPP_END_NAMESPACE_STD
257
258_LIBCPP_POP_MACROS
259

source code of libcxx/src/strstream.cpp