blob: 7dfb0c99bf15cf4a921f3e96b7762b89290ba3ca [file] [log] [blame]
Howard Hinnantbc8d3f92010-05-11 19:42:16 +00001// -*- C++ -*-
2//===----------------------------------------------------------------------===//
3//
Howard Hinnantf5256e12010-05-11 21:36:01 +00004// The LLVM Compiler Infrastructure
Howard Hinnantbc8d3f92010-05-11 19:42:16 +00005//
Howard Hinnantb64f8b02010-11-16 22:09:02 +00006// This file is dual licensed under the MIT and the University of Illinois Open
7// Source Licenses. See LICENSE.TXT for details.
Howard Hinnantbc8d3f92010-05-11 19:42:16 +00008//
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];
Howard Hinnant6cf5d8c2011-02-14 19:12:38 +0000100 int __nread = _STD::max(1, __encoding_);
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000101 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 _STD::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 _STD::codecvt_base::noconv:
140 __1buf = static_cast<char_type>(__extbuf[0]);
141 break;
142 }
143 } while (__r == _STD::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 _STD::codecvt_base::ok:
170 break;
171 case _STD::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();
Howard Hinnantf5256e12010-05-11 21:36:01 +0000182 return traits_type::not_eof(__c);
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000183}
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