13e519524SHoward Hinnant// -*- C++ -*-
23e519524SHoward Hinnant//===----------------------------------------------------------------------===//
33e519524SHoward Hinnant//
457b08b09SChandler Carruth// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
557b08b09SChandler Carruth// See https://llvm.org/LICENSE.txt for license information.
657b08b09SChandler Carruth// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
73e519524SHoward Hinnant//
83e519524SHoward Hinnant//===----------------------------------------------------------------------===//
93e519524SHoward Hinnant
103e519524SHoward Hinnant#ifndef _LIBCPP___STD_STREAM
113e519524SHoward Hinnant#define _LIBCPP___STD_STREAM
123e519524SHoward Hinnant
133e519524SHoward Hinnant#include <__config>
143e519524SHoward Hinnant#include <__locale>
153e519524SHoward Hinnant#include <cstdio>
16*bfbd73f8SArthur O'Dwyer#include <istream>
17*bfbd73f8SArthur O'Dwyer#include <ostream>
183e519524SHoward Hinnant
19073458b1SHoward Hinnant#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
203e519524SHoward Hinnant#  pragma GCC system_header
21073458b1SHoward Hinnant#endif
223e519524SHoward Hinnant
23a016efb1SEric Fiselier_LIBCPP_PUSH_MACROS
24a016efb1SEric Fiselier#include <__undef_macros>
25a016efb1SEric Fiselier
26a016efb1SEric Fiselier
273e519524SHoward Hinnant_LIBCPP_BEGIN_NAMESPACE_STD
283e519524SHoward Hinnant
29c206366fSHoward Hinnantstatic const int __limit = 8;
303e519524SHoward Hinnant
313e519524SHoward Hinnant// __stdinbuf
323e519524SHoward Hinnant
333e519524SHoward Hinnanttemplate <class _CharT>
343e519524SHoward Hinnantclass _LIBCPP_HIDDEN __stdinbuf
353e519524SHoward Hinnant    : public basic_streambuf<_CharT, char_traits<_CharT> >
363e519524SHoward Hinnant{
373e519524SHoward Hinnantpublic:
383e519524SHoward Hinnant    typedef _CharT                           char_type;
393e519524SHoward Hinnant    typedef char_traits<char_type>           traits_type;
403e519524SHoward Hinnant    typedef typename traits_type::int_type   int_type;
413e519524SHoward Hinnant    typedef typename traits_type::pos_type   pos_type;
423e519524SHoward Hinnant    typedef typename traits_type::off_type   off_type;
433e519524SHoward Hinnant    typedef typename traits_type::state_type state_type;
443e519524SHoward Hinnant
45591ebe3cSHoward Hinnant    __stdinbuf(FILE* __fp, state_type* __st);
463e519524SHoward Hinnant
473e519524SHoward Hinnantprotected:
483e519524SHoward Hinnant    virtual int_type underflow();
493e519524SHoward Hinnant    virtual int_type uflow();
503e519524SHoward Hinnant    virtual int_type pbackfail(int_type __c = traits_type::eof());
513e519524SHoward Hinnant    virtual void imbue(const locale& __loc);
523e519524SHoward Hinnant
533e519524SHoward Hinnantprivate:
543e519524SHoward Hinnant
553e519524SHoward Hinnant    FILE* __file_;
563e519524SHoward Hinnant    const codecvt<char_type, char, state_type>* __cv_;
57591ebe3cSHoward Hinnant    state_type* __st_;
583e519524SHoward Hinnant    int __encoding_;
59266abefeSHoward Hinnant    int_type __last_consumed_;
60266abefeSHoward Hinnant    bool __last_consumed_is_next_;
613e519524SHoward Hinnant    bool __always_noconv_;
623e519524SHoward Hinnant
633e519524SHoward Hinnant    __stdinbuf(const __stdinbuf&);
643e519524SHoward Hinnant    __stdinbuf& operator=(const __stdinbuf&);
653e519524SHoward Hinnant
663e519524SHoward Hinnant    int_type __getchar(bool __consume);
673e519524SHoward Hinnant};
683e519524SHoward Hinnant
693e519524SHoward Hinnanttemplate <class _CharT>
70591ebe3cSHoward Hinnant__stdinbuf<_CharT>::__stdinbuf(FILE* __fp, state_type* __st)
713e519524SHoward Hinnant    : __file_(__fp),
72266abefeSHoward Hinnant      __st_(__st),
73266abefeSHoward Hinnant      __last_consumed_(traits_type::eof()),
74266abefeSHoward Hinnant      __last_consumed_is_next_(false)
753e519524SHoward Hinnant{
763e519524SHoward Hinnant    imbue(this->getloc());
773e519524SHoward Hinnant}
783e519524SHoward Hinnant
793e519524SHoward Hinnanttemplate <class _CharT>
803e519524SHoward Hinnantvoid
813e519524SHoward Hinnant__stdinbuf<_CharT>::imbue(const locale& __loc)
823e519524SHoward Hinnant{
833e519524SHoward Hinnant    __cv_ = &use_facet<codecvt<char_type, char, state_type> >(__loc);
843e519524SHoward Hinnant    __encoding_ = __cv_->encoding();
853e519524SHoward Hinnant    __always_noconv_ = __cv_->always_noconv();
863e519524SHoward Hinnant    if (__encoding_ > __limit)
873e519524SHoward Hinnant        __throw_runtime_error("unsupported locale for standard input");
883e519524SHoward Hinnant}
893e519524SHoward Hinnant
903e519524SHoward Hinnanttemplate <class _CharT>
913e519524SHoward Hinnanttypename __stdinbuf<_CharT>::int_type
923e519524SHoward Hinnant__stdinbuf<_CharT>::underflow()
933e519524SHoward Hinnant{
943e519524SHoward Hinnant    return __getchar(false);
953e519524SHoward Hinnant}
963e519524SHoward Hinnant
973e519524SHoward Hinnanttemplate <class _CharT>
983e519524SHoward Hinnanttypename __stdinbuf<_CharT>::int_type
993e519524SHoward Hinnant__stdinbuf<_CharT>::uflow()
1003e519524SHoward Hinnant{
1013e519524SHoward Hinnant    return __getchar(true);
1023e519524SHoward Hinnant}
1033e519524SHoward Hinnant
1043e519524SHoward Hinnanttemplate <class _CharT>
1053e519524SHoward Hinnanttypename __stdinbuf<_CharT>::int_type
1063e519524SHoward Hinnant__stdinbuf<_CharT>::__getchar(bool __consume)
1073e519524SHoward Hinnant{
108266abefeSHoward Hinnant    if (__last_consumed_is_next_)
109266abefeSHoward Hinnant    {
110266abefeSHoward Hinnant        int_type __result = __last_consumed_;
111266abefeSHoward Hinnant        if (__consume)
112266abefeSHoward Hinnant        {
113266abefeSHoward Hinnant            __last_consumed_ = traits_type::eof();
114266abefeSHoward Hinnant            __last_consumed_is_next_ = false;
115266abefeSHoward Hinnant        }
116266abefeSHoward Hinnant        return __result;
117266abefeSHoward Hinnant    }
1183e519524SHoward Hinnant    char __extbuf[__limit];
119ce48a113SHoward Hinnant    int __nread = _VSTD::max(1, __encoding_);
1203e519524SHoward Hinnant    for (int __i = 0; __i < __nread; ++__i)
1213e519524SHoward Hinnant    {
122c206366fSHoward Hinnant        int __c = getc(__file_);
1233e519524SHoward Hinnant        if (__c == EOF)
1243e519524SHoward Hinnant            return traits_type::eof();
1253e519524SHoward Hinnant        __extbuf[__i] = static_cast<char>(__c);
1263e519524SHoward Hinnant    }
1273e519524SHoward Hinnant    char_type __1buf;
1283e519524SHoward Hinnant    if (__always_noconv_)
1293e519524SHoward Hinnant        __1buf = static_cast<char_type>(__extbuf[0]);
1303e519524SHoward Hinnant    else
1313e519524SHoward Hinnant    {
1323e519524SHoward Hinnant        const char* __enxt;
1333e519524SHoward Hinnant        char_type* __inxt;
1343e519524SHoward Hinnant        codecvt_base::result __r;
1353e519524SHoward Hinnant        do
1363e519524SHoward Hinnant        {
137591ebe3cSHoward Hinnant            state_type __sv_st = *__st_;
138591ebe3cSHoward Hinnant            __r = __cv_->in(*__st_, __extbuf, __extbuf + __nread, __enxt,
1393e519524SHoward Hinnant                                   &__1buf, &__1buf + 1, __inxt);
1403e519524SHoward Hinnant            switch (__r)
1413e519524SHoward Hinnant            {
142ce48a113SHoward Hinnant            case _VSTD::codecvt_base::ok:
1433e519524SHoward Hinnant                break;
1443e519524SHoward Hinnant            case codecvt_base::partial:
145591ebe3cSHoward Hinnant                *__st_ = __sv_st;
1463e519524SHoward Hinnant                if (__nread == sizeof(__extbuf))
1473e519524SHoward Hinnant                    return traits_type::eof();
1483e519524SHoward Hinnant                {
149c206366fSHoward Hinnant                    int __c = getc(__file_);
1503e519524SHoward Hinnant                    if (__c == EOF)
1513e519524SHoward Hinnant                        return traits_type::eof();
1523e519524SHoward Hinnant                    __extbuf[__nread] = static_cast<char>(__c);
1533e519524SHoward Hinnant                }
1543e519524SHoward Hinnant                ++__nread;
1553e519524SHoward Hinnant                break;
1563e519524SHoward Hinnant            case codecvt_base::error:
1573e519524SHoward Hinnant                return traits_type::eof();
158ce48a113SHoward Hinnant            case _VSTD::codecvt_base::noconv:
1593e519524SHoward Hinnant                __1buf = static_cast<char_type>(__extbuf[0]);
1603e519524SHoward Hinnant                break;
1613e519524SHoward Hinnant            }
162ce48a113SHoward Hinnant        } while (__r == _VSTD::codecvt_base::partial);
1633e519524SHoward Hinnant    }
1643e519524SHoward Hinnant    if (!__consume)
1653e519524SHoward Hinnant    {
1663e519524SHoward Hinnant        for (int __i = __nread; __i > 0;)
1673e519524SHoward Hinnant        {
16841801f14SHoward Hinnant            if (ungetc(traits_type::to_int_type(__extbuf[--__i]), __file_) == EOF)
1693e519524SHoward Hinnant                return traits_type::eof();
1703e519524SHoward Hinnant        }
1713e519524SHoward Hinnant    }
172266abefeSHoward Hinnant    else
173266abefeSHoward Hinnant        __last_consumed_ = traits_type::to_int_type(__1buf);
1743e519524SHoward Hinnant    return traits_type::to_int_type(__1buf);
1753e519524SHoward Hinnant}
1763e519524SHoward Hinnant
1773e519524SHoward Hinnanttemplate <class _CharT>
1783e519524SHoward Hinnanttypename __stdinbuf<_CharT>::int_type
1793e519524SHoward Hinnant__stdinbuf<_CharT>::pbackfail(int_type __c)
1803e519524SHoward Hinnant{
1813e519524SHoward Hinnant    if (traits_type::eq_int_type(__c, traits_type::eof()))
182266abefeSHoward Hinnant    {
183266abefeSHoward Hinnant        if (!__last_consumed_is_next_)
184266abefeSHoward Hinnant        {
185266abefeSHoward Hinnant            __c = __last_consumed_;
186266abefeSHoward Hinnant            __last_consumed_is_next_ = !traits_type::eq_int_type(__last_consumed_,
187266abefeSHoward Hinnant                                                                 traits_type::eof());
188266abefeSHoward Hinnant        }
1893e519524SHoward Hinnant        return __c;
190266abefeSHoward Hinnant    }
191266abefeSHoward Hinnant    if (__last_consumed_is_next_)
192266abefeSHoward Hinnant    {
1933e519524SHoward Hinnant        char __extbuf[__limit];
1943e519524SHoward Hinnant        char* __enxt;
195266abefeSHoward Hinnant        const char_type __ci = traits_type::to_char_type(__last_consumed_);
1963e519524SHoward Hinnant        const char_type* __inxt;
197591ebe3cSHoward Hinnant        switch (__cv_->out(*__st_, &__ci, &__ci + 1, __inxt,
1983e519524SHoward Hinnant                                  __extbuf, __extbuf + sizeof(__extbuf), __enxt))
1993e519524SHoward Hinnant        {
200ce48a113SHoward Hinnant        case _VSTD::codecvt_base::ok:
2013e519524SHoward Hinnant            break;
202ce48a113SHoward Hinnant        case _VSTD::codecvt_base::noconv:
203266abefeSHoward Hinnant            __extbuf[0] = static_cast<char>(__last_consumed_);
2043e519524SHoward Hinnant            __enxt = __extbuf + 1;
2053e519524SHoward Hinnant            break;
2063e519524SHoward Hinnant        case codecvt_base::partial:
2073e519524SHoward Hinnant        case codecvt_base::error:
2083e519524SHoward Hinnant            return traits_type::eof();
2093e519524SHoward Hinnant        }
2103e519524SHoward Hinnant        while (__enxt > __extbuf)
2113e519524SHoward Hinnant            if (ungetc(*--__enxt, __file_) == EOF)
2123e519524SHoward Hinnant                return traits_type::eof();
213266abefeSHoward Hinnant    }
214266abefeSHoward Hinnant    __last_consumed_ = __c;
215266abefeSHoward Hinnant    __last_consumed_is_next_ = true;
216266abefeSHoward Hinnant    return __c;
2173e519524SHoward Hinnant}
2183e519524SHoward Hinnant
2193e519524SHoward Hinnant// __stdoutbuf
2203e519524SHoward Hinnant
2213e519524SHoward Hinnanttemplate <class _CharT>
2223e519524SHoward Hinnantclass _LIBCPP_HIDDEN __stdoutbuf
2233e519524SHoward Hinnant    : public basic_streambuf<_CharT, char_traits<_CharT> >
2243e519524SHoward Hinnant{
2253e519524SHoward Hinnantpublic:
2263e519524SHoward Hinnant    typedef _CharT                           char_type;
2273e519524SHoward Hinnant    typedef char_traits<char_type>           traits_type;
2283e519524SHoward Hinnant    typedef typename traits_type::int_type   int_type;
2293e519524SHoward Hinnant    typedef typename traits_type::pos_type   pos_type;
2303e519524SHoward Hinnant    typedef typename traits_type::off_type   off_type;
2313e519524SHoward Hinnant    typedef typename traits_type::state_type state_type;
2323e519524SHoward Hinnant
233591ebe3cSHoward Hinnant    __stdoutbuf(FILE* __fp, state_type* __st);
2343e519524SHoward Hinnant
2353e519524SHoward Hinnantprotected:
2363e519524SHoward Hinnant    virtual int_type overflow (int_type __c = traits_type::eof());
237d7cda068SHoward Hinnant    virtual streamsize xsputn(const char_type* __s, streamsize __n);
2383e519524SHoward Hinnant    virtual int sync();
2393e519524SHoward Hinnant    virtual void imbue(const locale& __loc);
2403e519524SHoward Hinnant
2413e519524SHoward Hinnantprivate:
2423e519524SHoward Hinnant    FILE* __file_;
2433e519524SHoward Hinnant    const codecvt<char_type, char, state_type>* __cv_;
244591ebe3cSHoward Hinnant    state_type* __st_;
2453e519524SHoward Hinnant    bool __always_noconv_;
2463e519524SHoward Hinnant
2473e519524SHoward Hinnant    __stdoutbuf(const __stdoutbuf&);
2483e519524SHoward Hinnant    __stdoutbuf& operator=(const __stdoutbuf&);
2493e519524SHoward Hinnant};
2503e519524SHoward Hinnant
2513e519524SHoward Hinnanttemplate <class _CharT>
252591ebe3cSHoward Hinnant__stdoutbuf<_CharT>::__stdoutbuf(FILE* __fp, state_type* __st)
2533e519524SHoward Hinnant    : __file_(__fp),
2543e519524SHoward Hinnant      __cv_(&use_facet<codecvt<char_type, char, state_type> >(this->getloc())),
255591ebe3cSHoward Hinnant      __st_(__st),
2563e519524SHoward Hinnant      __always_noconv_(__cv_->always_noconv())
2573e519524SHoward Hinnant{
2583e519524SHoward Hinnant}
2593e519524SHoward Hinnant
2603e519524SHoward Hinnanttemplate <class _CharT>
2613e519524SHoward Hinnanttypename __stdoutbuf<_CharT>::int_type
2623e519524SHoward Hinnant__stdoutbuf<_CharT>::overflow(int_type __c)
2633e519524SHoward Hinnant{
2643e519524SHoward Hinnant    char __extbuf[__limit];
2653e519524SHoward Hinnant    char_type __1buf;
2663e519524SHoward Hinnant    if (!traits_type::eq_int_type(__c, traits_type::eof()))
2673e519524SHoward Hinnant    {
268e9672d04SHoward Hinnant        __1buf = traits_type::to_char_type(__c);
2693e519524SHoward Hinnant        if (__always_noconv_)
2703e519524SHoward Hinnant        {
271e9672d04SHoward Hinnant            if (fwrite(&__1buf, sizeof(char_type), 1, __file_) != 1)
2723e519524SHoward Hinnant                return traits_type::eof();
2733e519524SHoward Hinnant        }
2743e519524SHoward Hinnant        else
2753e519524SHoward Hinnant        {
2763e519524SHoward Hinnant            char* __extbe = __extbuf;
2773e519524SHoward Hinnant            codecvt_base::result __r;
278e9672d04SHoward Hinnant            char_type* pbase = &__1buf;
279e9672d04SHoward Hinnant            char_type* pptr = pbase + 1;
2803e519524SHoward Hinnant            do
2813e519524SHoward Hinnant            {
2823e519524SHoward Hinnant                const char_type* __e;
283e9672d04SHoward Hinnant                __r = __cv_->out(*__st_, pbase, pptr, __e,
2843e519524SHoward Hinnant                                        __extbuf,
2853e519524SHoward Hinnant                                        __extbuf + sizeof(__extbuf),
2863e519524SHoward Hinnant                                        __extbe);
287e9672d04SHoward Hinnant                if (__e == pbase)
2883e519524SHoward Hinnant                    return traits_type::eof();
2893e519524SHoward Hinnant                if (__r == codecvt_base::noconv)
2903e519524SHoward Hinnant                {
291e9672d04SHoward Hinnant                    if (fwrite(pbase, 1, 1, __file_) != 1)
2923e519524SHoward Hinnant                        return traits_type::eof();
2933e519524SHoward Hinnant                }
2943e519524SHoward Hinnant                else if (__r == codecvt_base::ok || __r == codecvt_base::partial)
2953e519524SHoward Hinnant                {
2963e519524SHoward Hinnant                    size_t __nmemb = static_cast<size_t>(__extbe - __extbuf);
2973e519524SHoward Hinnant                    if (fwrite(__extbuf, 1, __nmemb, __file_) != __nmemb)
2983e519524SHoward Hinnant                        return traits_type::eof();
2993e519524SHoward Hinnant                    if (__r == codecvt_base::partial)
3003e519524SHoward Hinnant                    {
3012177f3ceSSaleem Abdulrasool                        pbase = const_cast<char_type*>(__e);
3023e519524SHoward Hinnant                    }
3033e519524SHoward Hinnant                }
3043e519524SHoward Hinnant                else
3053e519524SHoward Hinnant                    return traits_type::eof();
3063e519524SHoward Hinnant            } while (__r == codecvt_base::partial);
3073e519524SHoward Hinnant        }
3083e519524SHoward Hinnant    }
3093e519524SHoward Hinnant    return traits_type::not_eof(__c);
3103e519524SHoward Hinnant}
3113e519524SHoward Hinnant
3123e519524SHoward Hinnanttemplate <class _CharT>
313d7cda068SHoward Hinnantstreamsize
314d7cda068SHoward Hinnant__stdoutbuf<_CharT>::xsputn(const char_type* __s, streamsize __n)
315d7cda068SHoward Hinnant{
316d7cda068SHoward Hinnant    if (__always_noconv_)
317d7cda068SHoward Hinnant        return fwrite(__s, sizeof(char_type), __n, __file_);
318d7cda068SHoward Hinnant    streamsize __i = 0;
319d7cda068SHoward Hinnant    for (; __i < __n; ++__i, ++__s)
320d7cda068SHoward Hinnant        if (overflow(traits_type::to_int_type(*__s)) == traits_type::eof())
321d7cda068SHoward Hinnant            break;
322d7cda068SHoward Hinnant    return __i;
323d7cda068SHoward Hinnant}
324d7cda068SHoward Hinnant
325d7cda068SHoward Hinnanttemplate <class _CharT>
3263e519524SHoward Hinnantint
3273e519524SHoward Hinnant__stdoutbuf<_CharT>::sync()
3283e519524SHoward Hinnant{
3293e519524SHoward Hinnant    char __extbuf[__limit];
3303e519524SHoward Hinnant    codecvt_base::result __r;
3313e519524SHoward Hinnant    do
3323e519524SHoward Hinnant    {
3333e519524SHoward Hinnant        char* __extbe;
334591ebe3cSHoward Hinnant        __r = __cv_->unshift(*__st_, __extbuf,
3353e519524SHoward Hinnant                                    __extbuf + sizeof(__extbuf),
3363e519524SHoward Hinnant                                    __extbe);
3373e519524SHoward Hinnant        size_t __nmemb = static_cast<size_t>(__extbe - __extbuf);
3383e519524SHoward Hinnant        if (fwrite(__extbuf, 1, __nmemb, __file_) != __nmemb)
3393e519524SHoward Hinnant            return -1;
3403e519524SHoward Hinnant    } while (__r == codecvt_base::partial);
3413e519524SHoward Hinnant    if (__r == codecvt_base::error)
3423e519524SHoward Hinnant        return -1;
3433e519524SHoward Hinnant    if (fflush(__file_))
3443e519524SHoward Hinnant        return -1;
3453e519524SHoward Hinnant    return 0;
3463e519524SHoward Hinnant}
3473e519524SHoward Hinnant
3483e519524SHoward Hinnanttemplate <class _CharT>
3493e519524SHoward Hinnantvoid
3503e519524SHoward Hinnant__stdoutbuf<_CharT>::imbue(const locale& __loc)
3513e519524SHoward Hinnant{
3523e519524SHoward Hinnant    sync();
3533e519524SHoward Hinnant    __cv_ = &use_facet<codecvt<char_type, char, state_type> >(__loc);
3543e519524SHoward Hinnant    __always_noconv_ = __cv_->always_noconv();
3553e519524SHoward Hinnant}
3563e519524SHoward Hinnant
3573e519524SHoward Hinnant_LIBCPP_END_NAMESPACE_STD
3583e519524SHoward Hinnant
359a016efb1SEric Fiselier_LIBCPP_POP_MACROS
360a016efb1SEric Fiselier
3613e519524SHoward Hinnant#endif // _LIBCPP___STD_STREAM
362