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]
36class intptr_t_converter(CConverter):
37    type = 'intptr_t'
38    format_unit = '"_Py_PARSE_INTPTR"'
39
40class handle_return_converter(long_return_converter):
41    type = 'intptr_t'
42    cast = '(void *)'
43    conversion_fn = 'PyLong_FromVoidPtr'
44
45class 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
54class 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]
65module 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]
72msvcrt.heapmin
73
74Minimize the malloc() heap.
75
76Force the malloc() heap to clean itself up and return unused blocks
77to the operating system. On failure, this raises OSError.
78[clinic start generated code]*/
79
80static PyObject *
81msvcrt_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]
90msvcrt.locking
91
92    fd: int
93    mode: int
94    nbytes: long
95    /
96
97Lock part of a file based on file descriptor fd from the C runtime.
98
99Raises IOError on failure. The locked region of the file extends from
100the current file position for nbytes bytes, and may continue beyond
101the end of the file. mode must be one of the LK_* constants listed
102below. Multiple regions in a file may be locked at the same time, but
103may not overlap. Adjacent regions are not merged; they must be unlocked
104individually.
105[clinic start generated code]*/
106
107static PyObject *
108msvcrt_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]
125msvcrt.setmode -> long
126
127    fd: int
128    mode as flags: int
129    /
130
131Set the line-end translation mode for the file descriptor fd.
132
133To set it to text mode, flags should be os.O_TEXT; for binary, it
134should be os.O_BINARY.
135
136Return value is the previous mode.
137[clinic start generated code]*/
138
139static long
140msvcrt_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]
153msvcrt.open_osfhandle -> long
154
155    handle: intptr_t
156    flags: int
157    /
158
159Create a C runtime file descriptor from the file handle handle.
160
161The flags parameter should be a bitwise OR of os.O_APPEND, os.O_RDONLY,
162and os.O_TEXT. The returned file descriptor may be used as a parameter
163to os.fdopen() to create a file object.
164[clinic start generated code]*/
165
166static long
167msvcrt_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]
182msvcrt.get_osfhandle -> handle
183
184    fd: int
185    /
186
187Return the file handle for the file descriptor fd.
188
189Raises IOError if fd is not recognized.
190[clinic start generated code]*/
191
192static intptr_t
193msvcrt_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]
209msvcrt.kbhit -> long
210
211Return true if a keypress is waiting to be read.
212[clinic start generated code]*/
213
214static long
215msvcrt_kbhit_impl(PyObject *module)
216/*[clinic end generated code: output=940dfce6587c1890 input=e70d678a5c2f6acc]*/
217{
218    return _kbhit();
219}
220
221/*[clinic input]
222msvcrt.getch -> byte_char
223
224Read a keypress and return the resulting character as a byte string.
225
226Nothing is echoed to the console. This call will block if a keypress is
227not already available, but will not wait for Enter to be pressed. If the
228pressed key was a special function key, this will return '\000' or
229'\xe0'; the next call will return the keycode. The Control-C keypress
230cannot be read with this function.
231[clinic start generated code]*/
232
233static int
234msvcrt_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]
246msvcrt.getwch -> wchar_t
247
248Wide char variant of getch(), returning a Unicode value.
249[clinic start generated code]*/
250
251static wchar_t
252msvcrt_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]
264msvcrt.getche -> byte_char
265
266Similar to getch(), but the keypress will be echoed if possible.
267[clinic start generated code]*/
268
269static int
270msvcrt_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]
282msvcrt.getwche -> wchar_t
283
284Wide char variant of getche(), returning a Unicode value.
285[clinic start generated code]*/
286
287static wchar_t
288msvcrt_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]
300msvcrt.putch
301
302    char: char
303    /
304
305Print the byte string char to the console without buffering.
306[clinic start generated code]*/
307
308static PyObject *
309msvcrt_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]
319msvcrt.putwch
320
321    unicode_char: int(accept={str})
322    /
323
324Wide char variant of putch(), accepting a Unicode value.
325[clinic start generated code]*/
326
327static PyObject *
328msvcrt_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]
339msvcrt.ungetch
340
341    char: char
342    /
343
344Opposite of getch.
345
346Cause the byte string char to be "pushed back" into the
347console buffer; it will be the next character read by
348getch() or getche().
349[clinic start generated code]*/
350
351static PyObject *
352msvcrt_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]
367msvcrt.ungetwch
368
369    unicode_char: int(accept={str})
370    /
371
372Wide char variant of ungetch(), accepting a Unicode value.
373[clinic start generated code]*/
374
375static PyObject *
376msvcrt_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]
392msvcrt.CrtSetReportFile -> long
393
394    type: int
395    file: int
396    /
397
398Wrapper around _CrtSetReportFile.
399
400Only available on Debug builds.
401[clinic start generated code]*/
402
403static long
404msvcrt_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]
417msvcrt.CrtSetReportMode -> long
418
419    type: int
420    mode: int
421    /
422
423Wrapper around _CrtSetReportMode.
424
425Only available on Debug builds.
426[clinic start generated code]*/
427
428static long
429msvcrt_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]
443msvcrt.set_error_mode -> long
444
445    mode: int
446    /
447
448Wrapper around _set_error_mode.
449
450Only available on Debug builds.
451[clinic start generated code]*/
452
453static long
454msvcrt_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]
468msvcrt.SetErrorMode
469
470    mode: unsigned_int(bitwise=True)
471    /
472
473Wrapper around SetErrorMode.
474[clinic start generated code]*/
475
476static PyObject *
477msvcrt_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 */
494static 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
517static 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
529static void
530insertint(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
543PyMODINIT_FUNC
544PyInit_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