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