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