xref: /freebsd-src/contrib/llvm-project/libcxx/src/std_stream.h (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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 
2706c3fb27SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD
2806c3fb27SDimitry Andric 
2906c3fb27SDimitry Andric static const int __limit = 8;
3006c3fb27SDimitry Andric 
3106c3fb27SDimitry Andric // __stdinbuf
3206c3fb27SDimitry Andric 
3306c3fb27SDimitry Andric template <class _CharT>
3406c3fb27SDimitry Andric class _LIBCPP_HIDDEN __stdinbuf
3506c3fb27SDimitry Andric     : public basic_streambuf<_CharT, char_traits<_CharT> >
3606c3fb27SDimitry Andric {
3706c3fb27SDimitry Andric public:
3806c3fb27SDimitry Andric     typedef _CharT                           char_type;
3906c3fb27SDimitry Andric     typedef char_traits<char_type>           traits_type;
4006c3fb27SDimitry Andric     typedef typename traits_type::int_type   int_type;
4106c3fb27SDimitry Andric     typedef typename traits_type::pos_type   pos_type;
4206c3fb27SDimitry Andric     typedef typename traits_type::off_type   off_type;
4306c3fb27SDimitry Andric     typedef typename traits_type::state_type state_type;
4406c3fb27SDimitry Andric 
4506c3fb27SDimitry Andric     __stdinbuf(FILE* __fp, state_type* __st);
4606c3fb27SDimitry Andric 
4706c3fb27SDimitry Andric protected:
4806c3fb27SDimitry Andric     virtual int_type underflow();
4906c3fb27SDimitry Andric     virtual int_type uflow();
5006c3fb27SDimitry Andric     virtual int_type pbackfail(int_type __c = traits_type::eof());
5106c3fb27SDimitry Andric     virtual void imbue(const locale& __loc);
5206c3fb27SDimitry Andric 
5306c3fb27SDimitry Andric private:
5406c3fb27SDimitry Andric 
5506c3fb27SDimitry Andric     FILE* __file_;
5606c3fb27SDimitry Andric     const codecvt<char_type, char, state_type>* __cv_;
5706c3fb27SDimitry Andric     state_type* __st_;
5806c3fb27SDimitry Andric     int __encoding_;
5906c3fb27SDimitry Andric     int_type __last_consumed_;
6006c3fb27SDimitry Andric     bool __last_consumed_is_next_;
6106c3fb27SDimitry Andric     bool __always_noconv_;
6206c3fb27SDimitry Andric 
6306c3fb27SDimitry Andric #if defined(_LIBCPP_WIN32API)
6406c3fb27SDimitry Andric     static constexpr bool __is_win32api_wide_char = !is_same_v<_CharT, char>;
6506c3fb27SDimitry Andric #else
6606c3fb27SDimitry Andric     static constexpr bool __is_win32api_wide_char = false;
6706c3fb27SDimitry Andric #endif
6806c3fb27SDimitry Andric 
6906c3fb27SDimitry Andric     __stdinbuf(const __stdinbuf&);
7006c3fb27SDimitry Andric     __stdinbuf& operator=(const __stdinbuf&);
7106c3fb27SDimitry Andric 
7206c3fb27SDimitry Andric     int_type __getchar(bool __consume);
7306c3fb27SDimitry Andric };
7406c3fb27SDimitry Andric 
7506c3fb27SDimitry Andric template <class _CharT>
7606c3fb27SDimitry Andric __stdinbuf<_CharT>::__stdinbuf(FILE* __fp, state_type* __st)
7706c3fb27SDimitry Andric     : __file_(__fp),
7806c3fb27SDimitry Andric       __st_(__st),
7906c3fb27SDimitry Andric       __last_consumed_(traits_type::eof()),
8006c3fb27SDimitry Andric       __last_consumed_is_next_(false)
8106c3fb27SDimitry Andric {
8206c3fb27SDimitry Andric     imbue(this->getloc());
8306c3fb27SDimitry Andric     // On Windows, in wchar_t mode, ignore the codecvt from the locale by
8406c3fb27SDimitry Andric     // default and assume noconv; this passes wchar_t through unmodified from
8506c3fb27SDimitry Andric     // getwc. If the user sets a custom locale with imbue(), that gets honored,
8606c3fb27SDimitry Andric     // the IO is done with getc() and converted with the provided codecvt.
8706c3fb27SDimitry Andric     if constexpr (__is_win32api_wide_char)
8806c3fb27SDimitry Andric         __always_noconv_ = true;
8906c3fb27SDimitry Andric }
9006c3fb27SDimitry Andric 
9106c3fb27SDimitry Andric template <class _CharT>
9206c3fb27SDimitry Andric void
9306c3fb27SDimitry Andric __stdinbuf<_CharT>::imbue(const locale& __loc)
9406c3fb27SDimitry Andric {
9506c3fb27SDimitry Andric     __cv_ = &use_facet<codecvt<char_type, char, state_type> >(__loc);
9606c3fb27SDimitry Andric     __encoding_ = __cv_->encoding();
9706c3fb27SDimitry Andric     __always_noconv_ = __cv_->always_noconv();
9806c3fb27SDimitry Andric     if (__encoding_ > __limit)
9906c3fb27SDimitry Andric         __throw_runtime_error("unsupported locale for standard input");
10006c3fb27SDimitry Andric }
10106c3fb27SDimitry Andric 
10206c3fb27SDimitry Andric template <class _CharT>
10306c3fb27SDimitry Andric typename __stdinbuf<_CharT>::int_type
10406c3fb27SDimitry Andric __stdinbuf<_CharT>::underflow()
10506c3fb27SDimitry Andric {
10606c3fb27SDimitry Andric     return __getchar(false);
10706c3fb27SDimitry Andric }
10806c3fb27SDimitry Andric 
10906c3fb27SDimitry Andric template <class _CharT>
11006c3fb27SDimitry Andric typename __stdinbuf<_CharT>::int_type
11106c3fb27SDimitry Andric __stdinbuf<_CharT>::uflow()
11206c3fb27SDimitry Andric {
11306c3fb27SDimitry Andric     return __getchar(true);
11406c3fb27SDimitry Andric }
11506c3fb27SDimitry Andric 
116*5f757f3fSDimitry Andric inline bool __do_getc(FILE *__fp, char *__pbuf) {
11706c3fb27SDimitry Andric     int __c = getc(__fp);
11806c3fb27SDimitry Andric     if (__c == EOF)
11906c3fb27SDimitry Andric         return false;
12006c3fb27SDimitry Andric     *__pbuf = static_cast<char>(__c);
12106c3fb27SDimitry Andric     return true;
12206c3fb27SDimitry Andric }
12306c3fb27SDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
124*5f757f3fSDimitry Andric inline bool __do_getc(FILE *__fp, wchar_t *__pbuf) {
12506c3fb27SDimitry Andric     wint_t __c = getwc(__fp);
12606c3fb27SDimitry Andric     if (__c == WEOF)
12706c3fb27SDimitry Andric         return false;
12806c3fb27SDimitry Andric     *__pbuf = static_cast<wchar_t>(__c);
12906c3fb27SDimitry Andric     return true;
13006c3fb27SDimitry Andric }
13106c3fb27SDimitry Andric #endif
13206c3fb27SDimitry Andric 
133*5f757f3fSDimitry Andric inline bool __do_ungetc(int __c, FILE *__fp, char __dummy) {
13406c3fb27SDimitry Andric     if (ungetc(__c, __fp) == EOF)
13506c3fb27SDimitry Andric         return false;
13606c3fb27SDimitry Andric     return true;
13706c3fb27SDimitry Andric }
13806c3fb27SDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
139*5f757f3fSDimitry Andric inline bool __do_ungetc(std::wint_t __c, FILE *__fp, wchar_t __dummy) {
14006c3fb27SDimitry Andric     if (ungetwc(__c, __fp) == WEOF)
14106c3fb27SDimitry Andric         return false;
14206c3fb27SDimitry Andric     return true;
14306c3fb27SDimitry Andric }
14406c3fb27SDimitry Andric #endif
14506c3fb27SDimitry Andric 
14606c3fb27SDimitry Andric template <class _CharT>
14706c3fb27SDimitry Andric typename __stdinbuf<_CharT>::int_type
14806c3fb27SDimitry Andric __stdinbuf<_CharT>::__getchar(bool __consume)
14906c3fb27SDimitry Andric {
15006c3fb27SDimitry Andric     if (__last_consumed_is_next_)
15106c3fb27SDimitry Andric     {
15206c3fb27SDimitry Andric         int_type __result = __last_consumed_;
15306c3fb27SDimitry Andric         if (__consume)
15406c3fb27SDimitry Andric         {
15506c3fb27SDimitry Andric             __last_consumed_ = traits_type::eof();
15606c3fb27SDimitry Andric             __last_consumed_is_next_ = false;
15706c3fb27SDimitry Andric         }
15806c3fb27SDimitry Andric         return __result;
15906c3fb27SDimitry Andric     }
16006c3fb27SDimitry Andric     if (__always_noconv_) {
16106c3fb27SDimitry Andric         char_type __1buf;
16206c3fb27SDimitry Andric         if (!__do_getc(__file_, &__1buf))
16306c3fb27SDimitry Andric             return traits_type::eof();
16406c3fb27SDimitry Andric         if (!__consume)
16506c3fb27SDimitry Andric         {
16606c3fb27SDimitry Andric             if (!__do_ungetc(traits_type::to_int_type(__1buf), __file_, __1buf))
16706c3fb27SDimitry Andric                 return traits_type::eof();
16806c3fb27SDimitry Andric         }
16906c3fb27SDimitry Andric         else
17006c3fb27SDimitry Andric             __last_consumed_ = traits_type::to_int_type(__1buf);
17106c3fb27SDimitry Andric         return traits_type::to_int_type(__1buf);
17206c3fb27SDimitry Andric     }
17306c3fb27SDimitry Andric 
17406c3fb27SDimitry Andric     char __extbuf[__limit];
175*5f757f3fSDimitry Andric     int __nread = std::max(1, __encoding_);
17606c3fb27SDimitry Andric     for (int __i = 0; __i < __nread; ++__i)
17706c3fb27SDimitry Andric     {
17806c3fb27SDimitry Andric         int __c = getc(__file_);
17906c3fb27SDimitry Andric         if (__c == EOF)
18006c3fb27SDimitry Andric             return traits_type::eof();
18106c3fb27SDimitry Andric         __extbuf[__i] = static_cast<char>(__c);
18206c3fb27SDimitry Andric     }
18306c3fb27SDimitry Andric     char_type __1buf;
18406c3fb27SDimitry Andric     const char* __enxt;
18506c3fb27SDimitry Andric     char_type* __inxt;
18606c3fb27SDimitry Andric     codecvt_base::result __r;
18706c3fb27SDimitry Andric     do
18806c3fb27SDimitry Andric     {
18906c3fb27SDimitry Andric         state_type __sv_st = *__st_;
19006c3fb27SDimitry Andric         __r = __cv_->in(*__st_, __extbuf, __extbuf + __nread, __enxt,
19106c3fb27SDimitry Andric                                &__1buf, &__1buf + 1, __inxt);
19206c3fb27SDimitry Andric         switch (__r)
19306c3fb27SDimitry Andric         {
194*5f757f3fSDimitry Andric         case std::codecvt_base::ok:
19506c3fb27SDimitry Andric             break;
19606c3fb27SDimitry Andric         case codecvt_base::partial:
19706c3fb27SDimitry Andric             *__st_ = __sv_st;
19806c3fb27SDimitry Andric             if (__nread == sizeof(__extbuf))
19906c3fb27SDimitry Andric                 return traits_type::eof();
20006c3fb27SDimitry Andric             {
20106c3fb27SDimitry Andric                 int __c = getc(__file_);
20206c3fb27SDimitry Andric                 if (__c == EOF)
20306c3fb27SDimitry Andric                     return traits_type::eof();
20406c3fb27SDimitry Andric                 __extbuf[__nread] = static_cast<char>(__c);
20506c3fb27SDimitry Andric             }
20606c3fb27SDimitry Andric             ++__nread;
20706c3fb27SDimitry Andric             break;
20806c3fb27SDimitry Andric         case codecvt_base::error:
20906c3fb27SDimitry Andric             return traits_type::eof();
210*5f757f3fSDimitry Andric         case std::codecvt_base::noconv:
21106c3fb27SDimitry Andric             __1buf = static_cast<char_type>(__extbuf[0]);
21206c3fb27SDimitry Andric             break;
21306c3fb27SDimitry Andric         }
214*5f757f3fSDimitry Andric     } while (__r == std::codecvt_base::partial);
21506c3fb27SDimitry Andric     if (!__consume)
21606c3fb27SDimitry Andric     {
21706c3fb27SDimitry Andric         for (int __i = __nread; __i > 0;)
21806c3fb27SDimitry Andric         {
21906c3fb27SDimitry Andric             if (ungetc(traits_type::to_int_type(__extbuf[--__i]), __file_) == EOF)
22006c3fb27SDimitry Andric                 return traits_type::eof();
22106c3fb27SDimitry Andric         }
22206c3fb27SDimitry Andric     }
22306c3fb27SDimitry Andric     else
22406c3fb27SDimitry Andric         __last_consumed_ = traits_type::to_int_type(__1buf);
22506c3fb27SDimitry Andric     return traits_type::to_int_type(__1buf);
22606c3fb27SDimitry Andric }
22706c3fb27SDimitry Andric 
22806c3fb27SDimitry Andric template <class _CharT>
22906c3fb27SDimitry Andric typename __stdinbuf<_CharT>::int_type
23006c3fb27SDimitry Andric __stdinbuf<_CharT>::pbackfail(int_type __c)
23106c3fb27SDimitry Andric {
23206c3fb27SDimitry Andric     if (traits_type::eq_int_type(__c, traits_type::eof()))
23306c3fb27SDimitry Andric     {
23406c3fb27SDimitry Andric         if (!__last_consumed_is_next_)
23506c3fb27SDimitry Andric         {
23606c3fb27SDimitry Andric             __c = __last_consumed_;
23706c3fb27SDimitry Andric             __last_consumed_is_next_ = !traits_type::eq_int_type(__last_consumed_,
23806c3fb27SDimitry Andric                                                                  traits_type::eof());
23906c3fb27SDimitry Andric         }
24006c3fb27SDimitry Andric         return __c;
24106c3fb27SDimitry Andric     }
24206c3fb27SDimitry Andric     if (__always_noconv_ && __last_consumed_is_next_) {
24306c3fb27SDimitry Andric         if (!__do_ungetc(__last_consumed_, __file_,
24406c3fb27SDimitry Andric                          traits_type::to_char_type(__last_consumed_)))
24506c3fb27SDimitry Andric             return traits_type::eof();
24606c3fb27SDimitry Andric     } else if (__last_consumed_is_next_) {
24706c3fb27SDimitry Andric         char __extbuf[__limit];
24806c3fb27SDimitry Andric         char* __enxt;
24906c3fb27SDimitry Andric         const char_type __ci = traits_type::to_char_type(__last_consumed_);
25006c3fb27SDimitry Andric         const char_type* __inxt;
25106c3fb27SDimitry Andric         switch (__cv_->out(*__st_, &__ci, &__ci + 1, __inxt,
25206c3fb27SDimitry Andric                                   __extbuf, __extbuf + sizeof(__extbuf), __enxt))
25306c3fb27SDimitry Andric         {
254*5f757f3fSDimitry Andric         case std::codecvt_base::ok:
25506c3fb27SDimitry Andric             break;
256*5f757f3fSDimitry Andric         case std::codecvt_base::noconv:
25706c3fb27SDimitry Andric             __extbuf[0] = static_cast<char>(__last_consumed_);
25806c3fb27SDimitry Andric             __enxt = __extbuf + 1;
25906c3fb27SDimitry Andric             break;
26006c3fb27SDimitry Andric         case codecvt_base::partial:
26106c3fb27SDimitry Andric         case codecvt_base::error:
26206c3fb27SDimitry Andric             return traits_type::eof();
26306c3fb27SDimitry Andric         }
26406c3fb27SDimitry Andric         while (__enxt > __extbuf)
26506c3fb27SDimitry Andric             if (ungetc(*--__enxt, __file_) == EOF)
26606c3fb27SDimitry Andric                 return traits_type::eof();
26706c3fb27SDimitry Andric     }
26806c3fb27SDimitry Andric     __last_consumed_ = __c;
26906c3fb27SDimitry Andric     __last_consumed_is_next_ = true;
27006c3fb27SDimitry Andric     return __c;
27106c3fb27SDimitry Andric }
27206c3fb27SDimitry Andric 
27306c3fb27SDimitry Andric // __stdoutbuf
27406c3fb27SDimitry Andric 
27506c3fb27SDimitry Andric template <class _CharT>
27606c3fb27SDimitry Andric class _LIBCPP_HIDDEN __stdoutbuf
27706c3fb27SDimitry Andric     : public basic_streambuf<_CharT, char_traits<_CharT> >
27806c3fb27SDimitry Andric {
27906c3fb27SDimitry Andric public:
28006c3fb27SDimitry Andric     typedef _CharT                           char_type;
28106c3fb27SDimitry Andric     typedef char_traits<char_type>           traits_type;
28206c3fb27SDimitry Andric     typedef typename traits_type::int_type   int_type;
28306c3fb27SDimitry Andric     typedef typename traits_type::pos_type   pos_type;
28406c3fb27SDimitry Andric     typedef typename traits_type::off_type   off_type;
28506c3fb27SDimitry Andric     typedef typename traits_type::state_type state_type;
28606c3fb27SDimitry Andric 
28706c3fb27SDimitry Andric     __stdoutbuf(FILE* __fp, state_type* __st);
28806c3fb27SDimitry Andric 
28906c3fb27SDimitry Andric protected:
29006c3fb27SDimitry Andric     virtual int_type overflow (int_type __c = traits_type::eof());
29106c3fb27SDimitry Andric     virtual streamsize xsputn(const char_type* __s, streamsize __n);
29206c3fb27SDimitry Andric     virtual int sync();
29306c3fb27SDimitry Andric     virtual void imbue(const locale& __loc);
29406c3fb27SDimitry Andric 
29506c3fb27SDimitry Andric private:
29606c3fb27SDimitry Andric     FILE* __file_;
29706c3fb27SDimitry Andric     const codecvt<char_type, char, state_type>* __cv_;
29806c3fb27SDimitry Andric     state_type* __st_;
29906c3fb27SDimitry Andric     bool __always_noconv_;
30006c3fb27SDimitry Andric 
30106c3fb27SDimitry Andric #if defined(_LIBCPP_WIN32API)
30206c3fb27SDimitry Andric     static constexpr bool __is_win32api_wide_char = !is_same_v<_CharT, char>;
30306c3fb27SDimitry Andric #else
30406c3fb27SDimitry Andric     static constexpr bool __is_win32api_wide_char = false;
30506c3fb27SDimitry Andric #endif
30606c3fb27SDimitry Andric 
30706c3fb27SDimitry Andric     __stdoutbuf(const __stdoutbuf&);
30806c3fb27SDimitry Andric     __stdoutbuf& operator=(const __stdoutbuf&);
30906c3fb27SDimitry Andric };
31006c3fb27SDimitry Andric 
31106c3fb27SDimitry Andric template <class _CharT>
31206c3fb27SDimitry Andric __stdoutbuf<_CharT>::__stdoutbuf(FILE* __fp, state_type* __st)
31306c3fb27SDimitry Andric     : __file_(__fp),
31406c3fb27SDimitry Andric       __cv_(&use_facet<codecvt<char_type, char, state_type> >(this->getloc())),
31506c3fb27SDimitry Andric       __st_(__st),
31606c3fb27SDimitry Andric       __always_noconv_(__cv_->always_noconv())
31706c3fb27SDimitry Andric {
31806c3fb27SDimitry Andric     // On Windows, in wchar_t mode, ignore the codecvt from the locale by
31906c3fb27SDimitry Andric     // default and assume noconv; this passes wchar_t through unmodified to
32006c3fb27SDimitry Andric     // fputwc, which handles it correctly depending on the actual mode of the
32106c3fb27SDimitry Andric     // output stream. If the user sets a custom locale with imbue(), that
32206c3fb27SDimitry Andric     // gets honored.
32306c3fb27SDimitry Andric     if constexpr (__is_win32api_wide_char)
32406c3fb27SDimitry Andric         __always_noconv_ = true;
32506c3fb27SDimitry Andric }
32606c3fb27SDimitry Andric 
327*5f757f3fSDimitry Andric inline bool __do_fputc(char __c, FILE* __fp) {
32806c3fb27SDimitry Andric     if (fwrite(&__c, sizeof(__c), 1, __fp) != 1)
32906c3fb27SDimitry Andric         return false;
33006c3fb27SDimitry Andric     return true;
33106c3fb27SDimitry Andric }
33206c3fb27SDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
333*5f757f3fSDimitry Andric inline bool __do_fputc(wchar_t __c, FILE* __fp) {
33406c3fb27SDimitry Andric     // fputwc works regardless of wide/narrow mode of stdout, while
33506c3fb27SDimitry Andric     // fwrite of wchar_t only works if the stream actually has been set
33606c3fb27SDimitry Andric     // into wide mode.
33706c3fb27SDimitry Andric     if (fputwc(__c, __fp) == WEOF)
33806c3fb27SDimitry Andric         return false;
33906c3fb27SDimitry Andric     return true;
34006c3fb27SDimitry Andric }
34106c3fb27SDimitry Andric #endif
34206c3fb27SDimitry Andric 
34306c3fb27SDimitry Andric template <class _CharT>
34406c3fb27SDimitry Andric typename __stdoutbuf<_CharT>::int_type
34506c3fb27SDimitry Andric __stdoutbuf<_CharT>::overflow(int_type __c)
34606c3fb27SDimitry Andric {
34706c3fb27SDimitry Andric     char __extbuf[__limit];
34806c3fb27SDimitry Andric     char_type __1buf;
34906c3fb27SDimitry Andric     if (!traits_type::eq_int_type(__c, traits_type::eof()))
35006c3fb27SDimitry Andric     {
35106c3fb27SDimitry Andric         __1buf = traits_type::to_char_type(__c);
35206c3fb27SDimitry Andric         if (__always_noconv_)
35306c3fb27SDimitry Andric         {
35406c3fb27SDimitry Andric             if (!__do_fputc(__1buf, __file_))
35506c3fb27SDimitry Andric                 return traits_type::eof();
35606c3fb27SDimitry Andric         }
35706c3fb27SDimitry Andric         else
35806c3fb27SDimitry Andric         {
35906c3fb27SDimitry Andric             char* __extbe = __extbuf;
36006c3fb27SDimitry Andric             codecvt_base::result __r;
36106c3fb27SDimitry Andric             char_type* pbase = &__1buf;
36206c3fb27SDimitry Andric             char_type* pptr = pbase + 1;
36306c3fb27SDimitry Andric             do
36406c3fb27SDimitry Andric             {
36506c3fb27SDimitry Andric                 const char_type* __e;
36606c3fb27SDimitry Andric                 __r = __cv_->out(*__st_, pbase, pptr, __e,
36706c3fb27SDimitry Andric                                         __extbuf,
36806c3fb27SDimitry Andric                                         __extbuf + sizeof(__extbuf),
36906c3fb27SDimitry Andric                                         __extbe);
37006c3fb27SDimitry Andric                 if (__e == pbase)
37106c3fb27SDimitry Andric                     return traits_type::eof();
37206c3fb27SDimitry Andric                 if (__r == codecvt_base::noconv)
37306c3fb27SDimitry Andric                 {
37406c3fb27SDimitry Andric                     if (fwrite(pbase, 1, 1, __file_) != 1)
37506c3fb27SDimitry Andric                         return traits_type::eof();
37606c3fb27SDimitry Andric                 }
37706c3fb27SDimitry Andric                 else if (__r == codecvt_base::ok || __r == codecvt_base::partial)
37806c3fb27SDimitry Andric                 {
37906c3fb27SDimitry Andric                     size_t __nmemb = static_cast<size_t>(__extbe - __extbuf);
38006c3fb27SDimitry Andric                     if (fwrite(__extbuf, 1, __nmemb, __file_) != __nmemb)
38106c3fb27SDimitry Andric                         return traits_type::eof();
38206c3fb27SDimitry Andric                     if (__r == codecvt_base::partial)
38306c3fb27SDimitry Andric                     {
38406c3fb27SDimitry Andric                         pbase = const_cast<char_type*>(__e);
38506c3fb27SDimitry Andric                     }
38606c3fb27SDimitry Andric                 }
38706c3fb27SDimitry Andric                 else
38806c3fb27SDimitry Andric                     return traits_type::eof();
38906c3fb27SDimitry Andric             } while (__r == codecvt_base::partial);
39006c3fb27SDimitry Andric         }
39106c3fb27SDimitry Andric     }
39206c3fb27SDimitry Andric     return traits_type::not_eof(__c);
39306c3fb27SDimitry Andric }
39406c3fb27SDimitry Andric 
39506c3fb27SDimitry Andric template <class _CharT>
39606c3fb27SDimitry Andric streamsize
39706c3fb27SDimitry Andric __stdoutbuf<_CharT>::xsputn(const char_type* __s, streamsize __n)
39806c3fb27SDimitry Andric {
39906c3fb27SDimitry Andric     // For wchar_t on Windows, don't call fwrite(), but write characters one
40006c3fb27SDimitry Andric     // at a time with fputwc(); that works both when stdout is in the default
40106c3fb27SDimitry Andric     // mode and when it is set to Unicode mode.
40206c3fb27SDimitry Andric     if (__always_noconv_ && !__is_win32api_wide_char)
40306c3fb27SDimitry Andric         return fwrite(__s, sizeof(char_type), __n, __file_);
40406c3fb27SDimitry Andric     streamsize __i = 0;
40506c3fb27SDimitry Andric     for (; __i < __n; ++__i, ++__s)
40606c3fb27SDimitry Andric         if (overflow(traits_type::to_int_type(*__s)) == traits_type::eof())
40706c3fb27SDimitry Andric             break;
40806c3fb27SDimitry Andric     return __i;
40906c3fb27SDimitry Andric }
41006c3fb27SDimitry Andric 
41106c3fb27SDimitry Andric template <class _CharT>
41206c3fb27SDimitry Andric int
41306c3fb27SDimitry Andric __stdoutbuf<_CharT>::sync()
41406c3fb27SDimitry Andric {
41506c3fb27SDimitry Andric     char __extbuf[__limit];
41606c3fb27SDimitry Andric     codecvt_base::result __r;
41706c3fb27SDimitry Andric     do
41806c3fb27SDimitry Andric     {
41906c3fb27SDimitry Andric         char* __extbe;
42006c3fb27SDimitry Andric         __r = __cv_->unshift(*__st_, __extbuf,
42106c3fb27SDimitry Andric                                     __extbuf + sizeof(__extbuf),
42206c3fb27SDimitry Andric                                     __extbe);
42306c3fb27SDimitry Andric         size_t __nmemb = static_cast<size_t>(__extbe - __extbuf);
42406c3fb27SDimitry Andric         if (fwrite(__extbuf, 1, __nmemb, __file_) != __nmemb)
42506c3fb27SDimitry Andric             return -1;
42606c3fb27SDimitry Andric     } while (__r == codecvt_base::partial);
42706c3fb27SDimitry Andric     if (__r == codecvt_base::error)
42806c3fb27SDimitry Andric         return -1;
42906c3fb27SDimitry Andric     if (fflush(__file_))
43006c3fb27SDimitry Andric         return -1;
43106c3fb27SDimitry Andric     return 0;
43206c3fb27SDimitry Andric }
43306c3fb27SDimitry Andric 
43406c3fb27SDimitry Andric template <class _CharT>
43506c3fb27SDimitry Andric void
43606c3fb27SDimitry Andric __stdoutbuf<_CharT>::imbue(const locale& __loc)
43706c3fb27SDimitry Andric {
43806c3fb27SDimitry Andric     sync();
43906c3fb27SDimitry Andric     __cv_ = &use_facet<codecvt<char_type, char, state_type> >(__loc);
44006c3fb27SDimitry Andric     __always_noconv_ = __cv_->always_noconv();
44106c3fb27SDimitry Andric }
44206c3fb27SDimitry Andric 
44306c3fb27SDimitry Andric _LIBCPP_END_NAMESPACE_STD
44406c3fb27SDimitry Andric 
44506c3fb27SDimitry Andric _LIBCPP_POP_MACROS
44606c3fb27SDimitry Andric 
44706c3fb27SDimitry Andric #endif // _LIBCPP_STD_STREAM_H
448