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