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     __stdinbuf(FILE* __fp, state_type* __st);
     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     int_type __last_consumed_;
     59     bool __last_consumed_is_next_;
     60     bool __always_noconv_;
     61 
     62     __stdinbuf(const __stdinbuf&);
     63     __stdinbuf& operator=(const __stdinbuf&);
     64 
     65     int_type __getchar(bool __consume);
     66 };
     67 
     68 template <class _CharT>
     69 __stdinbuf<_CharT>::__stdinbuf(FILE* __fp, state_type* __st)
     70     : __file_(__fp),
     71       __st_(__st),
     72       __last_consumed_(traits_type::eof()),
     73       __last_consumed_is_next_(false)
     74 {
     75     imbue(this->getloc());
     76 }
     77 
     78 template <class _CharT>
     79 void
     80 __stdinbuf<_CharT>::imbue(const locale& __loc)
     81 {
     82     __cv_ = &use_facet<codecvt<char_type, char, state_type> >(__loc);
     83     __encoding_ = __cv_->encoding();
     84     __always_noconv_ = __cv_->always_noconv();
     85     if (__encoding_ > __limit)
     86         __throw_runtime_error("unsupported locale for standard input");
     87 }
     88 
     89 template <class _CharT>
     90 typename __stdinbuf<_CharT>::int_type
     91 __stdinbuf<_CharT>::underflow()
     92 {
     93     return __getchar(false);
     94 }
     95 
     96 template <class _CharT>
     97 typename __stdinbuf<_CharT>::int_type
     98 __stdinbuf<_CharT>::uflow()
     99 {
    100     return __getchar(true);
    101 }
    102 
    103 template <class _CharT>
    104 typename __stdinbuf<_CharT>::int_type
    105 __stdinbuf<_CharT>::__getchar(bool __consume)
    106 {
    107     if (__last_consumed_is_next_)
    108     {
    109         int_type __result = __last_consumed_;
    110         if (__consume)
    111         {
    112             __last_consumed_ = traits_type::eof();
    113             __last_consumed_is_next_ = false;
    114         }
    115         return __result;
    116     }
    117     char __extbuf[__limit];
    118     int __nread = _VSTD::max(1, __encoding_);
    119     for (int __i = 0; __i < __nread; ++__i)
    120     {
    121         int __c = getc(__file_);
    122         if (__c == EOF)
    123             return traits_type::eof();
    124         __extbuf[__i] = static_cast<char>(__c);
    125     }
    126     char_type __1buf;
    127     if (__always_noconv_)
    128         __1buf = static_cast<char_type>(__extbuf[0]);
    129     else
    130     {
    131         const char* __enxt;
    132         char_type* __inxt;
    133         codecvt_base::result __r;
    134         do
    135         {
    136             state_type __sv_st = *__st_;
    137             __r = __cv_->in(*__st_, __extbuf, __extbuf + __nread, __enxt,
    138                                    &__1buf, &__1buf + 1, __inxt);
    139             switch (__r)
    140             {
    141             case _VSTD::codecvt_base::ok:
    142                 break;
    143             case codecvt_base::partial:
    144                 *__st_ = __sv_st;
    145                 if (__nread == sizeof(__extbuf))
    146                     return traits_type::eof();
    147                 {
    148                     int __c = getc(__file_);
    149                     if (__c == EOF)
    150                         return traits_type::eof();
    151                     __extbuf[__nread] = static_cast<char>(__c);
    152                 }
    153                 ++__nread;
    154                 break;
    155             case codecvt_base::error:
    156                 return traits_type::eof();
    157             case _VSTD::codecvt_base::noconv:
    158                 __1buf = static_cast<char_type>(__extbuf[0]);
    159                 break;
    160             }
    161         } while (__r == _VSTD::codecvt_base::partial);
    162     }
    163     if (!__consume)
    164     {
    165         for (int __i = __nread; __i > 0;)
    166         {
    167             if (ungetc(traits_type::to_int_type(__extbuf[--__i]), __file_) == EOF)
    168                 return traits_type::eof();
    169         }
    170     }
    171     else
    172         __last_consumed_ = traits_type::to_int_type(__1buf);
    173     return traits_type::to_int_type(__1buf);
    174 }
    175 
    176 template <class _CharT>
    177 typename __stdinbuf<_CharT>::int_type
    178 __stdinbuf<_CharT>::pbackfail(int_type __c)
    179 {
    180     if (traits_type::eq_int_type(__c, traits_type::eof()))
    181     {
    182         if (!__last_consumed_is_next_)
    183         {
    184             __c = __last_consumed_;
    185             __last_consumed_is_next_ = !traits_type::eq_int_type(__last_consumed_,
    186                                                                  traits_type::eof());
    187         }
    188         return __c;
    189     }
    190     if (__last_consumed_is_next_)
    191     {
    192         char __extbuf[__limit];
    193         char* __enxt;
    194         const char_type __ci = traits_type::to_char_type(__last_consumed_);
    195         const char_type* __inxt;
    196         switch (__cv_->out(*__st_, &__ci, &__ci + 1, __inxt,
    197                                   __extbuf, __extbuf + sizeof(__extbuf), __enxt))
    198         {
    199         case _VSTD::codecvt_base::ok:
    200             break;
    201         case _VSTD::codecvt_base::noconv:
    202             __extbuf[0] = static_cast<char>(__last_consumed_);
    203             __enxt = __extbuf + 1;
    204             break;
    205         case codecvt_base::partial:
    206         case codecvt_base::error:
    207             return traits_type::eof();
    208         }
    209         while (__enxt > __extbuf)
    210             if (ungetc(*--__enxt, __file_) == EOF)
    211                 return traits_type::eof();
    212     }
    213     __last_consumed_ = __c;
    214     __last_consumed_is_next_ = true;
    215     return __c;
    216 }
    217 
    218 // __stdoutbuf
    219 
    220 template <class _CharT>
    221 class _LIBCPP_HIDDEN __stdoutbuf
    222     : public basic_streambuf<_CharT, char_traits<_CharT> >
    223 {
    224 public:
    225     typedef _CharT                           char_type;
    226     typedef char_traits<char_type>           traits_type;
    227     typedef typename traits_type::int_type   int_type;
    228     typedef typename traits_type::pos_type   pos_type;
    229     typedef typename traits_type::off_type   off_type;
    230     typedef typename traits_type::state_type state_type;
    231 
    232     __stdoutbuf(FILE* __fp, state_type* __st);
    233 
    234 protected:
    235     virtual int_type overflow (int_type __c = traits_type::eof());
    236     virtual streamsize xsputn(const char_type* __s, streamsize __n);
    237     virtual int sync();
    238     virtual void imbue(const locale& __loc);
    239 
    240 private:
    241     FILE* __file_;
    242     const codecvt<char_type, char, state_type>* __cv_;
    243     state_type* __st_;
    244     bool __always_noconv_;
    245 
    246     __stdoutbuf(const __stdoutbuf&);
    247     __stdoutbuf& operator=(const __stdoutbuf&);
    248 };
    249 
    250 template <class _CharT>
    251 __stdoutbuf<_CharT>::__stdoutbuf(FILE* __fp, state_type* __st)
    252     : __file_(__fp),
    253       __cv_(&use_facet<codecvt<char_type, char, state_type> >(this->getloc())),
    254       __st_(__st),
    255       __always_noconv_(__cv_->always_noconv())
    256 {
    257 }
    258 
    259 template <class _CharT>
    260 typename __stdoutbuf<_CharT>::int_type
    261 __stdoutbuf<_CharT>::overflow(int_type __c)
    262 {
    263     char __extbuf[__limit];
    264     char_type __1buf;
    265     if (!traits_type::eq_int_type(__c, traits_type::eof()))
    266     {
    267         __1buf = traits_type::to_char_type(__c);
    268         if (__always_noconv_)
    269         {
    270             if (fwrite(&__1buf, sizeof(char_type), 1, __file_) != 1)
    271                 return traits_type::eof();
    272         }
    273         else
    274         {
    275             char* __extbe = __extbuf;
    276             codecvt_base::result __r;
    277             char_type* pbase = &__1buf;
    278             char_type* pptr = pbase + 1;
    279             char_type* epptr = pptr;
    280             do
    281             {
    282                 const char_type* __e;
    283                 __r = __cv_->out(*__st_, pbase, pptr, __e,
    284                                         __extbuf,
    285                                         __extbuf + sizeof(__extbuf),
    286                                         __extbe);
    287                 if (__e == pbase)
    288                     return traits_type::eof();
    289                 if (__r == codecvt_base::noconv)
    290                 {
    291                     if (fwrite(pbase, 1, 1, __file_) != 1)
    292                         return traits_type::eof();
    293                 }
    294                 else if (__r == codecvt_base::ok || __r == codecvt_base::partial)
    295                 {
    296                     size_t __nmemb = static_cast<size_t>(__extbe - __extbuf);
    297                     if (fwrite(__extbuf, 1, __nmemb, __file_) != __nmemb)
    298                         return traits_type::eof();
    299                     if (__r == codecvt_base::partial)
    300                     {
    301                         pbase = (char_type*)__e;
    302                     }
    303                 }
    304                 else
    305                     return traits_type::eof();
    306             } while (__r == codecvt_base::partial);
    307         }
    308     }
    309     return traits_type::not_eof(__c);
    310 }
    311 
    312 template <class _CharT>
    313 streamsize
    314 __stdoutbuf<_CharT>::xsputn(const char_type* __s, streamsize __n)
    315 {
    316     if (__always_noconv_)
    317         return fwrite(__s, sizeof(char_type), __n, __file_);
    318     streamsize __i = 0;
    319     for (; __i < __n; ++__i, ++__s)
    320         if (overflow(traits_type::to_int_type(*__s)) == traits_type::eof())
    321             break;
    322     return __i;
    323 }
    324 
    325 template <class _CharT>
    326 int
    327 __stdoutbuf<_CharT>::sync()
    328 {
    329     char __extbuf[__limit];
    330     codecvt_base::result __r;
    331     do
    332     {
    333         char* __extbe;
    334         __r = __cv_->unshift(*__st_, __extbuf,
    335                                     __extbuf + sizeof(__extbuf),
    336                                     __extbe);
    337         size_t __nmemb = static_cast<size_t>(__extbe - __extbuf);
    338         if (fwrite(__extbuf, 1, __nmemb, __file_) != __nmemb)
    339             return -1;
    340     } while (__r == codecvt_base::partial);
    341     if (__r == codecvt_base::error)
    342         return -1;
    343     if (fflush(__file_))
    344         return -1;
    345     return 0;
    346 }
    347 
    348 template <class _CharT>
    349 void
    350 __stdoutbuf<_CharT>::imbue(const locale& __loc)
    351 {
    352     sync();
    353     __cv_ = &use_facet<codecvt<char_type, char, state_type> >(__loc);
    354     __always_noconv_ = __cv_->always_noconv();
    355 }
    356 
    357 _LIBCPP_END_NAMESPACE_STD
    358 
    359 #endif  // _LIBCPP___STD_STREAM
    360