xref: /freebsd/contrib/llvm-project/libcxx/src/std_stream.h (revision cb14a3fe5122c879eae1fb480ed7ce82a699ddb6)
106c3fb27SDimitry Andric // -*- C++ -*-
206c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
306c3fb27SDimitry Andric //
406c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
506c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
606c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
706c3fb27SDimitry Andric //
806c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
906c3fb27SDimitry Andric 
1006c3fb27SDimitry Andric #ifndef _LIBCPP_STD_STREAM_H
1106c3fb27SDimitry Andric #define _LIBCPP_STD_STREAM_H
1206c3fb27SDimitry Andric 
1306c3fb27SDimitry Andric #include <__config>
1406c3fb27SDimitry Andric #include <__locale>
1506c3fb27SDimitry Andric #include <cstdio>
1606c3fb27SDimitry Andric #include <istream>
1706c3fb27SDimitry Andric #include <ostream>
1806c3fb27SDimitry Andric 
1906c3fb27SDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
2006c3fb27SDimitry Andric #  pragma GCC system_header
2106c3fb27SDimitry Andric #endif
2206c3fb27SDimitry Andric 
2306c3fb27SDimitry Andric _LIBCPP_PUSH_MACROS
2406c3fb27SDimitry Andric #include <__undef_macros>
2506c3fb27SDimitry Andric 
2606c3fb27SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD
2706c3fb27SDimitry Andric 
2806c3fb27SDimitry Andric static const int __limit = 8;
2906c3fb27SDimitry Andric 
3006c3fb27SDimitry Andric // __stdinbuf
3106c3fb27SDimitry Andric 
3206c3fb27SDimitry Andric template <class _CharT>
33*cb14a3feSDimitry Andric class _LIBCPP_HIDDEN __stdinbuf : public basic_streambuf<_CharT, char_traits<_CharT> > {
3406c3fb27SDimitry Andric public:
3506c3fb27SDimitry Andric   typedef _CharT char_type;
3606c3fb27SDimitry Andric   typedef char_traits<char_type> traits_type;
3706c3fb27SDimitry Andric   typedef typename traits_type::int_type int_type;
3806c3fb27SDimitry Andric   typedef typename traits_type::pos_type pos_type;
3906c3fb27SDimitry Andric   typedef typename traits_type::off_type off_type;
4006c3fb27SDimitry Andric   typedef typename traits_type::state_type state_type;
4106c3fb27SDimitry Andric 
4206c3fb27SDimitry Andric   __stdinbuf(FILE* __fp, state_type* __st);
4306c3fb27SDimitry Andric 
4406c3fb27SDimitry Andric protected:
4506c3fb27SDimitry Andric   virtual int_type underflow();
4606c3fb27SDimitry Andric   virtual int_type uflow();
4706c3fb27SDimitry Andric   virtual int_type pbackfail(int_type __c = traits_type::eof());
4806c3fb27SDimitry Andric   virtual void imbue(const locale& __loc);
4906c3fb27SDimitry Andric 
5006c3fb27SDimitry Andric private:
5106c3fb27SDimitry Andric   FILE* __file_;
5206c3fb27SDimitry Andric   const codecvt<char_type, char, state_type>* __cv_;
5306c3fb27SDimitry Andric   state_type* __st_;
5406c3fb27SDimitry Andric   int __encoding_;
5506c3fb27SDimitry Andric   int_type __last_consumed_;
5606c3fb27SDimitry Andric   bool __last_consumed_is_next_;
5706c3fb27SDimitry Andric   bool __always_noconv_;
5806c3fb27SDimitry Andric 
5906c3fb27SDimitry Andric #if defined(_LIBCPP_WIN32API)
6006c3fb27SDimitry Andric   static constexpr bool __is_win32api_wide_char = !is_same_v<_CharT, char>;
6106c3fb27SDimitry Andric #else
6206c3fb27SDimitry Andric   static constexpr bool __is_win32api_wide_char = false;
6306c3fb27SDimitry Andric #endif
6406c3fb27SDimitry Andric 
6506c3fb27SDimitry Andric   __stdinbuf(const __stdinbuf&);
6606c3fb27SDimitry Andric   __stdinbuf& operator=(const __stdinbuf&);
6706c3fb27SDimitry Andric 
6806c3fb27SDimitry Andric   int_type __getchar(bool __consume);
6906c3fb27SDimitry Andric };
7006c3fb27SDimitry Andric 
7106c3fb27SDimitry Andric template <class _CharT>
7206c3fb27SDimitry Andric __stdinbuf<_CharT>::__stdinbuf(FILE* __fp, state_type* __st)
73*cb14a3feSDimitry Andric     : __file_(__fp), __st_(__st), __last_consumed_(traits_type::eof()), __last_consumed_is_next_(false) {
7406c3fb27SDimitry Andric   imbue(this->getloc());
7506c3fb27SDimitry Andric   // On Windows, in wchar_t mode, ignore the codecvt from the locale by
7606c3fb27SDimitry Andric   // default and assume noconv; this passes wchar_t through unmodified from
7706c3fb27SDimitry Andric   // getwc. If the user sets a custom locale with imbue(), that gets honored,
7806c3fb27SDimitry Andric   // the IO is done with getc() and converted with the provided codecvt.
7906c3fb27SDimitry Andric   if constexpr (__is_win32api_wide_char)
8006c3fb27SDimitry Andric     __always_noconv_ = true;
8106c3fb27SDimitry Andric }
8206c3fb27SDimitry Andric 
8306c3fb27SDimitry Andric template <class _CharT>
84*cb14a3feSDimitry Andric void __stdinbuf<_CharT>::imbue(const locale& __loc) {
8506c3fb27SDimitry Andric   __cv_            = &use_facet<codecvt<char_type, char, state_type> >(__loc);
8606c3fb27SDimitry Andric   __encoding_      = __cv_->encoding();
8706c3fb27SDimitry Andric   __always_noconv_ = __cv_->always_noconv();
8806c3fb27SDimitry Andric   if (__encoding_ > __limit)
8906c3fb27SDimitry Andric     __throw_runtime_error("unsupported locale for standard input");
9006c3fb27SDimitry Andric }
9106c3fb27SDimitry Andric 
9206c3fb27SDimitry Andric template <class _CharT>
93*cb14a3feSDimitry Andric typename __stdinbuf<_CharT>::int_type __stdinbuf<_CharT>::underflow() {
9406c3fb27SDimitry Andric   return __getchar(false);
9506c3fb27SDimitry Andric }
9606c3fb27SDimitry Andric 
9706c3fb27SDimitry Andric template <class _CharT>
98*cb14a3feSDimitry Andric typename __stdinbuf<_CharT>::int_type __stdinbuf<_CharT>::uflow() {
9906c3fb27SDimitry Andric   return __getchar(true);
10006c3fb27SDimitry Andric }
10106c3fb27SDimitry Andric 
1025f757f3fSDimitry Andric inline bool __do_getc(FILE* __fp, char* __pbuf) {
10306c3fb27SDimitry Andric   int __c = getc(__fp);
10406c3fb27SDimitry Andric   if (__c == EOF)
10506c3fb27SDimitry Andric     return false;
10606c3fb27SDimitry Andric   *__pbuf = static_cast<char>(__c);
10706c3fb27SDimitry Andric   return true;
10806c3fb27SDimitry Andric }
10906c3fb27SDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
1105f757f3fSDimitry Andric inline bool __do_getc(FILE* __fp, wchar_t* __pbuf) {
11106c3fb27SDimitry Andric   wint_t __c = getwc(__fp);
11206c3fb27SDimitry Andric   if (__c == WEOF)
11306c3fb27SDimitry Andric     return false;
11406c3fb27SDimitry Andric   *__pbuf = static_cast<wchar_t>(__c);
11506c3fb27SDimitry Andric   return true;
11606c3fb27SDimitry Andric }
11706c3fb27SDimitry Andric #endif
11806c3fb27SDimitry Andric 
1195f757f3fSDimitry Andric inline bool __do_ungetc(int __c, FILE* __fp, char __dummy) {
12006c3fb27SDimitry Andric   if (ungetc(__c, __fp) == EOF)
12106c3fb27SDimitry Andric     return false;
12206c3fb27SDimitry Andric   return true;
12306c3fb27SDimitry Andric }
12406c3fb27SDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
1255f757f3fSDimitry Andric inline bool __do_ungetc(std::wint_t __c, FILE* __fp, wchar_t __dummy) {
12606c3fb27SDimitry Andric   if (ungetwc(__c, __fp) == WEOF)
12706c3fb27SDimitry Andric     return false;
12806c3fb27SDimitry Andric   return true;
12906c3fb27SDimitry Andric }
13006c3fb27SDimitry Andric #endif
13106c3fb27SDimitry Andric 
13206c3fb27SDimitry Andric template <class _CharT>
133*cb14a3feSDimitry Andric typename __stdinbuf<_CharT>::int_type __stdinbuf<_CharT>::__getchar(bool __consume) {
134*cb14a3feSDimitry Andric   if (__last_consumed_is_next_) {
13506c3fb27SDimitry Andric     int_type __result = __last_consumed_;
136*cb14a3feSDimitry Andric     if (__consume) {
13706c3fb27SDimitry Andric       __last_consumed_         = traits_type::eof();
13806c3fb27SDimitry Andric       __last_consumed_is_next_ = false;
13906c3fb27SDimitry Andric     }
14006c3fb27SDimitry Andric     return __result;
14106c3fb27SDimitry Andric   }
14206c3fb27SDimitry Andric   if (__always_noconv_) {
14306c3fb27SDimitry Andric     char_type __1buf;
14406c3fb27SDimitry Andric     if (!__do_getc(__file_, &__1buf))
14506c3fb27SDimitry Andric       return traits_type::eof();
146*cb14a3feSDimitry Andric     if (!__consume) {
14706c3fb27SDimitry Andric       if (!__do_ungetc(traits_type::to_int_type(__1buf), __file_, __1buf))
14806c3fb27SDimitry Andric         return traits_type::eof();
149*cb14a3feSDimitry Andric     } else
15006c3fb27SDimitry Andric       __last_consumed_ = traits_type::to_int_type(__1buf);
15106c3fb27SDimitry Andric     return traits_type::to_int_type(__1buf);
15206c3fb27SDimitry Andric   }
15306c3fb27SDimitry Andric 
15406c3fb27SDimitry Andric   char __extbuf[__limit];
1555f757f3fSDimitry Andric   int __nread = std::max(1, __encoding_);
156*cb14a3feSDimitry Andric   for (int __i = 0; __i < __nread; ++__i) {
15706c3fb27SDimitry Andric     int __c = getc(__file_);
15806c3fb27SDimitry Andric     if (__c == EOF)
15906c3fb27SDimitry Andric       return traits_type::eof();
16006c3fb27SDimitry Andric     __extbuf[__i] = static_cast<char>(__c);
16106c3fb27SDimitry Andric   }
16206c3fb27SDimitry Andric   char_type __1buf;
16306c3fb27SDimitry Andric   const char* __enxt;
16406c3fb27SDimitry Andric   char_type* __inxt;
16506c3fb27SDimitry Andric   codecvt_base::result __r;
166*cb14a3feSDimitry Andric   do {
16706c3fb27SDimitry Andric     state_type __sv_st = *__st_;
168*cb14a3feSDimitry Andric     __r                = __cv_->in(*__st_, __extbuf, __extbuf + __nread, __enxt, &__1buf, &__1buf + 1, __inxt);
169*cb14a3feSDimitry Andric     switch (__r) {
1705f757f3fSDimitry Andric     case std::codecvt_base::ok:
17106c3fb27SDimitry Andric       break;
17206c3fb27SDimitry Andric     case codecvt_base::partial:
17306c3fb27SDimitry Andric       *__st_ = __sv_st;
17406c3fb27SDimitry Andric       if (__nread == sizeof(__extbuf))
17506c3fb27SDimitry Andric         return traits_type::eof();
17606c3fb27SDimitry Andric       {
17706c3fb27SDimitry Andric         int __c = getc(__file_);
17806c3fb27SDimitry Andric         if (__c == EOF)
17906c3fb27SDimitry Andric           return traits_type::eof();
18006c3fb27SDimitry Andric         __extbuf[__nread] = static_cast<char>(__c);
18106c3fb27SDimitry Andric       }
18206c3fb27SDimitry Andric       ++__nread;
18306c3fb27SDimitry Andric       break;
18406c3fb27SDimitry Andric     case codecvt_base::error:
18506c3fb27SDimitry Andric       return traits_type::eof();
1865f757f3fSDimitry Andric     case std::codecvt_base::noconv:
18706c3fb27SDimitry Andric       __1buf = static_cast<char_type>(__extbuf[0]);
18806c3fb27SDimitry Andric       break;
18906c3fb27SDimitry Andric     }
1905f757f3fSDimitry Andric   } while (__r == std::codecvt_base::partial);
191*cb14a3feSDimitry Andric   if (!__consume) {
192*cb14a3feSDimitry Andric     for (int __i = __nread; __i > 0;) {
19306c3fb27SDimitry Andric       if (ungetc(traits_type::to_int_type(__extbuf[--__i]), __file_) == EOF)
19406c3fb27SDimitry Andric         return traits_type::eof();
19506c3fb27SDimitry Andric     }
196*cb14a3feSDimitry Andric   } else
19706c3fb27SDimitry Andric     __last_consumed_ = traits_type::to_int_type(__1buf);
19806c3fb27SDimitry Andric   return traits_type::to_int_type(__1buf);
19906c3fb27SDimitry Andric }
20006c3fb27SDimitry Andric 
20106c3fb27SDimitry Andric template <class _CharT>
202*cb14a3feSDimitry Andric typename __stdinbuf<_CharT>::int_type __stdinbuf<_CharT>::pbackfail(int_type __c) {
203*cb14a3feSDimitry Andric   if (traits_type::eq_int_type(__c, traits_type::eof())) {
204*cb14a3feSDimitry Andric     if (!__last_consumed_is_next_) {
20506c3fb27SDimitry Andric       __c                      = __last_consumed_;
206*cb14a3feSDimitry Andric       __last_consumed_is_next_ = !traits_type::eq_int_type(__last_consumed_, traits_type::eof());
20706c3fb27SDimitry Andric     }
20806c3fb27SDimitry Andric     return __c;
20906c3fb27SDimitry Andric   }
21006c3fb27SDimitry Andric   if (__always_noconv_ && __last_consumed_is_next_) {
211*cb14a3feSDimitry Andric     if (!__do_ungetc(__last_consumed_, __file_, traits_type::to_char_type(__last_consumed_)))
21206c3fb27SDimitry Andric       return traits_type::eof();
21306c3fb27SDimitry Andric   } else if (__last_consumed_is_next_) {
21406c3fb27SDimitry Andric     char __extbuf[__limit];
21506c3fb27SDimitry Andric     char* __enxt;
21606c3fb27SDimitry Andric     const char_type __ci = traits_type::to_char_type(__last_consumed_);
21706c3fb27SDimitry Andric     const char_type* __inxt;
218*cb14a3feSDimitry Andric     switch (__cv_->out(*__st_, &__ci, &__ci + 1, __inxt, __extbuf, __extbuf + sizeof(__extbuf), __enxt)) {
2195f757f3fSDimitry Andric     case std::codecvt_base::ok:
22006c3fb27SDimitry Andric       break;
2215f757f3fSDimitry Andric     case std::codecvt_base::noconv:
22206c3fb27SDimitry Andric       __extbuf[0] = static_cast<char>(__last_consumed_);
22306c3fb27SDimitry Andric       __enxt      = __extbuf + 1;
22406c3fb27SDimitry Andric       break;
22506c3fb27SDimitry Andric     case codecvt_base::partial:
22606c3fb27SDimitry Andric     case codecvt_base::error:
22706c3fb27SDimitry Andric       return traits_type::eof();
22806c3fb27SDimitry Andric     }
22906c3fb27SDimitry Andric     while (__enxt > __extbuf)
23006c3fb27SDimitry Andric       if (ungetc(*--__enxt, __file_) == EOF)
23106c3fb27SDimitry Andric         return traits_type::eof();
23206c3fb27SDimitry Andric   }
23306c3fb27SDimitry Andric   __last_consumed_         = __c;
23406c3fb27SDimitry Andric   __last_consumed_is_next_ = true;
23506c3fb27SDimitry Andric   return __c;
23606c3fb27SDimitry Andric }
23706c3fb27SDimitry Andric 
23806c3fb27SDimitry Andric // __stdoutbuf
23906c3fb27SDimitry Andric 
24006c3fb27SDimitry Andric template <class _CharT>
241*cb14a3feSDimitry Andric class _LIBCPP_HIDDEN __stdoutbuf : public basic_streambuf<_CharT, char_traits<_CharT> > {
24206c3fb27SDimitry Andric public:
24306c3fb27SDimitry Andric   typedef _CharT char_type;
24406c3fb27SDimitry Andric   typedef char_traits<char_type> traits_type;
24506c3fb27SDimitry Andric   typedef typename traits_type::int_type int_type;
24606c3fb27SDimitry Andric   typedef typename traits_type::pos_type pos_type;
24706c3fb27SDimitry Andric   typedef typename traits_type::off_type off_type;
24806c3fb27SDimitry Andric   typedef typename traits_type::state_type state_type;
24906c3fb27SDimitry Andric 
25006c3fb27SDimitry Andric   __stdoutbuf(FILE* __fp, state_type* __st);
25106c3fb27SDimitry Andric 
25206c3fb27SDimitry Andric protected:
25306c3fb27SDimitry Andric   virtual int_type overflow(int_type __c = traits_type::eof());
25406c3fb27SDimitry Andric   virtual streamsize xsputn(const char_type* __s, streamsize __n);
25506c3fb27SDimitry Andric   virtual int sync();
25606c3fb27SDimitry Andric   virtual void imbue(const locale& __loc);
25706c3fb27SDimitry Andric 
25806c3fb27SDimitry Andric private:
25906c3fb27SDimitry Andric   FILE* __file_;
26006c3fb27SDimitry Andric   const codecvt<char_type, char, state_type>* __cv_;
26106c3fb27SDimitry Andric   state_type* __st_;
26206c3fb27SDimitry Andric   bool __always_noconv_;
26306c3fb27SDimitry Andric 
26406c3fb27SDimitry Andric #if defined(_LIBCPP_WIN32API)
26506c3fb27SDimitry Andric   static constexpr bool __is_win32api_wide_char = !is_same_v<_CharT, char>;
26606c3fb27SDimitry Andric #else
26706c3fb27SDimitry Andric   static constexpr bool __is_win32api_wide_char = false;
26806c3fb27SDimitry Andric #endif
26906c3fb27SDimitry Andric 
27006c3fb27SDimitry Andric   __stdoutbuf(const __stdoutbuf&);
27106c3fb27SDimitry Andric   __stdoutbuf& operator=(const __stdoutbuf&);
272*cb14a3feSDimitry Andric 
273*cb14a3feSDimitry Andric   _LIBCPP_EXPORTED_FROM_ABI friend FILE* __get_ostream_file(ostream&);
27406c3fb27SDimitry Andric };
27506c3fb27SDimitry Andric 
27606c3fb27SDimitry Andric template <class _CharT>
27706c3fb27SDimitry Andric __stdoutbuf<_CharT>::__stdoutbuf(FILE* __fp, state_type* __st)
27806c3fb27SDimitry Andric     : __file_(__fp),
27906c3fb27SDimitry Andric       __cv_(&use_facet<codecvt<char_type, char, state_type> >(this->getloc())),
28006c3fb27SDimitry Andric       __st_(__st),
281*cb14a3feSDimitry Andric       __always_noconv_(__cv_->always_noconv()) {
28206c3fb27SDimitry Andric   // On Windows, in wchar_t mode, ignore the codecvt from the locale by
28306c3fb27SDimitry Andric   // default and assume noconv; this passes wchar_t through unmodified to
28406c3fb27SDimitry Andric   // fputwc, which handles it correctly depending on the actual mode of the
28506c3fb27SDimitry Andric   // output stream. If the user sets a custom locale with imbue(), that
28606c3fb27SDimitry Andric   // gets honored.
28706c3fb27SDimitry Andric   if constexpr (__is_win32api_wide_char)
28806c3fb27SDimitry Andric     __always_noconv_ = true;
28906c3fb27SDimitry Andric }
29006c3fb27SDimitry Andric 
2915f757f3fSDimitry Andric inline bool __do_fputc(char __c, FILE* __fp) {
29206c3fb27SDimitry Andric   if (fwrite(&__c, sizeof(__c), 1, __fp) != 1)
29306c3fb27SDimitry Andric     return false;
29406c3fb27SDimitry Andric   return true;
29506c3fb27SDimitry Andric }
29606c3fb27SDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2975f757f3fSDimitry Andric inline bool __do_fputc(wchar_t __c, FILE* __fp) {
29806c3fb27SDimitry Andric   // fputwc works regardless of wide/narrow mode of stdout, while
29906c3fb27SDimitry Andric   // fwrite of wchar_t only works if the stream actually has been set
30006c3fb27SDimitry Andric   // into wide mode.
30106c3fb27SDimitry Andric   if (fputwc(__c, __fp) == WEOF)
30206c3fb27SDimitry Andric     return false;
30306c3fb27SDimitry Andric   return true;
30406c3fb27SDimitry Andric }
30506c3fb27SDimitry Andric #endif
30606c3fb27SDimitry Andric 
30706c3fb27SDimitry Andric template <class _CharT>
308*cb14a3feSDimitry Andric typename __stdoutbuf<_CharT>::int_type __stdoutbuf<_CharT>::overflow(int_type __c) {
30906c3fb27SDimitry Andric   char __extbuf[__limit];
31006c3fb27SDimitry Andric   char_type __1buf;
311*cb14a3feSDimitry Andric   if (!traits_type::eq_int_type(__c, traits_type::eof())) {
31206c3fb27SDimitry Andric     __1buf = traits_type::to_char_type(__c);
313*cb14a3feSDimitry Andric     if (__always_noconv_) {
31406c3fb27SDimitry Andric       if (!__do_fputc(__1buf, __file_))
31506c3fb27SDimitry Andric         return traits_type::eof();
316*cb14a3feSDimitry Andric     } else {
31706c3fb27SDimitry Andric       char* __extbe = __extbuf;
31806c3fb27SDimitry Andric       codecvt_base::result __r;
31906c3fb27SDimitry Andric       char_type* pbase = &__1buf;
32006c3fb27SDimitry Andric       char_type* pptr  = pbase + 1;
321*cb14a3feSDimitry Andric       do {
32206c3fb27SDimitry Andric         const char_type* __e;
323*cb14a3feSDimitry Andric         __r = __cv_->out(*__st_, pbase, pptr, __e, __extbuf, __extbuf + sizeof(__extbuf), __extbe);
32406c3fb27SDimitry Andric         if (__e == pbase)
32506c3fb27SDimitry Andric           return traits_type::eof();
326*cb14a3feSDimitry Andric         if (__r == codecvt_base::noconv) {
32706c3fb27SDimitry Andric           if (fwrite(pbase, 1, 1, __file_) != 1)
32806c3fb27SDimitry Andric             return traits_type::eof();
329*cb14a3feSDimitry Andric         } else if (__r == codecvt_base::ok || __r == codecvt_base::partial) {
33006c3fb27SDimitry Andric           size_t __nmemb = static_cast<size_t>(__extbe - __extbuf);
33106c3fb27SDimitry Andric           if (fwrite(__extbuf, 1, __nmemb, __file_) != __nmemb)
33206c3fb27SDimitry Andric             return traits_type::eof();
333*cb14a3feSDimitry Andric           if (__r == codecvt_base::partial) {
33406c3fb27SDimitry Andric             pbase = const_cast<char_type*>(__e);
33506c3fb27SDimitry Andric           }
336*cb14a3feSDimitry Andric         } else
33706c3fb27SDimitry Andric           return traits_type::eof();
33806c3fb27SDimitry Andric       } while (__r == codecvt_base::partial);
33906c3fb27SDimitry Andric     }
34006c3fb27SDimitry Andric   }
34106c3fb27SDimitry Andric   return traits_type::not_eof(__c);
34206c3fb27SDimitry Andric }
34306c3fb27SDimitry Andric 
34406c3fb27SDimitry Andric template <class _CharT>
345*cb14a3feSDimitry Andric streamsize __stdoutbuf<_CharT>::xsputn(const char_type* __s, streamsize __n) {
34606c3fb27SDimitry Andric   // For wchar_t on Windows, don't call fwrite(), but write characters one
34706c3fb27SDimitry Andric   // at a time with fputwc(); that works both when stdout is in the default
34806c3fb27SDimitry Andric   // mode and when it is set to Unicode mode.
34906c3fb27SDimitry Andric   if (__always_noconv_ && !__is_win32api_wide_char)
35006c3fb27SDimitry Andric     return fwrite(__s, sizeof(char_type), __n, __file_);
35106c3fb27SDimitry Andric   streamsize __i = 0;
35206c3fb27SDimitry Andric   for (; __i < __n; ++__i, ++__s)
35306c3fb27SDimitry Andric     if (overflow(traits_type::to_int_type(*__s)) == traits_type::eof())
35406c3fb27SDimitry Andric       break;
35506c3fb27SDimitry Andric   return __i;
35606c3fb27SDimitry Andric }
35706c3fb27SDimitry Andric 
35806c3fb27SDimitry Andric template <class _CharT>
359*cb14a3feSDimitry Andric int __stdoutbuf<_CharT>::sync() {
36006c3fb27SDimitry Andric   char __extbuf[__limit];
36106c3fb27SDimitry Andric   codecvt_base::result __r;
362*cb14a3feSDimitry Andric   do {
36306c3fb27SDimitry Andric     char* __extbe;
364*cb14a3feSDimitry Andric     __r            = __cv_->unshift(*__st_, __extbuf, __extbuf + sizeof(__extbuf), __extbe);
36506c3fb27SDimitry Andric     size_t __nmemb = static_cast<size_t>(__extbe - __extbuf);
36606c3fb27SDimitry Andric     if (fwrite(__extbuf, 1, __nmemb, __file_) != __nmemb)
36706c3fb27SDimitry Andric       return -1;
36806c3fb27SDimitry Andric   } while (__r == codecvt_base::partial);
36906c3fb27SDimitry Andric   if (__r == codecvt_base::error)
37006c3fb27SDimitry Andric     return -1;
37106c3fb27SDimitry Andric   if (fflush(__file_))
37206c3fb27SDimitry Andric     return -1;
37306c3fb27SDimitry Andric   return 0;
37406c3fb27SDimitry Andric }
37506c3fb27SDimitry Andric 
37606c3fb27SDimitry Andric template <class _CharT>
377*cb14a3feSDimitry Andric void __stdoutbuf<_CharT>::imbue(const locale& __loc) {
37806c3fb27SDimitry Andric   sync();
37906c3fb27SDimitry Andric   __cv_            = &use_facet<codecvt<char_type, char, state_type> >(__loc);
38006c3fb27SDimitry Andric   __always_noconv_ = __cv_->always_noconv();
38106c3fb27SDimitry Andric }
38206c3fb27SDimitry Andric 
38306c3fb27SDimitry Andric _LIBCPP_END_NAMESPACE_STD
38406c3fb27SDimitry Andric 
38506c3fb27SDimitry Andric _LIBCPP_POP_MACROS
38606c3fb27SDimitry Andric 
38706c3fb27SDimitry Andric #endif // _LIBCPP_STD_STREAM_H
388