1 | //===-------------------------- ios.cpp -----------------------------------===// |
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 "__config" |
10 | |
11 | #include "ios" |
12 | |
13 | #include <stdlib.h> |
14 | |
15 | #include "__locale" |
16 | #include "algorithm" |
17 | #include "include/config_elast.h" |
18 | #include "istream" |
19 | #include "limits" |
20 | #include "memory" |
21 | #include "new" |
22 | #include "streambuf" |
23 | #include "string" |
24 | #include "__undef_macros" |
25 | |
26 | _LIBCPP_BEGIN_NAMESPACE_STD |
27 | |
28 | template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_ios<char>; |
29 | template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_ios<wchar_t>; |
30 | |
31 | template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_streambuf<char>; |
32 | template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_streambuf<wchar_t>; |
33 | |
34 | template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_istream<char>; |
35 | template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_istream<wchar_t>; |
36 | |
37 | template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_ostream<char>; |
38 | template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_ostream<wchar_t>; |
39 | |
40 | template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_iostream<char>; |
41 | |
42 | class _LIBCPP_HIDDEN __iostream_category |
43 | : public __do_message |
44 | { |
45 | public: |
46 | virtual const char* name() const _NOEXCEPT; |
47 | virtual string message(int ev) const; |
48 | }; |
49 | |
50 | const char* |
51 | __iostream_category::name() const _NOEXCEPT |
52 | { |
53 | return "iostream" ; |
54 | } |
55 | |
56 | string |
57 | __iostream_category::message(int ev) const |
58 | { |
59 | if (ev != static_cast<int>(io_errc::stream) |
60 | #ifdef _LIBCPP_ELAST |
61 | && ev <= _LIBCPP_ELAST |
62 | #endif // _LIBCPP_ELAST |
63 | ) |
64 | return __do_message::message(ev); |
65 | return string("unspecified iostream_category error" ); |
66 | } |
67 | |
68 | const error_category& |
69 | iostream_category() _NOEXCEPT |
70 | { |
71 | static __iostream_category s; |
72 | return s; |
73 | } |
74 | |
75 | // ios_base::failure |
76 | |
77 | ios_base::failure::failure(const string& msg, const error_code& ec) |
78 | : system_error(ec, msg) |
79 | { |
80 | } |
81 | |
82 | ios_base::failure::failure(const char* msg, const error_code& ec) |
83 | : system_error(ec, msg) |
84 | { |
85 | } |
86 | |
87 | ios_base::failure::~failure() throw() |
88 | { |
89 | } |
90 | |
91 | // ios_base locale |
92 | |
93 | const ios_base::fmtflags ios_base::boolalpha; |
94 | const ios_base::fmtflags ios_base::dec; |
95 | const ios_base::fmtflags ios_base::fixed; |
96 | const ios_base::fmtflags ios_base::hex; |
97 | const ios_base::fmtflags ios_base::internal; |
98 | const ios_base::fmtflags ios_base::left; |
99 | const ios_base::fmtflags ios_base::oct; |
100 | const ios_base::fmtflags ios_base::right; |
101 | const ios_base::fmtflags ios_base::scientific; |
102 | const ios_base::fmtflags ios_base::showbase; |
103 | const ios_base::fmtflags ios_base::showpoint; |
104 | const ios_base::fmtflags ios_base::showpos; |
105 | const ios_base::fmtflags ios_base::skipws; |
106 | const ios_base::fmtflags ios_base::unitbuf; |
107 | const ios_base::fmtflags ios_base::uppercase; |
108 | const ios_base::fmtflags ios_base::adjustfield; |
109 | const ios_base::fmtflags ios_base::basefield; |
110 | const ios_base::fmtflags ios_base::floatfield; |
111 | |
112 | const ios_base::iostate ios_base::badbit; |
113 | const ios_base::iostate ios_base::eofbit; |
114 | const ios_base::iostate ios_base::failbit; |
115 | const ios_base::iostate ios_base::goodbit; |
116 | |
117 | const ios_base::openmode ios_base::app; |
118 | const ios_base::openmode ios_base::ate; |
119 | const ios_base::openmode ios_base::binary; |
120 | const ios_base::openmode ios_base::in; |
121 | const ios_base::openmode ios_base::out; |
122 | const ios_base::openmode ios_base::trunc; |
123 | |
124 | void |
125 | ios_base::__call_callbacks(event ev) |
126 | { |
127 | for (size_t i = __event_size_; i;) |
128 | { |
129 | --i; |
130 | __fn_[i](ev, *this, __index_[i]); |
131 | } |
132 | } |
133 | |
134 | // locale |
135 | |
136 | locale |
137 | ios_base::imbue(const locale& newloc) |
138 | { |
139 | static_assert(sizeof(locale) == sizeof(__loc_), "" ); |
140 | locale& loc_storage = *reinterpret_cast<locale*>(&__loc_); |
141 | locale oldloc = loc_storage; |
142 | loc_storage = newloc; |
143 | __call_callbacks(imbue_event); |
144 | return oldloc; |
145 | } |
146 | |
147 | locale |
148 | ios_base::getloc() const |
149 | { |
150 | const locale& loc_storage = *reinterpret_cast<const locale*>(&__loc_); |
151 | return loc_storage; |
152 | } |
153 | |
154 | // xalloc |
155 | #if defined(_LIBCPP_HAS_C_ATOMIC_IMP) && !defined(_LIBCPP_HAS_NO_THREADS) |
156 | atomic<int> ios_base::__xindex_ = ATOMIC_VAR_INIT(0); |
157 | #else |
158 | int ios_base::__xindex_ = 0; |
159 | #endif |
160 | |
161 | template <typename _Tp> |
162 | static size_t __ios_new_cap(size_t __req_size, size_t __current_cap) |
163 | { // Precondition: __req_size > __current_cap |
164 | const size_t mx = std::numeric_limits<size_t>::max() / sizeof(_Tp); |
165 | if (__req_size < mx/2) |
166 | return _VSTD::max(2 * __current_cap, __req_size); |
167 | else |
168 | return mx; |
169 | } |
170 | |
171 | int |
172 | ios_base::xalloc() |
173 | { |
174 | return __xindex_++; |
175 | } |
176 | |
177 | long& |
178 | ios_base::iword(int index) |
179 | { |
180 | size_t req_size = static_cast<size_t>(index)+1; |
181 | if (req_size > __iarray_cap_) |
182 | { |
183 | size_t newcap = __ios_new_cap<long>(req_size, __iarray_cap_); |
184 | long* iarray = static_cast<long*>(realloc(__iarray_, newcap * sizeof(long))); |
185 | if (iarray == 0) |
186 | { |
187 | setstate(badbit); |
188 | static long error; |
189 | error = 0; |
190 | return error; |
191 | } |
192 | __iarray_ = iarray; |
193 | for (long* p = __iarray_ + __iarray_size_; p < __iarray_ + newcap; ++p) |
194 | *p = 0; |
195 | __iarray_cap_ = newcap; |
196 | } |
197 | __iarray_size_ = max<size_t>(__iarray_size_, req_size); |
198 | return __iarray_[index]; |
199 | } |
200 | |
201 | void*& |
202 | ios_base::pword(int index) |
203 | { |
204 | size_t req_size = static_cast<size_t>(index)+1; |
205 | if (req_size > __parray_cap_) |
206 | { |
207 | size_t newcap = __ios_new_cap<void *>(req_size, __iarray_cap_); |
208 | void** parray = static_cast<void**>(realloc(__parray_, newcap * sizeof(void *))); |
209 | if (parray == 0) |
210 | { |
211 | setstate(badbit); |
212 | static void* error; |
213 | error = 0; |
214 | return error; |
215 | } |
216 | __parray_ = parray; |
217 | for (void** p = __parray_ + __parray_size_; p < __parray_ + newcap; ++p) |
218 | *p = 0; |
219 | __parray_cap_ = newcap; |
220 | } |
221 | __parray_size_ = max<size_t>(__parray_size_, req_size); |
222 | return __parray_[index]; |
223 | } |
224 | |
225 | // register_callback |
226 | |
227 | void |
228 | ios_base::register_callback(event_callback fn, int index) |
229 | { |
230 | size_t req_size = __event_size_ + 1; |
231 | if (req_size > __event_cap_) |
232 | { |
233 | size_t newcap = __ios_new_cap<event_callback>(req_size, __event_cap_); |
234 | event_callback* fns = static_cast<event_callback*>(realloc(__fn_, newcap * sizeof(event_callback))); |
235 | if (fns == 0) |
236 | setstate(badbit); |
237 | __fn_ = fns; |
238 | int* indxs = static_cast<int *>(realloc(__index_, newcap * sizeof(int))); |
239 | if (indxs == 0) |
240 | setstate(badbit); |
241 | __index_ = indxs; |
242 | __event_cap_ = newcap; |
243 | } |
244 | __fn_[__event_size_] = fn; |
245 | __index_[__event_size_] = index; |
246 | ++__event_size_; |
247 | } |
248 | |
249 | ios_base::~ios_base() |
250 | { |
251 | __call_callbacks(erase_event); |
252 | locale& loc_storage = *reinterpret_cast<locale*>(&__loc_); |
253 | loc_storage.~locale(); |
254 | free(__fn_); |
255 | free(__index_); |
256 | free(__iarray_); |
257 | free(__parray_); |
258 | } |
259 | |
260 | // iostate |
261 | |
262 | void |
263 | ios_base::clear(iostate state) |
264 | { |
265 | if (__rdbuf_) |
266 | __rdstate_ = state; |
267 | else |
268 | __rdstate_ = state | badbit; |
269 | |
270 | if (((state | (__rdbuf_ ? goodbit : badbit)) & __exceptions_) != 0) |
271 | __throw_failure("ios_base::clear" ); |
272 | } |
273 | |
274 | // init |
275 | |
276 | void |
277 | ios_base::init(void* sb) |
278 | { |
279 | __rdbuf_ = sb; |
280 | __rdstate_ = __rdbuf_ ? goodbit : badbit; |
281 | __exceptions_ = goodbit; |
282 | __fmtflags_ = skipws | dec; |
283 | __width_ = 0; |
284 | __precision_ = 6; |
285 | __fn_ = 0; |
286 | __index_ = 0; |
287 | __event_size_ = 0; |
288 | __event_cap_ = 0; |
289 | __iarray_ = 0; |
290 | __iarray_size_ = 0; |
291 | __iarray_cap_ = 0; |
292 | __parray_ = 0; |
293 | __parray_size_ = 0; |
294 | __parray_cap_ = 0; |
295 | ::new(&__loc_) locale; |
296 | } |
297 | |
298 | void |
299 | ios_base::copyfmt(const ios_base& rhs) |
300 | { |
301 | // If we can't acquire the needed resources, throw bad_alloc (can't set badbit) |
302 | // Don't alter *this until all needed resources are acquired |
303 | unique_ptr<event_callback, void (*)(void*)> new_callbacks(0, free); |
304 | unique_ptr<int, void (*)(void*)> new_ints(0, free); |
305 | unique_ptr<long, void (*)(void*)> new_longs(0, free); |
306 | unique_ptr<void*, void (*)(void*)> new_pointers(0, free); |
307 | if (__event_cap_ < rhs.__event_size_) |
308 | { |
309 | size_t newesize = sizeof(event_callback) * rhs.__event_size_; |
310 | new_callbacks.reset(static_cast<event_callback*>(malloc(newesize))); |
311 | if (!new_callbacks) |
312 | __throw_bad_alloc(); |
313 | |
314 | size_t newisize = sizeof(int) * rhs.__event_size_; |
315 | new_ints.reset(static_cast<int *>(malloc(newisize))); |
316 | if (!new_ints) |
317 | __throw_bad_alloc(); |
318 | } |
319 | if (__iarray_cap_ < rhs.__iarray_size_) |
320 | { |
321 | size_t newsize = sizeof(long) * rhs.__iarray_size_; |
322 | new_longs.reset(static_cast<long*>(malloc(newsize))); |
323 | if (!new_longs) |
324 | __throw_bad_alloc(); |
325 | } |
326 | if (__parray_cap_ < rhs.__parray_size_) |
327 | { |
328 | size_t newsize = sizeof(void*) * rhs.__parray_size_; |
329 | new_pointers.reset(static_cast<void**>(malloc(newsize))); |
330 | if (!new_pointers) |
331 | __throw_bad_alloc(); |
332 | } |
333 | // Got everything we need. Copy everything but __rdstate_, __rdbuf_ and __exceptions_ |
334 | __fmtflags_ = rhs.__fmtflags_; |
335 | __precision_ = rhs.__precision_; |
336 | __width_ = rhs.__width_; |
337 | locale& lhs_loc = *reinterpret_cast<locale*>(&__loc_); |
338 | const locale& rhs_loc = *reinterpret_cast<const locale*>(&rhs.__loc_); |
339 | lhs_loc = rhs_loc; |
340 | if (__event_cap_ < rhs.__event_size_) |
341 | { |
342 | free(__fn_); |
343 | __fn_ = new_callbacks.release(); |
344 | free(__index_); |
345 | __index_ = new_ints.release(); |
346 | __event_cap_ = rhs.__event_size_; |
347 | } |
348 | for (__event_size_ = 0; __event_size_ < rhs.__event_size_; ++__event_size_) |
349 | { |
350 | __fn_[__event_size_] = rhs.__fn_[__event_size_]; |
351 | __index_[__event_size_] = rhs.__index_[__event_size_]; |
352 | } |
353 | if (__iarray_cap_ < rhs.__iarray_size_) |
354 | { |
355 | free(__iarray_); |
356 | __iarray_ = new_longs.release(); |
357 | __iarray_cap_ = rhs.__iarray_size_; |
358 | } |
359 | for (__iarray_size_ = 0; __iarray_size_ < rhs.__iarray_size_; ++__iarray_size_) |
360 | __iarray_[__iarray_size_] = rhs.__iarray_[__iarray_size_]; |
361 | if (__parray_cap_ < rhs.__parray_size_) |
362 | { |
363 | free(__parray_); |
364 | __parray_ = new_pointers.release(); |
365 | __parray_cap_ = rhs.__parray_size_; |
366 | } |
367 | for (__parray_size_ = 0; __parray_size_ < rhs.__parray_size_; ++__parray_size_) |
368 | __parray_[__parray_size_] = rhs.__parray_[__parray_size_]; |
369 | } |
370 | |
371 | void |
372 | ios_base::move(ios_base& rhs) |
373 | { |
374 | // *this is uninitialized |
375 | __fmtflags_ = rhs.__fmtflags_; |
376 | __precision_ = rhs.__precision_; |
377 | __width_ = rhs.__width_; |
378 | __rdstate_ = rhs.__rdstate_; |
379 | __exceptions_ = rhs.__exceptions_; |
380 | __rdbuf_ = 0; |
381 | locale& rhs_loc = *reinterpret_cast<locale*>(&rhs.__loc_); |
382 | ::new(&__loc_) locale(rhs_loc); |
383 | __fn_ = rhs.__fn_; |
384 | rhs.__fn_ = 0; |
385 | __index_ = rhs.__index_; |
386 | rhs.__index_ = 0; |
387 | __event_size_ = rhs.__event_size_; |
388 | rhs.__event_size_ = 0; |
389 | __event_cap_ = rhs.__event_cap_; |
390 | rhs.__event_cap_ = 0; |
391 | __iarray_ = rhs.__iarray_; |
392 | rhs.__iarray_ = 0; |
393 | __iarray_size_ = rhs.__iarray_size_; |
394 | rhs.__iarray_size_ = 0; |
395 | __iarray_cap_ = rhs.__iarray_cap_; |
396 | rhs.__iarray_cap_ = 0; |
397 | __parray_ = rhs.__parray_; |
398 | rhs.__parray_ = 0; |
399 | __parray_size_ = rhs.__parray_size_; |
400 | rhs.__parray_size_ = 0; |
401 | __parray_cap_ = rhs.__parray_cap_; |
402 | rhs.__parray_cap_ = 0; |
403 | } |
404 | |
405 | void |
406 | ios_base::swap(ios_base& rhs) _NOEXCEPT |
407 | { |
408 | _VSTD::swap(__fmtflags_, rhs.__fmtflags_); |
409 | _VSTD::swap(__precision_, rhs.__precision_); |
410 | _VSTD::swap(__width_, rhs.__width_); |
411 | _VSTD::swap(__rdstate_, rhs.__rdstate_); |
412 | _VSTD::swap(__exceptions_, rhs.__exceptions_); |
413 | locale& lhs_loc = *reinterpret_cast<locale*>(&__loc_); |
414 | locale& rhs_loc = *reinterpret_cast<locale*>(&rhs.__loc_); |
415 | _VSTD::swap(lhs_loc, rhs_loc); |
416 | _VSTD::swap(__fn_, rhs.__fn_); |
417 | _VSTD::swap(__index_, rhs.__index_); |
418 | _VSTD::swap(__event_size_, rhs.__event_size_); |
419 | _VSTD::swap(__event_cap_, rhs.__event_cap_); |
420 | _VSTD::swap(__iarray_, rhs.__iarray_); |
421 | _VSTD::swap(__iarray_size_, rhs.__iarray_size_); |
422 | _VSTD::swap(__iarray_cap_, rhs.__iarray_cap_); |
423 | _VSTD::swap(__parray_, rhs.__parray_); |
424 | _VSTD::swap(__parray_size_, rhs.__parray_size_); |
425 | _VSTD::swap(__parray_cap_, rhs.__parray_cap_); |
426 | } |
427 | |
428 | void |
429 | ios_base::__set_badbit_and_consider_rethrow() |
430 | { |
431 | __rdstate_ |= badbit; |
432 | #ifndef _LIBCPP_NO_EXCEPTIONS |
433 | if (__exceptions_ & badbit) |
434 | throw; |
435 | #endif // _LIBCPP_NO_EXCEPTIONS |
436 | } |
437 | |
438 | void |
439 | ios_base::__set_failbit_and_consider_rethrow() |
440 | { |
441 | __rdstate_ |= failbit; |
442 | #ifndef _LIBCPP_NO_EXCEPTIONS |
443 | if (__exceptions_ & failbit) |
444 | throw; |
445 | #endif // _LIBCPP_NO_EXCEPTIONS |
446 | } |
447 | |
448 | bool |
449 | ios_base::sync_with_stdio(bool sync) |
450 | { |
451 | static bool previous_state = true; |
452 | bool r = previous_state; |
453 | previous_state = sync; |
454 | return r; |
455 | } |
456 | |
457 | _LIBCPP_END_NAMESPACE_STD |
458 | |