mirror of
				https://github.com/python/cpython.git
				synced 2025-11-03 19:34:08 +00:00 
			
		
		
		
	svn+ssh://pythondev@svn.python.org/python/trunk ........ r80720 | antoine.pitrou | 2010-05-03 18:25:33 +0200 (lun., 03 mai 2010) | 5 lines Issue #7865: The close() method of :mod:`io` objects should not swallow exceptions raised by the implicit flush(). Also ensure that calling close() several times is supported. Patch by Pascal Chambon. ........
		
			
				
	
	
		
			885 lines
		
	
	
	
		
			26 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			885 lines
		
	
	
	
		
			26 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 "structmember.h"
 | 
						|
#include "_iomodule.h"
 | 
						|
 | 
						|
/*
 | 
						|
 * 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 a IOError when operations they do not support are called.\n"
 | 
						|
    "\n"
 | 
						|
    "The basic type used for binary data read from or written to a file is\n"
 | 
						|
    "bytes. bytearrays are accepted too, and in some cases (such as\n"
 | 
						|
    "readinto) needed. Text I/O classes work with str data.\n"
 | 
						|
    "\n"
 | 
						|
    "Note that calling any method (even inquiries) on a closed stream is\n"
 | 
						|
    "undefined. Implementations may raise IOError in this case.\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 statment 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. */
 | 
						|
 | 
						|
#define IS_CLOSED(self) \
 | 
						|
    PyObject_HasAttrString(self, "__IOBase_closed")
 | 
						|
 | 
						|
/* Internal methods */
 | 
						|
static PyObject *
 | 
						|
iobase_unsupported(const char *message)
 | 
						|
{
 | 
						|
    PyErr_SetString(IO_STATE->unsupported_operation, message);
 | 
						|
    return NULL;
 | 
						|
}
 | 
						|
 | 
						|
/* Positionning */
 | 
						|
 | 
						|
PyDoc_STRVAR(iobase_seek_doc,
 | 
						|
    "Change stream position.\n"
 | 
						|
    "\n"
 | 
						|
    "Change the stream position to byte offset offset. 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");
 | 
						|
}
 | 
						|
 | 
						|
PyDoc_STRVAR(iobase_tell_doc,
 | 
						|
             "Return current stream position.");
 | 
						|
 | 
						|
static PyObject *
 | 
						|
iobase_tell(PyObject *self, PyObject *args)
 | 
						|
{
 | 
						|
    return PyObject_CallMethod(self, "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");
 | 
						|
}
 | 
						|
 | 
						|
/* Flush and close methods */
 | 
						|
 | 
						|
PyDoc_STRVAR(iobase_flush_doc,
 | 
						|
    "Flush write buffers, if applicable.\n"
 | 
						|
    "\n"
 | 
						|
    "This is not implemented for read-only and non-blocking streams.\n");
 | 
						|
 | 
						|
static PyObject *
 | 
						|
