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(__gnext, __gnext, __gnext + __n);
35  else {
36    setg(__gnext, __gnext, __pbeg);
37    setp(__pbeg, __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