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 
     25 #ifdef _MSC_VER
     26 #if _MSC_VER >= 1500 && _MSC_VER < 1600
     27 #include <crtassem.h>
     28 #endif
     29 #endif
     30 
     31 // Force the malloc heap to clean itself up, and free unused blocks
     32 // back to the OS.  (According to the docs, only works on NT.)
     33 static PyObject *
     34 msvcrt_heapmin(PyObject *self, PyObject *args)
     35 {
     36     if (!PyArg_ParseTuple(args, ":heapmin"))
     37         return NULL;
     38 
     39     if (_heapmin() != 0)
     40         return PyErr_SetFromErrno(PyExc_IOError);
     41 
     42     Py_INCREF(Py_None);
     43     return Py_None;
     44 }
     45 
     46 PyDoc_STRVAR(heapmin_doc,
     47 "heapmin() -> None\n\
     48 \n\
     49 Force the malloc() heap to clean itself up and return unused blocks\n\
     50 to the operating system. On failure, this raises IOError.");
     51 
     52 // Perform locking operations on a C runtime file descriptor.
     53 static PyObject *
     54 msvcrt_locking(PyObject *self, PyObject *args)
     55 {
     56     int fd;
     57     int mode;
     58     long nbytes;
     59     int err;
     60 
     61     if (!PyArg_ParseTuple(args, "iil:locking", &fd, &mode, &nbytes))
     62         return NULL;
     63 
     64     Py_BEGIN_ALLOW_THREADS
     65     err = _locking(fd, mode, nbytes);
     66     Py_END_ALLOW_THREADS
     67     if (err != 0)
     68         return PyErr_SetFromErrno(PyExc_IOError);
     69 
     70     Py_INCREF(Py_None);
     71     return Py_None;
     72 }
     73 
     74 PyDoc_STRVAR(locking_doc,
     75 "locking(fd, mode, nbytes) -> None\n\
     76 \n\
     77 Lock part of a file based on file descriptor fd from the C runtime.\n\
     78 Raises IOError on failure. The locked region of the file extends from\n\
     79 the current file position for nbytes bytes, and may continue beyond\n\
     80 the end of the file. mode must be one of the LK_* constants listed\n\
     81 below. Multiple regions in a file may be locked at the same time, but\n\
     82 may not overlap. Adjacent regions are not merged; they must be unlocked\n\
     83 individually.");
     84 
     85 // Set the file translation mode for a C runtime file descriptor.
     86 static PyObject *
     87 msvcrt_setmode(PyObject *self, PyObject *args)
     88 {
     89     int fd;
     90     int flags;
     91     if (!PyArg_ParseTuple(args,"ii:setmode", &fd, &flags))
     92         return NULL;
     93 
     94     flags = _setmode(fd, flags);
     95     if (flags == -1)
     96         return PyErr_SetFromErrno(PyExc_IOError);
     97 
     98     return PyInt_FromLong(flags);
     99 }
    100 
    101 PyDoc_STRVAR(setmode_doc,
    102 "setmode(fd, mode) -> Previous mode\n\
    103 \n\
    104 Set the line-end translation mode for the file descriptor fd. To set\n\
    105 it to text mode, flags should be os.O_TEXT; for binary, it should be\n\
    106 os.O_BINARY.");
    107 
    108 // Convert an OS file handle to a C runtime file descriptor.
    109 static PyObject *
    110 msvcrt_open_osfhandle(PyObject *self, PyObject *args)
    111 {
    112     long handle;
    113     int flags;
    114     int fd;
    115 
    116     if (!PyArg_ParseTuple(args, "li:open_osfhandle", &handle, &flags))
    117         return NULL;
    118 
    119     fd = _open_osfhandle(handle, flags);
    120     if (fd == -1)
    121         return PyErr_SetFromErrno(PyExc_IOError);
    122 
    123     return PyInt_FromLong(fd);
    124 }
    125 
    126 PyDoc_STRVAR(open_osfhandle_doc,
    127 "open_osfhandle(handle, flags) -> file descriptor\n\
    128 \n\
    129 Create a C runtime file descriptor from the file handle handle. The\n\
    130 flags parameter should be a bitwise OR of os.O_APPEND, os.O_RDONLY,\n\
    131 and os.O_TEXT. The returned file descriptor may be used as a parameter\n\
    132 to os.fdopen() to create a file object.");
    133 
    134 // Convert a C runtime file descriptor to an OS file handle.
    135 static PyObject *
    136 msvcrt_get_osfhandle(PyObject *self, PyObject *args)
    137 {
    138     int fd;
    139     Py_intptr_t handle;
    140 
    141     if (!PyArg_ParseTuple(args,"i:get_osfhandle", &fd))
    142         return NULL;
    143 
    144     if (!_PyVerify_fd(fd))
    145         return PyErr_SetFromErrno(PyExc_IOError);
    146 
    147     handle = _get_osfhandle(fd);
    148     if (handle == -1)
    149         return PyErr_SetFromErrno(PyExc_IOError);
    150 
    151     /* technically 'handle' is not a pointer, but an integer as
    152        large as a pointer, Python's *VoidPtr interface is the
    153        most appropriate here */
    154     return PyLong_FromVoidPtr((void*)handle);
    155 }
    156 
    157 PyDoc_STRVAR(get_osfhandle_doc,
    158 "get_osfhandle(fd) -> file handle\n\
    159 \n\
    160 Return the file handle for the file descriptor fd. Raises IOError\n\
    161 if fd is not recognized.");
    162 
    163 /* Console I/O */
    164 
    165 static PyObject *
    166 msvcrt_kbhit(PyObject *self, PyObject *args)
    167 {
    168     int ok;
    169 
    170     if (!PyArg_ParseTuple(args, ":kbhit"))
    171         return NULL;
    172 
    173     ok = _kbhit();
    174     return PyInt_FromLong(ok);
    175 }
    176 
    177 PyDoc_STRVAR(kbhit_doc,
    178 "kbhit() -> bool\n\
    179 \n\
    180 Return true if a keypress is waiting to be read.");
    181 
    182 static PyObject *
    183 msvcrt_getch(PyObject *self, PyObject *args)
    184 {
    185     int ch;
    186     char s[1];
    187 
    188     if (!PyArg_ParseTuple(args, ":getch"))
    189         return NULL;
    190 
    191     Py_BEGIN_ALLOW_THREADS
    192     ch = _getch();
    193     Py_END_ALLOW_THREADS
    194     s[0] = ch;
    195     return PyString_FromStringAndSize(s, 1);
    196 }
    197 
    198 PyDoc_STRVAR(getch_doc,
    199 "getch() -> key character\n\
    200 \n\
    201 Read a keypress and return the resulting character. Nothing is echoed to\n\
    202 the console. This call will block if a keypress is not already\n\
    203 available, but will not wait for Enter to be pressed. If the pressed key\n\
    204 was a special function key, this will return '\\000' or '\\xe0'; the next\n\
    205 call will return the keycode. The Control-C keypress cannot be read with\n\
    206 this function.");
    207 
    208 #ifdef _WCONIO_DEFINED
    209 static PyObject *
    210 msvcrt_getwch(PyObject *self, PyObject *args)
    211 {
    212     Py_UNICODE ch;
    213     Py_UNICODE u[1];
    214 
    215     if (!PyArg_ParseTuple(args, ":getwch"))
    216         return NULL;
    217 
    218     Py_BEGIN_ALLOW_THREADS
    219     ch = _getwch();
    220     Py_END_ALLOW_THREADS
    221     u[0] = ch;
    222     return PyUnicode_FromUnicode(u, 1);
    223 }
    224 
    225 PyDoc_STRVAR(getwch_doc,
    226 "getwch() -> Unicode key character\n\
    227 \n\
    228 Wide char variant of getch(), returning a Unicode value.");
    229 #endif
    230 
    231 static PyObject *
    232 msvcrt_getche(PyObject *self, PyObject *args)
    233 {
    234     int ch;
    235     char s[1];
    236 
    237     if (!PyArg_ParseTuple(args, ":getche"))
    238         return NULL;
    239 
    240     Py_BEGIN_ALLOW_THREADS
    241     ch = _getche();
    242     Py_END_ALLOW_THREADS
    243     s[0] = ch;
    244     return PyString_FromStringAndSize(s, 1);
    245 }
    246 
    247 PyDoc_STRVAR(getche_doc,
    248 "getche() -> key character\n\
    249 \n\
    250 Similar to getch(), but the keypress will be echoed if it represents\n\
    251 a printable character.");
    252 
    253 #ifdef _WCONIO_DEFINED
    254 static PyObject *
    255 msvcrt_getwche(PyObject *self, PyObject *args)
    256 {
    257     Py_UNICODE ch;
    258     Py_UNICODE s[1];
    259 
    260     if (!PyArg_ParseTuple(args, ":getwche"))
    261         return NULL;
    262 
    263     Py_BEGIN_ALLOW_THREADS
    264     ch = _getwche();
    265     Py_END_ALLOW_THREADS
    266     s[0] = ch;
    267     return PyUnicode_FromUnicode(s, 1);
    268 }
    269 
    270 PyDoc_STRVAR(getwche_doc,
    271 "getwche() -> Unicode key character\n\
    272 \n\
    273 Wide char variant of getche(), returning a Unicode value.");
    274 #endif
    275 
    276 static PyObject *
    277 msvcrt_putch(PyObject *self, PyObject *args)
    278 {
    279     char ch;
    280 
    281     if (!PyArg_ParseTuple(args, "c:putch", &ch))
    282         return NULL;
    283 
    284     _putch(ch);
    285     Py_INCREF(Py_None);
    286     return Py_None;
    287 }
    288 
    289 PyDoc_STRVAR(putch_doc,
    290 "putch(char) -> None\n\
    291 \n\
    292 Print the character char to the console without buffering.");
    293 
    294 #ifdef _WCONIO_DEFINED
    295 static PyObject *
    296 msvcrt_putwch(PyObject *self, PyObject *args)
    297 {
    298     Py_UNICODE *ch;
    299     int size;
    300 
    301     if (!PyArg_ParseTuple(args, "u#:putwch", &ch, &size))
    302         return NULL;
    303 
    304     if (size == 0) {
    305         PyErr_SetString(PyExc_ValueError,
    306             "Expected unicode string of length 1");
    307         return NULL;
    308     }
    309     _putwch(*ch);
    310     Py_RETURN_NONE;
    311 
    312 }
    313 
    314 PyDoc_STRVAR(putwch_doc,
    315 "putwch(unicode_char) -> None\n\
    316 \n\
    317 Wide char variant of putch(), accepting a Unicode value.");
    318 #endif
    319 
    320 static PyObject *
    321 msvcrt_ungetch(PyObject *self, PyObject *args)
    322 {
    323     char ch;
    324 
    325     if (!PyArg_ParseTuple(args, "c:ungetch", &ch))
    326         return NULL;
    327 
    328     if (_ungetch(ch) == EOF)
    329         return PyErr_SetFromErrno(PyExc_IOError);
    330     Py_INCREF(Py_None);
    331     return Py_None;
    332 }
    333 
    334 PyDoc_STRVAR(ungetch_doc,
    335 "ungetch(char) -> None\n\
    336 \n\
    337 Cause the character char to be \"pushed back\" into the console buffer;\n\
    338 it will be the next character read by getch() or getche().");
    339 
    340 #ifdef _WCONIO_DEFINED
    341 static PyObject *
    342 msvcrt_ungetwch(PyObject *self, PyObject *args)
    343 {
    344     Py_UNICODE ch;
    345 
    346     if (!PyArg_ParseTuple(args, "u:ungetwch", &ch))
    347         return NULL;
    348 
    349     if (_ungetch(ch) == EOF)
    350         return PyErr_SetFromErrno(PyExc_IOError);
    351     Py_INCREF(Py_None);
    352     return Py_None;
    353 }
    354 
    355 PyDoc_STRVAR(ungetwch_doc,
    356 "ungetwch(unicode_char) -> None\n\
    357 \n\
    358 Wide char variant of ungetch(), accepting a Unicode value.");
    359 #endif
    360 
    361 static void
    362 insertint(PyObject *d, char *name, int value)
    363 {
    364     PyObject *v = PyInt_FromLong((long) value);
    365     if (v == NULL) {
    366         /* Don't bother reporting this error */
    367         PyErr_Clear();
    368     }
    369     else {
    370         PyDict_SetItemString(d, name, v);
    371         Py_DECREF(v);
    372     }
    373 }
    374 
    375 
    376 /* List of functions exported by this module */
    377 static struct PyMethodDef msvcrt_functions[] = {
    378     {"heapmin",                 msvcrt_heapmin, METH_VARARGS, heapmin_doc},
    379     {"locking",             msvcrt_locking, METH_VARARGS, locking_doc},
    380     {"setmode",                 msvcrt_setmode, METH_VARARGS, setmode_doc},
    381     {"open_osfhandle",          msvcrt_open_osfhandle, METH_VARARGS, open_osfhandle_doc},
    382     {"get_osfhandle",           msvcrt_get_osfhandle, METH_VARARGS, get_osfhandle_doc},
    383     {"kbhit",                   msvcrt_kbhit, METH_VARARGS, kbhit_doc},
    384     {"getch",                   msvcrt_getch, METH_VARARGS, getch_doc},
    385     {"getche",                  msvcrt_getche, METH_VARARGS, getche_doc},
    386     {"putch",                   msvcrt_putch, METH_VARARGS, putch_doc},
    387     {"ungetch",                 msvcrt_ungetch, METH_VARARGS, ungetch_doc},
    388 #ifdef _WCONIO_DEFINED
    389     {"getwch",                  msvcrt_getwch, METH_VARARGS, getwch_doc},
    390     {"getwche",                 msvcrt_getwche, METH_VARARGS, getwche_doc},
    391     {"putwch",                  msvcrt_putwch, METH_VARARGS, putwch_doc},
    392     {"ungetwch",                msvcrt_ungetwch, METH_VARARGS, ungetwch_doc},
    393 #endif
    394     {NULL,                      NULL}
    395 };
    396 
    397 PyMODINIT_FUNC
    398 initmsvcrt(void)
    399 {
    400     int st;
    401     PyObject *d;
    402     PyObject *m = Py_InitModule("msvcrt", msvcrt_functions);
    403     if (m == NULL)
    404         return;
    405     d = PyModule_GetDict(m);
    406 
    407     /* constants for the locking() function's mode argument */
    408     insertint(d, "LK_LOCK", _LK_LOCK);
    409     insertint(d, "LK_NBLCK", _LK_NBLCK);
    410     insertint(d, "LK_NBRLCK", _LK_NBRLCK);
    411     insertint(d, "LK_RLCK", _LK_RLCK);
    412     insertint(d, "LK_UNLCK", _LK_UNLCK);
    413 
    414     /* constants for the crt versions */
    415 #ifdef _VC_ASSEMBLY_PUBLICKEYTOKEN
    416     st = PyModule_AddStringConstant(m, "VC_ASSEMBLY_PUBLICKEYTOKEN",
    417                                     _VC_ASSEMBLY_PUBLICKEYTOKEN);
    418     if (st < 0)return;
    419 #endif
    420 #ifdef _CRT_ASSEMBLY_VERSION
    421     st = PyModule_AddStringConstant(m, "CRT_ASSEMBLY_VERSION",
    422                                     _CRT_ASSEMBLY_VERSION);
    423     if (st < 0)return;
    424 #endif
    425 #ifdef __LIBRARIES_ASSEMBLY_NAME_PREFIX
    426     st = PyModule_AddStringConstant(m, "LIBRARIES_ASSEMBLY_NAME_PREFIX",
    427                                     __LIBRARIES_ASSEMBLY_NAME_PREFIX);
    428     if (st < 0)return;
    429 #endif
    430 }
    431