1227825Stheraven// -*- C++ -*-
2227825Stheraven//===----------------------------------------------------------------------===//
3227825Stheraven//
4227825Stheraven//                     The LLVM Compiler Infrastructure
5227825Stheraven//
6227825Stheraven// This file is dual licensed under the MIT and the University of Illinois Open
7227825Stheraven// Source Licenses. See LICENSE.TXT for details.
8227825Stheraven//
9227825Stheraven//===----------------------------------------------------------------------===//
10227825Stheraven
11227825Stheraven#ifndef _LIBCPP___STD_STREAM
12227825Stheraven#define _LIBCPP___STD_STREAM
13227825Stheraven
14227825Stheraven#include <__config>
15227825Stheraven#include <ostream>
16227825Stheraven#include <istream>
17227825Stheraven#include <__locale>
18227825Stheraven#include <cstdio>
19227825Stheraven
20232950Stheraven#include <__undef_min_max>
21232950Stheraven
22227825Stheraven#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
23227825Stheraven#pragma GCC system_header
24227825Stheraven#endif
25227825Stheraven
26227825Stheraven_LIBCPP_BEGIN_NAMESPACE_STD
27227825Stheraven
28232950Stheravenstatic const int __limit = 8;
29227825Stheraven
30227825Stheraven// __stdinbuf
31227825Stheraven
32227825Stheraventemplate <class _CharT>
33227825Stheravenclass _LIBCPP_HIDDEN __stdinbuf
34227825Stheraven    : public basic_streambuf<_CharT, char_traits<_CharT> >
35227825Stheraven{
36227825Stheravenpublic:
37227825Stheraven    typedef _CharT                           char_type;
38227825Stheraven    typedef char_traits<char_type>           traits_type;
39227825Stheraven    typedef typename traits_type::int_type   int_type;
40227825Stheraven    typedef typename traits_type::pos_type   pos_type;
41227825Stheraven    typedef typename traits_type::off_type   off_type;
42227825Stheraven    typedef typename traits_type::state_type state_type;
43227825Stheraven
44250514Sdim    __stdinbuf(FILE* __fp, state_type* __st);
45227825Stheraven
46227825Stheravenprotected:
47227825Stheraven    virtual int_type underflow();
48227825Stheraven    virtual int_type uflow();
49227825Stheraven    virtual int_type pbackfail(int_type __c = traits_type::eof());
50227825Stheraven    virtual void imbue(const locale& __loc);
51227825Stheraven
52227825Stheravenprivate:
53227825Stheraven
54227825Stheraven    FILE* __file_;
55227825Stheraven    const codecvt<char_type, char, state_type>* __cv_;
56250514Sdim    state_type* __st_;
57227825Stheraven    int __encoding_;
58253222Sdim    int_type __last_consumed_;
59253222Sdim    bool __last_consumed_is_next_;
60227825Stheraven    bool __always_noconv_;
61227825Stheraven
62227825Stheraven    __stdinbuf(const __stdinbuf&);
63227825Stheraven    __stdinbuf& operator=(const __stdinbuf&);
64227825Stheraven
65227825Stheraven    int_type __getchar(bool __consume);
66227825Stheraven};
67227825Stheraven
68227825Stheraventemplate <class _CharT>
69250514Sdim__stdinbuf<_CharT>::__stdinbuf(FILE* __fp, state_type* __st)
70227825Stheraven    : __file_(__fp),
71253222Sdim      __st_(__st),
72253222Sdim      __last_consumed_(traits_type::eof()),
73253222Sdim      __last_consumed_is_next_(false)
74227825Stheraven{
75227825Stheraven    imbue(this->getloc());
76227825Stheraven}
77227825Stheraven
78227825Stheraventemplate <class _CharT>
79227825Stheravenvoid
80227825Stheraven__stdinbuf<_CharT>::imbue(const locale& __loc)
81227825Stheraven{
82227825Stheraven    __cv_ = &use_facet<codecvt<char_type, char, state_type> >(__loc);
83227825Stheraven    __encoding_ = __cv_->encoding();
84227825Stheraven    __always_noconv_ = __cv_->always_noconv();
85227825Stheraven    if (__encoding_ > __limit)
86227825Stheraven        __throw_runtime_error("unsupported locale for standard input");
87227825Stheraven}
88227825Stheraven
89227825Stheraventemplate <class _CharT>
90227825Stheraventypename __stdinbuf<_CharT>::int_type
91227825Stheraven__stdinbuf<_CharT>::underflow()
92227825Stheraven{
93227825Stheraven    return __getchar(false);
94227825Stheraven}
95227825Stheraven
96227825Stheraventemplate <class _CharT>
97227825Stheraventypename __stdinbuf<_CharT>::int_type
98227825Stheraven__stdinbuf<_CharT>::uflow()
99227825Stheraven{
100227825Stheraven    return __getchar(true);
101227825Stheraven}
102227825Stheraven
103227825Stheraventemplate <class _CharT>
104227825Stheraventypename __stdinbuf<_CharT>::int_type
105227825Stheraven__stdinbuf<_CharT>::__getchar(bool __consume)
106227825Stheraven{
107253222Sdim    if (__last_consumed_is_next_)
108253222Sdim    {
109253222Sdim        int_type __result = __last_consumed_;
110253222Sdim        if (__consume)
111253222Sdim        {
112253222Sdim            __last_consumed_ = traits_type::eof();
113253222Sdim            __last_consumed_is_next_ = false;
114253222Sdim        }
115253222Sdim        return __result;
116253222Sdim    }
117227825Stheraven    char __extbuf[__limit];
118227825Stheraven    int __nread = _VSTD::max(1, __encoding_);
119227825Stheraven    for (int __i = 0; __i < __nread; ++__i)
120227825Stheraven    {
121232950Stheraven        int __c = getc(__file_);
122227825Stheraven        if (__c == EOF)
123227825Stheraven            return traits_type::eof();
124227825Stheraven        __extbuf[__i] = static_cast<char>(__c);
125227825Stheraven    }
126227825Stheraven    char_type __1buf;
127227825Stheraven    if (__always_noconv_)
128227825Stheraven        __1buf = static_cast<char_type>(__extbuf[0]);
129227825Stheraven    else
130227825Stheraven    {
131227825Stheraven        const char* __enxt;
132227825Stheraven        char_type* __inxt;
133227825Stheraven        codecvt_base::result __r;
134227825Stheraven        do
135227825Stheraven        {
136250514Sdim            state_type __sv_st = *__st_;
137250514Sdim            __r = __cv_->in(*__st_, __extbuf, __extbuf + __nread, __enxt,
138227825Stheraven                                   &__1buf, &__1buf + 1, __inxt);
139227825Stheraven            switch (__r)
140227825Stheraven            {
141227825Stheraven            case _VSTD::codecvt_base::ok:
142227825Stheraven                break;
143227825Stheraven            case codecvt_base::partial:
144250514Sdim                *__st_ = __sv_st;
145227825Stheraven                if (__nread == sizeof(__extbuf))
146227825Stheraven                    return traits_type::eof();
147227825Stheraven                {
148232950Stheraven                    int __c = getc(__file_);
149227825Stheraven                    if (__c == EOF)
150227825Stheraven                        return traits_type::eof();
151227825Stheraven                    __extbuf[__nread] = static_cast<char>(__c);
152227825Stheraven                }
153227825Stheraven                ++__nread;
154227825Stheraven                break;
155227825Stheraven            case codecvt_base::error:
156227825Stheraven                return traits_type::eof();
157227825Stheraven            case _VSTD::codecvt_base::noconv:
158227825Stheraven                __1buf = static_cast<char_type>(__extbuf[0]);
159227825Stheraven                break;
160227825Stheraven            }
161227825Stheraven        } while (__r == _VSTD::codecvt_base::partial);
162227825Stheraven    }
163227825Stheraven    if (!__consume)
164227825Stheraven    {
165227825Stheraven        for (int __i = __nread; __i > 0;)
166227825Stheraven        {
167250514Sdim            if (ungetc(traits_type::to_int_type(__extbuf[--__i]), __file_) == EOF)
168227825Stheraven                return traits_type::eof();
169227825Stheraven        }
170227825Stheraven    }
171253222Sdim    else
172253222Sdim        __last_consumed_ = traits_type::to_int_type(__1buf);
173227825Stheraven    return traits_type::to_int_type(__1buf);
174227825Stheraven}
175227825Stheraven
176227825Stheraventemplate <class _CharT>
177227825Stheraventypename __stdinbuf<_CharT>::int_type
178227825Stheraven__stdinbuf<_CharT>::pbackfail(int_type __c)
179227825Stheraven{
180227825Stheraven    if (traits_type::eq_int_type(__c, traits_type::eof()))
181253222Sdim    {
182253222Sdim        if (!__last_consumed_is_next_)
183253222Sdim        {
184253222Sdim            __c = __last_consumed_;
185253222Sdim            __last_consumed_is_next_ = !traits_type::eq_int_type(__last_consumed_,
186253222Sdim                                                                 traits_type::eof());
187253222Sdim        }
188227825Stheraven        return __c;
189253222Sdim    }
190253222Sdim    if (__last_consumed_is_next_)
191227825Stheraven    {
192253222Sdim        char __extbuf[__limit];
193253222Sdim        char* __enxt;
194253222Sdim        const char_type __ci = traits_type::to_char_type(__last_consumed_);
195253222Sdim        const char_type* __inxt;
196253222Sdim        switch (__cv_->out(*__st_, &__ci, &__ci + 1, __inxt,
197253222Sdim                                  __extbuf, __extbuf + sizeof(__extbuf), __enxt))
198253222Sdim        {
199253222Sdim        case _VSTD::codecvt_base::ok:
200253222Sdim            break;
201253222Sdim        case _VSTD::codecvt_base::noconv:
202253222Sdim            __extbuf[0] = static_cast<char>(__last_consumed_);
203253222Sdim            __enxt = __extbuf + 1;
204253222Sdim            break;
205253222Sdim        case codecvt_base::partial:
206253222Sdim        case codecvt_base::error:
207253222Sdim            return traits_type::eof();
208253222Sdim        }
209253222Sdim        while (__enxt > __extbuf)
210253222Sdim            if (ungetc(*--__enxt, __file_) == EOF)
211253222Sdim                return traits_type::eof();
212227825Stheraven    }
213253222Sdim    __last_consumed_ = __c;
214253222Sdim    __last_consumed_is_next_ = true;
215253222Sdim    return __c;
216227825Stheraven}
217227825Stheraven
218227825Stheraven// __stdoutbuf
219227825Stheraven
220227825Stheraventemplate <class _CharT>
221227825Stheravenclass _LIBCPP_HIDDEN __stdoutbuf
222227825Stheraven    : public basic_streambuf<_CharT, char_traits<_CharT> >
223227825Stheraven{
224227825Stheravenpublic:
225227825Stheraven    typedef _CharT                           char_type;
226227825Stheraven    typedef char_traits<char_type>           traits_type;
227227825Stheraven    typedef typename traits_type::int_type   int_type;
228227825Stheraven    typedef typename traits_type::pos_type   pos_type;
229227825Stheraven    typedef typename traits_type::off_type   off_type;
230227825Stheraven    typedef typename traits_type::state_type state_type;
231227825Stheraven
232250514Sdim    __stdoutbuf(FILE* __fp, state_type* __st);
233227825Stheraven
234227825Stheravenprotected:
235227825Stheraven    virtual int_type overflow (int_type __c = traits_type::eof());
236262801Sdim    virtual streamsize xsputn(const char_type* __s, streamsize __n);
237227825Stheraven    virtual int sync();
238227825Stheraven    virtual void imbue(const locale& __loc);
239227825Stheraven
240227825Stheravenprivate:
241227825Stheraven    FILE* __file_;
242227825Stheraven    const codecvt<char_type, char, state_type>* __cv_;
243250514Sdim    state_type* __st_;
244227825Stheraven    bool __always_noconv_;
245227825Stheraven
246227825Stheraven    __stdoutbuf(const __stdoutbuf&);
247227825Stheraven    __stdoutbuf& operator=(const __stdoutbuf&);
248227825Stheraven};
249227825Stheraven
250227825Stheraventemplate <class _CharT>
251250514Sdim__stdoutbuf<_CharT>::__stdoutbuf(FILE* __fp, state_type* __st)
252227825Stheraven    : __file_(__fp),
253227825Stheraven      __cv_(&use_facet<codecvt<char_type, char, state_type> >(this->getloc())),
254250514Sdim      __st_(__st),
255227825Stheraven      __always_noconv_(__cv_->always_noconv())
256227825Stheraven{
257227825Stheraven}
258227825Stheraven
259227825Stheraventemplate <class _CharT>
260227825Stheraventypename __stdoutbuf<_CharT>::int_type
261227825Stheraven__stdoutbuf<_CharT>::overflow(int_type __c)
262227825Stheraven{
263227825Stheraven    char __extbuf[__limit];
264227825Stheraven    char_type __1buf;
265227825Stheraven    if (!traits_type::eq_int_type(__c, traits_type::eof()))
266227825Stheraven    {
267253222Sdim        __1buf = traits_type::to_char_type(__c);
268227825Stheraven        if (__always_noconv_)
269227825Stheraven        {
270253222Sdim            if (fwrite(&__1buf, sizeof(char_type), 1, __file_) != 1)
271227825Stheraven                return traits_type::eof();
272227825Stheraven        }
273227825Stheraven        else
274227825Stheraven        {
275227825Stheraven            char* __extbe = __extbuf;
276227825Stheraven            codecvt_base::result __r;
277253222Sdim            char_type* pbase = &__1buf;
278253222Sdim            char_type* pptr = pbase + 1;
279253222Sdim            char_type* epptr = pptr;
280227825Stheraven            do
281227825Stheraven            {
282227825Stheraven                const char_type* __e;
283253222Sdim                __r = __cv_->out(*__st_, pbase, pptr, __e,
284227825Stheraven                                        __extbuf,
285227825Stheraven                                        __extbuf + sizeof(__extbuf),
286227825Stheraven                                        __extbe);
287253222Sdim                if (__e == pbase)
288227825Stheraven                    return traits_type::eof();
289227825Stheraven                if (__r == codecvt_base::noconv)
290227825Stheraven                {
291253222Sdim                    if (fwrite(pbase, 1, 1, __file_) != 1)
292227825Stheraven                        return traits_type::eof();
293227825Stheraven                }
294227825Stheraven                else if (__r == codecvt_base::ok || __r == codecvt_base::partial)
295227825Stheraven                {
296227825Stheraven                    size_t __nmemb = static_cast<size_t>(__extbe - __extbuf);
297227825Stheraven                    if (fwrite(__extbuf, 1, __nmemb, __file_) != __nmemb)
298227825Stheraven                        return traits_type::eof();
299227825Stheraven                    if (__r == codecvt_base::partial)
300227825Stheraven                    {
301253222Sdim                        pbase = (char_type*)__e;
302227825Stheraven                    }
303227825Stheraven                }
304227825Stheraven                else
305227825Stheraven                    return traits_type::eof();
306227825Stheraven            } while (__r == codecvt_base::partial);
307227825Stheraven        }
308227825Stheraven    }
309227825Stheraven    return traits_type::not_eof(__c);
310227825Stheraven}
311227825Stheraven
312227825Stheraventemplate <class _CharT>
313262801Sdimstreamsize
314262801Sdim__stdoutbuf<_CharT>::xsputn(const char_type* __s, streamsize __n)
315262801Sdim{
316262801Sdim    if (__always_noconv_)
317262801Sdim        return fwrite(__s, sizeof(char_type), __n, __file_);
318262801Sdim    streamsize __i = 0;
319262801Sdim    for (; __i < __n; ++__i, ++__s)
320262801Sdim        if (overflow(traits_type::to_int_type(*__s)) == traits_type::eof())
321262801Sdim            break;
322262801Sdim    return __i;
323262801Sdim}
324262801Sdim
325262801Sdimtemplate <class _CharT>
326227825Stheravenint
327227825Stheraven__stdoutbuf<_CharT>::sync()
328227825Stheraven{
329227825Stheraven    char __extbuf[__limit];
330227825Stheraven    codecvt_base::result __r;
331227825Stheraven    do
332227825Stheraven    {
333227825Stheraven        char* __extbe;
334250514Sdim        __r = __cv_->unshift(*__st_, __extbuf,
335227825Stheraven                                    __extbuf + sizeof(__extbuf),
336227825Stheraven                                    __extbe);
337227825Stheraven        size_t __nmemb = static_cast<size_t>(__extbe - __extbuf);
338227825Stheraven        if (fwrite(__extbuf, 1, __nmemb, __file_) != __nmemb)
339227825Stheraven            return -1;
340227825Stheraven    } while (__r == codecvt_base::partial);
341227825Stheraven    if (__r == codecvt_base::error)
342227825Stheraven        return -1;
343227825Stheraven    if (fflush(__file_))
344227825Stheraven        return -1;
345227825Stheraven    return 0;
346227825Stheraven}
347227825Stheraven
348227825Stheraventemplate <class _CharT>
349227825Stheravenvoid
350227825Stheraven__stdoutbuf<_CharT>::imbue(const locale& __loc)
351227825Stheraven{
352227825Stheraven    sync();
353227825Stheraven    __cv_ = &use_facet<codecvt<char_type, char, state_type> >(__loc);
354227825Stheraven    __always_noconv_ = __cv_->always_noconv();
355227825Stheraven}
356227825Stheraven
357227825Stheraven_LIBCPP_END_NAMESPACE_STD
358227825Stheraven
359227825Stheraven#endif  // _LIBCPP___STD_STREAM
360