xref: /third_party/python/PC/msvcrtmodule.c (revision 7db96d56)
1/*********************************************************
2
3    msvcrtmodule.c
4
5    A Python interface to the Microsoft Visual C Runtime
6    Library, providing access to those non-portable, but
7    still useful routines.
8
9    Only ever compiled with an MS compiler, so no attempt
10    has been made to avoid MS language extensions, etc...
11
12    This may only work on NT or 95...
13
14    Author: Mark Hammond and Guido van Rossum.
15    Maintenance: Guido van Rossum.
16
17***********************************************************/
18
19#include "Python.h"
20#include "pycore_fileutils.h"     // _Py_BEGIN_SUPPRESS_IPH
21#include "malloc.h"
22#include <io.h>
23#include <conio.h>
24#include <sys/locking.h>
25#include <crtdbg.h>
26#include <windows.h>
27
28#ifdef _MSC_VER
29#if _MSC_VER >= 1500 && _MSC_VER < 1600
30#include <crtassem.h>
31#elif _MSC_VER >= 1600
32#include <crtversion.h>
33#endif
34#endif
35
36/*[python input]
37class HANDLE_converter(CConverter):
38    type = 'void *'
39    format_unit = '"_Py_PARSE_UINTPTR"'
40
41class HANDLE_return_converter(CReturnConverter):
42    type = 'void *'
43
44    def render(self, function, data):
45        self.declare(data)
46        self.err_occurred_if(
47            "_return_value == NULL || _return_value == INVALID_HANDLE_VALUE",
48            data)
49        data.return_conversion.append(
50            'return_value = PyLong_FromVoidPtr(_return_value);\n')
51
52class byte_char_return_converter(CReturnConverter):
53    type = 'int'
54
55    def render(self, function, data):
56        data.declarations.append('char s[1];')
57        data.return_value = 's[0]'
58        data.return_conversion.append(
59            'return_value = PyBytes_FromStringAndSize(s, 1);\n')
60
61class wchar_t_return_converter(CReturnConverter):
62    type = 'wchar_t'
63
64    def render(self, function, data):
65        self.declare(data)
66        data.return_conversion.append(
67            'return_value = PyUnicode_FromOrdinal(_return_value);\n')
68[python start generated code]*/
69/*[python end generated code: output=da39a3ee5e6b4b0d input=d102511df3cda2eb]*/
70
71/*[clinic input]
72module msvcrt
73[clinic start generated code]*/
74/*[clinic end generated code: output=da39a3ee5e6b4b0d input=f31a87a783d036cd]*/
75
76#include "clinic/msvcrtmodule.c.h"
77
78/*[clinic input]
79msvcrt.heapmin
80
81Minimize the malloc() heap.
82
83Force the malloc() heap to clean itself up and return unused blocks
84to the operating system. On failure, this raises OSError.
85[clinic start generated code]*/
86
87static PyObject *
88msvcrt_heapmin_impl(PyObject *module)
89/*[clinic end generated code: output=1ba00f344782dc19 input=82e1771d21bde2d8]*/
90{
91    if (_heapmin() != 0)
92        return PyErr_SetFromErrno(PyExc_OSError);
93
94    Py_RETURN_NONE;
95}
96/*[clinic input]
97msvcrt.locking
98
99    fd: int
100    mode: int
101    nbytes: long
102    /
103
104Lock part of a file based on file descriptor fd from the C runtime.
105
106Raises OSError on failure. The locked region of the file extends from
107the current file position for nbytes bytes, and may continue beyond
108the end of the file. mode must be one of the LK_* constants listed
109below. Multiple regions in a file may be locked at the same time, but
110may not overlap. Adjacent regions are not merged; they must be unlocked
111individually.
112[clinic start generated code]*/
113
114static PyObject *
115msvcrt_locking_impl(PyObject *module, int fd, int mode, long nbytes)
116/*[clinic end generated code: output=a4a90deca9785a03 input=e97bd15fc4a04fef]*/
117{
118    int err;
119
120    if (PySys_Audit("msvcrt.locking", "iil", fd, mode, nbytes) < 0) {
121        return NULL;
122    }
123
124    Py_BEGIN_ALLOW_THREADS
125    _Py_BEGIN_SUPPRESS_IPH
126    err = _locking(fd, mode, nbytes);
127    _Py_END_SUPPRESS_IPH
128    Py_END_ALLOW_THREADS
129    if (err != 0)
130        return PyErr_SetFromErrno(PyExc_OSError);
131
132    Py_RETURN_NONE;
133}
134
135/*[clinic input]
136msvcrt.setmode -> long
137
138    fd: int
139    mode as flags: int
140    /
141
142Set the line-end translation mode for the file descriptor fd.
143
144To set it to text mode, flags should be os.O_TEXT; for binary, it
145should be os.O_BINARY.
146
147Return value is the previous mode.
148[clinic start generated code]*/
149
150static long
151msvcrt_setmode_impl(PyObject *module, int fd, int flags)
152/*[clinic end generated code: output=24a9be5ea07ccb9b input=76e7c01f6b137f75]*/
153{
154    _Py_BEGIN_SUPPRESS_IPH
155    flags = _setmode(fd, flags);
156    _Py_END_SUPPRESS_IPH
157    if (flags == -1)
158        PyErr_SetFromErrno(PyExc_OSError);
159
160    return flags;
161}
162
163/*[clinic input]
164msvcrt.open_osfhandle -> long
165
166    handle: HANDLE
167    flags: int
168    /
169
170Create a C runtime file descriptor from the file handle handle.
171
172The flags parameter should be a bitwise OR of os.O_APPEND, os.O_RDONLY,
173and os.O_TEXT. The returned file descriptor may be used as a parameter
174to os.fdopen() to create a file object.
175[clinic start generated code]*/
176
177static long
178msvcrt_open_osfhandle_impl(PyObject *module, void *handle, int flags)
179/*[clinic end generated code: output=b2fb97c4b515e4e6 input=d5db190a307cf4bb]*/
180{
181    if (PySys_Audit("msvcrt.open_osfhandle", "Ki", handle, flags) < 0) {
182        return -1;
183    }
184
185    return _Py_open_osfhandle(handle, flags);
186}
187
188/*[clinic input]
189msvcrt.get_osfhandle -> HANDLE
190
191    fd: int
192    /
193
194Return the file handle for the file descriptor fd.
195
196Raises OSError if fd is not recognized.
197[clinic start generated code]*/
198
199static void *
200msvcrt_get_osfhandle_impl(PyObject *module, int fd)
201/*[clinic end generated code: output=aca01dfe24637374 input=5fcfde9b17136aa2]*/
202{
203    if (PySys_Audit("msvcrt.get_osfhandle", "(i)", fd) < 0) {
204        return NULL;
205    }
206
207    return _Py_get_osfhandle(fd);
208}
209
210/* Console I/O */
211/*[clinic input]
212msvcrt.kbhit -> long
213
214Return true if a keypress is waiting to be read.
215[clinic start generated code]*/
216
217static long
218msvcrt_kbhit_impl(PyObject *module)
219/*[clinic end generated code: output=940dfce6587c1890 input=e70d678a5c2f6acc]*/
220{
221    return _kbhit();
222}
223
224/*[clinic input]
225msvcrt.getch -> byte_char
226
227Read a keypress and return the resulting character as a byte string.
228
229Nothing is echoed to the console. This call will block if a keypress is
230not already available, but will not wait for Enter to be pressed. If the
231pressed key was a special function key, this will return '\000' or
232'\xe0'; the next call will return the keycode. The Control-C keypress
233cannot be read with this function.
234[clinic start generated code]*/
235
236static int
237msvcrt_getch_impl(PyObject *module)
238/*[clinic end generated code: output=a4e51f0565064a7d input=37a40cf0ed0d1153]*/
239{
240    int ch;
241
242    Py_BEGIN_ALLOW_THREADS
243    ch = _getch();
244    Py_END_ALLOW_THREADS
245    return ch;
246}
247
248/*[clinic input]
249msvcrt.getwch -> wchar_t
250
251Wide char variant of getch(), returning a Unicode value.
252[clinic start generated code]*/
253
254static wchar_t
255msvcrt_getwch_impl(PyObject *module)
256/*[clinic end generated code: output=be9937494e22f007 input=27b3dec8ad823d7c]*/
257{
258    wchar_t ch;
259
260    Py_BEGIN_ALLOW_THREADS
261    ch = _getwch();
262    Py_END_ALLOW_THREADS
263    return ch;
264}
265
266/*[clinic input]
267msvcrt.getche -> byte_char
268
269Similar to getch(), but the keypress will be echoed if possible.
270[clinic start generated code]*/
271
272static int
273msvcrt_getche_impl(PyObject *module)
274/*[clinic end generated code: output=d8f7db4fd2990401 input=43311ade9ed4a9c0]*/
275{
276    int ch;
277
278    Py_BEGIN_ALLOW_THREADS
279    ch = _getche();
280    Py_END_ALLOW_THREADS
281    return ch;
282}
283
284/*[clinic input]
285msvcrt.getwche -> wchar_t
286
287Wide char variant of getche(), returning a Unicode value.
288[clinic start generated code]*/
289
290static wchar_t
291msvcrt_getwche_impl(PyObject *module)
292/*[clinic end generated code: output=d0dae5ba3829d596 input=49337d59d1a591f8]*/
293{
294    wchar_t ch;
295
296    Py_BEGIN_ALLOW_THREADS
297    ch = _getwche();
298    Py_END_ALLOW_THREADS
299    return ch;
300}
301
302/*[clinic input]
303msvcrt.putch
304
305    char: char
306    /
307
308Print the byte string char to the console without buffering.
309[clinic start generated code]*/
310
311static PyObject *
312msvcrt_putch_impl(PyObject *module, char char_value)
313/*[clinic end generated code: output=92ec9b81012d8f60 input=ec078dd10cb054d6]*/
314{
315    _Py_BEGIN_SUPPRESS_IPH
316    _putch(char_value);
317    _Py_END_SUPPRESS_IPH
318    Py_RETURN_NONE;
319}
320
321/*[clinic input]
322msvcrt.putwch
323
324    unicode_char: int(accept={str})
325    /
326
327Wide char variant of putch(), accepting a Unicode value.
328[clinic start generated code]*/
329
330static PyObject *
331msvcrt_putwch_impl(PyObject *module, int unicode_char)
332/*[clinic end generated code: output=a3bd1a8951d28eee input=996ccd0bbcbac4c3]*/
333{
334    _Py_BEGIN_SUPPRESS_IPH
335    _putwch(unicode_char);
336    _Py_END_SUPPRESS_IPH
337    Py_RETURN_NONE;
338
339}
340
341/*[clinic input]
342msvcrt.ungetch
343
344    char: char
345    /
346
347Opposite of getch.
348
349Cause the byte string char to be "pushed back" into the
350console buffer; it will be the next character read by
351getch() or getche().
352[clinic start generated code]*/
353
354static PyObject *
355msvcrt_ungetch_impl(PyObject *module, char char_value)
356/*[clinic end generated code: output=c6942a0efa119000 input=22f07ee9001bbf0f]*/
357{
358    int res;
359
360    _Py_BEGIN_SUPPRESS_IPH
361    res = _ungetch(char_value);
362    _Py_END_SUPPRESS_IPH
363
364    if (res == EOF)
365        return PyErr_SetFromErrno(PyExc_OSError);
366    Py_RETURN_NONE;
367}
368
369/*[clinic input]
370msvcrt.ungetwch
371
372    unicode_char: int(accept={str})
373    /
374
375Wide char variant of ungetch(), accepting a Unicode value.
376[clinic start generated code]*/
377
378static PyObject *
379msvcrt_ungetwch_impl(PyObject *module, int unicode_char)
380/*[clinic end generated code: output=e63af05438b8ba3d input=83ec0492be04d564]*/
381{
382    int res;
383
384    _Py_BEGIN_SUPPRESS_IPH
385    res = _ungetwch(unicode_char);
386    _Py_END_SUPPRESS_IPH
387
388    if (res == WEOF)
389        return PyErr_SetFromErrno(PyExc_OSError);
390    Py_RETURN_NONE;
391}
392
393#ifdef _DEBUG
394/*[clinic input]
395msvcrt.CrtSetReportFile -> HANDLE
396
397    type: int
398    file: HANDLE
399    /
400
401Wrapper around _CrtSetReportFile.
402
403Only available on Debug builds.
404[clinic start generated code]*/
405
406static void *
407msvcrt_CrtSetReportFile_impl(PyObject *module, int type, void *file)
408/*[clinic end generated code: output=9393e8c77088bbe9 input=290809b5f19e65b9]*/
409{
410    HANDLE res;
411
412    _Py_BEGIN_SUPPRESS_IPH
413    res = _CrtSetReportFile(type, file);
414    _Py_END_SUPPRESS_IPH
415
416    return res;
417}
418
419/*[clinic input]
420msvcrt.CrtSetReportMode -> long
421
422    type: int
423    mode: int
424    /
425
426Wrapper around _CrtSetReportMode.
427
428Only available on Debug builds.
429[clinic start generated code]*/
430
431static long
432msvcrt_CrtSetReportMode_impl(PyObject *module, int type, int mode)
433/*[clinic end generated code: output=b2863761523de317 input=9319d29b4319426b]*/
434{
435    int res;
436
437    _Py_BEGIN_SUPPRESS_IPH
438    res = _CrtSetReportMode(type, mode);
439    _Py_END_SUPPRESS_IPH
440    if (res == -1)
441        PyErr_SetFromErrno(PyExc_OSError);
442    return res;
443}
444
445/*[clinic input]
446msvcrt.set_error_mode -> long
447
448    mode: int
449    /
450
451Wrapper around _set_error_mode.
452
453Only available on Debug builds.
454[clinic start generated code]*/
455
456static long
457msvcrt_set_error_mode_impl(PyObject *module, int mode)
458/*[clinic end generated code: output=ac4a09040d8ac4e3 input=046fca59c0f20872]*/
459{
460    long res;
461
462    _Py_BEGIN_SUPPRESS_IPH
463    res = _set_error_mode(mode);
464    _Py_END_SUPPRESS_IPH
465
466    return res;
467}
468#endif /* _DEBUG */
469
470/*[clinic input]
471msvcrt.GetErrorMode
472
473Wrapper around GetErrorMode.
474[clinic start generated code]*/
475
476static PyObject *
477msvcrt_GetErrorMode_impl(PyObject *module)
478/*[clinic end generated code: output=3103fc6145913591 input=5a7fb083b6dd71fd]*/
479{
480    unsigned int res;
481
482    _Py_BEGIN_SUPPRESS_IPH
483    res = GetErrorMode();
484    _Py_END_SUPPRESS_IPH
485
486    return PyLong_FromUnsignedLong(res);
487}
488
489/*[clinic input]
490msvcrt.SetErrorMode
491
492    mode: unsigned_int(bitwise=True)
493    /
494
495Wrapper around SetErrorMode.
496[clinic start generated code]*/
497
498static PyObject *
499msvcrt_SetErrorMode_impl(PyObject *module, unsigned int mode)
500/*[clinic end generated code: output=01d529293f00da8f input=d8b167258d32d907]*/
501{
502    unsigned int res;
503
504    _Py_BEGIN_SUPPRESS_IPH
505    res = SetErrorMode(mode);
506    _Py_END_SUPPRESS_IPH
507
508    return PyLong_FromUnsignedLong(res);
509}
510
511/*[clinic input]
512[clinic start generated code]*/
513/*[clinic end generated code: output=da39a3ee5e6b4b0d input=da39a3ee5e6b4b0d]*/
514
515/* List of functions exported by this module */
516static struct PyMethodDef msvcrt_functions[] = {
517    MSVCRT_HEAPMIN_METHODDEF
518    MSVCRT_LOCKING_METHODDEF
519    MSVCRT_SETMODE_METHODDEF
520    MSVCRT_OPEN_OSFHANDLE_METHODDEF
521    MSVCRT_GET_OSFHANDLE_METHODDEF
522    MSVCRT_KBHIT_METHODDEF
523    MSVCRT_GETCH_METHODDEF
524    MSVCRT_GETCHE_METHODDEF
525    MSVCRT_PUTCH_METHODDEF
526    MSVCRT_UNGETCH_METHODDEF
527    MSVCRT_GETERRORMODE_METHODDEF
528    MSVCRT_SETERRORMODE_METHODDEF
529    MSVCRT_CRTSETREPORTFILE_METHODDEF
530    MSVCRT_CRTSETREPORTMODE_METHODDEF
531    MSVCRT_SET_ERROR_MODE_METHODDEF
532    MSVCRT_GETWCH_METHODDEF
533    MSVCRT_GETWCHE_METHODDEF
534    MSVCRT_PUTWCH_METHODDEF
535    MSVCRT_UNGETWCH_METHODDEF
536    {NULL,                      NULL}
537};
538
539
540static struct PyModuleDef msvcrtmodule = {
541    PyModuleDef_HEAD_INIT,
542    "msvcrt",
543    NULL,
544    -1,
545    msvcrt_functions,
546    NULL,
547    NULL,
548    NULL,
549    NULL
550};
551
552static void
553insertint(PyObject *d, char *name, int value)
554{
555    PyObject *v = PyLong_FromLong((long) value);
556    if (v == NULL) {
557        /* Don't bother reporting this error */
558        PyErr_Clear();
559    }
560    else {
561        PyDict_SetItemString(d, name, v);
562        Py_DECREF(v);
563    }
564}
565
566static void
567insertptr(PyObject *d, char *name, void *value)
568{
569    PyObject *v = PyLong_FromVoidPtr(value);
570    if (v == NULL) {
571        /* Don't bother reporting this error */
572        PyErr_Clear();
573    }
574    else {
575        PyDict_SetItemString(d, name, v);
576        Py_DECREF(v);
577    }
578}
579
580PyMODINIT_FUNC
581PyInit_msvcrt(void)
582{
583    int st;
584    PyObject *d, *version;
585    PyObject *m = PyModule_Create(&msvcrtmodule);
586    if (m == NULL)
587        return NULL;
588    d = PyModule_GetDict(m);
589
590    /* constants for the locking() function's mode argument */
591    insertint(d, "LK_LOCK", _LK_LOCK);
592    insertint(d, "LK_NBLCK", _LK_NBLCK);
593    insertint(d, "LK_NBRLCK", _LK_NBRLCK);
594    insertint(d, "LK_RLCK", _LK_RLCK);
595    insertint(d, "LK_UNLCK", _LK_UNLCK);
596    insertint(d, "SEM_FAILCRITICALERRORS", SEM_FAILCRITICALERRORS);
597    insertint(d, "SEM_NOALIGNMENTFAULTEXCEPT", SEM_NOALIGNMENTFAULTEXCEPT);
598    insertint(d, "SEM_NOGPFAULTERRORBOX", SEM_NOGPFAULTERRORBOX);
599    insertint(d, "SEM_NOOPENFILEERRORBOX", SEM_NOOPENFILEERRORBOX);
600#ifdef _DEBUG
601    insertint(d, "CRT_WARN", _CRT_WARN);
602    insertint(d, "CRT_ERROR", _CRT_ERROR);
603    insertint(d, "CRT_ASSERT", _CRT_ASSERT);
604    insertint(d, "CRTDBG_MODE_DEBUG", _CRTDBG_MODE_DEBUG);
605    insertint(d, "CRTDBG_MODE_FILE", _CRTDBG_MODE_FILE);
606    insertint(d, "CRTDBG_MODE_WNDW", _CRTDBG_MODE_WNDW);
607    insertint(d, "CRTDBG_REPORT_MODE", _CRTDBG_REPORT_MODE);
608    insertptr(d, "CRTDBG_FILE_STDERR", _CRTDBG_FILE_STDERR);
609    insertptr(d, "CRTDBG_FILE_STDOUT", _CRTDBG_FILE_STDOUT);
610    insertptr(d, "CRTDBG_REPORT_FILE", _CRTDBG_REPORT_FILE);
611#endif
612
613    /* constants for the crt versions */
614#ifdef _VC_ASSEMBLY_PUBLICKEYTOKEN
615    st = PyModule_AddStringConstant(m, "VC_ASSEMBLY_PUBLICKEYTOKEN",
616                                    _VC_ASSEMBLY_PUBLICKEYTOKEN);
617    if (st < 0) return NULL;
618#endif
619#ifdef _CRT_ASSEMBLY_VERSION
620    st = PyModule_AddStringConstant(m, "CRT_ASSEMBLY_VERSION",
621                                    _CRT_ASSEMBLY_VERSION);
622    if (st < 0) return NULL;
623#endif
624#ifdef __LIBRARIES_ASSEMBLY_NAME_PREFIX
625    st = PyModule_AddStringConstant(m, "LIBRARIES_ASSEMBLY_NAME_PREFIX",
626                                    __LIBRARIES_ASSEMBLY_NAME_PREFIX);
627    if (st < 0) return NULL;
628#endif
629
630    /* constants for the 2010 crt versions */
631#if defined(_VC_CRT_MAJOR_VERSION) && defined (_VC_CRT_MINOR_VERSION) && defined(_VC_CRT_BUILD_VERSION) && defined(_VC_CRT_RBUILD_VERSION)
632    version = PyUnicode_FromFormat("%d.%d.%d.%d", _VC_CRT_MAJOR_VERSION,
633                                                  _VC_CRT_MINOR_VERSION,
634                                                  _VC_CRT_BUILD_VERSION,
635                                                  _VC_CRT_RBUILD_VERSION);
636    st = PyModule_AddObject(m, "CRT_ASSEMBLY_VERSION", version);
637    if (st < 0) return NULL;
638#endif
639    /* make compiler warning quiet if st is unused */
640    (void)st;
641
642    return m;
643}
644