1 // -*- C++ -*- 2 //===----------------------------------------------------------------------===// 3 // 4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5 // See https://llvm.org/LICENSE.txt for license information. 6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7 // 8 //===----------------------------------------------------------------------===// 9 10 #ifndef _LIBCPP_STD_STREAM_H 11 #define _LIBCPP_STD_STREAM_H 12 13 #include <__config> 14 #include <__locale> 15 #include <cstdio> 16 #include <istream> 17 #include <ostream> 18 19 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 20 # pragma GCC system_header 21 #endif 22 23 _LIBCPP_PUSH_MACROS 24 #include <__undef_macros> 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 : public basic_streambuf<_CharT, char_traits<_CharT> > { 34 public: 35 typedef _CharT char_type; 36 typedef char_traits<char_type> traits_type; 37 typedef typename traits_type::int_type int_type; 38 typedef typename traits_type::pos_type pos_type; 39 typedef typename traits_type::off_type off_type; 40 typedef typename traits_type::state_type state_type; 41 42 __stdinbuf(FILE* __fp, state_type* __st); 43 44 protected: 45 virtual int_type underflow(); 46 virtual int_type uflow(); 47 virtual int_type pbackfail(int_type __c = traits_type::eof()); 48 virtual void imbue(const locale& __loc); 49 50 private: 51 FILE* __file_; 52 const codecvt<char_type, char, state_type>* __cv_; 53 state_type* __st_; 54 int __encoding_; 55 int_type __last_consumed_; 56 bool __last_consumed_is_next_; 57 bool __always_noconv_; 58 59 #if defined(_LIBCPP_WIN32API) 60 static constexpr bool __is_win32api_wide_char = !is_same_v<_CharT, char>; 61 #else 62 static constexpr bool __is_win32api_wide_char = false; 63 #endif 64 65 __stdinbuf(const __stdinbuf&); 66 __stdinbuf& operator=(const __stdinbuf&); 67 68 int_type __getchar(bool __consume); 69 }; 70 71 template <class _CharT> 72 __stdinbuf<_CharT>::__stdinbuf(FILE* __fp, state_type* __st) 73 : __file_(__fp), __st_(__st), __last_consumed_(traits_type::eof()), __last_consumed_is_next_(false) { 74 imbue(this->getloc()); 75 // On Windows, in wchar_t mode, ignore the codecvt from the locale by 76 // default and assume noconv; this passes wchar_t through unmodified from 77 // getwc. If the user sets a custom locale with imbue(), that gets honored, 78 // the IO is done with getc() and converted with the provided codecvt. 79 if constexpr (__is_win32api_wide_char) 80 __always_noconv_ = true; 81 } 82 83 template <class _CharT> 84 void __stdinbuf<_CharT>::imbue(const locale& __loc) { 85 __cv_ = &use_facet<codecvt<char_type, char, state_type> >(__loc); 86 __encoding_ = __cv_->encoding(); 87 __always_noconv_ = __cv_->always_noconv(); 88 if (__encoding_ > __limit) 89 __throw_runtime_error("unsupported locale for standard input"); 90 } 91 92 template <class _CharT> 93 typename __stdinbuf<_CharT>::int_type __stdinbuf<_CharT>::underflow() { 94 return __getchar(false); 95 } 96 97 template <class _CharT> 98 typename __stdinbuf<_CharT>::int_type __stdinbuf<_CharT>::uflow() { 99 return __getchar(true); 100 } 101 102 inline bool __do_getc(FILE* __fp, char* __pbuf) { 103 int __c = getc(__fp); 104 if (__c == EOF) 105 return false; 106 *__pbuf = static_cast<char>(__c); 107 return true; 108 } 109 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS 110 inline bool __do_getc(FILE* __fp, wchar_t* __pbuf) { 111 wint_t __c = getwc(__fp); 112 if (__c == WEOF) 113 return false; 114 *__pbuf = static_cast<wchar_t>(__c); 115 return true; 116 } 117 #endif 118 119 inline bool __do_ungetc(int __c, FILE* __fp, char __dummy) { 120 if (ungetc(__c, __fp) == EOF) 121 return false; 122 return true; 123 } 124 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS 125 inline bool __do_ungetc(std::wint_t __c, FILE* __fp, wchar_t __dummy) { 126 if (ungetwc(__c, __fp) == WEOF) 127 return false; 128 return true; 129 } 130 #endif 131 132 template <class _CharT> 133 typename __stdinbuf<_CharT>::int_type __stdinbuf<_CharT>::__getchar(bool __consume) { 134 if (__last_consumed_is_next_) { 135 int_type __result = __last_consumed_; 136 if (__consume) { 137 __last_consumed_ = traits_type::eof(); 138 __last_consumed_is_next_ = false; 139 } 140 return __result; 141 } 142 if (__always_noconv_) { 143 char_type __1buf; 144 if (!__do_getc(__file_, &__1buf)) 145 return traits_type::eof(); 146 if (!__consume) { 147 if (!__do_ungetc(traits_type::to_int_type(__1buf), __file_, __1buf)) 148 return traits_type::eof(); 149 } else 150 __last_consumed_ = traits_type::to_int_type(__1buf); 151 return traits_type::to_int_type(__1buf); 152 } 153 154 char __extbuf[__limit]; 155 int __nread = std::max(1, __encoding_); 156 for (int __i = 0; __i < __nread; ++__i) { 157 int __c = getc(__file_); 158 if (__c == EOF) 159 return traits_type::eof(); 160 __extbuf[__i] = static_cast<char>(__c); 161 } 162 char_type __1buf; 163 const char* __enxt; 164 char_type* __inxt; 165 codecvt_base::result __r; 166 do { 167 state_type __sv_st = *__st_; 168 __r = __cv_->in(*__st_, __extbuf, __extbuf + __nread, __enxt, &__1buf, &__1buf + 1, __inxt); 169 switch (__r) { 170 case std::codecvt_base::ok: 171 break; 172 case codecvt_base::partial: 173 *__st_ = __sv_st; 174 if (__nread == sizeof(__extbuf)) 175 return traits_type::eof(); 176 { 177 int __c = getc(__file_); 178 if (__c == EOF) 179 return traits_type::eof(); 180 __extbuf[__nread] = static_cast<char>(__c); 181 } 182 ++__nread; 183 break; 184 case codecvt_base::error: 185 return traits_type::eof(); 186 case std::codecvt_base::noconv: 187 __1buf = static_cast<char_type>(__extbuf[0]); 188 break; 189 } 190 } while (__r == std::codecvt_base::partial); 191 if (!__consume) { 192 for (int __i = __nread; __i > 0;) { 193 if (ungetc(traits_type::to_int_type(__extbuf[--__i]), __file_) == EOF) 194 return traits_type::eof(); 195 } 196 } else 197 __last_consumed_ = traits_type::to_int_type(__1buf); 198 return traits_type::to_int_type(__1buf); 199 } 200 201 template <class _CharT> 202 typename __stdinbuf<_CharT>::int_type __stdinbuf<_CharT>::pbackfail(int_type __c) { 203 if (traits_type::eq_int_type(__c, traits_type::eof())) { 204 if (!__last_consumed_is_next_) { 205 __c = __last_consumed_; 206 __last_consumed_is_next_ = !traits_type::eq_int_type(__last_consumed_, traits_type::eof()); 207 } 208 return __c; 209 } 210 if (__always_noconv_ && __last_consumed_is_next_) { 211 if (!__do_ungetc(__last_consumed_, __file_, traits_type::to_char_type(__last_consumed_))) 212 return traits_type::eof(); 213 } else if (__last_consumed_is_next_) { 214 char __extbuf[__limit]; 215 char* __enxt; 216 const char_type __ci = traits_type::to_char_type(__last_consumed_); 217 const char_type* __inxt; 218 switch (__cv_->out(*__st_, &__ci, &__ci + 1, __inxt, __extbuf, __extbuf + sizeof(__extbuf), __enxt)) { 219 case std::codecvt_base::ok: 220 break; 221 case std::codecvt_base::noconv: 222 __extbuf[0] = static_cast<char>(__last_consumed_); 223 __enxt = __extbuf + 1; 224 break; 225 case codecvt_base::partial: 226 case codecvt_base::error: 227 return traits_type::eof(); 228 } 229 while (__enxt > __extbuf) 230 if (ungetc(*--__enxt, __file_) == EOF) 231 return traits_type::eof(); 232 } 233 __last_consumed_ = __c; 234 __last_consumed_is_next_ = true; 235 return __c; 236 } 237 238 // __stdoutbuf 239 240 template <class _CharT> 241 class _LIBCPP_HIDDEN __stdoutbuf : public basic_streambuf<_CharT, char_traits<_CharT> > { 242 public: 243 typedef _CharT char_type; 244 typedef char_traits<char_type> traits_type; 245 typedef typename traits_type::int_type int_type; 246 typedef typename traits_type::pos_type pos_type; 247 typedef typename traits_type::off_type off_type; 248 typedef typename traits_type::state_type state_type; 249 250 __stdoutbuf(FILE* __fp, state_type* __st); 251 252 protected: 253 virtual int_type overflow(int_type __c = traits_type::eof()); 254 virtual streamsize xsputn(const char_type* __s, streamsize __n); 255 virtual int sync(); 256 virtual void imbue(const locale& __loc); 257 258 private: 259 FILE* __file_; 260 const codecvt<char_type, char, state_type>* __cv_; 261 state_type* __st_; 262 bool __always_noconv_; 263 264 #if defined(_LIBCPP_WIN32API) 265 static constexpr bool __is_win32api_wide_char = !is_same_v<_CharT, char>; 266 #else 267 static constexpr bool __is_win32api_wide_char = false; 268 #endif 269 270 __stdoutbuf(const __stdoutbuf&); 271 __stdoutbuf& operator=(const __stdoutbuf&); 272 273 _LIBCPP_EXPORTED_FROM_ABI friend FILE* __get_ostream_file(ostream&); 274 }; 275 276 template <class _CharT> 277 __stdoutbuf<_CharT>::__stdoutbuf(FILE* __fp, state_type* __st) 278 : __file_(__fp), 279 __cv_(&use_facet<codecvt<char_type, char, state_type> >(this->getloc())), 280 __st_(__st), 281 __always_noconv_(__cv_->always_noconv()) { 282 // On Windows, in wchar_t mode, ignore the codecvt from the locale by 283 // default and assume noconv; this passes wchar_t through unmodified to 284 // fputwc, which handles it correctly depending on the actual mode of the 285 // output stream. If the user sets a custom locale with imbue(), that 286 // gets honored. 287 if constexpr (__is_win32api_wide_char) 288 __always_noconv_ = true; 289 } 290 291 inline bool __do_fputc(char __c, FILE* __fp) { 292 if (fwrite(&__c, sizeof(__c), 1, __fp) != 1) 293 return false; 294 return true; 295 } 296 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS 297 inline bool __do_fputc(wchar_t __c, FILE* __fp) { 298 // fputwc works regardless of wide/narrow mode of stdout, while 299 // fwrite of wchar_t only works if the stream actually has been set 300 // into wide mode. 301 if (fputwc(__c, __fp) == WEOF) 302 return false; 303 return true; 304 } 305 #endif 306 307 template <class _CharT> 308 typename __stdoutbuf<_CharT>::int_type __stdoutbuf<_CharT>::overflow(int_type __c) { 309 char __extbuf[__limit]; 310 char_type __1buf; 311 if (!traits_type::eq_int_type(__c, traits_type::eof())) { 312 __1buf = traits_type::to_char_type(__c); 313 if (__always_noconv_) { 314 if (!__do_fputc(__1buf, __file_)) 315 return traits_type::eof(); 316 } else { 317 char* __extbe = __extbuf; 318 codecvt_base::result __r; 319 char_type* pbase = &__1buf; 320 char_type* pptr = pbase + 1; 321 do { 322 const char_type* __e; 323 __r = __cv_->out(*__st_, pbase, pptr, __e, __extbuf, __extbuf + sizeof(__extbuf), __extbe); 324 if (__e == pbase) 325 return traits_type::eof(); 326 if (__r == codecvt_base::noconv) { 327 if (fwrite(pbase, 1, 1, __file_) != 1) 328 return traits_type::eof(); 329 } else if (__r == codecvt_base::ok || __r == codecvt_base::partial) { 330 size_t __nmemb = static_cast<size_t>(__extbe - __extbuf); 331 if (fwrite(__extbuf, 1, __nmemb, __file_) != __nmemb) 332 return traits_type::eof(); 333 if (__r == codecvt_base::partial) { 334 pbase = const_cast<char_type*>(__e); 335 } 336 } else 337 return traits_type::eof(); 338 } while (__r == codecvt_base::partial); 339 } 340 } 341 return traits_type::not_eof(__c); 342 } 343 344 template <class _CharT> 345 streamsize __stdoutbuf<_CharT>::xsputn(const char_type* __s, streamsize __n) { 346 // For wchar_t on Windows, don't call fwrite(), but write characters one 347 // at a time with fputwc(); that works both when stdout is in the default 348 // mode and when it is set to Unicode mode. 349 if (__always_noconv_ && !__is_win32api_wide_char) 350 return fwrite(__s, sizeof(char_type), __n, __file_); 351 streamsize __i = 0; 352 for (; __i < __n; ++__i, ++__s) 353 if (overflow(traits_type::to_int_type(*__s)) == traits_type::eof()) 354 break; 355 return __i; 356 } 357 358 template <class _CharT> 359 int __stdoutbuf<_CharT>::sync() { 360 char __extbuf[__limit]; 361 codecvt_base::result __r; 362 do { 363 char* __extbe; 364 __r = __cv_->unshift(*__st_, __extbuf, __extbuf + sizeof(__extbuf), __extbe); 365 size_t __nmemb = static_cast<size_t>(__extbe - __extbuf); 366 if (fwrite(__extbuf, 1, __nmemb, __file_) != __nmemb) 367 return -1; 368 } while (__r == codecvt_base::partial); 369 if (__r == codecvt_base::error) 370 return -1; 371 if (fflush(__file_)) 372 return -1; 373 return 0; 374 } 375 376 template <class _CharT> 377 void __stdoutbuf<_CharT>::imbue(const locale& __loc) { 378 sync(); 379 __cv_ = &use_facet<codecvt<char_type, char, state_type> >(__loc); 380 __always_noconv_ = __cv_->always_noconv(); 381 } 382 383 _LIBCPP_END_NAMESPACE_STD 384 385 _LIBCPP_POP_MACROS 386 387 #endif // _LIBCPP_STD_STREAM_H 388