1 | // -*- C++ -*- |
2 | //===----------------------------------------------------------------------===// |
3 | // |
4 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
5 | // See https://llvm.org/LICENSE.txt for license information. |
6 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
7 | // |
8 | //===----------------------------------------------------------------------===// |
9 | |
10 | #ifndef _LIBCPP___STD_STREAM |
11 | #define _LIBCPP___STD_STREAM |
12 | |
13 | #include <__config> |
14 | #include <ostream> |
15 | #include <istream> |
16 | #include <__locale> |
17 | #include <cstdio> |
18 | |
19 | #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) |
20 | #pragma GCC system_header |
21 | #endif |
22 | |
23 | _LIBCPP_PUSH_MACROS |
24 | #include <__undef_macros> |
25 | |
26 | |
27 | _LIBCPP_BEGIN_NAMESPACE_STD |
28 | |
29 | static const int __limit = 8; |
30 | |
31 | // __stdinbuf |
32 | |
33 | template <class _CharT> |
34 | class _LIBCPP_HIDDEN __stdinbuf |
35 | : public basic_streambuf<_CharT, char_traits<_CharT> > |
36 | { |
37 | public: |
38 | typedef _CharT char_type; |
39 | typedef char_traits<char_type> traits_type; |
40 | typedef typename traits_type::int_type int_type; |
41 | typedef typename traits_type::pos_type pos_type; |
42 | typedef typename traits_type::off_type off_type; |
43 | typedef typename traits_type::state_type state_type; |
44 | |
45 | __stdinbuf(FILE* __fp, state_type* __st); |
46 | |
47 | protected: |
48 | virtual int_type underflow(); |
49 | virtual int_type uflow(); |
50 | virtual int_type pbackfail(int_type __c = traits_type::eof()); |
51 | virtual void imbue(const locale& __loc); |
52 | |
53 | private: |
54 | |
55 | FILE* __file_; |
56 | const codecvt<char_type, char, state_type>* __cv_; |
57 | state_type* __st_; |
58 | int __encoding_; |
59 | int_type __last_consumed_; |
60 | bool __last_consumed_is_next_; |
61 | bool __always_noconv_; |
62 | |
63 | __stdinbuf(const __stdinbuf&); |
64 | __stdinbuf& operator=(const __stdinbuf&); |
65 | |
66 | int_type __getchar(bool __consume); |
67 | }; |
68 | |
69 | template <class _CharT> |
70 | __stdinbuf<_CharT>::__stdinbuf(FILE* __fp, state_type* __st) |
71 | : __file_(__fp), |
72 | __st_(__st), |
73 | __last_consumed_(traits_type::eof()), |
74 | __last_consumed_is_next_(false) |
75 | { |
76 | imbue(this->getloc()); |
77 | } |
78 | |
79 | template <class _CharT> |
80 | void |
81 | __stdinbuf<_CharT>::imbue(const locale& __loc) |
82 | { |
83 | __cv_ = &use_facet<codecvt<char_type, char, state_type> >(__loc); |
84 | __encoding_ = __cv_->encoding(); |
85 | __always_noconv_ = __cv_->always_noconv(); |
86 | if (__encoding_ > __limit) |
87 | __throw_runtime_error("unsupported locale for standard input" ); |
88 | } |
89 | |
90 | template <class _CharT> |
91 | typename __stdinbuf<_CharT>::int_type |
92 | __stdinbuf<_CharT>::underflow() |
93 | { |
94 | return __getchar(false); |
95 | } |
96 | |
97 | template <class _CharT> |
98 | typename __stdinbuf<_CharT>::int_type |
99 | __stdinbuf<_CharT>::uflow() |
100 | { |
101 | return __getchar(true); |
102 | } |
103 | |
104 | template <class _CharT> |
105 | typename __stdinbuf<_CharT>::int_type |
106 | __stdinbuf<_CharT>::__getchar(bool __consume) |
107 | { |
108 | if (__last_consumed_is_next_) |
109 | { |
110 | int_type __result = __last_consumed_; |
111 | if (__consume) |
112 | { |
113 | __last_consumed_ = traits_type::eof(); |
114 | __last_consumed_is_next_ = false; |
115 | } |
116 | return __result; |
117 | } |
118 | char __extbuf[__limit]; |
119 | int __nread = _VSTD::max(1, __encoding_); |
120 | for (int __i = 0; __i < __nread; ++__i) |
121 | { |
122 | int __c = getc(__file_); |
123 | if (__c == EOF) |
124 | return traits_type::eof(); |
125 | __extbuf[__i] = static_cast<char>(__c); |
126 | } |
127 | char_type __1buf; |
128 | if (__always_noconv_) |
129 | __1buf = static_cast<char_type>(__extbuf[0]); |
130 | else |
131 | { |
132 | const char* __enxt; |
133 | char_type* __inxt; |
134 | codecvt_base::result __r; |
135 | do |
136 | { |
137 | state_type __sv_st = *__st_; |
138 | __r = __cv_->in(*__st_, __extbuf, __extbuf + __nread, __enxt, |
139 | &__1buf, &__1buf + 1, __inxt); |
140 | switch (__r) |
141 | { |
142 | case _VSTD::codecvt_base::ok: |
143 | break; |
144 | case codecvt_base::partial: |
145 | *__st_ = __sv_st; |
146 | if (__nread == sizeof(__extbuf)) |
147 | return traits_type::eof(); |
148 | { |
149 | int __c = getc(__file_); |
150 | if (__c == EOF) |
151 | return traits_type::eof(); |
152 | __extbuf[__nread] = static_cast<char>(__c); |
153 | } |
154 | ++__nread; |
155 | break; |
156 | case codecvt_base::error: |
157 | return traits_type::eof(); |
158 | case _VSTD::codecvt_base::noconv: |
159 | __1buf = static_cast<char_type>(__extbuf[0]); |
160 | break; |
161 | } |
162 | } while (__r == _VSTD::codecvt_base::partial); |
163 | } |
164 | if (!__consume) |
165 | { |
166 | for (int __i = __nread; __i > 0;) |
167 | { |
168 | if (ungetc(traits_type::to_int_type(__extbuf[--__i]), __file_) == EOF) |
169 | return traits_type::eof(); |
170 | } |
171 | } |
172 | else |
173 | __last_consumed_ = traits_type::to_int_type(__1buf); |
174 | return traits_type::to_int_type(__1buf); |
175 | } |
176 | |
177 | template <class _CharT> |
178 | typename __stdinbuf<_CharT>::int_type |
179 | __stdinbuf<_CharT>::pbackfail(int_type __c) |
180 | { |
181 | if (traits_type::eq_int_type(__c, traits_type::eof())) |
182 | { |
183 | if (!__last_consumed_is_next_) |
184 | { |
185 | __c = __last_consumed_; |
186 | __last_consumed_is_next_ = !traits_type::eq_int_type(__last_consumed_, |
187 | traits_type::eof()); |
188 | } |
189 | return __c; |
190 | } |
191 | if (__last_consumed_is_next_) |
192 | { |
193 | char __extbuf[__limit]; |
194 | char* __enxt; |
195 | const char_type __ci = traits_type::to_char_type(__last_consumed_); |
196 | const char_type* __inxt; |
197 | switch (__cv_->out(*__st_, &__ci, &__ci + 1, __inxt, |
198 | __extbuf, __extbuf + sizeof(__extbuf), __enxt)) |
199 | { |
200 | case _VSTD::codecvt_base::ok: |
201 | break; |
202 | case _VSTD::codecvt_base::noconv: |
203 | __extbuf[0] = static_cast<char>(__last_consumed_); |
204 | __enxt = __extbuf + 1; |
205 | break; |
206 | case codecvt_base::partial: |
207 | case codecvt_base::error: |
208 | return traits_type::eof(); |
209 | } |
210 | while (__enxt > __extbuf) |
211 | if (ungetc(*--__enxt, __file_) == EOF) |
212 | return traits_type::eof(); |
213 | } |
214 | __last_consumed_ = __c; |
215 | __last_consumed_is_next_ = true; |
216 | return __c; |
217 | } |
218 | |
219 | // __stdoutbuf |
220 | |
221 | template <class _CharT> |
222 | class _LIBCPP_HIDDEN __stdoutbuf |
223 | : public basic_streambuf<_CharT, char_traits<_CharT> > |
224 | { |
225 | public: |
226 | typedef _CharT char_type; |
227 | typedef char_traits<char_type> traits_type; |
228 | typedef typename traits_type::int_type int_type; |
229 | typedef typename traits_type::pos_type pos_type; |
230 | typedef typename traits_type::off_type off_type; |
231 | typedef typename traits_type::state_type state_type; |
232 | |
233 | __stdoutbuf(FILE* __fp, state_type* __st); |
234 | |
235 | protected: |
236 | virtual int_type overflow (int_type __c = traits_type::eof()); |
237 | virtual streamsize xsputn(const char_type* __s, streamsize __n); |
238 | virtual int sync(); |
239 | virtual void imbue(const locale& __loc); |
240 | |
241 | private: |
242 | FILE* __file_; |
243 | const codecvt<char_type, char, state_type>* __cv_; |
244 | state_type* __st_; |
245 | bool __always_noconv_; |
246 | |
247 | __stdoutbuf(const __stdoutbuf&); |
248 | __stdoutbuf& operator=(const __stdoutbuf&); |
249 | }; |
250 | |
251 | template <class _CharT> |
252 | __stdoutbuf<_CharT>::__stdoutbuf(FILE* __fp, state_type* __st) |
253 | : __file_(__fp), |
254 | __cv_(&use_facet<codecvt<char_type, char, state_type> >(this->getloc())), |
255 | __st_(__st), |
256 | __always_noconv_(__cv_->always_noconv()) |
257 | { |
258 | } |
259 | |
260 | template <class _CharT> |
261 | typename __stdoutbuf<_CharT>::int_type |
262 | __stdoutbuf<_CharT>::overflow(int_type __c) |
263 | { |
264 | char __extbuf[__limit]; |
265 | char_type __1buf; |
266 | if (!traits_type::eq_int_type(__c, traits_type::eof())) |
267 | { |
268 | __1buf = traits_type::to_char_type(__c); |
269 | if (__always_noconv_) |
270 | { |
271 | if (fwrite(&__1buf, sizeof(char_type), 1, __file_) != 1) |
272 | return traits_type::eof(); |
273 | } |
274 | else |
275 | { |
276 | char* __extbe = __extbuf; |
277 | codecvt_base::result __r; |
278 | char_type* pbase = &__1buf; |
279 | char_type* pptr = pbase + 1; |
280 | do |
281 | { |
282 | const char_type* __e; |
283 | __r = __cv_->out(*__st_, pbase, pptr, __e, |
284 | __extbuf, |
285 | __extbuf + sizeof(__extbuf), |
286 | __extbe); |
287 | if (__e == pbase) |
288 | return traits_type::eof(); |
289 | if (__r == codecvt_base::noconv) |
290 | { |
291 | if (fwrite(pbase, 1, 1, __file_) != 1) |
292 | return traits_type::eof(); |
293 | } |
294 | else if (__r == codecvt_base::ok || __r == codecvt_base::partial) |
295 | { |
296 | size_t __nmemb = static_cast<size_t>(__extbe - __extbuf); |
297 | if (fwrite(__extbuf, 1, __nmemb, __file_) != __nmemb) |
298 | return traits_type::eof(); |
299 | if (__r == codecvt_base::partial) |
300 | { |
301 | pbase = const_cast<char_type*>(__e); |
302 | } |
303 | } |
304 | else |
305 | return traits_type::eof(); |
306 | } while (__r == codecvt_base::partial); |
307 | } |
308 | } |
309 | return traits_type::not_eof(__c); |
310 | } |
311 | |
312 | template <class _CharT> |
313 | streamsize |
314 | __stdoutbuf<_CharT>::xsputn(const char_type* __s, streamsize __n) |
315 | { |
316 | if (__always_noconv_) |
317 | return fwrite(__s, sizeof(char_type), __n, __file_); |
318 | streamsize __i = 0; |
319 | for (; __i < __n; ++__i, ++__s) |
320 | if (overflow(traits_type::to_int_type(*__s)) == traits_type::eof()) |
321 | break; |
322 | return __i; |
323 | } |
324 | |
325 | template <class _CharT> |
326 | int |
327 | __stdoutbuf<_CharT>::sync() |
328 | { |
329 | char __extbuf[__limit]; |
330 | codecvt_base::result __r; |
331 | do |
332 | { |
333 | char* __extbe; |
334 | __r = __cv_->unshift(*__st_, __extbuf, |
335 | __extbuf + sizeof(__extbuf), |
336 | __extbe); |
337 | size_t __nmemb = static_cast<size_t>(__extbe - __extbuf); |
338 | if (fwrite(__extbuf, 1, __nmemb, __file_) != __nmemb) |
339 | return -1; |
340 | } while (__r == codecvt_base::partial); |
341 | if (__r == codecvt_base::error) |
342 | return -1; |
343 | if (fflush(__file_)) |
344 | return -1; |
345 | return 0; |
346 | } |
347 | |
348 | template <class _CharT> |
349 | void |
350 | __stdoutbuf<_CharT>::imbue(const locale& __loc) |
351 | { |
352 | sync(); |
353 | __cv_ = &use_facet<codecvt<char_type, char, state_type> >(__loc); |
354 | __always_noconv_ = __cv_->always_noconv(); |
355 | } |
356 | |
357 | _LIBCPP_END_NAMESPACE_STD |
358 | |
359 | _LIBCPP_POP_MACROS |
360 | |
361 | #endif // _LIBCPP___STD_STREAM |
362 | |