/* 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; #ifdef MS_WINDOWS int i; #endif while (1) { if (PyOS_InputHook != NULL) (void)(PyOS_InputHook)(); errno = 0; clearerr(fp); p = fgets(buf, len, fp); if (p != NULL) return 0; /* No error */ #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. 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) { for (i = 0; i < 10; i++) { if (PyOS_InterruptOccurred()) return 1; Sleep(1); } } #endif /* MS_WINDOWS */ if (feof(fp)) { clearerr(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; /* try again */ continue; } #endif if (PyOS_InterruptOccurred()) { return 1; /* Interrupt */ } return -2; /* Error */ } /* NOTREACHED */ } /* 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; }