| 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 | #ifdef __VMS
|
|---|
| 19 | extern char* vms__StdioReadline(FILE *sys_stdin, FILE *sys_stdout, char *prompt);
|
|---|
| 20 | #endif
|
|---|
| 21 |
|
|---|
| 22 |
|
|---|
| 23 | PyThreadState* _PyOS_ReadlineTState;
|
|---|
| 24 |
|
|---|
| 25 | #ifdef WITH_THREAD
|
|---|
| 26 | #include "pythread.h"
|
|---|
| 27 | static PyThread_type_lock _PyOS_ReadlineLock = NULL;
|
|---|
| 28 | #endif
|
|---|
| 29 |
|
|---|
| 30 | int (*PyOS_InputHook)(void) = NULL;
|
|---|
| 31 |
|
|---|
| 32 | #ifdef RISCOS
|
|---|
| 33 | int Py_RISCOSWimpFlag;
|
|---|
| 34 | #endif
|
|---|
| 35 |
|
|---|
| 36 | /* This function restarts a fgets() after an EINTR error occurred
|
|---|
| 37 | except if PyOS_InterruptOccurred() returns true. */
|
|---|
| 38 |
|
|---|
| 39 | static int
|
|---|
| 40 | my_fgets(char *buf, int len, FILE *fp)
|
|---|
| 41 | {
|
|---|
| 42 | char *p;
|
|---|
| 43 | for (;;) {
|
|---|
| 44 | if (PyOS_InputHook != NULL)
|
|---|
| 45 | (void)(PyOS_InputHook)();
|
|---|
| 46 | errno = 0;
|
|---|
| 47 | p = fgets(buf, len, fp);
|
|---|
| 48 | if (p != NULL)
|
|---|
| 49 | return 0; /* No error */
|
|---|
| 50 | #ifdef MS_WINDOWS
|
|---|
| 51 | /* In the case of a Ctrl+C or some other external event
|
|---|
| 52 | interrupting the operation:
|
|---|
| 53 | Win2k/NT: ERROR_OPERATION_ABORTED is the most recent Win32
|
|---|
| 54 | error code (and feof() returns TRUE).
|
|---|
| 55 | Win9x: Ctrl+C seems to have no effect on fgets() returning
|
|---|
| 56 | early - the signal handler is called, but the fgets()
|
|---|
| 57 | only returns "normally" (ie, when Enter hit or feof())
|
|---|
| 58 | */
|
|---|
| 59 | if (GetLastError()==ERROR_OPERATION_ABORTED) {
|
|---|
| 60 | /* Signals come asynchronously, so we sleep a brief
|
|---|
| 61 | moment before checking if the handler has been
|
|---|
| 62 | triggered (we cant just return 1 before the
|
|---|
| 63 | signal handler has been called, as the later
|
|---|
| 64 | signal may be treated as a separate interrupt).
|
|---|
| 65 | */
|
|---|
| 66 | Sleep(1);
|
|---|
| 67 | if (PyOS_InterruptOccurred()) {
|
|---|
| 68 | return 1; /* Interrupt */
|
|---|
| 69 | }
|
|---|
| 70 | /* Either the sleep wasn't long enough (need a
|
|---|
| 71 | short loop retrying?) or not interrupted at all
|
|---|
| 72 | (in which case we should revisit the whole thing!)
|
|---|
| 73 | Logging some warning would be nice. assert is not
|
|---|
| 74 | viable as under the debugger, the various dialogs
|
|---|
| 75 | mean the condition is not true.
|
|---|
| 76 | */
|
|---|
| 77 | }
|
|---|
| 78 | #endif /* MS_WINDOWS */
|
|---|
| 79 | if (feof(fp)) {
|
|---|
| 80 | return -1; /* EOF */
|
|---|
| 81 | }
|
|---|
| 82 | #ifdef EINTR
|
|---|
| 83 | if (errno == EINTR) {
|
|---|
| 84 | int s;
|
|---|
| 85 | #ifdef WITH_THREAD
|
|---|
| 86 | PyEval_RestoreThread(_PyOS_ReadlineTState);
|
|---|
| 87 | #endif
|
|---|
| 88 | s = PyErr_CheckSignals();
|
|---|
| 89 | #ifdef WITH_THREAD
|
|---|
| 90 | PyEval_SaveThread();
|
|---|
| 91 | #endif
|
|---|
| 92 | if (s < 0) {
|
|---|
| 93 | return 1;
|
|---|
| 94 | }
|
|---|
| 95 | }
|
|---|
| 96 | #endif
|
|---|
| 97 | if (PyOS_InterruptOccurred()) {
|
|---|
| 98 | return 1; /* Interrupt */
|
|---|
| 99 | }
|
|---|
| 100 | return -2; /* Error */
|
|---|
| 101 | }
|
|---|
| 102 | /* NOTREACHED */
|
|---|
| 103 | }
|
|---|
| 104 |
|
|---|
| 105 |
|
|---|
| 106 | /* Readline implementation using fgets() */
|
|---|
| 107 |
|
|---|
| 108 | char *
|
|---|
| 109 | PyOS_StdioReadline(FILE *sys_stdin, FILE *sys_stdout, char *prompt)
|
|---|
| 110 | {
|
|---|
| 111 | size_t n;
|
|---|
| 112 | char *p;
|
|---|
| 113 | n = 100;
|
|---|
| 114 | if ((p = (char *)PyMem_MALLOC(n)) == NULL)
|
|---|
| 115 | return NULL;
|
|---|
| 116 | fflush(sys_stdout);
|
|---|
| 117 | #ifndef RISCOS
|
|---|
| 118 | if (prompt)
|
|---|
| 119 | fprintf(stderr, "%s", prompt);
|
|---|
| 120 | #else
|
|---|
| 121 | if (prompt) {
|
|---|
| 122 | if(Py_RISCOSWimpFlag)
|
|---|
| 123 | fprintf(stderr, "\x0cr%s\x0c", prompt);
|
|---|
| 124 | else
|
|---|
| 125 | fprintf(stderr, "%s", prompt);
|
|---|
| 126 | }
|
|---|
| 127 | #endif
|
|---|
| 128 | fflush(stderr);
|
|---|
| 129 | switch (my_fgets(p, (int)n, sys_stdin)) {
|
|---|
| 130 | case 0: /* Normal case */
|
|---|
| 131 | break;
|
|---|
| 132 | case 1: /* Interrupt */
|
|---|
| 133 | PyMem_FREE(p);
|
|---|
| 134 | return NULL;
|
|---|
| 135 | case -1: /* EOF */
|
|---|
| 136 | case -2: /* Error */
|
|---|
| 137 | default: /* Shouldn't happen */
|
|---|
| 138 | *p = '\0';
|
|---|
| 139 | break;
|
|---|
| 140 | }
|
|---|
| 141 | n = strlen(p);
|
|---|
| 142 | while (n > 0 && p[n-1] != '\n') {
|
|---|
| 143 | size_t incr = n+2;
|
|---|
| 144 | p = (char *)PyMem_REALLOC(p, n + incr);
|
|---|
| 145 | if (p == NULL)
|
|---|
| 146 | return NULL;
|
|---|
| 147 | if (incr > INT_MAX) {
|
|---|
| 148 | PyErr_SetString(PyExc_OverflowError, "input line too long");
|
|---|
| 149 | }
|
|---|
| 150 | if (my_fgets(p+n, (int)incr, sys_stdin) != 0)
|
|---|
| 151 | break;
|
|---|
| 152 | n += strlen(p+n);
|
|---|
| 153 | }
|
|---|
| 154 | return (char *)PyMem_REALLOC(p, n+1);
|
|---|
| 155 | }
|
|---|
| 156 |
|
|---|
| 157 |
|
|---|
| 158 | /* By initializing this function pointer, systems embedding Python can
|
|---|
| 159 | override the readline function.
|
|---|
| 160 |
|
|---|
| 161 | Note: Python expects in return a buffer allocated with PyMem_Malloc. */
|
|---|
| 162 |
|
|---|
| 163 | char *(*PyOS_ReadlineFunctionPointer)(FILE *, FILE *, char *);
|
|---|
| 164 |
|
|---|
| 165 |
|
|---|
| 166 | /* Interface used by tokenizer.c and bltinmodule.c */
|
|---|
| 167 |
|
|---|
| 168 | char *
|
|---|
| 169 | PyOS_Readline(FILE *sys_stdin, FILE *sys_stdout, char *prompt)
|
|---|
| 170 | {
|
|---|
| 171 | char *rv;
|
|---|
| 172 |
|
|---|
| 173 | if (_PyOS_ReadlineTState == PyThreadState_GET()) {
|
|---|
| 174 | PyErr_SetString(PyExc_RuntimeError,
|
|---|
| 175 | "can't re-enter readline");
|
|---|
| 176 | return NULL;
|
|---|
| 177 | }
|
|---|
| 178 |
|
|---|
| 179 |
|
|---|
| 180 | if (PyOS_ReadlineFunctionPointer == NULL) {
|
|---|
| 181 | #ifdef __VMS
|
|---|
| 182 | PyOS_ReadlineFunctionPointer = vms__StdioReadline;
|
|---|
| 183 | #else
|
|---|
| 184 | PyOS_ReadlineFunctionPointer = PyOS_StdioReadline;
|
|---|
| 185 | #endif
|
|---|
| 186 | }
|
|---|
| 187 |
|
|---|
| 188 | #ifdef WITH_THREAD
|
|---|
| 189 | if (_PyOS_ReadlineLock == NULL) {
|
|---|
| 190 | _PyOS_ReadlineLock = PyThread_allocate_lock();
|
|---|
| 191 | }
|
|---|
| 192 | #endif
|
|---|
| 193 |
|
|---|
| 194 | _PyOS_ReadlineTState = PyThreadState_GET();
|
|---|
| 195 | Py_BEGIN_ALLOW_THREADS
|
|---|
| 196 | #ifdef WITH_THREAD
|
|---|
| 197 | PyThread_acquire_lock(_PyOS_ReadlineLock, 1);
|
|---|
| 198 | #endif
|
|---|
| 199 |
|
|---|
| 200 | /* This is needed to handle the unlikely case that the
|
|---|
| 201 | * interpreter is in interactive mode *and* stdin/out are not
|
|---|
| 202 | * a tty. This can happen, for example if python is run like
|
|---|
| 203 | * this: python -i < test1.py
|
|---|
| 204 | */
|
|---|
| 205 | if (!isatty (fileno (sys_stdin)) || !isatty (fileno (sys_stdout)))
|
|---|
| 206 | rv = PyOS_StdioReadline (sys_stdin, sys_stdout, prompt);
|
|---|
| 207 | else
|
|---|
| 208 | rv = (*PyOS_ReadlineFunctionPointer)(sys_stdin, sys_stdout,
|
|---|
| 209 | prompt);
|
|---|
| 210 | Py_END_ALLOW_THREADS
|
|---|
| 211 |
|
|---|
| 212 | #ifdef WITH_THREAD
|
|---|
| 213 | PyThread_release_lock(_PyOS_ReadlineLock);
|
|---|
| 214 | #endif
|
|---|
| 215 |
|
|---|
| 216 | _PyOS_ReadlineTState = NULL;
|
|---|
| 217 |
|
|---|
| 218 | return rv;
|
|---|
| 219 | }
|
|---|