• 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 intptr_t_converter(CConverter):
37     type = 'intptr_t'
38     format_unit = '"_Py_PARSE_INTPTR"'
39 
40 class handle_return_converter(long_return_converter):
41     type = 'intptr_t'
42     cast = '(void *)'
43     conversion_fn = 'PyLong_FromVoidPtr'
44 
45 class byte_char_return_converter(CReturnConverter):
46     type = 'int'
47 
48     def render(self, function, data):
49         data.declarations.append('char s[1];')
50         data.return_value = 's[0]'
51         data.return_conversion.append(
52             'return_value = PyBytes_FromStringAndSize(s, 1);\n')
53 
54 class wchar_t_return_converter(CReturnConverter):
55     type = 'wchar_t'
56 
57     def render(self, function, data):
58         self.declare(data)
59         data.return_conversion.append(
60             'return_value = PyUnicode_FromOrdinal(_return_value);\n')
61 [python start generated code]*/
62 /*[python end generated code: output=da39a3ee5e6b4b0d input=b59f1663dba11997]*/
63 
64 /*[clinic input]
65 module msvcrt
66 [clinic start generated code]*/
67 /*[clinic end generated code: output=da39a3ee5e6b4b0d input=f31a87a783d036cd]*/
68 
69 #include "clinic/msvcrtmodule.c.h"
70 
71 /*[clinic input]
72 msvcrt.heapmin
73 
74 Minimize the malloc() heap.
75 
76 Force the malloc() heap to clean itself up and return unused blocks
77 to the operating system. On failure, this raises OSError.
78 [clinic start generated code]*/
79 
80 static PyObject *
msvcrt_heapmin_impl(PyObject * module)81 msvcrt_heapmin_impl(PyObject *module)
82 /*[clinic end generated code: output=1ba00f344782dc19 input=82e1771d21bde2d8]*/
83 {
84     if (_heapmin() != 0)
85         return PyErr_SetFromErrno(PyExc_IOError);
86 
87     Py_RETURN_NONE;
88 }
89 /*[clinic input]
90 msvcrt.locking
91 
92     fd: int
93     mode: int
94     nbytes: long
95     /
96 
97 Lock part of a file based on file descriptor fd from the C runtime.
98 
99 Raises IOError on failure. The locked region of the file extends from
100 the current file position for nbytes bytes, and may continue beyond
101 the end of the file. mode must be one of the LK_* constants listed
102 below. Multiple regions in a file may be locked at the same time, but
103 may not overlap. Adjacent regions are not merged; they must be unlocked
104 individually.
105 [clinic start generated code]*/
106 
107 static PyObject *
msvcrt_locking_impl(PyObject * module,int fd,int mode,long nbytes)108 msvcrt_locking_impl(PyObject *module, int fd, int mode, long nbytes)
109 /*[clinic end generated code: output=a4a90deca9785a03 input=d9f13f0f6a713ba7]*/
110 {
111     int err;
112 
113     Py_BEGIN_ALLOW_THREADS
114     _Py_BEGIN_SUPPRESS_IPH
115     err = _locking(fd, mode, nbytes);
116     _Py_END_SUPPRESS_IPH
117     Py_END_ALLOW_THREADS
118     if (err != 0)
119         return PyErr_SetFromErrno(PyExc_IOError);
120 
121     Py_RETURN_NONE;
122 }
123 
124 /*[clinic input]
125 msvcrt.setmode -> long
126 
127     fd: int
128     mode as flags: int
129     /
130 
131 Set the line-end translation mode for the file descriptor fd.
132 
133 To set it to text mode, flags should be os.O_TEXT; for binary, it
134 should be os.O_BINARY.
135 
136 Return value is the previous mode.
137 [clinic start generated code]*/
138 
139 static long
msvcrt_setmode_impl(PyObject * module,int fd,int flags)140 msvcrt_setmode_impl(PyObject *module, int fd, int flags)
141 /*[clinic end generated code: output=24a9be5ea07ccb9b input=76e7c01f6b137f75]*/
142 {
143     _Py_BEGIN_SUPPRESS_IPH
144     flags = _setmode(fd, flags);
145     _Py_END_SUPPRESS_IPH
146     if (flags == -1)
147         PyErr_SetFromErrno(PyExc_IOError);
148 
149     return flags;
150 }
151 
152 /*[clinic input]
153 msvcrt.open_osfhandle -> long
154 
155     handle: intptr_t
156     flags: int
157     /
158 
159 Create a C runtime file descriptor from the file handle handle.
160 
161 The flags parameter should be a bitwise OR of os.O_APPEND, os.O_RDONLY,
162 and os.O_TEXT. The returned file descriptor may be used as a parameter
163 to os.fdopen() to create a file object.
164 [clinic start generated code]*/
165 
166 static long
msvcrt_open_osfhandle_impl(PyObject * module,intptr_t handle,int flags)167 msvcrt_open_osfhandle_impl(PyObject *module, intptr_t handle, int flags)
168 /*[clinic end generated code: output=cede871bf939d6e3 input=cb2108bbea84514e]*/
169 {
170     int fd;
171 
172     _Py_BEGIN_SUPPRESS_IPH
173     fd = _open_osfhandle(handle, flags);
174     _Py_END_SUPPRESS_IPH
175     if (fd == -1)
176         PyErr_SetFromErrno(PyExc_IOError);
177 
178     return fd;
179 }
180 
181 /*[clinic input]
182 msvcrt.get_osfhandle -> handle
183 
184     fd: int
185     /
186 
187 Return the file handle for the file descriptor fd.
188 
189 Raises IOError if fd is not recognized.
190 [clinic start generated code]*/
191 
192 static intptr_t
msvcrt_get_osfhandle_impl(PyObject * module,int fd)193 msvcrt_get_osfhandle_impl(PyObject *module, int fd)
194 /*[clinic end generated code: output=7ce761dd0de2b503 input=c7d18d02c8017ec1]*/
195 {
196     intptr_t handle = -1;
197 
198     _Py_BEGIN_SUPPRESS_IPH
199     handle = _get_osfhandle(fd);
200     _Py_END_SUPPRESS_IPH
201     if (handle == -1)
202         PyErr_SetFromErrno(PyExc_IOError);
203 
204     return handle;
205 }
206 
207 /* Console I/O */
208 /*[clinic input]
209 msvcrt.kbhit -> long
210 
211 Return true if a keypress is waiting to be read.
212 [clinic start generated code]*/
213 
214 static long
msvcrt_kbhit_impl(PyObject * module)215 msvcrt_kbhit_impl(PyObject *module)
216 /*[clinic end generated code: output=940dfce6587c1890 input=e70d678a5c2f6acc]*/
217 {
218     return _kbhit();
219 }
220 
221 /*[clinic input]
222 msvcrt.getch -> byte_char
223 
224 Read a keypress and return the resulting character as a byte string.
225 
226 Nothing is echoed to the console. This call will block if a keypress is
227 not already available, but will not wait for Enter to be pressed. If the
228 pressed key was a special function key, this will return '\000' or
229 '\xe0'; the next call will return the keycode. The Control-C keypress
230 cannot be read with this function.
231 [clinic start generated code]*/
232 
233 static int
msvcrt_getch_impl(PyObject * module)234 msvcrt_getch_impl(PyObject *module)
235 /*[clinic end generated code: output=a4e51f0565064a7d input=37a40cf0ed0d1153]*/
236 {
237     int ch;
238 
239     Py_BEGIN_ALLOW_THREADS
240     ch = _getch();
241     Py_END_ALLOW_THREADS
242     return ch;
243 }
244 
245 /*[clinic input]
246 msvcrt.getwch -> wchar_t
247 
248 Wide char variant of getch(), returning a Unicode value.
249 [clinic start generated code]*/
250 
251 static wchar_t
msvcrt_getwch_impl(PyObject * module)252 msvcrt_getwch_impl(PyObject *module)
253 /*[clinic end generated code: output=be9937494e22f007 input=27b3dec8ad823d7c]*/
254 {
255     wchar_t ch;
256 
257     Py_BEGIN_ALLOW_THREADS
258     ch = _getwch();
259     Py_END_ALLOW_THREADS
260     return ch;
261 }
262 
263 /*[clinic input]
264 msvcrt.getche -> byte_char
265 
266 Similar to getch(), but the keypress will be echoed if possible.
267 [clinic start generated code]*/
268 
269 static int
msvcrt_getche_impl(PyObject * module)270 msvcrt_getche_impl(PyObject *module)
271 /*[clinic end generated code: output=d8f7db4fd2990401 input=43311ade9ed4a9c0]*/
272 {
273     int ch;
274 
275     Py_BEGIN_ALLOW_THREADS
276     ch = _getche();
277     Py_END_ALLOW_THREADS
278     return ch;
279 }
280 
281 /*[clinic input]
282 msvcrt.getwche -> wchar_t
283 
284 Wide char variant of getche(), returning a Unicode value.
285 [clinic start generated code]*/
286 
287 static wchar_t
msvcrt_getwche_impl(PyObject * module)288 msvcrt_getwche_impl(PyObject *module)
289 /*[clinic end generated code: output=d0dae5ba3829d596 input=49337d59d1a591f8]*/
290 {
291     wchar_t ch;
292 
293     Py_BEGIN_ALLOW_THREADS
294     ch = _getwche();
295     Py_END_ALLOW_THREADS
296     return ch;
297 }
298 
299 /*[clinic input]
300 msvcrt.putch
301 
302     char: char
303     /
304 
305 Print the byte string char to the console without buffering.
306 [clinic start generated code]*/
307 
308 static PyObject *
msvcrt_putch_impl(PyObject * module,char char_value)309 msvcrt_putch_impl(PyObject *module, char char_value)
310 /*[clinic end generated code: output=92ec9b81012d8f60 input=ec078dd10cb054d6]*/
311 {
312     _Py_BEGIN_SUPPRESS_IPH
313     _putch(char_value);
314     _Py_END_SUPPRESS_IPH
315     Py_RETURN_NONE;
316 }
317 
318 /*[clinic input]
319 msvcrt.putwch
320 
321     unicode_char: int(accept={str})
322     /
323 
324 Wide char variant of putch(), accepting a Unicode value.
325 [clinic start generated code]*/
326 
327 static PyObject *
msvcrt_putwch_impl(PyObject * module,int unicode_char)328 msvcrt_putwch_impl(PyObject *module, int unicode_char)
329 /*[clinic end generated code: output=a3bd1a8951d28eee input=996ccd0bbcbac4c3]*/
330 {
331     _Py_BEGIN_SUPPRESS_IPH
332     _putwch(unicode_char);
333     _Py_END_SUPPRESS_IPH
334     Py_RETURN_NONE;
335 
336 }
337 
338 /*[clinic input]
339 msvcrt.ungetch
340 
341     char: char
342     /
343 
344 Opposite of getch.
345 
346 Cause the byte string char to be "pushed back" into the
347 console buffer; it will be the next character read by
348 getch() or getche().
349 [clinic start generated code]*/
350 
351 static PyObject *
msvcrt_ungetch_impl(PyObject * module,char char_value)352 msvcrt_ungetch_impl(PyObject *module, char char_value)
353 /*[clinic end generated code: output=c6942a0efa119000 input=22f07ee9001bbf0f]*/
354 {
355     int res;
356 
357     _Py_BEGIN_SUPPRESS_IPH
358     res = _ungetch(char_value);
359     _Py_END_SUPPRESS_IPH
360 
361     if (res == EOF)
362         return PyErr_SetFromErrno(PyExc_IOError);
363     Py_RETURN_NONE;
364 }
365 
366 /*[clinic input]
367 msvcrt.ungetwch
368 
369     unicode_char: int(accept={str})
370     /
371 
372 Wide char variant of ungetch(), accepting a Unicode value.
373 [clinic start generated code]*/
374 
375 static PyObject *
msvcrt_ungetwch_impl(PyObject * module,int unicode_char)376 msvcrt_ungetwch_impl(PyObject *module, int unicode_char)
377 /*[clinic end generated code: output=e63af05438b8ba3d input=83ec0492be04d564]*/
378 {
379     int res;
380 
381     _Py_BEGIN_SUPPRESS_IPH
382     res = _ungetwch(unicode_char);
383     _Py_END_SUPPRESS_IPH
384 
385     if (res == WEOF)
386         return PyErr_SetFromErrno(PyExc_IOError);
387     Py_RETURN_NONE;
388 }
389 
390 #ifdef _DEBUG
391 /*[clinic input]
392 msvcrt.CrtSetReportFile -> long
393 
394     type: int
395     file: int
396     /
397 
398 Wrapper around _CrtSetReportFile.
399 
400 Only available on Debug builds.
401 [clinic start generated code]*/
402 
403 static long
msvcrt_CrtSetReportFile_impl(PyObject * module,int type,int file)404 msvcrt_CrtSetReportFile_impl(PyObject *module, int type, int file)
405 /*[clinic end generated code: output=df291c7fe032eb68 input=bb8f721a604fcc45]*/
406 {
407     long res;
408 
409     _Py_BEGIN_SUPPRESS_IPH
410     res = (long)_CrtSetReportFile(type, (_HFILE)file);
411     _Py_END_SUPPRESS_IPH
412 
413     return res;
414 }
415 
416 /*[clinic input]
417 msvcrt.CrtSetReportMode -> long
418 
419     type: int
420     mode: int
421     /
422 
423 Wrapper around _CrtSetReportMode.
424 
425 Only available on Debug builds.
426 [clinic start generated code]*/
427 
428 static long
msvcrt_CrtSetReportMode_impl(PyObject * module,int type,int mode)429 msvcrt_CrtSetReportMode_impl(PyObject *module, int type, int mode)
430 /*[clinic end generated code: output=b2863761523de317 input=9319d29b4319426b]*/
431 {
432     int res;
433 
434     _Py_BEGIN_SUPPRESS_IPH
435     res = _CrtSetReportMode(type, mode);
436     _Py_END_SUPPRESS_IPH
437     if (res == -1)
438         PyErr_SetFromErrno(PyExc_IOError);
439     return res;
440 }
441 
442 /*[clinic input]
443 msvcrt.set_error_mode -> long
444 
445     mode: int
446     /
447 
448 Wrapper around _set_error_mode.
449 
450 Only available on Debug builds.
451 [clinic start generated code]*/
452 
453 static long
msvcrt_set_error_mode_impl(PyObject * module,int mode)454 msvcrt_set_error_mode_impl(PyObject *module, int mode)
455 /*[clinic end generated code: output=ac4a09040d8ac4e3 input=046fca59c0f20872]*/
456 {
457     long res;
458 
459     _Py_BEGIN_SUPPRESS_IPH
460     res = _set_error_mode(mode);
461     _Py_END_SUPPRESS_IPH
462 
463     return res;
464 }
465 #endif /* _DEBUG */
466 
467 /*[clinic input]
468 msvcrt.SetErrorMode
469 
470     mode: unsigned_int(bitwise=True)
471     /
472 
473 Wrapper around SetErrorMode.
474 [clinic start generated code]*/
475 
476 static PyObject *
msvcrt_SetErrorMode_impl(PyObject * module,unsigned int mode)477 msvcrt_SetErrorMode_impl(PyObject *module, unsigned int mode)
478 /*[clinic end generated code: output=01d529293f00da8f input=d8b167258d32d907]*/
479 {
480     unsigned int res;
481 
482     _Py_BEGIN_SUPPRESS_IPH
483     res = SetErrorMode(mode);
484     _Py_END_SUPPRESS_IPH
485 
486     return PyLong_FromUnsignedLong(res);
487 }
488 
489 /*[clinic input]
490 [clinic start generated code]*/
491 /*[clinic end generated code: output=da39a3ee5e6b4b0d input=da39a3ee5e6b4b0d]*/
492 
493 /* List of functions exported by this module */
494 static struct PyMethodDef msvcrt_functions[] = {
495     MSVCRT_HEAPMIN_METHODDEF
496     MSVCRT_LOCKING_METHODDEF
497     MSVCRT_SETMODE_METHODDEF
498     MSVCRT_OPEN_OSFHANDLE_METHODDEF
499     MSVCRT_GET_OSFHANDLE_METHODDEF
500     MSVCRT_KBHIT_METHODDEF
501     MSVCRT_GETCH_METHODDEF
502     MSVCRT_GETCHE_METHODDEF
503     MSVCRT_PUTCH_METHODDEF
504     MSVCRT_UNGETCH_METHODDEF
505     MSVCRT_SETERRORMODE_METHODDEF
506     MSVCRT_CRTSETREPORTFILE_METHODDEF
507     MSVCRT_CRTSETREPORTMODE_METHODDEF
508     MSVCRT_SET_ERROR_MODE_METHODDEF
509     MSVCRT_GETWCH_METHODDEF
510     MSVCRT_GETWCHE_METHODDEF
511     MSVCRT_PUTWCH_METHODDEF
512     MSVCRT_UNGETWCH_METHODDEF
513     {NULL,                      NULL}
514 };
515 
516 
517 static struct PyModuleDef msvcrtmodule = {
518     PyModuleDef_HEAD_INIT,
519     "msvcrt",
520     NULL,
521     -1,
522     msvcrt_functions,
523     NULL,
524     NULL,
525     NULL,
526     NULL
527 };
528 
529 static void
insertint(PyObject * d,char * name,int value)530 insertint(PyObject *d, char *name, int value)
531 {
532     PyObject *v = PyLong_FromLong((long) value);
533     if (v == NULL) {
534         /* Don't bother reporting this error */
535         PyErr_Clear();
536     }
537     else {
538         PyDict_SetItemString(d, name, v);
539         Py_DECREF(v);
540     }
541 }
542 
543 PyMODINIT_FUNC
PyInit_msvcrt(void)544 PyInit_msvcrt(void)
545 {
546     int st;
547     PyObject *d, *version;
548     PyObject *m = PyModule_Create(&msvcrtmodule);
549     if (m == NULL)
550         return NULL;
551     d = PyModule_GetDict(m);
552 
553     /* constants for the locking() function's mode argument */
554     insertint(d, "LK_LOCK", _LK_LOCK);
555     insertint(d, "LK_NBLCK", _LK_NBLCK);
556     insertint(d, "LK_NBRLCK", _LK_NBRLCK);
557     insertint(d, "LK_RLCK", _LK_RLCK);
558     insertint(d, "LK_UNLCK", _LK_UNLCK);
559     insertint(d, "SEM_FAILCRITICALERRORS", SEM_FAILCRITICALERRORS);
560     insertint(d, "SEM_NOALIGNMENTFAULTEXCEPT", SEM_NOALIGNMENTFAULTEXCEPT);
561     insertint(d, "SEM_NOGPFAULTERRORBOX", SEM_NOGPFAULTERRORBOX);
562     insertint(d, "SEM_NOOPENFILEERRORBOX", SEM_NOOPENFILEERRORBOX);
563 #ifdef _DEBUG
564     insertint(d, "CRT_WARN", _CRT_WARN);
565     insertint(d, "CRT_ERROR", _CRT_ERROR);
566     insertint(d, "CRT_ASSERT", _CRT_ASSERT);
567     insertint(d, "CRTDBG_MODE_DEBUG", _CRTDBG_MODE_DEBUG);
568     insertint(d, "CRTDBG_MODE_FILE", _CRTDBG_MODE_FILE);
569     insertint(d, "CRTDBG_MODE_WNDW", _CRTDBG_MODE_WNDW);
570     insertint(d, "CRTDBG_REPORT_MODE", _CRTDBG_REPORT_MODE);
571     insertint(d, "CRTDBG_FILE_STDERR", (int)_CRTDBG_FILE_STDERR);
572     insertint(d, "CRTDBG_FILE_STDOUT", (int)_CRTDBG_FILE_STDOUT);
573     insertint(d, "CRTDBG_REPORT_FILE", (int)_CRTDBG_REPORT_FILE);
574 #endif
575 
576     /* constants for the crt versions */
577 #ifdef _VC_ASSEMBLY_PUBLICKEYTOKEN
578     st = PyModule_AddStringConstant(m, "VC_ASSEMBLY_PUBLICKEYTOKEN",
579                                     _VC_ASSEMBLY_PUBLICKEYTOKEN);
580     if (st < 0) return NULL;
581 #endif
582 #ifdef _CRT_ASSEMBLY_VERSION
583     st = PyModule_AddStringConstant(m, "CRT_ASSEMBLY_VERSION",
584                                     _CRT_ASSEMBLY_VERSION);
585     if (st < 0) return NULL;
586 #endif
587 #ifdef __LIBRARIES_ASSEMBLY_NAME_PREFIX
588     st = PyModule_AddStringConstant(m, "LIBRARIES_ASSEMBLY_NAME_PREFIX",
589                                     __LIBRARIES_ASSEMBLY_NAME_PREFIX);
590     if (st < 0) return NULL;
591 #endif
592 
593     /* constants for the 2010 crt versions */
594 #if defined(_VC_CRT_MAJOR_VERSION) && defined (_VC_CRT_MINOR_VERSION) && defined(_VC_CRT_BUILD_VERSION) && defined(_VC_CRT_RBUILD_VERSION)
595     version = PyUnicode_FromFormat("%d.%d.%d.%d", _VC_CRT_MAJOR_VERSION,
596                                                   _VC_CRT_MINOR_VERSION,
597                                                   _VC_CRT_BUILD_VERSION,
598                                                   _VC_CRT_RBUILD_VERSION);
599     st = PyModule_AddObject(m, "CRT_ASSEMBLY_VERSION", version);
600     if (st < 0) return NULL;
601 #endif
602     /* make compiler warning quiet if st is unused */
603     (void)st;
604 
605     return m;
606 }
607