From 9c166f423fbc1698d89fc10fb15481d5bb150e9b Mon Sep 17 00:00:00 2001 From: ValeriyaSinevich Date: Fri, 15 Jun 2018 23:21:08 -0700 Subject: [PATCH 01/13] convert content length to string before putting to header --- Lib/http/server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/http/server.py b/Lib/http/server.py index ea0e295d283442..ca2dd507392c8e 100644 --- a/Lib/http/server.py +++ b/Lib/http/server.py @@ -474,7 +474,7 @@ def send_error(self, code, message=None, explain=None): }) body = content.encode('UTF-8', 'replace') self.send_header("Content-Type", self.error_content_type) - self.send_header('Content-Length', int(len(body))) + self.send_header('Content-Length', str(len(body))) self.end_headers() if self.command != 'HEAD' and body: From 02842b657d3a0ad76fcf6cab77632d7ba4900fc6 Mon Sep 17 00:00:00 2001 From: ValeriyaSinevich Date: Sun, 17 Jun 2018 10:48:36 -0700 Subject: [PATCH 02/13] news entry --- .../NEWS.d/next/Library/2018-06-17-10-48-03.bpo-33663.sUuGmq.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2018-06-17-10-48-03.bpo-33663.sUuGmq.rst diff --git a/Misc/NEWS.d/next/Library/2018-06-17-10-48-03.bpo-33663.sUuGmq.rst b/Misc/NEWS.d/next/Library/2018-06-17-10-48-03.bpo-33663.sUuGmq.rst new file mode 100644 index 00000000000000..b2a8e3cc00c67c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-06-17-10-48-03.bpo-33663.sUuGmq.rst @@ -0,0 +1 @@ +Convert content length to string before putting to header. From 11a898a0b0a66436fdeffae39f4546c7e2459e42 Mon Sep 17 00:00:00 2001 From: ValeriyaSinevich Date: Mon, 25 Jun 2018 09:18:33 -0700 Subject: [PATCH 03/13] output error when ReadConsole is canceled by CancelSynchronousIo instead of crashing --- Modules/_io/winconsoleio.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c index 2bf48eb55532d8..2a1bb5c845d5fe 100644 --- a/Modules/_io/winconsoleio.c +++ b/Modules/_io/winconsoleio.c @@ -556,7 +556,8 @@ read_console_w(HANDLE handle, DWORD maxlen, DWORD *readlen) { Py_BEGIN_ALLOW_THREADS DWORD off = 0; while (off < maxlen) { - DWORD n, len = min(maxlen - off, BUFSIZ); + DWORD n = (DWORD) - 1; + DWORD len = min(maxlen - off, BUFSIZ); SetLastError(0); BOOL res = ReadConsoleW(handle, &buf[off], len, &n, NULL); @@ -564,6 +565,9 @@ read_console_w(HANDLE handle, DWORD maxlen, DWORD *readlen) { err = GetLastError(); break; } + if (n == (DWORD) - 1 && (err = GetLastError()) == ERROR_OPERATION_ABORTED) { + break; + } if (n == 0) { err = GetLastError(); if (err != ERROR_OPERATION_ABORTED) From c2dfff715acff81dcaf3d730c990180d4255ab7a Mon Sep 17 00:00:00 2001 From: ValeriyaSinevich Date: Mon, 25 Jun 2018 09:34:06 -0700 Subject: [PATCH 04/13] news --- .../next/Windows/2018-06-25-09-33-48.bpo-30237.EybiZA.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Windows/2018-06-25-09-33-48.bpo-30237.EybiZA.rst diff --git a/Misc/NEWS.d/next/Windows/2018-06-25-09-33-48.bpo-30237.EybiZA.rst b/Misc/NEWS.d/next/Windows/2018-06-25-09-33-48.bpo-30237.EybiZA.rst new file mode 100644 index 00000000000000..18aac756cb580a --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2018-06-25-09-33-48.bpo-30237.EybiZA.rst @@ -0,0 +1,2 @@ +Output error when ReadConsole is canceled by CancelSynchronousIo instead of +crashing. From 7145a7fde0e1095373951a868d7b85c8f53c52de Mon Sep 17 00:00:00 2001 From: ValeriyaSinevich Date: Mon, 25 Jun 2018 09:18:33 -0700 Subject: [PATCH 05/13] output error when ReadConsole is canceled by CancelSynchronousIo instead of crashing --- Modules/_io/winconsoleio.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c index 2bf48eb55532d8..2a1bb5c845d5fe 100644 --- a/Modules/_io/winconsoleio.c +++ b/Modules/_io/winconsoleio.c @@ -556,7 +556,8 @@ read_console_w(HANDLE handle, DWORD maxlen, DWORD *readlen) { Py_BEGIN_ALLOW_THREADS DWORD off = 0; while (off < maxlen) { - DWORD n, len = min(maxlen - off, BUFSIZ); + DWORD n = (DWORD) - 1; + DWORD len = min(maxlen - off, BUFSIZ); SetLastError(0); BOOL res = ReadConsoleW(handle, &buf[off], len, &n, NULL); @@ -564,6 +565,9 @@ read_console_w(HANDLE handle, DWORD maxlen, DWORD *readlen) { err = GetLastError(); break; } + if (n == (DWORD) - 1 && (err = GetLastError()) == ERROR_OPERATION_ABORTED) { + break; + } if (n == 0) { err = GetLastError(); if (err != ERROR_OPERATION_ABORTED) From 34e5061fdd01f4e17bb75ca7fe91fc7591ae6a1d Mon Sep 17 00:00:00 2001 From: ValeriyaSinevich Date: Mon, 25 Jun 2018 09:34:06 -0700 Subject: [PATCH 06/13] news --- .../next/Windows/2018-06-25-09-33-48.bpo-30237.EybiZA.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Windows/2018-06-25-09-33-48.bpo-30237.EybiZA.rst diff --git a/Misc/NEWS.d/next/Windows/2018-06-25-09-33-48.bpo-30237.EybiZA.rst b/Misc/NEWS.d/next/Windows/2018-06-25-09-33-48.bpo-30237.EybiZA.rst new file mode 100644 index 00000000000000..18aac756cb580a --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2018-06-25-09-33-48.bpo-30237.EybiZA.rst @@ -0,0 +1,2 @@ +Output error when ReadConsole is canceled by CancelSynchronousIo instead of +crashing. From 29dd01fa6c51e5549519ea310138a4f16574ff34 Mon Sep 17 00:00:00 2001 From: ValeriyaSinevich Date: Mon, 25 Jun 2018 10:15:14 -0700 Subject: [PATCH 07/13] output error in myreadline.c --- Parser/myreadline.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Parser/myreadline.c b/Parser/myreadline.c index ab6bd4e83000ae..3b2b3aee6f894d 100644 --- a/Parser/myreadline.c +++ b/Parser/myreadline.c @@ -109,7 +109,7 @@ _PyOS_WindowsConsoleReadline(HANDLE hStdIn) char *buf = NULL; int err = 0; - n_read = 0; + n_read = (DWORD) - 1; total_read = 0; wbuf = wbuf_local; wbuflen = sizeof(wbuf_local) / sizeof(wbuf_local[0]) - 1; @@ -118,6 +118,9 @@ _PyOS_WindowsConsoleReadline(HANDLE hStdIn) err = GetLastError(); goto exit; } + if (n_read == (DWORD) - 1 && (err = GetLastError()) == ERROR_OPERATION_ABORTED) { + break; + } if (n_read == 0) { int s; err = GetLastError(); From 79ca38a685054bcf7d2bba7d0c1e038f098458b6 Mon Sep 17 00:00:00 2001 From: ValeriyaSinevich Date: Thu, 19 Jul 2018 10:39:41 -0700 Subject: [PATCH 08/13] remove spaces around - --- Modules/_io/winconsoleio.c | 4 ++-- Parser/myreadline.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c index 2a1bb5c845d5fe..f08406643f0323 100644 --- a/Modules/_io/winconsoleio.c +++ b/Modules/_io/winconsoleio.c @@ -556,7 +556,7 @@ read_console_w(HANDLE handle, DWORD maxlen, DWORD *readlen) { Py_BEGIN_ALLOW_THREADS DWORD off = 0; while (off < maxlen) { - DWORD n = (DWORD) - 1; + DWORD n = (DWORD)-1; DWORD len = min(maxlen - off, BUFSIZ); SetLastError(0); BOOL res = ReadConsoleW(handle, &buf[off], len, &n, NULL); @@ -565,7 +565,7 @@ read_console_w(HANDLE handle, DWORD maxlen, DWORD *readlen) { err = GetLastError(); break; } - if (n == (DWORD) - 1 && (err = GetLastError()) == ERROR_OPERATION_ABORTED) { + if (n == (DWORD)-1 && (err = GetLastError()) == ERROR_OPERATION_ABORTED) { break; } if (n == 0) { diff --git a/Parser/myreadline.c b/Parser/myreadline.c index 3b2b3aee6f894d..fb92e0dd7bec4e 100644 --- a/Parser/myreadline.c +++ b/Parser/myreadline.c @@ -109,7 +109,7 @@ _PyOS_WindowsConsoleReadline(HANDLE hStdIn) char *buf = NULL; int err = 0; - n_read = (DWORD) - 1; + n_read = (DWORD)-1; total_read = 0; wbuf = wbuf_local; wbuflen = sizeof(wbuf_local) / sizeof(wbuf_local[0]) - 1; @@ -118,7 +118,7 @@ _PyOS_WindowsConsoleReadline(HANDLE hStdIn) err = GetLastError(); goto exit; } - if (n_read == (DWORD) - 1 && (err = GetLastError()) == ERROR_OPERATION_ABORTED) { + if (n_read == (DWORD)-1 && (err = GetLastError()) == ERROR_OPERATION_ABORTED) { break; } if (n_read == 0) { From d4c46829cc6cfd411e9734f80b1d613e5a944272 Mon Sep 17 00:00:00 2001 From: ValeriyaSinevich Date: Thu, 19 Jul 2018 16:33:40 -0700 Subject: [PATCH 09/13] Continue reading when SIGINT is ignored --- Modules/_io/winconsoleio.c | 6 ++++-- Parser/myreadline.c | 17 ++++++++++------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c index f08406643f0323..8f1d2a88c96dc1 100644 --- a/Modules/_io/winconsoleio.c +++ b/Modules/_io/winconsoleio.c @@ -574,14 +574,16 @@ read_console_w(HANDLE handle, DWORD maxlen, DWORD *readlen) { break; err = 0; HANDLE hInterruptEvent = _PyOS_SigintEvent(); - if (WaitForSingleObjectEx(hInterruptEvent, 100, FALSE) - == WAIT_OBJECT_0) { + DWORD state = WaitForSingleObjectEx(hInterruptEvent, 100, FALSE); + if (state == WAIT_OBJECT_0 || state == WAIT_TIMEOUT) { ResetEvent(hInterruptEvent); Py_BLOCK_THREADS sig = PyErr_CheckSignals(); Py_UNBLOCK_THREADS if (sig < 0) break; + else + continue; } } *readlen += n; diff --git a/Parser/myreadline.c b/Parser/myreadline.c index fb92e0dd7bec4e..12ca2434539434 100644 --- a/Parser/myreadline.c +++ b/Parser/myreadline.c @@ -18,7 +18,7 @@ PyThreadState* _PyOS_ReadlineTState = NULL; - + #include "pythread.h" static PyThread_type_lock _PyOS_ReadlineLock = NULL; @@ -124,19 +124,22 @@ _PyOS_WindowsConsoleReadline(HANDLE hStdIn) if (n_read == 0) { int s; err = GetLastError(); - if (err != ERROR_OPERATION_ABORTED) + if (err != ERROR_OPERATION_ABORTED) { goto exit; + } err = 0; HANDLE hInterruptEvent = _PyOS_SigintEvent(); - if (WaitForSingleObjectEx(hInterruptEvent, 100, FALSE) - == WAIT_OBJECT_0) { + DWORD state = WaitForSingleObjectEx(hInterruptEvent, 100, FALSE); + if (state == WAIT_OBJECT_0 || state == WAIT_TIMEOUT) { ResetEvent(hInterruptEvent); PyEval_RestoreThread(_PyOS_ReadlineTState); s = PyErr_CheckSignals(); PyEval_SaveThread(); - if (s < 0) - goto exit; - } + if (s < 0) + goto exit; + else + continue; + } break; } From 531e40bc394436e48d6a25e7996fb93e66a69df3 Mon Sep 17 00:00:00 2001 From: ValeriyaSinevich Date: Thu, 19 Jul 2018 16:38:04 -0700 Subject: [PATCH 10/13] news --- .../NEWS.d/next/Windows/2018-07-19-16-37-47.bpo-28166.bBdWo8.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Windows/2018-07-19-16-37-47.bpo-28166.bBdWo8.rst diff --git a/Misc/NEWS.d/next/Windows/2018-07-19-16-37-47.bpo-28166.bBdWo8.rst b/Misc/NEWS.d/next/Windows/2018-07-19-16-37-47.bpo-28166.bBdWo8.rst new file mode 100644 index 00000000000000..75b5128de4a765 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2018-07-19-16-37-47.bpo-28166.bBdWo8.rst @@ -0,0 +1 @@ +Continue reading when SIGINT is ignored. From 3c37a08e428e38e65766eaa68d3c145b0ff83c22 Mon Sep 17 00:00:00 2001 From: ValeriyaSinevich Date: Thu, 19 Jul 2018 18:16:55 -0700 Subject: [PATCH 11/13] remove trailing space --- Parser/myreadline.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Parser/myreadline.c b/Parser/myreadline.c index f60788916161d7..edbd7a1a805260 100644 --- a/Parser/myreadline.c +++ b/Parser/myreadline.c @@ -18,7 +18,7 @@ PyThreadState* _PyOS_ReadlineTState = NULL; - + #include "pythread.h" static PyThread_type_lock _PyOS_ReadlineLock = NULL; @@ -127,9 +127,8 @@ _PyOS_WindowsConsoleReadline(HANDLE hStdIn) if (n_read == 0) { int s; err = GetLastError(); - if (err != ERROR_OPERATION_ABORTED) { + if (err != ERROR_OPERATION_ABORTED) goto exit; - } err = 0; HANDLE hInterruptEvent = _PyOS_SigintEvent(); DWORD state = WaitForSingleObjectEx(hInterruptEvent, 100, FALSE); From 14eac500dc00e67d2c3442814eb04c923743a214 Mon Sep 17 00:00:00 2001 From: ValeriyaSinevich Date: Fri, 20 Jul 2018 07:14:20 -0700 Subject: [PATCH 12/13] trailing whitespace --- Modules/_io/winconsoleio.c | 1709 ++++++++++++++++++------------------ Parser/myreadline.c | 10 +- 2 files changed, 864 insertions(+), 855 deletions(-) diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c index 8f1d2a88c96dc1..5c8ff75d0e1613 100644 --- a/Modules/_io/winconsoleio.c +++ b/Modules/_io/winconsoleio.c @@ -1,9 +1,9 @@ /* - An implementation of Windows console I/O + An implementation of Windows console I/O - Classes defined here: _WindowsConsoleIO + Classes defined here: _WindowsConsoleIO - Written by Steve Dower + Written by Steve Dower */ #define PY_SSIZE_T_CLEAN @@ -36,7 +36,7 @@ #define SMALLCHUNK BUFSIZ #endif -/* BUFMAX determines how many bytes can be read in one go. */ + /* 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 @@ -45,92 +45,96 @@ #define SMALLBUF 4 char _get_console_type(HANDLE handle) { - DWORD mode, peek_count; + DWORD mode, peek_count; - if (handle == INVALID_HANDLE_VALUE) - return '\0'; + if (handle == INVALID_HANDLE_VALUE) + return '\0'; - if (!GetConsoleMode(handle, &mode)) - 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'; + /* 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; + 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; } @@ -141,19 +145,19 @@ class _io._WindowsConsoleIO "winconsoleio *" "&PyWindowsConsoleIO_Type" /*[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; + 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; @@ -163,7 +167,7 @@ _Py_IDENTIFIER(name); int _PyWindowsConsoleIO_closed(PyObject *self) { - return ((winconsoleio *)self)->handle == INVALID_HANDLE_VALUE; + return ((winconsoleio *)self)->handle == INVALID_HANDLE_VALUE; } @@ -171,19 +175,19 @@ _PyWindowsConsoleIO_closed(PyObject *self) 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; + 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] @@ -199,54 +203,54 @@ 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_CallMethodIdObjArgs((PyObject*)&PyRawIOBase_Type, - &PyId_close, self, NULL); - 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; + PyObject *res; + PyObject *exc, *val, *tb; + int rc; + _Py_IDENTIFIER(close); + res = _PyObject_CallMethodIdObjArgs((PyObject*)&PyRawIOBase_Type, + &PyId_close, self, NULL); + 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; + 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 + file as nameobj: object + mode: str = "r" + closefd: bool(accept={int}) = True + opener: object = None Open a console buffer by file descriptor. @@ -257,207 +261,208 @@ omitted. The *opener* parameter is always ignored. 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 *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; - } - - 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; - - 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; + 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; + + 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"); + PyErr_SetString(PyExc_ValueError, + "Must have exactly one of read or write mode"); error: - ret = -1; - internal_close(self); + ret = -1; + internal_close(self); done: - if (name) - PyMem_Free(name); - return ret; + if (name) + PyMem_Free(name); + return ret; } static int winconsoleio_traverse(winconsoleio *self, visitproc visit, void *arg) { - Py_VISIT(self->dict); - return 0; + Py_VISIT(self->dict); + return 0; } static int winconsoleio_clear(winconsoleio *self) { - Py_CLEAR(self->dict); - return 0; + 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); + 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; + 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; + _PyIO_State *state = IO_STATE(); + if (state != NULL) + PyErr_Format(state->unsupported_operation, + "Console buffer does not support %s", action); + return NULL; } /*[clinic input] @@ -474,17 +479,17 @@ 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); + 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] @@ -497,9 +502,9 @@ 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); + if (self->handle == INVALID_HANDLE_VALUE) + return err_closed(); + return PyBool_FromLong((long)self->readable); } /*[clinic input] @@ -512,236 +517,238 @@ 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); + 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; + 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; + 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; - } + 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; + 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(); + 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(); DWORD state = WaitForSingleObjectEx(hInterruptEvent, 100, FALSE); - if (state == WAIT_OBJECT_0 || state == WAIT_TIMEOUT) { - ResetEvent(hInterruptEvent); - Py_BLOCK_THREADS - sig = PyErr_CheckSignals(); - Py_UNBLOCK_THREADS - if (sig < 0) - break; - else - continue; - } - } - *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; + if (state == WAIT_OBJECT_0 || state == WAIT_TIMEOUT) { + ResetEvent(hInterruptEvent); + Py_BLOCK_THREADS + sig = PyErr_CheckSignals(); + Py_UNBLOCK_THREADS + if (sig < 0) + break; + else + continue; + } + } + *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; + 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; + 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}) - / + buffer: Py_buffer(accept={rwbuffer}) + / Same as RawIOBase.readinto(). [clinic start generated code]*/ @@ -750,29 +757,29 @@ 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; + Py_ssize_t len = readinto(self, buffer->buf, buffer->len); + if (len < 0) + return NULL; - return PyLong_FromSsize_t(len); + 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; + 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] @@ -787,118 +794,119 @@ 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; + 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: Py_ssize_t(accept={int, NoneType}) = -1 - / + size: Py_ssize_t(accept={int, NoneType}) = -1 + / Read at most size bytes, returned as bytes. @@ -911,45 +919,45 @@ 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; + 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 - / + b: Py_buffer + / Write buffer b to file, return number of bytes written. @@ -961,89 +969,90 @@ 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); + 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; + 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] @@ -1056,34 +1065,34 @@ 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(); + if (self->handle == INVALID_HANDLE_VALUE) + return err_closed(); - Py_RETURN_TRUE; + Py_RETURN_TRUE; } static PyObject * winconsoleio_getstate(winconsoleio *self, PyObject *Py_UNUSED(ignored)) { - PyErr_Format(PyExc_TypeError, - "cannot serialize '%s' object", Py_TYPE(self)->tp_name); - return NULL; + 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 */ + _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. */ @@ -1091,85 +1100,85 @@ static PyMethodDef winconsoleio_methods[] = { static PyObject * get_closed(winconsoleio *self, void *closure) { - return PyBool_FromLong((long)(self->handle == INVALID_HANDLE_VALUE)); + return PyBool_FromLong((long)(self->handle == INVALID_HANDLE_VALUE)); } static PyObject * get_closefd(winconsoleio *self, void *closure) { - return PyBool_FromLong((long)(self->closehandle)); + return PyBool_FromLong((long)(self->closehandle)); } static PyObject * get_mode(winconsoleio *self, void *closure) { - return PyUnicode_FromString(self->readable ? "rb" : "wb"); + 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}, + {"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} + {"_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 */ + 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; diff --git a/Parser/myreadline.c b/Parser/myreadline.c index edbd7a1a805260..55c96736bc3e35 100644 --- a/Parser/myreadline.c +++ b/Parser/myreadline.c @@ -132,11 +132,11 @@ _PyOS_WindowsConsoleReadline(HANDLE hStdIn) err = 0; HANDLE hInterruptEvent = _PyOS_SigintEvent(); DWORD state = WaitForSingleObjectEx(hInterruptEvent, 100, FALSE); - if (state == WAIT_OBJECT_0 || state == WAIT_TIMEOUT) { - ResetEvent(hInterruptEvent); - PyEval_RestoreThread(_PyOS_ReadlineTState); - s = PyErr_CheckSignals(); - PyEval_SaveThread(); + if (state == WAIT_OBJECT_0 || state == WAIT_TIMEOUT) { + ResetEvent(hInterruptEvent); + PyEval_RestoreThread(_PyOS_ReadlineTState); + s = PyErr_CheckSignals(); + PyEval_SaveThread(); if (s < 0) goto exit; else From 3d5be97bba543747fd7173e947d53efa6a5dc6b4 Mon Sep 17 00:00:00 2001 From: ValeriyaSinevich Date: Fri, 20 Jul 2018 07:21:12 -0700 Subject: [PATCH 13/13] remove unrelated changes --- Modules/_io/winconsoleio.c | 1707 ++++++++++++++++++------------------ 1 file changed, 849 insertions(+), 858 deletions(-) diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c index 5c8ff75d0e1613..b7b1f8cf813f59 100644 --- a/Modules/_io/winconsoleio.c +++ b/Modules/_io/winconsoleio.c @@ -1,9 +1,9 @@ /* - An implementation of Windows console I/O + An implementation of Windows console I/O - Classes defined here: _WindowsConsoleIO + Classes defined here: _WindowsConsoleIO - Written by Steve Dower + Written by Steve Dower */ #define PY_SSIZE_T_CLEAN @@ -36,7 +36,7 @@ #define SMALLCHUNK BUFSIZ #endif - /* BUFMAX determines how many bytes can be read in one go. */ +/* 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 @@ -45,96 +45,92 @@ #define SMALLBUF 4 char _get_console_type(HANDLE handle) { - DWORD mode, peek_count; + DWORD mode, peek_count; - if (handle == INVALID_HANDLE_VALUE) - return '\0'; + if (handle == INVALID_HANDLE_VALUE) + return '\0'; - if (!GetConsoleMode(handle, &mode)) - 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'; + /* 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; + 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; } @@ -145,19 +141,19 @@ class _io._WindowsConsoleIO "winconsoleio *" "&PyWindowsConsoleIO_Type" /*[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; + 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; @@ -167,7 +163,7 @@ _Py_IDENTIFIER(name); int _PyWindowsConsoleIO_closed(PyObject *self) { - return ((winconsoleio *)self)->handle == INVALID_HANDLE_VALUE; + return ((winconsoleio *)self)->handle == INVALID_HANDLE_VALUE; } @@ -175,19 +171,19 @@ _PyWindowsConsoleIO_closed(PyObject *self) 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; + 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] @@ -203,54 +199,54 @@ 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_CallMethodIdObjArgs((PyObject*)&PyRawIOBase_Type, - &PyId_close, self, NULL); - 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; + PyObject *res; + PyObject *exc, *val, *tb; + int rc; + _Py_IDENTIFIER(close); + res = _PyObject_CallMethodIdObjArgs((PyObject*)&PyRawIOBase_Type, + &PyId_close, self, NULL); + 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; + 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 + file as nameobj: object + mode: str = "r" + closefd: bool(accept={int}) = True + opener: object = None Open a console buffer by file descriptor. @@ -261,208 +257,207 @@ omitted. The *opener* parameter is always ignored. 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 *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; - } - - 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; - - 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; + 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; + + 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"); + PyErr_SetString(PyExc_ValueError, + "Must have exactly one of read or write mode"); error: - ret = -1; - internal_close(self); + ret = -1; + internal_close(self); done: - if (name) - PyMem_Free(name); - return ret; + if (name) + PyMem_Free(name); + return ret; } static int winconsoleio_traverse(winconsoleio *self, visitproc visit, void *arg) { - Py_VISIT(self->dict); - return 0; + Py_VISIT(self->dict); + return 0; } static int winconsoleio_clear(winconsoleio *self) { - Py_CLEAR(self->dict); - return 0; + 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); + 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; + 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; + _PyIO_State *state = IO_STATE(); + if (state != NULL) + PyErr_Format(state->unsupported_operation, + "Console buffer does not support %s", action); + return NULL; } /*[clinic input] @@ -479,17 +474,17 @@ 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); + 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] @@ -502,9 +497,9 @@ 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); + if (self->handle == INVALID_HANDLE_VALUE) + return err_closed(); + return PyBool_FromLong((long) self->readable); } /*[clinic input] @@ -517,238 +512,236 @@ 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); + 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; + 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; + 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; - } + 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; + 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(); + 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(); DWORD state = WaitForSingleObjectEx(hInterruptEvent, 100, FALSE); if (state == WAIT_OBJECT_0 || state == WAIT_TIMEOUT) { - ResetEvent(hInterruptEvent); - Py_BLOCK_THREADS - sig = PyErr_CheckSignals(); - Py_UNBLOCK_THREADS - if (sig < 0) - break; - else - continue; - } - } - *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; + ResetEvent(hInterruptEvent); + Py_BLOCK_THREADS + sig = PyErr_CheckSignals(); + Py_UNBLOCK_THREADS + if (sig < 0) + break; + else + continue; + } + } + *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; + 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; + 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}) - / + buffer: Py_buffer(accept={rwbuffer}) + / Same as RawIOBase.readinto(). [clinic start generated code]*/ @@ -757,29 +750,29 @@ 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; + Py_ssize_t len = readinto(self, buffer->buf, buffer->len); + if (len < 0) + return NULL; - return PyLong_FromSsize_t(len); + 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; + 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] @@ -794,119 +787,118 @@ 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; + 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: Py_ssize_t(accept={int, NoneType}) = -1 - / + size: Py_ssize_t(accept={int, NoneType}) = -1 + / Read at most size bytes, returned as bytes. @@ -919,45 +911,45 @@ 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; + 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 - / + b: Py_buffer + / Write buffer b to file, return number of bytes written. @@ -969,90 +961,89 @@ 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); + 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; + 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] @@ -1065,34 +1056,34 @@ 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(); + if (self->handle == INVALID_HANDLE_VALUE) + return err_closed(); - Py_RETURN_TRUE; + Py_RETURN_TRUE; } static PyObject * winconsoleio_getstate(winconsoleio *self, PyObject *Py_UNUSED(ignored)) { - PyErr_Format(PyExc_TypeError, - "cannot serialize '%s' object", Py_TYPE(self)->tp_name); - return NULL; + 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 */ + _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. */ @@ -1100,85 +1091,85 @@ static PyMethodDef winconsoleio_methods[] = { static PyObject * get_closed(winconsoleio *self, void *closure) { - return PyBool_FromLong((long)(self->handle == INVALID_HANDLE_VALUE)); + return PyBool_FromLong((long)(self->handle == INVALID_HANDLE_VALUE)); } static PyObject * get_closefd(winconsoleio *self, void *closure) { - return PyBool_FromLong((long)(self->closehandle)); + return PyBool_FromLong((long)(self->closehandle)); } static PyObject * get_mode(winconsoleio *self, void *closure) { - return PyUnicode_FromString(self->readable ? "rb" : "wb"); + 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}, + {"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} + {"_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 */ + 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;