Home | History | Annotate | Download | only in include
      1 // -*- C++ -*-
      2 //===----------------------------------------------------------------------===//
      3 //
      4 //                     The LLVM Compiler Infrastructure
      5 //
      6 // This file is dual licensed under the MIT and the University of Illinois Open
      7 // Source Licenses. See LICENSE.TXT for details.
      8 //
      9 //===----------------------------------------------------------------------===//
     10 
     11 #ifndef _LIBCPP___STD_STREAM
     12 #define _LIBCPP___STD_STREAM
     13 
     14 #include <__config>
     15 #include <ostream>
     16 #include <istream>
     17 #include <__locale>
     18 #include <cstdio>
     19 
     20 #include <__undef_min_max>
     21 
     22 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
     23 #pragma GCC system_header
     24 #endif
     25 
     26 _LIBCPP_BEGIN_NAMESPACE_STD
     27 
     28 static const int __limit = 8;
     29 
     30 // __stdinbuf
     31 
     32 template <class _CharT>
     33 class _LIBCPP_HIDDEN __stdinbuf
     34     : public basic_streambuf<_CharT, char_traits<_CharT> >
     35 {
     36 public:
     37     typedef _CharT                           char_type;
     38     typedef char_traits<char_type>           traits_type;
     39     typedef typename traits_type::int_type   int_type;
     40     typedef typename traits_type::pos_type   pos_type;
     41     typedef typename traits_type::off_type   off_type;
     42     typedef typename traits_type::state_type state_type;
     43 
     44     explicit __stdinbuf(FILE* __fp);
     45 
     46 protected:
     47     virtual int_type underflow();
     48     virtual int_type uflow();
     49     virtual int_type pbackfail(int_type __c = traits_type::eof());
     50     virtual void imbue(const locale& __loc);
     51 
     52 private:
     53 
     54     FILE* __file_;
     55     const codecvt<char_type, char, state_type>* __cv_;
     56     state_type __st_;
     57     int __encoding_;
     58     bool __always_noconv_;
     59 
     60     __stdinbuf(const __stdinbuf&);
     61     __stdinbuf& operator=(const __stdinbuf&);
     62 
     63     int_type __getchar(bool __consume);
     64 };
     65 
     66 template <class _CharT>
     67 __stdinbuf<_CharT>::__stdinbuf(FILE* __fp)
     68     : __file_(__fp),
     69       __st_()
     70 {
     71     imbue(this->getloc());
     72 }
     73 
     74 template <class _CharT>
     75 void
     76 __stdinbuf<_CharT>::imbue(const locale& __loc)
     77 {
     78     __cv_ = &use_facet<codecvt<char_type, char, state_type> >(__loc);
     79     __encoding_ = __cv_->encoding();
     80     __always_noconv_ = __cv_->always_noconv();
     81     if (__encoding_ > __limit)
     82         __throw_runtime_error("unsupported locale for standard input");
     83 }
     84 
     85 template <class _CharT>
     86 typename __stdinbuf<_CharT>::int_type
     87 __stdinbuf<_CharT>::underflow()
     88 {
     89     return __getchar(false);
     90 }
     91 
     92 template <class _CharT>
     93 typename __stdinbuf<_CharT>::int_type
     94 __stdinbuf<_CharT>::uflow()
     95 {
     96     return __getchar(true);
     97 }
     98 
     99 template <class _CharT>
    100 typename __stdinbuf<_CharT>::int_type
    101 __stdinbuf<_CharT>::__getchar(bool __consume)
    102 {
    103     char __extbuf[__limit];
    104     int __nread = _VSTD::max(1, __encoding_);
    105     for (int __i = 0; __i < __nread; ++__i)
    106     {
    107         int __c = getc(__file_);
    108         if (__c == EOF)
    109             return traits_type::eof();
    110         __extbuf[__i] = static_cast<char>(__c);
    111     }
    112     char_type __1buf;
    113     if (__always_noconv_)
    114         __1buf = static_cast<char_type>(__extbuf[0]);
    115     else
    116     {
    117         const char* __enxt;
    118         char_type* __inxt;
    119         codecvt_base::result __r;
    120         do
    121         {
    122             state_type __sv_st = __st_;
    123             __r = __cv_->in(__st_, __extbuf, __extbuf + __nread, __enxt,
    124                                    &__1buf, &__1buf + 1, __inxt);
    125             switch (__r)
    126             {
    127             case _VSTD::codecvt_base::ok:
    128                 break;
    129             case codecvt_base::partial:
    130                 __st_ = __sv_st;
    131                 if (__nread == sizeof(__extbuf))
    132                     return traits_type::eof();
    133                 {
    134                     int __c = getc(__file_);
    135                     if (__c == EOF)
    136                         return traits_type::eof();
    137                     __extbuf[__nread] = static_cast<char>(__c);
    138                 }
    139                 ++__nread;
    140                 break;
    141             case codecvt_base::error:
    142                 return traits_type::eof();
    143             case _VSTD::codecvt_base::noconv:
    144                 __1buf = static_cast<char_type>(__extbuf[0]);
    145                 break;
    146             }
    147         } while (__r == _VSTD::codecvt_base::partial);
    148     }
    149     if (!__consume)
    150     {
    151         for (int __i = __nread; __i > 0;)
    152         {
    153             if (ungetc(__extbuf[--__i], __file_) == EOF)
    154                 return traits_type::eof();
    155         }
    156     }
    157     return traits_type::to_int_type(__1buf);
    158 }
    159 
    160 template <class _CharT>
    161 typename __stdinbuf<_CharT>::int_type
    162 __stdinbuf<_CharT>::pbackfail(int_type __c)
    163 {
    164     if (traits_type::eq_int_type(__c, traits_type::eof()))
    165         return __c;
    166     char __extbuf[__limit];
    167     char* __enxt;
    168     const char_type __ci = traits_type::to_char_type(__c);
    169     const char_type* __inxt;
    170     switch (__cv_->out(__st_, &__ci, &__ci + 1, __inxt,
    171                               __extbuf, __extbuf + sizeof(__extbuf), __enxt))
    172     {
    173     case _VSTD::codecvt_base::ok:
    174         break;
    175     case _VSTD::codecvt_base::noconv:
    176         __extbuf[0] = static_cast<char>(__c);
    177         __enxt = __extbuf + 1;
    178         break;
    179     case codecvt_base::partial:
    180     case codecvt_base::error:
    181         return traits_type::eof();
    182     }
    183     while (__enxt > __extbuf)
    184         if (ungetc(*--__enxt, __file_) == EOF)
    185             return traits_type::eof();
    186  return traits_type::not_eof(__c);
    187 }
    188 
    189 // __stdoutbuf
    190 
    191 template <class _CharT>
    192 class _LIBCPP_HIDDEN __stdoutbuf
    193     : public basic_streambuf<_CharT, char_traits<_CharT> >
    194 {
    195 public:
    196     typedef _CharT                           char_type;
    197     typedef char_traits<char_type>           traits_type;
    198     typedef typename traits_type::int_type   int_type;
    199     typedef typename traits_type::pos_type   pos_type;
    200     typedef typename traits_type::off_type   off_type;
    201     typedef typename traits_type::state_type state_type;
    202 
    203     explicit __stdoutbuf(FILE* __fp);
    204 
    205 protected:
    206     virtual int_type overflow (int_type __c = traits_type::eof());
    207     virtual int sync();
    208     virtual void imbue(const locale& __loc);
    209 
    210 private:
    211     FILE* __file_;
    212     const codecvt<char_type, char, state_type>* __cv_;
    213     state_type __st_;
    214     bool __always_noconv_;
    215 
    216     __stdoutbuf(const __stdoutbuf&);
    217     __stdoutbuf& operator=(const __stdoutbuf&);
    218 };
    219 
    220 template <class _CharT>
    221 __stdoutbuf<_CharT>::__stdoutbuf(FILE* __fp)
    222     : __file_(__fp),
    223       __cv_(&use_facet<codecvt<char_type, char, state_type> >(this->getloc())),
    224       __st_(),
    225       __always_noconv_(__cv_->always_noconv())
    226 {
    227 }
    228 
    229 template <class _CharT>
    230 typename __stdoutbuf<_CharT>::int_type
    231 __stdoutbuf<_CharT>::overflow(int_type __c)
    232 {
    233     char __extbuf[__limit];
    234     char_type __1buf;
    235     if (!traits_type::eq_int_type(__c, traits_type::eof()))
    236     {
    237         this->setp(&__1buf, &__1buf+1);
    238         *this->pptr() = traits_type::to_char_type(__c);
    239         this->pbump(1);
    240         if (__always_noconv_)
    241         {
    242             if (fwrite(this->pbase(), sizeof(char_type), 1, __file_) != 1)
    243                 return traits_type::eof();
    244         }
    245         else
    246         {
    247             char* __extbe = __extbuf;
    248             codecvt_base::result __r;
    249             do
    250             {
    251                 const char_type* __e;
    252                 __r = __cv_->out(__st_, this->pbase(), this->pptr(), __e,
    253                                         __extbuf,
    254                                         __extbuf + sizeof(__extbuf),
    255                                         __extbe);
    256                 if (__e == this->pbase())
    257                     return traits_type::eof();
    258                 if (__r == codecvt_base::noconv)
    259                 {
    260                     if (fwrite(this->pbase(), 1, 1, __file_) != 1)
    261                         return traits_type::eof();
    262                 }
    263                 else if (__r == codecvt_base::ok || __r == codecvt_base::partial)
    264                 {
    265                     size_t __nmemb = static_cast<size_t>(__extbe - __extbuf);
    266                     if (fwrite(__extbuf, 1, __nmemb, __file_) != __nmemb)
    267                         return traits_type::eof();
    268                     if (__r == codecvt_base::partial)
    269                     {
    270                         this->setp((char_type*)__e, this->pptr());
    271                         this->pbump(static_cast<int>(this->epptr() - this->pbase()));
    272                     }
    273                 }
    274                 else
    275                     return traits_type::eof();
    276             } while (__r == codecvt_base::partial);
    277         }
    278         this->setp(0, 0);
    279     }
    280     return traits_type::not_eof(__c);
    281 }
    282 
    283 template <class _CharT>
    284 int
    285 __stdoutbuf<_CharT>::sync()
    286 {
    287     char __extbuf[__limit];
    288     codecvt_base::result __r;
    289     do
    290     {
    291         char* __extbe;
    292         __r = __cv_->unshift(__st_, __extbuf,
    293                                     __extbuf + sizeof(__extbuf),
    294                                     __extbe);
    295         size_t __nmemb = static_cast<size_t>(__extbe - __extbuf);
    296         if (fwrite(__extbuf, 1, __nmemb, __file_) != __nmemb)
    297             return -1;
    298     } while (__r == codecvt_base::partial);
    299     if (__r == codecvt_base::error)
    300         return -1;
    301     if (fflush(__file_))
    302         return -1;
    303     return 0;
    304 }
    305 
    306 template <class _CharT>
    307 void
    308 __stdoutbuf<_CharT>::imbue(const locale& __loc)
    309 {
    310     sync();
    311     __cv_ = &use_facet<codecvt<char_type, char, state_type> >(__loc);
    312     __always_noconv_ = __cv_->always_noconv();
    313 }
    314 
    315 _LIBCPP_END_NAMESPACE_STD
    316 
    317 #endif  // _LIBCPP___STD_STREAM
    318