xref: /third_party/python/PC/_testconsole.c (revision 7db96d56)
1/* Testing module for multi-phase initialization of extension modules (PEP 489)
2 */
3
4#ifndef Py_BUILD_CORE_BUILTIN
5#  define Py_BUILD_CORE_MODULE 1
6#endif
7
8#include "Python.h"
9
10#ifdef MS_WINDOWS
11
12#include "pycore_fileutils.h"     // _Py_get_osfhandle()
13#include "..\modules\_io\_iomodule.h"
14
15#define WIN32_LEAN_AND_MEAN
16#include <windows.h>
17#include <fcntl.h>
18
19 /* The full definition is in iomodule. We reproduce
20 enough here to get the fd, which is all we want. */
21typedef struct {
22    PyObject_HEAD
23    int fd;
24} winconsoleio;
25
26
27static int execfunc(PyObject *m)
28{
29    return 0;
30}
31
32PyModuleDef_Slot testconsole_slots[] = {
33    {Py_mod_exec, execfunc},
34    {0, NULL},
35};
36
37/*[clinic input]
38module _testconsole
39
40_testconsole.write_input
41    file: object
42    s: PyBytesObject
43
44Writes UTF-16-LE encoded bytes to the console as if typed by a user.
45[clinic start generated code]*/
46
47static PyObject *
48_testconsole_write_input_impl(PyObject *module, PyObject *file,
49                              PyBytesObject *s)
50/*[clinic end generated code: output=48f9563db34aedb3 input=4c774f2d05770bc6]*/
51{
52    INPUT_RECORD *rec = NULL;
53
54    if (!PyWindowsConsoleIO_Check(file)) {
55        PyErr_SetString(PyExc_TypeError, "expected raw console object");
56        return NULL;
57    }
58
59    const wchar_t *p = (const wchar_t *)PyBytes_AS_STRING(s);
60    DWORD size = (DWORD)PyBytes_GET_SIZE(s) / sizeof(wchar_t);
61
62    rec = (INPUT_RECORD*)PyMem_Calloc(size, sizeof(INPUT_RECORD));
63    if (!rec)
64        goto error;
65
66    INPUT_RECORD *prec = rec;
67    for (DWORD i = 0; i < size; ++i, ++p, ++prec) {
68        prec->EventType = KEY_EVENT;
69        prec->Event.KeyEvent.bKeyDown = TRUE;
70        prec->Event.KeyEvent.wRepeatCount = 1;
71        prec->Event.KeyEvent.uChar.UnicodeChar = *p;
72    }
73
74    HANDLE hInput = _Py_get_osfhandle(((winconsoleio*)file)->fd);
75    if (hInput == INVALID_HANDLE_VALUE)
76        goto error;
77
78    DWORD total = 0;
79    while (total < size) {
80        DWORD wrote;
81        if (!WriteConsoleInputW(hInput, &rec[total], (size - total), &wrote)) {
82            PyErr_SetFromWindowsErr(0);
83            goto error;
84        }
85        total += wrote;
86    }
87
88    PyMem_Free((void*)rec);
89
90    Py_RETURN_NONE;
91error:
92    if (rec)
93        PyMem_Free((void*)rec);
94    return NULL;
95}
96
97/*[clinic input]
98_testconsole.read_output
99    file: object
100
101Reads a str from the console as written to stdout.
102[clinic start generated code]*/
103
104static PyObject *
105_testconsole_read_output_impl(PyObject *module, PyObject *file)
106/*[clinic end generated code: output=876310d81a73e6d2 input=b3521f64b1b558e3]*/
107{
108    Py_RETURN_NONE;
109}
110
111#include "clinic\_testconsole.c.h"
112
113PyMethodDef testconsole_methods[] = {
114    _TESTCONSOLE_WRITE_INPUT_METHODDEF
115    _TESTCONSOLE_READ_OUTPUT_METHODDEF
116    {NULL, NULL}
117};
118
119static PyModuleDef testconsole_def = {
120    PyModuleDef_HEAD_INIT,                      /* m_base */
121    "_testconsole",                             /* m_name */
122    PyDoc_STR("Test module for the Windows console"), /* m_doc */
123    0,                                          /* m_size */
124    testconsole_methods,                        /* m_methods */
125    testconsole_slots,                          /* m_slots */
126    NULL,                                       /* m_traverse */
127    NULL,                                       /* m_clear */
128    NULL,                                       /* m_free */
129};
130
131PyMODINIT_FUNC
132PyInit__testconsole(PyObject *spec)
133{
134    return PyModuleDef_Init(&testconsole_def);
135}
136
137#endif /* MS_WINDOWS */
138