Line data Source code
1 :
2 : /* Readline interface for tokenizer.c and [raw_]input() in bltinmodule.c.
3 : By default, or when stdin is not a tty device, we have a super
4 : simple my_readline function using fgets.
5 : Optionally, we can use the GNU readline library.
6 : my_readline() has a different return value from GNU readline():
7 : - NULL if an interrupt occurred or if an error occurred
8 : - a malloc'ed empty string if EOF was read
9 : - a malloc'ed string ending in \n normally
10 : */
11 :
12 : #include "Python.h"
13 : #include "pycore_fileutils.h" // _Py_BEGIN_SUPPRESS_IPH
14 : #include "pycore_pystate.h" // _PyThreadState_GET()
15 : #ifdef MS_WINDOWS
16 : # define WIN32_LEAN_AND_MEAN
17 : # include "windows.h"
18 : #endif /* MS_WINDOWS */
19 :
20 :
21 : PyThreadState* _PyOS_ReadlineTState = NULL;
22 :
23 : static PyThread_type_lock _PyOS_ReadlineLock = NULL;
24 :
25 : int (*PyOS_InputHook)(void) = NULL;
26 :
27 : /* This function restarts a fgets() after an EINTR error occurred
28 : except if _PyOS_InterruptOccurred() returns true. */
29 :
30 : static int
31 52 : my_fgets(PyThreadState* tstate, char *buf, int len, FILE *fp)
32 : {
33 : #ifdef MS_WINDOWS
34 : HANDLE handle;
35 : _Py_BEGIN_SUPPRESS_IPH
36 : handle = (HANDLE)_get_osfhandle(fileno(fp));
37 : _Py_END_SUPPRESS_IPH
38 :
39 : /* bpo-40826: fgets(fp) does crash if fileno(fp) is closed */
40 : if (handle == INVALID_HANDLE_VALUE) {
41 : return -1; /* EOF */
42 : }
43 : #endif
44 :
45 0 : while (1) {
46 52 : if (PyOS_InputHook != NULL) {
47 0 : (void)(PyOS_InputHook)();
48 : }
49 :
50 52 : errno = 0;
51 52 : clearerr(fp);
52 52 : char *p = fgets(buf, len, fp);
53 52 : if (p != NULL) {
54 45 : return 0; /* No error */
55 : }
56 7 : int err = errno;
57 :
58 : #ifdef MS_WINDOWS
59 : /* Ctrl-C anywhere on the line or Ctrl-Z if the only character
60 : on a line will set ERROR_OPERATION_ABORTED. Under normal
61 : circumstances Ctrl-C will also have caused the SIGINT handler
62 : to fire which will have set the event object returned by
63 : _PyOS_SigintEvent. This signal fires in another thread and
64 : is not guaranteed to have occurred before this point in the
65 : code.
66 :
67 : Therefore: check whether the event is set with a small timeout.
68 : If it is, assume this is a Ctrl-C and reset the event. If it
69 : isn't set assume that this is a Ctrl-Z on its own and drop
70 : through to check for EOF.
71 : */
72 : if (GetLastError()==ERROR_OPERATION_ABORTED) {
73 : HANDLE hInterruptEvent = _PyOS_SigintEvent();
74 : switch (WaitForSingleObjectEx(hInterruptEvent, 10, FALSE)) {
75 : case WAIT_OBJECT_0:
76 : ResetEvent(hInterruptEvent);
77 : return 1; /* Interrupt */
78 : case WAIT_FAILED:
79 : return -2; /* Error */
80 : }
81 : }
82 : #endif /* MS_WINDOWS */
83 :
84 7 : if (feof(fp)) {
85 6 : clearerr(fp);
86 6 : return -1; /* EOF */
87 : }
88 :
89 : #ifdef EINTR
90 1 : if (err == EINTR) {
91 0 : PyEval_RestoreThread(tstate);
92 0 : int s = PyErr_CheckSignals();
93 0 : PyEval_SaveThread();
94 :
95 0 : if (s < 0) {
96 0 : return 1;
97 : }
98 : /* try again */
99 0 : continue;
100 : }
101 : #endif
102 :
103 1 : if (_PyOS_InterruptOccurred(tstate)) {
104 0 : return 1; /* Interrupt */
105 : }
106 1 : return -2; /* Error */
107 : }
108 : /* NOTREACHED */
109 : }
110 :
111 : #ifdef MS_WINDOWS
112 : /* Readline implementation using ReadConsoleW */
113 :
114 : extern char _get_console_type(HANDLE handle);
115 :
116 : char *
117 : _PyOS_WindowsConsoleReadline(PyThreadState *tstate, HANDLE hStdIn)
118 : {
119 : static wchar_t wbuf_local[1024 * 16];
120 : const DWORD chunk_size = 1024;
121 :
122 : DWORD n_read, total_read, wbuflen, u8len;
123 : wchar_t *wbuf;
124 : char *buf = NULL;
125 : int err = 0;
126 :
127 : n_read = (DWORD)-1;
128 : total_read = 0;
129 : wbuf = wbuf_local;
130 : wbuflen = sizeof(wbuf_local) / sizeof(wbuf_local[0]) - 1;
131 : while (1) {
132 : if (PyOS_InputHook != NULL) {
133 : (void)(PyOS_InputHook)();
134 : }
135 : if (!ReadConsoleW(hStdIn, &wbuf[total_read], wbuflen - total_read, &n_read, NULL)) {
136 : err = GetLastError();
137 : goto exit;
138 : }
139 : if (n_read == (DWORD)-1 && (err = GetLastError()) == ERROR_OPERATION_ABORTED) {
140 : break;
141 : }
142 : if (n_read == 0) {
143 : int s;
144 : err = GetLastError();
145 : if (err != ERROR_OPERATION_ABORTED)
146 : goto exit;
147 : err = 0;
148 : HANDLE hInterruptEvent = _PyOS_SigintEvent();
149 : if (WaitForSingleObjectEx(hInterruptEvent, 100, FALSE)
150 : == WAIT_OBJECT_0) {
151 : ResetEvent(hInterruptEvent);
152 : PyEval_RestoreThread(tstate);
153 : s = PyErr_CheckSignals();
154 : PyEval_SaveThread();
155 : if (s < 0) {
156 : goto exit;
157 : }
158 : }
159 : break;
160 : }
161 :
162 : total_read += n_read;
163 : if (total_read == 0 || wbuf[total_read - 1] == L'\n') {
164 : break;
165 : }
166 : wbuflen += chunk_size;
167 : if (wbuf == wbuf_local) {
168 : wbuf[total_read] = '\0';
169 : wbuf = (wchar_t*)PyMem_RawMalloc(wbuflen * sizeof(wchar_t));
170 : if (wbuf) {
171 : wcscpy_s(wbuf, wbuflen, wbuf_local);
172 : }
173 : else {
174 : PyEval_RestoreThread(tstate);
175 : PyErr_NoMemory();
176 : PyEval_SaveThread();
177 : goto exit;
178 : }
179 : }
180 : else {
181 : wchar_t *tmp = PyMem_RawRealloc(wbuf, wbuflen * sizeof(wchar_t));
182 : if (tmp == NULL) {
183 : PyEval_RestoreThread(tstate);
184 : PyErr_NoMemory();
185 : PyEval_SaveThread();
186 : goto exit;
187 : }
188 : wbuf = tmp;
189 : }
190 : }
191 :
192 : if (wbuf[0] == '\x1a') {
193 : buf = PyMem_RawMalloc(1);
194 : if (buf) {
195 : buf[0] = '\0';
196 : }
197 : else {
198 : PyEval_RestoreThread(tstate);
199 : PyErr_NoMemory();
200 : PyEval_SaveThread();
201 : }
202 : goto exit;
203 : }
204 :
205 : u8len = WideCharToMultiByte(CP_UTF8, 0,
206 : wbuf, total_read,
207 : NULL, 0,
208 : NULL, NULL);
209 : buf = PyMem_RawMalloc(u8len + 1);
210 : if (buf == NULL) {
211 : PyEval_RestoreThread(tstate);
212 : PyErr_NoMemory();
213 : PyEval_SaveThread();
214 : goto exit;
215 : }
216 :
217 : u8len = WideCharToMultiByte(CP_UTF8, 0,
218 : wbuf, total_read,
219 : buf, u8len,
220 : NULL, NULL);
221 : buf[u8len] = '\0';
222 :
223 : exit:
224 : if (wbuf != wbuf_local) {
225 : PyMem_RawFree(wbuf);
226 : }
227 :
228 : if (err) {
229 : PyEval_RestoreThread(tstate);
230 : PyErr_SetFromWindowsErr(err);
231 : PyEval_SaveThread();
232 : }
233 : return buf;
234 : }
235 :
236 : #endif
237 :
238 :
239 : /* Readline implementation using fgets() */
240 :
241 : char *
242 52 : PyOS_StdioReadline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt)
243 : {
244 : size_t n;
245 : char *p, *pr;
246 52 : PyThreadState *tstate = _PyOS_ReadlineTState;
247 52 : assert(tstate != NULL);
248 :
249 : #ifdef MS_WINDOWS
250 : const PyConfig *config = _PyInterpreterState_GetConfig(tstate->interp);
251 : if (!config->legacy_windows_stdio && sys_stdin == stdin) {
252 : HANDLE hStdIn, hStdErr;
253 :
254 : hStdIn = _Py_get_osfhandle_noraise(fileno(sys_stdin));
255 : hStdErr = _Py_get_osfhandle_noraise(fileno(stderr));
256 :
257 : if (_get_console_type(hStdIn) == 'r') {
258 : fflush(sys_stdout);
259 : if (prompt) {
260 : if (_get_console_type(hStdErr) == 'w') {
261 : wchar_t *wbuf;
262 : int wlen;
263 : wlen = MultiByteToWideChar(CP_UTF8, 0, prompt, -1,
264 : NULL, 0);
265 : if (wlen) {
266 : wbuf = PyMem_RawMalloc(wlen * sizeof(wchar_t));
267 : if (wbuf == NULL) {
268 : PyEval_RestoreThread(tstate);
269 : PyErr_NoMemory();
270 : PyEval_SaveThread();
271 : return NULL;
272 : }
273 : wlen = MultiByteToWideChar(CP_UTF8, 0, prompt, -1,
274 : wbuf, wlen);
275 : if (wlen) {
276 : DWORD n;
277 : fflush(stderr);
278 : /* wlen includes null terminator, so subtract 1 */
279 : WriteConsoleW(hStdErr, wbuf, wlen - 1, &n, NULL);
280 : }
281 : PyMem_RawFree(wbuf);
282 : }
283 : } else {
284 : fprintf(stderr, "%s", prompt);
285 : fflush(stderr);
286 : }
287 : }
288 : clearerr(sys_stdin);
289 : return _PyOS_WindowsConsoleReadline(tstate, hStdIn);
290 : }
291 : }
292 : #endif
293 :
294 52 : fflush(sys_stdout);
295 52 : if (prompt) {
296 52 : fprintf(stderr, "%s", prompt);
297 : }
298 52 : fflush(stderr);
299 :
300 52 : n = 0;
301 52 : p = NULL;
302 : do {
303 52 : size_t incr = (n > 0) ? n + 2 : 100;
304 52 : if (incr > INT_MAX) {
305 0 : PyMem_RawFree(p);
306 0 : PyEval_RestoreThread(tstate);
307 0 : PyErr_SetString(PyExc_OverflowError, "input line too long");
308 0 : PyEval_SaveThread();
309 0 : return NULL;
310 : }
311 52 : pr = (char *)PyMem_RawRealloc(p, n + incr);
312 52 : if (pr == NULL) {
313 0 : PyMem_RawFree(p);
314 0 : PyEval_RestoreThread(tstate);
315 0 : PyErr_NoMemory();
316 0 : PyEval_SaveThread();
317 0 : return NULL;
318 : }
319 52 : p = pr;
320 52 : int err = my_fgets(tstate, p + n, (int)incr, sys_stdin);
321 52 : if (err == 1) {
322 : // Interrupt
323 0 : PyMem_RawFree(p);
324 0 : return NULL;
325 52 : } else if (err != 0) {
326 : // EOF or error
327 7 : p[n] = '\0';
328 7 : break;
329 : }
330 45 : n += strlen(p + n);
331 45 : } while (p[n-1] != '\n');
332 :
333 52 : pr = (char *)PyMem_RawRealloc(p, n+1);
334 52 : if (pr == NULL) {
335 0 : PyMem_RawFree(p);
336 0 : PyEval_RestoreThread(tstate);
337 0 : PyErr_NoMemory();
338 0 : PyEval_SaveThread();
339 0 : return NULL;
340 : }
341 52 : return pr;
342 : }
343 :
344 :
345 : /* By initializing this function pointer, systems embedding Python can
346 : override the readline function.
347 :
348 : Note: Python expects in return a buffer allocated with PyMem_Malloc. */
349 :
350 : char *(*PyOS_ReadlineFunctionPointer)(FILE *, FILE *, const char *) = NULL;
351 :
352 :
353 : /* Interface used by tokenizer.c and bltinmodule.c */
354 :
355 : char *
356 56 : PyOS_Readline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt)
357 : {
358 : char *rv, *res;
359 : size_t len;
360 :
361 56 : PyThreadState *tstate = _PyThreadState_GET();
362 56 : if (_PyOS_ReadlineTState == tstate) {
363 0 : PyErr_SetString(PyExc_RuntimeError,
364 : "can't re-enter readline");
365 0 : return NULL;
366 : }
367 :
368 :
369 56 : if (PyOS_ReadlineFunctionPointer == NULL) {
370 0 : PyOS_ReadlineFunctionPointer = PyOS_StdioReadline;
371 : }
372 :
373 56 : if (_PyOS_ReadlineLock == NULL) {
374 16 : _PyOS_ReadlineLock = PyThread_allocate_lock();
375 16 : if (_PyOS_ReadlineLock == NULL) {
376 0 : PyErr_SetString(PyExc_MemoryError, "can't allocate lock");
377 0 : return NULL;
378 : }
379 : }
380 :
381 56 : _PyOS_ReadlineTState = tstate;
382 56 : Py_BEGIN_ALLOW_THREADS
383 56 : PyThread_acquire_lock(_PyOS_ReadlineLock, 1);
384 :
385 : /* This is needed to handle the unlikely case that the
386 : * interpreter is in interactive mode *and* stdin/out are not
387 : * a tty. This can happen, for example if python is run like
388 : * this: python -i < test1.py
389 : */
390 56 : if (!isatty (fileno (sys_stdin)) || !isatty (fileno (sys_stdout)))
391 52 : rv = PyOS_StdioReadline (sys_stdin, sys_stdout, prompt);
392 : else
393 4 : rv = (*PyOS_ReadlineFunctionPointer)(sys_stdin, sys_stdout,
394 : prompt);
395 56 : Py_END_ALLOW_THREADS
396 :
397 56 : PyThread_release_lock(_PyOS_ReadlineLock);
398 :
399 56 : _PyOS_ReadlineTState = NULL;
400 :
401 56 : if (rv == NULL)
402 0 : return NULL;
403 :
404 56 : len = strlen(rv) + 1;
405 56 : res = PyMem_Malloc(len);
406 56 : if (res != NULL) {
407 56 : memcpy(res, rv, len);
408 : }
409 : else {
410 0 : PyErr_NoMemory();
411 : }
412 56 : PyMem_RawFree(rv);
413 :
414 56 : return res;
415 : }
|