11#define Py_LIMITED_API 0x030600F0
22#include " Python.h"
3+
34#include < cstdio>
45#include < iostream>
56#include < locale>
2526// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2627// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2728// THE SOFTWARE.
28- template < class _CharT >
29- class stdio_filebuf
30- : public std::basic_streambuf<_CharT, std::char_traits<_CharT>> {
29+
30+ template < class _CharT > class stdio_filebuf : public std ::basic_streambuf<_CharT, std::char_traits<_CharT>>
31+ {
3132public:
32- typedef _CharT char_type;
33- typedef std::char_traits<char_type> traits_type;
34- typedef typename traits_type::int_type int_type;
35- typedef typename traits_type::pos_type pos_type;
36- typedef typename traits_type::off_type off_type;
37- typedef typename traits_type::state_type state_type;
38- explicit stdio_filebuf (FILE *__fp);
39- ~stdio_filebuf () override ;
33+ typedef _CharT char_type;
34+ typedef std::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+ explicit stdio_filebuf (FILE *__fp);
40+ ~stdio_filebuf () override ;
4041
4142protected:
42- virtual int_type underflow () override ;
43- virtual int_type uflow () override ;
44- virtual int_type pbackfail (int_type __c = traits_type::eof()) override ;
45- virtual void imbue (const std::locale &__loc) override ;
43+ virtual int_type underflow () override ;
44+ virtual int_type uflow () override ;
45+ virtual int_type pbackfail (int_type __c = traits_type::eof()) override ;
46+ virtual void imbue (const std::locale &__loc) override ;
4647
4748private:
48- FILE *__file_;
49- const std::codecvt<char_type, char , state_type> *__cv_;
50- state_type __st_;
51- int __encoding_;
52- int_type __last_consumed_;
53- bool __last_consumed_is_next_;
54- bool __always_noconv_;
55- stdio_filebuf (const stdio_filebuf &);
56- stdio_filebuf &operator =(const stdio_filebuf &);
57- int_type __getchar (bool __consume);
58- static const int __limit = 8 ;
49+ FILE *__file_;
50+ const std::codecvt<char_type, char , state_type> *__cv_;
51+ state_type __st_;
52+ int __encoding_;
53+ int_type __last_consumed_;
54+ bool __last_consumed_is_next_;
55+ bool __always_noconv_;
56+ stdio_filebuf (const stdio_filebuf &);
57+ stdio_filebuf &operator =(const stdio_filebuf &);
58+ int_type __getchar (bool __consume);
59+ static const int __limit = 8 ;
5960};
6061template <class _CharT >
61- stdio_filebuf<_CharT>::stdio_filebuf(FILE *__fp)
62- : __file_(__fp), __last_consumed_(traits_type::eof()),
63- __last_consumed_is_next_ (false ) {
64- imbue (this ->getloc ());
65- }
66- template <class _CharT > stdio_filebuf<_CharT>::~stdio_filebuf () {
67- if (__file_)
68- fclose (__file_);
69- }
70- template <class _CharT >
71- void stdio_filebuf<_CharT>::imbue(const std::locale &__loc) {
72- __cv_ = &std::use_facet<std::codecvt<char_type, char , state_type>>(__loc);
73- __encoding_ = __cv_->encoding ();
74- __always_noconv_ = __cv_->always_noconv ();
75- if (__encoding_ > __limit)
76- std::__throw_runtime_error (" unsupported locale for standard io" );
62+ stdio_filebuf<_CharT>::stdio_filebuf(FILE *__fp) : __file_(__fp), __last_consumed_(traits_type::eof()), __last_consumed_is_next_(false )
63+ {
64+ imbue (this ->getloc ());
7765}
78- template <class _CharT >
79- typename stdio_filebuf<_CharT>::int_type stdio_filebuf<_CharT>::underflow() {
80- return __getchar (false );
66+ template <class _CharT > stdio_filebuf<_CharT>::~stdio_filebuf ()
67+ {
68+ if (__file_)
69+ fclose (__file_);
8170}
82- template <class _CharT >
83- typename stdio_filebuf<_CharT>::int_type stdio_filebuf<_CharT>::uflow() {
84- return __getchar (true );
71+ template <class _CharT > void stdio_filebuf<_CharT>::imbue(const std::locale &__loc)
72+ {
73+ __cv_ = &std::use_facet<std::codecvt<char_type, char , state_type>>(__loc);
74+ __encoding_ = __cv_->encoding ();
75+ __always_noconv_ = __cv_->always_noconv ();
76+ if (__encoding_ > __limit)
77+ std::__throw_runtime_error (" unsupported locale for standard io" );
8578}
86- template <class _CharT >
87- typename stdio_filebuf<_CharT>::int_type
88- stdio_filebuf<_CharT>::__getchar(bool __consume) {
89- if (__last_consumed_is_next_) {
90- int_type __result = __last_consumed_;
91- if (__consume) {
92- __last_consumed_ = traits_type::eof ();
93- __last_consumed_is_next_ = false ;
79+ template <class _CharT > typename stdio_filebuf<_CharT>::int_type stdio_filebuf<_CharT>::underflow() { return __getchar (false ); }
80+ template <class _CharT > typename stdio_filebuf<_CharT>::int_type stdio_filebuf<_CharT>::uflow() { return __getchar (true ); }
81+ template <class _CharT > typename stdio_filebuf<_CharT>::int_type stdio_filebuf<_CharT>::__getchar(bool __consume)
82+ {
83+ if (__last_consumed_is_next_) {
84+ int_type __result = __last_consumed_;
85+ if (__consume) {
86+ __last_consumed_ = traits_type::eof ();
87+ __last_consumed_is_next_ = false ;
88+ }
89+ return __result;
9490 }
95- return __result;
96- }
97- char __extbuf[__limit];
98- int __nread = std::max (1 , __encoding_);
99- for (int __i = 0 ; __i < __nread; ++__i) {
100- int __c = getc (__file_);
101- if (__c == EOF)
102- return traits_type::eof ();
103- __extbuf[__i] = static_cast <char >(__c);
104- }
105- char_type __1buf;
106- if (__always_noconv_)
107- __1buf = static_cast <char_type>(__extbuf[0 ]);
108- else {
109- const char *__enxt;
110- char_type *__inxt;
111- std::codecvt_base::result __r;
112- do {
113- state_type __sv_st = __st_;
114- __r = __cv_->in (__st_, __extbuf, __extbuf + __nread, __enxt, &__1buf,
115- &__1buf + 1 , __inxt);
116- switch (__r) {
117- case std::codecvt_base::ok:
118- break ;
119- case std::codecvt_base::partial:
120- __st_ = __sv_st;
121- if (__nread == sizeof (__extbuf))
122- return traits_type::eof ();
123- {
124- int __c = getc (__file_);
125- if (__c == EOF)
91+ char __extbuf[__limit];
92+ int __nread = std::max (1 , __encoding_);
93+ for (int __i = 0 ; __i < __nread; ++__i) {
94+ int __c = getc (__file_);
95+ if (__c == EOF)
12696 return traits_type::eof ();
127- __extbuf[__nread] = static_cast <char >(__c);
128- }
129- ++__nread;
130- break ;
131- case std::codecvt_base::error:
132- return traits_type::eof ();
133- case std::codecvt_base::noconv:
97+ __extbuf[__i] = static_cast <char >(__c);
98+ }
99+ char_type __1buf;
100+ if (__always_noconv_)
134101 __1buf = static_cast <char_type>(__extbuf[0 ]);
135- break ;
136- }
137- } while (__r == std::codecvt_base::partial);
138- }
139- if (!__consume) {
140- for (int __i = __nread; __i > 0 ;) {
141- if (ungetc (traits_type::to_int_type (__extbuf[--__i]), __file_) == EOF)
142- return traits_type::eof ();
102+ else {
103+ const char *__enxt;
104+ char_type *__inxt;
105+ std::codecvt_base::result __r;
106+ do {
107+ state_type __sv_st = __st_;
108+ __r = __cv_->in (__st_, __extbuf, __extbuf + __nread, __enxt, &__1buf, &__1buf + 1 , __inxt);
109+ switch (__r) {
110+ case std::codecvt_base::ok:
111+ break ;
112+ case std::codecvt_base::partial:
113+ __st_ = __sv_st;
114+ if (__nread == sizeof (__extbuf))
115+ return traits_type::eof ();
116+ {
117+ int __c = getc (__file_);
118+ if (__c == EOF)
119+ return traits_type::eof ();
120+ __extbuf[__nread] = static_cast <char >(__c);
121+ }
122+ ++__nread;
123+ break ;
124+ case std::codecvt_base::error:
125+ return traits_type::eof ();
126+ case std::codecvt_base::noconv:
127+ __1buf = static_cast <char_type>(__extbuf[0 ]);
128+ break ;
129+ }
130+ } while (__r == std::codecvt_base::partial);
143131 }
144- } else
145- __last_consumed_ = traits_type::to_int_type (__1buf);
146- return traits_type::to_int_type (__1buf);
132+ if (!__consume) {
133+ for (int __i = __nread; __i > 0 ;) {
134+ if (ungetc (traits_type::to_int_type (__extbuf[--__i]), __file_) == EOF)
135+ return traits_type::eof ();
136+ }
137+ } else
138+ __last_consumed_ = traits_type::to_int_type (__1buf);
139+ return traits_type::to_int_type (__1buf);
147140}
148- template <class _CharT >
149- typename stdio_filebuf<_CharT>::int_type
150- stdio_filebuf<_CharT>::pbackfail(int_type __c) {
151- if (traits_type::eq_int_type (__c, traits_type::eof ()) ) {
152- if (!__last_consumed_is_next_) {
153- __c = __last_consumed_;
154- __last_consumed_is_next_ =
155- ! traits_type::eq_int_type (__last_consumed_, traits_type::eof ()) ;
141+ template <class _CharT > typename stdio_filebuf<_CharT>::int_type stdio_filebuf<_CharT>::pbackfail(int_type __c)
142+ {
143+ if ( traits_type::eq_int_type ( __c, traits_type::eof ()) ) {
144+ if (!__last_consumed_is_next_ ) {
145+ __c = __last_consumed_;
146+ __last_consumed_is_next_ = ! traits_type::eq_int_type ( __last_consumed_, traits_type::eof ()) ;
147+ }
148+ return __c ;
156149 }
157- return __c;
158- }
159- if (__last_consumed_is_next_) {
160- char __extbuf[__limit];
161- char *__enxt;
162- const char_type __ci = traits_type::to_char_type (__last_consumed_);
163- const char_type *__inxt;
164- switch (__cv_->out (__st_, &__ci, &__ci + 1 , __inxt, __extbuf,
165- __extbuf + sizeof (__extbuf), __enxt)) {
166- case std::codecvt_base::ok:
167- break ;
168- case std::codecvt_base::noconv:
169- __extbuf[0 ] = static_cast <char >(__last_consumed_);
170- __enxt = __extbuf + 1 ;
171- break ;
172- case std::codecvt_base::partial:
173- case std::codecvt_base::error:
174- return traits_type::eof ();
150+ if (__last_consumed_is_next_) {
151+ char __extbuf[__limit];
152+ char *__enxt;
153+ const char_type __ci = traits_type::to_char_type (__last_consumed_);
154+ const char_type *__inxt;
155+ switch (__cv_->out (__st_, &__ci, &__ci + 1 , __inxt, __extbuf, __extbuf + sizeof (__extbuf), __enxt)) {
156+ case std::codecvt_base::ok:
157+ break ;
158+ case std::codecvt_base::noconv:
159+ __extbuf[0 ] = static_cast <char >(__last_consumed_);
160+ __enxt = __extbuf + 1 ;
161+ break ;
162+ case std::codecvt_base::partial:
163+ case std::codecvt_base::error:
164+ return traits_type::eof ();
165+ }
166+ while (__enxt > __extbuf)
167+ if (ungetc (*--__enxt, __file_) == EOF)
168+ return traits_type::eof ();
175169 }
176- while (__enxt > __extbuf)
177- if (ungetc (*--__enxt, __file_) == EOF)
178- return traits_type::eof ();
179- }
180- __last_consumed_ = __c;
181- __last_consumed_is_next_ = true ;
182- return __c;
170+ __last_consumed_ = __c;
171+ __last_consumed_is_next_ = true ;
172+ return __c;
183173}
184174
185- struct PyIStream : public std ::istream {
186- PyIStream (PyObject *pyfile) {
175+ typedef std::pair<stdio_filebuf<char > *, FILE *> buffer_pair;
176+ static buffer_pair from_pyobject (PyObject *pyfile)
177+ {
187178 if (pyfile == Py_None) {
188- throw std::runtime_error (" None is not a valid input stream" );
179+ throw std::runtime_error (" None is not a valid input stream" );
189180 }
190181 auto fileno = PyObject_GetAttrString (pyfile, " fileno" );
191182 if (!fileno) {
192- throw std::runtime_error (" Passed object has no fileno() method" );
183+ throw std::runtime_error (" Passed object has no fileno() method" );
193184 }
194- fd = PyObject_AsFileDescriptor (pyfile);
185+
186+ auto fd = PyObject_AsFileDescriptor (pyfile);
195187 if (fd == -1 ) {
196- throw std::runtime_error (" Failed to get file descriptor" );
188+ throw std::runtime_error (" Failed to get file descriptor" );
197189 }
198190
199- f = fdopen (fd, " r" );
191+ auto f = fdopen (fd, " r" );
200192 if (!f) {
201- throw std::runtime_error (" Failed to open input stream" );
193+ throw std::runtime_error (" Failed to open input stream" );
202194 }
203195
204- buf = new stdio_filebuf<char >(f);
196+ return buffer_pair (new stdio_filebuf<char >(f), f);
197+ }
205198
206- init (buf);
207- }
199+ struct PyIStream : public std ::istream {
200+ PyIStream (PyObject *pyfile) : buffers(from_pyobject(pyfile)), std::istream(std::get< 0 >(buffers)) { }
208201
209- ~PyIStream () {
210- if (f) {
211- fclose (f);
212- }
213- if (buf) {
214- free (buf);
202+ ~PyIStream ()
203+ {
204+ FILE *f;
205+ stdio_filebuf<char > *buf;
206+
207+ if ((f = std::get<1 >(buffers))) {
208+ fclose (f);
209+ }
210+ if ((buf = std::get<0 >(buffers))) {
211+ free (buf);
212+ }
215213 }
216- }
217214
218215private:
219- int fd = -1 ;
220- FILE *f = nullptr ;
221- stdio_filebuf<char > *buf = nullptr ;
216+ buffer_pair buffers;
217+ stdio_filebuf<char > *buf = nullptr ;
222218};
0 commit comments