• 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 
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 *
msvcrt_heapmin(PyObject * self,PyObject * args)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 *
msvcrt_locking(PyObject * self,PyObject * args)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 *
msvcrt_setmode(PyObject * self,PyObject * args)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 *
msvcrt_open_osfhandle(PyObject * self,PyObject * args)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 *
msvcrt_get_osfhandle(PyObject * self,PyObject * args)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 *
msvcrt_kbhit(PyObject * self,PyObject * args)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 *
msvcrt_getch(PyObject * self,PyObject * args)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 *
msvcrt_getwch(PyObject * self,PyObject * args)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 *
msvcrt_getche(PyObject * self,PyObject * args)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 *
msvcrt_getwche(PyObject * self,PyObject * args)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 *
msvcrt_putch(PyObject * self,PyObject * args)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 *
msvcrt_putwch(PyObject * self,PyObject * args)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 *
msvcrt_ungetch(PyObject * self,PyObject * args)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 *
msvcrt_ungetwch(PyObject * self,PyObject * args)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
insertint(PyObject * d,char * name,int value)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
initmsvcrt(void)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