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 int fd;
181
182 if (PySys_Audit("msvcrt.open_osfhandle", "Ki", handle, flags) < 0) {
183 return -1;
184 }
185
186 _Py_BEGIN_SUPPRESS_IPH
187 fd = _open_osfhandle((intptr_t)handle, flags);
188 _Py_END_SUPPRESS_IPH
189 if (fd == -1)
190 PyErr_SetFromErrno(PyExc_OSError);
191
192 return fd;
193 }
194
195 /*[clinic input]
196 msvcrt.get_osfhandle -> HANDLE
197
198 fd: int
199 /
200
201 Return the file handle for the file descriptor fd.
202
203 Raises OSError if fd is not recognized.
204 [clinic start generated code]*/
205
206 static void *
msvcrt_get_osfhandle_impl(PyObject * module,int fd)207 msvcrt_get_osfhandle_impl(PyObject *module, int fd)
208 /*[clinic end generated code: output=aca01dfe24637374 input=5fcfde9b17136aa2]*/
209 {
210 intptr_t handle = -1;
211
212 if (PySys_Audit("msvcrt.get_osfhandle", "(i)", fd) < 0) {
213 return NULL;
214 }
215
216 _Py_BEGIN_SUPPRESS_IPH
217 handle = _get_osfhandle(fd);
218 _Py_END_SUPPRESS_IPH
219 if (handle == -1)
220 PyErr_SetFromErrno(PyExc_OSError);
221
222 return (HANDLE)handle;
223 }
224
225 /* Console I/O */
226 /*[clinic input]
227 msvcrt.kbhit -> long
228
229 Return true if a keypress is waiting to be read.
230 [clinic start generated code]*/
231
232 static long
msvcrt_kbhit_impl(PyObject * module)233 msvcrt_kbhit_impl(PyObject *module)
234 /*[clinic end generated code: output=940dfce6587c1890 input=e70d678a5c2f6acc]*/
235 {
236 return _kbhit();
237 }
238
239 /*[clinic input]
240 msvcrt.getch -> byte_char
241
242 Read a keypress and return the resulting character as a byte string.
243
244 Nothing is echoed to the console. This call will block if a keypress is
245 not already available, but will not wait for Enter to be pressed. If the
246 pressed key was a special function key, this will return '\000' or
247 '\xe0'; the next call will return the keycode. The Control-C keypress
248 cannot be read with this function.
249 [clinic start generated code]*/
250
251 static int
msvcrt_getch_impl(PyObject * module)252 msvcrt_getch_impl(PyObject *module)
253 /*[clinic end generated code: output=a4e51f0565064a7d input=37a40cf0ed0d1153]*/
254 {
255 int ch;
256
257 Py_BEGIN_ALLOW_THREADS
258 ch = _getch();
259 Py_END_ALLOW_THREADS
260 return ch;
261 }
262
263 /*[clinic input]
264 msvcrt.getwch -> wchar_t
265
266 Wide char variant of getch(), returning a Unicode value.
267 [clinic start generated code]*/
268
269 static wchar_t
msvcrt_getwch_impl(PyObject * module)270 msvcrt_getwch_impl(PyObject *module)
271 /*[clinic end generated code: output=be9937494e22f007 input=27b3dec8ad823d7c]*/
272 {
273 wchar_t ch;
274
275 Py_BEGIN_ALLOW_THREADS
276 ch = _getwch();
277 Py_END_ALLOW_THREADS
278 return ch;
279 }
280
281 /*[clinic input]
282 msvcrt.getche -> byte_char
283
284 Similar to getch(), but the keypress will be echoed if possible.
285 [clinic start generated code]*/
286
287 static int
msvcrt_getche_impl(PyObject * module)288 msvcrt_getche_impl(PyObject *module)
289 /*[clinic end generated code: output=d8f7db4fd2990401 input=43311ade9ed4a9c0]*/
290 {
291 int ch;
292
293 Py_BEGIN_ALLOW_THREADS
294 ch = _getche();
295 Py_END_ALLOW_THREADS
296 return ch;
297 }
298
299 /*[clinic input]
300 msvcrt.getwche -> wchar_t
301
302 Wide char variant of getche(), returning a Unicode value.
303 [clinic start generated code]*/
304
305 static wchar_t
msvcrt_getwche_impl(PyObject * module)306 msvcrt_getwche_impl(PyObject *module)
307 /*[clinic end generated code: output=d0dae5ba3829d596 input=49337d59d1a591f8]*/
308 {
309 wchar_t ch;
310
311 Py_BEGIN_ALLOW_THREADS
312 ch = _getwche();
313 Py_END_ALLOW_THREADS
314 return ch;
315 }
316
317 /*[clinic input]
318 msvcrt.putch
319
320 char: char
321 /
322
323 Print the byte string char to the console without buffering.
324 [clinic start generated code]*/
325
326 static PyObject *
msvcrt_putch_impl(PyObject * module,char char_value)327 msvcrt_putch_impl(PyObject *module, char char_value)
328 /*[clinic end generated code: output=92ec9b81012d8f60 input=ec078dd10cb054d6]*/
329 {
330 _Py_BEGIN_SUPPRESS_IPH
331 _putch(char_value);
332 _Py_END_SUPPRESS_IPH
333 Py_RETURN_NONE;
334 }
335
336 /*[clinic input]
337 msvcrt.putwch
338
339 unicode_char: int(accept={str})
340 /
341
342 Wide char variant of putch(), accepting a Unicode value.
343 [clinic start generated code]*/
344
345 static PyObject *
msvcrt_putwch_impl(PyObject * module,int unicode_char)346 msvcrt_putwch_impl(PyObject *module, int unicode_char)
347 /*[clinic end generated code: output=a3bd1a8951d28eee input=996ccd0bbcbac4c3]*/
348 {
349 _Py_BEGIN_SUPPRESS_IPH
350 _putwch(unicode_char);
351 _Py_END_SUPPRESS_IPH
352 Py_RETURN_NONE;
353
354 }
355
356 /*[clinic input]
357 msvcrt.ungetch
358
359 char: char
360 /
361
362 Opposite of getch.
363
364 Cause the byte string char to be "pushed back" into the
365 console buffer; it will be the next character read by
366 getch() or getche().
367 [clinic start generated code]*/
368
369 static PyObject *
msvcrt_ungetch_impl(PyObject * module,char char_value)370 msvcrt_ungetch_impl(PyObject *module, char char_value)
371 /*[clinic end generated code: output=c6942a0efa119000 input=22f07ee9001bbf0f]*/
372 {
373 int res;
374
375 _Py_BEGIN_SUPPRESS_IPH
376 res = _ungetch(char_value);
377 _Py_END_SUPPRESS_IPH
378
379 if (res == EOF)
380 return PyErr_SetFromErrno(PyExc_OSError);
381 Py_RETURN_NONE;
382 }
383
384 /*[clinic input]
385 msvcrt.ungetwch
386
387 unicode_char: int(accept={str})
388 /
389
390 Wide char variant of ungetch(), accepting a Unicode value.
391 [clinic start generated code]*/
392
393 static PyObject *
msvcrt_ungetwch_impl(PyObject * module,int unicode_char)394 msvcrt_ungetwch_impl(PyObject *module, int unicode_char)
395 /*[clinic end generated code: output=e63af05438b8ba3d input=83ec0492be04d564]*/
396 {
397 int res;
398
399 _Py_BEGIN_SUPPRESS_IPH
400 res = _ungetwch(unicode_char);
401 _Py_END_SUPPRESS_IPH
402
403 if (res == WEOF)
404 return PyErr_SetFromErrno(PyExc_OSError);
405 Py_RETURN_NONE;
406 }
407
408 #ifdef _DEBUG
409 /*[clinic input]
410 msvcrt.CrtSetReportFile -> HANDLE
411
412 type: int
413 file: HANDLE
414 /
415
416 Wrapper around _CrtSetReportFile.
417
418 Only available on Debug builds.
419 [clinic start generated code]*/
420
421 static void *
msvcrt_CrtSetReportFile_impl(PyObject * module,int type,void * file)422 msvcrt_CrtSetReportFile_impl(PyObject *module, int type, void *file)
423 /*[clinic end generated code: output=9393e8c77088bbe9 input=290809b5f19e65b9]*/
424 {
425 HANDLE res;
426
427 _Py_BEGIN_SUPPRESS_IPH
428 res = _CrtSetReportFile(type, file);
429 _Py_END_SUPPRESS_IPH
430
431 return res;
432 }
433
434 /*[clinic input]
435 msvcrt.CrtSetReportMode -> long
436
437 type: int
438 mode: int
439 /
440
441 Wrapper around _CrtSetReportMode.
442
443 Only available on Debug builds.
444 [clinic start generated code]*/
445
446 static long
msvcrt_CrtSetReportMode_impl(PyObject * module,int type,int mode)447 msvcrt_CrtSetReportMode_impl(PyObject *module, int type, int mode)
448 /*[clinic end generated code: output=b2863761523de317 input=9319d29b4319426b]*/
449 {
450 int res;
451
452 _Py_BEGIN_SUPPRESS_IPH
453 res = _CrtSetReportMode(type, mode);
454 _Py_END_SUPPRESS_IPH
455 if (res == -1)
456 PyErr_SetFromErrno(PyExc_OSError);
457 return res;
458 }
459
460 /*[clinic input]
461 msvcrt.set_error_mode -> long
462
463 mode: int
464 /
465
466 Wrapper around _set_error_mode.
467
468 Only available on Debug builds.
469 [clinic start generated code]*/
470
471 static long
msvcrt_set_error_mode_impl(PyObject * module,int mode)472 msvcrt_set_error_mode_impl(PyObject *module, int mode)
473 /*[clinic end generated code: output=ac4a09040d8ac4e3 input=046fca59c0f20872]*/
474 {
475 long res;
476
477 _Py_BEGIN_SUPPRESS_IPH
478 res = _set_error_mode(mode);
479 _Py_END_SUPPRESS_IPH
480
481 return res;
482 }
483 #endif /* _DEBUG */
484
485 /*[clinic input]
486 msvcrt.SetErrorMode
487
488 mode: unsigned_int(bitwise=True)
489 /
490
491 Wrapper around SetErrorMode.
492 [clinic start generated code]*/
493
494 static PyObject *
msvcrt_SetErrorMode_impl(PyObject * module,unsigned int mode)495 msvcrt_SetErrorMode_impl(PyObject *module, unsigned int mode)
496 /*[clinic end generated code: output=01d529293f00da8f input=d8b167258d32d907]*/
497 {
498 unsigned int res;
499
500 _Py_BEGIN_SUPPRESS_IPH
501 res = SetErrorMode(mode);
502 _Py_END_SUPPRESS_IPH
503
504 return PyLong_FromUnsignedLong(res);
505 }
506
507 /*[clinic input]
508 [clinic start generated code]*/
509 /*[clinic end generated code: output=da39a3ee5e6b4b0d input=da39a3ee5e6b4b0d]*/
510
511 /* List of functions exported by this module */
512 static struct PyMethodDef msvcrt_functions[] = {
513 MSVCRT_HEAPMIN_METHODDEF
514 MSVCRT_LOCKING_METHODDEF
515 MSVCRT_SETMODE_METHODDEF
516 MSVCRT_OPEN_OSFHANDLE_METHODDEF
517 MSVCRT_GET_OSFHANDLE_METHODDEF
518 MSVCRT_KBHIT_METHODDEF
519 MSVCRT_GETCH_METHODDEF
520 MSVCRT_GETCHE_METHODDEF
521 MSVCRT_PUTCH_METHODDEF
522 MSVCRT_UNGETCH_METHODDEF
523 MSVCRT_SETERRORMODE_METHODDEF
524 MSVCRT_CRTSETREPORTFILE_METHODDEF
525 MSVCRT_CRTSETREPORTMODE_METHODDEF
526 MSVCRT_SET_ERROR_MODE_METHODDEF
527 MSVCRT_GETWCH_METHODDEF
528 MSVCRT_GETWCHE_METHODDEF
529 MSVCRT_PUTWCH_METHODDEF
530 MSVCRT_UNGETWCH_METHODDEF
531 {NULL, NULL}
532 };
533
534
535 static struct PyModuleDef msvcrtmodule = {
536 PyModuleDef_HEAD_INIT,
537 "msvcrt",
538 NULL,
539 -1,
540 msvcrt_functions,
541 NULL,
542 NULL,
543 NULL,
544 NULL
545 };
546
547 static void
insertint(PyObject * d,char * name,int value)548 insertint(PyObject *d, char *name, int value)
549 {
550 PyObject *v = PyLong_FromLong((long) value);
551 if (v == NULL) {
552 /* Don't bother reporting this error */
553 PyErr_Clear();
554 }
555 else {
556 PyDict_SetItemString(d, name, v);
557 Py_DECREF(v);
558 }
559 }
560
561 static void
insertptr(PyObject * d,char * name,void * value)562 insertptr(PyObject *d, char *name, void *value)
563 {
564 PyObject *v = PyLong_FromVoidPtr(value);
565 if (v == NULL) {
566 /* Don't bother reporting this error */
567 PyErr_Clear();
568 }
569 else {
570 PyDict_SetItemString(d, name, v);
571 Py_DECREF(v);
572 }
573 }
574
575 PyMODINIT_FUNC
PyInit_msvcrt(void)576 PyInit_msvcrt(void)
577 {
578 int st;
579 PyObject *d, *version;
580 PyObject *m = PyModule_Create(&msvcrtmodule);
581 if (m == NULL)
582 return NULL;
583 d = PyModule_GetDict(m);
584
585 /* constants for the locking() function's mode argument */
586 insertint(d, "LK_LOCK", _LK_LOCK);
587 insertint(d, "LK_NBLCK", _LK_NBLCK);
588 insertint(d, "LK_NBRLCK", _LK_NBRLCK);
589 insertint(d, "LK_RLCK", _LK_RLCK);
590 insertint(d, "LK_UNLCK", _LK_UNLCK);
591 insertint(d, "SEM_FAILCRITICALERRORS", SEM_FAILCRITICALERRORS);
592 insertint(d, "SEM_NOALIGNMENTFAULTEXCEPT", SEM_NOALIGNMENTFAULTEXCEPT);
593 insertint(d, "SEM_NOGPFAULTERRORBOX", SEM_NOGPFAULTERRORBOX);
594 insertint(d, "SEM_NOOPENFILEERRORBOX", SEM_NOOPENFILEERRORBOX);
595 #ifdef _DEBUG
596 insertint(d, "CRT_WARN", _CRT_WARN);
597 insertint(d, "CRT_ERROR", _CRT_ERROR);
598 insertint(d, "CRT_ASSERT", _CRT_ASSERT);
599 insertint(d, "CRTDBG_MODE_DEBUG", _CRTDBG_MODE_DEBUG);
600 insertint(d, "CRTDBG_MODE_FILE", _CRTDBG_MODE_FILE);
601 insertint(d, "CRTDBG_MODE_WNDW", _CRTDBG_MODE_WNDW);
602 insertint(d, "CRTDBG_REPORT_MODE", _CRTDBG_REPORT_MODE);
603 insertptr(d, "CRTDBG_FILE_STDERR", _CRTDBG_FILE_STDERR);
604 insertptr(d, "CRTDBG_FILE_STDOUT", _CRTDBG_FILE_STDOUT);
605 insertptr(d, "CRTDBG_REPORT_FILE", _CRTDBG_REPORT_FILE);
606 #endif
607
608 /* constants for the crt versions */
609 #ifdef _VC_ASSEMBLY_PUBLICKEYTOKEN
610 st = PyModule_AddStringConstant(m, "VC_ASSEMBLY_PUBLICKEYTOKEN",
611 _VC_ASSEMBLY_PUBLICKEYTOKEN);
612 if (st < 0) return NULL;
613 #endif
614 #ifdef _CRT_ASSEMBLY_VERSION
615 st = PyModule_AddStringConstant(m, "CRT_ASSEMBLY_VERSION",
616 _CRT_ASSEMBLY_VERSION);
617 if (st < 0) return NULL;
618 #endif
619 #ifdef __LIBRARIES_ASSEMBLY_NAME_PREFIX
620 st = PyModule_AddStringConstant(m, "LIBRARIES_ASSEMBLY_NAME_PREFIX",
621 __LIBRARIES_ASSEMBLY_NAME_PREFIX);
622 if (st < 0) return NULL;
623 #endif
624
625 /* constants for the 2010 crt versions */
626 #if defined(_VC_CRT_MAJOR_VERSION) && defined (_VC_CRT_MINOR_VERSION) && defined(_VC_CRT_BUILD_VERSION) && defined(_VC_CRT_RBUILD_VERSION)
627 version = PyUnicode_FromFormat("%d.%d.%d.%d", _VC_CRT_MAJOR_VERSION,
628 _VC_CRT_MINOR_VERSION,
629 _VC_CRT_BUILD_VERSION,
630 _VC_CRT_RBUILD_VERSION);
631 st = PyModule_AddObject(m, "CRT_ASSEMBLY_VERSION", version);
632 if (st < 0) return NULL;
633 #endif
634 /* make compiler warning quiet if st is unused */
635 (void)st;
636
637 return m;
638 }
639