|  | 
 | /* Readline interface for tokenizer.c and [raw_]input() in bltinmodule.c. | 
 |    By default, or when stdin is not a tty device, we have a super | 
 |    simple my_readline function using fgets. | 
 |    Optionally, we can use the GNU readline library. | 
 |    my_readline() has a different return value from GNU readline(): | 
 |    - NULL if an interrupt occurred or if an error occurred | 
 |    - a malloc'ed empty string if EOF was read | 
 |    - a malloc'ed string ending in \n normally | 
 | */ | 
 |  | 
 | #include "Python.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; | 
 |  | 
 | #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; | 
 |     if (PyOS_InputHook != NULL) | 
 |         (void)(PyOS_InputHook)(); | 
 |     errno = 0; | 
 |     p = fgets(buf, len, fp); | 
 |     if (p != NULL) | 
 |         return 0; /* No error */ | 
 | #ifdef MS_WINDOWS | 
 |     /* In the case of a Ctrl+C or some other external event | 
 |        interrupting the operation: | 
 |        Win2k/NT: ERROR_OPERATION_ABORTED is the most recent Win32 | 
 |        error code (and feof() returns TRUE). | 
 |        Win9x: Ctrl+C seems to have no effect on fgets() returning | 
 |        early - the signal handler is called, but the fgets() | 
 |        only returns "normally" (ie, when Enter hit or feof()) | 
 |     */ | 
 |     if (GetLastError()==ERROR_OPERATION_ABORTED) { | 
 |         /* Signals come asynchronously, so we sleep a brief | 
 |            moment before checking if the handler has been | 
 |            triggered (we cant just return 1 before the | 
 |            signal handler has been called, as the later | 
 |            signal may be treated as a separate interrupt). | 
 |         */ | 
 |         Sleep(1); | 
 |         if (PyOS_InterruptOccurred()) { | 
 |             return 1; /* Interrupt */ | 
 |         } | 
 |         /* Either the sleep wasn't long enough (need a | 
 |            short loop retrying?) or not interrupted at all | 
 |            (in which case we should revisit the whole thing!) | 
 |            Logging some warning would be nice.  assert is not | 
 |            viable as under the debugger, the various dialogs | 
 |            mean the condition is not true. | 
 |         */ | 
 |     } | 
 | #endif /* MS_WINDOWS */ | 
 |     if (feof(fp)) { | 
 |         return -1; /* EOF */ | 
 |     } | 
 | #ifdef 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; | 
 |         } | 
 |     } | 
 | #endif | 
 |     if (PyOS_InterruptOccurred()) { | 
 |         return 1; /* Interrupt */ | 
 |     } | 
 |     return -2; /* Error */ | 
 | } | 
 |  | 
 |  | 
 | /* Readline implementation using fgets() */ | 
 |  | 
 | char * | 
 | PyOS_StdioReadline(FILE *sys_stdin, FILE *sys_stdout, char *prompt) | 
 | { | 
 |     size_t n; | 
 |     char *p; | 
 |     n = 100; | 
 |     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_FREE(p); | 
 |         return NULL; | 
 |     case -1: /* EOF */ | 
 |     case -2: /* Error */ | 
 |     default: /* Shouldn't happen */ | 
 |         *p = '\0'; | 
 |         break; | 
 |     } | 
 |     n = strlen(p); | 
 |     while (n > 0 && p[n-1] != '\n') { | 
 |         size_t incr = n+2; | 
 |         p = (char *)PyMem_REALLOC(p, n + incr); | 
 |         if (p == NULL) | 
 |             return NULL; | 
 |         if (incr > INT_MAX) { | 
 |             PyErr_SetString(PyExc_OverflowError, "input line too long"); | 
 |         } | 
 |         if (my_fgets(p+n, (int)incr, sys_stdin) != 0) | 
 |             break; | 
 |         n += strlen(p+n); | 
 |     } | 
 |     return (char *)PyMem_REALLOC(p, n+1); | 
 | } | 
 |  | 
 |  | 
 | /* By initializing this function pointer, systems embedding Python can | 
 |    override the readline function. | 
 |  | 
 |    Note: Python expects in return a buffer allocated with PyMem_Malloc. */ | 
 |  | 
 | char *(*PyOS_ReadlineFunctionPointer)(FILE *, FILE *, char *); | 
 |  | 
 |  | 
 | /* Interface used by tokenizer.c and bltinmodule.c */ | 
 |  | 
 | char * | 
 | PyOS_Readline(FILE *sys_stdin, FILE *sys_stdout, char *prompt) | 
 | { | 
 |     char *rv; | 
 |  | 
 |     if (_PyOS_ReadlineTState == PyThreadState_GET()) { | 
 |         PyErr_SetString(PyExc_RuntimeError, | 
 |                         "can't re-enter readline"); | 
 |         return NULL; | 
 |     } | 
 |  | 
 |  | 
 |     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(); | 
 |     } | 
 | #endif | 
 |  | 
 |     _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 | 
 |      * a tty.  This can happen, for example if python is run like | 
 |      * this: python -i < test1.py | 
 |      */ | 
 |     if (!isatty (fileno (sys_stdin)) || !isatty (fileno (sys_stdout))) | 
 |         rv = PyOS_StdioReadline (sys_stdin, sys_stdout, prompt); | 
 |     else | 
 |         rv = (*PyOS_ReadlineFunctionPointer)(sys_stdin, sys_stdout, | 
 |                                              prompt); | 
 |     Py_END_ALLOW_THREADS | 
 |  | 
 | #ifdef WITH_THREAD | 
 |     PyThread_release_lock(_PyOS_ReadlineLock); | 
 | #endif | 
 |  | 
 |     _PyOS_ReadlineTState = NULL; | 
 |  | 
 |     return rv; | 
 | } |