• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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