Home | History | Annotate | Download | only in PC
      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 *
     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 *
    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
    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
    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
    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
    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
    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
    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
    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
    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 *
    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 *
    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 *
    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 *
    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
    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
    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
    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 *
    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
    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
    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