diff options
Diffstat (limited to 'python/pyfstream.h')
-rw-r--r-- | python/pyfstream.h | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/python/pyfstream.h b/python/pyfstream.h new file mode 100644 index 00000000..1d72d471 --- /dev/null +++ b/python/pyfstream.h @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2003-2008, John Wiegley. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of New Artisans LLC nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PYFSTREAM_H +#define _PYFSTREAM_H + +// pyofstream +// - a stream that writes on a Python file object + +class pyoutbuf : public boost::noncopyable, public std::streambuf +{ + pyoutbf(); + +protected: + PyFileObject * fo; // Python file object + +public: + // constructor + pyoutbuf(PyFileObject * _fo) : fo(_fo) { + TRACE_CTOR(pyoutbuf, "PyFileObject *"); + } + ~pyoutbuf() : throw() { + TRACE_DTOR(pyoutbuf); + } + +protected: + // write one character + virtual int_type overflow (int_type c) { + if (c != EOF) { + char z[2]; + z[0] = c; + z[1] = '\0'; + if (PyFile_WriteString(z, (PyObject *)fo) < 0) { + return EOF; + } + } + return c; + } + + // write multiple characters + virtual std::streamsize xsputn (const char* s, std::streamsize num) { + char * buf = new char[num + 1]; + std::strncpy(buf, s, num); + buf[num] = '\0'; + if (PyFile_WriteString(buf, (PyObject *)fo) < 0) + num = 0; + checked_array_delete(buf); + return num; + } +}; + +class pyofstream : public noncopyable, public std::ostream +{ + pyofstream(); + +protected: + pyoutbuf buf; + +public: + pyofstream (PyFileObject * fo) : std::ostream(0), buf(fo) { + TRACE_CTOR(pyofstream, "PyFileObject *"); + rdbuf(&buf); + } + ~pyofstream() throw() { + TRACE_DTOR(pyofstream); + } +}; + +// pyifstream +// - a stream that reads on a file descriptor + +class pyinbuf : public noncopyable, public std::streambuf +{ + pyinbuf(); + +protected: + PyFileObject * fo; // Python file object + +protected: + /* data buffer: + * - at most, pbSize characters in putback area plus + * - at most, bufSize characters in ordinary read buffer + */ + static const int pbSize = 4; // size of putback area + static const int bufSize = 1024; // size of the data buffer + char buffer[bufSize + pbSize]; // data buffer + +public: + /* constructor + * - initialize file descriptor + * - initialize empty data buffer + * - no putback area + * => force underflow() + */ + pyinbuf (PyFileObject * _fo) : fo(_fo) { + TRACE_CTOR(pyinbuf, "PyFileObject *"); + + setg (buffer+pbSize, // beginning of putback area + buffer+pbSize, // read position + buffer+pbSize); // end position + } + ~pyinbuf() throw() { + TRACE_DTOR(pyinbuf); + } + +protected: + // insert new characters into the buffer + virtual int_type underflow () { +#ifndef _MSC_VER + using std::memmove; +#endif + + // is read position before end of buffer? + if (gptr() < egptr()) { + return traits_type::to_int_type(*gptr()); + } + + /* process size of putback area + * - use number of characters read + * - but at most size of putback area + */ + int numPutback; + numPutback = gptr() - eback(); + if (numPutback > pbSize) { + numPutback = pbSize; + } + + /* copy up to pbSize characters previously read into + * the putback area + */ + memmove (buffer+(pbSize-numPutback), gptr()-numPutback, + numPutback); + + // read at most bufSize new characters + int num; + PyObject *line = PyFile_GetLine((PyObject *)fo, bufSize); + if (! line || ! PyString_Check(line)) { + // ERROR or EOF + return EOF; + } + + num = PyString_Size(line); + if (num == 0) + return EOF; + + memmove (buffer+pbSize, PyString_AsString(line), num); + + // reset buffer pointers + setg (buffer+(pbSize-numPutback), // beginning of putback area + buffer+pbSize, // read position + buffer+pbSize+num); // end of buffer + + // return next character + return traits_type::to_int_type(*gptr()); + } +}; + +class pyifstream : public noncopyable, public std::istream +{ + pyifstream(); + +protected: + pyinbuf buf; + +public: + pyifstream (PyFileObject * fo) : std::istream(0), buf(fo) { + TRACE_CTOR(pyifstream, "PyFileObject *"); + rdbuf(&buf); + } + ~pyifstream() throw() { + TRACE_DTOR(pyifstream); + } +}; + +#endif // _PYFSTREAM_H |