xref: /openbsd/gnu/llvm/libcxx/include/__std_stream (revision 4bdff4be)
146035553Spatrick// -*- C++ -*-
246035553Spatrick//===----------------------------------------------------------------------===//
346035553Spatrick//
446035553Spatrick// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
546035553Spatrick// See https://llvm.org/LICENSE.txt for license information.
646035553Spatrick// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
746035553Spatrick//
846035553Spatrick//===----------------------------------------------------------------------===//
946035553Spatrick
1046035553Spatrick#ifndef _LIBCPP___STD_STREAM
1146035553Spatrick#define _LIBCPP___STD_STREAM
1246035553Spatrick
1346035553Spatrick#include <__config>
1446035553Spatrick#include <__locale>
1546035553Spatrick#include <cstdio>
16*76d0caaeSpatrick#include <istream>
17*76d0caaeSpatrick#include <ostream>
1846035553Spatrick
1946035553Spatrick#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
2046035553Spatrick#  pragma GCC system_header
2146035553Spatrick#endif
2246035553Spatrick
2346035553Spatrick_LIBCPP_PUSH_MACROS
2446035553Spatrick#include <__undef_macros>
2546035553Spatrick
2646035553Spatrick
2746035553Spatrick_LIBCPP_BEGIN_NAMESPACE_STD
2846035553Spatrick
2946035553Spatrickstatic const int __limit = 8;
3046035553Spatrick
3146035553Spatrick// __stdinbuf
3246035553Spatrick
3346035553Spatricktemplate <class _CharT>
3446035553Spatrickclass _LIBCPP_HIDDEN __stdinbuf
3546035553Spatrick    : public basic_streambuf<_CharT, char_traits<_CharT> >
3646035553Spatrick{
3746035553Spatrickpublic:
3846035553Spatrick    typedef _CharT                           char_type;
3946035553Spatrick    typedef char_traits<char_type>           traits_type;
4046035553Spatrick    typedef typename traits_type::int_type   int_type;
4146035553Spatrick    typedef typename traits_type::pos_type   pos_type;
4246035553Spatrick    typedef typename traits_type::off_type   off_type;
4346035553Spatrick    typedef typename traits_type::state_type state_type;
4446035553Spatrick
4546035553Spatrick    __stdinbuf(FILE* __fp, state_type* __st);
4646035553Spatrick
4746035553Spatrickprotected:
4846035553Spatrick    virtual int_type underflow();
4946035553Spatrick    virtual int_type uflow();
5046035553Spatrick    virtual int_type pbackfail(int_type __c = traits_type::eof());
5146035553Spatrick    virtual void imbue(const locale& __loc);
5246035553Spatrick
5346035553Spatrickprivate:
5446035553Spatrick
5546035553Spatrick    FILE* __file_;
5646035553Spatrick    const codecvt<char_type, char, state_type>* __cv_;
5746035553Spatrick    state_type* __st_;
5846035553Spatrick    int __encoding_;
5946035553Spatrick    int_type __last_consumed_;
6046035553Spatrick    bool __last_consumed_is_next_;
6146035553Spatrick    bool __always_noconv_;
6246035553Spatrick
6346035553Spatrick    __stdinbuf(const __stdinbuf&);
6446035553Spatrick    __stdinbuf& operator=(const __stdinbuf&);
6546035553Spatrick
6646035553Spatrick    int_type __getchar(bool __consume);
6746035553Spatrick};
6846035553Spatrick
6946035553Spatricktemplate <class _CharT>
7046035553Spatrick__stdinbuf<_CharT>::__stdinbuf(FILE* __fp, state_type* __st)
7146035553Spatrick    : __file_(__fp),
7246035553Spatrick      __st_(__st),
7346035553Spatrick      __last_consumed_(traits_type::eof()),
7446035553Spatrick      __last_consumed_is_next_(false)
7546035553Spatrick{
7646035553Spatrick    imbue(this->getloc());
7746035553Spatrick}
7846035553Spatrick
7946035553Spatricktemplate <class _CharT>
8046035553Spatrickvoid
8146035553Spatrick__stdinbuf<_CharT>::imbue(const locale& __loc)
8246035553Spatrick{
8346035553Spatrick    __cv_ = &use_facet<codecvt<char_type, char, state_type> >(__loc);
8446035553Spatrick    __encoding_ = __cv_->encoding();
8546035553Spatrick    __always_noconv_ = __cv_->always_noconv();
8646035553Spatrick    if (__encoding_ > __limit)
8746035553Spatrick        __throw_runtime_error("unsupported locale for standard input");
8846035553Spatrick}
8946035553Spatrick
9046035553Spatricktemplate <class _CharT>
9146035553Spatricktypename __stdinbuf<_CharT>::int_type
9246035553Spatrick__stdinbuf<_CharT>::underflow()
9346035553Spatrick{
9446035553Spatrick    return __getchar(false);
9546035553Spatrick}
9646035553Spatrick
9746035553Spatricktemplate <class _CharT>
9846035553Spatricktypename __stdinbuf<_CharT>::int_type
9946035553Spatrick__stdinbuf<_CharT>::uflow()
10046035553Spatrick{
10146035553Spatrick    return __getchar(true);
10246035553Spatrick}
10346035553Spatrick
10446035553Spatricktemplate <class _CharT>
10546035553Spatricktypename __stdinbuf<_CharT>::int_type
10646035553Spatrick__stdinbuf<_CharT>::__getchar(bool __consume)
10746035553Spatrick{
10846035553Spatrick    if (__last_consumed_is_next_)
10946035553Spatrick    {
11046035553Spatrick        int_type __result = __last_consumed_;
11146035553Spatrick        if (__consume)
11246035553Spatrick        {
11346035553Spatrick            __last_consumed_ = traits_type::eof();
11446035553Spatrick            __last_consumed_is_next_ = false;
11546035553Spatrick        }
11646035553Spatrick        return __result;
11746035553Spatrick    }
11846035553Spatrick    char __extbuf[__limit];
11946035553Spatrick    int __nread = _VSTD::max(1, __encoding_);
12046035553Spatrick    for (int __i = 0; __i < __nread; ++__i)
12146035553Spatrick    {
12246035553Spatrick        int __c = getc(__file_);
12346035553Spatrick        if (__c == EOF)
12446035553Spatrick            return traits_type::eof();
12546035553Spatrick        __extbuf[__i] = static_cast<char>(__c);
12646035553Spatrick    }
12746035553Spatrick    char_type __1buf;
12846035553Spatrick    if (__always_noconv_)
12946035553Spatrick        __1buf = static_cast<char_type>(__extbuf[0]);
13046035553Spatrick    else
13146035553Spatrick    {
13246035553Spatrick        const char* __enxt;
13346035553Spatrick        char_type* __inxt;
13446035553Spatrick        codecvt_base::result __r;
13546035553Spatrick        do
13646035553Spatrick        {
13746035553Spatrick            state_type __sv_st = *__st_;
13846035553Spatrick            __r = __cv_->in(*__st_, __extbuf, __extbuf + __nread, __enxt,
13946035553Spatrick                                   &__1buf, &__1buf + 1, __inxt);
14046035553Spatrick            switch (__r)
14146035553Spatrick            {
14246035553Spatrick            case _VSTD::codecvt_base::ok:
14346035553Spatrick                break;
14446035553Spatrick            case codecvt_base::partial:
14546035553Spatrick                *__st_ = __sv_st;
14646035553Spatrick                if (__nread == sizeof(__extbuf))
14746035553Spatrick                    return traits_type::eof();
14846035553Spatrick                {
14946035553Spatrick                    int __c = getc(__file_);
15046035553Spatrick                    if (__c == EOF)
15146035553Spatrick                        return traits_type::eof();
15246035553Spatrick                    __extbuf[__nread] = static_cast<char>(__c);
15346035553Spatrick                }
15446035553Spatrick                ++__nread;
15546035553Spatrick                break;
15646035553Spatrick            case codecvt_base::error:
15746035553Spatrick                return traits_type::eof();
15846035553Spatrick            case _VSTD::codecvt_base::noconv:
15946035553Spatrick                __1buf = static_cast<char_type>(__extbuf[0]);
16046035553Spatrick                break;
16146035553Spatrick            }
16246035553Spatrick        } while (__r == _VSTD::codecvt_base::partial);
16346035553Spatrick    }
16446035553Spatrick    if (!__consume)
16546035553Spatrick    {
16646035553Spatrick        for (int __i = __nread; __i > 0;)
16746035553Spatrick        {
16846035553Spatrick            if (ungetc(traits_type::to_int_type(__extbuf[--__i]), __file_) == EOF)
16946035553Spatrick                return traits_type::eof();
17046035553Spatrick        }
17146035553Spatrick    }
17246035553Spatrick    else
17346035553Spatrick        __last_consumed_ = traits_type::to_int_type(__1buf);
17446035553Spatrick    return traits_type::to_int_type(__1buf);
17546035553Spatrick}
17646035553Spatrick
17746035553Spatricktemplate <class _CharT>
17846035553Spatricktypename __stdinbuf<_CharT>::int_type
17946035553Spatrick__stdinbuf<_CharT>::pbackfail(int_type __c)
18046035553Spatrick{
18146035553Spatrick    if (traits_type::eq_int_type(__c, traits_type::eof()))
18246035553Spatrick    {
18346035553Spatrick        if (!__last_consumed_is_next_)
18446035553Spatrick        {
18546035553Spatrick            __c = __last_consumed_;
18646035553Spatrick            __last_consumed_is_next_ = !traits_type::eq_int_type(__last_consumed_,
18746035553Spatrick                                                                 traits_type::eof());
18846035553Spatrick        }
18946035553Spatrick        return __c;
19046035553Spatrick    }
19146035553Spatrick    if (__last_consumed_is_next_)
19246035553Spatrick    {
19346035553Spatrick        char __extbuf[__limit];
19446035553Spatrick        char* __enxt;
19546035553Spatrick        const char_type __ci = traits_type::to_char_type(__last_consumed_);
19646035553Spatrick        const char_type* __inxt;
19746035553Spatrick        switch (__cv_->out(*__st_, &__ci, &__ci + 1, __inxt,
19846035553Spatrick                                  __extbuf, __extbuf + sizeof(__extbuf), __enxt))
19946035553Spatrick        {
20046035553Spatrick        case _VSTD::codecvt_base::ok:
20146035553Spatrick            break;
20246035553Spatrick        case _VSTD::codecvt_base::noconv:
20346035553Spatrick            __extbuf[0] = static_cast<char>(__last_consumed_);
20446035553Spatrick            __enxt = __extbuf + 1;
20546035553Spatrick            break;
20646035553Spatrick        case codecvt_base::partial:
20746035553Spatrick        case codecvt_base::error:
20846035553Spatrick            return traits_type::eof();
20946035553Spatrick        }
21046035553Spatrick        while (__enxt > __extbuf)
21146035553Spatrick            if (ungetc(*--__enxt, __file_) == EOF)
21246035553Spatrick                return traits_type::eof();
21346035553Spatrick    }
21446035553Spatrick    __last_consumed_ = __c;
21546035553Spatrick    __last_consumed_is_next_ = true;
21646035553Spatrick    return __c;
21746035553Spatrick}
21846035553Spatrick
21946035553Spatrick// __stdoutbuf
22046035553Spatrick
22146035553Spatricktemplate <class _CharT>
22246035553Spatrickclass _LIBCPP_HIDDEN __stdoutbuf
22346035553Spatrick    : public basic_streambuf<_CharT, char_traits<_CharT> >
22446035553Spatrick{
22546035553Spatrickpublic:
22646035553Spatrick    typedef _CharT                           char_type;
22746035553Spatrick    typedef char_traits<char_type>           traits_type;
22846035553Spatrick    typedef typename traits_type::int_type   int_type;
22946035553Spatrick    typedef typename traits_type::pos_type   pos_type;
23046035553Spatrick    typedef typename traits_type::off_type   off_type;
23146035553Spatrick    typedef typename traits_type::state_type state_type;
23246035553Spatrick
23346035553Spatrick    __stdoutbuf(FILE* __fp, state_type* __st);
23446035553Spatrick
23546035553Spatrickprotected:
23646035553Spatrick    virtual int_type overflow (int_type __c = traits_type::eof());
23746035553Spatrick    virtual streamsize xsputn(const char_type* __s, streamsize __n);
23846035553Spatrick    virtual int sync();
23946035553Spatrick    virtual void imbue(const locale& __loc);
24046035553Spatrick
24146035553Spatrickprivate:
24246035553Spatrick    FILE* __file_;
24346035553Spatrick    const codecvt<char_type, char, state_type>* __cv_;
24446035553Spatrick    state_type* __st_;
24546035553Spatrick    bool __always_noconv_;
24646035553Spatrick
24746035553Spatrick    __stdoutbuf(const __stdoutbuf&);
24846035553Spatrick    __stdoutbuf& operator=(const __stdoutbuf&);
24946035553Spatrick};
25046035553Spatrick
25146035553Spatricktemplate <class _CharT>
25246035553Spatrick__stdoutbuf<_CharT>::__stdoutbuf(FILE* __fp, state_type* __st)
25346035553Spatrick    : __file_(__fp),
25446035553Spatrick      __cv_(&use_facet<codecvt<char_type, char, state_type> >(this->getloc())),
25546035553Spatrick      __st_(__st),
25646035553Spatrick      __always_noconv_(__cv_->always_noconv())
25746035553Spatrick{
25846035553Spatrick}
25946035553Spatrick
26046035553Spatricktemplate <class _CharT>
26146035553Spatricktypename __stdoutbuf<_CharT>::int_type
26246035553Spatrick__stdoutbuf<_CharT>::overflow(int_type __c)
26346035553Spatrick{
26446035553Spatrick    char __extbuf[__limit];
26546035553Spatrick    char_type __1buf;
26646035553Spatrick    if (!traits_type::eq_int_type(__c, traits_type::eof()))
26746035553Spatrick    {
26846035553Spatrick        __1buf = traits_type::to_char_type(__c);
26946035553Spatrick        if (__always_noconv_)
27046035553Spatrick        {
27146035553Spatrick            if (fwrite(&__1buf, sizeof(char_type), 1, __file_) != 1)
27246035553Spatrick                return traits_type::eof();
27346035553Spatrick        }
27446035553Spatrick        else
27546035553Spatrick        {
27646035553Spatrick            char* __extbe = __extbuf;
27746035553Spatrick            codecvt_base::result __r;
27846035553Spatrick            char_type* pbase = &__1buf;
27946035553Spatrick            char_type* pptr = pbase + 1;
28046035553Spatrick            do
28146035553Spatrick            {
28246035553Spatrick                const char_type* __e;
28346035553Spatrick                __r = __cv_->out(*__st_, pbase, pptr, __e,
28446035553Spatrick                                        __extbuf,
28546035553Spatrick                                        __extbuf + sizeof(__extbuf),
28646035553Spatrick                                        __extbe);
28746035553Spatrick                if (__e == pbase)
28846035553Spatrick                    return traits_type::eof();
28946035553Spatrick                if (__r == codecvt_base::noconv)
29046035553Spatrick                {
29146035553Spatrick                    if (fwrite(pbase, 1, 1, __file_) != 1)
29246035553Spatrick                        return traits_type::eof();
29346035553Spatrick                }
29446035553Spatrick                else if (__r == codecvt_base::ok || __r == codecvt_base::partial)
29546035553Spatrick                {
29646035553Spatrick                    size_t __nmemb = static_cast<size_t>(__extbe - __extbuf);
29746035553Spatrick                    if (fwrite(__extbuf, 1, __nmemb, __file_) != __nmemb)
29846035553Spatrick                        return traits_type::eof();
29946035553Spatrick                    if (__r == codecvt_base::partial)
30046035553Spatrick                    {
30146035553Spatrick                        pbase = const_cast<char_type*>(__e);
30246035553Spatrick                    }
30346035553Spatrick                }
30446035553Spatrick                else
30546035553Spatrick                    return traits_type::eof();
30646035553Spatrick            } while (__r == codecvt_base::partial);
30746035553Spatrick        }
30846035553Spatrick    }
30946035553Spatrick    return traits_type::not_eof(__c);
31046035553Spatrick}
31146035553Spatrick
31246035553Spatricktemplate <class _CharT>
31346035553Spatrickstreamsize
31446035553Spatrick__stdoutbuf<_CharT>::xsputn(const char_type* __s, streamsize __n)
31546035553Spatrick{
31646035553Spatrick    if (__always_noconv_)
31746035553Spatrick        return fwrite(__s, sizeof(char_type), __n, __file_);
31846035553Spatrick    streamsize __i = 0;
31946035553Spatrick    for (; __i < __n; ++__i, ++__s)
32046035553Spatrick        if (overflow(traits_type::to_int_type(*__s)) == traits_type::eof())
32146035553Spatrick            break;
32246035553Spatrick    return __i;
32346035553Spatrick}
32446035553Spatrick
32546035553Spatricktemplate <class _CharT>
32646035553Spatrickint
32746035553Spatrick__stdoutbuf<_CharT>::sync()
32846035553Spatrick{
32946035553Spatrick    char __extbuf[__limit];
33046035553Spatrick    codecvt_base::result __r;
33146035553Spatrick    do
33246035553Spatrick    {
33346035553Spatrick        char* __extbe;
33446035553Spatrick        __r = __cv_->unshift(*__st_, __extbuf,
33546035553Spatrick                                    __extbuf + sizeof(__extbuf),
33646035553Spatrick                                    __extbe);
33746035553Spatrick        size_t __nmemb = static_cast<size_t>(__extbe - __extbuf);
33846035553Spatrick        if (fwrite(__extbuf, 1, __nmemb, __file_) != __nmemb)
33946035553Spatrick            return -1;
34046035553Spatrick    } while (__r == codecvt_base::partial);
34146035553Spatrick    if (__r == codecvt_base::error)
34246035553Spatrick        return -1;
34346035553Spatrick    if (fflush(__file_))
34446035553Spatrick        return -1;
34546035553Spatrick    return 0;
34646035553Spatrick}
34746035553Spatrick
34846035553Spatricktemplate <class _CharT>
34946035553Spatrickvoid
35046035553Spatrick__stdoutbuf<_CharT>::imbue(const locale& __loc)
35146035553Spatrick{
35246035553Spatrick    sync();
35346035553Spatrick    __cv_ = &use_facet<codecvt<char_type, char, state_type> >(__loc);
35446035553Spatrick    __always_noconv_ = __cv_->always_noconv();
35546035553Spatrick}
35646035553Spatrick
35746035553Spatrick_LIBCPP_END_NAMESPACE_STD
35846035553Spatrick
35946035553Spatrick_LIBCPP_POP_MACROS
36046035553Spatrick
36146035553Spatrick#endif // _LIBCPP___STD_STREAM
362