diff options
Diffstat (limited to 'Modules/_io')
-rw-r--r-- | Modules/_io/_iomodule.c | 83 | ||||
-rw-r--r-- | Modules/_io/_iomodule.h | 29 | ||||
-rw-r--r-- | Modules/_io/bufferedio.c | 2 | ||||
-rw-r--r-- | Modules/_io/bytesio.c | 6 | ||||
-rw-r--r-- | Modules/_io/clinic/_iomodule.c.h | 14 | ||||
-rw-r--r-- | Modules/_io/clinic/bufferedio.c.h | 80 | ||||
-rw-r--r-- | Modules/_io/clinic/bytesio.c.h | 31 | ||||
-rw-r--r-- | Modules/_io/clinic/fileio.c.h | 31 | ||||
-rw-r--r-- | Modules/_io/clinic/iobase.c.h | 11 | ||||
-rw-r--r-- | Modules/_io/clinic/stringio.c.h | 22 | ||||
-rw-r--r-- | Modules/_io/clinic/textio.c.h | 45 | ||||
-rw-r--r-- | Modules/_io/clinic/winconsoleio.c.h | 331 | ||||
-rw-r--r-- | Modules/_io/fileio.c | 49 | ||||
-rw-r--r-- | Modules/_io/iobase.c | 2 | ||||
-rw-r--r-- | Modules/_io/stringio.c | 4 | ||||
-rw-r--r-- | Modules/_io/textio.c | 34 | ||||
-rw-r--r-- | Modules/_io/winconsoleio.c | 1154 |
17 files changed, 1755 insertions, 173 deletions
diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index e9f22afb50..f4d3cbd49f 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -20,6 +20,9 @@ #include <sys/stat.h> #endif /* HAVE_SYS_STAT_H */ +#ifdef MS_WINDOWS +#include <consoleapi.h> +#endif /* Various interned strings */ @@ -52,7 +55,6 @@ PyObject *_PyIO_empty_str; PyObject *_PyIO_empty_bytes; PyObject *_PyIO_zero; - PyDoc_STRVAR(module_doc, "The io module provides the Python interfaces to stream handling. The\n" "builtin open function is defined in this module.\n" @@ -238,20 +240,33 @@ _io_open_impl(PyObject *module, PyObject *file, const char *mode, int text = 0, binary = 0, universal = 0; char rawmode[6], *m; - int line_buffering, isatty; + int line_buffering, is_number; + long isatty; - PyObject *raw, *modeobj = NULL, *buffer, *wrapper, *result = NULL; + PyObject *raw, *modeobj = NULL, *buffer, *wrapper, *result = NULL, *path_or_fd = NULL; _Py_IDENTIFIER(_blksize); _Py_IDENTIFIER(isatty); _Py_IDENTIFIER(mode); _Py_IDENTIFIER(close); - if (!PyUnicode_Check(file) && - !PyBytes_Check(file) && - !PyNumber_Check(file)) { + is_number = PyNumber_Check(file); + + if (is_number) { + path_or_fd = file; + Py_INCREF(path_or_fd); + } else { + path_or_fd = PyOS_FSPath(file); + if (path_or_fd == NULL) { + return NULL; + } + } + + if (!is_number && + !PyUnicode_Check(path_or_fd) && + !PyBytes_Check(path_or_fd)) { PyErr_Format(PyExc_TypeError, "invalid file: %R", file); - return NULL; + goto error; } /* Decode mode */ @@ -292,7 +307,7 @@ _io_open_impl(PyObject *module, PyObject *file, const char *mode, if (strchr(mode+i+1, c)) { invalid_mode: PyErr_Format(PyExc_ValueError, "invalid mode: '%s'", mode); - return NULL; + goto error; } } @@ -307,54 +322,67 @@ _io_open_impl(PyObject *module, PyObject *file, const char *mode, /* Parameters validation */ if (universal) { - if (writing || appending) { + if (creating || writing || appending || updating) { PyErr_SetString(PyExc_ValueError, - "can't use U and writing mode at once"); - return NULL; + "mode U cannot be combined with x', 'w', 'a', or '+'"); + goto error; } if (PyErr_WarnEx(PyExc_DeprecationWarning, "'U' mode is deprecated", 1) < 0) - return NULL; + goto error; reading = 1; } if (text && binary) { PyErr_SetString(PyExc_ValueError, "can't have text and binary mode at once"); - return NULL; + goto error; } if (creating + reading + writing + appending > 1) { PyErr_SetString(PyExc_ValueError, "must have exactly one of create/read/write/append mode"); - return NULL; + goto error; } if (binary && encoding != NULL) { PyErr_SetString(PyExc_ValueError, "binary mode doesn't take an encoding argument"); - return NULL; + goto error; } if (binary && errors != NULL) { PyErr_SetString(PyExc_ValueError, "binary mode doesn't take an errors argument"); - return NULL; + goto error; } if (binary && newline != NULL) { PyErr_SetString(PyExc_ValueError, "binary mode doesn't take a newline argument"); - return NULL; + goto error; } /* Create the Raw file stream */ - raw = PyObject_CallFunction((PyObject *)&PyFileIO_Type, - "OsiO", file, rawmode, closefd, opener); + { + PyObject *RawIO_class = (PyObject *)&PyFileIO_Type; +#ifdef MS_WINDOWS + if (!Py_LegacyWindowsStdioFlag && _PyIO_get_console_type(path_or_fd) != '\0') { + RawIO_class = (PyObject *)&PyWindowsConsoleIO_Type; + encoding = "utf-8"; + } +#endif + raw = PyObject_CallFunction(RawIO_class, + "OsiO", path_or_fd, rawmode, closefd, opener); + } + if (raw == NULL) - return NULL; + goto error; result = raw; + Py_DECREF(path_or_fd); + path_or_fd = NULL; + modeobj = PyUnicode_FromString(mode); if (modeobj == NULL) goto error; @@ -437,10 +465,10 @@ _io_open_impl(PyObject *module, PyObject *file, const char *mode, /* wraps into a TextIOWrapper */ wrapper = PyObject_CallFunction((PyObject *)&PyTextIOWrapper_Type, - "Osssi", - buffer, - encoding, errors, newline, - line_buffering); + "Osssi", + buffer, + encoding, errors, newline, + line_buffering); if (wrapper == NULL) goto error; result = wrapper; @@ -460,6 +488,7 @@ _io_open_impl(PyObject *module, PyObject *file, const char *mode, Py_XDECREF(close_result); Py_DECREF(result); } + Py_XDECREF(path_or_fd); Py_XDECREF(modeobj); return NULL; } @@ -691,6 +720,12 @@ PyInit__io(void) PyStringIO_Type.tp_base = &PyTextIOBase_Type; ADD_TYPE(&PyStringIO_Type, "StringIO"); +#ifdef MS_WINDOWS + /* WindowsConsoleIO */ + PyWindowsConsoleIO_Type.tp_base = &PyRawIOBase_Type; + ADD_TYPE(&PyWindowsConsoleIO_Type, "_WindowsConsoleIO"); +#endif + /* BufferedReader */ PyBufferedReader_Type.tp_base = &PyBufferedIOBase_Type; ADD_TYPE(&PyBufferedReader_Type, "BufferedReader"); diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index 0c6eae26b7..daaebd2ab6 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -19,6 +19,13 @@ extern PyTypeObject PyBufferedRandom_Type; extern PyTypeObject PyTextIOWrapper_Type; extern PyTypeObject PyIncrementalNewlineDecoder_Type; +#ifndef Py_LIMITED_API +#ifdef MS_WINDOWS +extern PyTypeObject PyWindowsConsoleIO_Type; +PyAPI_DATA(PyObject *) _PyWindowsConsoleIO_Type; +#define PyWindowsConsoleIO_Check(op) (PyObject_TypeCheck((op), (PyTypeObject*)_PyWindowsConsoleIO_Type)) +#endif /* MS_WINDOWS */ +#endif /* Py_LIMITED_API */ extern int _PyIO_ConvertSsize_t(PyObject *, void *); @@ -60,7 +67,7 @@ extern PyObject *_PyIncrementalNewlineDecoder_decode( * Otherwise, the line ending is specified by readnl, a str object */ extern Py_ssize_t _PyIO_find_line_ending( int translated, int universal, PyObject *readnl, - int kind, char *start, char *end, Py_ssize_t *consumed); + int kind, const char *start, const char *end, Py_ssize_t *consumed); /* Return 1 if an EnvironmentError with errno == EINTR is set (and then clears the error indicator), 0 otherwise. @@ -85,12 +92,12 @@ extern int _PyIO_trap_eintr(void); #ifdef MS_WINDOWS /* Windows uses long long for offsets */ -typedef PY_LONG_LONG Py_off_t; +typedef long long Py_off_t; # define PyLong_AsOff_t PyLong_AsLongLong # define PyLong_FromOff_t PyLong_FromLongLong -# define PY_OFF_T_MAX PY_LLONG_MAX -# define PY_OFF_T_MIN PY_LLONG_MIN -# define PY_OFF_T_COMPAT PY_LONG_LONG /* type compatible with off_t */ +# define PY_OFF_T_MAX LLONG_MAX +# define PY_OFF_T_MIN LLONG_MIN +# define PY_OFF_T_COMPAT long long /* type compatible with off_t */ # define PY_PRIdOFF "lld" /* format to use for that type */ #else @@ -104,12 +111,12 @@ typedef off_t Py_off_t; # define PY_OFF_T_MIN PY_SSIZE_T_MIN # define PY_OFF_T_COMPAT Py_ssize_t # define PY_PRIdOFF "zd" -#elif (HAVE_LONG_LONG && SIZEOF_OFF_T == SIZEOF_LONG_LONG) +#elif (SIZEOF_OFF_T == SIZEOF_LONG_LONG) # define PyLong_AsOff_t PyLong_AsLongLong # define PyLong_FromOff_t PyLong_FromLongLong -# define PY_OFF_T_MAX PY_LLONG_MAX -# define PY_OFF_T_MIN PY_LLONG_MIN -# define PY_OFF_T_COMPAT PY_LONG_LONG +# define PY_OFF_T_MAX LLONG_MAX +# define PY_OFF_T_MIN LLONG_MIN +# define PY_OFF_T_COMPAT long long # define PY_PRIdOFF "lld" #elif (SIZEOF_OFF_T == SIZEOF_LONG) # define PyLong_AsOff_t PyLong_AsLong @@ -145,6 +152,10 @@ typedef struct { extern _PyIO_State *_PyIO_get_module_state(void); extern PyObject *_PyIO_get_locale_module(_PyIO_State *); +#ifdef MS_WINDOWS +extern char _PyIO_get_console_type(PyObject *); +#endif + extern PyObject *_PyIO_str_close; extern PyObject *_PyIO_str_closed; extern PyObject *_PyIO_str_decode; diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index 6d67751c7d..cbe7425eae 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -659,7 +659,7 @@ _bufferedreader_raw_read(buffered *self, char *start, Py_ssize_t len); /* Sets the current error to BlockingIOError */ static void -_set_BlockingIOError(char *msg, Py_ssize_t written) +_set_BlockingIOError(const char *msg, Py_ssize_t written) { PyObject *err; PyErr_Clear(); diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c index 9e5d78b166..a1ba121e26 100644 --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -87,7 +87,7 @@ scan_eol(bytesio *self, Py_ssize_t len) static int unshare_buffer(bytesio *self, size_t size) { - PyObject *new_buf, *old_buf; + PyObject *new_buf; assert(SHARED_BUF(self)); assert(self->exports == 0); assert(size >= (size_t)self->string_size); @@ -96,9 +96,7 @@ unshare_buffer(bytesio *self, size_t size) return -1; memcpy(PyBytes_AS_STRING(new_buf), PyBytes_AS_STRING(self->buf), self->string_size); - old_buf = self->buf; - self->buf = new_buf; - Py_DECREF(old_buf); + Py_SETREF(self->buf, new_buf); return 0; } diff --git a/Modules/_io/clinic/_iomodule.c.h b/Modules/_io/clinic/_iomodule.c.h index 6c88e32e5a..f2e91a9fe6 100644 --- a/Modules/_io/clinic/_iomodule.c.h +++ b/Modules/_io/clinic/_iomodule.c.h @@ -127,7 +127,7 @@ PyDoc_STRVAR(_io_open__doc__, "opened in a binary mode."); #define _IO_OPEN_METHODDEF \ - {"open", (PyCFunction)_io_open, METH_VARARGS|METH_KEYWORDS, _io_open__doc__}, + {"open", (PyCFunction)_io_open, METH_FASTCALL, _io_open__doc__}, static PyObject * _io_open_impl(PyObject *module, PyObject *file, const char *mode, @@ -135,10 +135,11 @@ _io_open_impl(PyObject *module, PyObject *file, const char *mode, const char *newline, int closefd, PyObject *opener); static PyObject * -_io_open(PyObject *module, PyObject *args, PyObject *kwargs) +_io_open(PyObject *module, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; - static char *_keywords[] = {"file", "mode", "buffering", "encoding", "errors", "newline", "closefd", "opener", NULL}; + static const char * const _keywords[] = {"file", "mode", "buffering", "encoding", "errors", "newline", "closefd", "opener", NULL}; + static _PyArg_Parser _parser = {"O|sizzziO:open", _keywords, 0}; PyObject *file; const char *mode = "r"; int buffering = -1; @@ -148,12 +149,13 @@ _io_open(PyObject *module, PyObject *args, PyObject *kwargs) int closefd = 1; PyObject *opener = Py_None; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|sizzziO:open", _keywords, - &file, &mode, &buffering, &encoding, &errors, &newline, &closefd, &opener)) + if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, + &file, &mode, &buffering, &encoding, &errors, &newline, &closefd, &opener)) { goto exit; + } return_value = _io_open_impl(module, file, mode, buffering, encoding, errors, newline, closefd, opener); exit: return return_value; } -/*[clinic end generated code: output=bc2c003cb7daeafe input=a9049054013a1b77]*/ +/*[clinic end generated code: output=c5b8fc8b83102bbf input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/bufferedio.c.h b/Modules/_io/clinic/bufferedio.c.h index 437e275730..58144a4015 100644 --- a/Modules/_io/clinic/bufferedio.c.h +++ b/Modules/_io/clinic/bufferedio.c.h @@ -19,14 +19,16 @@ _io__BufferedIOBase_readinto(PyObject *self, PyObject *arg) PyObject *return_value = NULL; Py_buffer buffer = {NULL, NULL}; - if (!PyArg_Parse(arg, "w*:readinto", &buffer)) + if (!PyArg_Parse(arg, "w*:readinto", &buffer)) { goto exit; + } return_value = _io__BufferedIOBase_readinto_impl(self, &buffer); exit: /* Cleanup for buffer */ - if (buffer.obj) + if (buffer.obj) { PyBuffer_Release(&buffer); + } return return_value; } @@ -48,14 +50,16 @@ _io__BufferedIOBase_readinto1(PyObject *self, PyObject *arg) PyObject *return_value = NULL; Py_buffer buffer = {NULL, NULL}; - if (!PyArg_Parse(arg, "w*:readinto1", &buffer)) + if (!PyArg_Parse(arg, "w*:readinto1", &buffer)) { goto exit; + } return_value = _io__BufferedIOBase_readinto1_impl(self, &buffer); exit: /* Cleanup for buffer */ - if (buffer.obj) + if (buffer.obj) { PyBuffer_Release(&buffer); + } return return_value; } @@ -99,8 +103,9 @@ _io__Buffered_peek(buffered *self, PyObject *args) Py_ssize_t size = 0; if (!PyArg_ParseTuple(args, "|n:peek", - &size)) + &size)) { goto exit; + } return_value = _io__Buffered_peek_impl(self, size); exit: @@ -125,8 +130,9 @@ _io__Buffered_read(buffered *self, PyObject *args) Py_ssize_t n = -1; if (!PyArg_ParseTuple(args, "|O&:read", - _PyIO_ConvertSsize_t, &n)) + _PyIO_ConvertSsize_t, &n)) { goto exit; + } return_value = _io__Buffered_read_impl(self, n); exit: @@ -150,8 +156,9 @@ _io__Buffered_read1(buffered *self, PyObject *arg) PyObject *return_value = NULL; Py_ssize_t n; - if (!PyArg_Parse(arg, "n:read1", &n)) + if (!PyArg_Parse(arg, "n:read1", &n)) { goto exit; + } return_value = _io__Buffered_read1_impl(self, n); exit: @@ -175,14 +182,16 @@ _io__Buffered_readinto(buffered *self, PyObject *arg) PyObject *return_value = NULL; Py_buffer buffer = {NULL, NULL}; - if (!PyArg_Parse(arg, "w*:readinto", &buffer)) + if (!PyArg_Parse(arg, "w*:readinto", &buffer)) { goto exit; + } return_value = _io__Buffered_readinto_impl(self, &buffer); exit: /* Cleanup for buffer */ - if (buffer.obj) + if (buffer.obj) { PyBuffer_Release(&buffer); + } return return_value; } @@ -204,14 +213,16 @@ _io__Buffered_readinto1(buffered *self, PyObject *arg) PyObject *return_value = NULL; Py_buffer buffer = {NULL, NULL}; - if (!PyArg_Parse(arg, "w*:readinto1", &buffer)) + if (!PyArg_Parse(arg, "w*:readinto1", &buffer)) { goto exit; + } return_value = _io__Buffered_readinto1_impl(self, &buffer); exit: /* Cleanup for buffer */ - if (buffer.obj) + if (buffer.obj) { PyBuffer_Release(&buffer); + } return return_value; } @@ -234,8 +245,9 @@ _io__Buffered_readline(buffered *self, PyObject *args) Py_ssize_t size = -1; if (!PyArg_ParseTuple(args, "|O&:readline", - _PyIO_ConvertSsize_t, &size)) + _PyIO_ConvertSsize_t, &size)) { goto exit; + } return_value = _io__Buffered_readline_impl(self, size); exit: @@ -261,8 +273,9 @@ _io__Buffered_seek(buffered *self, PyObject *args) int whence = 0; if (!PyArg_ParseTuple(args, "O|i:seek", - &targetobj, &whence)) + &targetobj, &whence)) { goto exit; + } return_value = _io__Buffered_seek_impl(self, targetobj, whence); exit: @@ -288,8 +301,9 @@ _io__Buffered_truncate(buffered *self, PyObject *args) if (!PyArg_UnpackTuple(args, "truncate", 0, 1, - &pos)) + &pos)) { goto exit; + } return_value = _io__Buffered_truncate_impl(self, pos); exit: @@ -310,13 +324,15 @@ static int _io_BufferedReader___init__(PyObject *self, PyObject *args, PyObject *kwargs) { int return_value = -1; - static char *_keywords[] = {"raw", "buffer_size", NULL}; + static const char * const _keywords[] = {"raw", "buffer_size", NULL}; + static _PyArg_Parser _parser = {"O|n:BufferedReader", _keywords, 0}; PyObject *raw; Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|n:BufferedReader", _keywords, - &raw, &buffer_size)) + if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser, + &raw, &buffer_size)) { goto exit; + } return_value = _io_BufferedReader___init___impl((buffered *)self, raw, buffer_size); exit: @@ -341,13 +357,15 @@ static int _io_BufferedWriter___init__(PyObject *self, PyObject *args, PyObject *kwargs) { int return_value = -1; - static char *_keywords[] = {"raw", "buffer_size", NULL}; + static const char * const _keywords[] = {"raw", "buffer_size", NULL}; + static _PyArg_Parser _parser = {"O|n:BufferedWriter", _keywords, 0}; PyObject *raw; Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|n:BufferedWriter", _keywords, - &raw, &buffer_size)) + if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser, + &raw, &buffer_size)) { goto exit; + } return_value = _io_BufferedWriter___init___impl((buffered *)self, raw, buffer_size); exit: @@ -371,14 +389,16 @@ _io_BufferedWriter_write(buffered *self, PyObject *arg) PyObject *return_value = NULL; Py_buffer buffer = {NULL, NULL}; - if (!PyArg_Parse(arg, "y*:write", &buffer)) + if (!PyArg_Parse(arg, "y*:write", &buffer)) { goto exit; + } return_value = _io_BufferedWriter_write_impl(self, &buffer); exit: /* Cleanup for buffer */ - if (buffer.obj) + if (buffer.obj) { PyBuffer_Release(&buffer); + } return return_value; } @@ -410,11 +430,13 @@ _io_BufferedRWPair___init__(PyObject *self, PyObject *args, PyObject *kwargs) Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE; if ((Py_TYPE(self) == &PyBufferedRWPair_Type) && - !_PyArg_NoKeywords("BufferedRWPair", kwargs)) + !_PyArg_NoKeywords("BufferedRWPair", kwargs)) { goto exit; + } if (!PyArg_ParseTuple(args, "OO|n:BufferedRWPair", - &reader, &writer, &buffer_size)) + &reader, &writer, &buffer_size)) { goto exit; + } return_value = _io_BufferedRWPair___init___impl((rwpair *)self, reader, writer, buffer_size); exit: @@ -439,16 +461,18 @@ static int _io_BufferedRandom___init__(PyObject *self, PyObject *args, PyObject *kwargs) { int return_value = -1; - static char *_keywords[] = {"raw", "buffer_size", NULL}; + static const char * const _keywords[] = {"raw", "buffer_size", NULL}; + static _PyArg_Parser _parser = {"O|n:BufferedRandom", _keywords, 0}; PyObject *raw; Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|n:BufferedRandom", _keywords, - &raw, &buffer_size)) + if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser, + &raw, &buffer_size)) { goto exit; + } return_value = _io_BufferedRandom___init___impl((buffered *)self, raw, buffer_size); exit: return return_value; } -/*[clinic end generated code: output=2bbb5e239b4ffe6f input=a9049054013a1b77]*/ +/*[clinic end generated code: output=a956f394ecde4cf9 input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/bytesio.c.h b/Modules/_io/clinic/bytesio.c.h index 5f2abb03a7..c64ce5c77c 100644 --- a/Modules/_io/clinic/bytesio.c.h +++ b/Modules/_io/clinic/bytesio.c.h @@ -171,8 +171,9 @@ _io_BytesIO_read(bytesio *self, PyObject *args) if (!PyArg_UnpackTuple(args, "read", 0, 1, - &arg)) + &arg)) { goto exit; + } return_value = _io_BytesIO_read_impl(self, arg); exit: @@ -215,8 +216,9 @@ _io_BytesIO_readline(bytesio *self, PyObject *args) if (!PyArg_UnpackTuple(args, "readline", 0, 1, - &arg)) + &arg)) { goto exit; + } return_value = _io_BytesIO_readline_impl(self, arg); exit: @@ -247,8 +249,9 @@ _io_BytesIO_readlines(bytesio *self, PyObject *args) if (!PyArg_UnpackTuple(args, "readlines", 0, 1, - &arg)) + &arg)) { goto exit; + } return_value = _io_BytesIO_readlines_impl(self, arg); exit: @@ -276,14 +279,16 @@ _io_BytesIO_readinto(bytesio *self, PyObject *arg) PyObject *return_value = NULL; Py_buffer buffer = {NULL, NULL}; - if (!PyArg_Parse(arg, "w*:readinto", &buffer)) + if (!PyArg_Parse(arg, "w*:readinto", &buffer)) { goto exit; + } return_value = _io_BytesIO_readinto_impl(self, &buffer); exit: /* Cleanup for buffer */ - if (buffer.obj) + if (buffer.obj) { PyBuffer_Release(&buffer); + } return return_value; } @@ -311,8 +316,9 @@ _io_BytesIO_truncate(bytesio *self, PyObject *args) if (!PyArg_UnpackTuple(args, "truncate", 0, 1, - &arg)) + &arg)) { goto exit; + } return_value = _io_BytesIO_truncate_impl(self, arg); exit: @@ -345,8 +351,9 @@ _io_BytesIO_seek(bytesio *self, PyObject *args) int whence = 0; if (!PyArg_ParseTuple(args, "n|i:seek", - &pos, &whence)) + &pos, &whence)) { goto exit; + } return_value = _io_BytesIO_seek_impl(self, pos, whence); exit: @@ -408,15 +415,17 @@ static int _io_BytesIO___init__(PyObject *self, PyObject *args, PyObject *kwargs) { int return_value = -1; - static char *_keywords[] = {"initial_bytes", NULL}; + static const char * const _keywords[] = {"initial_bytes", NULL}; + static _PyArg_Parser _parser = {"|O:BytesIO", _keywords, 0}; PyObject *initvalue = NULL; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O:BytesIO", _keywords, - &initvalue)) + if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser, + &initvalue)) { goto exit; + } return_value = _io_BytesIO___init___impl((bytesio *)self, initvalue); exit: return return_value; } -/*[clinic end generated code: output=60ce2c6272718431 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=6382e8eb578eea64 input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/fileio.c.h b/Modules/_io/clinic/fileio.c.h index 10420082ac..908fe0f8c8 100644 --- a/Modules/_io/clinic/fileio.c.h +++ b/Modules/_io/clinic/fileio.c.h @@ -49,15 +49,17 @@ static int _io_FileIO___init__(PyObject *self, PyObject *args, PyObject *kwargs) { int return_value = -1; - static char *_keywords[] = {"file", "mode", "closefd", "opener", NULL}; + static const char * const _keywords[] = {"file", "mode", "closefd", "opener", NULL}; + static _PyArg_Parser _parser = {"O|siO:FileIO", _keywords, 0}; PyObject *nameobj; const char *mode = "r"; int closefd = 1; PyObject *opener = Py_None; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|siO:FileIO", _keywords, - &nameobj, &mode, &closefd, &opener)) + if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser, + &nameobj, &mode, &closefd, &opener)) { goto exit; + } return_value = _io_FileIO___init___impl((fileio *)self, nameobj, mode, closefd, opener); exit: @@ -154,14 +156,16 @@ _io_FileIO_readinto(fileio *self, PyObject *arg) PyObject *return_value = NULL; Py_buffer buffer = {NULL, NULL}; - if (!PyArg_Parse(arg, "w*:readinto", &buffer)) + if (!PyArg_Parse(arg, "w*:readinto", &buffer)) { goto exit; + } return_value = _io_FileIO_readinto_impl(self, &buffer); exit: /* Cleanup for buffer */ - if (buffer.obj) + if (buffer.obj) { PyBuffer_Release(&buffer); + } return return_value; } @@ -210,8 +214,9 @@ _io_FileIO_read(fileio *self, PyObject *args) Py_ssize_t size = -1; if (!PyArg_ParseTuple(args, "|O&:read", - _PyIO_ConvertSsize_t, &size)) + _PyIO_ConvertSsize_t, &size)) { goto exit; + } return_value = _io_FileIO_read_impl(self, size); exit: @@ -240,14 +245,16 @@ _io_FileIO_write(fileio *self, PyObject *arg) PyObject *return_value = NULL; Py_buffer b = {NULL, NULL}; - if (!PyArg_Parse(arg, "y*:write", &b)) + if (!PyArg_Parse(arg, "y*:write", &b)) { goto exit; + } return_value = _io_FileIO_write_impl(self, &b); exit: /* Cleanup for b */ - if (b.obj) + if (b.obj) { PyBuffer_Release(&b); + } return return_value; } @@ -280,8 +287,9 @@ _io_FileIO_seek(fileio *self, PyObject *args) int whence = 0; if (!PyArg_ParseTuple(args, "O|i:seek", - &pos, &whence)) + &pos, &whence)) { goto exit; + } return_value = _io_FileIO_seek_impl(self, pos, whence); exit: @@ -333,8 +341,9 @@ _io_FileIO_truncate(fileio *self, PyObject *args) if (!PyArg_UnpackTuple(args, "truncate", 0, 1, - &posobj)) + &posobj)) { goto exit; + } return_value = _io_FileIO_truncate_impl(self, posobj); exit: @@ -364,4 +373,4 @@ _io_FileIO_isatty(fileio *self, PyObject *Py_UNUSED(ignored)) #ifndef _IO_FILEIO_TRUNCATE_METHODDEF #define _IO_FILEIO_TRUNCATE_METHODDEF #endif /* !defined(_IO_FILEIO_TRUNCATE_METHODDEF) */ -/*[clinic end generated code: output=dcbc39b466598492 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=51924bc0ee11d58e input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/iobase.c.h b/Modules/_io/clinic/iobase.c.h index 9762f11222..edbf73a40b 100644 --- a/Modules/_io/clinic/iobase.c.h +++ b/Modules/_io/clinic/iobase.c.h @@ -186,8 +186,9 @@ _io__IOBase_readline(PyObject *self, PyObject *args) Py_ssize_t limit = -1; if (!PyArg_ParseTuple(args, "|O&:readline", - _PyIO_ConvertSsize_t, &limit)) + _PyIO_ConvertSsize_t, &limit)) { goto exit; + } return_value = _io__IOBase_readline_impl(self, limit); exit: @@ -217,8 +218,9 @@ _io__IOBase_readlines(PyObject *self, PyObject *args) Py_ssize_t hint = -1; if (!PyArg_ParseTuple(args, "|O&:readlines", - _PyIO_ConvertSsize_t, &hint)) + _PyIO_ConvertSsize_t, &hint)) { goto exit; + } return_value = _io__IOBase_readlines_impl(self, hint); exit: @@ -251,8 +253,9 @@ _io__RawIOBase_read(PyObject *self, PyObject *args) Py_ssize_t n = -1; if (!PyArg_ParseTuple(args, "|n:read", - &n)) + &n)) { goto exit; + } return_value = _io__RawIOBase_read_impl(self, n); exit: @@ -276,4 +279,4 @@ _io__RawIOBase_readall(PyObject *self, PyObject *Py_UNUSED(ignored)) { return _io__RawIOBase_readall_impl(self); } -/*[clinic end generated code: output=b874952f5cc248a4 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=0f53fed928d8e02f input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/stringio.c.h b/Modules/_io/clinic/stringio.c.h index a8e32a3376..d2c05d7cb1 100644 --- a/Modules/_io/clinic/stringio.c.h +++ b/Modules/_io/clinic/stringio.c.h @@ -61,8 +61,9 @@ _io_StringIO_read(stringio *self, PyObject *args) if (!PyArg_UnpackTuple(args, "read", 0, 1, - &arg)) + &arg)) { goto exit; + } return_value = _io_StringIO_read_impl(self, arg); exit: @@ -91,8 +92,9 @@ _io_StringIO_readline(stringio *self, PyObject *args) if (!PyArg_UnpackTuple(args, "readline", 0, 1, - &arg)) + &arg)) { goto exit; + } return_value = _io_StringIO_readline_impl(self, arg); exit: @@ -123,8 +125,9 @@ _io_StringIO_truncate(stringio *self, PyObject *args) if (!PyArg_UnpackTuple(args, "truncate", 0, 1, - &arg)) + &arg)) { goto exit; + } return_value = _io_StringIO_truncate_impl(self, arg); exit: @@ -157,8 +160,9 @@ _io_StringIO_seek(stringio *self, PyObject *args) int whence = 0; if (!PyArg_ParseTuple(args, "n|i:seek", - &pos, &whence)) + &pos, &whence)) { goto exit; + } return_value = _io_StringIO_seek_impl(self, pos, whence); exit: @@ -217,13 +221,15 @@ static int _io_StringIO___init__(PyObject *self, PyObject *args, PyObject *kwargs) { int return_value = -1; - static char *_keywords[] = {"initial_value", "newline", NULL}; + static const char * const _keywords[] = {"initial_value", "newline", NULL}; + static _PyArg_Parser _parser = {"|OO:StringIO", _keywords, 0}; PyObject *value = NULL; PyObject *newline_obj = NULL; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OO:StringIO", _keywords, - &value, &newline_obj)) + if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser, + &value, &newline_obj)) { goto exit; + } return_value = _io_StringIO___init___impl((stringio *)self, value, newline_obj); exit: @@ -283,4 +289,4 @@ _io_StringIO_seekable(stringio *self, PyObject *Py_UNUSED(ignored)) { return _io_StringIO_seekable_impl(self); } -/*[clinic end generated code: output=f061cf3a20cd14ed input=a9049054013a1b77]*/ +/*[clinic end generated code: output=5dd5c2a213e75405 input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/textio.c.h b/Modules/_io/clinic/textio.c.h index dc7e8c7584..f39c35581e 100644 --- a/Modules/_io/clinic/textio.c.h +++ b/Modules/_io/clinic/textio.c.h @@ -24,14 +24,16 @@ static int _io_IncrementalNewlineDecoder___init__(PyObject *self, PyObject *args, PyObject *kwargs) { int return_value = -1; - static char *_keywords[] = {"decoder", "translate", "errors", NULL}; + static const char * const _keywords[] = {"decoder", "translate", "errors", NULL}; + static _PyArg_Parser _parser = {"Oi|O:IncrementalNewlineDecoder", _keywords, 0}; PyObject *decoder; int translate; PyObject *errors = NULL; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Oi|O:IncrementalNewlineDecoder", _keywords, - &decoder, &translate, &errors)) + if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser, + &decoder, &translate, &errors)) { goto exit; + } return_value = _io_IncrementalNewlineDecoder___init___impl((nldecoder_object *)self, decoder, translate, errors); exit: @@ -44,23 +46,25 @@ PyDoc_STRVAR(_io_IncrementalNewlineDecoder_decode__doc__, "\n"); #define _IO_INCREMENTALNEWLINEDECODER_DECODE_METHODDEF \ - {"decode", (PyCFunction)_io_IncrementalNewlineDecoder_decode, METH_VARARGS|METH_KEYWORDS, _io_IncrementalNewlineDecoder_decode__doc__}, + {"decode", (PyCFunction)_io_IncrementalNewlineDecoder_decode, METH_FASTCALL, _io_IncrementalNewlineDecoder_decode__doc__}, static PyObject * _io_IncrementalNewlineDecoder_decode_impl(nldecoder_object *self, PyObject *input, int final); static PyObject * -_io_IncrementalNewlineDecoder_decode(nldecoder_object *self, PyObject *args, PyObject *kwargs) +_io_IncrementalNewlineDecoder_decode(nldecoder_object *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; - static char *_keywords[] = {"input", "final", NULL}; + static const char * const _keywords[] = {"input", "final", NULL}; + static _PyArg_Parser _parser = {"O|i:decode", _keywords, 0}; PyObject *input; int final = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|i:decode", _keywords, - &input, &final)) + if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, + &input, &final)) { goto exit; + } return_value = _io_IncrementalNewlineDecoder_decode_impl(self, input, final); exit: @@ -153,7 +157,8 @@ static int _io_TextIOWrapper___init__(PyObject *self, PyObject *args, PyObject *kwargs) { int return_value = -1; - static char *_keywords[] = {"buffer", "encoding", "errors", "newline", "line_buffering", "write_through", NULL}; + static const char * const _keywords[] = {"buffer", "encoding", "errors", "newline", "line_buffering", "write_through", NULL}; + static _PyArg_Parser _parser = {"O|zzzii:TextIOWrapper", _keywords, 0}; PyObject *buffer; const char *encoding = NULL; const char *errors = NULL; @@ -161,9 +166,10 @@ _io_TextIOWrapper___init__(PyObject *self, PyObject *args, PyObject *kwargs) int line_buffering = 0; int write_through = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|zzzii:TextIOWrapper", _keywords, - &buffer, &encoding, &errors, &newline, &line_buffering, &write_through)) + if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser, + &buffer, &encoding, &errors, &newline, &line_buffering, &write_through)) { goto exit; + } return_value = _io_TextIOWrapper___init___impl((textio *)self, buffer, encoding, errors, newline, line_buffering, write_through); exit: @@ -204,8 +210,9 @@ _io_TextIOWrapper_write(textio *self, PyObject *arg) PyObject *return_value = NULL; PyObject *text; - if (!PyArg_Parse(arg, "U:write", &text)) + if (!PyArg_Parse(arg, "U:write", &text)) { goto exit; + } return_value = _io_TextIOWrapper_write_impl(self, text); exit: @@ -230,8 +237,9 @@ _io_TextIOWrapper_read(textio *self, PyObject *args) Py_ssize_t n = -1; if (!PyArg_ParseTuple(args, "|O&:read", - _PyIO_ConvertSsize_t, &n)) + _PyIO_ConvertSsize_t, &n)) { goto exit; + } return_value = _io_TextIOWrapper_read_impl(self, n); exit: @@ -256,8 +264,9 @@ _io_TextIOWrapper_readline(textio *self, PyObject *args) Py_ssize_t size = -1; if (!PyArg_ParseTuple(args, "|n:readline", - &size)) + &size)) { goto exit; + } return_value = _io_TextIOWrapper_readline_impl(self, size); exit: @@ -283,8 +292,9 @@ _io_TextIOWrapper_seek(textio *self, PyObject *args) int whence = 0; if (!PyArg_ParseTuple(args, "O|i:seek", - &cookieObj, &whence)) + &cookieObj, &whence)) { goto exit; + } return_value = _io_TextIOWrapper_seek_impl(self, cookieObj, whence); exit: @@ -327,8 +337,9 @@ _io_TextIOWrapper_truncate(textio *self, PyObject *args) if (!PyArg_UnpackTuple(args, "truncate", 0, 1, - &pos)) + &pos)) { goto exit; + } return_value = _io_TextIOWrapper_truncate_impl(self, pos); exit: @@ -453,4 +464,4 @@ _io_TextIOWrapper_close(textio *self, PyObject *Py_UNUSED(ignored)) { return _io_TextIOWrapper_close_impl(self); } -/*[clinic end generated code: output=690608f85aab8ba5 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=78ad14eba1667254 input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/winconsoleio.c.h b/Modules/_io/clinic/winconsoleio.c.h new file mode 100644 index 0000000000..e44fcbb7a1 --- /dev/null +++ b/Modules/_io/clinic/winconsoleio.c.h @@ -0,0 +1,331 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +#if defined(MS_WINDOWS) + +PyDoc_STRVAR(_io__WindowsConsoleIO_close__doc__, +"close($self, /)\n" +"--\n" +"\n" +"Close the handle.\n" +"\n" +"A closed handle cannot be used for further I/O operations. close() may be\n" +"called more than once without error."); + +#define _IO__WINDOWSCONSOLEIO_CLOSE_METHODDEF \ + {"close", (PyCFunction)_io__WindowsConsoleIO_close, METH_NOARGS, _io__WindowsConsoleIO_close__doc__}, + +static PyObject * +_io__WindowsConsoleIO_close_impl(winconsoleio *self); + +static PyObject * +_io__WindowsConsoleIO_close(winconsoleio *self, PyObject *Py_UNUSED(ignored)) +{ + return _io__WindowsConsoleIO_close_impl(self); +} + +#endif /* defined(MS_WINDOWS) */ + +#if defined(MS_WINDOWS) + +PyDoc_STRVAR(_io__WindowsConsoleIO___init____doc__, +"_WindowsConsoleIO(file, mode=\'r\', closefd=True, opener=None)\n" +"--\n" +"\n" +"Open a console buffer by file descriptor.\n" +"\n" +"The mode can be \'rb\' (default), or \'wb\' for reading or writing bytes. All\n" +"other mode characters will be ignored. Mode \'b\' will be assumed if it is\n" +"omitted. The *opener* parameter is always ignored."); + +static int +_io__WindowsConsoleIO___init___impl(winconsoleio *self, PyObject *nameobj, + const char *mode, int closefd, + PyObject *opener); + +static int +_io__WindowsConsoleIO___init__(PyObject *self, PyObject *args, PyObject *kwargs) +{ + int return_value = -1; + static const char * const _keywords[] = {"file", "mode", "closefd", "opener", NULL}; + static _PyArg_Parser _parser = {"O|siO:_WindowsConsoleIO", _keywords, 0}; + PyObject *nameobj; + const char *mode = "r"; + int closefd = 1; + PyObject *opener = Py_None; + + if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser, + &nameobj, &mode, &closefd, &opener)) { + goto exit; + } + return_value = _io__WindowsConsoleIO___init___impl((winconsoleio *)self, nameobj, mode, closefd, opener); + +exit: + return return_value; +} + +#endif /* defined(MS_WINDOWS) */ + +#if defined(MS_WINDOWS) + +PyDoc_STRVAR(_io__WindowsConsoleIO_fileno__doc__, +"fileno($self, /)\n" +"--\n" +"\n" +"Return the underlying file descriptor (an integer).\n" +"\n" +"fileno is only set when a file descriptor is used to open\n" +"one of the standard streams."); + +#define _IO__WINDOWSCONSOLEIO_FILENO_METHODDEF \ + {"fileno", (PyCFunction)_io__WindowsConsoleIO_fileno, METH_NOARGS, _io__WindowsConsoleIO_fileno__doc__}, + +static PyObject * +_io__WindowsConsoleIO_fileno_impl(winconsoleio *self); + +static PyObject * +_io__WindowsConsoleIO_fileno(winconsoleio *self, PyObject *Py_UNUSED(ignored)) +{ + return _io__WindowsConsoleIO_fileno_impl(self); +} + +#endif /* defined(MS_WINDOWS) */ + +#if defined(MS_WINDOWS) + +PyDoc_STRVAR(_io__WindowsConsoleIO_readable__doc__, +"readable($self, /)\n" +"--\n" +"\n" +"True if console is an input buffer."); + +#define _IO__WINDOWSCONSOLEIO_READABLE_METHODDEF \ + {"readable", (PyCFunction)_io__WindowsConsoleIO_readable, METH_NOARGS, _io__WindowsConsoleIO_readable__doc__}, + +static PyObject * +_io__WindowsConsoleIO_readable_impl(winconsoleio *self); + +static PyObject * +_io__WindowsConsoleIO_readable(winconsoleio *self, PyObject *Py_UNUSED(ignored)) +{ + return _io__WindowsConsoleIO_readable_impl(self); +} + +#endif /* defined(MS_WINDOWS) */ + +#if defined(MS_WINDOWS) + +PyDoc_STRVAR(_io__WindowsConsoleIO_writable__doc__, +"writable($self, /)\n" +"--\n" +"\n" +"True if console is an output buffer."); + +#define _IO__WINDOWSCONSOLEIO_WRITABLE_METHODDEF \ + {"writable", (PyCFunction)_io__WindowsConsoleIO_writable, METH_NOARGS, _io__WindowsConsoleIO_writable__doc__}, + +static PyObject * +_io__WindowsConsoleIO_writable_impl(winconsoleio *self); + +static PyObject * +_io__WindowsConsoleIO_writable(winconsoleio *self, PyObject *Py_UNUSED(ignored)) +{ + return _io__WindowsConsoleIO_writable_impl(self); +} + +#endif /* defined(MS_WINDOWS) */ + +#if defined(MS_WINDOWS) + +PyDoc_STRVAR(_io__WindowsConsoleIO_readinto__doc__, +"readinto($self, buffer, /)\n" +"--\n" +"\n" +"Same as RawIOBase.readinto()."); + +#define _IO__WINDOWSCONSOLEIO_READINTO_METHODDEF \ + {"readinto", (PyCFunction)_io__WindowsConsoleIO_readinto, METH_O, _io__WindowsConsoleIO_readinto__doc__}, + +static PyObject * +_io__WindowsConsoleIO_readinto_impl(winconsoleio *self, Py_buffer *buffer); + +static PyObject * +_io__WindowsConsoleIO_readinto(winconsoleio *self, PyObject *arg) +{ + PyObject *return_value = NULL; + Py_buffer buffer = {NULL, NULL}; + + if (!PyArg_Parse(arg, "w*:readinto", &buffer)) { + goto exit; + } + return_value = _io__WindowsConsoleIO_readinto_impl(self, &buffer); + +exit: + /* Cleanup for buffer */ + if (buffer.obj) { + PyBuffer_Release(&buffer); + } + + return return_value; +} + +#endif /* defined(MS_WINDOWS) */ + +#if defined(MS_WINDOWS) + +PyDoc_STRVAR(_io__WindowsConsoleIO_readall__doc__, +"readall($self, /)\n" +"--\n" +"\n" +"Read all data from the console, returned as bytes.\n" +"\n" +"Return an empty bytes object at EOF."); + +#define _IO__WINDOWSCONSOLEIO_READALL_METHODDEF \ + {"readall", (PyCFunction)_io__WindowsConsoleIO_readall, METH_NOARGS, _io__WindowsConsoleIO_readall__doc__}, + +static PyObject * +_io__WindowsConsoleIO_readall_impl(winconsoleio *self); + +static PyObject * +_io__WindowsConsoleIO_readall(winconsoleio *self, PyObject *Py_UNUSED(ignored)) +{ + return _io__WindowsConsoleIO_readall_impl(self); +} + +#endif /* defined(MS_WINDOWS) */ + +#if defined(MS_WINDOWS) + +PyDoc_STRVAR(_io__WindowsConsoleIO_read__doc__, +"read($self, size=-1, /)\n" +"--\n" +"\n" +"Read at most size bytes, returned as bytes.\n" +"\n" +"Only makes one system call when size is a positive integer,\n" +"so less data may be returned than requested.\n" +"Return an empty bytes object at EOF."); + +#define _IO__WINDOWSCONSOLEIO_READ_METHODDEF \ + {"read", (PyCFunction)_io__WindowsConsoleIO_read, METH_VARARGS, _io__WindowsConsoleIO_read__doc__}, + +static PyObject * +_io__WindowsConsoleIO_read_impl(winconsoleio *self, Py_ssize_t size); + +static PyObject * +_io__WindowsConsoleIO_read(winconsoleio *self, PyObject *args) +{ + PyObject *return_value = NULL; + Py_ssize_t size = -1; + + if (!PyArg_ParseTuple(args, "|O&:read", + _PyIO_ConvertSsize_t, &size)) { + goto exit; + } + return_value = _io__WindowsConsoleIO_read_impl(self, size); + +exit: + return return_value; +} + +#endif /* defined(MS_WINDOWS) */ + +#if defined(MS_WINDOWS) + +PyDoc_STRVAR(_io__WindowsConsoleIO_write__doc__, +"write($self, b, /)\n" +"--\n" +"\n" +"Write buffer b to file, return number of bytes written.\n" +"\n" +"Only makes one system call, so not all of the data may be written.\n" +"The number of bytes actually written is returned."); + +#define _IO__WINDOWSCONSOLEIO_WRITE_METHODDEF \ + {"write", (PyCFunction)_io__WindowsConsoleIO_write, METH_O, _io__WindowsConsoleIO_write__doc__}, + +static PyObject * +_io__WindowsConsoleIO_write_impl(winconsoleio *self, Py_buffer *b); + +static PyObject * +_io__WindowsConsoleIO_write(winconsoleio *self, PyObject *arg) +{ + PyObject *return_value = NULL; + Py_buffer b = {NULL, NULL}; + + if (!PyArg_Parse(arg, "y*:write", &b)) { + goto exit; + } + return_value = _io__WindowsConsoleIO_write_impl(self, &b); + +exit: + /* Cleanup for b */ + if (b.obj) { + PyBuffer_Release(&b); + } + + return return_value; +} + +#endif /* defined(MS_WINDOWS) */ + +#if defined(MS_WINDOWS) + +PyDoc_STRVAR(_io__WindowsConsoleIO_isatty__doc__, +"isatty($self, /)\n" +"--\n" +"\n" +"Always True."); + +#define _IO__WINDOWSCONSOLEIO_ISATTY_METHODDEF \ + {"isatty", (PyCFunction)_io__WindowsConsoleIO_isatty, METH_NOARGS, _io__WindowsConsoleIO_isatty__doc__}, + +static PyObject * +_io__WindowsConsoleIO_isatty_impl(winconsoleio *self); + +static PyObject * +_io__WindowsConsoleIO_isatty(winconsoleio *self, PyObject *Py_UNUSED(ignored)) +{ + return _io__WindowsConsoleIO_isatty_impl(self); +} + +#endif /* defined(MS_WINDOWS) */ + +#ifndef _IO__WINDOWSCONSOLEIO_CLOSE_METHODDEF + #define _IO__WINDOWSCONSOLEIO_CLOSE_METHODDEF +#endif /* !defined(_IO__WINDOWSCONSOLEIO_CLOSE_METHODDEF) */ + +#ifndef _IO__WINDOWSCONSOLEIO_FILENO_METHODDEF + #define _IO__WINDOWSCONSOLEIO_FILENO_METHODDEF +#endif /* !defined(_IO__WINDOWSCONSOLEIO_FILENO_METHODDEF) */ + +#ifndef _IO__WINDOWSCONSOLEIO_READABLE_METHODDEF + #define _IO__WINDOWSCONSOLEIO_READABLE_METHODDEF +#endif /* !defined(_IO__WINDOWSCONSOLEIO_READABLE_METHODDEF) */ + +#ifndef _IO__WINDOWSCONSOLEIO_WRITABLE_METHODDEF + #define _IO__WINDOWSCONSOLEIO_WRITABLE_METHODDEF +#endif /* !defined(_IO__WINDOWSCONSOLEIO_WRITABLE_METHODDEF) */ + +#ifndef _IO__WINDOWSCONSOLEIO_READINTO_METHODDEF + #define _IO__WINDOWSCONSOLEIO_READINTO_METHODDEF +#endif /* !defined(_IO__WINDOWSCONSOLEIO_READINTO_METHODDEF) */ + +#ifndef _IO__WINDOWSCONSOLEIO_READALL_METHODDEF + #define _IO__WINDOWSCONSOLEIO_READALL_METHODDEF +#endif /* !defined(_IO__WINDOWSCONSOLEIO_READALL_METHODDEF) */ + +#ifndef _IO__WINDOWSCONSOLEIO_READ_METHODDEF + #define _IO__WINDOWSCONSOLEIO_READ_METHODDEF +#endif /* !defined(_IO__WINDOWSCONSOLEIO_READ_METHODDEF) */ + +#ifndef _IO__WINDOWSCONSOLEIO_WRITE_METHODDEF + #define _IO__WINDOWSCONSOLEIO_WRITE_METHODDEF +#endif /* !defined(_IO__WINDOWSCONSOLEIO_WRITE_METHODDEF) */ + +#ifndef _IO__WINDOWSCONSOLEIO_ISATTY_METHODDEF + #define _IO__WINDOWSCONSOLEIO_ISATTY_METHODDEF +#endif /* !defined(_IO__WINDOWSCONSOLEIO_ISATTY_METHODDEF) */ +/*[clinic end generated code: output=9eba916f8537fff7 input=a9049054013a1b77]*/ diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index 919cf502dc..6854a44e2d 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -9,6 +9,9 @@ #ifdef HAVE_SYS_STAT_H #include <sys/stat.h> #endif +#ifdef HAVE_IO_H +#include <io.h> +#endif #ifdef HAVE_FCNTL_H #include <fcntl.h> #endif @@ -92,8 +95,7 @@ fileio_dealloc_warn(fileio *self, PyObject *source) if (self->fd >= 0 && self->closefd) { PyObject *exc, *val, *tb; PyErr_Fetch(&exc, &val, &tb); - if (PyErr_WarnFormat(PyExc_ResourceWarning, 1, - "unclosed file %R", source)) { + if (PyErr_ResourceWarning(source, 1, "unclosed file %R", source)) { /* Spurious errors can appear at shutdown */ if (PyErr_ExceptionMatches(PyExc_Warning)) PyErr_WriteUnraisable((PyObject *) self); @@ -118,18 +120,13 @@ internal_close(fileio *self) int fd = self->fd; self->fd = -1; /* fd is accessible and someone else may have closed it */ - if (_PyVerify_fd(fd)) { - Py_BEGIN_ALLOW_THREADS - _Py_BEGIN_SUPPRESS_IPH - err = close(fd); - if (err < 0) - save_errno = errno; - _Py_END_SUPPRESS_IPH - Py_END_ALLOW_THREADS - } else { + Py_BEGIN_ALLOW_THREADS + _Py_BEGIN_SUPPRESS_IPH + err = close(fd); + if (err < 0) save_errno = errno; - err = -1; - } + _Py_END_SUPPRESS_IPH + Py_END_ALLOW_THREADS } if (err < 0) { errno = save_errno; @@ -546,7 +543,7 @@ err_closed(void) } static PyObject * -err_mode(char *action) +err_mode(const char *action) { _PyIO_State *state = IO_STATE(); if (state != NULL) @@ -701,8 +698,6 @@ _io_FileIO_readall_impl(fileio *self) if (self->fd < 0) return err_closed(); - if (!_PyVerify_fd(self->fd)) - return PyErr_SetFromErrno(PyExc_IOError); _Py_BEGIN_SUPPRESS_IPH #ifdef MS_WINDOWS @@ -915,18 +910,15 @@ portable_lseek(int fd, PyObject *posobj, int whence) return NULL; } - if (_PyVerify_fd(fd)) { - Py_BEGIN_ALLOW_THREADS - _Py_BEGIN_SUPPRESS_IPH + Py_BEGIN_ALLOW_THREADS + _Py_BEGIN_SUPPRESS_IPH #ifdef MS_WINDOWS - res = _lseeki64(fd, pos, whence); + res = _lseeki64(fd, pos, whence); #else - res = lseek(fd, pos, whence); + res = lseek(fd, pos, whence); #endif - _Py_END_SUPPRESS_IPH - Py_END_ALLOW_THREADS - } else - res = -1; + _Py_END_SUPPRESS_IPH + Py_END_ALLOW_THREADS if (res < 0) return PyErr_SetFromErrno(PyExc_IOError); @@ -1049,7 +1041,7 @@ _io_FileIO_truncate_impl(fileio *self, PyObject *posobj) } #endif /* HAVE_FTRUNCATE */ -static char * +static const char * mode_string(fileio *self) { if (self->created) { @@ -1117,10 +1109,7 @@ _io_FileIO_isatty_impl(fileio *self) return err_closed(); Py_BEGIN_ALLOW_THREADS _Py_BEGIN_SUPPRESS_IPH - if (_PyVerify_fd(self->fd)) - res = isatty(self->fd); - else - res = 0; + res = isatty(self->fd); _Py_END_SUPPRESS_IPH Py_END_ALLOW_THREADS return PyBool_FromLong(res); diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c index 57541a8519..472ef3b97c 100644 --- a/Modules/_io/iobase.c +++ b/Modules/_io/iobase.c @@ -828,7 +828,7 @@ PyTypeObject PyIOBase_Type = { 0, /* tp_weaklist */ 0, /* tp_del */ 0, /* tp_version_tag */ - (destructor)iobase_finalize, /* tp_finalize */ + iobase_finalize, /* tp_finalize */ }; diff --git a/Modules/_io/stringio.c b/Modules/_io/stringio.c index 06b4144578..8542efd972 100644 --- a/Modules/_io/stringio.c +++ b/Modules/_io/stringio.c @@ -438,7 +438,7 @@ stringio_iternext(stringio *self) _PyIO_str_readline, NULL); if (line && !PyUnicode_Check(line)) { PyErr_Format(PyExc_IOError, - "readline() should have returned an str object, " + "readline() should have returned a str object, " "not '%.200s'", Py_TYPE(line)->tp_name); Py_DECREF(line); return NULL; @@ -708,7 +708,7 @@ _io_StringIO___init___impl(stringio *self, PyObject *value, Py_TYPE(newline_obj)->tp_name); return -1; } - newline = _PyUnicode_AsString(newline_obj); + newline = PyUnicode_AsUTF8(newline_obj); if (newline == NULL) return -1; } diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index 89b0798cd0..4df55626d4 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -531,7 +531,7 @@ _io_IncrementalNewlineDecoder_getstate_impl(nldecoder_object *self) /*[clinic end generated code: output=f0d2c9c136f4e0d0 input=f8ff101825e32e7f]*/ { PyObject *buffer; - unsigned PY_LONG_LONG flag; + unsigned long long flag; if (self->decoder != Py_None) { PyObject *state = PyObject_CallMethodObjArgs(self->decoder, @@ -567,7 +567,7 @@ _io_IncrementalNewlineDecoder_setstate(nldecoder_object *self, /*[clinic end generated code: output=c10c622508b576cb input=c53fb505a76dbbe2]*/ { PyObject *buffer; - unsigned PY_LONG_LONG flag; + unsigned long long flag; if (!PyArg_ParseTuple(state, "OK", &buffer, &flag)) return NULL; @@ -772,7 +772,7 @@ typedef struct { encodefunc_t encodefunc; } encodefuncentry; -static encodefuncentry encodefuncs[] = { +static const encodefuncentry encodefuncs[] = { {"ascii", (encodefunc_t) ascii_encode}, {"iso8859-1", (encodefunc_t) latin1_encode}, {"utf-8", (encodefunc_t) utf8_encode}, @@ -921,7 +921,7 @@ _io_TextIOWrapper___init___impl(textio *self, PyObject *buffer, Py_CLEAR(self->encoding); } if (self->encoding != NULL) { - encoding = _PyUnicode_AsString(self->encoding); + encoding = PyUnicode_AsUTF8(self->encoding); if (encoding == NULL) goto error; } @@ -964,7 +964,7 @@ _io_TextIOWrapper___init___impl(textio *self, PyObject *buffer, } self->writetranslate = (newline == NULL || newline[0] != '\0'); if (!self->readuniversal && self->readnl) { - self->writenl = _PyUnicode_AsString(self->readnl); + self->writenl = PyUnicode_AsUTF8(self->readnl); if (self->writenl == NULL) goto error; if (!strcmp(self->writenl, "\n")) @@ -1021,7 +1021,7 @@ _io_TextIOWrapper___init___impl(textio *self, PyObject *buffer, goto error; } else if (PyUnicode_Check(res)) { - encodefuncentry *e = encodefuncs; + const encodefuncentry *e = encodefuncs; while (e->name != NULL) { if (_PyUnicode_EqualToASCIIString(res, e->name)) { self->encodefunc = e->encodefunc; @@ -1637,8 +1637,8 @@ _io_TextIOWrapper_read_impl(textio *self, Py_ssize_t n) /* NOTE: `end` must point to the real end of the Py_UCS4 storage, that is to the NUL character. Otherwise the function will produce incorrect results. */ -static char * -find_control_char(int kind, char *s, char *end, Py_UCS4 ch) +static const char * +find_control_char(int kind, const char *s, const char *end, Py_UCS4 ch) { if (kind == PyUnicode_1BYTE_KIND) { assert(ch < 256); @@ -1658,13 +1658,13 @@ find_control_char(int kind, char *s, char *end, Py_UCS4 ch) Py_ssize_t _PyIO_find_line_ending( int translated, int universal, PyObject *readnl, - int kind, char *start, char *end, Py_ssize_t *consumed) + int kind, const char *start, const char *end, Py_ssize_t *consumed) { Py_ssize_t len = ((char*)end - (char*)start)/kind; if (translated) { /* Newlines are already translated, only search for \n */ - char *pos = find_control_char(kind, start, end, '\n'); + const char *pos = find_control_char(kind, start, end, '\n'); if (pos != NULL) return (pos - start)/kind + 1; else { @@ -1676,7 +1676,7 @@ _PyIO_find_line_ending( /* Universal newline search. Find any of \r, \r\n, \n * The decoder ensures that \r\n are not split in two pieces */ - char *s = start; + const char *s = start; for (;;) { Py_UCS4 ch; /* Fast path for non-control chars. The loop always ends @@ -1706,21 +1706,21 @@ _PyIO_find_line_ending( /* Assume that readnl is an ASCII character. */ assert(PyUnicode_KIND(readnl) == PyUnicode_1BYTE_KIND); if (readnl_len == 1) { - char *pos = find_control_char(kind, start, end, nl[0]); + const char *pos = find_control_char(kind, start, end, nl[0]); if (pos != NULL) return (pos - start)/kind + 1; *consumed = len; return -1; } else { - char *s = start; - char *e = end - (readnl_len - 1)*kind; - char *pos; + const char *s = start; + const char *e = end - (readnl_len - 1)*kind; + const char *pos; if (e < s) e = s; while (s < e) { Py_ssize_t i; - char *pos = find_control_char(kind, s, end, nl[0]); + const char *pos = find_control_char(kind, s, end, nl[0]); if (pos == NULL || pos >= e) break; for (i = 1; i < readnl_len; i++) { @@ -2682,7 +2682,7 @@ textiowrapper_iternext(textio *self) _PyIO_str_readline, NULL); if (line && !PyUnicode_Check(line)) { PyErr_Format(PyExc_IOError, - "readline() should have returned an str object, " + "readline() should have returned a str object, " "not '%.200s'", Py_TYPE(line)->tp_name); Py_DECREF(line); return NULL; diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c new file mode 100644 index 0000000000..7b00a9eb6d --- /dev/null +++ b/Modules/_io/winconsoleio.c @@ -0,0 +1,1154 @@ +/* + An implementation of Windows console I/O + + Classes defined here: _WindowsConsoleIO + + Written by Steve Dower +*/ + +#define PY_SSIZE_T_CLEAN +#include "Python.h" + +#ifdef MS_WINDOWS + +#include "structmember.h" +#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 > 64MB 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; + + 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) + return '\0'; + return _get_console_type(handle); + } + + PyObject *decoded, *decoded_upper; + + int d = PyUnicode_FSDecoder(path_or_fd, &decoded); + if (!d) { + PyErr_Clear(); + return '\0'; + } + if (!PyUnicode_Check(decoded)) { + Py_CLEAR(decoded); + return '\0'; + } + decoded_upper = PyObject_CallMethod(decoded, "upper", ""); + Py_CLEAR(decoded); + if (!decoded_upper) { + PyErr_Clear(); + return '\0'; + } + + char m = '\0'; + if (_PyUnicode_EqualToASCIIString(decoded_upper, "CONIN$")) { + m = 'r'; + } else if (_PyUnicode_EqualToASCIIString(decoded_upper, "CONOUT$")) { + m = 'w'; + } else if (_PyUnicode_EqualToASCIIString(decoded_upper, "CON")) { + m = 'x'; + } + + Py_CLEAR(decoded_upper); + return m; +} + +/*[clinic input] +module _io +class _io._WindowsConsoleIO "winconsoleio *" "&PyWindowsConsoleIO_Type" +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=e897fdc1fba4e131]*/ + +/*[python input] +class io_ssize_t_converter(CConverter): + type = 'Py_ssize_t' + converter = '_PyIO_ConvertSsize_t' +[python start generated code]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=d0a811d3cbfd1b33]*/ + +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_CallMethodId((PyObject*)&PyRawIOBase_Type, + &PyId_close, "O", 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: int(c_default="1") = 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=61be39633a86f5d7]*/ +{ + 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; + } + + if (PyFloat_Check(nameobj)) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float"); + return -1; + } + + 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 = Py_None; + Py_INCREF(decodedname); + + int d = PyUnicode_FSDecoder(nameobj, (void*)&decodedname); + if (!d) + return -1; + + Py_ssize_t length; + name = PyUnicode_AsWideCharString(decodedname, &length); + console_type = _PyIO_get_console_type(decodedname); + Py_CLEAR(decodedname); + if (name == NULL) + return -1; + + if (wcslen(name) != length) { + PyMem_Free(name); + PyErr_SetString(PyExc_ValueError, "embedded null character"); + 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, len = min(maxlen - off, BUFSIZ); + SetLastError(0); + BOOL res = ReadConsoleW(handle, &buf[off], len, &n, NULL); + + if (!res) { + err = GetLastError(); + 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 %d bytes but %d 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; + + buf = PyMem_Realloc(buf, (bufsize + 1) * sizeof(wchar_t)); + if (!buf) { + PyMem_Free(buf); + return NULL; + } + } + + 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: io_ssize_t = -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=6c56fceec460f1dd]*/ +{ + 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 > 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 (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; +} + +static PyObject * +winconsoleio_getstate(winconsoleio *self) +{ + PyErr_Format(PyExc_TypeError, + "cannot serialize '%s' object", Py_TYPE(self)->tp_name); + return NULL; +} + +#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 + {"__getstate__", (PyCFunction)winconsoleio_getstate, METH_NOARGS, NULL}, + {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_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_reserved */ + (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 | Py_TPFLAGS_HAVE_FINALIZE, /* 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 */ +}; + +PyAPI_DATA(PyObject *) _PyWindowsConsoleIO_Type = (PyObject*)&PyWindowsConsoleIO_Type; + +#endif /* MS_WINDOWS */ |