iobase_flush(PyObject *self, PyObject *args)
 | 
						|
{
 | 
						|
    /* XXX Should this return the number of bytes written??? */
 | 
						|
    if (IS_CLOSED(self)) {
 | 
						|
        PyErr_SetString(PyExc_ValueError, "I/O operation on closed file.");
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
    Py_RETURN_NONE;
 | 
						|
}
 | 
						|
 | 
						|
PyDoc_STRVAR(iobase_close_doc,
 | 
						|
    "Flush and close the IO object.\n"
 | 
						|
    "\n"
 | 
						|
    "This method has no effect if the file is already closed.\n");
 | 
						|
 | 
						|
static int
 | 
						|
iobase_closed(PyObject *self)
 | 
						|
{
 | 
						|
    PyObject *res;
 | 
						|
    int closed;
 | 
						|
    /* This gets the derived attribute, which is *not* __IOBase_closed
 | 
						|
       in most cases! */
 | 
						|
    res = PyObject_GetAttr(self, _PyIO_str_closed);
 | 
						|
    if (res == NULL)
 | 
						|
        return 0;
 | 
						|
    closed = PyObject_IsTrue(res);
 | 
						|
    Py_DECREF(res);
 | 
						|
    return closed;
 | 
						|
}
 | 
						|
 | 
						|
static PyObject *
 | 
						|
iobase_closed_get(PyObject *self, void *context)
 | 
						|
{
 | 
						|
    return PyBool_FromLong(IS_CLOSED(self));
 | 
						|
}
 | 
						|
 | 
						|
PyObject *
 | 
						|
_PyIOBase_check_closed(PyObject *self, PyObject *args)
 | 
						|
{
 | 
						|
    if (iobase_closed(self)) {
 | 
						|
        PyErr_SetString(PyExc_ValueError, "I/O operation on closed file.");
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
    if (args == Py_True)
 | 
						|
        return Py_None;
 | 
						|
    else
 | 
						|
        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. */
 | 
						|
 | 
						|
static PyObject *
 | 
						|
iobase_close(PyObject *self, PyObject *args)
 | 
						|
{
 | 
						|
    PyObject *res;
 | 
						|
 | 
						|
    if (IS_CLOSED(self))
 | 
						|
        Py_RETURN_NONE;
 | 
						|
 | 
						|
    res = PyObject_CallMethodObjArgs(self, _PyIO_str_flush, NULL);
 | 
						|
    PyObject_SetAttrString(self, "__IOBase_closed", Py_True);
 | 
						|
    if (res == NULL) {
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
    Py_XDECREF(res);
 | 
						|
    Py_RETURN_NONE;
 | 
						|
}
 | 
						|
 | 
						|
/* Finalization and garbage collection support */
 | 
						|
 | 
						|
int
 | 
						|
_PyIOBase_finalize(PyObject *self)
 | 
						|
{
 | 
						|
    PyObject *res;
 | 
						|
    PyObject *tp, *v, *tb;
 | 
						|
    int closed = 1;
 | 
						|
    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) {
 | 
						|
        ++Py_REFCNT(self);
 | 
						|
    }
 | 
						|
    PyErr_Fetch(&tp, &v, &tb);
 | 
						|
    /* If `closed` doesn't exist or can't be evaluated as bool, then the
 | 
						|
       object is probably in an unusable state, so ignore. */
 | 
						|
    res = PyObject_GetAttr(self, _PyIO_str_closed);
 | 
						|
    if (res == NULL)
 | 
						|
        PyErr_Clear();
 | 
						|
    else {
 | 
						|
        closed = PyObject_IsTrue(res);
 | 
						|
        Py_DECREF(res);
 | 
						|
        if (closed == -1)
 | 
						|
            PyErr_Clear();
 | 
						|
    }
 | 
						|
    if (closed == 0) {
 | 
						|
        res = PyObject_CallMethodObjArgs((PyObject *) self, _PyIO_str_close,
 | 
						|
                                          NULL);
 | 
						|
        /* 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)
 | 
						|
            PyErr_Clear();
 | 
						|
        else
 | 
						|
            Py_DECREF(res);
 | 
						|
    }
 | 
						|
    PyErr_Restore(tp, v, tb);
 | 
						|
    if (is_zombie) {
 | 
						|
        if (--Py_REFCNT(self) != 0) {
 | 
						|
            /* The object lives again. The following code is taken from
 | 
						|
               slot_tp_del in typeobject.c. */
 | 
						|
            Py_ssize_t refcnt = Py_REFCNT(self);
 | 
						|
            _Py_NewReference(self);
 | 
						|
            Py_REFCNT(self) = refcnt;
 | 
						|
            /* If Py_REF_DEBUG, _Py_NewReference bumped _Py_RefTotal, so
 | 
						|
             * we need to undo that. */
 | 
						|
            _Py_DEC_REFTOTAL;
 | 
						|
            /* If Py_TRACE_REFS, _Py_NewReference re-added self to the object
 | 
						|
             * chain, so no more to do there.
 | 
						|
             * If COUNT_ALLOCS, the original decref bumped tp_frees, and
 | 
						|
             * _Py_NewReference bumped tp_allocs:  both of those need to be
 | 
						|
             * undone.
 | 
						|
             */
 | 
						|
#ifdef COUNT_ALLOCS
 | 
						|
            --Py_TYPE(self)->tp_frees;
 | 
						|
            --Py_TYPE(self)->tp_allocs;
 | 
						|
#endif
 | 
						|
            return -1;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
iobase_traverse(iobase *self, visitproc visit, void *arg)
 | 
						|
{
 | 
						|
    Py_VISIT(self->dict);
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
iobase_clear(iobase *self)
 | 
						|
{
 | 
						|
    if (_PyIOBase_finalize((PyObject *) self) < 0)
 | 
						|
        return -1;
 | 
						|
    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 */
 | 
						|
 | 
						|
PyDoc_STRVAR(iobase_seekable_doc,
 | 
						|
    "Return whether object supports random access.\n"
 | 
						|
    "\n"
 | 
						|
    "If False, seek(), tell() and truncate() will raise IOError.\n"
 | 
						|
    "This method may need to do a test seek().");
 | 
						|
 | 
						|
static PyObject *
 | 
						|
iobase_seekable(PyObject *self, PyObject *args)
 | 
						|
{
 | 
						|
    Py_RETURN_FALSE;
 | 
						|
}
 | 
						|
 | 
						|
PyObject *
 | 
						|
_PyIOBase_check_seekable(PyObject *self, PyObject *args)
 | 
						|
{
 | 
						|
    PyObject *res  = PyObject_CallMethodObjArgs(self, _PyIO_str_seekable, NULL);
 | 
						|
    if (res == NULL)
 | 
						|
        return NULL;
 | 
						|
    if (res != Py_True) {
 | 
						|
        Py_CLEAR(res);
 | 
						|
        PyErr_SetString(PyExc_IOError, "File or stream is not seekable.");
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
    if (args == Py_True) {
 | 
						|
        Py_DECREF(res);
 | 
						|
    }
 | 
						|
    return res;
 | 
						|
}
 | 
						|
 | 
						|
PyDoc_STRVAR(iobase_readable_doc,
 | 
						|
    "Return whether object was opened for reading.\n"
 | 
						|
    "\n"
 | 
						|
    "If False, read() will raise IOError.");
 | 
						|
 | 
						|
static PyObject *
 | 
						|
iobase_readable(PyObject *self, PyObject *args)
 | 
						|
{
 | 
						|
    Py_RETURN_FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/* May be called with any object */
 | 
						|
PyObject *
 | 
						|
_PyIOBase_check_readable(PyObject *self, PyObject *args)
 | 
						|
{
 | 
						|
    PyObject *res  = PyObject_CallMethodObjArgs(self, _PyIO_str_readable, NULL);
 | 
						|
    if (res == NULL)
 | 
						|
        return NULL;
 | 
						|
    if (res != Py_True) {
 | 
						|
        Py_CLEAR(res);
 | 
						|
        PyErr_SetString(PyExc_IOError, "File or stream is not readable.");
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
    if (args == Py_True) {
 | 
						|
        Py_DECREF(res);
 | 
						|
    }
 | 
						|
    return res;
 | 
						|
}
 | 
						|
 | 
						|
PyDoc_STRVAR(iobase_writable_doc,
 | 
						|
    "Return whether object was opened for writing.\n"
 | 
						|
    "\n"
 | 
						|
    "If False, read() will raise IOError.");
 | 
						|
 | 
						|
static PyObject *
 | 
						|
iobase_writable(PyObject *self, PyObject *args)
 | 
						|
{
 | 
						|
    Py_RETURN_FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/* May be called with any object */
 | 
						|
PyObject *
 | 
						|
_PyIOBase_check_writable(PyObject *self, PyObject *args)
 | 
						|
{
 | 
						|
    PyObject *res  = PyObject_CallMethodObjArgs(self, _PyIO_str_writable, NULL);
 | 
						|
    if (res == NULL)
 | 
						|
        return NULL;
 | 
						|
    if (res != Py_True) {
 | 
						|
        Py_CLEAR(res);
 | 
						|
        PyErr_SetString(PyExc_IOError, "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 (_PyIOBase_check_closed(self, Py_True) == NULL)
 | 
						|
        return NULL;
 | 
						|
 | 
						|
    Py_INCREF(self);
 | 
						|
    return self;
 | 
						|
}
 | 
						|
 | 
						|
static PyObject *
 | 
						|
iobase_exit(PyObject *self, PyObject *args)
 | 
						|
{
 | 
						|
    return PyObject_CallMethodObjArgs(self, _PyIO_str_close, NULL);
 | 
						|
}
 | 
						|
 | 
						|
/* Lower-level APIs */
 | 
						|
 | 
						|
/* XXX Should these be present even if unimplemented? */
 | 
						|
 | 
						|
PyDoc_STRVAR(iobase_fileno_doc,
 | 
						|
    "Returns underlying file descriptor if one exists.\n"
 | 
						|
    "\n"
 | 
						|
    "An IOError is raised if the IO object does not use a file descriptor.\n");
 | 
						|
 | 
						|
static PyObject *
 | 
						|
iobase_fileno(PyObject *self, PyObject *args)
 | 
						|
{
 | 
						|
    return iobase_unsupported("fileno");
 | 
						|
}
 | 
						|
 | 
						|
PyDoc_STRVAR(iobase_isatty_doc,
 | 
						|
    "Return whether this is an 'interactive' stream.\n"
 | 
						|
    "\n"
 | 
						|
    "Return False if it can't be determined.\n");
 | 
						|
 | 
						|
static PyObject *
 | 
						|
iobase_isatty(PyObject *self, PyObject *args)
 | 
						|
{
 | 
						|
    if (_PyIOBase_check_closed(self, Py_True) == NULL)
 | 
						|
        return NULL;
 | 
						|
    Py_RETURN_FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/* Readline(s) and writelines */
 | 
						|
 | 
						|
PyDoc_STRVAR(iobase_readline_doc,
 | 
						|
    "Read and return a line from the stream.\n"
 | 
						|
    "\n"
 | 
						|
    "If limit is specified, at most limit bytes will be read.\n"
 | 
						|
    "\n"
 | 
						|
    "The line terminator is always b'\n' for binary files; for text\n"
 | 
						|
    "files, the newlines argument to open can be used to select the line\n"
 | 
						|
    "terminator(s) recognized.\n");
 | 
						|
 | 
						|
static PyObject *
 | 
						|
iobase_readline(PyObject *self, PyObject *args)
 | 
						|
{
 | 
						|
    /* For backwards compatibility, a (slowish) readline(). */
 | 
						|
 | 
						|
    Py_ssize_t limit = -1;
 | 
						|
    int has_peek = 0;
 | 
						|
    PyObject *buffer, *result;
 | 
						|
    Py_ssize_t old_size = -1;
 | 
						|
 | 
						|
    if (!PyArg_ParseTuple(args, "|O&:readline", &_PyIO_ConvertSsize_t, &limit)) {
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    if (PyObject_HasAttrString(self, "peek"))
 | 
						|
        has_peek = 1;
 | 
						|
 | 
						|
    buffer = PyByteArray_FromStringAndSize(NULL, 0);
 | 
						|
    if (buffer == NULL)
 | 
						|
        return NULL;
 | 
						|
 | 
						|
    while (limit < 0 || Py_SIZE(buffer) < limit) {
 | 
						|
        Py_ssize_t nreadahead = 1;
 | 
						|
        PyObject *b;
 | 
						|
 | 
						|
        if (has_peek) {
 | 
						|
            PyObject *readahead = PyObject_CallMethod(self, "peek", "i", 1);
 | 
						|
            if (readahead == NULL)
 | 
						|
                goto fail;
 | 
						|
            if (!PyBytes_Check(readahead)) {
 | 
						|
                PyErr_Format(PyExc_IOError,
 | 
						|
                             "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, "read", "n", nreadahead);
 | 
						|
        if (b == NULL)
 | 
						|
            goto fail;
 | 
						|
        if (!PyBytes_Check(b)) {
 | 
						|
            PyErr_Format(PyExc_IOError,
 | 
						|
                         "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);
 | 
						|
        PyByteArray_Resize(buffer, old_size + PyBytes_GET_SIZE(b));
 | 
						|
        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_DECREF(buffer);
 | 
						|
    return result;
 | 
						|
  fail:
 | 
						|
    Py_DECREF(buffer);
 | 
						|
    return NULL;
 | 
						|
}
 | 
						|
 | 
						|
static PyObject *
 | 
						|
iobase_iter(PyObject *self)
 | 
						|
{
 | 
						|
    if (_PyIOBase_check_closed(self, Py_True) == NULL)
 | 
						|
        return NULL;
 | 
						|
 | 
						|
    Py_INCREF(self);
 | 
						|
    return self;
 | 
						|
}
 | 
						|
 | 
						|
static PyObject *
 | 
						|
iobase_iternext(PyObject *self)
 | 
						|
{
 | 
						|
    PyObject *line = PyObject_CallMethodObjArgs(self, _PyIO_str_readline, NULL);
 | 
						|
 | 
						|
    if (line == NULL)
 | 
						|
        return NULL;
 | 
						|
 | 
						|
    if (PyObject_Size(line) == 0) {
 | 
						|
        Py_DECREF(line);
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    return line;
 | 
						|
}
 | 
						|
 | 
						|
PyDoc_STRVAR(iobase_readlines_doc,
 | 
						|
    "Return a list of lines from the stream.\n"
 | 
						|
    "\n"
 | 
						|
    "hint can be specified to control the number of lines read: no more\n"
 | 
						|
    "lines will be read if the total size (in bytes/characters) of all\n"
 | 
						|
    "lines so far exceeds hint.");
 | 
						|
 | 
						|
static PyObject *
 | 
						|
iobase_readlines(PyObject *self, PyObject *args)
 | 
						|
{
 | 
						|
    Py_ssize_t hint = -1, length = 0;
 | 
						|
    PyObject *result;
 | 
						|
 | 
						|
    if (!PyArg_ParseTuple(args, "|O&:readlines", &_PyIO_ConvertSsize_t, &hint)) {
 | 
						|
        return 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_CallMethod(result, "extend", "O", self);
 | 
						|
        if (ret == NULL) {
 | 
						|
            Py_DECREF(result);
 | 
						|
            return NULL;
 | 
						|
        }
 | 
						|
        Py_DECREF(ret);
 | 
						|
        return result;
 | 
						|
    }
 | 
						|
 | 
						|
    while (1) {
 | 
						|
        PyObject *line = PyIter_Next(self);
 | 
						|
        if (line == NULL) {
 | 
						|
            if (PyErr_Occurred()) {
 | 
						|
                Py_DECREF(result);
 | 
						|
                return NULL;
 | 
						|
            }
 | 
						|
            else
 | 
						|
                break; /* StopIteration raised */
 | 
						|
        }
 | 
						|
 | 
						|
        if (PyList_Append(result, line) < 0) {
 | 
						|
            Py_DECREF(line);
 | 
						|
            Py_DECREF(result);
 | 
						|
            return NULL;
 | 
						|
        }
 | 
						|
        length += PyObject_Size(line);
 | 
						|
        Py_DECREF(line);
 | 
						|
 | 
						|
        if (length > hint)
 | 
						|
            break;
 | 
						|
    }
 | 
						|
    return result;
 | 
						|
}
 | 
						|
 | 
						|
static PyObject *
 | 
						|
iobase_writelines(PyObject *self, PyObject *args)
 | 
						|
{
 | 
						|
    PyObject *lines, *iter, *res;
 | 
						|
 | 
						|
    if (!PyArg_ParseTuple(args, "O:writelines", &lines)) {
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    if (_PyIOBase_check_closed(self, Py_True) == NULL)
 | 
						|
        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 = PyObject_CallMethodObjArgs(self, _PyIO_str_write, line, NULL);
 | 
						|
        Py_DECREF(line);
 | 
						|
        if (res == NULL) {
 | 
						|
            Py_DECREF(iter);
 | 
						|
            return NULL;
 | 
						|
        }
 | 
						|
        Py_DECREF(res);
 | 
						|
    }
 | 
						|
    Py_DECREF(iter);
 | 
						|
    Py_RETURN_NONE;
 | 
						|
}
 | 
						|
 | 
						|
static PyMethodDef iobase_methods[] = {
 | 
						|
    {"seek", iobase_seek, METH_VARARGS, iobase_seek_doc},
 | 
						|
    {"tell", iobase_tell, METH_NOARGS, iobase_tell_doc},
 | 
						|
    {"truncate", iobase_truncate, METH_VARARGS, iobase_truncate_doc},
 | 
						|
    {"flush", iobase_flush, METH_NOARGS, iobase_flush_doc},
 | 
						|
    {"close", iobase_close, METH_NOARGS, iobase_close_doc},
 | 
						|
 | 
						|
    {"seekable", iobase_seekable, METH_NOARGS, iobase_seekable_doc},
 | 
						|
    {"readable", iobase_readable, METH_NOARGS, iobase_readable_doc},
 | 
						|
    {"writable", iobase_writable, METH_NOARGS, iobase_writable_doc},
 | 
						|
 | 
						|
    {"_checkClosed",   _PyIOBase_check_closed, METH_NOARGS},
 | 
						|
    {"_checkSeekable", _PyIOBase_check_seekable, METH_NOARGS},
 | 
						|
    {"_checkReadable", _PyIOBase_check_readable, METH_NOARGS},
 | 
						|
    {"_checkWritable", _PyIOBase_check_writable, METH_NOARGS},
 | 
						|
 | 
						|
    {"fileno", iobase_fileno, METH_NOARGS, iobase_fileno_doc},
 | 
						|
    {"isatty", iobase_isatty, METH_NOARGS, iobase_isatty_doc},
 | 
						|
 | 
						|
    {"__enter__", iobase_enter, METH_NOARGS},
 | 
						|
    {"__exit__", iobase_exit, METH_VARARGS},
 | 
						|
 | 
						|
    {"readline", iobase_readline, METH_VARARGS, iobase_readline_doc},
 | 
						|
    {"readlines", iobase_readlines, METH_VARARGS, iobase_readlines_doc},
 | 
						|
    {"writelines", iobase_writelines, METH_VARARGS},
 | 
						|
 | 
						|
    {NULL, NULL}
 | 
						|
};
 | 
						|
 | 
						|
static PyGetSetDef iobase_getset[] = {
 | 
						|
    {"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_print*/
 | 
						|
    0,                          /*tp_getattr*/
 | 
						|
    0,                          /*tp_setattr*/
 | 
						|
    0,                          /*tp_compare */
 | 
						|
    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 */
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * 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.)
 | 
						|
*/
 | 
						|
 | 
						|
static PyObject *
 | 
						|
rawiobase_read(PyObject *self, PyObject *args)
 | 
						|
{
 | 
						|
    Py_ssize_t n = -1;
 | 
						|
    PyObject *b, *res;
 | 
						|
 | 
						|
    if (!PyArg_ParseTuple(args, "|n:read", &n)) {
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    if (n < 0)
 | 
						|
        return PyObject_CallMethod(self, "readall", NULL);
 | 
						|
 | 
						|
    /* 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) {
 | 
						|
        Py_DECREF(b);
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    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;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
PyDoc_STRVAR(rawiobase_readall_doc,
 | 
						|
             "Read until EOF, using multiple read() call.");
 | 
						|
 | 
						|
static PyObject *
 | 
						|
rawiobase_readall(PyObject *self, PyObject *args)
 | 
						|
{
 | 
						|
    int r;
 | 
						|
    PyObject *chunks = PyList_New(0);
 | 
						|
    PyObject *result;
 | 
						|
    
 | 
						|
    if (chunks == NULL)
 | 
						|
        return NULL;
 | 
						|
 | 
						|
    while (1) {
 | 
						|
        PyObject *data = PyObject_CallMethod(self, "read",
 | 
						|
                                             "i", DEFAULT_BUFFER_SIZE);
 | 
						|
        if (!data) {
 | 
						|
            Py_DECREF(chunks);
 | 
						|
            return NULL;
 | 
						|
        }
 | 
						|
        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 PyMethodDef rawiobase_methods[] = {
 | 
						|
    {"read", rawiobase_read, METH_VARARGS},
 | 
						|
    {"readall", rawiobase_readall, METH_NOARGS, rawiobase_readall_doc},
 | 
						|
    {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_print*/
 | 
						|
    0,                          /*tp_getattr*/
 | 
						|
    0,                          /*tp_setattr*/
 | 
						|
    0,                          /*tp_compare */
 | 
						|
    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 */
 | 
						|
};
 |