17a984708SDavid Chisnall// -*- C++ -*-
27a984708SDavid Chisnall//===----------------------------------------------------------------------===//
37a984708SDavid Chisnall//
47a984708SDavid Chisnall//                     The LLVM Compiler Infrastructure
57a984708SDavid Chisnall//
67a984708SDavid Chisnall// This file is dual licensed under the MIT and the University of Illinois Open
77a984708SDavid Chisnall// Source Licenses. See LICENSE.TXT for details.
87a984708SDavid Chisnall//
97a984708SDavid Chisnall//===----------------------------------------------------------------------===//
107a984708SDavid Chisnall
117a984708SDavid Chisnall#ifndef _LIBCPP___STD_STREAM
127a984708SDavid Chisnall#define _LIBCPP___STD_STREAM
137a984708SDavid Chisnall
147a984708SDavid Chisnall#include <__config>
157a984708SDavid Chisnall#include <ostream>
167a984708SDavid Chisnall#include <istream>
177a984708SDavid Chisnall#include <__locale>
187a984708SDavid Chisnall#include <cstdio>
197a984708SDavid Chisnall
2094e3ee44SDavid Chisnall#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
2194e3ee44SDavid Chisnall#pragma GCC system_header
227a984708SDavid Chisnall#endif
237a984708SDavid Chisnall
247a984708SDavid Chisnall_LIBCPP_PUSH_MACROS
257a984708SDavid Chisnall#include <__undef_macros>
267a984708SDavid Chisnall
277a984708SDavid Chisnall
2894e3ee44SDavid Chisnall_LIBCPP_BEGIN_NAMESPACE_STD
297a984708SDavid Chisnall
307a984708SDavid Chisnallstatic const int __limit = 8;
317a984708SDavid Chisnall
327a984708SDavid Chisnall// __stdinbuf
337a984708SDavid Chisnall
347a984708SDavid Chisnalltemplate <class _CharT>
357a984708SDavid Chisnallclass _LIBCPP_HIDDEN __stdinbuf
367a984708SDavid Chisnall    : public basic_streambuf<_CharT, char_traits<_CharT> >
377a984708SDavid Chisnall{
387a984708SDavid Chisnallpublic:
397a984708SDavid Chisnall    typedef _CharT                           char_type;
407a984708SDavid Chisnall    typedef char_traits<char_type>           traits_type;
417a984708SDavid Chisnall    typedef typename traits_type::int_type   int_type;
427a984708SDavid Chisnall    typedef typename traits_type::pos_type   pos_type;
437a984708SDavid Chisnall    typedef typename traits_type::off_type   off_type;
441bf9f7c1SDimitry Andric    typedef typename traits_type::state_type state_type;
457a984708SDavid Chisnall
467a984708SDavid Chisnall    __stdinbuf(FILE* __fp, state_type* __st);
477a984708SDavid Chisnall
487a984708SDavid Chisnallprotected:
497a984708SDavid Chisnall    virtual int_type underflow();
507a984708SDavid Chisnall    virtual int_type uflow();
517a984708SDavid Chisnall    virtual int_type pbackfail(int_type __c = traits_type::eof());
527a984708SDavid Chisnall    virtual void imbue(const locale& __loc);
537a984708SDavid Chisnall
547a984708SDavid Chisnallprivate:
557a984708SDavid Chisnall
561bf9f7c1SDimitry Andric    FILE* __file_;
577a984708SDavid Chisnall    const codecvt<char_type, char, state_type>* __cv_;
584bab9fd9SDavid Chisnall    state_type* __st_;
594bab9fd9SDavid Chisnall    int __encoding_;
607a984708SDavid Chisnall    int_type __last_consumed_;
617a984708SDavid Chisnall    bool __last_consumed_is_next_;
627a984708SDavid Chisnall    bool __always_noconv_;
637a984708SDavid Chisnall
647a984708SDavid Chisnall    __stdinbuf(const __stdinbuf&);
657a984708SDavid Chisnall    __stdinbuf& operator=(const __stdinbuf&);
667a984708SDavid Chisnall
677a984708SDavid Chisnall    int_type __getchar(bool __consume);
687a984708SDavid Chisnall};
691bf9f7c1SDimitry Andric
707a984708SDavid Chisnalltemplate <class _CharT>
714bab9fd9SDavid Chisnall__stdinbuf<_CharT>::__stdinbuf(FILE* __fp, state_type* __st)
724bab9fd9SDavid Chisnall    : __file_(__fp),
734bab9fd9SDavid Chisnall      __st_(__st),
747a984708SDavid Chisnall      __last_consumed_(traits_type::eof()),
757a984708SDavid Chisnall      __last_consumed_is_next_(false)
767a984708SDavid Chisnall{
777a984708SDavid Chisnall    imbue(this->getloc());
787a984708SDavid Chisnall}
797a984708SDavid Chisnall
807a984708SDavid Chisnalltemplate <class _CharT>
817a984708SDavid Chisnallvoid
827a984708SDavid Chisnall__stdinbuf<_CharT>::imbue(const locale& __loc)
837a984708SDavid Chisnall{
847a984708SDavid Chisnall    __cv_ = &use_facet<codecvt<char_type, char, state_type> >(__loc);
857a984708SDavid Chisnall    __encoding_ = __cv_->encoding();
867a984708SDavid Chisnall    __always_noconv_ = __cv_->always_noconv();
877a984708SDavid Chisnall    if (__encoding_ > __limit)
887a984708SDavid Chisnall        __throw_runtime_error("unsupported locale for standard input");
897a984708SDavid Chisnall}
907a984708SDavid Chisnall
917a984708SDavid Chisnalltemplate <class _CharT>
927a984708SDavid Chisnalltypename __stdinbuf<_CharT>::int_type
937a984708SDavid Chisnall__stdinbuf<_CharT>::underflow()
947a984708SDavid Chisnall{
957a984708SDavid Chisnall    return __getchar(false);
967a984708SDavid Chisnall}
977a984708SDavid Chisnall
987a984708SDavid Chisnalltemplate <class _CharT>
997a984708SDavid Chisnalltypename __stdinbuf<_CharT>::int_type
1007a984708SDavid Chisnall__stdinbuf<_CharT>::uflow()
1017a984708SDavid Chisnall{
1027a984708SDavid Chisnall    return __getchar(true);
1037a984708SDavid Chisnall}
1047a984708SDavid Chisnall
1057a984708SDavid Chisnalltemplate <class _CharT>
1067a984708SDavid Chisnalltypename __stdinbuf<_CharT>::int_type
1074bab9fd9SDavid Chisnall__stdinbuf<_CharT>::__getchar(bool __consume)
1084bab9fd9SDavid Chisnall{
1094bab9fd9SDavid Chisnall    if (__last_consumed_is_next_)
1104bab9fd9SDavid Chisnall    {
1114bab9fd9SDavid Chisnall        int_type __result = __last_consumed_;
1124bab9fd9SDavid Chisnall        if (__consume)
1134bab9fd9SDavid Chisnall        {
1144bab9fd9SDavid Chisnall            __last_consumed_ = traits_type::eof();
1154bab9fd9SDavid Chisnall            __last_consumed_is_next_ = false;
1164bab9fd9SDavid Chisnall        }
1177a984708SDavid Chisnall        return __result;
1187a984708SDavid Chisnall    }
1197a984708SDavid Chisnall    char __extbuf[__limit];
1207a984708SDavid Chisnall    int __nread = _VSTD::max(1, __encoding_);
12194e3ee44SDavid Chisnall    for (int __i = 0; __i < __nread; ++__i)
1227a984708SDavid Chisnall    {
1237a984708SDavid Chisnall        int __c = getc(__file_);
1247a984708SDavid Chisnall        if (__c == EOF)
1257a984708SDavid Chisnall            return traits_type::eof();
1267a984708SDavid Chisnall        __extbuf[__i] = static_cast<char>(__c);
1277a984708SDavid Chisnall    }
1287a984708SDavid Chisnall    char_type __1buf;
1297a984708SDavid Chisnall    if (__always_noconv_)
1307a984708SDavid Chisnall        __1buf = static_cast<char_type>(__extbuf[0]);
1317a984708SDavid Chisnall    else
1327a984708SDavid Chisnall    {
1337a984708SDavid Chisnall        const char* __enxt;
1347a984708SDavid Chisnall        char_type* __inxt;
1357a984708SDavid Chisnall        codecvt_base::result __r;
1361bf9f7c1SDimitry Andric        do
1371bf9f7c1SDimitry Andric        {
1387a984708SDavid Chisnall            state_type __sv_st = *__st_;
1397a984708SDavid Chisnall            __r = __cv_->in(*__st_, __extbuf, __extbuf + __nread, __enxt,
1407a984708SDavid Chisnall                                   &__1buf, &__1buf + 1, __inxt);
1417a984708SDavid Chisnall            switch (__r)
1427a984708SDavid Chisnall            {
1437a984708SDavid Chisnall            case _VSTD::codecvt_base::ok:
1441bf9f7c1SDimitry Andric                break;
1457a984708SDavid Chisnall            case codecvt_base::partial:
1467a984708SDavid Chisnall                *__st_ = __sv_st;
1477a984708SDavid Chisnall                if (__nread == sizeof(__extbuf))
14894e3ee44SDavid Chisnall                    return traits_type::eof();
1497a984708SDavid Chisnall                {
1507a984708SDavid Chisnall                    int __c = getc(__file_);
1517a984708SDavid Chisnall                    if (__c == EOF)
1527a984708SDavid Chisnall                        return traits_type::eof();
1537a984708SDavid Chisnall                    __extbuf[__nread] = static_cast<char>(__c);
1547a984708SDavid Chisnall                }
1557a984708SDavid Chisnall                ++__nread;
1567a984708SDavid Chisnall                break;
1577a984708SDavid Chisnall            case codecvt_base::error:
1587a984708SDavid Chisnall                return traits_type::eof();
1597a984708SDavid Chisnall            case _VSTD::codecvt_base::noconv:
1607a984708SDavid Chisnall                __1buf = static_cast<char_type>(__extbuf[0]);
1617a984708SDavid Chisnall                break;
1627a984708SDavid Chisnall            }
1637a984708SDavid Chisnall        } while (__r == _VSTD::codecvt_base::partial);
1647a984708SDavid Chisnall    }
1657a984708SDavid Chisnall    if (!__consume)
1667a984708SDavid Chisnall    {
1671bf9f7c1SDimitry Andric        for (int __i = __nread; __i > 0;)
1687a984708SDavid Chisnall        {
1697a984708SDavid Chisnall            if (ungetc(traits_type::to_int_type(__extbuf[--__i]), __file_) == EOF)
1707a984708SDavid Chisnall                return traits_type::eof();
1714bab9fd9SDavid Chisnall        }
1724bab9fd9SDavid Chisnall    }
1737a984708SDavid Chisnall    else
1747a984708SDavid Chisnall        __last_consumed_ = traits_type::to_int_type(__1buf);
1757a984708SDavid Chisnall    return traits_type::to_int_type(__1buf);
1767a984708SDavid Chisnall}
1777a984708SDavid Chisnall
1787a984708SDavid Chisnalltemplate <class _CharT>
1797a984708SDavid Chisnalltypename __stdinbuf<_CharT>::int_type
1807a984708SDavid Chisnall__stdinbuf<_CharT>::pbackfail(int_type __c)
1814bab9fd9SDavid Chisnall{
1824bab9fd9SDavid Chisnall    if (traits_type::eq_int_type(__c, traits_type::eof()))
1834bab9fd9SDavid Chisnall    {
1844bab9fd9SDavid Chisnall        if (!__last_consumed_is_next_)
1854bab9fd9SDavid Chisnall        {
1864bab9fd9SDavid Chisnall            __c = __last_consumed_;
1874bab9fd9SDavid Chisnall            __last_consumed_is_next_ = !traits_type::eq_int_type(__last_consumed_,
1887a984708SDavid Chisnall                                                                 traits_type::eof());
1894bab9fd9SDavid Chisnall        }
1904bab9fd9SDavid Chisnall        return __c;
1914bab9fd9SDavid Chisnall    }
1927a984708SDavid Chisnall    if (__last_consumed_is_next_)
1937a984708SDavid Chisnall    {
1944bab9fd9SDavid Chisnall        char __extbuf[__limit];
1957a984708SDavid Chisnall        char* __enxt;
1961bf9f7c1SDimitry Andric        const char_type __ci = traits_type::to_char_type(__last_consumed_);
1977a984708SDavid Chisnall        const char_type* __inxt;
1987a984708SDavid Chisnall        switch (__cv_->out(*__st_, &__ci, &__ci + 1, __inxt,
1997a984708SDavid Chisnall                                  __extbuf, __extbuf + sizeof(__extbuf), __enxt))
2007a984708SDavid Chisnall        {
2017a984708SDavid Chisnall        case _VSTD::codecvt_base::ok:
2024bab9fd9SDavid Chisnall            break;
2037a984708SDavid Chisnall        case _VSTD::codecvt_base::noconv:
2047a984708SDavid Chisnall            __extbuf[0] = static_cast<char>(__last_consumed_);
2057a984708SDavid Chisnall            __enxt = __extbuf + 1;
2067a984708SDavid Chisnall            break;
2077a984708SDavid Chisnall        case codecvt_base::partial:
2087a984708SDavid Chisnall        case codecvt_base::error:
2097a984708SDavid Chisnall            return traits_type::eof();
2107a984708SDavid Chisnall        }
2117a984708SDavid Chisnall        while (__enxt > __extbuf)
2124bab9fd9SDavid Chisnall            if (ungetc(*--__enxt, __file_) == EOF)
2134bab9fd9SDavid Chisnall                return traits_type::eof();
2144bab9fd9SDavid Chisnall    }
2154bab9fd9SDavid Chisnall    __last_consumed_ = __c;
2167a984708SDavid Chisnall    __last_consumed_is_next_ = true;
2177a984708SDavid Chisnall    return __c;
2187a984708SDavid Chisnall}
2197a984708SDavid Chisnall
2207a984708SDavid Chisnall// __stdoutbuf
2217a984708SDavid Chisnall
2227a984708SDavid Chisnalltemplate <class _CharT>
2237a984708SDavid Chisnallclass _LIBCPP_HIDDEN __stdoutbuf
2247a984708SDavid Chisnall    : public basic_streambuf<_CharT, char_traits<_CharT> >
2257a984708SDavid Chisnall{
2267a984708SDavid Chisnallpublic:
2277a984708SDavid Chisnall    typedef _CharT                           char_type;
2287a984708SDavid Chisnall    typedef char_traits<char_type>           traits_type;
2297a984708SDavid Chisnall    typedef typename traits_type::int_type   int_type;
2307a984708SDavid Chisnall    typedef typename traits_type::pos_type   pos_type;
2317a984708SDavid Chisnall    typedef typename traits_type::off_type   off_type;
2321bf9f7c1SDimitry Andric    typedef typename traits_type::state_type state_type;
2337a984708SDavid Chisnall
2347a984708SDavid Chisnall    __stdoutbuf(FILE* __fp, state_type* __st);
2357a984708SDavid Chisnall
2364f7ab58eSDimitry Andricprotected:
2377a984708SDavid Chisnall    virtual int_type overflow (int_type __c = traits_type::eof());
2387a984708SDavid Chisnall    virtual streamsize xsputn(const char_type* __s, streamsize __n);
2397a984708SDavid Chisnall    virtual int sync();
2407a984708SDavid Chisnall    virtual void imbue(const locale& __loc);
2417a984708SDavid Chisnall
2427a984708SDavid Chisnallprivate:
2431bf9f7c1SDimitry Andric    FILE* __file_;
2447a984708SDavid Chisnall    const codecvt<char_type, char, state_type>* __cv_;
2457a984708SDavid Chisnall    state_type* __st_;
2467a984708SDavid Chisnall    bool __always_noconv_;
2477a984708SDavid Chisnall
2487a984708SDavid Chisnall    __stdoutbuf(const __stdoutbuf&);
2497a984708SDavid Chisnall    __stdoutbuf& operator=(const __stdoutbuf&);
2507a984708SDavid Chisnall};
2511bf9f7c1SDimitry Andric
2527a984708SDavid Chisnalltemplate <class _CharT>
2537a984708SDavid Chisnall__stdoutbuf<_CharT>::__stdoutbuf(FILE* __fp, state_type* __st)
2541bf9f7c1SDimitry Andric    : __file_(__fp),
2557a984708SDavid Chisnall      __cv_(&use_facet<codecvt<char_type, char, state_type> >(this->getloc())),
2567a984708SDavid Chisnall      __st_(__st),
2577a984708SDavid Chisnall      __always_noconv_(__cv_->always_noconv())
2587a984708SDavid Chisnall{
2597a984708SDavid Chisnall}
2607a984708SDavid Chisnall
2617a984708SDavid Chisnalltemplate <class _CharT>
2627a984708SDavid Chisnalltypename __stdoutbuf<_CharT>::int_type
2637a984708SDavid Chisnall__stdoutbuf<_CharT>::overflow(int_type __c)
2647a984708SDavid Chisnall{
2657a984708SDavid Chisnall    char __extbuf[__limit];
2667a984708SDavid Chisnall    char_type __1buf;
2674bab9fd9SDavid Chisnall    if (!traits_type::eq_int_type(__c, traits_type::eof()))
2687a984708SDavid Chisnall    {
2697a984708SDavid Chisnall        __1buf = traits_type::to_char_type(__c);
2704bab9fd9SDavid Chisnall        if (__always_noconv_)
2717a984708SDavid Chisnall        {
2727a984708SDavid Chisnall            if (fwrite(&__1buf, sizeof(char_type), 1, __file_) != 1)
2737a984708SDavid Chisnall                return traits_type::eof();
2747a984708SDavid Chisnall        }
2757a984708SDavid Chisnall        else
2767a984708SDavid Chisnall        {
2774bab9fd9SDavid Chisnall            char* __extbe = __extbuf;
2784bab9fd9SDavid Chisnall            codecvt_base::result __r;
2797a984708SDavid Chisnall            char_type* pbase = &__1buf;
2807a984708SDavid Chisnall            char_type* pptr = pbase + 1;
2817a984708SDavid Chisnall            do
2824bab9fd9SDavid Chisnall            {
2837a984708SDavid Chisnall                const char_type* __e;
2847a984708SDavid Chisnall                __r = __cv_->out(*__st_, pbase, pptr, __e,
2857a984708SDavid Chisnall                                        __extbuf,
2864bab9fd9SDavid Chisnall                                        __extbuf + sizeof(__extbuf),
2877a984708SDavid Chisnall                                        __extbe);
2887a984708SDavid Chisnall                if (__e == pbase)
2897a984708SDavid Chisnall                    return traits_type::eof();
2904bab9fd9SDavid Chisnall                if (__r == codecvt_base::noconv)
2917a984708SDavid Chisnall                {
2927a984708SDavid Chisnall                    if (fwrite(pbase, 1, 1, __file_) != 1)
2937a984708SDavid Chisnall                        return traits_type::eof();
2947a984708SDavid Chisnall                }
2957a984708SDavid Chisnall                else if (__r == codecvt_base::ok || __r == codecvt_base::partial)
2967a984708SDavid Chisnall                {
2977a984708SDavid Chisnall                    size_t __nmemb = static_cast<size_t>(__extbe - __extbuf);
2987a984708SDavid Chisnall                    if (fwrite(__extbuf, 1, __nmemb, __file_) != __nmemb)
2997a984708SDavid Chisnall                        return traits_type::eof();
3004bab9fd9SDavid Chisnall                    if (__r == codecvt_base::partial)
3017a984708SDavid Chisnall                    {
3027a984708SDavid Chisnall                        pbase = const_cast<char_type*>(__e);
3037a984708SDavid Chisnall                    }
3047a984708SDavid Chisnall                }
3057a984708SDavid Chisnall                else
3067a984708SDavid Chisnall                    return traits_type::eof();
3077a984708SDavid Chisnall            } while (__r == codecvt_base::partial);
3087a984708SDavid Chisnall        }
3097a984708SDavid Chisnall    }
3107a984708SDavid Chisnall    return traits_type::not_eof(__c);
3117a984708SDavid Chisnall}
3124f7ab58eSDimitry Andric
3134f7ab58eSDimitry Andrictemplate <class _CharT>
3144f7ab58eSDimitry Andricstreamsize
3154f7ab58eSDimitry Andric__stdoutbuf<_CharT>::xsputn(const char_type* __s, streamsize __n)
3164f7ab58eSDimitry Andric{
3174f7ab58eSDimitry Andric    if (__always_noconv_)
3184f7ab58eSDimitry Andric        return fwrite(__s, sizeof(char_type), __n, __file_);
3194f7ab58eSDimitry Andric    streamsize __i = 0;
3204f7ab58eSDimitry Andric    for (; __i < __n; ++__i, ++__s)
3214f7ab58eSDimitry Andric        if (overflow(traits_type::to_int_type(*__s)) == traits_type::eof())
3224f7ab58eSDimitry Andric            break;
3234f7ab58eSDimitry Andric    return __i;
3244f7ab58eSDimitry Andric}
3257a984708SDavid Chisnall
3267a984708SDavid Chisnalltemplate <class _CharT>
3277a984708SDavid Chisnallint
3287a984708SDavid Chisnall__stdoutbuf<_CharT>::sync()
3297a984708SDavid Chisnall{
3307a984708SDavid Chisnall    char __extbuf[__limit];
3317a984708SDavid Chisnall    codecvt_base::result __r;
3327a984708SDavid Chisnall    do
3331bf9f7c1SDimitry Andric    {
3347a984708SDavid Chisnall        char* __extbe;
3357a984708SDavid Chisnall        __r = __cv_->unshift(*__st_, __extbuf,
3367a984708SDavid Chisnall                                    __extbuf + sizeof(__extbuf),
3377a984708SDavid Chisnall                                    __extbe);
3387a984708SDavid Chisnall        size_t __nmemb = static_cast<size_t>(__extbe - __extbuf);
3397a984708SDavid Chisnall        if (fwrite(__extbuf, 1, __nmemb, __file_) != __nmemb)
3407a984708SDavid Chisnall            return -1;
3417a984708SDavid Chisnall    } while (__r == codecvt_base::partial);
3427a984708SDavid Chisnall    if (__r == codecvt_base::error)
3437a984708SDavid Chisnall        return -1;
3447a984708SDavid Chisnall    if (fflush(__file_))
3457a984708SDavid Chisnall        return -1;
3467a984708SDavid Chisnall    return 0;
3477a984708SDavid Chisnall}
3487a984708SDavid Chisnall
3497a984708SDavid Chisnalltemplate <class _CharT>
3507a984708SDavid Chisnallvoid
3517a984708SDavid Chisnall__stdoutbuf<_CharT>::imbue(const locale& __loc)
3527a984708SDavid Chisnall{
3537a984708SDavid Chisnall    sync();
3547a984708SDavid Chisnall    __cv_ = &use_facet<codecvt<char_type, char, state_type> >(__loc);
3557a984708SDavid Chisnall    __always_noconv_ = __cv_->always_noconv();
3567a984708SDavid Chisnall}
3577a984708SDavid Chisnall
3587a984708SDavid Chisnall_LIBCPP_END_NAMESPACE_STD
359
360_LIBCPP_POP_MACROS
361
362#endif  // _LIBCPP___STD_STREAM
363