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>
26 _LIBCPP_BEGIN_NAMESPACE_STD
28 static const int __limit
= 8;
32 template <class _CharT
>
33 class _LIBCPP_HIDDEN __stdinbuf
: public basic_streambuf
<_CharT
, char_traits
<_CharT
> > {
35 typedef _CharT char_type
;
36 typedef char_traits
<char_type
> traits_type
;
37 typedef typename
traits_type::int_type int_type
;
38 typedef typename
traits_type::pos_type pos_type
;
39 typedef typename
traits_type::off_type off_type
;
40 typedef typename
traits_type::state_type state_type
;
42 __stdinbuf(FILE* __fp
, state_type
* __st
);
45 virtual int_type
underflow();
46 virtual int_type
uflow();
47 virtual int_type
pbackfail(int_type __c
= traits_type::eof());
48 virtual void imbue(const locale
& __loc
);
52 const codecvt
<char_type
, char, state_type
>* __cv_
;
55 int_type __last_consumed_
;
56 bool __last_consumed_is_next_
;
57 bool __always_noconv_
;
59 #if defined(_LIBCPP_WIN32API)
60 static constexpr bool __is_win32api_wide_char
= !is_same_v
<_CharT
, char>;
62 static constexpr bool __is_win32api_wide_char
= false;
65 __stdinbuf(const __stdinbuf
&);
66 __stdinbuf
& operator=(const __stdinbuf
&);
68 int_type
__getchar(bool __consume
);
71 template <class _CharT
>
72 __stdinbuf
<_CharT
>::__stdinbuf(FILE* __fp
, state_type
* __st
)
73 : __file_(__fp
), __st_(__st
), __last_consumed_(traits_type::eof()), __last_consumed_is_next_(false) {
74 imbue(this->getloc());
75 // On Windows, in wchar_t mode, ignore the codecvt from the locale by
76 // default and assume noconv; this passes wchar_t through unmodified from
77 // getwc. If the user sets a custom locale with imbue(), that gets honored,
78 // the IO is done with getc() and converted with the provided codecvt.
79 if constexpr (__is_win32api_wide_char
)
80 __always_noconv_
= true;
83 template <class _CharT
>
84 void __stdinbuf
<_CharT
>::imbue(const locale
& __loc
) {
85 __cv_
= &use_facet
<codecvt
<char_type
, char, state_type
> >(__loc
);
86 __encoding_
= __cv_
->encoding();
87 __always_noconv_
= __cv_
->always_noconv();
88 if (__encoding_
> __limit
)
89 __throw_runtime_error("unsupported locale for standard input");
92 template <class _CharT
>
93 typename __stdinbuf
<_CharT
>::int_type __stdinbuf
<_CharT
>::underflow() {
94 return __getchar(false);
97 template <class _CharT
>
98 typename __stdinbuf
<_CharT
>::int_type __stdinbuf
<_CharT
>::uflow() {
99 return __getchar(true);
102 inline bool __do_getc(FILE* __fp
, char* __pbuf
) {
103 int __c
= getc(__fp
);
106 *__pbuf
= static_cast<char>(__c
);
109 #if _LIBCPP_HAS_WIDE_CHARACTERS
110 inline bool __do_getc(FILE* __fp
, wchar_t* __pbuf
) {
111 wint_t __c
= getwc(__fp
);
114 *__pbuf
= static_cast<wchar_t>(__c
);
119 inline bool __do_ungetc(int __c
, FILE* __fp
, char __dummy
) {
120 if (ungetc(__c
, __fp
) == EOF
)
124 #if _LIBCPP_HAS_WIDE_CHARACTERS
125 inline bool __do_ungetc(std::wint_t __c
, FILE* __fp
, wchar_t __dummy
) {
126 if (ungetwc(__c
, __fp
) == WEOF
)
132 template <class _CharT
>
133 typename __stdinbuf
<_CharT
>::int_type __stdinbuf
<_CharT
>::__getchar(bool __consume
) {
134 if (__last_consumed_is_next_
) {
135 int_type __result
= __last_consumed_
;
137 __last_consumed_
= traits_type::eof();
138 __last_consumed_is_next_
= false;
142 if (__always_noconv_
) {
144 if (!__do_getc(__file_
, &__1buf
))
145 return traits_type::eof();
147 if (!__do_ungetc(traits_type::to_int_type(__1buf
), __file_
, __1buf
))
148 return traits_type::eof();
150 __last_consumed_
= traits_type::to_int_type(__1buf
);
151 return traits_type::to_int_type(__1buf
);
154 char __extbuf
[__limit
];
155 int __nread
= std::max(1, __encoding_
);
156 for (int __i
= 0; __i
< __nread
; ++__i
) {
157 int __c
= getc(__file_
);
159 return traits_type::eof();
160 __extbuf
[__i
] = static_cast<char>(__c
);
165 codecvt_base::result __r
;
167 state_type __sv_st
= *__st_
;
168 __r
= __cv_
->in(*__st_
, __extbuf
, __extbuf
+ __nread
, __enxt
, &__1buf
, &__1buf
+ 1, __inxt
);
170 case std::codecvt_base::ok
:
172 case codecvt_base::partial
:
174 if (__nread
== sizeof(__extbuf
))
175 return traits_type::eof();
177 int __c
= getc(__file_
);
179 return traits_type::eof();
180 __extbuf
[__nread
] = static_cast<char>(__c
);
184 case codecvt_base::error
:
185 return traits_type::eof();
186 case std::codecvt_base::noconv
:
187 __1buf
= static_cast<char_type
>(__extbuf
[0]);
190 } while (__r
== std::codecvt_base::partial
);
192 for (int __i
= __nread
; __i
> 0;) {
193 if (ungetc(traits_type::to_int_type(__extbuf
[--__i
]), __file_
) == EOF
)
194 return traits_type::eof();
197 __last_consumed_
= traits_type::to_int_type(__1buf
);
198 return traits_type::to_int_type(__1buf
);
201 template <class _CharT
>
202 typename __stdinbuf
<_CharT
>::int_type __stdinbuf
<_CharT
>::pbackfail(int_type __c
) {
203 if (traits_type::eq_int_type(__c
, traits_type::eof())) {
204 if (!__last_consumed_is_next_
) {
205 __c
= __last_consumed_
;
206 __last_consumed_is_next_
= !traits_type::eq_int_type(__last_consumed_
, traits_type::eof());
210 if (__always_noconv_
&& __last_consumed_is_next_
) {
211 if (!__do_ungetc(__last_consumed_
, __file_
, traits_type::to_char_type(__last_consumed_
)))
212 return traits_type::eof();
213 } else if (__last_consumed_is_next_
) {
214 char __extbuf
[__limit
];
216 const char_type __ci
= traits_type::to_char_type(__last_consumed_
);
217 const char_type
* __inxt
;
218 switch (__cv_
->out(*__st_
, &__ci
, &__ci
+ 1, __inxt
, __extbuf
, __extbuf
+ sizeof(__extbuf
), __enxt
)) {
219 case std::codecvt_base::ok
:
221 case std::codecvt_base::noconv
:
222 __extbuf
[0] = static_cast<char>(__last_consumed_
);
223 __enxt
= __extbuf
+ 1;
225 case codecvt_base::partial
:
226 case codecvt_base::error
:
227 return traits_type::eof();
229 while (__enxt
> __extbuf
)
230 if (ungetc(*--__enxt
, __file_
) == EOF
)
231 return traits_type::eof();
233 __last_consumed_
= __c
;
234 __last_consumed_is_next_
= true;
240 template <class _CharT
>
241 class _LIBCPP_HIDDEN __stdoutbuf
: public basic_streambuf
<_CharT
, char_traits
<_CharT
> > {
243 typedef _CharT char_type
;
244 typedef char_traits
<char_type
> traits_type
;
245 typedef typename
traits_type::int_type int_type
;
246 typedef typename
traits_type::pos_type pos_type
;
247 typedef typename
traits_type::off_type off_type
;
248 typedef typename
traits_type::state_type state_type
;
250 __stdoutbuf(FILE* __fp
, state_type
* __st
);
253 virtual int_type
overflow(int_type __c
= traits_type::eof());
254 virtual streamsize
xsputn(const char_type
* __s
, streamsize __n
);
256 virtual void imbue(const locale
& __loc
);
260 const codecvt
<char_type
, char, state_type
>* __cv_
;
262 bool __always_noconv_
;
264 #if defined(_LIBCPP_WIN32API)
265 static constexpr bool __is_win32api_wide_char
= !is_same_v
<_CharT
, char>;
267 static constexpr bool __is_win32api_wide_char
= false;
270 __stdoutbuf(const __stdoutbuf
&);
271 __stdoutbuf
& operator=(const __stdoutbuf
&);
273 _LIBCPP_EXPORTED_FROM_ABI
friend FILE* __get_ostream_file(ostream
&);
276 template <class _CharT
>
277 __stdoutbuf
<_CharT
>::__stdoutbuf(FILE* __fp
, state_type
* __st
)
279 __cv_(&use_facet
<codecvt
<char_type
, char, state_type
> >(this->getloc())),
281 __always_noconv_(__cv_
->always_noconv()) {
282 // On Windows, in wchar_t mode, ignore the codecvt from the locale by
283 // default and assume noconv; this passes wchar_t through unmodified to
284 // fputwc, which handles it correctly depending on the actual mode of the
285 // output stream. If the user sets a custom locale with imbue(), that
287 if constexpr (__is_win32api_wide_char
)
288 __always_noconv_
= true;
291 inline bool __do_fputc(char __c
, FILE* __fp
) {
292 if (fwrite(&__c
, sizeof(__c
), 1, __fp
) != 1)
296 #if _LIBCPP_HAS_WIDE_CHARACTERS
297 inline bool __do_fputc(wchar_t __c
, FILE* __fp
) {
298 // fputwc works regardless of wide/narrow mode of stdout, while
299 // fwrite of wchar_t only works if the stream actually has been set
301 if (fputwc(__c
, __fp
) == WEOF
)
307 template <class _CharT
>
308 typename __stdoutbuf
<_CharT
>::int_type __stdoutbuf
<_CharT
>::overflow(int_type __c
) {
309 char __extbuf
[__limit
];
311 if (!traits_type::eq_int_type(__c
, traits_type::eof())) {
312 __1buf
= traits_type::to_char_type(__c
);
313 if (__always_noconv_
) {
314 if (!__do_fputc(__1buf
, __file_
))
315 return traits_type::eof();
317 char* __extbe
= __extbuf
;
318 codecvt_base::result __r
;
319 char_type
* pbase
= &__1buf
;
320 char_type
* pptr
= pbase
+ 1;
322 const char_type
* __e
;
323 __r
= __cv_
->out(*__st_
, pbase
, pptr
, __e
, __extbuf
, __extbuf
+ sizeof(__extbuf
), __extbe
);
325 return traits_type::eof();
326 if (__r
== codecvt_base::noconv
) {
327 if (fwrite(pbase
, 1, 1, __file_
) != 1)
328 return traits_type::eof();
329 } else if (__r
== codecvt_base::ok
|| __r
== codecvt_base::partial
) {
330 size_t __nmemb
= static_cast<size_t>(__extbe
- __extbuf
);
331 if (fwrite(__extbuf
, 1, __nmemb
, __file_
) != __nmemb
)
332 return traits_type::eof();
333 if (__r
== codecvt_base::partial
) {
334 pbase
= const_cast<char_type
*>(__e
);
337 return traits_type::eof();
338 } while (__r
== codecvt_base::partial
);
341 return traits_type::not_eof(__c
);
344 template <class _CharT
>
345 streamsize __stdoutbuf
<_CharT
>::xsputn(const char_type
* __s
, streamsize __n
) {
346 // For wchar_t on Windows, don't call fwrite(), but write characters one
347 // at a time with fputwc(); that works both when stdout is in the default
348 // mode and when it is set to Unicode mode.
349 if (__always_noconv_
&& !__is_win32api_wide_char
)
350 return fwrite(__s
, sizeof(char_type
), __n
, __file_
);
352 for (; __i
< __n
; ++__i
, ++__s
)
353 if (overflow(traits_type::to_int_type(*__s
)) == traits_type::eof())
358 template <class _CharT
>
359 int __stdoutbuf
<_CharT
>::sync() {
360 char __extbuf
[__limit
];
361 codecvt_base::result __r
;
364 __r
= __cv_
->unshift(*__st_
, __extbuf
, __extbuf
+ sizeof(__extbuf
), __extbe
);
365 size_t __nmemb
= static_cast<size_t>(__extbe
- __extbuf
);
366 if (fwrite(__extbuf
, 1, __nmemb
, __file_
) != __nmemb
)
368 } while (__r
== codecvt_base::partial
);
369 if (__r
== codecvt_base::error
)
376 template <class _CharT
>
377 void __stdoutbuf
<_CharT
>::imbue(const locale
& __loc
) {
379 __cv_
= &use_facet
<codecvt
<char_type
, char, state_type
> >(__loc
);
380 __always_noconv_
= __cv_
->always_noconv();
383 _LIBCPP_END_NAMESPACE_STD
387 #endif // _LIBCPP_STD_STREAM_H