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