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