| 
									
										
										
										
											2016-10-03 09:04:58 -07:00
										 |  |  | /* Testing module for multi-phase initialization of extension modules (PEP 489)
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-03 08:30:55 -07:00
										 |  |  | // Need limited C API version 3.13 for Py_mod_gil
 | 
					
						
							| 
									
										
										
										
											2024-03-21 17:45:43 +01:00
										 |  |  | #include "pyconfig.h"   // Py_GIL_DISABLED
 | 
					
						
							|  |  |  | #ifndef Py_GIL_DISABLED
 | 
					
						
							| 
									
										
										
										
											2024-05-03 08:30:55 -07:00
										 |  |  | #  define Py_LIMITED_API 0x030d0000
 | 
					
						
							| 
									
										
										
										
											2022-01-12 00:35:26 +01:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-03 09:04:58 -07:00
										 |  |  | #include "Python.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef MS_WINDOWS
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define WIN32_LEAN_AND_MEAN
 | 
					
						
							|  |  |  | #include <windows.h>
 | 
					
						
							|  |  |  | #include <fcntl.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  /* The full definition is in iomodule. We reproduce
 | 
					
						
							| 
									
										
										
										
											2021-04-24 01:00:27 +03:00
										 |  |  |  enough here to get the fd, which is all we want. */ | 
					
						
							| 
									
										
										
										
											2016-10-03 09:04:58 -07:00
										 |  |  | typedef struct { | 
					
						
							|  |  |  |     PyObject_HEAD | 
					
						
							| 
									
										
										
										
											2021-04-24 01:00:27 +03:00
										 |  |  |     int fd; | 
					
						
							| 
									
										
										
										
											2016-10-03 09:04:58 -07:00
										 |  |  | } winconsoleio; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int execfunc(PyObject *m) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PyModuleDef_Slot testconsole_slots[] = { | 
					
						
							|  |  |  |     {Py_mod_exec, execfunc}, | 
					
						
							| 
									
										
										
										
											2023-05-05 15:11:27 -06:00
										 |  |  |     {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, | 
					
						
							| 
									
										
										
										
											2024-05-03 08:30:55 -07:00
										 |  |  |     {Py_mod_gil, Py_MOD_GIL_NOT_USED}, | 
					
						
							| 
									
										
										
										
											2016-10-03 09:04:58 -07:00
										 |  |  |     {0, NULL}, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-22 08:19:48 +08:00
										 |  |  | /*[python input]
 | 
					
						
							|  |  |  | class HANDLE_converter(CConverter): | 
					
						
							|  |  |  |     type = 'void *' | 
					
						
							|  |  |  |     format_unit = '"_Py_PARSE_UINTPTR"' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def parse_arg(self, argname, displayname, *, limited_capi): | 
					
						
							|  |  |  |         return self.format_code(""" | 
					
						
							|  |  |  |             {paramname} = PyLong_AsVoidPtr({argname}); | 
					
						
							|  |  |  |             if (!{paramname} && PyErr_Occurred()) {{{{ | 
					
						
							|  |  |  |                 goto exit; | 
					
						
							|  |  |  |             }}}} | 
					
						
							|  |  |  |             """, | 
					
						
							|  |  |  |             argname=argname) | 
					
						
							|  |  |  | [python start generated code]*/ | 
					
						
							|  |  |  | /*[python end generated code: output=da39a3ee5e6b4b0d input=380aa5c91076742b]*/ | 
					
						
							|  |  |  | /*[python end generated code:]*/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-03 09:04:58 -07:00
										 |  |  | /*[clinic input]
 | 
					
						
							|  |  |  | module _testconsole | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _testconsole.write_input | 
					
						
							|  |  |  |     file: object | 
					
						
							| 
									
										
										
										
											2024-03-21 17:45:43 +01:00
										 |  |  |     s: Py_buffer | 
					
						
							| 
									
										
										
										
											2016-10-03 09:04:58 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | Writes UTF-16-LE encoded bytes to the console as if typed by a user. | 
					
						
							|  |  |  | [clinic start generated code]*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							| 
									
										
										
										
											2024-03-21 17:45:43 +01:00
										 |  |  | _testconsole_write_input_impl(PyObject *module, PyObject *file, Py_buffer *s) | 
					
						
							|  |  |  | /*[clinic end generated code: output=58631a8985426ad3 input=68062f1bb2e52206]*/ | 
					
						
							| 
									
										
										
										
											2016-10-03 09:04:58 -07:00
										 |  |  | { | 
					
						
							|  |  |  |     INPUT_RECORD *rec = NULL; | 
					
						
							| 
									
										
										
										
											2017-09-14 09:38:36 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-21 17:45:43 +01:00
										 |  |  |     PyObject *mod = PyImport_ImportModule("_io"); | 
					
						
							|  |  |  |     if (mod == NULL) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     PyTypeObject *winconsoleio_type = (PyTypeObject *)PyObject_GetAttrString(mod, "_WindowsConsoleIO"); | 
					
						
							|  |  |  |     Py_DECREF(mod); | 
					
						
							| 
									
										
										
										
											2023-02-15 14:07:59 +01:00
										 |  |  |     if (winconsoleio_type == NULL) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     int is_subclass = PyObject_TypeCheck(file, winconsoleio_type); | 
					
						
							|  |  |  |     Py_DECREF(winconsoleio_type); | 
					
						
							|  |  |  |     if (!is_subclass) { | 
					
						
							| 
									
										
										
										
											2016-10-03 09:04:58 -07:00
										 |  |  |         PyErr_SetString(PyExc_TypeError, "expected raw console object"); | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-21 17:45:43 +01:00
										 |  |  |     const wchar_t *p = (const wchar_t *)s->buf; | 
					
						
							|  |  |  |     DWORD size = (DWORD)s->len / sizeof(wchar_t); | 
					
						
							| 
									
										
										
										
											2016-10-03 09:04:58 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-24 23:26:44 -05:00
										 |  |  |     rec = (INPUT_RECORD*)PyMem_Calloc(size, sizeof(INPUT_RECORD)); | 
					
						
							| 
									
										
										
										
											2016-10-03 09:04:58 -07:00
										 |  |  |     if (!rec) | 
					
						
							|  |  |  |         goto error; | 
					
						
							| 
									
										
										
										
											2017-09-14 09:38:36 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-03 09:04:58 -07:00
										 |  |  |     INPUT_RECORD *prec = rec; | 
					
						
							|  |  |  |     for (DWORD i = 0; i < size; ++i, ++p, ++prec) { | 
					
						
							|  |  |  |         prec->EventType = KEY_EVENT; | 
					
						
							|  |  |  |         prec->Event.KeyEvent.bKeyDown = TRUE; | 
					
						
							| 
									
										
										
										
											2020-09-12 01:51:52 -04:00
										 |  |  |         prec->Event.KeyEvent.wRepeatCount = 1; | 
					
						
							| 
									
										
										
										
											2016-10-03 09:04:58 -07:00
										 |  |  |         prec->Event.KeyEvent.uChar.UnicodeChar = *p; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-21 17:45:43 +01:00
										 |  |  |     HANDLE hInput = (HANDLE)_get_osfhandle(((winconsoleio*)file)->fd); | 
					
						
							|  |  |  |     if (hInput == INVALID_HANDLE_VALUE) { | 
					
						
							|  |  |  |         PyErr_SetFromErrno(PyExc_OSError); | 
					
						
							| 
									
										
										
										
											2021-04-24 01:00:27 +03:00
										 |  |  |         goto error; | 
					
						
							| 
									
										
										
										
											2024-03-21 17:45:43 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-04-24 01:00:27 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-03 09:04:58 -07:00
										 |  |  |     DWORD total = 0; | 
					
						
							|  |  |  |     while (total < size) { | 
					
						
							|  |  |  |         DWORD wrote; | 
					
						
							|  |  |  |         if (!WriteConsoleInputW(hInput, &rec[total], (size - total), &wrote)) { | 
					
						
							|  |  |  |             PyErr_SetFromWindowsErr(0); | 
					
						
							|  |  |  |             goto error; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         total += wrote; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     PyMem_Free((void*)rec); | 
					
						
							| 
									
										
										
										
											2017-09-14 09:38:36 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-03 09:04:58 -07:00
										 |  |  |     Py_RETURN_NONE; | 
					
						
							|  |  |  | error: | 
					
						
							|  |  |  |     if (rec) | 
					
						
							|  |  |  |         PyMem_Free((void*)rec); | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*[clinic input]
 | 
					
						
							|  |  |  | _testconsole.read_output | 
					
						
							|  |  |  |     file: object | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Reads a str from the console as written to stdout. | 
					
						
							|  |  |  | [clinic start generated code]*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							|  |  |  | _testconsole_read_output_impl(PyObject *module, PyObject *file) | 
					
						
							|  |  |  | /*[clinic end generated code: output=876310d81a73e6d2 input=b3521f64b1b558e3]*/ | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     Py_RETURN_NONE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-22 08:19:48 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-03 09:04:58 -07:00
										 |  |  | #include "clinic\_testconsole.c.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PyMethodDef testconsole_methods[] = { | 
					
						
							|  |  |  |     _TESTCONSOLE_WRITE_INPUT_METHODDEF | 
					
						
							|  |  |  |     _TESTCONSOLE_READ_OUTPUT_METHODDEF | 
					
						
							|  |  |  |     {NULL, NULL} | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyModuleDef testconsole_def = { | 
					
						
							|  |  |  |     PyModuleDef_HEAD_INIT,                      /* m_base */ | 
					
						
							|  |  |  |     "_testconsole",                             /* m_name */ | 
					
						
							|  |  |  |     PyDoc_STR("Test module for the Windows console"), /* m_doc */ | 
					
						
							|  |  |  |     0,                                          /* m_size */ | 
					
						
							|  |  |  |     testconsole_methods,                        /* m_methods */ | 
					
						
							|  |  |  |     testconsole_slots,                          /* m_slots */ | 
					
						
							|  |  |  |     NULL,                                       /* m_traverse */ | 
					
						
							|  |  |  |     NULL,                                       /* m_clear */ | 
					
						
							|  |  |  |     NULL,                                       /* m_free */ | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PyMODINIT_FUNC | 
					
						
							|  |  |  | PyInit__testconsole(PyObject *spec) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return PyModuleDef_Init(&testconsole_def); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif /* MS_WINDOWS */
 |