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