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