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 class 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 
52 class 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 
61 class 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]
72 module 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]
79 msvcrt.heapmin
80 
81 Minimize the malloc() heap.
82 
83 Force the malloc() heap to clean itself up and return unused blocks
84 to the operating system. On failure, this raises OSError.
85 [clinic start generated code]*/
86 
87 static PyObject *
msvcrt_heapmin_impl(PyObject * module)88 msvcrt_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]
97 msvcrt.locking
98 
99     fd: int
100     mode: int
101     nbytes: long
102     /
103 
104 Lock part of a file based on file descriptor fd from the C runtime.
105 
106 Raises OSError on failure. The locked region of the file extends from
107 the current file position for nbytes bytes, and may continue beyond
108 the end of the file. mode must be one of the LK_* constants listed
109 below. Multiple regions in a file may be locked at the same time, but
110 may not overlap. Adjacent regions are not merged; they must be unlocked
111 individually.
112 [clinic start generated code]*/
113 
114 static PyObject *
msvcrt_locking_impl(PyObject * module,int fd,int mode,long nbytes)115 msvcrt_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]
136 msvcrt.setmode -> long
137 
138     fd: int
139     mode as flags: int
140     /
141 
142 Set the line-end translation mode for the file descriptor fd.
143 
144 To set it to text mode, flags should be os.O_TEXT; for binary, it
145 should be os.O_BINARY.
146 
147 Return value is the previous mode.
148 [clinic start generated code]*/
149 
150 static long
msvcrt_setmode_impl(PyObject * module,int fd,int flags)151 msvcrt_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]
164 msvcrt.open_osfhandle -> long
165 
166     handle: HANDLE
167     flags: int
168     /
169 
170 Create a C runtime file descriptor from the file handle handle.
171 
172 The flags parameter should be a bitwise OR of os.O_APPEND, os.O_RDONLY,
173 and os.O_TEXT. The returned file descriptor may be used as a parameter
174 to os.fdopen() to create a file object.
175 [clinic start generated code]*/
176 
177 static long
msvcrt_open_osfhandle_impl(PyObject * module,void * handle,int flags)178 msvcrt_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]
189 msvcrt.get_osfhandle -> HANDLE
190 
191     fd: int
192     /
193 
194 Return the file handle for the file descriptor fd.
195 
196 Raises OSError if fd is not recognized.
197 [clinic start generated code]*/
198 
199 static void *
msvcrt_get_osfhandle_impl(PyObject * module,int fd)200 msvcrt_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]
212 msvcrt.kbhit -> long
213 
214 Return true if a keypress is waiting to be read.
215 [clinic start generated code]*/
216 
217 static long
msvcrt_kbhit_impl(PyObject * module)218 msvcrt_kbhit_impl(PyObject *module)
219 /*[clinic end generated code: output=940dfce6587c1890 input=e70d678a5c2f6acc]*/
220 {
221     return _kbhit();
222 }
223 
224 /*[clinic input]
225 msvcrt.getch -> byte_char
226 
227 Read a keypress and return the resulting character as a byte string.
228 
229 Nothing is echoed to the console. This call will block if a keypress is
230 not already available, but will not wait for Enter to be pressed. If the
231 pressed key was a special function key, this will return '\000' or
232 '\xe0'; the next call will return the keycode. The Control-C keypress
233 cannot be read with this function.
234 [clinic start generated code]*/
235 
236 static int
msvcrt_getch_impl(PyObject * module)237 msvcrt_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]
249 msvcrt.getwch -> wchar_t
250 
251 Wide char variant of getch(), returning a Unicode value.
252 [clinic start generated code]*/
253 
254 static wchar_t
msvcrt_getwch_impl(PyObject * module)255 msvcrt_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]
267 msvcrt.getche -> byte_char
268 
269 Similar to getch(), but the keypress will be echoed if possible.
270 [clinic start generated code]*/
271 
272 static int
msvcrt_getche_impl(PyObject * module)273 msvcrt_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]
285 msvcrt.getwche -> wchar_t
286 
287 Wide char variant of getche(), returning a Unicode value.
288 [clinic start generated code]*/
289 
290 static wchar_t
msvcrt_getwche_impl(PyObject * module)291 msvcrt_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]
303 msvcrt.putch
304 
305     char: char
306     /
307 
308 Print the byte string char to the console without buffering.
309 [clinic start generated code]*/
310 
311 static PyObject *
msvcrt_putch_impl(PyObject * module,char char_value)312 msvcrt_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]
322 msvcrt.putwch
323 
324     unicode_char: int(accept={str})
325     /
326 
327 Wide char variant of putch(), accepting a Unicode value.
328 [clinic start generated code]*/
329 
330 static PyObject *
msvcrt_putwch_impl(PyObject * module,int unicode_char)331 msvcrt_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]
342 msvcrt.ungetch
343 
344     char: char
345     /
346 
347 Opposite of getch.
348 
349 Cause the byte string char to be "pushed back" into the
350 console buffer; it will be the next character read by
351 getch() or getche().
352 [clinic start generated code]*/
353 
354 static PyObject *
msvcrt_ungetch_impl(PyObject * module,char char_value)355 msvcrt_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]
370 msvcrt.ungetwch
371 
372     unicode_char: int(accept={str})
373     /
374 
375 Wide char variant of ungetch(), accepting a Unicode value.
376 [clinic start generated code]*/
377 
378 static PyObject *
msvcrt_ungetwch_impl(PyObject * module,int unicode_char)379 msvcrt_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]
395 msvcrt.CrtSetReportFile -> HANDLE
396 
397     type: int
398     file: HANDLE
399     /
400 
401 Wrapper around _CrtSetReportFile.
402 
403 Only available on Debug builds.
404 [clinic start generated code]*/
405 
406 static void *
msvcrt_CrtSetReportFile_impl(PyObject * module,int type,void * file)407 msvcrt_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]
420 msvcrt.CrtSetReportMode -> long
421 
422     type: int
423     mode: int
424     /
425 
426 Wrapper around _CrtSetReportMode.
427 
428 Only available on Debug builds.
429 [clinic start generated code]*/
430 
431 static long
msvcrt_CrtSetReportMode_impl(PyObject * module,int type,int mode)432 msvcrt_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]
446 msvcrt.set_error_mode -> long
447 
448     mode: int
449     /
450 
451 Wrapper around _set_error_mode.
452 
453 Only available on Debug builds.
454 [clinic start generated code]*/
455 
456 static long
msvcrt_set_error_mode_impl(PyObject * module,int mode)457 msvcrt_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]
471 msvcrt.GetErrorMode
472 
473 Wrapper around GetErrorMode.
474 [clinic start generated code]*/
475 
476 static PyObject *
msvcrt_GetErrorMode_impl(PyObject * module)477 msvcrt_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]
490 msvcrt.SetErrorMode
491 
492     mode: unsigned_int(bitwise=True)
493     /
494 
495 Wrapper around SetErrorMode.
496 [clinic start generated code]*/
497 
498 static PyObject *
msvcrt_SetErrorMode_impl(PyObject * module,unsigned int mode)499 msvcrt_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 */
516 static 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 
540 static 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 
552 static void
insertint(PyObject * d,char * name,int value)553 insertint(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 
566 static void
insertptr(PyObject * d,char * name,void * value)567 insertptr(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 
580 PyMODINIT_FUNC
PyInit_msvcrt(void)581 PyInit_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