diff options
Diffstat (limited to 'Parser/myreadline.c')
-rw-r--r-- | Parser/myreadline.c | 280 |
1 files changed, 65 insertions, 215 deletions
diff --git a/Parser/myreadline.c b/Parser/myreadline.c index 43e5583..5376214 100644 --- a/Parser/myreadline.c +++ b/Parser/myreadline.c @@ -10,31 +10,40 @@ */ #include "Python.h" -#include "pycore_pystate.h" #ifdef MS_WINDOWS #define WIN32_LEAN_AND_MEAN #include "windows.h" #endif /* MS_WINDOWS */ +#ifdef __VMS +extern char* vms__StdioReadline(FILE *sys_stdin, FILE *sys_stdout, char *prompt); +#endif + -PyThreadState* _PyOS_ReadlineTState = NULL; +PyThreadState* _PyOS_ReadlineTState; +#ifdef WITH_THREAD #include "pythread.h" static PyThread_type_lock _PyOS_ReadlineLock = NULL; +#endif int (*PyOS_InputHook)(void) = NULL; +#ifdef RISCOS +int Py_RISCOSWimpFlag; +#endif + /* This function restarts a fgets() after an EINTR error occurred except if PyOS_InterruptOccurred() returns true. */ static int my_fgets(char *buf, int len, FILE *fp) { + char *p; #ifdef MS_WINDOWS - HANDLE hInterruptEvent; + int i; #endif - char *p; - int err; + while (1) { if (PyOS_InputHook != NULL) (void)(PyOS_InputHook)(); @@ -43,29 +52,24 @@ my_fgets(char *buf, int len, FILE *fp) p = fgets(buf, len, fp); if (p != NULL) return 0; /* No error */ - err = errno; #ifdef MS_WINDOWS /* Ctrl-C anywhere on the line or Ctrl-Z if the only character on a line will set ERROR_OPERATION_ABORTED. Under normal circumstances Ctrl-C will also have caused the SIGINT handler - to fire which will have set the event object returned by - _PyOS_SigintEvent. This signal fires in another thread and - is not guaranteed to have occurred before this point in the - code. - - Therefore: check whether the event is set with a small timeout. - If it is, assume this is a Ctrl-C and reset the event. If it - isn't set assume that this is a Ctrl-Z on its own and drop - through to check for EOF. + to fire. This signal fires in another thread and is not + guaranteed to have occurred before this point in the code. + + Therefore: check in a small loop to see if the trigger has + fired, in which case assume this is a Ctrl-C event. If it + hasn't fired within 10ms assume that this is a Ctrl-Z on its + own or that the signal isn't going to fire for some other + reason and drop through to check for EOF. */ if (GetLastError()==ERROR_OPERATION_ABORTED) { - hInterruptEvent = _PyOS_SigintEvent(); - switch (WaitForSingleObjectEx(hInterruptEvent, 10, FALSE)) { - case WAIT_OBJECT_0: - ResetEvent(hInterruptEvent); - return 1; /* Interrupt */ - case WAIT_FAILED: - return -2; /* Error */ + for (i = 0; i < 10; i++) { + if (PyOS_InterruptOccurred()) + return 1; + Sleep(1); } } #endif /* MS_WINDOWS */ @@ -74,14 +78,18 @@ my_fgets(char *buf, int len, FILE *fp) return -1; /* EOF */ } #ifdef EINTR - if (err == EINTR) { + if (errno == EINTR) { int s; +#ifdef WITH_THREAD PyEval_RestoreThread(_PyOS_ReadlineTState); +#endif s = PyErr_CheckSignals(); +#ifdef WITH_THREAD PyEval_SaveThread(); +#endif if (s < 0) return 1; - /* try again */ + /* try again */ continue; } #endif @@ -93,185 +101,35 @@ my_fgets(char *buf, int len, FILE *fp) /* NOTREACHED */ } -#ifdef MS_WINDOWS -/* Readline implementation using ReadConsoleW */ - -extern char _get_console_type(HANDLE handle); - -char * -_PyOS_WindowsConsoleReadline(HANDLE hStdIn) -{ - static wchar_t wbuf_local[1024 * 16]; - const DWORD chunk_size = 1024; - - DWORD n_read, total_read, wbuflen, u8len; - wchar_t *wbuf; - char *buf = NULL; - int err = 0; - - n_read = (DWORD)-1; - total_read = 0; - wbuf = wbuf_local; - wbuflen = sizeof(wbuf_local) / sizeof(wbuf_local[0]) - 1; - while (1) { - if (PyOS_InputHook != NULL) { - (void)(PyOS_InputHook)(); - } - if (!ReadConsoleW(hStdIn, &wbuf[total_read], wbuflen - total_read, &n_read, NULL)) { - err = GetLastError(); - goto exit; - } - if (n_read == (DWORD)-1 && (err = GetLastError()) == ERROR_OPERATION_ABORTED) { - break; - } - if (n_read == 0) { - int s; - err = GetLastError(); - if (err != ERROR_OPERATION_ABORTED) - goto exit; - err = 0; - HANDLE hInterruptEvent = _PyOS_SigintEvent(); - if (WaitForSingleObjectEx(hInterruptEvent, 100, FALSE) - == WAIT_OBJECT_0) { - ResetEvent(hInterruptEvent); - PyEval_RestoreThread(_PyOS_ReadlineTState); - s = PyErr_CheckSignals(); - PyEval_SaveThread(); - if (s < 0) - goto exit; - } - break; - } - - total_read += n_read; - if (total_read == 0 || wbuf[total_read - 1] == L'\n') { - break; - } - wbuflen += chunk_size; - if (wbuf == wbuf_local) { - wbuf[total_read] = '\0'; - wbuf = (wchar_t*)PyMem_RawMalloc(wbuflen * sizeof(wchar_t)); - if (wbuf) - wcscpy_s(wbuf, wbuflen, wbuf_local); - else { - PyErr_NoMemory(); - goto exit; - } - } - else { - wchar_t *tmp = PyMem_RawRealloc(wbuf, wbuflen * sizeof(wchar_t)); - if (tmp == NULL) { - PyErr_NoMemory(); - goto exit; - } - wbuf = tmp; - } - } - - if (wbuf[0] == '\x1a') { - buf = PyMem_RawMalloc(1); - if (buf) - buf[0] = '\0'; - else { - PyErr_NoMemory(); - } - goto exit; - } - - u8len = WideCharToMultiByte(CP_UTF8, 0, wbuf, total_read, NULL, 0, NULL, NULL); - buf = PyMem_RawMalloc(u8len + 1); - if (buf == NULL) { - PyErr_NoMemory(); - goto exit; - } - u8len = WideCharToMultiByte(CP_UTF8, 0, wbuf, total_read, buf, u8len, NULL, NULL); - buf[u8len] = '\0'; - -exit: - if (wbuf != wbuf_local) - PyMem_RawFree(wbuf); - - if (err) { - PyEval_RestoreThread(_PyOS_ReadlineTState); - PyErr_SetFromWindowsErr(err); - PyEval_SaveThread(); - } - - return buf; -} - -#endif - /* Readline implementation using fgets() */ char * -PyOS_StdioReadline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt) +PyOS_StdioReadline(FILE *sys_stdin, FILE *sys_stdout, char *prompt) { size_t n; char *p, *pr; - -#ifdef MS_WINDOWS - if (!Py_LegacyWindowsStdioFlag && sys_stdin == stdin) { - HANDLE hStdIn, hStdErr; - - _Py_BEGIN_SUPPRESS_IPH - hStdIn = (HANDLE)_get_osfhandle(fileno(sys_stdin)); - hStdErr = (HANDLE)_get_osfhandle(fileno(stderr)); - _Py_END_SUPPRESS_IPH - - if (_get_console_type(hStdIn) == 'r') { - fflush(sys_stdout); - if (prompt) { - if (_get_console_type(hStdErr) == 'w') { - wchar_t *wbuf; - int wlen; - wlen = MultiByteToWideChar(CP_UTF8, 0, prompt, -1, - NULL, 0); - if (wlen) { - wbuf = PyMem_RawMalloc(wlen * sizeof(wchar_t)); - if (wbuf == NULL) { - PyErr_NoMemory(); - return NULL; - } - wlen = MultiByteToWideChar(CP_UTF8, 0, prompt, -1, - wbuf, wlen); - if (wlen) { - DWORD n; - fflush(stderr); - /* wlen includes null terminator, so subtract 1 */ - WriteConsoleW(hStdErr, wbuf, wlen - 1, &n, NULL); - } - PyMem_RawFree(wbuf); - } - } else { - fprintf(stderr, "%s", prompt); - fflush(stderr); - } - } - clearerr(sys_stdin); - return _PyOS_WindowsConsoleReadline(hStdIn); - } - } -#endif - n = 100; - p = (char *)PyMem_RawMalloc(n); - if (p == NULL) { - PyErr_NoMemory(); + if ((p = (char *)PyMem_MALLOC(n)) == NULL) return NULL; - } - fflush(sys_stdout); +#ifndef RISCOS if (prompt) fprintf(stderr, "%s", prompt); +#else + if (prompt) { + if(Py_RISCOSWimpFlag) + fprintf(stderr, "\x0cr%s\x0c", prompt); + else + fprintf(stderr, "%s", prompt); + } +#endif fflush(stderr); - switch (my_fgets(p, (int)n, sys_stdin)) { case 0: /* Normal case */ break; case 1: /* Interrupt */ - PyMem_RawFree(p); + PyMem_FREE(p); return NULL; case -1: /* EOF */ case -2: /* Error */ @@ -283,13 +141,13 @@ PyOS_StdioReadline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt) while (n > 0 && p[n-1] != '\n') { size_t incr = n+2; if (incr > INT_MAX) { - PyMem_RawFree(p); + PyMem_FREE(p); PyErr_SetString(PyExc_OverflowError, "input line too long"); return NULL; } - pr = (char *)PyMem_RawRealloc(p, n + incr); + pr = (char *)PyMem_REALLOC(p, n + incr); if (pr == NULL) { - PyMem_RawFree(p); + PyMem_FREE(p); PyErr_NoMemory(); return NULL; } @@ -298,9 +156,9 @@ PyOS_StdioReadline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt) break; n += strlen(p+n); } - pr = (char *)PyMem_RawRealloc(p, n+1); + pr = (char *)PyMem_REALLOC(p, n+1); if (pr == NULL) { - PyMem_RawFree(p); + PyMem_FREE(p); PyErr_NoMemory(); return NULL; } @@ -313,18 +171,17 @@ PyOS_StdioReadline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt) Note: Python expects in return a buffer allocated with PyMem_Malloc. */ -char *(*PyOS_ReadlineFunctionPointer)(FILE *, FILE *, const char *) = NULL; +char *(*PyOS_ReadlineFunctionPointer)(FILE *, FILE *, char *); /* Interface used by tokenizer.c and bltinmodule.c */ char * -PyOS_Readline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt) +PyOS_Readline(FILE *sys_stdin, FILE *sys_stdout, char *prompt) { - char *rv, *res; - size_t len; + char *rv; - if (_PyOS_ReadlineTState == _PyThreadState_GET()) { + if (_PyOS_ReadlineTState == PyThreadState_GET()) { PyErr_SetString(PyExc_RuntimeError, "can't re-enter readline"); return NULL; @@ -332,20 +189,24 @@ PyOS_Readline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt) if (PyOS_ReadlineFunctionPointer == NULL) { +#ifdef __VMS + PyOS_ReadlineFunctionPointer = vms__StdioReadline; +#else PyOS_ReadlineFunctionPointer = PyOS_StdioReadline; +#endif } +#ifdef WITH_THREAD if (_PyOS_ReadlineLock == NULL) { _PyOS_ReadlineLock = PyThread_allocate_lock(); - if (_PyOS_ReadlineLock == NULL) { - PyErr_SetString(PyExc_MemoryError, "can't allocate lock"); - return NULL; - } } +#endif - _PyOS_ReadlineTState = _PyThreadState_GET(); + _PyOS_ReadlineTState = PyThreadState_GET(); Py_BEGIN_ALLOW_THREADS +#ifdef WITH_THREAD PyThread_acquire_lock(_PyOS_ReadlineLock, 1); +#endif /* This is needed to handle the unlikely case that the * interpreter is in interactive mode *and* stdin/out are not @@ -359,22 +220,11 @@ PyOS_Readline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt) prompt); Py_END_ALLOW_THREADS +#ifdef WITH_THREAD PyThread_release_lock(_PyOS_ReadlineLock); +#endif _PyOS_ReadlineTState = NULL; - if (rv == NULL) - return NULL; - - len = strlen(rv) + 1; - res = PyMem_Malloc(len); - if (res != NULL) { - memcpy(res, rv, len); - } - else { - PyErr_NoMemory(); - } - PyMem_RawFree(rv); - - return res; + return rv; } |