2 //===----------------------------------------------------------------------===//
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
8 //===----------------------------------------------------------------------===//
10 #ifndef _LIBCPP_STD_STREAM_H
11 #define _LIBCPP_STD_STREAM_H
19 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
20 # pragma GCC system_header
24 #include <__undef_macros>
27 _LIBCPP_BEGIN_NAMESPACE_STD
29 static const int __limit
= 8;
33 template <class _CharT
>
34 class _LIBCPP_HIDDEN __stdinbuf
35 : public basic_streambuf
<_CharT
, char_traits
<_CharT
> >
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
;
45 __stdinbuf(FILE* __fp
, state_type
* __st
);
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
);
56 const codecvt
<char_type
, char, state_type
>* __cv_
;
59 int_type __last_consumed_
;
60 bool __last_consumed_is_next_
;
61 bool __always_noconv_
;
63 #if defined(_LIBCPP_WIN32API)
64 static constexpr bool __is_win32api_wide_char
= !is_same_v
<_CharT
, char>;
66 static constexpr bool __is_win32api_wide_char
= false;
69 __stdinbuf(const __stdinbuf
&);
70 __stdinbuf
& operator=(const __stdinbuf
&);
72 int_type
__getchar(bool __consume
);
75 template <class _CharT
>
76 __stdinbuf
<_CharT
>::__stdinbuf(FILE* __fp
, state_type
* __st
)
79 __last_consumed_(traits_type::eof()),
80 __last_consumed_is_next_(false)
82 imbue(this->getloc());
83 // On Windows, in wchar_t mode, ignore the codecvt from the locale by
84 // default and assume noconv; this passes wchar_t through unmodified from
85 // getwc. If the user sets a custom locale with imbue(), that gets honored,
86 // the IO is done with getc() and converted with the provided codecvt.
87 if constexpr (__is_win32api_wide_char
)
88 __always_noconv_
= true;
91 template <class _CharT
>
93 __stdinbuf
<_CharT
>::imbue(const locale
& __loc
)
95 __cv_
= &use_facet
<codecvt
<char_type
, char, state_type
> >(__loc
);
96 __encoding_
= __cv_
->encoding();
97 __always_noconv_
= __cv_
->always_noconv();
98 if (__encoding_
> __limit
)
99 __throw_runtime_error("unsupported locale for standard input");
102 template <class _CharT
>
103 typename __stdinbuf
<_CharT
>::int_type
104 __stdinbuf
<_CharT
>::underflow()
106 return __getchar(false);
109 template <class _CharT
>
110 typename __stdinbuf
<_CharT
>::int_type
111 __stdinbuf
<_CharT
>::uflow()
113 return __getchar(true);
116 inline bool __do_getc(FILE *__fp
, char *__pbuf
) {
117 int __c
= getc(__fp
);
120 *__pbuf
= static_cast<char>(__c
);
123 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
124 inline bool __do_getc(FILE *__fp
, wchar_t *__pbuf
) {
125 wint_t __c
= getwc(__fp
);
128 *__pbuf
= static_cast<wchar_t>(__c
);
133 inline bool __do_ungetc(int __c
, FILE *__fp
, char __dummy
) {
134 if (ungetc(__c
, __fp
) == EOF
)
138 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
139 inline bool __do_ungetc(std::wint_t __c
, FILE *__fp
, wchar_t __dummy
) {
140 if (ungetwc(__c
, __fp
) == WEOF
)
146 template <class _CharT
>
147 typename __stdinbuf
<_CharT
>::int_type
148 __stdinbuf
<_CharT
>::__getchar(bool __consume
)
150 if (__last_consumed_is_next_
)
152 int_type __result
= __last_consumed_
;
155 __last_consumed_
= traits_type::eof();
156 __last_consumed_is_next_
= false;
160 if (__always_noconv_
) {
162 if (!__do_getc(__file_
, &__1buf
))
163 return traits_type::eof();
166 if (!__do_ungetc(traits_type::to_int_type(__1buf
), __file_
, __1buf
))
167 return traits_type::eof();
170 __last_consumed_
= traits_type::to_int_type(__1buf
);
171 return traits_type::to_int_type(__1buf
);
174 char __extbuf
[__limit
];
175 int __nread
= _VSTD::max(1, __encoding_
);
176 for (int __i
= 0; __i
< __nread
; ++__i
)
178 int __c
= getc(__file_
);
180 return traits_type::eof();
181 __extbuf
[__i
] = static_cast<char>(__c
);
186 codecvt_base::result __r
;
189 state_type __sv_st
= *__st_
;
190 __r
= __cv_
->in(*__st_
, __extbuf
, __extbuf
+ __nread
, __enxt
,
191 &__1buf
, &__1buf
+ 1, __inxt
);
194 case _VSTD::codecvt_base::ok
:
196 case codecvt_base::partial
:
198 if (__nread
== sizeof(__extbuf
))
199 return traits_type::eof();
201 int __c
= getc(__file_
);
203 return traits_type::eof();
204 __extbuf
[__nread
] = static_cast<char>(__c
);
208 case codecvt_base::error
:
209 return traits_type::eof();
210 case _VSTD::codecvt_base::noconv
:
211 __1buf
= static_cast<char_type
>(__extbuf
[0]);
214 } while (__r
== _VSTD::codecvt_base::partial
);
217 for (int __i
= __nread
; __i
> 0;)
219 if (ungetc(traits_type::to_int_type(__extbuf
[--__i
]), __file_
) == EOF
)
220 return traits_type::eof();
224 __last_consumed_
= traits_type::to_int_type(__1buf
);
225 return traits_type::to_int_type(__1buf
);
228 template <class _CharT
>
229 typename __stdinbuf
<_CharT
>::int_type
230 __stdinbuf
<_CharT
>::pbackfail(int_type __c
)
232 if (traits_type::eq_int_type(__c
, traits_type::eof()))
234 if (!__last_consumed_is_next_
)
236 __c
= __last_consumed_
;
237 __last_consumed_is_next_
= !traits_type::eq_int_type(__last_consumed_
,
242 if (__always_noconv_
&& __last_consumed_is_next_
) {
243 if (!__do_ungetc(__last_consumed_
, __file_
,
244 traits_type::to_char_type(__last_consumed_
)))
245 return traits_type::eof();
246 } else if (__last_consumed_is_next_
) {
247 char __extbuf
[__limit
];
249 const char_type __ci
= traits_type::to_char_type(__last_consumed_
);
250 const char_type
* __inxt
;
251 switch (__cv_
->out(*__st_
, &__ci
, &__ci
+ 1, __inxt
,
252 __extbuf
, __extbuf
+ sizeof(__extbuf
), __enxt
))
254 case _VSTD::codecvt_base::ok
:
256 case _VSTD::codecvt_base::noconv
:
257 __extbuf
[0] = static_cast<char>(__last_consumed_
);
258 __enxt
= __extbuf
+ 1;
260 case codecvt_base::partial
:
261 case codecvt_base::error
:
262 return traits_type::eof();
264 while (__enxt
> __extbuf
)
265 if (ungetc(*--__enxt
, __file_
) == EOF
)
266 return traits_type::eof();
268 __last_consumed_
= __c
;
269 __last_consumed_is_next_
= true;
275 template <class _CharT
>
276 class _LIBCPP_HIDDEN __stdoutbuf
277 : public basic_streambuf
<_CharT
, char_traits
<_CharT
> >
280 typedef _CharT char_type
;
281 typedef char_traits
<char_type
> traits_type
;
282 typedef typename
traits_type::int_type int_type
;
283 typedef typename
traits_type::pos_type pos_type
;
284 typedef typename
traits_type::off_type off_type
;
285 typedef typename
traits_type::state_type state_type
;
287 __stdoutbuf(FILE* __fp
, state_type
* __st
);
290 virtual int_type
overflow (int_type __c
= traits_type::eof());
291 virtual streamsize
xsputn(const char_type
* __s
, streamsize __n
);
293 virtual void imbue(const locale
& __loc
);
297 const codecvt
<char_type
, char, state_type
>* __cv_
;
299 bool __always_noconv_
;
301 #if defined(_LIBCPP_WIN32API)
302 static constexpr bool __is_win32api_wide_char
= !is_same_v
<_CharT
, char>;
304 static constexpr bool __is_win32api_wide_char
= false;
307 __stdoutbuf(const __stdoutbuf
&);
308 __stdoutbuf
& operator=(const __stdoutbuf
&);
311 template <class _CharT
>
312 __stdoutbuf
<_CharT
>::__stdoutbuf(FILE* __fp
, state_type
* __st
)
314 __cv_(&use_facet
<codecvt
<char_type
, char, state_type
> >(this->getloc())),
316 __always_noconv_(__cv_
->always_noconv())
318 // On Windows, in wchar_t mode, ignore the codecvt from the locale by
319 // default and assume noconv; this passes wchar_t through unmodified to
320 // fputwc, which handles it correctly depending on the actual mode of the
321 // output stream. If the user sets a custom locale with imbue(), that
323 if constexpr (__is_win32api_wide_char
)
324 __always_noconv_
= true;
327 inline bool __do_fputc(char __c
, FILE* __fp
) {
328 if (fwrite(&__c
, sizeof(__c
), 1, __fp
) != 1)
332 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
333 inline bool __do_fputc(wchar_t __c
, FILE* __fp
) {
334 // fputwc works regardless of wide/narrow mode of stdout, while
335 // fwrite of wchar_t only works if the stream actually has been set
337 if (fputwc(__c
, __fp
) == WEOF
)
343 template <class _CharT
>
344 typename __stdoutbuf
<_CharT
>::int_type
345 __stdoutbuf
<_CharT
>::overflow(int_type __c
)
347 char __extbuf
[__limit
];
349 if (!traits_type::eq_int_type(__c
, traits_type::eof()))
351 __1buf
= traits_type::to_char_type(__c
);
352 if (__always_noconv_
)
354 if (!__do_fputc(__1buf
, __file_
))
355 return traits_type::eof();
359 char* __extbe
= __extbuf
;
360 codecvt_base::result __r
;
361 char_type
* pbase
= &__1buf
;
362 char_type
* pptr
= pbase
+ 1;
365 const char_type
* __e
;
366 __r
= __cv_
->out(*__st_
, pbase
, pptr
, __e
,
368 __extbuf
+ sizeof(__extbuf
),
371 return traits_type::eof();
372 if (__r
== codecvt_base::noconv
)
374 if (fwrite(pbase
, 1, 1, __file_
) != 1)
375 return traits_type::eof();
377 else if (__r
== codecvt_base::ok
|| __r
== codecvt_base::partial
)
379 size_t __nmemb
= static_cast<size_t>(__extbe
- __extbuf
);
380 if (fwrite(__extbuf
, 1, __nmemb
, __file_
) != __nmemb
)
381 return traits_type::eof();
382 if (__r
== codecvt_base::partial
)
384 pbase
= const_cast<char_type
*>(__e
);
388 return traits_type::eof();
389 } while (__r
== codecvt_base::partial
);
392 return traits_type::not_eof(__c
);
395 template <class _CharT
>
397 __stdoutbuf
<_CharT
>::xsputn(const char_type
* __s
, streamsize __n
)
399 // For wchar_t on Windows, don't call fwrite(), but write characters one
400 // at a time with fputwc(); that works both when stdout is in the default
401 // mode and when it is set to Unicode mode.
402 if (__always_noconv_
&& !__is_win32api_wide_char
)
403 return fwrite(__s
, sizeof(char_type
), __n
, __file_
);
405 for (; __i
< __n
; ++__i
, ++__s
)
406 if (overflow(traits_type::to_int_type(*__s
)) == traits_type::eof())
411 template <class _CharT
>
413 __stdoutbuf
<_CharT
>::sync()
415 char __extbuf
[__limit
];
416 codecvt_base::result __r
;
420 __r
= __cv_
->unshift(*__st_
, __extbuf
,
421 __extbuf
+ sizeof(__extbuf
),
423 size_t __nmemb
= static_cast<size_t>(__extbe
- __extbuf
);
424 if (fwrite(__extbuf
, 1, __nmemb
, __file_
) != __nmemb
)
426 } while (__r
== codecvt_base::partial
);
427 if (__r
== codecvt_base::error
)
434 template <class _CharT
>
436 __stdoutbuf
<_CharT
>::imbue(const locale
& __loc
)
439 __cv_
= &use_facet
<codecvt
<char_type
, char, state_type
> >(__loc
);
440 __always_noconv_
= __cv_
->always_noconv();
443 _LIBCPP_END_NAMESPACE_STD
447 #endif // _LIBCPP_STD_STREAM_H