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 21PyThreadState* _PyOS_ReadlineTState = NULL; 22 23static PyThread_type_lock _PyOS_ReadlineLock = NULL; 24 25int (*PyOS_InputHook)(void) = NULL; 26 27/* This function restarts a fgets() after an EINTR error occurred 28 except if _PyOS_InterruptOccurred() returns true. */ 29 30static int 31my_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 while (1) { 46 if (PyOS_InputHook != NULL) { 47 (void)(PyOS_InputHook)(); 48 } 49 50 errno = 0; 51 clearerr(fp); 52 char *p = fgets(buf, len, fp); 53 if (p != NULL) { 54 return 0; /* No error */ 55 } 56 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 if (feof(fp)) { 85 clearerr(fp); 86 return -1; /* EOF */ 87 } 88 89#ifdef EINTR 90 if (err == EINTR) { 91 PyEval_RestoreThread(tstate); 92 int s = PyErr_CheckSignals(); 93 PyEval_SaveThread(); 94 95 if (s < 0) { 96 return 1; 97 } 98 /* try again */ 99 continue; 100 } 101#endif 102 103 if (_PyOS_InterruptOccurred(tstate)) { 104 return 1; /* Interrupt */ 105 } 106 return -2; /* Error */ 107 } 108 /* NOTREACHED */ 109} 110 111#ifdef MS_WINDOWS 112/* Readline implementation using ReadConsoleW */ 113 114extern char _get_console_type(HANDLE handle); 115 116char * 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 223exit: 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 241char * 242PyOS_StdioReadline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt) 243{ 244 size_t n; 245 char *p, *pr; 246 PyThreadState *tstate = _PyOS_ReadlineTState; 247 assert(tstate != NULL); 248 249#ifdef MS_WINDOWS 250 if (!Py_LegacyWindowsStdioFlag && sys_stdin == stdin) { 251 HANDLE hStdIn, hStdErr; 252 253 hStdIn = _Py_get_osfhandle_noraise(fileno(sys_stdin)); 254 hStdErr = _Py_get_osfhandle_noraise(fileno(stderr)); 255 256 if (_get_console_type(hStdIn) == 'r') { 257 fflush(sys_stdout); 258 if (prompt) { 259 if (_get_console_type(hStdErr) == 'w') { 260 wchar_t *wbuf; 261 int wlen; 262 wlen = MultiByteToWideChar(CP_UTF8, 0, prompt, -1, 263 NULL, 0); 264 if (wlen) { 265 wbuf = PyMem_RawMalloc(wlen * sizeof(wchar_t)); 266 if (wbuf == NULL) { 267 PyEval_RestoreThread(tstate); 268 PyErr_NoMemory(); 269 PyEval_SaveThread(); 270 return NULL; 271 } 272 wlen = MultiByteToWideChar(CP_UTF8, 0, prompt, -1, 273 wbuf, wlen); 274 if (wlen) { 275 DWORD n; 276 fflush(stderr); 277 /* wlen includes null terminator, so subtract 1 */ 278 WriteConsoleW(hStdErr, wbuf, wlen - 1, &n, NULL); 279 } 280 PyMem_RawFree(wbuf); 281 } 282 } else { 283 fprintf(stderr, "%s", prompt); 284 fflush(stderr); 285 } 286 } 287 clearerr(sys_stdin); 288 return _PyOS_WindowsConsoleReadline(tstate, hStdIn); 289 } 290 } 291#endif 292 293 fflush(sys_stdout); 294 if (prompt) { 295 fprintf(stderr, "%s", prompt); 296 } 297 fflush(stderr); 298 299 n = 0; 300 p = NULL; 301 do { 302 size_t incr = (n > 0) ? n + 2 : 100; 303 if (incr > INT_MAX) { 304 PyMem_RawFree(p); 305 PyEval_RestoreThread(tstate); 306 PyErr_SetString(PyExc_OverflowError, "input line too long"); 307 PyEval_SaveThread(); 308 return NULL; 309 } 310 pr = (char *)PyMem_RawRealloc(p, n + incr); 311 if (pr == NULL) { 312 PyMem_RawFree(p); 313 PyEval_RestoreThread(tstate); 314 PyErr_NoMemory(); 315 PyEval_SaveThread(); 316 return NULL; 317 } 318 p = pr; 319 int err = my_fgets(tstate, p + n, (int)incr, sys_stdin); 320 if (err == 1) { 321 // Interrupt 322 PyMem_RawFree(p); 323 return NULL; 324 } else if (err != 0) { 325 // EOF or error 326 p[n] = '\0'; 327 break; 328 } 329 n += strlen(p + n); 330 } while (p[n-1] != '\n'); 331 332 pr = (char *)PyMem_RawRealloc(p, n+1); 333 if (pr == NULL) { 334 PyMem_RawFree(p); 335 PyEval_RestoreThread(tstate); 336 PyErr_NoMemory(); 337 PyEval_SaveThread(); 338 return NULL; 339 } 340 return pr; 341} 342 343 344/* By initializing this function pointer, systems embedding Python can 345 override the readline function. 346 347 Note: Python expects in return a buffer allocated with PyMem_Malloc. */ 348 349char *(*PyOS_ReadlineFunctionPointer)(FILE *, FILE *, const char *) = NULL; 350 351 352/* Interface used by tokenizer.c and bltinmodule.c */ 353 354char * 355PyOS_Readline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt) 356{ 357 char *rv, *res; 358 size_t len; 359 360 PyThreadState *tstate = _PyThreadState_GET(); 361 if (_PyOS_ReadlineTState == tstate) { 362 PyErr_SetString(PyExc_RuntimeError, 363 "can't re-enter readline"); 364 return NULL; 365 } 366 367 368 if (PyOS_ReadlineFunctionPointer == NULL) { 369 PyOS_ReadlineFunctionPointer = PyOS_StdioReadline; 370 } 371 372 if (_PyOS_ReadlineLock == NULL) { 373 _PyOS_ReadlineLock = PyThread_allocate_lock(); 374 if (_PyOS_ReadlineLock == NULL) { 375 PyErr_SetString(PyExc_MemoryError, "can't allocate lock"); 376 return NULL; 377 } 378 } 379 380 _PyOS_ReadlineTState = tstate; 381 Py_BEGIN_ALLOW_THREADS 382 PyThread_acquire_lock(_PyOS_ReadlineLock, 1); 383 384 /* This is needed to handle the unlikely case that the 385 * interpreter is in interactive mode *and* stdin/out are not 386 * a tty. This can happen, for example if python is run like 387 * this: python -i < test1.py 388 */ 389 if (!isatty (fileno (sys_stdin)) || !isatty (fileno (sys_stdout))) 390 rv = PyOS_StdioReadline (sys_stdin, sys_stdout, prompt); 391 else 392 rv = (*PyOS_ReadlineFunctionPointer)(sys_stdin, sys_stdout, 393 prompt); 394 Py_END_ALLOW_THREADS 395 396 PyThread_release_lock(_PyOS_ReadlineLock); 397 398 _PyOS_ReadlineTState = NULL; 399 400 if (rv == NULL) 401 return NULL; 402 403 len = strlen(rv) + 1; 404 res = PyMem_Malloc(len); 405 if (res != NULL) { 406 memcpy(res, rv, len); 407 } 408 else { 409 PyErr_NoMemory(); 410 } 411 PyMem_RawFree(rv); 412 413 return res; 414} 415