xref: /llvm-project/libcxx/src/std_stream.h (revision c6f3b7bcd0596d30f8dabecdfb9e44f9a07b6e4c)
140a187bbSMartin Storsjö // -*- C++ -*-
240a187bbSMartin Storsjö //===----------------------------------------------------------------------===//
340a187bbSMartin Storsjö //
440a187bbSMartin Storsjö // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
540a187bbSMartin Storsjö // See https://llvm.org/LICENSE.txt for license information.
640a187bbSMartin Storsjö // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
740a187bbSMartin Storsjö //
840a187bbSMartin Storsjö //===----------------------------------------------------------------------===//
940a187bbSMartin Storsjö 
1040a187bbSMartin Storsjö #ifndef _LIBCPP_STD_STREAM_H
1140a187bbSMartin Storsjö #define _LIBCPP_STD_STREAM_H
1240a187bbSMartin Storsjö 
1340a187bbSMartin Storsjö #include <__config>
1440a187bbSMartin Storsjö #include <__locale>
1540a187bbSMartin Storsjö #include <cstdio>
1640a187bbSMartin Storsjö #include <istream>
1740a187bbSMartin Storsjö #include <ostream>
1840a187bbSMartin Storsjö 
1940a187bbSMartin Storsjö #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
2040a187bbSMartin Storsjö #  pragma GCC system_header
2140a187bbSMartin Storsjö #endif
2240a187bbSMartin Storsjö 
2340a187bbSMartin Storsjö _LIBCPP_PUSH_MACROS
2440a187bbSMartin Storsjö #include <__undef_macros>
2540a187bbSMartin Storsjö 
2640a187bbSMartin Storsjö _LIBCPP_BEGIN_NAMESPACE_STD
2740a187bbSMartin Storsjö 
2840a187bbSMartin Storsjö static const int __limit = 8;
2940a187bbSMartin Storsjö 
3040a187bbSMartin Storsjö // __stdinbuf
3140a187bbSMartin Storsjö 
3240a187bbSMartin Storsjö template <class _CharT>
339783f28cSLouis Dionne class _LIBCPP_HIDDEN __stdinbuf : public basic_streambuf<_CharT, char_traits<_CharT> > {
3440a187bbSMartin Storsjö public:
3540a187bbSMartin Storsjö   typedef _CharT char_type;
3640a187bbSMartin Storsjö   typedef char_traits<char_type> traits_type;
3740a187bbSMartin Storsjö   typedef typename traits_type::int_type int_type;
3840a187bbSMartin Storsjö   typedef typename traits_type::pos_type pos_type;
3940a187bbSMartin Storsjö   typedef typename traits_type::off_type off_type;
4040a187bbSMartin Storsjö   typedef typename traits_type::state_type state_type;
4140a187bbSMartin Storsjö 
4240a187bbSMartin Storsjö   __stdinbuf(FILE* __fp, state_type* __st);
4340a187bbSMartin Storsjö 
4440a187bbSMartin Storsjö protected:
4540a187bbSMartin Storsjö   virtual int_type underflow();
4640a187bbSMartin Storsjö   virtual int_type uflow();
4740a187bbSMartin Storsjö   virtual int_type pbackfail(int_type __c = traits_type::eof());
4840a187bbSMartin Storsjö   virtual void imbue(const locale& __loc);
4940a187bbSMartin Storsjö 
5040a187bbSMartin Storsjö private:
5140a187bbSMartin Storsjö   FILE* __file_;
5240a187bbSMartin Storsjö   const codecvt<char_type, char, state_type>* __cv_;
5340a187bbSMartin Storsjö   state_type* __st_;
5440a187bbSMartin Storsjö   int __encoding_;
5540a187bbSMartin Storsjö   int_type __last_consumed_;
5640a187bbSMartin Storsjö   bool __last_consumed_is_next_;
5740a187bbSMartin Storsjö   bool __always_noconv_;
5840a187bbSMartin Storsjö 
59fcbbd964SMartin Storsjö #if defined(_LIBCPP_WIN32API)
60fcbbd964SMartin Storsjö   static constexpr bool __is_win32api_wide_char = !is_same_v<_CharT, char>;
61fcbbd964SMartin Storsjö #else
62fcbbd964SMartin Storsjö   static constexpr bool __is_win32api_wide_char = false;
63fcbbd964SMartin Storsjö #endif
64fcbbd964SMartin Storsjö 
6540a187bbSMartin Storsjö   __stdinbuf(const __stdinbuf&);
6640a187bbSMartin Storsjö   __stdinbuf& operator=(const __stdinbuf&);
6740a187bbSMartin Storsjö 
6840a187bbSMartin Storsjö   int_type __getchar(bool __consume);
6940a187bbSMartin Storsjö };
7040a187bbSMartin Storsjö 
7140a187bbSMartin Storsjö template <class _CharT>
7240a187bbSMartin Storsjö __stdinbuf<_CharT>::__stdinbuf(FILE* __fp, state_type* __st)
739783f28cSLouis Dionne     : __file_(__fp), __st_(__st), __last_consumed_(traits_type::eof()), __last_consumed_is_next_(false) {
7440a187bbSMartin Storsjö   imbue(this->getloc());
75fcbbd964SMartin Storsjö   // On Windows, in wchar_t mode, ignore the codecvt from the locale by
76fcbbd964SMartin Storsjö   // default and assume noconv; this passes wchar_t through unmodified from
77fcbbd964SMartin Storsjö   // getwc. If the user sets a custom locale with imbue(), that gets honored,
78fcbbd964SMartin Storsjö   // the IO is done with getc() and converted with the provided codecvt.
79fcbbd964SMartin Storsjö   if constexpr (__is_win32api_wide_char)
80fcbbd964SMartin Storsjö     __always_noconv_ = true;
8140a187bbSMartin Storsjö }
8240a187bbSMartin Storsjö 
8340a187bbSMartin Storsjö template <class _CharT>
849783f28cSLouis Dionne void __stdinbuf<_CharT>::imbue(const locale& __loc) {
8540a187bbSMartin Storsjö   __cv_            = &use_facet<codecvt<char_type, char, state_type> >(__loc);
8640a187bbSMartin Storsjö   __encoding_      = __cv_->encoding();
8740a187bbSMartin Storsjö   __always_noconv_ = __cv_->always_noconv();
8840a187bbSMartin Storsjö   if (__encoding_ > __limit)
8940a187bbSMartin Storsjö     __throw_runtime_error("unsupported locale for standard input");
9040a187bbSMartin Storsjö }
9140a187bbSMartin Storsjö 
9240a187bbSMartin Storsjö template <class _CharT>
939783f28cSLouis Dionne typename __stdinbuf<_CharT>::int_type __stdinbuf<_CharT>::underflow() {
9440a187bbSMartin Storsjö   return __getchar(false);
9540a187bbSMartin Storsjö }
9640a187bbSMartin Storsjö 
9740a187bbSMartin Storsjö template <class _CharT>
989783f28cSLouis Dionne typename __stdinbuf<_CharT>::int_type __stdinbuf<_CharT>::uflow() {
9940a187bbSMartin Storsjö   return __getchar(true);
10040a187bbSMartin Storsjö }
10140a187bbSMartin Storsjö 
1022a0f2fa9SMark de Wever inline bool __do_getc(FILE* __fp, char* __pbuf) {
103fcbbd964SMartin Storsjö   int __c = getc(__fp);
104fcbbd964SMartin Storsjö   if (__c == EOF)
105fcbbd964SMartin Storsjö     return false;
106fcbbd964SMartin Storsjö   *__pbuf = static_cast<char>(__c);
107fcbbd964SMartin Storsjö   return true;
108fcbbd964SMartin Storsjö }
109*c6f3b7bcSNikolas Klauser #if _LIBCPP_HAS_WIDE_CHARACTERS
1102a0f2fa9SMark de Wever inline bool __do_getc(FILE* __fp, wchar_t* __pbuf) {
111fcbbd964SMartin Storsjö   wint_t __c = getwc(__fp);
112fcbbd964SMartin Storsjö   if (__c == WEOF)
113fcbbd964SMartin Storsjö     return false;
114fcbbd964SMartin Storsjö   *__pbuf = static_cast<wchar_t>(__c);
115fcbbd964SMartin Storsjö   return true;
116fcbbd964SMartin Storsjö }
117fcbbd964SMartin Storsjö #endif
118fcbbd964SMartin Storsjö 
1192a0f2fa9SMark de Wever inline bool __do_ungetc(int __c, FILE* __fp, char __dummy) {
120fcbbd964SMartin Storsjö   if (ungetc(__c, __fp) == EOF)
121fcbbd964SMartin Storsjö     return false;
122fcbbd964SMartin Storsjö   return true;
123fcbbd964SMartin Storsjö }
124*c6f3b7bcSNikolas Klauser #if _LIBCPP_HAS_WIDE_CHARACTERS
1252a0f2fa9SMark de Wever inline bool __do_ungetc(std::wint_t __c, FILE* __fp, wchar_t __dummy) {
126fcbbd964SMartin Storsjö   if (ungetwc(__c, __fp) == WEOF)
127fcbbd964SMartin Storsjö     return false;
128fcbbd964SMartin Storsjö   return true;
129fcbbd964SMartin Storsjö }
130fcbbd964SMartin Storsjö #endif
131fcbbd964SMartin Storsjö 
13240a187bbSMartin Storsjö template <class _CharT>
1339783f28cSLouis Dionne typename __stdinbuf<_CharT>::int_type __stdinbuf<_CharT>::__getchar(bool __consume) {
1349783f28cSLouis Dionne   if (__last_consumed_is_next_) {
13540a187bbSMartin Storsjö     int_type __result = __last_consumed_;
1369783f28cSLouis Dionne     if (__consume) {
13740a187bbSMartin Storsjö       __last_consumed_         = traits_type::eof();
13840a187bbSMartin Storsjö       __last_consumed_is_next_ = false;
13940a187bbSMartin Storsjö     }
14040a187bbSMartin Storsjö     return __result;
14140a187bbSMartin Storsjö   }
142fcbbd964SMartin Storsjö   if (__always_noconv_) {
143fcbbd964SMartin Storsjö     char_type __1buf;
144fcbbd964SMartin Storsjö     if (!__do_getc(__file_, &__1buf))
145fcbbd964SMartin Storsjö       return traits_type::eof();
1469783f28cSLouis Dionne     if (!__consume) {
147fcbbd964SMartin Storsjö       if (!__do_ungetc(traits_type::to_int_type(__1buf), __file_, __1buf))
148fcbbd964SMartin Storsjö         return traits_type::eof();
1499783f28cSLouis Dionne     } else
150fcbbd964SMartin Storsjö       __last_consumed_ = traits_type::to_int_type(__1buf);
151fcbbd964SMartin Storsjö     return traits_type::to_int_type(__1buf);
152fcbbd964SMartin Storsjö   }
153fcbbd964SMartin Storsjö 
15440a187bbSMartin Storsjö   char __extbuf[__limit];
15577a00c0dSLouis Dionne   int __nread = std::max(1, __encoding_);
1569783f28cSLouis Dionne   for (int __i = 0; __i < __nread; ++__i) {
15740a187bbSMartin Storsjö     int __c = getc(__file_);
15840a187bbSMartin Storsjö     if (__c == EOF)
15940a187bbSMartin Storsjö       return traits_type::eof();
16040a187bbSMartin Storsjö     __extbuf[__i] = static_cast<char>(__c);
16140a187bbSMartin Storsjö   }
16240a187bbSMartin Storsjö   char_type __1buf;
16340a187bbSMartin Storsjö   const char* __enxt;
16440a187bbSMartin Storsjö   char_type* __inxt;
16540a187bbSMartin Storsjö   codecvt_base::result __r;
1669783f28cSLouis Dionne   do {
16740a187bbSMartin Storsjö     state_type __sv_st = *__st_;
1689783f28cSLouis Dionne     __r                = __cv_->in(*__st_, __extbuf, __extbuf + __nread, __enxt, &__1buf, &__1buf + 1, __inxt);
1699783f28cSLouis Dionne     switch (__r) {
17077a00c0dSLouis Dionne     case std::codecvt_base::ok:
17140a187bbSMartin Storsjö       break;
17240a187bbSMartin Storsjö     case codecvt_base::partial:
17340a187bbSMartin Storsjö       *__st_ = __sv_st;
17440a187bbSMartin Storsjö       if (__nread == sizeof(__extbuf))
17540a187bbSMartin Storsjö         return traits_type::eof();
17640a187bbSMartin Storsjö       {
17740a187bbSMartin Storsjö         int __c = getc(__file_);
17840a187bbSMartin Storsjö         if (__c == EOF)
17940a187bbSMartin Storsjö           return traits_type::eof();
18040a187bbSMartin Storsjö         __extbuf[__nread] = static_cast<char>(__c);
18140a187bbSMartin Storsjö       }
18240a187bbSMartin Storsjö       ++__nread;
18340a187bbSMartin Storsjö       break;
18440a187bbSMartin Storsjö     case codecvt_base::error:
18540a187bbSMartin Storsjö       return traits_type::eof();
18677a00c0dSLouis Dionne     case std::codecvt_base::noconv:
18740a187bbSMartin Storsjö       __1buf = static_cast<char_type>(__extbuf[0]);
18840a187bbSMartin Storsjö       break;
18940a187bbSMartin Storsjö     }
19077a00c0dSLouis Dionne   } while (__r == std::codecvt_base::partial);
1919783f28cSLouis Dionne   if (!__consume) {
1929783f28cSLouis Dionne     for (int __i = __nread; __i > 0;) {
19340a187bbSMartin Storsjö       if (ungetc(traits_type::to_int_type(__extbuf[--__i]), __file_) == EOF)
19440a187bbSMartin Storsjö         return traits_type::eof();
19540a187bbSMartin Storsjö     }
1969783f28cSLouis Dionne   } else
19740a187bbSMartin Storsjö     __last_consumed_ = traits_type::to_int_type(__1buf);
19840a187bbSMartin Storsjö   return traits_type::to_int_type(__1buf);
19940a187bbSMartin Storsjö }
20040a187bbSMartin Storsjö 
20140a187bbSMartin Storsjö template <class _CharT>
2029783f28cSLouis Dionne typename __stdinbuf<_CharT>::int_type __stdinbuf<_CharT>::pbackfail(int_type __c) {
2039783f28cSLouis Dionne   if (traits_type::eq_int_type(__c, traits_type::eof())) {
2049783f28cSLouis Dionne     if (!__last_consumed_is_next_) {
20540a187bbSMartin Storsjö       __c                      = __last_consumed_;
2069783f28cSLouis Dionne       __last_consumed_is_next_ = !traits_type::eq_int_type(__last_consumed_, traits_type::eof());
20740a187bbSMartin Storsjö     }
20840a187bbSMartin Storsjö     return __c;
20940a187bbSMartin Storsjö   }
210fcbbd964SMartin Storsjö   if (__always_noconv_ && __last_consumed_is_next_) {
2119783f28cSLouis Dionne     if (!__do_ungetc(__last_consumed_, __file_, traits_type::to_char_type(__last_consumed_)))
212fcbbd964SMartin Storsjö       return traits_type::eof();
213fcbbd964SMartin Storsjö   } else if (__last_consumed_is_next_) {
21440a187bbSMartin Storsjö     char __extbuf[__limit];
21540a187bbSMartin Storsjö     char* __enxt;
21640a187bbSMartin Storsjö     const char_type __ci = traits_type::to_char_type(__last_consumed_);
21740a187bbSMartin Storsjö     const char_type* __inxt;
2189783f28cSLouis Dionne     switch (__cv_->out(*__st_, &__ci, &__ci + 1, __inxt, __extbuf, __extbuf + sizeof(__extbuf), __enxt)) {
21977a00c0dSLouis Dionne     case std::codecvt_base::ok:
22040a187bbSMartin Storsjö       break;
22177a00c0dSLouis Dionne     case std::codecvt_base::noconv:
22240a187bbSMartin Storsjö       __extbuf[0] = static_cast<char>(__last_consumed_);
22340a187bbSMartin Storsjö       __enxt      = __extbuf + 1;
22440a187bbSMartin Storsjö       break;
22540a187bbSMartin Storsjö     case codecvt_base::partial:
22640a187bbSMartin Storsjö     case codecvt_base::error:
22740a187bbSMartin Storsjö       return traits_type::eof();
22840a187bbSMartin Storsjö     }
22940a187bbSMartin Storsjö     while (__enxt > __extbuf)
23040a187bbSMartin Storsjö       if (ungetc(*--__enxt, __file_) == EOF)
23140a187bbSMartin Storsjö         return traits_type::eof();
23240a187bbSMartin Storsjö   }
23340a187bbSMartin Storsjö   __last_consumed_         = __c;
23440a187bbSMartin Storsjö   __last_consumed_is_next_ = true;
23540a187bbSMartin Storsjö   return __c;
23640a187bbSMartin Storsjö }
23740a187bbSMartin Storsjö 
23840a187bbSMartin Storsjö // __stdoutbuf
23940a187bbSMartin Storsjö 
24040a187bbSMartin Storsjö template <class _CharT>
2419783f28cSLouis Dionne class _LIBCPP_HIDDEN __stdoutbuf : public basic_streambuf<_CharT, char_traits<_CharT> > {
24240a187bbSMartin Storsjö public:
24340a187bbSMartin Storsjö   typedef _CharT char_type;
24440a187bbSMartin Storsjö   typedef char_traits<char_type> traits_type;
24540a187bbSMartin Storsjö   typedef typename traits_type::int_type int_type;
24640a187bbSMartin Storsjö   typedef typename traits_type::pos_type pos_type;
24740a187bbSMartin Storsjö   typedef typename traits_type::off_type off_type;
24840a187bbSMartin Storsjö   typedef typename traits_type::state_type state_type;
24940a187bbSMartin Storsjö 
25040a187bbSMartin Storsjö   __stdoutbuf(FILE* __fp, state_type* __st);
25140a187bbSMartin Storsjö 
25240a187bbSMartin Storsjö protected:
25340a187bbSMartin Storsjö   virtual int_type overflow(int_type __c = traits_type::eof());
25440a187bbSMartin Storsjö   virtual streamsize xsputn(const char_type* __s, streamsize __n);
25540a187bbSMartin Storsjö   virtual int sync();
25640a187bbSMartin Storsjö   virtual void imbue(const locale& __loc);
25740a187bbSMartin Storsjö 
25840a187bbSMartin Storsjö private:
25940a187bbSMartin Storsjö   FILE* __file_;
26040a187bbSMartin Storsjö   const codecvt<char_type, char, state_type>* __cv_;
26140a187bbSMartin Storsjö   state_type* __st_;
26240a187bbSMartin Storsjö   bool __always_noconv_;
26340a187bbSMartin Storsjö 
264fcbbd964SMartin Storsjö #if defined(_LIBCPP_WIN32API)
265fcbbd964SMartin Storsjö   static constexpr bool __is_win32api_wide_char = !is_same_v<_CharT, char>;
266fcbbd964SMartin Storsjö #else
267fcbbd964SMartin Storsjö   static constexpr bool __is_win32api_wide_char = false;
268fcbbd964SMartin Storsjö #endif
269fcbbd964SMartin Storsjö 
27040a187bbSMartin Storsjö   __stdoutbuf(const __stdoutbuf&);
27140a187bbSMartin Storsjö   __stdoutbuf& operator=(const __stdoutbuf&);
2722fd4084fSMark de Wever 
2732fd4084fSMark de Wever   _LIBCPP_EXPORTED_FROM_ABI friend FILE* __get_ostream_file(ostream&);
27440a187bbSMartin Storsjö };
27540a187bbSMartin Storsjö 
27640a187bbSMartin Storsjö template <class _CharT>
27740a187bbSMartin Storsjö __stdoutbuf<_CharT>::__stdoutbuf(FILE* __fp, state_type* __st)
27840a187bbSMartin Storsjö     : __file_(__fp),
27940a187bbSMartin Storsjö       __cv_(&use_facet<codecvt<char_type, char, state_type> >(this->getloc())),
28040a187bbSMartin Storsjö       __st_(__st),
2819783f28cSLouis Dionne       __always_noconv_(__cv_->always_noconv()) {
282fcbbd964SMartin Storsjö   // On Windows, in wchar_t mode, ignore the codecvt from the locale by
283fcbbd964SMartin Storsjö   // default and assume noconv; this passes wchar_t through unmodified to
284fcbbd964SMartin Storsjö   // fputwc, which handles it correctly depending on the actual mode of the
285fcbbd964SMartin Storsjö   // output stream. If the user sets a custom locale with imbue(), that
286fcbbd964SMartin Storsjö   // gets honored.
287fcbbd964SMartin Storsjö   if constexpr (__is_win32api_wide_char)
288fcbbd964SMartin Storsjö     __always_noconv_ = true;
28940a187bbSMartin Storsjö }
29040a187bbSMartin Storsjö 
2912a0f2fa9SMark de Wever inline bool __do_fputc(char __c, FILE* __fp) {
292fcbbd964SMartin Storsjö   if (fwrite(&__c, sizeof(__c), 1, __fp) != 1)
293fcbbd964SMartin Storsjö     return false;
294fcbbd964SMartin Storsjö   return true;
295fcbbd964SMartin Storsjö }
296*c6f3b7bcSNikolas Klauser #if _LIBCPP_HAS_WIDE_CHARACTERS
2972a0f2fa9SMark de Wever inline bool __do_fputc(wchar_t __c, FILE* __fp) {
298fcbbd964SMartin Storsjö   // fputwc works regardless of wide/narrow mode of stdout, while
299fcbbd964SMartin Storsjö   // fwrite of wchar_t only works if the stream actually has been set
300fcbbd964SMartin Storsjö   // into wide mode.
301fcbbd964SMartin Storsjö   if (fputwc(__c, __fp) == WEOF)
302fcbbd964SMartin Storsjö     return false;
303fcbbd964SMartin Storsjö   return true;
304fcbbd964SMartin Storsjö }
305fcbbd964SMartin Storsjö #endif
306fcbbd964SMartin Storsjö 
30740a187bbSMartin Storsjö template <class _CharT>
3089783f28cSLouis Dionne typename __stdoutbuf<_CharT>::int_type __stdoutbuf<_CharT>::overflow(int_type __c) {
30940a187bbSMartin Storsjö   char __extbuf[__limit];
31040a187bbSMartin Storsjö   char_type __1buf;
3119783f28cSLouis Dionne   if (!traits_type::eq_int_type(__c, traits_type::eof())) {
31240a187bbSMartin Storsjö     __1buf = traits_type::to_char_type(__c);
3139783f28cSLouis Dionne     if (__always_noconv_) {
314fcbbd964SMartin Storsjö       if (!__do_fputc(__1buf, __file_))
31540a187bbSMartin Storsjö         return traits_type::eof();
3169783f28cSLouis Dionne     } else {
31740a187bbSMartin Storsjö       char* __extbe = __extbuf;
31840a187bbSMartin Storsjö       codecvt_base::result __r;
31940a187bbSMartin Storsjö       char_type* pbase = &__1buf;
32040a187bbSMartin Storsjö       char_type* pptr  = pbase + 1;
3219783f28cSLouis Dionne       do {
32240a187bbSMartin Storsjö         const char_type* __e;
3239783f28cSLouis Dionne         __r = __cv_->out(*__st_, pbase, pptr, __e, __extbuf, __extbuf + sizeof(__extbuf), __extbe);
32440a187bbSMartin Storsjö         if (__e == pbase)
32540a187bbSMartin Storsjö           return traits_type::eof();
3269783f28cSLouis Dionne         if (__r == codecvt_base::noconv) {
32740a187bbSMartin Storsjö           if (fwrite(pbase, 1, 1, __file_) != 1)
32840a187bbSMartin Storsjö             return traits_type::eof();
3299783f28cSLouis Dionne         } else if (__r == codecvt_base::ok || __r == codecvt_base::partial) {
33040a187bbSMartin Storsjö           size_t __nmemb = static_cast<size_t>(__extbe - __extbuf);
33140a187bbSMartin Storsjö           if (fwrite(__extbuf, 1, __nmemb, __file_) != __nmemb)
33240a187bbSMartin Storsjö             return traits_type::eof();
3339783f28cSLouis Dionne           if (__r == codecvt_base::partial) {
33440a187bbSMartin Storsjö             pbase = const_cast<char_type*>(__e);
33540a187bbSMartin Storsjö           }
3369783f28cSLouis Dionne         } else
33740a187bbSMartin Storsjö           return traits_type::eof();
33840a187bbSMartin Storsjö       } while (__r == codecvt_base::partial);
33940a187bbSMartin Storsjö     }
34040a187bbSMartin Storsjö   }
34140a187bbSMartin Storsjö   return traits_type::not_eof(__c);
34240a187bbSMartin Storsjö }
34340a187bbSMartin Storsjö 
34440a187bbSMartin Storsjö template <class _CharT>
3459783f28cSLouis Dionne streamsize __stdoutbuf<_CharT>::xsputn(const char_type* __s, streamsize __n) {
346fcbbd964SMartin Storsjö   // For wchar_t on Windows, don't call fwrite(), but write characters one
347fcbbd964SMartin Storsjö   // at a time with fputwc(); that works both when stdout is in the default
348fcbbd964SMartin Storsjö   // mode and when it is set to Unicode mode.
349fcbbd964SMartin Storsjö   if (__always_noconv_ && !__is_win32api_wide_char)
35040a187bbSMartin Storsjö     return fwrite(__s, sizeof(char_type), __n, __file_);
35140a187bbSMartin Storsjö   streamsize __i = 0;
35240a187bbSMartin Storsjö   for (; __i < __n; ++__i, ++__s)
35340a187bbSMartin Storsjö     if (overflow(traits_type::to_int_type(*__s)) == traits_type::eof())
35440a187bbSMartin Storsjö       break;
35540a187bbSMartin Storsjö   return __i;
35640a187bbSMartin Storsjö }
35740a187bbSMartin Storsjö 
35840a187bbSMartin Storsjö template <class _CharT>
3599783f28cSLouis Dionne int __stdoutbuf<_CharT>::sync() {
36040a187bbSMartin Storsjö   char __extbuf[__limit];
36140a187bbSMartin Storsjö   codecvt_base::result __r;
3629783f28cSLouis Dionne   do {
36340a187bbSMartin Storsjö     char* __extbe;
3649783f28cSLouis Dionne     __r            = __cv_->unshift(*__st_, __extbuf, __extbuf + sizeof(__extbuf), __extbe);
36540a187bbSMartin Storsjö     size_t __nmemb = static_cast<size_t>(__extbe - __extbuf);
36640a187bbSMartin Storsjö     if (fwrite(__extbuf, 1, __nmemb, __file_) != __nmemb)
36740a187bbSMartin Storsjö       return -1;
36840a187bbSMartin Storsjö   } while (__r == codecvt_base::partial);
36940a187bbSMartin Storsjö   if (__r == codecvt_base::error)
37040a187bbSMartin Storsjö     return -1;
37140a187bbSMartin Storsjö   if (fflush(__file_))
37240a187bbSMartin Storsjö     return -1;
37340a187bbSMartin Storsjö   return 0;
37440a187bbSMartin Storsjö }
37540a187bbSMartin Storsjö 
37640a187bbSMartin Storsjö template <class _CharT>
3779783f28cSLouis Dionne void __stdoutbuf<_CharT>::imbue(const locale& __loc) {
37840a187bbSMartin Storsjö   sync();
37940a187bbSMartin Storsjö   __cv_            = &use_facet<codecvt<char_type, char, state_type> >(__loc);
38040a187bbSMartin Storsjö   __always_noconv_ = __cv_->always_noconv();
38140a187bbSMartin Storsjö }
38240a187bbSMartin Storsjö 
38340a187bbSMartin Storsjö _LIBCPP_END_NAMESPACE_STD
38440a187bbSMartin Storsjö 
38540a187bbSMartin Storsjö _LIBCPP_POP_MACROS
38640a187bbSMartin Storsjö 
38740a187bbSMartin Storsjö #endif // _LIBCPP_STD_STREAM_H
388