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