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