xref: /freebsd-src/contrib/llvm-project/libcxx/src/std_stream.h (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
1*06c3fb27SDimitry Andric // -*- C++ -*-
2*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
3*06c3fb27SDimitry Andric //
4*06c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5*06c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
6*06c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7*06c3fb27SDimitry Andric //
8*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
9*06c3fb27SDimitry Andric 
10*06c3fb27SDimitry Andric #ifndef _LIBCPP_STD_STREAM_H
11*06c3fb27SDimitry Andric #define _LIBCPP_STD_STREAM_H
12*06c3fb27SDimitry Andric 
13*06c3fb27SDimitry Andric #include <__config>
14*06c3fb27SDimitry Andric #include <__locale>
15*06c3fb27SDimitry Andric #include <cstdio>
16*06c3fb27SDimitry Andric #include <istream>
17*06c3fb27SDimitry Andric #include <ostream>
18*06c3fb27SDimitry Andric 
19*06c3fb27SDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
20*06c3fb27SDimitry Andric #  pragma GCC system_header
21*06c3fb27SDimitry Andric #endif
22*06c3fb27SDimitry Andric 
23*06c3fb27SDimitry Andric _LIBCPP_PUSH_MACROS
24*06c3fb27SDimitry Andric #include <__undef_macros>
25*06c3fb27SDimitry Andric 
26*06c3fb27SDimitry Andric 
27*06c3fb27SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD
28*06c3fb27SDimitry Andric 
29*06c3fb27SDimitry Andric static const int __limit = 8;
30*06c3fb27SDimitry Andric 
31*06c3fb27SDimitry Andric // __stdinbuf
32*06c3fb27SDimitry Andric 
33*06c3fb27SDimitry Andric template <class _CharT>
34*06c3fb27SDimitry Andric class _LIBCPP_HIDDEN __stdinbuf
35*06c3fb27SDimitry Andric     : public basic_streambuf<_CharT, char_traits<_CharT> >
36*06c3fb27SDimitry Andric {
37*06c3fb27SDimitry Andric public:
38*06c3fb27SDimitry Andric     typedef _CharT                           char_type;
39*06c3fb27SDimitry Andric     typedef char_traits<char_type>           traits_type;
40*06c3fb27SDimitry Andric     typedef typename traits_type::int_type   int_type;
41*06c3fb27SDimitry Andric     typedef typename traits_type::pos_type   pos_type;
42*06c3fb27SDimitry Andric     typedef typename traits_type::off_type   off_type;
43*06c3fb27SDimitry Andric     typedef typename traits_type::state_type state_type;
44*06c3fb27SDimitry Andric 
45*06c3fb27SDimitry Andric     __stdinbuf(FILE* __fp, state_type* __st);
46*06c3fb27SDimitry Andric 
47*06c3fb27SDimitry Andric protected:
48*06c3fb27SDimitry Andric     virtual int_type underflow();
49*06c3fb27SDimitry Andric     virtual int_type uflow();
50*06c3fb27SDimitry Andric     virtual int_type pbackfail(int_type __c = traits_type::eof());
51*06c3fb27SDimitry Andric     virtual void imbue(const locale& __loc);
52*06c3fb27SDimitry Andric 
53*06c3fb27SDimitry Andric private:
54*06c3fb27SDimitry Andric 
55*06c3fb27SDimitry Andric     FILE* __file_;
56*06c3fb27SDimitry Andric     const codecvt<char_type, char, state_type>* __cv_;
57*06c3fb27SDimitry Andric     state_type* __st_;
58*06c3fb27SDimitry Andric     int __encoding_;
59*06c3fb27SDimitry Andric     int_type __last_consumed_;
60*06c3fb27SDimitry Andric     bool __last_consumed_is_next_;
61*06c3fb27SDimitry Andric     bool __always_noconv_;
62*06c3fb27SDimitry Andric 
63*06c3fb27SDimitry Andric #if defined(_LIBCPP_WIN32API)
64*06c3fb27SDimitry Andric     static constexpr bool __is_win32api_wide_char = !is_same_v<_CharT, char>;
65*06c3fb27SDimitry Andric #else
66*06c3fb27SDimitry Andric     static constexpr bool __is_win32api_wide_char = false;
67*06c3fb27SDimitry Andric #endif
68*06c3fb27SDimitry Andric 
69*06c3fb27SDimitry Andric     __stdinbuf(const __stdinbuf&);
70*06c3fb27SDimitry Andric     __stdinbuf& operator=(const __stdinbuf&);
71*06c3fb27SDimitry Andric 
72*06c3fb27SDimitry Andric     int_type __getchar(bool __consume);
73*06c3fb27SDimitry Andric };
74*06c3fb27SDimitry Andric 
75*06c3fb27SDimitry Andric template <class _CharT>
76*06c3fb27SDimitry Andric __stdinbuf<_CharT>::__stdinbuf(FILE* __fp, state_type* __st)
77*06c3fb27SDimitry Andric     : __file_(__fp),
78*06c3fb27SDimitry Andric       __st_(__st),
79*06c3fb27SDimitry Andric       __last_consumed_(traits_type::eof()),
80*06c3fb27SDimitry Andric       __last_consumed_is_next_(false)
81*06c3fb27SDimitry Andric {
82*06c3fb27SDimitry Andric     imbue(this->getloc());
83*06c3fb27SDimitry Andric     // On Windows, in wchar_t mode, ignore the codecvt from the locale by
84*06c3fb27SDimitry Andric     // default and assume noconv; this passes wchar_t through unmodified from
85*06c3fb27SDimitry Andric     // getwc. If the user sets a custom locale with imbue(), that gets honored,
86*06c3fb27SDimitry Andric     // the IO is done with getc() and converted with the provided codecvt.
87*06c3fb27SDimitry Andric     if constexpr (__is_win32api_wide_char)
88*06c3fb27SDimitry Andric         __always_noconv_ = true;
89*06c3fb27SDimitry Andric }
90*06c3fb27SDimitry Andric 
91*06c3fb27SDimitry Andric template <class _CharT>
92*06c3fb27SDimitry Andric void
93*06c3fb27SDimitry Andric __stdinbuf<_CharT>::imbue(const locale& __loc)
94*06c3fb27SDimitry Andric {
95*06c3fb27SDimitry Andric     __cv_ = &use_facet<codecvt<char_type, char, state_type> >(__loc);
96*06c3fb27SDimitry Andric     __encoding_ = __cv_->encoding();
97*06c3fb27SDimitry Andric     __always_noconv_ = __cv_->always_noconv();
98*06c3fb27SDimitry Andric     if (__encoding_ > __limit)
99*06c3fb27SDimitry Andric         __throw_runtime_error("unsupported locale for standard input");
100*06c3fb27SDimitry Andric }
101*06c3fb27SDimitry Andric 
102*06c3fb27SDimitry Andric template <class _CharT>
103*06c3fb27SDimitry Andric typename __stdinbuf<_CharT>::int_type
104*06c3fb27SDimitry Andric __stdinbuf<_CharT>::underflow()
105*06c3fb27SDimitry Andric {
106*06c3fb27SDimitry Andric     return __getchar(false);
107*06c3fb27SDimitry Andric }
108*06c3fb27SDimitry Andric 
109*06c3fb27SDimitry Andric template <class _CharT>
110*06c3fb27SDimitry Andric typename __stdinbuf<_CharT>::int_type
111*06c3fb27SDimitry Andric __stdinbuf<_CharT>::uflow()
112*06c3fb27SDimitry Andric {
113*06c3fb27SDimitry Andric     return __getchar(true);
114*06c3fb27SDimitry Andric }
115*06c3fb27SDimitry Andric 
116*06c3fb27SDimitry Andric static bool __do_getc(FILE *__fp, char *__pbuf) {
117*06c3fb27SDimitry Andric     int __c = getc(__fp);
118*06c3fb27SDimitry Andric     if (__c == EOF)
119*06c3fb27SDimitry Andric         return false;
120*06c3fb27SDimitry Andric     *__pbuf = static_cast<char>(__c);
121*06c3fb27SDimitry Andric     return true;
122*06c3fb27SDimitry Andric }
123*06c3fb27SDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
124*06c3fb27SDimitry Andric static bool __do_getc(FILE *__fp, wchar_t *__pbuf) {
125*06c3fb27SDimitry Andric     wint_t __c = getwc(__fp);
126*06c3fb27SDimitry Andric     if (__c == WEOF)
127*06c3fb27SDimitry Andric         return false;
128*06c3fb27SDimitry Andric     *__pbuf = static_cast<wchar_t>(__c);
129*06c3fb27SDimitry Andric     return true;
130*06c3fb27SDimitry Andric }
131*06c3fb27SDimitry Andric #endif
132*06c3fb27SDimitry Andric 
133*06c3fb27SDimitry Andric static bool __do_ungetc(int __c, FILE *__fp, char __dummy) {
134*06c3fb27SDimitry Andric     if (ungetc(__c, __fp) == EOF)
135*06c3fb27SDimitry Andric         return false;
136*06c3fb27SDimitry Andric     return true;
137*06c3fb27SDimitry Andric }
138*06c3fb27SDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
139*06c3fb27SDimitry Andric static bool __do_ungetc(std::wint_t __c, FILE *__fp, wchar_t __dummy) {
140*06c3fb27SDimitry Andric     if (ungetwc(__c, __fp) == WEOF)
141*06c3fb27SDimitry Andric         return false;
142*06c3fb27SDimitry Andric     return true;
143*06c3fb27SDimitry Andric }
144*06c3fb27SDimitry Andric #endif
145*06c3fb27SDimitry Andric 
146*06c3fb27SDimitry Andric template <class _CharT>
147*06c3fb27SDimitry Andric typename __stdinbuf<_CharT>::int_type
148*06c3fb27SDimitry Andric __stdinbuf<_CharT>::__getchar(bool __consume)
149*06c3fb27SDimitry Andric {
150*06c3fb27SDimitry Andric     if (__last_consumed_is_next_)
151*06c3fb27SDimitry Andric     {
152*06c3fb27SDimitry Andric         int_type __result = __last_consumed_;
153*06c3fb27SDimitry Andric         if (__consume)
154*06c3fb27SDimitry Andric         {
155*06c3fb27SDimitry Andric             __last_consumed_ = traits_type::eof();
156*06c3fb27SDimitry Andric             __last_consumed_is_next_ = false;
157*06c3fb27SDimitry Andric         }
158*06c3fb27SDimitry Andric         return __result;
159*06c3fb27SDimitry Andric     }
160*06c3fb27SDimitry Andric     if (__always_noconv_) {
161*06c3fb27SDimitry Andric         char_type __1buf;
162*06c3fb27SDimitry Andric         if (!__do_getc(__file_, &__1buf))
163*06c3fb27SDimitry Andric             return traits_type::eof();
164*06c3fb27SDimitry Andric         if (!__consume)
165*06c3fb27SDimitry Andric         {
166*06c3fb27SDimitry Andric             if (!__do_ungetc(traits_type::to_int_type(__1buf), __file_, __1buf))
167*06c3fb27SDimitry Andric                 return traits_type::eof();
168*06c3fb27SDimitry Andric         }
169*06c3fb27SDimitry Andric         else
170*06c3fb27SDimitry Andric             __last_consumed_ = traits_type::to_int_type(__1buf);
171*06c3fb27SDimitry Andric         return traits_type::to_int_type(__1buf);
172*06c3fb27SDimitry Andric     }
173*06c3fb27SDimitry Andric 
174*06c3fb27SDimitry Andric     char __extbuf[__limit];
175*06c3fb27SDimitry Andric     int __nread = _VSTD::max(1, __encoding_);
176*06c3fb27SDimitry Andric     for (int __i = 0; __i < __nread; ++__i)
177*06c3fb27SDimitry Andric     {
178*06c3fb27SDimitry Andric         int __c = getc(__file_);
179*06c3fb27SDimitry Andric         if (__c == EOF)
180*06c3fb27SDimitry Andric             return traits_type::eof();
181*06c3fb27SDimitry Andric         __extbuf[__i] = static_cast<char>(__c);
182*06c3fb27SDimitry Andric     }
183*06c3fb27SDimitry Andric     char_type __1buf;
184*06c3fb27SDimitry Andric     const char* __enxt;
185*06c3fb27SDimitry Andric     char_type* __inxt;
186*06c3fb27SDimitry Andric     codecvt_base::result __r;
187*06c3fb27SDimitry Andric     do
188*06c3fb27SDimitry Andric     {
189*06c3fb27SDimitry Andric         state_type __sv_st = *__st_;
190*06c3fb27SDimitry Andric         __r = __cv_->in(*__st_, __extbuf, __extbuf + __nread, __enxt,
191*06c3fb27SDimitry Andric                                &__1buf, &__1buf + 1, __inxt);
192*06c3fb27SDimitry Andric         switch (__r)
193*06c3fb27SDimitry Andric         {
194*06c3fb27SDimitry Andric         case _VSTD::codecvt_base::ok:
195*06c3fb27SDimitry Andric             break;
196*06c3fb27SDimitry Andric         case codecvt_base::partial:
197*06c3fb27SDimitry Andric             *__st_ = __sv_st;
198*06c3fb27SDimitry Andric             if (__nread == sizeof(__extbuf))
199*06c3fb27SDimitry Andric                 return traits_type::eof();
200*06c3fb27SDimitry Andric             {
201*06c3fb27SDimitry Andric                 int __c = getc(__file_);
202*06c3fb27SDimitry Andric                 if (__c == EOF)
203*06c3fb27SDimitry Andric                     return traits_type::eof();
204*06c3fb27SDimitry Andric                 __extbuf[__nread] = static_cast<char>(__c);
205*06c3fb27SDimitry Andric             }
206*06c3fb27SDimitry Andric             ++__nread;
207*06c3fb27SDimitry Andric             break;
208*06c3fb27SDimitry Andric         case codecvt_base::error:
209*06c3fb27SDimitry Andric             return traits_type::eof();
210*06c3fb27SDimitry Andric         case _VSTD::codecvt_base::noconv:
211*06c3fb27SDimitry Andric             __1buf = static_cast<char_type>(__extbuf[0]);
212*06c3fb27SDimitry Andric             break;
213*06c3fb27SDimitry Andric         }
214*06c3fb27SDimitry Andric     } while (__r == _VSTD::codecvt_base::partial);
215*06c3fb27SDimitry Andric     if (!__consume)
216*06c3fb27SDimitry Andric     {
217*06c3fb27SDimitry Andric         for (int __i = __nread; __i > 0;)
218*06c3fb27SDimitry Andric         {
219*06c3fb27SDimitry Andric             if (ungetc(traits_type::to_int_type(__extbuf[--__i]), __file_) == EOF)
220*06c3fb27SDimitry Andric                 return traits_type::eof();
221*06c3fb27SDimitry Andric         }
222*06c3fb27SDimitry Andric     }
223*06c3fb27SDimitry Andric     else
224*06c3fb27SDimitry Andric         __last_consumed_ = traits_type::to_int_type(__1buf);
225*06c3fb27SDimitry Andric     return traits_type::to_int_type(__1buf);
226*06c3fb27SDimitry Andric }
227*06c3fb27SDimitry Andric 
228*06c3fb27SDimitry Andric template <class _CharT>
229*06c3fb27SDimitry Andric typename __stdinbuf<_CharT>::int_type
230*06c3fb27SDimitry Andric __stdinbuf<_CharT>::pbackfail(int_type __c)
231*06c3fb27SDimitry Andric {
232*06c3fb27SDimitry Andric     if (traits_type::eq_int_type(__c, traits_type::eof()))
233*06c3fb27SDimitry Andric     {
234*06c3fb27SDimitry Andric         if (!__last_consumed_is_next_)
235*06c3fb27SDimitry Andric         {
236*06c3fb27SDimitry Andric             __c = __last_consumed_;
237*06c3fb27SDimitry Andric             __last_consumed_is_next_ = !traits_type::eq_int_type(__last_consumed_,
238*06c3fb27SDimitry Andric                                                                  traits_type::eof());
239*06c3fb27SDimitry Andric         }
240*06c3fb27SDimitry Andric         return __c;
241*06c3fb27SDimitry Andric     }
242*06c3fb27SDimitry Andric     if (__always_noconv_ && __last_consumed_is_next_) {
243*06c3fb27SDimitry Andric         if (!__do_ungetc(__last_consumed_, __file_,
244*06c3fb27SDimitry Andric                          traits_type::to_char_type(__last_consumed_)))
245*06c3fb27SDimitry Andric             return traits_type::eof();
246*06c3fb27SDimitry Andric     } else if (__last_consumed_is_next_) {
247*06c3fb27SDimitry Andric         char __extbuf[__limit];
248*06c3fb27SDimitry Andric         char* __enxt;
249*06c3fb27SDimitry Andric         const char_type __ci = traits_type::to_char_type(__last_consumed_);
250*06c3fb27SDimitry Andric         const char_type* __inxt;
251*06c3fb27SDimitry Andric         switch (__cv_->out(*__st_, &__ci, &__ci + 1, __inxt,
252*06c3fb27SDimitry Andric                                   __extbuf, __extbuf + sizeof(__extbuf), __enxt))
253*06c3fb27SDimitry Andric         {
254*06c3fb27SDimitry Andric         case _VSTD::codecvt_base::ok:
255*06c3fb27SDimitry Andric             break;
256*06c3fb27SDimitry Andric         case _VSTD::codecvt_base::noconv:
257*06c3fb27SDimitry Andric             __extbuf[0] = static_cast<char>(__last_consumed_);
258*06c3fb27SDimitry Andric             __enxt = __extbuf + 1;
259*06c3fb27SDimitry Andric             break;
260*06c3fb27SDimitry Andric         case codecvt_base::partial:
261*06c3fb27SDimitry Andric         case codecvt_base::error:
262*06c3fb27SDimitry Andric             return traits_type::eof();
263*06c3fb27SDimitry Andric         }
264*06c3fb27SDimitry Andric         while (__enxt > __extbuf)
265*06c3fb27SDimitry Andric             if (ungetc(*--__enxt, __file_) == EOF)
266*06c3fb27SDimitry Andric                 return traits_type::eof();
267*06c3fb27SDimitry Andric     }
268*06c3fb27SDimitry Andric     __last_consumed_ = __c;
269*06c3fb27SDimitry Andric     __last_consumed_is_next_ = true;
270*06c3fb27SDimitry Andric     return __c;
271*06c3fb27SDimitry Andric }
272*06c3fb27SDimitry Andric 
273*06c3fb27SDimitry Andric // __stdoutbuf
274*06c3fb27SDimitry Andric 
275*06c3fb27SDimitry Andric template <class _CharT>
276*06c3fb27SDimitry Andric class _LIBCPP_HIDDEN __stdoutbuf
277*06c3fb27SDimitry Andric     : public basic_streambuf<_CharT, char_traits<_CharT> >
278*06c3fb27SDimitry Andric {
279*06c3fb27SDimitry Andric public:
280*06c3fb27SDimitry Andric     typedef _CharT                           char_type;
281*06c3fb27SDimitry Andric     typedef char_traits<char_type>           traits_type;
282*06c3fb27SDimitry Andric     typedef typename traits_type::int_type   int_type;
283*06c3fb27SDimitry Andric     typedef typename traits_type::pos_type   pos_type;
284*06c3fb27SDimitry Andric     typedef typename traits_type::off_type   off_type;
285*06c3fb27SDimitry Andric     typedef typename traits_type::state_type state_type;
286*06c3fb27SDimitry Andric 
287*06c3fb27SDimitry Andric     __stdoutbuf(FILE* __fp, state_type* __st);
288*06c3fb27SDimitry Andric 
289*06c3fb27SDimitry Andric protected:
290*06c3fb27SDimitry Andric     virtual int_type overflow (int_type __c = traits_type::eof());
291*06c3fb27SDimitry Andric     virtual streamsize xsputn(const char_type* __s, streamsize __n);
292*06c3fb27SDimitry Andric     virtual int sync();
293*06c3fb27SDimitry Andric     virtual void imbue(const locale& __loc);
294*06c3fb27SDimitry Andric 
295*06c3fb27SDimitry Andric private:
296*06c3fb27SDimitry Andric     FILE* __file_;
297*06c3fb27SDimitry Andric     const codecvt<char_type, char, state_type>* __cv_;
298*06c3fb27SDimitry Andric     state_type* __st_;
299*06c3fb27SDimitry Andric     bool __always_noconv_;
300*06c3fb27SDimitry Andric 
301*06c3fb27SDimitry Andric #if defined(_LIBCPP_WIN32API)
302*06c3fb27SDimitry Andric     static constexpr bool __is_win32api_wide_char = !is_same_v<_CharT, char>;
303*06c3fb27SDimitry Andric #else
304*06c3fb27SDimitry Andric     static constexpr bool __is_win32api_wide_char = false;
305*06c3fb27SDimitry Andric #endif
306*06c3fb27SDimitry Andric 
307*06c3fb27SDimitry Andric     __stdoutbuf(const __stdoutbuf&);
308*06c3fb27SDimitry Andric     __stdoutbuf& operator=(const __stdoutbuf&);
309*06c3fb27SDimitry Andric };
310*06c3fb27SDimitry Andric 
311*06c3fb27SDimitry Andric template <class _CharT>
312*06c3fb27SDimitry Andric __stdoutbuf<_CharT>::__stdoutbuf(FILE* __fp, state_type* __st)
313*06c3fb27SDimitry Andric     : __file_(__fp),
314*06c3fb27SDimitry Andric       __cv_(&use_facet<codecvt<char_type, char, state_type> >(this->getloc())),
315*06c3fb27SDimitry Andric       __st_(__st),
316*06c3fb27SDimitry Andric       __always_noconv_(__cv_->always_noconv())
317*06c3fb27SDimitry Andric {
318*06c3fb27SDimitry Andric     // On Windows, in wchar_t mode, ignore the codecvt from the locale by
319*06c3fb27SDimitry Andric     // default and assume noconv; this passes wchar_t through unmodified to
320*06c3fb27SDimitry Andric     // fputwc, which handles it correctly depending on the actual mode of the
321*06c3fb27SDimitry Andric     // output stream. If the user sets a custom locale with imbue(), that
322*06c3fb27SDimitry Andric     // gets honored.
323*06c3fb27SDimitry Andric     if constexpr (__is_win32api_wide_char)
324*06c3fb27SDimitry Andric         __always_noconv_ = true;
325*06c3fb27SDimitry Andric }
326*06c3fb27SDimitry Andric 
327*06c3fb27SDimitry Andric static bool __do_fputc(char __c, FILE* __fp) {
328*06c3fb27SDimitry Andric     if (fwrite(&__c, sizeof(__c), 1, __fp) != 1)
329*06c3fb27SDimitry Andric         return false;
330*06c3fb27SDimitry Andric     return true;
331*06c3fb27SDimitry Andric }
332*06c3fb27SDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
333*06c3fb27SDimitry Andric static bool __do_fputc(wchar_t __c, FILE* __fp) {
334*06c3fb27SDimitry Andric     // fputwc works regardless of wide/narrow mode of stdout, while
335*06c3fb27SDimitry Andric     // fwrite of wchar_t only works if the stream actually has been set
336*06c3fb27SDimitry Andric     // into wide mode.
337*06c3fb27SDimitry Andric     if (fputwc(__c, __fp) == WEOF)
338*06c3fb27SDimitry Andric         return false;
339*06c3fb27SDimitry Andric     return true;
340*06c3fb27SDimitry Andric }
341*06c3fb27SDimitry Andric #endif
342*06c3fb27SDimitry Andric 
343*06c3fb27SDimitry Andric template <class _CharT>
344*06c3fb27SDimitry Andric typename __stdoutbuf<_CharT>::int_type
345*06c3fb27SDimitry Andric __stdoutbuf<_CharT>::overflow(int_type __c)
346*06c3fb27SDimitry Andric {
347*06c3fb27SDimitry Andric     char __extbuf[__limit];
348*06c3fb27SDimitry Andric     char_type __1buf;
349*06c3fb27SDimitry Andric     if (!traits_type::eq_int_type(__c, traits_type::eof()))
350*06c3fb27SDimitry Andric     {
351*06c3fb27SDimitry Andric         __1buf = traits_type::to_char_type(__c);
352*06c3fb27SDimitry Andric         if (__always_noconv_)
353*06c3fb27SDimitry Andric         {
354*06c3fb27SDimitry Andric             if (!__do_fputc(__1buf, __file_))
355*06c3fb27SDimitry Andric                 return traits_type::eof();
356*06c3fb27SDimitry Andric         }
357*06c3fb27SDimitry Andric         else
358*06c3fb27SDimitry Andric         {
359*06c3fb27SDimitry Andric             char* __extbe = __extbuf;
360*06c3fb27SDimitry Andric             codecvt_base::result __r;
361*06c3fb27SDimitry Andric             char_type* pbase = &__1buf;
362*06c3fb27SDimitry Andric             char_type* pptr = pbase + 1;
363*06c3fb27SDimitry Andric             do
364*06c3fb27SDimitry Andric             {
365*06c3fb27SDimitry Andric                 const char_type* __e;
366*06c3fb27SDimitry Andric                 __r = __cv_->out(*__st_, pbase, pptr, __e,
367*06c3fb27SDimitry Andric                                         __extbuf,
368*06c3fb27SDimitry Andric                                         __extbuf + sizeof(__extbuf),
369*06c3fb27SDimitry Andric                                         __extbe);
370*06c3fb27SDimitry Andric                 if (__e == pbase)
371*06c3fb27SDimitry Andric                     return traits_type::eof();
372*06c3fb27SDimitry Andric                 if (__r == codecvt_base::noconv)
373*06c3fb27SDimitry Andric                 {
374*06c3fb27SDimitry Andric                     if (fwrite(pbase, 1, 1, __file_) != 1)
375*06c3fb27SDimitry Andric                         return traits_type::eof();
376*06c3fb27SDimitry Andric                 }
377*06c3fb27SDimitry Andric                 else if (__r == codecvt_base::ok || __r == codecvt_base::partial)
378*06c3fb27SDimitry Andric                 {
379*06c3fb27SDimitry Andric                     size_t __nmemb = static_cast<size_t>(__extbe - __extbuf);
380*06c3fb27SDimitry Andric                     if (fwrite(__extbuf, 1, __nmemb, __file_) != __nmemb)
381*06c3fb27SDimitry Andric                         return traits_type::eof();
382*06c3fb27SDimitry Andric                     if (__r == codecvt_base::partial)
383*06c3fb27SDimitry Andric                     {
384*06c3fb27SDimitry Andric                         pbase = const_cast<char_type*>(__e);
385*06c3fb27SDimitry Andric                     }
386*06c3fb27SDimitry Andric                 }
387*06c3fb27SDimitry Andric                 else
388*06c3fb27SDimitry Andric                     return traits_type::eof();
389*06c3fb27SDimitry Andric             } while (__r == codecvt_base::partial);
390*06c3fb27SDimitry Andric         }
391*06c3fb27SDimitry Andric     }
392*06c3fb27SDimitry Andric     return traits_type::not_eof(__c);
393*06c3fb27SDimitry Andric }
394*06c3fb27SDimitry Andric 
395*06c3fb27SDimitry Andric template <class _CharT>
396*06c3fb27SDimitry Andric streamsize
397*06c3fb27SDimitry Andric __stdoutbuf<_CharT>::xsputn(const char_type* __s, streamsize __n)
398*06c3fb27SDimitry Andric {
399*06c3fb27SDimitry Andric     // For wchar_t on Windows, don't call fwrite(), but write characters one
400*06c3fb27SDimitry Andric     // at a time with fputwc(); that works both when stdout is in the default
401*06c3fb27SDimitry Andric     // mode and when it is set to Unicode mode.
402*06c3fb27SDimitry Andric     if (__always_noconv_ && !__is_win32api_wide_char)
403*06c3fb27SDimitry Andric         return fwrite(__s, sizeof(char_type), __n, __file_);
404*06c3fb27SDimitry Andric     streamsize __i = 0;
405*06c3fb27SDimitry Andric     for (; __i < __n; ++__i, ++__s)
406*06c3fb27SDimitry Andric         if (overflow(traits_type::to_int_type(*__s)) == traits_type::eof())
407*06c3fb27SDimitry Andric             break;
408*06c3fb27SDimitry Andric     return __i;
409*06c3fb27SDimitry Andric }
410*06c3fb27SDimitry Andric 
411*06c3fb27SDimitry Andric template <class _CharT>
412*06c3fb27SDimitry Andric int
413*06c3fb27SDimitry Andric __stdoutbuf<_CharT>::sync()
414*06c3fb27SDimitry Andric {
415*06c3fb27SDimitry Andric     char __extbuf[__limit];
416*06c3fb27SDimitry Andric     codecvt_base::result __r;
417*06c3fb27SDimitry Andric     do
418*06c3fb27SDimitry Andric     {
419*06c3fb27SDimitry Andric         char* __extbe;
420*06c3fb27SDimitry Andric         __r = __cv_->unshift(*__st_, __extbuf,
421*06c3fb27SDimitry Andric                                     __extbuf + sizeof(__extbuf),
422*06c3fb27SDimitry Andric                                     __extbe);
423*06c3fb27SDimitry Andric         size_t __nmemb = static_cast<size_t>(__extbe - __extbuf);
424*06c3fb27SDimitry Andric         if (fwrite(__extbuf, 1, __nmemb, __file_) != __nmemb)
425*06c3fb27SDimitry Andric             return -1;
426*06c3fb27SDimitry Andric     } while (__r == codecvt_base::partial);
427*06c3fb27SDimitry Andric     if (__r == codecvt_base::error)
428*06c3fb27SDimitry Andric         return -1;
429*06c3fb27SDimitry Andric     if (fflush(__file_))
430*06c3fb27SDimitry Andric         return -1;
431*06c3fb27SDimitry Andric     return 0;
432*06c3fb27SDimitry Andric }
433*06c3fb27SDimitry Andric 
434*06c3fb27SDimitry Andric template <class _CharT>
435*06c3fb27SDimitry Andric void
436*06c3fb27SDimitry Andric __stdoutbuf<_CharT>::imbue(const locale& __loc)
437*06c3fb27SDimitry Andric {
438*06c3fb27SDimitry Andric     sync();
439*06c3fb27SDimitry Andric     __cv_ = &use_facet<codecvt<char_type, char, state_type> >(__loc);
440*06c3fb27SDimitry Andric     __always_noconv_ = __cv_->always_noconv();
441*06c3fb27SDimitry Andric }
442*06c3fb27SDimitry Andric 
443*06c3fb27SDimitry Andric _LIBCPP_END_NAMESPACE_STD
444*06c3fb27SDimitry Andric 
445*06c3fb27SDimitry Andric _LIBCPP_POP_MACROS
446*06c3fb27SDimitry Andric 
447*06c3fb27SDimitry Andric #endif // _LIBCPP_STD_STREAM_H
448