mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 03:44:55 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			1163 lines
		
	
	
	
		
			32 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1163 lines
		
	
	
	
		
			32 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
    An implementation of Windows console I/O
 | 
						|
 | 
						|
    Classes defined here: _WindowsConsoleIO
 | 
						|
 | 
						|
    Written by Steve Dower
 | 
						|
*/
 | 
						|
 | 
						|
#define PY_SSIZE_T_CLEAN
 | 
						|
#include "Python.h"
 | 
						|
#include "pycore_object.h"
 | 
						|
 | 
						|
#ifdef MS_WINDOWS
 | 
						|
 | 
						|
#include "structmember.h"         // PyMemberDef
 | 
						|
#ifdef HAVE_SYS_TYPES_H
 | 
						|
#include <sys/types.h>
 | 
						|
#endif
 | 
						|
#ifdef HAVE_SYS_STAT_H
 | 
						|
#include <sys/stat.h>
 | 
						|
#endif
 | 
						|
#include <stddef.h> /* For offsetof */
 | 
						|
 | 
						|
#define WIN32_LEAN_AND_MEAN
 | 
						|
#include <windows.h>
 | 
						|
#include <fcntl.h>
 | 
						|
 | 
						|
#include "_iomodule.h"
 | 
						|
 | 
						|
/* BUFSIZ determines how many characters can be typed at the console
 | 
						|
   before it starts blocking. */
 | 
						|
#if BUFSIZ < (16*1024)
 | 
						|
#define SMALLCHUNK (2*1024)
 | 
						|
#elif (BUFSIZ >= (2 << 25))
 | 
						|
#error "unreasonable BUFSIZ > 64 MiB defined"
 | 
						|
#else
 | 
						|
#define SMALLCHUNK BUFSIZ
 | 
						|
#endif
 | 
						|
 | 
						|
/* BUFMAX determines how many bytes can be read in one go. */
 | 
						|
#define BUFMAX (32*1024*1024)
 | 
						|
 | 
						|
/* SMALLBUF determines how many utf-8 characters will be
 | 
						|
   buffered within the stream, in order to support reads
 | 
						|
   of less than one character */
 | 
						|
#define SMALLBUF 4
 | 
						|
 | 
						|
char _get_console_type(HANDLE handle) {
 | 
						|
    DWORD mode, peek_count;
 | 
						|
 | 
						|
    if (handle == INVALID_HANDLE_VALUE)
 | 
						|
        return '\0';
 | 
						|
 | 
						|
    if (!GetConsoleMode(handle, &mode))
 | 
						|
        return '\0';
 | 
						|
 | 
						|
    /* Peek at the handle to see whether it is an input or output handle */
 | 
						|
    if (GetNumberOfConsoleInputEvents(handle, &peek_count))
 | 
						|
        return 'r';
 | 
						|
    return 'w';
 | 
						|
}
 | 
						|
 | 
						|
