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