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