mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 05:31:20 +00:00 
			
		
		
		
	 37834136d0
			
		
	
	
		37834136d0
		
			
		
	
	
	
	
		
			
			Use _PyLong_GetZero() and _PyLong_GetOne() in Modules/ directory. _cursesmodule.c and zoneinfo.c are now built with Py_BUILD_CORE_MODULE macro defined.
		
			
				
	
	
		
			1083 lines
		
	
	
	
		
			30 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1083 lines
		
	
	
	
		
			30 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|     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, acting on streams of\n"
 | |
|     "bytes. There is no public constructor.\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. */
 | |
| 
 | |
| _Py_IDENTIFIER(__IOBase_closed);
 | |
| _Py_IDENTIFIER(read);
 | |
| 
 | |
| 
 | |
| /* 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]*/
 | |
| {
 | |
|     _Py_IDENTIFIER(seek);
 | |
| 
 | |
|     return _PyObject_CallMethodId(self, &PyId_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_LookupAttrId(self, &PyId___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, _PyIO_str_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, _PyIO_str_flush);
 | |
| 
 | |
|     PyErr_Fetch(&exc, &val, &tb);
 | |
|     rc = _PyObject_SetAttrId(self, &PyId___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;
 | |
|     _Py_IDENTIFIER(_finalizing);
 | |
| 
 | |
|     /* 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, _PyIO_str_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_SetAttrId(self, &PyId__finalizing, Py_True))
 | |
|             PyErr_Clear();
 | |
|         res = PyObject_CallMethodNoArgs((PyObject *)self, _PyIO_str_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, _PyIO_str_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, _PyIO_str_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, _PyIO_str_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;
 | |
| 
 | |
|     Py_INCREF(self);
 | |
|     return self;
 | |
| }
 | |
| 
 | |
| static PyObject *
 | |
| iobase_exit(PyObject *self, PyObject *args)
 | |
| {
 | |
|     return PyObject_CallMethodNoArgs(self, _PyIO_str_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, _PyIO_str_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_CallMethodId(self, &PyId_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;
 | |
| 
 | |
|     Py_INCREF(self);
 | |
|     return self;
 | |
| }
 | |
| 
 | |
| static PyObject *
 | |
| iobase_iternext(PyObject *self)
 | |
| {
 | |
|     PyObject *line = PyObject_CallMethodNoArgs(self, _PyIO_str_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. */
 | |
|         _Py_IDENTIFIER(extend);
 | |
|         PyObject *ret = _PyObject_CallMethodIdObjArgs(result, &PyId_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, _PyIO_str_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) {
 | |
|         _Py_IDENTIFIER(readall);
 | |
| 
 | |
|         return _PyObject_CallMethodIdNoArgs(self, &PyId_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, _PyIO_str_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_CallMethodId(self, &PyId_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(_PyIO_empty_bytes, 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 */
 | |
| };
 |