|  | /* | 
|  | An implementation of the I/O abstract base classes hierarchy | 
|  | as defined by PEP 3116 - "New I/O" | 
|  |  | 
|  | Classes defined here: IOBase, RawIOBase. | 
|  |  | 
|  | Written by Amaury Forgeot d'Arc and Antoine Pitrou | 
|  | */ | 
|  |  | 
|  |  | 
|  | #define PY_SSIZE_T_CLEAN | 
|  | #include "Python.h" | 
|  | #include "pycore_long.h"          // _PyLong_GetOne() | 
|  | #include "pycore_object.h" | 
|  | #include <stddef.h>               // offsetof() | 
|  | #include "_iomodule.h" | 
|  |  | 
|  | /*[clinic input] | 
|  | module _io | 
|  | class _io._IOBase "PyObject *" "&PyIOBase_Type" | 
|  | class _io._RawIOBase "PyObject *" "&PyRawIOBase_Type" | 
|  | [clinic start generated code]*/ | 
|  | /*[clinic end generated code: output=da39a3ee5e6b4b0d input=d29a4d076c2b211c]*/ | 
|  |  | 
|  | /* | 
|  | * IOBase class, an abstract class | 
|  | */ | 
|  |  | 
|  | typedef struct { | 
|  | PyObject_HEAD | 
|  |  | 
|  | PyObject *dict; | 
|  | PyObject *weakreflist; | 
|  | } iobase; | 
|  |  | 
|  | PyDoc_STRVAR(iobase_doc, | 
|  | "The abstract base class for all I/O classes.\n" | 
|  | "\n" | 
|  | "This class provides dummy implementations for many methods that\n" | 
|  | "derived classes can override selectively; the default implementations\n" | 
|  | "represent a file that cannot be read, written or seeked.\n" | 
|  | "\n" | 
|  | "Even though IOBase does not declare read, readinto, or write because\n" | 
|  | "their signatures will vary, implementations and clients should\n" | 
|  | "consider those methods part of the interface. Also, implementations\n" | 
|  | "may raise UnsupportedOperation when operations they do not support are\n" | 
|  | "called.\n" | 
|  | "\n" | 
|  | "The basic type used for binary data read from or written to a file is\n" | 
|  | "bytes. Other bytes-like objects are accepted as method arguments too.\n" | 
|  | "In some cases (such as readinto), a writable object is required. Text\n" | 
|  | "I/O classes work with str data.\n" | 
|  | "\n" | 
|  | "Note that calling any method (except additional calls to close(),\n" | 
|  | "which are ignored) on a closed stream should raise a ValueError.\n" | 
|  | "\n" | 
|  | "IOBase (and its subclasses) support the iterator protocol, meaning\n" | 
|  | "that an IOBase object can be iterated over yielding the lines in a\n" | 
|  | "stream.\n" | 
|  | "\n" | 
|  | "IOBase also supports the :keyword:`with` statement. In this example,\n" | 
|  | "fp is closed after the suite of the with statement is complete:\n" | 
|  | "\n" | 
|  | "with open('spam.txt', 'r') as fp:\n" | 
|  | "    fp.write('Spam and eggs!')\n"); | 
|  |  | 
|  | /* Use this macro whenever you want to check the internal `closed` status | 
|  | of the IOBase object rather than the virtual `closed` attribute as returned | 
|  | by whatever subclass. */ | 
|  |  | 
|  |  | 
|  | /* Internal methods */ | 
|  | static PyObject * | 
|  | iobase_unsupported(const char *message) | 
|  | { | 
|  | _PyIO_State *state = IO_STATE(); | 
|  | if (state != NULL) | 
|  | PyErr_SetString(state->unsupported_operation, message); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | /* Positioning */ | 
|  |  | 
|  | PyDoc_STRVAR(iobase_seek_doc, | 
|  | "Change stream position.\n" | 
|  | "\n" | 
|  | "Change the stream position to the given byte offset. The offset is\n" | 
|  | "interpreted relative to the position indicated by whence.  Values\n" | 
|  | "for whence are:\n" | 
|  | "\n" | 
|  | "* 0 -- start of stream (the default); offset should be zero or positive\n" | 
|  | "* 1 -- current stream position; offset may be negative\n" | 
|  | "* 2 -- end of stream; offset is usually negative\n" | 
|  | "\n" | 
|  | "Return the new absolute position."); | 
|  |  | 
|  | static PyObject * | 
|  | iobase_seek(PyObject *self, PyObject *args) | 
|  | { | 
|  | return iobase_unsupported("seek"); | 
|  | } | 
|  |  | 
|  | /*[clinic input] | 
|  | _io._IOBase.tell | 
|  |  | 
|  | Return current stream position. | 
|  | [clinic start generated code]*/ | 
|  |  | 
|  | static PyObject * | 
|  | _io__IOBase_tell_impl(PyObject *self) | 
|  | /*[clinic end generated code: output=89a1c0807935abe2 input=04e615fec128801f]*/ | 
|  | { | 
|  | return _PyObject_CallMethod(self, &_Py_ID(seek), "ii", 0, 1); | 
|  | } | 
|  |  | 
|  | PyDoc_STRVAR(iobase_truncate_doc, | 
|  | "Truncate file to size bytes.\n" | 
|  | "\n" | 
|  | "File pointer is left unchanged.  Size defaults to the current IO\n" | 
|  | "position as reported by tell().  Returns the new size."); | 
|  |  | 
|  | static PyObject * | 
|  | iobase_truncate(PyObject *self, PyObject *args) | 
|  | { | 
|  | return iobase_unsupported("truncate"); | 
|  | } | 
|  |  | 
|  | static int | 
|  | iobase_is_closed(PyObject *self) | 
|  | { | 
|  | PyObject *res; | 
|  | int ret; | 
|  | /* This gets the derived attribute, which is *not* __IOBase_closed | 
|  | in most cases! */ | 
|  | ret = _PyObject_LookupAttr(self, &_Py_ID(__IOBase_closed), &res); | 
|  | Py_XDECREF(res); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /* Flush and close methods */ | 
|  |  | 
|  | /*[clinic input] | 
|  | _io._IOBase.flush | 
|  |  | 
|  | Flush write buffers, if applicable. | 
|  |  | 
|  | This is not implemented for read-only and non-blocking streams. | 
|  | [clinic start generated code]*/ | 
|  |  | 
|  | static PyObject * | 
|  | _io__IOBase_flush_impl(PyObject *self) | 
|  | /*[clinic end generated code: output=7cef4b4d54656a3b input=773be121abe270aa]*/ | 
|  | { | 
|  | /* XXX Should this return the number of bytes written??? */ | 
|  | int closed = iobase_is_closed(self); | 
|  |  | 
|  | if (!closed) { | 
|  | Py_RETURN_NONE; | 
|  | } | 
|  | if (closed > 0) { | 
|  | PyErr_SetString(PyExc_ValueError, "I/O operation on closed file."); | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | static PyObject * | 
|  | iobase_closed_get(PyObject *self, void *context) | 
|  | { | 
|  | int closed = iobase_is_closed(self); | 
|  | if (closed < 0) { | 
|  | return NULL; | 
|  | } | 
|  | return PyBool_FromLong(closed); | 
|  | } | 
|  |  | 
|  | static int | 
|  | iobase_check_closed(PyObject *self) | 
|  | { | 
|  | PyObject *res; | 
|  | int closed; | 
|  | /* This gets the derived attribute, which is *not* __IOBase_closed | 
|  | in most cases! */ | 
|  | closed = _PyObject_LookupAttr(self, &_Py_ID(closed), &res); | 
|  | if (closed > 0) { | 
|  | closed = PyObject_IsTrue(res); | 
|  | Py_DECREF(res); | 
|  | if (closed > 0) { | 
|  | PyErr_SetString(PyExc_ValueError, "I/O operation on closed file."); | 
|  | return -1; | 
|  | } | 
|  | } | 
|  | return closed; | 
|  | } | 
|  |  | 
|  | PyObject * | 
|  | _PyIOBase_check_closed(PyObject *self, PyObject *args) | 
|  | { | 
|  | if (iobase_check_closed(self)) { | 
|  | return NULL; | 
|  | } | 
|  | if (args == Py_True) { | 
|  | return Py_None; | 
|  | } | 
|  | Py_RETURN_NONE; | 
|  | } | 
|  |  | 
|  | /* XXX: IOBase thinks it has to maintain its own internal state in | 
|  | `__IOBase_closed` and call flush() by itself, but it is redundant with | 
|  | whatever behaviour a non-trivial derived class will implement. */ | 
|  |  | 
|  | /*[clinic input] | 
|  | _io._IOBase.close | 
|  |  | 
|  | Flush and close the IO object. | 
|  |  | 
|  | This method has no effect if the file is already closed. | 
|  | [clinic start generated code]*/ | 
|  |  | 
|  | static PyObject * | 
|  | _io__IOBase_close_impl(PyObject *self) | 
|  | /*[clinic end generated code: output=63c6a6f57d783d6d input=f4494d5c31dbc6b7]*/ | 
|  | { | 
|  | PyObject *res, *exc, *val, *tb; | 
|  | int rc, closed = iobase_is_closed(self); | 
|  |  | 
|  | if (closed < 0) { | 
|  | return NULL; | 
|  | } | 
|  | if (closed) { | 
|  | Py_RETURN_NONE; | 
|  | } | 
|  |  | 
|  | res = PyObject_CallMethodNoArgs(self, &_Py_ID(flush)); | 
|  |  | 
|  | PyErr_Fetch(&exc, &val, &tb); | 
|  | rc = PyObject_SetAttr(self, &_Py_ID(__IOBase_closed), Py_True); | 
|  | _PyErr_ChainExceptions(exc, val, tb); | 
|  | if (rc < 0) { | 
|  | Py_CLEAR(res); | 
|  | } | 
|  |  | 
|  | if (res == NULL) | 
|  | return NULL; | 
|  |  | 
|  | Py_DECREF(res); | 
|  | Py_RETURN_NONE; | 
|  | } | 
|  |  | 
|  | /* Finalization and garbage collection support */ | 
|  |  | 
|  | static void | 
|  | iobase_finalize(PyObject *self) | 
|  | { | 
|  | PyObject *res; | 
|  | PyObject *error_type, *error_value, *error_traceback; | 
|  | int closed; | 
|  |  | 
|  | /* Save the current exception, if any. */ | 
|  | PyErr_Fetch(&error_type, &error_value, &error_traceback); | 
|  |  | 
|  | /* If `closed` doesn't exist or can't be evaluated as bool, then the | 
|  | object is probably in an unusable state, so ignore. */ | 
|  | if (_PyObject_LookupAttr(self, &_Py_ID(closed), &res) <= 0) { | 
|  | PyErr_Clear(); | 
|  | closed = -1; | 
|  | } | 
|  | else { | 
|  | closed = PyObject_IsTrue(res); | 
|  | Py_DECREF(res); | 
|  | if (closed == -1) | 
|  | PyErr_Clear(); | 
|  | } | 
|  | if (closed == 0) { | 
|  | /* Signal close() that it was called as part of the object | 
|  | finalization process. */ | 
|  | if (PyObject_SetAttr(self, &_Py_ID(_finalizing), Py_True)) | 
|  | PyErr_Clear(); | 
|  | res = PyObject_CallMethodNoArgs((PyObject *)self, &_Py_ID(close)); | 
|  | /* Silencing I/O errors is bad, but printing spurious tracebacks is | 
|  | equally as bad, and potentially more frequent (because of | 
|  | shutdown issues). */ | 
|  | if (res == NULL) { | 
|  | #ifndef Py_DEBUG | 
|  | if (_Py_GetConfig()->dev_mode) { | 
|  | PyErr_WriteUnraisable(self); | 
|  | } | 
|  | else { | 
|  | PyErr_Clear(); | 
|  | } | 
|  | #else | 
|  | PyErr_WriteUnraisable(self); | 
|  | #endif | 
|  | } | 
|  | else { | 
|  | Py_DECREF(res); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Restore the saved exception. */ | 
|  | PyErr_Restore(error_type, error_value, error_traceback); | 
|  | } | 
|  |  | 
|  | int | 
|  | _PyIOBase_finalize(PyObject *self) | 
|  | { | 
|  | int is_zombie; | 
|  |  | 
|  | /* If _PyIOBase_finalize() is called from a destructor, we need to | 
|  | resurrect the object as calling close() can invoke arbitrary code. */ | 
|  | is_zombie = (Py_REFCNT(self) == 0); | 
|  | if (is_zombie) | 
|  | return PyObject_CallFinalizerFromDealloc(self); | 
|  | else { | 
|  | PyObject_CallFinalizer(self); | 
|  | return 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | static int | 
|  | iobase_traverse(iobase *self, visitproc visit, void *arg) | 
|  | { | 
|  | Py_VISIT(self->dict); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int | 
|  | iobase_clear(iobase *self) | 
|  | { | 
|  | Py_CLEAR(self->dict); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Destructor */ | 
|  |  | 
|  | static void | 
|  | iobase_dealloc(iobase *self) | 
|  | { | 
|  | /* NOTE: since IOBaseObject has its own dict, Python-defined attributes | 
|  | are still available here for close() to use. | 
|  | However, if the derived class declares a __slots__, those slots are | 
|  | already gone. | 
|  | */ | 
|  | if (_PyIOBase_finalize((PyObject *) self) < 0) { | 
|  | /* When called from a heap type's dealloc, the type will be | 
|  | decref'ed on return (see e.g. subtype_dealloc in typeobject.c). */ | 
|  | if (_PyType_HasFeature(Py_TYPE(self), Py_TPFLAGS_HEAPTYPE)) { | 
|  | Py_INCREF(Py_TYPE(self)); | 
|  | } | 
|  | return; | 
|  | } | 
|  | _PyObject_GC_UNTRACK(self); | 
|  | if (self->weakreflist != NULL) | 
|  | PyObject_ClearWeakRefs((PyObject *) self); | 
|  | Py_CLEAR(self->dict); | 
|  | Py_TYPE(self)->tp_free((PyObject *) self); | 
|  | } | 
|  |  | 
|  | /* Inquiry methods */ | 
|  |  | 
|  | /*[clinic input] | 
|  | _io._IOBase.seekable | 
|  |  | 
|  | Return whether object supports random access. | 
|  |  | 
|  | If False, seek(), tell() and truncate() will raise OSError. | 
|  | This method may need to do a test seek(). | 
|  | [clinic start generated code]*/ | 
|  |  | 
|  | static PyObject * | 
|  | _io__IOBase_seekable_impl(PyObject *self) | 
|  | /*[clinic end generated code: output=4c24c67f5f32a43d input=b976622f7fdf3063]*/ | 
|  | { | 
|  | Py_RETURN_FALSE; | 
|  | } | 
|  |  | 
|  | PyObject * | 
|  | _PyIOBase_check_seekable(PyObject *self, PyObject *args) | 
|  | { | 
|  | PyObject *res  = PyObject_CallMethodNoArgs(self, &_Py_ID(seekable)); | 
|  | if (res == NULL) | 
|  | return NULL; | 
|  | if (res != Py_True) { | 
|  | Py_CLEAR(res); | 
|  | iobase_unsupported("File or stream is not seekable."); | 
|  | return NULL; | 
|  | } | 
|  | if (args == Py_True) { | 
|  | Py_DECREF(res); | 
|  | } | 
|  | return res; | 
|  | } | 
|  |  | 
|  | /*[clinic input] | 
|  | _io._IOBase.readable | 
|  |  | 
|  | Return whether object was opened for reading. | 
|  |  | 
|  | If False, read() will raise OSError. | 
|  | [clinic start generated code]*/ | 
|  |  | 
|  | static PyObject * | 
|  | _io__IOBase_readable_impl(PyObject *self) | 
|  | /*[clinic end generated code: output=e48089250686388b input=285b3b866a0ec35f]*/ | 
|  | { | 
|  | Py_RETURN_FALSE; | 
|  | } | 
|  |  | 
|  | /* May be called with any object */ | 
|  | PyObject * | 
|  | _PyIOBase_check_readable(PyObject *self, PyObject *args) | 
|  | { | 
|  | PyObject *res = PyObject_CallMethodNoArgs(self, &_Py_ID(readable)); | 
|  | if (res == NULL) | 
|  | return NULL; | 
|  | if (res != Py_True) { | 
|  | Py_CLEAR(res); | 
|  | iobase_unsupported("File or stream is not readable."); | 
|  | return NULL; | 
|  | } | 
|  | if (args == Py_True) { | 
|  | Py_DECREF(res); | 
|  | } | 
|  | return res; | 
|  | } | 
|  |  | 
|  | /*[clinic input] | 
|  | _io._IOBase.writable | 
|  |  | 
|  | Return whether object was opened for writing. | 
|  |  | 
|  | If False, write() will raise OSError. | 
|  | [clinic start generated code]*/ | 
|  |  | 
|  | static PyObject * | 
|  | _io__IOBase_writable_impl(PyObject *self) | 
|  | /*[clinic end generated code: output=406001d0985be14f input=9dcac18a013a05b5]*/ | 
|  | { | 
|  | Py_RETURN_FALSE; | 
|  | } | 
|  |  | 
|  | /* May be called with any object */ | 
|  | PyObject * | 
|  | _PyIOBase_check_writable(PyObject *self, PyObject *args) | 
|  | { | 
|  | PyObject *res = PyObject_CallMethodNoArgs(self, &_Py_ID(writable)); | 
|  | if (res == NULL) | 
|  | return NULL; | 
|  | if (res != Py_True) { | 
|  | Py_CLEAR(res); | 
|  | iobase_unsupported("File or stream is not writable."); | 
|  | return NULL; | 
|  | } | 
|  | if (args == Py_True) { | 
|  | Py_DECREF(res); | 
|  | } | 
|  | return res; | 
|  | } | 
|  |  | 
|  | /* Context manager */ | 
|  |  | 
|  | static PyObject * | 
|  | iobase_enter(PyObject *self, PyObject *args) | 
|  | { | 
|  | if (iobase_check_closed(self)) | 
|  | return NULL; | 
|  |  | 
|  | return Py_NewRef(self); | 
|  | } | 
|  |  | 
|  | static PyObject * | 
|  | iobase_exit(PyObject *self, PyObject *args) | 
|  | { | 
|  | return PyObject_CallMethodNoArgs(self, &_Py_ID(close)); | 
|  | } | 
|  |  | 
|  | /* Lower-level APIs */ | 
|  |  | 
|  | /* XXX Should these be present even if unimplemented? */ | 
|  |  | 
|  | /*[clinic input] | 
|  | _io._IOBase.fileno | 
|  |  | 
|  | Returns underlying file descriptor if one exists. | 
|  |  | 
|  | OSError is raised if the IO object does not use a file descriptor. | 
|  | [clinic start generated code]*/ | 
|  |  | 
|  | static PyObject * | 
|  | _io__IOBase_fileno_impl(PyObject *self) | 
|  | /*[clinic end generated code: output=7cc0973f0f5f3b73 input=4e37028947dc1cc8]*/ | 
|  | { | 
|  | return iobase_unsupported("fileno"); | 
|  | } | 
|  |  | 
|  | /*[clinic input] | 
|  | _io._IOBase.isatty | 
|  |  | 
|  | Return whether this is an 'interactive' stream. | 
|  |  | 
|  | Return False if it can't be determined. | 
|  | [clinic start generated code]*/ | 
|  |  | 
|  | static PyObject * | 
|  | _io__IOBase_isatty_impl(PyObject *self) | 
|  | /*[clinic end generated code: output=60cab77cede41cdd input=9ef76530d368458b]*/ | 
|  | { | 
|  | if (iobase_check_closed(self)) | 
|  | return NULL; | 
|  | Py_RETURN_FALSE; | 
|  | } | 
|  |  | 
|  | /* Readline(s) and writelines */ | 
|  |  | 
|  | /*[clinic input] | 
|  | _io._IOBase.readline | 
|  | size as limit: Py_ssize_t(accept={int, NoneType}) = -1 | 
|  | / | 
|  |  | 
|  | Read and return a line from the stream. | 
|  |  | 
|  | If size is specified, at most size bytes will be read. | 
|  |  | 
|  | The line terminator is always b'\n' for binary files; for text | 
|  | files, the newlines argument to open can be used to select the line | 
|  | terminator(s) recognized. | 
|  | [clinic start generated code]*/ | 
|  |  | 
|  | static PyObject * | 
|  | _io__IOBase_readline_impl(PyObject *self, Py_ssize_t limit) | 
|  | /*[clinic end generated code: output=4479f79b58187840 input=d0c596794e877bff]*/ | 
|  | { | 
|  | /* For backwards compatibility, a (slowish) readline(). */ | 
|  |  | 
|  | PyObject *peek, *buffer, *result; | 
|  | Py_ssize_t old_size = -1; | 
|  |  | 
|  | if (_PyObject_LookupAttr(self, &_Py_ID(peek), &peek) < 0) { | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | buffer = PyByteArray_FromStringAndSize(NULL, 0); | 
|  | if (buffer == NULL) { | 
|  | Py_XDECREF(peek); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | while (limit < 0 || PyByteArray_GET_SIZE(buffer) < limit) { | 
|  | Py_ssize_t nreadahead = 1; | 
|  | PyObject *b; | 
|  |  | 
|  | if (peek != NULL) { | 
|  | PyObject *readahead = PyObject_CallOneArg(peek, _PyLong_GetOne()); | 
|  | if (readahead == NULL) { | 
|  | /* NOTE: PyErr_SetFromErrno() calls PyErr_CheckSignals() | 
|  | when EINTR occurs so we needn't do it ourselves. */ | 
|  | if (_PyIO_trap_eintr()) { | 
|  | continue; | 
|  | } | 
|  | goto fail; | 
|  | } | 
|  | if (!PyBytes_Check(readahead)) { | 
|  | PyErr_Format(PyExc_OSError, | 
|  | "peek() should have returned a bytes object, " | 
|  | "not '%.200s'", Py_TYPE(readahead)->tp_name); | 
|  | Py_DECREF(readahead); | 
|  | goto fail; | 
|  | } | 
|  | if (PyBytes_GET_SIZE(readahead) > 0) { | 
|  | Py_ssize_t n = 0; | 
|  | const char *buf = PyBytes_AS_STRING(readahead); | 
|  | if (limit >= 0) { | 
|  | do { | 
|  | if (n >= PyBytes_GET_SIZE(readahead) || n >= limit) | 
|  | break; | 
|  | if (buf[n++] == '\n') | 
|  | break; | 
|  | } while (1); | 
|  | } | 
|  | else { | 
|  | do { | 
|  | if (n >= PyBytes_GET_SIZE(readahead)) | 
|  | break; | 
|  | if (buf[n++] == '\n') | 
|  | break; | 
|  | } while (1); | 
|  | } | 
|  | nreadahead = n; | 
|  | } | 
|  | Py_DECREF(readahead); | 
|  | } | 
|  |  | 
|  | b = _PyObject_CallMethod(self, &_Py_ID(read), "n", nreadahead); | 
|  | if (b == NULL) { | 
|  | /* NOTE: PyErr_SetFromErrno() calls PyErr_CheckSignals() | 
|  | when EINTR occurs so we needn't do it ourselves. */ | 
|  | if (_PyIO_trap_eintr()) { | 
|  | continue; | 
|  | } | 
|  | goto fail; | 
|  | } | 
|  | if (!PyBytes_Check(b)) { | 
|  | PyErr_Format(PyExc_OSError, | 
|  | "read() should have returned a bytes object, " | 
|  | "not '%.200s'", Py_TYPE(b)->tp_name); | 
|  | Py_DECREF(b); | 
|  | goto fail; | 
|  | } | 
|  | if (PyBytes_GET_SIZE(b) == 0) { | 
|  | Py_DECREF(b); | 
|  | break; | 
|  | } | 
|  |  | 
|  | old_size = PyByteArray_GET_SIZE(buffer); | 
|  | if (PyByteArray_Resize(buffer, old_size + PyBytes_GET_SIZE(b)) < 0) { | 
|  | Py_DECREF(b); | 
|  | goto fail; | 
|  | } | 
|  | memcpy(PyByteArray_AS_STRING(buffer) + old_size, | 
|  | PyBytes_AS_STRING(b), PyBytes_GET_SIZE(b)); | 
|  |  | 
|  | Py_DECREF(b); | 
|  |  | 
|  | if (PyByteArray_AS_STRING(buffer)[PyByteArray_GET_SIZE(buffer) - 1] == '\n') | 
|  | break; | 
|  | } | 
|  |  | 
|  | result = PyBytes_FromStringAndSize(PyByteArray_AS_STRING(buffer), | 
|  | PyByteArray_GET_SIZE(buffer)); | 
|  | Py_XDECREF(peek); | 
|  | Py_DECREF(buffer); | 
|  | return result; | 
|  | fail: | 
|  | Py_XDECREF(peek); | 
|  | Py_DECREF(buffer); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | static PyObject * | 
|  | iobase_iter(PyObject *self) | 
|  | { | 
|  | if (iobase_check_closed(self)) | 
|  | return NULL; | 
|  |  | 
|  | return Py_NewRef(self); | 
|  | } | 
|  |  | 
|  | static PyObject * | 
|  | iobase_iternext(PyObject *self) | 
|  | { | 
|  | PyObject *line = PyObject_CallMethodNoArgs(self, &_Py_ID(readline)); | 
|  |  | 
|  | if (line == NULL) | 
|  | return NULL; | 
|  |  | 
|  | if (PyObject_Size(line) <= 0) { | 
|  | /* Error or empty */ | 
|  | Py_DECREF(line); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | return line; | 
|  | } | 
|  |  | 
|  | /*[clinic input] | 
|  | _io._IOBase.readlines | 
|  | hint: Py_ssize_t(accept={int, NoneType}) = -1 | 
|  | / | 
|  |  | 
|  | Return a list of lines from the stream. | 
|  |  | 
|  | hint can be specified to control the number of lines read: no more | 
|  | lines will be read if the total size (in bytes/characters) of all | 
|  | lines so far exceeds hint. | 
|  | [clinic start generated code]*/ | 
|  |  | 
|  | static PyObject * | 
|  | _io__IOBase_readlines_impl(PyObject *self, Py_ssize_t hint) | 
|  | /*[clinic end generated code: output=2f50421677fa3dea input=9400c786ea9dc416]*/ | 
|  | { | 
|  | Py_ssize_t length = 0; | 
|  | PyObject *result, *it = NULL; | 
|  |  | 
|  | result = PyList_New(0); | 
|  | if (result == NULL) | 
|  | return NULL; | 
|  |  | 
|  | if (hint <= 0) { | 
|  | /* XXX special-casing this made sense in the Python version in order | 
|  | to remove the bytecode interpretation overhead, but it could | 
|  | probably be removed here. */ | 
|  | PyObject *ret = PyObject_CallMethodObjArgs(result, &_Py_ID(extend), | 
|  | self, NULL); | 
|  | if (ret == NULL) { | 
|  | goto error; | 
|  | } | 
|  | Py_DECREF(ret); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | it = PyObject_GetIter(self); | 
|  | if (it == NULL) { | 
|  | goto error; | 
|  | } | 
|  |  | 
|  | while (1) { | 
|  | Py_ssize_t line_length; | 
|  | PyObject *line = PyIter_Next(it); | 
|  | if (line == NULL) { | 
|  | if (PyErr_Occurred()) { | 
|  | goto error; | 
|  | } | 
|  | else | 
|  | break; /* StopIteration raised */ | 
|  | } | 
|  |  | 
|  | if (PyList_Append(result, line) < 0) { | 
|  | Py_DECREF(line); | 
|  | goto error; | 
|  | } | 
|  | line_length = PyObject_Size(line); | 
|  | Py_DECREF(line); | 
|  | if (line_length < 0) { | 
|  | goto error; | 
|  | } | 
|  | if (line_length > hint - length) | 
|  | break; | 
|  | length += line_length; | 
|  | } | 
|  |  | 
|  | Py_DECREF(it); | 
|  | return result; | 
|  |  | 
|  | error: | 
|  | Py_XDECREF(it); | 
|  | Py_DECREF(result); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | /*[clinic input] | 
|  | _io._IOBase.writelines | 
|  | lines: object | 
|  | / | 
|  |  | 
|  | Write a list of lines to stream. | 
|  |  | 
|  | Line separators are not added, so it is usual for each of the | 
|  | lines provided to have a line separator at the end. | 
|  | [clinic start generated code]*/ | 
|  |  | 
|  | static PyObject * | 
|  | _io__IOBase_writelines(PyObject *self, PyObject *lines) | 
|  | /*[clinic end generated code: output=976eb0a9b60a6628 input=cac3fc8864183359]*/ | 
|  | { | 
|  | PyObject *iter, *res; | 
|  |  | 
|  | if (iobase_check_closed(self)) | 
|  | return NULL; | 
|  |  | 
|  | iter = PyObject_GetIter(lines); | 
|  | if (iter == NULL) | 
|  | return NULL; | 
|  |  | 
|  | while (1) { | 
|  | PyObject *line = PyIter_Next(iter); | 
|  | if (line == NULL) { | 
|  | if (PyErr_Occurred()) { | 
|  | Py_DECREF(iter); | 
|  | return NULL; | 
|  | } | 
|  | else | 
|  | break; /* Stop Iteration */ | 
|  | } | 
|  |  | 
|  | res = NULL; | 
|  | do { | 
|  | res = PyObject_CallMethodObjArgs(self, &_Py_ID(write), line, NULL); | 
|  | } while (res == NULL && _PyIO_trap_eintr()); | 
|  | Py_DECREF(line); | 
|  | if (res == NULL) { | 
|  | Py_DECREF(iter); | 
|  | return NULL; | 
|  | } | 
|  | Py_DECREF(res); | 
|  | } | 
|  | Py_DECREF(iter); | 
|  | Py_RETURN_NONE; | 
|  | } | 
|  |  | 
|  | #include "clinic/iobase.c.h" | 
|  |  | 
|  | static PyMethodDef iobase_methods[] = { | 
|  | {"seek", iobase_seek, METH_VARARGS, iobase_seek_doc}, | 
|  | _IO__IOBASE_TELL_METHODDEF | 
|  | {"truncate", iobase_truncate, METH_VARARGS, iobase_truncate_doc}, | 
|  | _IO__IOBASE_FLUSH_METHODDEF | 
|  | _IO__IOBASE_CLOSE_METHODDEF | 
|  |  | 
|  | _IO__IOBASE_SEEKABLE_METHODDEF | 
|  | _IO__IOBASE_READABLE_METHODDEF | 
|  | _IO__IOBASE_WRITABLE_METHODDEF | 
|  |  | 
|  | {"_checkClosed",   _PyIOBase_check_closed, METH_NOARGS}, | 
|  | {"_checkSeekable", _PyIOBase_check_seekable, METH_NOARGS}, | 
|  | {"_checkReadable", _PyIOBase_check_readable, METH_NOARGS}, | 
|  | {"_checkWritable", _PyIOBase_check_writable, METH_NOARGS}, | 
|  |  | 
|  | _IO__IOBASE_FILENO_METHODDEF | 
|  | _IO__IOBASE_ISATTY_METHODDEF | 
|  |  | 
|  | {"__enter__", iobase_enter, METH_NOARGS}, | 
|  | {"__exit__", iobase_exit, METH_VARARGS}, | 
|  |  | 
|  | _IO__IOBASE_READLINE_METHODDEF | 
|  | _IO__IOBASE_READLINES_METHODDEF | 
|  | _IO__IOBASE_WRITELINES_METHODDEF | 
|  |  | 
|  | {NULL, NULL} | 
|  | }; | 
|  |  | 
|  | static PyGetSetDef iobase_getset[] = { | 
|  | {"__dict__", PyObject_GenericGetDict, NULL, NULL}, | 
|  | {"closed", (getter)iobase_closed_get, NULL, NULL}, | 
|  | {NULL} | 
|  | }; | 
|  |  | 
|  |  | 
|  | PyTypeObject PyIOBase_Type = { | 
|  | PyVarObject_HEAD_INIT(NULL, 0) | 
|  | "_io._IOBase",              /*tp_name*/ | 
|  | sizeof(iobase),             /*tp_basicsize*/ | 
|  | 0,                          /*tp_itemsize*/ | 
|  | (destructor)iobase_dealloc, /*tp_dealloc*/ | 
|  | 0,                          /*tp_vectorcall_offset*/ | 
|  | 0,                          /*tp_getattr*/ | 
|  | 0,                          /*tp_setattr*/ | 
|  | 0,                          /*tp_as_async*/ | 
|  | 0,                          /*tp_repr*/ | 
|  | 0,                          /*tp_as_number*/ | 
|  | 0,                          /*tp_as_sequence*/ | 
|  | 0,                          /*tp_as_mapping*/ | 
|  | 0,                          /*tp_hash */ | 
|  | 0,                          /*tp_call*/ | 
|  | 0,                          /*tp_str*/ | 
|  | 0,                          /*tp_getattro*/ | 
|  | 0,                          /*tp_setattro*/ | 
|  | 0,                          /*tp_as_buffer*/ | 
|  | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | 
|  | | Py_TPFLAGS_HAVE_GC,   /*tp_flags*/ | 
|  | iobase_doc,                 /* tp_doc */ | 
|  | (traverseproc)iobase_traverse, /* tp_traverse */ | 
|  | (inquiry)iobase_clear,      /* tp_clear */ | 
|  | 0,                          /* tp_richcompare */ | 
|  | offsetof(iobase, weakreflist), /* tp_weaklistoffset */ | 
|  | iobase_iter,                /* tp_iter */ | 
|  | iobase_iternext,            /* tp_iternext */ | 
|  | iobase_methods,             /* tp_methods */ | 
|  | 0,                          /* tp_members */ | 
|  | iobase_getset,              /* tp_getset */ | 
|  | 0,                          /* tp_base */ | 
|  | 0,                          /* tp_dict */ | 
|  | 0,                          /* tp_descr_get */ | 
|  | 0,                          /* tp_descr_set */ | 
|  | offsetof(iobase, dict),     /* tp_dictoffset */ | 
|  | 0,                          /* tp_init */ | 
|  | 0,                          /* tp_alloc */ | 
|  | PyType_GenericNew,          /* tp_new */ | 
|  | 0,                          /* tp_free */ | 
|  | 0,                          /* tp_is_gc */ | 
|  | 0,                          /* tp_bases */ | 
|  | 0,                          /* tp_mro */ | 
|  | 0,                          /* tp_cache */ | 
|  | 0,                          /* tp_subclasses */ | 
|  | 0,                          /* tp_weaklist */ | 
|  | 0,                          /* tp_del */ | 
|  | 0,                          /* tp_version_tag */ | 
|  | iobase_finalize,            /* tp_finalize */ | 
|  | }; | 
|  |  | 
|  |  | 
|  | /* | 
|  | * RawIOBase class, Inherits from IOBase. | 
|  | */ | 
|  | PyDoc_STRVAR(rawiobase_doc, | 
|  | "Base class for raw binary I/O."); | 
|  |  | 
|  | /* | 
|  | * The read() method is implemented by calling readinto(); derived classes | 
|  | * that want to support read() only need to implement readinto() as a | 
|  | * primitive operation.  In general, readinto() can be more efficient than | 
|  | * read(). | 
|  | * | 
|  | * (It would be tempting to also provide an implementation of readinto() in | 
|  | * terms of read(), in case the latter is a more suitable primitive operation, | 
|  | * but that would lead to nasty recursion in case a subclass doesn't implement | 
|  | * either.) | 
|  | */ | 
|  |  | 
|  | /*[clinic input] | 
|  | _io._RawIOBase.read | 
|  | size as n: Py_ssize_t = -1 | 
|  | / | 
|  | [clinic start generated code]*/ | 
|  |  | 
|  | static PyObject * | 
|  | _io__RawIOBase_read_impl(PyObject *self, Py_ssize_t n) | 
|  | /*[clinic end generated code: output=6cdeb731e3c9f13c input=b6d0dcf6417d1374]*/ | 
|  | { | 
|  | PyObject *b, *res; | 
|  |  | 
|  | if (n < 0) { | 
|  | return PyObject_CallMethodNoArgs(self, &_Py_ID(readall)); | 
|  | } | 
|  |  | 
|  | /* TODO: allocate a bytes object directly instead and manually construct | 
|  | a writable memoryview pointing to it. */ | 
|  | b = PyByteArray_FromStringAndSize(NULL, n); | 
|  | if (b == NULL) | 
|  | return NULL; | 
|  |  | 
|  | res = PyObject_CallMethodObjArgs(self, &_Py_ID(readinto), b, NULL); | 
|  | if (res == NULL || res == Py_None) { | 
|  | Py_DECREF(b); | 
|  | return res; | 
|  | } | 
|  |  | 
|  | n = PyNumber_AsSsize_t(res, PyExc_ValueError); | 
|  | Py_DECREF(res); | 
|  | if (n == -1 && PyErr_Occurred()) { | 
|  | Py_DECREF(b); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | res = PyBytes_FromStringAndSize(PyByteArray_AsString(b), n); | 
|  | Py_DECREF(b); | 
|  | return res; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*[clinic input] | 
|  | _io._RawIOBase.readall | 
|  |  | 
|  | Read until EOF, using multiple read() call. | 
|  | [clinic start generated code]*/ | 
|  |  | 
|  | static PyObject * | 
|  | _io__RawIOBase_readall_impl(PyObject *self) | 
|  | /*[clinic end generated code: output=1987b9ce929425a0 input=688874141213622a]*/ | 
|  | { | 
|  | int r; | 
|  | PyObject *chunks = PyList_New(0); | 
|  | PyObject *result; | 
|  |  | 
|  | if (chunks == NULL) | 
|  | return NULL; | 
|  |  | 
|  | while (1) { | 
|  | PyObject *data = _PyObject_CallMethod(self, &_Py_ID(read), | 
|  | "i", DEFAULT_BUFFER_SIZE); | 
|  | if (!data) { | 
|  | /* NOTE: PyErr_SetFromErrno() calls PyErr_CheckSignals() | 
|  | when EINTR occurs so we needn't do it ourselves. */ | 
|  | if (_PyIO_trap_eintr()) { | 
|  | continue; | 
|  | } | 
|  | Py_DECREF(chunks); | 
|  | return NULL; | 
|  | } | 
|  | if (data == Py_None) { | 
|  | if (PyList_GET_SIZE(chunks) == 0) { | 
|  | Py_DECREF(chunks); | 
|  | return data; | 
|  | } | 
|  | Py_DECREF(data); | 
|  | break; | 
|  | } | 
|  | if (!PyBytes_Check(data)) { | 
|  | Py_DECREF(chunks); | 
|  | Py_DECREF(data); | 
|  | PyErr_SetString(PyExc_TypeError, "read() should return bytes"); | 
|  | return NULL; | 
|  | } | 
|  | if (PyBytes_GET_SIZE(data) == 0) { | 
|  | /* EOF */ | 
|  | Py_DECREF(data); | 
|  | break; | 
|  | } | 
|  | r = PyList_Append(chunks, data); | 
|  | Py_DECREF(data); | 
|  | if (r < 0) { | 
|  | Py_DECREF(chunks); | 
|  | return NULL; | 
|  | } | 
|  | } | 
|  | result = _PyBytes_Join((PyObject *)&_Py_SINGLETON(bytes_empty), chunks); | 
|  | Py_DECREF(chunks); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | static PyObject * | 
|  | rawiobase_readinto(PyObject *self, PyObject *args) | 
|  | { | 
|  | PyErr_SetNone(PyExc_NotImplementedError); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | static PyObject * | 
|  | rawiobase_write(PyObject *self, PyObject *args) | 
|  | { | 
|  | PyErr_SetNone(PyExc_NotImplementedError); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | static PyMethodDef rawiobase_methods[] = { | 
|  | _IO__RAWIOBASE_READ_METHODDEF | 
|  | _IO__RAWIOBASE_READALL_METHODDEF | 
|  | {"readinto", rawiobase_readinto, METH_VARARGS}, | 
|  | {"write", rawiobase_write, METH_VARARGS}, | 
|  | {NULL, NULL} | 
|  | }; | 
|  |  | 
|  | PyTypeObject PyRawIOBase_Type = { | 
|  | PyVarObject_HEAD_INIT(NULL, 0) | 
|  | "_io._RawIOBase",                /*tp_name*/ | 
|  | 0,                          /*tp_basicsize*/ | 
|  | 0,                          /*tp_itemsize*/ | 
|  | 0,                          /*tp_dealloc*/ | 
|  | 0,                          /*tp_vectorcall_offset*/ | 
|  | 0,                          /*tp_getattr*/ | 
|  | 0,                          /*tp_setattr*/ | 
|  | 0,                          /*tp_as_async*/ | 
|  | 0,                          /*tp_repr*/ | 
|  | 0,                          /*tp_as_number*/ | 
|  | 0,                          /*tp_as_sequence*/ | 
|  | 0,                          /*tp_as_mapping*/ | 
|  | 0,                          /*tp_hash */ | 
|  | 0,                          /*tp_call*/ | 
|  | 0,                          /*tp_str*/ | 
|  | 0,                          /*tp_getattro*/ | 
|  | 0,                          /*tp_setattro*/ | 
|  | 0,                          /*tp_as_buffer*/ | 
|  | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /*tp_flags*/ | 
|  | rawiobase_doc,              /* tp_doc */ | 
|  | 0,                          /* tp_traverse */ | 
|  | 0,                          /* tp_clear */ | 
|  | 0,                          /* tp_richcompare */ | 
|  | 0,                          /* tp_weaklistoffset */ | 
|  | 0,                          /* tp_iter */ | 
|  | 0,                          /* tp_iternext */ | 
|  | rawiobase_methods,          /* tp_methods */ | 
|  | 0,                          /* tp_members */ | 
|  | 0,                          /* tp_getset */ | 
|  | &PyIOBase_Type,             /* tp_base */ | 
|  | 0,                          /* tp_dict */ | 
|  | 0,                          /* tp_descr_get */ | 
|  | 0,                          /* tp_descr_set */ | 
|  | 0,                          /* tp_dictoffset */ | 
|  | 0,                          /* tp_init */ | 
|  | 0,                          /* tp_alloc */ | 
|  | 0,                          /* tp_new */ | 
|  | 0,                          /* tp_free */ | 
|  | 0,                          /* tp_is_gc */ | 
|  | 0,                          /* tp_bases */ | 
|  | 0,                          /* tp_mro */ | 
|  | 0,                          /* tp_cache */ | 
|  | 0,                          /* tp_subclasses */ | 
|  | 0,                          /* tp_weaklist */ | 
|  | 0,                          /* tp_del */ | 
|  | 0,                          /* tp_version_tag */ | 
|  | 0,                          /* tp_finalize */ | 
|  | }; |