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