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