char _PyIO_get_console_type(PyObject *path_or_fd) {
 | 
						|
    int fd = PyLong_AsLong(path_or_fd);
 | 
						|
    PyErr_Clear();
 | 
						|
    if (fd >= 0) {
 | 
						|
        HANDLE handle;
 | 
						|
        _Py_BEGIN_SUPPRESS_IPH
 | 
						|
        handle = (HANDLE)_get_osfhandle(fd);
 | 
						|
        _Py_END_SUPPRESS_IPH
 | 
						|
        if (handle == INVALID_HANDLE_VALUE)
 | 
						|
            return '\0';
 | 
						|
        return _get_console_type(handle);
 | 
						|
    }
 | 
						|
 | 
						|
    PyObject *decoded;
 | 
						|
    wchar_t *decoded_wstr;
 | 
						|
 | 
						|
    if (!PyUnicode_FSDecoder(path_or_fd, &decoded)) {
 | 
						|
        PyErr_Clear();
 | 
						|
        return '\0';
 | 
						|
    }
 | 
						|
    decoded_wstr = PyUnicode_AsWideCharString(decoded, NULL);
 | 
						|
    Py_CLEAR(decoded);
 | 
						|
    if (!decoded_wstr) {
 | 
						|
        PyErr_Clear();
 | 
						|
        return '\0';
 | 
						|
    }
 | 
						|
 | 
						|
    char m = '\0';
 | 
						|
    if (!_wcsicmp(decoded_wstr, L"CONIN$")) {
 | 
						|
        m = 'r';
 | 
						|
    } else if (!_wcsicmp(decoded_wstr, L"CONOUT$")) {
 | 
						|
        m = 'w';
 | 
						|
    } else if (!_wcsicmp(decoded_wstr, L"CON")) {
 | 
						|
        m = 'x';
 | 
						|
    }
 | 
						|
    if (m) {
 | 
						|
        PyMem_Free(decoded_wstr);
 | 
						|
        return m;
 | 
						|
    }
 | 
						|
 | 
						|
    DWORD length;
 | 
						|
    wchar_t name_buf[MAX_PATH], *pname_buf = name_buf;
 | 
						|
 | 
						|
    length = GetFullPathNameW(decoded_wstr, MAX_PATH, pname_buf, NULL);
 | 
						|
    if (length > MAX_PATH) {
 | 
						|
        pname_buf = PyMem_New(wchar_t, length);
 | 
						|
        if (pname_buf)
 | 
						|
            length = GetFullPathNameW(decoded_wstr, length, pname_buf, NULL);
 | 
						|
        else
 | 
						|
            length = 0;
 | 
						|
    }
 | 
						|
    PyMem_Free(decoded_wstr);
 | 
						|
 | 
						|
    if (length) {
 | 
						|
        wchar_t *name = pname_buf;
 | 
						|
        if (length >= 4 && name[3] == L'\\' &&
 | 
						|
            (name[2] == L'.' || name[2] == L'?') &&
 | 
						|
            name[1] == L'\\' && name[0] == L'\\') {
 | 
						|
            name += 4;
 | 
						|
        }
 | 
						|
        if (!_wcsicmp(name, L"CONIN$")) {
 | 
						|
            m = 'r';
 | 
						|
        } else if (!_wcsicmp(name, L"CONOUT$")) {
 | 
						|
            m = 'w';
 | 
						|
        } else if (!_wcsicmp(name, L"CON")) {
 | 
						|
            m = 'x';
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if (pname_buf != name_buf)
 | 
						|
        PyMem_Free(pname_buf);
 | 
						|
    return m;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*[clinic input]
 | 
						|
module _io
 | 
						|
class _io._WindowsConsoleIO "winconsoleio *" "&PyWindowsConsoleIO_Type"
 | 
						|
[clinic start generated code]*/
 | 
						|
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=e897fdc1fba4e131]*/
 | 
						|
 | 
						|
typedef struct {
 | 
						|
    PyObject_HEAD
 | 
						|
    HANDLE handle;
 | 
						|
    int fd;
 | 
						|
    unsigned int created : 1;
 | 
						|
    unsigned int readable : 1;
 | 
						|
    unsigned int writable : 1;
 | 
						|
    unsigned int closehandle : 1;
 | 
						|
    char finalizing;
 | 
						|
    unsigned int blksize;
 | 
						|
    PyObject *weakreflist;
 | 
						|
    PyObject *dict;
 | 
						|
    char buf[SMALLBUF];
 | 
						|
    wchar_t wbuf;
 | 
						|
} winconsoleio;
 | 
						|
 | 
						|
PyTypeObject PyWindowsConsoleIO_Type;
 | 
						|
 | 
						|
_Py_IDENTIFIER(name);
 | 
						|
 | 
						|
int
 | 
						|
_PyWindowsConsoleIO_closed(PyObject *self)
 | 
						|
{
 | 
						|
    return ((winconsoleio *)self)->handle == INVALID_HANDLE_VALUE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* Returns 0 on success, -1 with exception set on failure. */
 | 
						|
static int
 | 
						|
internal_close(winconsoleio *self)
 | 
						|
{
 | 
						|
    if (self->handle != INVALID_HANDLE_VALUE) {
 | 
						|
        if (self->closehandle) {
 | 
						|
            if (self->fd >= 0) {
 | 
						|
                _Py_BEGIN_SUPPRESS_IPH
 | 
						|
                close(self->fd);
 | 
						|
                _Py_END_SUPPRESS_IPH
 | 
						|
            }
 | 
						|
            CloseHandle(self->handle);
 | 
						|
        }
 | 
						|
        self->handle = INVALID_HANDLE_VALUE;
 | 
						|
        self->fd = -1;
 | 
						|
    }
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
/*[clinic input]
 | 
						|
_io._WindowsConsoleIO.close
 | 
						|
 | 
						|
Close the handle.
 | 
						|
 | 
						|
A closed handle cannot be used for further I/O operations.  close() may be
 | 
						|
called more than once without error.
 | 
						|
[clinic start generated code]*/
 | 
						|
 | 
						|
static PyObject *
 | 
						|
_io__WindowsConsoleIO_close_impl(winconsoleio *self)
 | 
						|
/*[clinic end generated code: output=27ef95b66c29057b input=185617e349ae4c7b]*/
 | 
						|
{
 | 
						|
    PyObject *res;
 | 
						|
    PyObject *exc, *val, *tb;
 | 
						|
    int rc;
 | 
						|
    _Py_IDENTIFIER(close);
 | 
						|
    res = _PyObject_CallMethodIdOneArg((PyObject*)&PyRawIOBase_Type,
 | 
						|
                                       &PyId_close, (PyObject*)self);
 | 
						|
    if (!self->closehandle) {
 | 
						|
        self->handle = INVALID_HANDLE_VALUE;
 | 
						|
        return res;
 | 
						|
    }
 | 
						|
    if (res == NULL)
 | 
						|
        PyErr_Fetch(&exc, &val, &tb);
 | 
						|
    rc = internal_close(self);
 | 
						|
    if (res == NULL)
 | 
						|
        _PyErr_ChainExceptions(exc, val, tb);
 | 
						|
    if (rc < 0)
 | 
						|
        Py_CLEAR(res);
 | 
						|
    return res;
 | 
						|
}
 | 
						|
 | 
						|
static PyObject *
 | 
						|
winconsoleio_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
 | 
						|
{
 | 
						|
    winconsoleio *self;
 | 
						|
 | 
						|
    assert(type != NULL && type->tp_alloc != NULL);
 | 
						|
 | 
						|
    self = (winconsoleio *) type->tp_alloc(type, 0);
 | 
						|
    if (self != NULL) {
 | 
						|
        self->handle = INVALID_HANDLE_VALUE;
 | 
						|
        self->fd = -1;
 | 
						|
        self->created = 0;
 | 
						|
        self->readable = 0;
 | 
						|
        self->writable = 0;
 | 
						|
        self->closehandle = 0;
 | 
						|
        self->blksize = 0;
 | 
						|
        self->weakreflist = NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    return (PyObject *) self;
 | 
						|
}
 | 
						|
 | 
						|
/*[clinic input]
 | 
						|
_io._WindowsConsoleIO.__init__
 | 
						|
    file as nameobj: object
 | 
						|
    mode: str = "r"
 | 
						|
    closefd: bool(accept={int}) = True
 | 
						|
    opener: object = None
 | 
						|
 | 
						|
Open a console buffer by file descriptor.
 | 
						|
 | 
						|
The mode can be 'rb' (default), or 'wb' for reading or writing bytes. All
 | 
						|
other mode characters will be ignored. Mode 'b' will be assumed if it is
 | 
						|
omitted. The *opener* parameter is always ignored.
 | 
						|
[clinic start generated code]*/
 | 
						|
 | 
						|
static int
 | 
						|
_io__WindowsConsoleIO___init___impl(winconsoleio *self, PyObject *nameobj,
 | 
						|
                                    const char *mode, int closefd,
 | 
						|
                                    PyObject *opener)
 | 
						|
/*[clinic end generated code: output=3fd9cbcdd8d95429 input=06ae4b863c63244b]*/
 | 
						|
{
 | 
						|
    const char *s;
 | 
						|
    wchar_t *name = NULL;
 | 
						|
    char console_type = '\0';
 | 
						|
    int ret = 0;
 | 
						|
    int rwa = 0;
 | 
						|
    int fd = -1;
 | 
						|
    int fd_is_own = 0;
 | 
						|
 | 
						|
    assert(PyWindowsConsoleIO_Check(self));
 | 
						|
    if (self->handle >= 0) {
 | 
						|
        if (self->closehandle) {
 | 
						|
            /* Have to close the existing file first. */
 | 
						|
            if (internal_close(self) < 0)
 | 
						|
                return -1;
 | 
						|
        }
 | 
						|
        else
 | 
						|
            self->handle = INVALID_HANDLE_VALUE;
 | 
						|
    }
 | 
						|
 | 
						|
    fd = _PyLong_AsInt(nameobj);
 | 
						|
    if (fd < 0) {
 | 
						|
        if (!PyErr_Occurred()) {
 | 
						|
            PyErr_SetString(PyExc_ValueError,
 | 
						|
                            "negative file descriptor");
 | 
						|
            return -1;
 | 
						|
        }
 | 
						|
        PyErr_Clear();
 | 
						|
    }
 | 
						|
    self->fd = fd;
 | 
						|
 | 
						|
    if (fd < 0) {
 | 
						|
        PyObject *decodedname;
 | 
						|
 | 
						|
        int d = PyUnicode_FSDecoder(nameobj, (void*)&decodedname);
 | 
						|
        if (!d)
 | 
						|
            return -1;
 | 
						|
 | 
						|
        name = PyUnicode_AsWideCharString(decodedname, NULL);
 | 
						|
        console_type = _PyIO_get_console_type(decodedname);
 | 
						|
        Py_CLEAR(decodedname);
 | 
						|
        if (name == NULL)
 | 
						|
            return -1;
 | 
						|
    }
 | 
						|
 | 
						|
    s = mode;
 | 
						|
    while (*s) {
 | 
						|
        switch (*s++) {
 | 
						|
        case '+':
 | 
						|
        case 'a':
 | 
						|
        case 'b':
 | 
						|
        case 'x':
 | 
						|
            break;
 | 
						|
        case 'r':
 | 
						|
            if (rwa)
 | 
						|
                goto bad_mode;
 | 
						|
            rwa = 1;
 | 
						|
            self->readable = 1;
 | 
						|
            if (console_type == 'x')
 | 
						|
                console_type = 'r';
 | 
						|
            break;
 | 
						|
        case 'w':
 | 
						|
            if (rwa)
 | 
						|
                goto bad_mode;
 | 
						|
            rwa = 1;
 | 
						|
            self->writable = 1;
 | 
						|
            if (console_type == 'x')
 | 
						|
                console_type = 'w';
 | 
						|
            break;
 | 
						|
        default:
 | 
						|
            PyErr_Format(PyExc_ValueError,
 | 
						|
                         "invalid mode: %.200s", mode);
 | 
						|
            goto error;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if (!rwa)
 | 
						|
        goto bad_mode;
 | 
						|
 | 
						|
    if (fd >= 0) {
 | 
						|
        _Py_BEGIN_SUPPRESS_IPH
 | 
						|
        self->handle = (HANDLE)_get_osfhandle(fd);
 | 
						|
        _Py_END_SUPPRESS_IPH
 | 
						|
        self->closehandle = 0;
 | 
						|
    } else {
 | 
						|
        DWORD access = GENERIC_READ;
 | 
						|
 | 
						|
        self->closehandle = 1;
 | 
						|
        if (!closefd) {
 | 
						|
            PyErr_SetString(PyExc_ValueError,
 | 
						|
                "Cannot use closefd=False with file name");
 | 
						|
            goto error;
 | 
						|
        }
 | 
						|
 | 
						|
        if (self->writable)
 | 
						|
            access = GENERIC_WRITE;
 | 
						|
 | 
						|
        Py_BEGIN_ALLOW_THREADS
 | 
						|
        /* Attempt to open for read/write initially, then fall back
 | 
						|
           on the specific access. This is required for modern names
 | 
						|
           CONIN$ and CONOUT$, which allow reading/writing state as
 | 
						|
           well as reading/writing content. */
 | 
						|
        self->handle = CreateFileW(name, GENERIC_READ | GENERIC_WRITE,
 | 
						|
            FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
 | 
						|
        if (self->handle == INVALID_HANDLE_VALUE)
 | 
						|
            self->handle = CreateFileW(name, access,
 | 
						|
                FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
 | 
						|
        Py_END_ALLOW_THREADS
 | 
						|
 | 
						|
        if (self->handle == INVALID_HANDLE_VALUE) {
 | 
						|
            PyErr_SetExcFromWindowsErrWithFilenameObject(PyExc_OSError, GetLastError(), nameobj);
 | 
						|
            goto error;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if (console_type == '\0')
 | 
						|
        console_type = _get_console_type(self->handle);
 | 
						|
 | 
						|
    if (self->writable && console_type != 'w') {
 | 
						|
        PyErr_SetString(PyExc_ValueError,
 | 
						|
            "Cannot open console input buffer for writing");
 | 
						|
        goto error;
 | 
						|
    }
 | 
						|
    if (self->readable && console_type != 'r') {
 | 
						|
        PyErr_SetString(PyExc_ValueError,
 | 
						|
            "Cannot open console output buffer for reading");
 | 
						|
        goto error;
 | 
						|
    }
 | 
						|
 | 
						|
    self->blksize = DEFAULT_BUFFER_SIZE;
 | 
						|
    memset(self->buf, 0, 4);
 | 
						|
 | 
						|
    if (_PyObject_SetAttrId((PyObject *)self, &PyId_name, nameobj) < 0)
 | 
						|
        goto error;
 | 
						|
 | 
						|
    goto done;
 | 
						|
 | 
						|
bad_mode:
 | 
						|
    PyErr_SetString(PyExc_ValueError,
 | 
						|
                    "Must have exactly one of read or write mode");
 | 
						|
error:
 | 
						|
    ret = -1;
 | 
						|
    internal_close(self);
 | 
						|
 | 
						|
done:
 | 
						|
    if (name)
 | 
						|
        PyMem_Free(name);
 | 
						|
    return ret;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
winconsoleio_traverse(winconsoleio *self, visitproc visit, void *arg)
 | 
						|
{
 | 
						|
    Py_VISIT(self->dict);
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
winconsoleio_clear(winconsoleio *self)
 | 
						|
{
 | 
						|
    Py_CLEAR(self->dict);
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
winconsoleio_dealloc(winconsoleio *self)
 | 
						|
{
 | 
						|
    self->finalizing = 1;
 | 
						|
    if (_PyIOBase_finalize((PyObject *) self) < 0)
 | 
						|
        return;
 | 
						|
    _PyObject_GC_UNTRACK(self);
 | 
						|
    if (self->weakreflist != NULL)
 | 
						|
        PyObject_ClearWeakRefs((PyObject *) self);
 | 
						|
    Py_CLEAR(self->dict);
 | 
						|
    Py_TYPE(self)->tp_free((PyObject *)self);
 | 
						|
}
 | 
						|
 | 
						|
static PyObject *
 | 
						|
err_closed(void)
 | 
						|
{
 | 
						|
    PyErr_SetString(PyExc_ValueError, "I/O operation on closed file");
 | 
						|
    return NULL;
 | 
						|
}
 | 
						|
 | 
						|
static PyObject *
 | 
						|
err_mode(const char *action)
 | 
						|
{
 | 
						|
    _PyIO_State *state = IO_STATE();
 | 
						|
    if (state != NULL)
 | 
						|
        PyErr_Format(state->unsupported_operation,
 | 
						|
                     "Console buffer does not support %s", action);
 | 
						|
    return NULL;
 | 
						|
}
 | 
						|
 | 
						|
/*[clinic input]
 | 
						|
_io._WindowsConsoleIO.fileno
 | 
						|
 | 
						|
Return the underlying file descriptor (an integer).
 | 
						|
 | 
						|
fileno is only set when a file descriptor is used to open
 | 
						|
one of the standard streams.
 | 
						|
 | 
						|
[clinic start generated code]*/
 | 
						|
 | 
						|
static PyObject *
 | 
						|
_io__WindowsConsoleIO_fileno_impl(winconsoleio *self)
 | 
						|
/*[clinic end generated code: output=006fa74ce3b5cfbf input=079adc330ddaabe6]*/
 | 
						|
{
 | 
						|
    if (self->fd < 0 && self->handle != INVALID_HANDLE_VALUE) {
 | 
						|
        _Py_BEGIN_SUPPRESS_IPH
 | 
						|
        if (self->writable)
 | 
						|
            self->fd = _open_osfhandle((intptr_t)self->handle, _O_WRONLY | _O_BINARY);
 | 
						|
        else
 | 
						|
            self->fd = _open_osfhandle((intptr_t)self->handle, _O_RDONLY | _O_BINARY);
 | 
						|
        _Py_END_SUPPRESS_IPH
 | 
						|
    }
 | 
						|
    if (self->fd < 0)
 | 
						|
        return err_mode("fileno");
 | 
						|
    return PyLong_FromLong(self->fd);
 | 
						|
}
 | 
						|
 | 
						|
/*[clinic input]
 | 
						|
_io._WindowsConsoleIO.readable
 | 
						|
 | 
						|
True if console is an input buffer.
 | 
						|
[clinic start generated code]*/
 | 
						|
 | 
						|
static PyObject *
 | 
						|
_io__WindowsConsoleIO_readable_impl(winconsoleio *self)
 | 
						|
/*[clinic end generated code: output=daf9cef2743becf0 input=6be9defb5302daae]*/
 | 
						|
{
 | 
						|
    if (self->handle == INVALID_HANDLE_VALUE)
 | 
						|
        return err_closed();
 | 
						|
    return PyBool_FromLong((long) self->readable);
 | 
						|
}
 | 
						|
 | 
						|
/*[clinic input]
 | 
						|
_io._WindowsConsoleIO.writable
 | 
						|
 | 
						|
True if console is an output buffer.
 | 
						|
[clinic start generated code]*/
 | 
						|
 | 
						|
static PyObject *
 | 
						|
_io__WindowsConsoleIO_writable_impl(winconsoleio *self)
 | 
						|
/*[clinic end generated code: output=e0a2ad7eae5abf67 input=cefbd8abc24df6a0]*/
 | 
						|
{
 | 
						|
    if (self->handle == INVALID_HANDLE_VALUE)
 | 
						|
        return err_closed();
 | 
						|
    return PyBool_FromLong((long) self->writable);
 | 
						|
}
 | 
						|
 | 
						|
static DWORD
 | 
						|
_buflen(winconsoleio *self)
 | 
						|
{
 | 
						|
    for (DWORD i = 0; i < SMALLBUF; ++i) {
 | 
						|
        if (!self->buf[i])
 | 
						|
            return i;
 | 
						|
    }
 | 
						|
    return SMALLBUF;
 | 
						|
}
 | 
						|
 | 
						|
static DWORD
 | 
						|
_copyfrombuf(winconsoleio *self, char *buf, DWORD len)
 | 
						|
{
 | 
						|
    DWORD n = 0;
 | 
						|
 | 
						|
    while (self->buf[0] && len--) {
 | 
						|
        buf[n++] = self->buf[0];
 | 
						|
        for (int i = 1; i < SMALLBUF; ++i)
 | 
						|
            self->buf[i - 1] = self->buf[i];
 | 
						|
        self->buf[SMALLBUF - 1] = 0;
 | 
						|
    }
 | 
						|
 | 
						|
    return n;
 | 
						|
}
 | 
						|
 | 
						|
static wchar_t *
 | 
						|
read_console_w(HANDLE handle, DWORD maxlen, DWORD *readlen) {
 | 
						|
    int err = 0, sig = 0;
 | 
						|
 | 
						|
    wchar_t *buf = (wchar_t*)PyMem_Malloc(maxlen * sizeof(wchar_t));
 | 
						|
    if (!buf)
 | 
						|
        goto error;
 | 
						|
 | 
						|
    *readlen = 0;
 | 
						|
 | 
						|
    //DebugBreak();
 | 
						|
    Py_BEGIN_ALLOW_THREADS
 | 
						|
    DWORD off = 0;
 | 
						|
    while (off < maxlen) {
 | 
						|
        DWORD n = (DWORD)-1;
 | 
						|
        DWORD len = min(maxlen - off, BUFSIZ);
 | 
						|
        SetLastError(0);
 | 
						|
        BOOL res = ReadConsoleW(handle, &buf[off], len, &n, NULL);
 | 
						|
 | 
						|
        if (!res) {
 | 
						|
            err = GetLastError();
 | 
						|
            break;
 | 
						|
        }
 | 
						|
        if (n == (DWORD)-1 && (err = GetLastError()) == ERROR_OPERATION_ABORTED) {
 | 
						|
            break;
 | 
						|
        }
 | 
						|
        if (n == 0) {
 | 
						|
            err = GetLastError();
 | 
						|
            if (err != ERROR_OPERATION_ABORTED)
 | 
						|
                break;
 | 
						|
            err = 0;
 | 
						|
            HANDLE hInterruptEvent = _PyOS_SigintEvent();
 | 
						|
            if (WaitForSingleObjectEx(hInterruptEvent, 100, FALSE)
 | 
						|
                    == WAIT_OBJECT_0) {
 | 
						|
                ResetEvent(hInterruptEvent);
 | 
						|
                Py_BLOCK_THREADS
 | 
						|
                sig = PyErr_CheckSignals();
 | 
						|
                Py_UNBLOCK_THREADS
 | 
						|
                if (sig < 0)
 | 
						|
                    break;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        *readlen += n;
 | 
						|
 | 
						|
        /* If we didn't read a full buffer that time, don't try
 | 
						|
           again or we will block a second time. */
 | 
						|
        if (n < len)
 | 
						|
            break;
 | 
						|
        /* If the buffer ended with a newline, break out */
 | 
						|
        if (buf[*readlen - 1] == '\n')
 | 
						|
            break;
 | 
						|
        /* If the buffer ends with a high surrogate, expand the
 | 
						|
           buffer and read an extra character. */
 | 
						|
        WORD char_type;
 | 
						|
        if (off + BUFSIZ >= maxlen &&
 | 
						|
            GetStringTypeW(CT_CTYPE3, &buf[*readlen - 1], 1, &char_type) &&
 | 
						|
            char_type == C3_HIGHSURROGATE) {
 | 
						|
            wchar_t *newbuf;
 | 
						|
            maxlen += 1;
 | 
						|
            Py_BLOCK_THREADS
 | 
						|
            newbuf = (wchar_t*)PyMem_Realloc(buf, maxlen * sizeof(wchar_t));
 | 
						|
            Py_UNBLOCK_THREADS
 | 
						|
            if (!newbuf) {
 | 
						|
                sig = -1;
 | 
						|
                break;
 | 
						|
            }
 | 
						|
            buf = newbuf;
 | 
						|
            /* Only advance by n and not BUFSIZ in this case */
 | 
						|
            off += n;
 | 
						|
            continue;
 | 
						|
        }
 | 
						|
 | 
						|
        off += BUFSIZ;
 | 
						|
    }
 | 
						|
 | 
						|
    Py_END_ALLOW_THREADS
 | 
						|
 | 
						|
    if (sig)
 | 
						|
        goto error;
 | 
						|
    if (err) {
 | 
						|
        PyErr_SetFromWindowsErr(err);
 | 
						|
        goto error;
 | 
						|
    }
 | 
						|
 | 
						|
    if (*readlen > 0 && buf[0] == L'\x1a') {
 | 
						|
        PyMem_Free(buf);
 | 
						|
        buf = (wchar_t *)PyMem_Malloc(sizeof(wchar_t));
 | 
						|
        if (!buf)
 | 
						|
            goto error;
 | 
						|
        buf[0] = L'\0';
 | 
						|
        *readlen = 0;
 | 
						|
    }
 | 
						|
 | 
						|
    return buf;
 | 
						|
 | 
						|
error:
 | 
						|
    if (buf)
 | 
						|
        PyMem_Free(buf);
 | 
						|
    return NULL;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static Py_ssize_t
 | 
						|
readinto(winconsoleio *self, char *buf, Py_ssize_t len)
 | 
						|
{
 | 
						|
    if (self->handle == INVALID_HANDLE_VALUE) {
 | 
						|
        err_closed();
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
    if (!self->readable) {
 | 
						|
        err_mode("reading");
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
    if (len == 0)
 | 
						|
        return 0;
 | 
						|
    if (len > BUFMAX) {
 | 
						|
        PyErr_Format(PyExc_ValueError, "cannot read more than %d bytes", BUFMAX);
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
 | 
						|
    /* Each character may take up to 4 bytes in the final buffer.
 | 
						|
       This is highly conservative, but necessary to avoid
 | 
						|
       failure for any given Unicode input (e.g. \U0010ffff).
 | 
						|
       If the caller requests fewer than 4 bytes, we buffer one
 | 
						|
       character.
 | 
						|
    */
 | 
						|
    DWORD wlen = (DWORD)(len / 4);
 | 
						|
    if (wlen == 0) {
 | 
						|
        wlen = 1;
 | 
						|
    }
 | 
						|
 | 
						|
    DWORD read_len = _copyfrombuf(self, buf, (DWORD)len);
 | 
						|
    if (read_len) {
 | 
						|
        buf = &buf[read_len];
 | 
						|
        len -= read_len;
 | 
						|
        wlen -= 1;
 | 
						|
    }
 | 
						|
    if (len == read_len || wlen == 0)
 | 
						|
        return read_len;
 | 
						|
 | 
						|
    DWORD n;
 | 
						|
    wchar_t *wbuf = read_console_w(self->handle, wlen, &n);
 | 
						|
    if (wbuf == NULL)
 | 
						|
        return -1;
 | 
						|
    if (n == 0) {
 | 
						|
        PyMem_Free(wbuf);
 | 
						|
        return read_len;
 | 
						|
    }
 | 
						|
 | 
						|
    int err = 0;
 | 
						|
    DWORD u8n = 0;
 | 
						|
 | 
						|
    Py_BEGIN_ALLOW_THREADS
 | 
						|
    if (len < 4) {
 | 
						|
        if (WideCharToMultiByte(CP_UTF8, 0, wbuf, n,
 | 
						|
                self->buf, sizeof(self->buf) / sizeof(self->buf[0]),
 | 
						|
                NULL, NULL))
 | 
						|
            u8n = _copyfrombuf(self, buf, (DWORD)len);
 | 
						|
    } else {
 | 
						|
        u8n = WideCharToMultiByte(CP_UTF8, 0, wbuf, n,
 | 
						|
            buf, (DWORD)len, NULL, NULL);
 | 
						|
    }
 | 
						|
 | 
						|
    if (u8n) {
 | 
						|
        read_len += u8n;
 | 
						|
        u8n = 0;
 | 
						|
    } else {
 | 
						|
        err = GetLastError();
 | 
						|
        if (err == ERROR_INSUFFICIENT_BUFFER) {
 | 
						|
            /* Calculate the needed buffer for a more useful error, as this
 | 
						|
                means our "/ 4" logic above is insufficient for some input.
 | 
						|
            */
 | 
						|
            u8n = WideCharToMultiByte(CP_UTF8, 0, wbuf, n,
 | 
						|
                NULL, 0, NULL, NULL);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    Py_END_ALLOW_THREADS
 | 
						|
 | 
						|
    PyMem_Free(wbuf);
 | 
						|
 | 
						|
    if (u8n) {
 | 
						|
        PyErr_Format(PyExc_SystemError,
 | 
						|
            "Buffer had room for %zd bytes but %u bytes required",
 | 
						|
            len, u8n);
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
    if (err) {
 | 
						|
        PyErr_SetFromWindowsErr(err);
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
 | 
						|
    return read_len;
 | 
						|
}
 | 
						|
 | 
						|
/*[clinic input]
 | 
						|
_io._WindowsConsoleIO.readinto
 | 
						|
    buffer: Py_buffer(accept={rwbuffer})
 | 
						|
    /
 | 
						|
 | 
						|
Same as RawIOBase.readinto().
 | 
						|
[clinic start generated code]*/
 | 
						|
 | 
						|
static PyObject *
 | 
						|
_io__WindowsConsoleIO_readinto_impl(winconsoleio *self, Py_buffer *buffer)
 | 
						|
/*[clinic end generated code: output=66d1bdfa3f20af39 input=4ed68da48a6baffe]*/
 | 
						|
{
 | 
						|
    Py_ssize_t len = readinto(self, buffer->buf, buffer->len);
 | 
						|
    if (len < 0)
 | 
						|
        return NULL;
 | 
						|
 | 
						|
    return PyLong_FromSsize_t(len);
 | 
						|
}
 | 
						|
 | 
						|
static DWORD
 | 
						|
new_buffersize(winconsoleio *self, DWORD currentsize)
 | 
						|
{
 | 
						|
    DWORD addend;
 | 
						|
 | 
						|
    /* Expand the buffer by an amount proportional to the current size,
 | 
						|
       giving us amortized linear-time behavior.  For bigger sizes, use a
 | 
						|
       less-than-double growth factor to avoid excessive allocation. */
 | 
						|
    if (currentsize > 65536)
 | 
						|
        addend = currentsize >> 3;
 | 
						|
    else
 | 
						|
        addend = 256 + currentsize;
 | 
						|
    if (addend < SMALLCHUNK)
 | 
						|
        /* Avoid tiny read() calls. */
 | 
						|
        addend = SMALLCHUNK;
 | 
						|
    return addend + currentsize;
 | 
						|
}
 | 
						|
 | 
						|
/*[clinic input]
 | 
						|
_io._WindowsConsoleIO.readall
 | 
						|
 | 
						|
Read all data from the console, returned as bytes.
 | 
						|
 | 
						|
Return an empty bytes object at EOF.
 | 
						|
[clinic start generated code]*/
 | 
						|
 | 
						|
static PyObject *
 | 
						|
_io__WindowsConsoleIO_readall_impl(winconsoleio *self)
 | 
						|
/*[clinic end generated code: output=e6d312c684f6e23b input=4024d649a1006e69]*/
 | 
						|
{
 | 
						|
    wchar_t *buf;
 | 
						|
    DWORD bufsize, n, len = 0;
 | 
						|
    PyObject *bytes;
 | 
						|
    DWORD bytes_size, rn;
 | 
						|
 | 
						|
    if (self->handle == INVALID_HANDLE_VALUE)
 | 
						|
        return err_closed();
 | 
						|
 | 
						|
    bufsize = BUFSIZ;
 | 
						|
 | 
						|
    buf = (wchar_t*)PyMem_Malloc((bufsize + 1) * sizeof(wchar_t));
 | 
						|
    if (buf == NULL)
 | 
						|
        return NULL;
 | 
						|
 | 
						|
    while (1) {
 | 
						|
        wchar_t *subbuf;
 | 
						|
 | 
						|
        if (len >= (Py_ssize_t)bufsize) {
 | 
						|
            DWORD newsize = new_buffersize(self, len);
 | 
						|
            if (newsize > BUFMAX)
 | 
						|
                break;
 | 
						|
            if (newsize < bufsize) {
 | 
						|
                PyErr_SetString(PyExc_OverflowError,
 | 
						|
                                "unbounded read returned more bytes "
 | 
						|
                                "than a Python bytes object can hold");
 | 
						|
                PyMem_Free(buf);
 | 
						|
                return NULL;
 | 
						|
            }
 | 
						|
            bufsize = newsize;
 | 
						|
 | 
						|
            wchar_t *tmp = PyMem_Realloc(buf,
 | 
						|
                                         (bufsize + 1) * sizeof(wchar_t));
 | 
						|
            if (tmp == NULL) {
 | 
						|
                PyMem_Free(buf);
 | 
						|
                return NULL;
 | 
						|
            }
 | 
						|
            buf = tmp;
 | 
						|
        }
 | 
						|
 | 
						|
        subbuf = read_console_w(self->handle, bufsize - len, &n);
 | 
						|
 | 
						|
        if (subbuf == NULL) {
 | 
						|
            PyMem_Free(buf);
 | 
						|
            return NULL;
 | 
						|
        }
 | 
						|
 | 
						|
        if (n > 0)
 | 
						|
            wcsncpy_s(&buf[len], bufsize - len + 1, subbuf, n);
 | 
						|
 | 
						|
        PyMem_Free(subbuf);
 | 
						|
 | 
						|
        /* when the read is empty we break */
 | 
						|
        if (n == 0)
 | 
						|
            break;
 | 
						|
 | 
						|
        len += n;
 | 
						|
    }
 | 
						|
 | 
						|
    if (len == 0 && _buflen(self) == 0) {
 | 
						|
        /* when the result starts with ^Z we return an empty buffer */
 | 
						|
        PyMem_Free(buf);
 | 
						|
        return PyBytes_FromStringAndSize(NULL, 0);
 | 
						|
    }
 | 
						|
 | 
						|
    if (len) {
 | 
						|
        Py_BEGIN_ALLOW_THREADS
 | 
						|
        bytes_size = WideCharToMultiByte(CP_UTF8, 0, buf, len,
 | 
						|
            NULL, 0, NULL, NULL);
 | 
						|
        Py_END_ALLOW_THREADS
 | 
						|
 | 
						|
        if (!bytes_size) {
 | 
						|
            DWORD err = GetLastError();
 | 
						|
            PyMem_Free(buf);
 | 
						|
            return PyErr_SetFromWindowsErr(err);
 | 
						|
        }
 | 
						|
    } else {
 | 
						|
        bytes_size = 0;
 | 
						|
    }
 | 
						|
 | 
						|
    bytes_size += _buflen(self);
 | 
						|
    bytes = PyBytes_FromStringAndSize(NULL, bytes_size);
 | 
						|
    rn = _copyfrombuf(self, PyBytes_AS_STRING(bytes), bytes_size);
 | 
						|
 | 
						|
    if (len) {
 | 
						|
        Py_BEGIN_ALLOW_THREADS
 | 
						|
        bytes_size = WideCharToMultiByte(CP_UTF8, 0, buf, len,
 | 
						|
            &PyBytes_AS_STRING(bytes)[rn], bytes_size - rn, NULL, NULL);
 | 
						|
        Py_END_ALLOW_THREADS
 | 
						|
 | 
						|
        if (!bytes_size) {
 | 
						|
            DWORD err = GetLastError();
 | 
						|
            PyMem_Free(buf);
 | 
						|
            Py_CLEAR(bytes);
 | 
						|
            return PyErr_SetFromWindowsErr(err);
 | 
						|
        }
 | 
						|
 | 
						|
        /* add back the number of preserved bytes */
 | 
						|
        bytes_size += rn;
 | 
						|
    }
 | 
						|
 | 
						|
    PyMem_Free(buf);
 | 
						|
    if (bytes_size < (size_t)PyBytes_GET_SIZE(bytes)) {
 | 
						|
        if (_PyBytes_Resize(&bytes, n * sizeof(wchar_t)) < 0) {
 | 
						|
            Py_CLEAR(bytes);
 | 
						|
            return NULL;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return bytes;
 | 
						|
}
 | 
						|
 | 
						|
/*[clinic input]
 | 
						|
_io._WindowsConsoleIO.read
 | 
						|
    size: Py_ssize_t(accept={int, NoneType}) = -1
 | 
						|
    /
 | 
						|
 | 
						|
Read at most size bytes, returned as bytes.
 | 
						|
 | 
						|
Only makes one system call when size is a positive integer,
 | 
						|
so less data may be returned than requested.
 | 
						|
Return an empty bytes object at EOF.
 | 
						|
[clinic start generated code]*/
 | 
						|
 | 
						|
static PyObject *
 | 
						|
_io__WindowsConsoleIO_read_impl(winconsoleio *self, Py_ssize_t size)
 | 
						|
/*[clinic end generated code: output=57df68af9f4b22d0 input=8bc73bc15d0fa072]*/
 | 
						|
{
 | 
						|
    PyObject *bytes;
 | 
						|
    Py_ssize_t bytes_size;
 | 
						|
 | 
						|
    if (self->handle == INVALID_HANDLE_VALUE)
 | 
						|
        return err_closed();
 | 
						|
    if (!self->readable)
 | 
						|
        return err_mode("reading");
 | 
						|
 | 
						|
    if (size < 0)
 | 
						|
        return _io__WindowsConsoleIO_readall_impl(self);
 | 
						|
    if (size > BUFMAX) {
 | 
						|
        PyErr_Format(PyExc_ValueError, "cannot read more than %d bytes", BUFMAX);
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    bytes = PyBytes_FromStringAndSize(NULL, size);
 | 
						|
    if (bytes == NULL)
 | 
						|
        return NULL;
 | 
						|
 | 
						|
    bytes_size = readinto(self, PyBytes_AS_STRING(bytes), PyBytes_GET_SIZE(bytes));
 | 
						|
    if (bytes_size < 0) {
 | 
						|
        Py_CLEAR(bytes);
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    if (bytes_size < PyBytes_GET_SIZE(bytes)) {
 | 
						|
        if (_PyBytes_Resize(&bytes, bytes_size) < 0) {
 | 
						|
            Py_CLEAR(bytes);
 | 
						|
            return NULL;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return bytes;
 | 
						|
}
 | 
						|
 | 
						|
/*[clinic input]
 | 
						|
_io._WindowsConsoleIO.write
 | 
						|
    b: Py_buffer
 | 
						|
    /
 | 
						|
 | 
						|
Write buffer b to file, return number of bytes written.
 | 
						|
 | 
						|
Only makes one system call, so not all of the data may be written.
 | 
						|
The number of bytes actually written is returned.
 | 
						|
[clinic start generated code]*/
 | 
						|
 | 
						|
static PyObject *
 | 
						|
_io__WindowsConsoleIO_write_impl(winconsoleio *self, Py_buffer *b)
 | 
						|
/*[clinic end generated code: output=775bdb16fbf9137b input=be35fb624f97c941]*/
 | 
						|
{
 | 
						|
    BOOL res = TRUE;
 | 
						|
    wchar_t *wbuf;
 | 
						|
    DWORD len, wlen, n = 0;
 | 
						|
 | 
						|
    if (self->handle == INVALID_HANDLE_VALUE)
 | 
						|
        return err_closed();
 | 
						|
    if (!self->writable)
 | 
						|
        return err_mode("writing");
 | 
						|
 | 
						|
    if (!b->len) {
 | 
						|
        return PyLong_FromLong(0);
 | 
						|
    }
 | 
						|
    if (b->len > BUFMAX)
 | 
						|
        len = BUFMAX;
 | 
						|
    else
 | 
						|
        len = (DWORD)b->len;
 | 
						|
 | 
						|
    Py_BEGIN_ALLOW_THREADS
 | 
						|
    wlen = MultiByteToWideChar(CP_UTF8, 0, b->buf, len, NULL, 0);
 | 
						|
 | 
						|
    /* issue11395 there is an unspecified upper bound on how many bytes
 | 
						|
       can be written at once. We cap at 32k - the caller will have to
 | 
						|
       handle partial writes.
 | 
						|
       Since we don't know how many input bytes are being ignored, we
 | 
						|
       have to reduce and recalculate. */
 | 
						|
    while (wlen > 32766 / sizeof(wchar_t)) {
 | 
						|
        len /= 2;
 | 
						|
        wlen = MultiByteToWideChar(CP_UTF8, 0, b->buf, len, NULL, 0);
 | 
						|
    }
 | 
						|
    Py_END_ALLOW_THREADS
 | 
						|
 | 
						|
    if (!wlen)
 | 
						|
        return PyErr_SetFromWindowsErr(0);
 | 
						|
 | 
						|
    wbuf = (wchar_t*)PyMem_Malloc(wlen * sizeof(wchar_t));
 | 
						|
 | 
						|
    Py_BEGIN_ALLOW_THREADS
 | 
						|
    wlen = MultiByteToWideChar(CP_UTF8, 0, b->buf, len, wbuf, wlen);
 | 
						|
    if (wlen) {
 | 
						|
        res = WriteConsoleW(self->handle, wbuf, wlen, &n, NULL);
 | 
						|
        if (res && n < wlen) {
 | 
						|
            /* Wrote fewer characters than expected, which means our
 | 
						|
             * len value may be wrong. So recalculate it from the
 | 
						|
             * characters that were written. As this could potentially
 | 
						|
             * result in a different value, we also validate that value.
 | 
						|
             */
 | 
						|
            len = WideCharToMultiByte(CP_UTF8, 0, wbuf, n,
 | 
						|
                NULL, 0, NULL, NULL);
 | 
						|
            if (len) {
 | 
						|
                wlen = MultiByteToWideChar(CP_UTF8, 0, b->buf, len,
 | 
						|
                    NULL, 0);
 | 
						|
                assert(wlen == len);
 | 
						|
            }
 | 
						|
        }
 | 
						|
    } else
 | 
						|
        res = 0;
 | 
						|
    Py_END_ALLOW_THREADS
 | 
						|
 | 
						|
    if (!res) {
 | 
						|
        DWORD err = GetLastError();
 | 
						|
        PyMem_Free(wbuf);
 | 
						|
        return PyErr_SetFromWindowsErr(err);
 | 
						|
    }
 | 
						|
 | 
						|
    PyMem_Free(wbuf);
 | 
						|
    return PyLong_FromSsize_t(len);
 | 
						|
}
 | 
						|
 | 
						|
static PyObject *
 | 
						|
winconsoleio_repr(winconsoleio *self)
 | 
						|
{
 | 
						|
    if (self->handle == INVALID_HANDLE_VALUE)
 | 
						|
        return PyUnicode_FromFormat("<_io._WindowsConsoleIO [closed]>");
 | 
						|
 | 
						|
    if (self->readable)
 | 
						|
        return PyUnicode_FromFormat("<_io._WindowsConsoleIO mode='rb' closefd=%s>",
 | 
						|
            self->closehandle ? "True" : "False");
 | 
						|
    if (self->writable)
 | 
						|
        return PyUnicode_FromFormat("<_io._WindowsConsoleIO mode='wb' closefd=%s>",
 | 
						|
            self->closehandle ? "True" : "False");
 | 
						|
 | 
						|
    PyErr_SetString(PyExc_SystemError, "_WindowsConsoleIO has invalid mode");
 | 
						|
    return NULL;
 | 
						|
}
 | 
						|
 | 
						|
/*[clinic input]
 | 
						|
_io._WindowsConsoleIO.isatty
 | 
						|
 | 
						|
Always True.
 | 
						|
[clinic start generated code]*/
 | 
						|
 | 
						|
static PyObject *
 | 
						|
_io__WindowsConsoleIO_isatty_impl(winconsoleio *self)
 | 
						|
/*[clinic end generated code: output=9eac09d287c11bd7 input=9b91591dbe356f86]*/
 | 
						|
{
 | 
						|
    if (self->handle == INVALID_HANDLE_VALUE)
 | 
						|
        return err_closed();
 | 
						|
 | 
						|
    Py_RETURN_TRUE;
 | 
						|
}
 | 
						|
 | 
						|
#include "clinic/winconsoleio.c.h"
 | 
						|
 | 
						|
static PyMethodDef winconsoleio_methods[] = {
 | 
						|
    _IO__WINDOWSCONSOLEIO_READ_METHODDEF
 | 
						|
    _IO__WINDOWSCONSOLEIO_READALL_METHODDEF
 | 
						|
    _IO__WINDOWSCONSOLEIO_READINTO_METHODDEF
 | 
						|
    _IO__WINDOWSCONSOLEIO_WRITE_METHODDEF
 | 
						|
    _IO__WINDOWSCONSOLEIO_CLOSE_METHODDEF
 | 
						|
    _IO__WINDOWSCONSOLEIO_READABLE_METHODDEF
 | 
						|
    _IO__WINDOWSCONSOLEIO_WRITABLE_METHODDEF
 | 
						|
    _IO__WINDOWSCONSOLEIO_FILENO_METHODDEF
 | 
						|
    _IO__WINDOWSCONSOLEIO_ISATTY_METHODDEF
 | 
						|
    {NULL,           NULL}             /* sentinel */
 | 
						|
};
 | 
						|
 | 
						|
/* 'closed' and 'mode' are attributes for compatibility with FileIO. */
 | 
						|
 | 
						|
static PyObject *
 | 
						|
get_closed(winconsoleio *self, void *closure)
 | 
						|
{
 | 
						|
    return PyBool_FromLong((long)(self->handle == INVALID_HANDLE_VALUE));
 | 
						|
}
 | 
						|
 | 
						|
static PyObject *
 | 
						|
get_closefd(winconsoleio *self, void *closure)
 | 
						|
{
 | 
						|
    return PyBool_FromLong((long)(self->closehandle));
 | 
						|
}
 | 
						|
 | 
						|
static PyObject *
 | 
						|
get_mode(winconsoleio *self, void *closure)
 | 
						|
{
 | 
						|
    return PyUnicode_FromString(self->readable ? "rb" : "wb");
 | 
						|
}
 | 
						|
 | 
						|
static PyGetSetDef winconsoleio_getsetlist[] = {
 | 
						|
    {"closed", (getter)get_closed, NULL, "True if the file is closed"},
 | 
						|
    {"closefd", (getter)get_closefd, NULL,
 | 
						|
        "True if the file descriptor will be closed by close()."},
 | 
						|
    {"mode", (getter)get_mode, NULL, "String giving the file mode"},
 | 
						|
    {NULL},
 | 
						|
};
 | 
						|
 | 
						|
static PyMemberDef winconsoleio_members[] = {
 | 
						|
    {"_blksize", T_UINT, offsetof(winconsoleio, blksize), 0},
 | 
						|
    {"_finalizing", T_BOOL, offsetof(winconsoleio, finalizing), 0},
 | 
						|
    {NULL}
 | 
						|
};
 | 
						|
 | 
						|
PyTypeObject PyWindowsConsoleIO_Type = {
 | 
						|
    PyVarObject_HEAD_INIT(NULL, 0)
 | 
						|
    "_io._WindowsConsoleIO",
 | 
						|
    sizeof(winconsoleio),
 | 
						|
    0,
 | 
						|
    (destructor)winconsoleio_dealloc,           /* tp_dealloc */
 | 
						|
    0,                                          /* tp_vectorcall_offset */
 | 
						|
    0,                                          /* tp_getattr */
 | 
						|
    0,                                          /* tp_setattr */
 | 
						|
    0,                                          /* tp_as_async */
 | 
						|
    (reprfunc)winconsoleio_repr,                /* tp_repr */
 | 
						|
    0,                                          /* tp_as_number */
 | 
						|
    0,                                          /* tp_as_sequence */
 | 
						|
    0,                                          /* tp_as_mapping */
 | 
						|
    0,                                          /* tp_hash */
 | 
						|
    0,                                          /* tp_call */
 | 
						|
    0,                                          /* tp_str */
 | 
						|
    PyObject_GenericGetAttr,                    /* tp_getattro */
 | 
						|
    0,                                          /* tp_setattro */
 | 
						|
    0,                                          /* tp_as_buffer */
 | 
						|
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
 | 
						|
        | Py_TPFLAGS_HAVE_GC,                   /* tp_flags */
 | 
						|
    _io__WindowsConsoleIO___init____doc__,      /* tp_doc */
 | 
						|
    (traverseproc)winconsoleio_traverse,        /* tp_traverse */
 | 
						|
    (inquiry)winconsoleio_clear,                /* tp_clear */
 | 
						|
    0,                                          /* tp_richcompare */
 | 
						|
    offsetof(winconsoleio, weakreflist),        /* tp_weaklistoffset */
 | 
						|
    0,                                          /* tp_iter */
 | 
						|
    0,                                          /* tp_iternext */
 | 
						|
    winconsoleio_methods,                       /* tp_methods */
 | 
						|
    winconsoleio_members,                       /* tp_members */
 | 
						|
    winconsoleio_getsetlist,                    /* tp_getset */
 | 
						|
    0,                                          /* tp_base */
 | 
						|
    0,                                          /* tp_dict */
 | 
						|
    0,                                          /* tp_descr_get */
 | 
						|
    0,                                          /* tp_descr_set */
 | 
						|
    offsetof(winconsoleio, dict),               /* tp_dictoffset */
 | 
						|
    _io__WindowsConsoleIO___init__,             /* tp_init */
 | 
						|
    PyType_GenericAlloc,                        /* tp_alloc */
 | 
						|
    winconsoleio_new,                           /* tp_new */
 | 
						|
    PyObject_GC_Del,                            /* 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 */
 | 
						|
};
 | 
						|
 | 
						|
PyObject * _PyWindowsConsoleIO_Type = (PyObject*)&PyWindowsConsoleIO_Type;
 | 
						|
 | 
						|
#endif /* MS_WINDOWS */
 |