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
my_fgets(char * buf,int len,FILE * fp)40 my_fgets(char *buf, int len, FILE *fp)
41 {
42     char *p;
43     while (1) {
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             clearerr(fp);
81             return -1; /* EOF */
82         }
83 #ifdef EINTR
84         if (errno == EINTR) {
85             int s;
86 #ifdef WITH_THREAD
87             PyEval_RestoreThread(_PyOS_ReadlineTState);
88 #endif
89             s = PyErr_CheckSignals();
90 #ifdef WITH_THREAD
91             PyEval_SaveThread();
92 #endif
93             if (s < 0)
94                     return 1;
95 	    /* try again */
96             continue;
97         }
98 #endif
99         if (PyOS_InterruptOccurred()) {
100             return 1; /* Interrupt */
101         }
102         return -2; /* Error */
103     }
104     /* NOTREACHED */
105 }
106 
107 
108 /* Readline implementation using fgets() */
109 
110 char *
PyOS_StdioReadline(FILE * sys_stdin,FILE * sys_stdout,char * prompt)111 PyOS_StdioReadline(FILE *sys_stdin, FILE *sys_stdout, char *prompt)
112 {
113     size_t n;
114     char *p;
115     n = 100;
116     if ((p = (char *)PyMem_MALLOC(n)) == NULL)
117         return NULL;
118     fflush(sys_stdout);
119 #ifndef RISCOS
120     if (prompt)
121         fprintf(stderr, "%s", prompt);
122 #else
123     if (prompt) {
124         if(Py_RISCOSWimpFlag)
125             fprintf(stderr, "\x0cr%s\x0c", prompt);
126         else
127             fprintf(stderr, "%s", prompt);
128     }
129 #endif
130     fflush(stderr);
131     switch (my_fgets(p, (int)n, sys_stdin)) {
132     case 0: /* Normal case */
133         break;
134     case 1: /* Interrupt */
135         PyMem_FREE(p);
136         return NULL;
137     case -1: /* EOF */
138     case -2: /* Error */
139     default: /* Shouldn't happen */
140         *p = '\0';
141         break;
142     }
143     n = strlen(p);
144     while (n > 0 && p[n-1] != '\n') {
145         size_t incr = n+2;
146         p = (char *)PyMem_REALLOC(p, n + incr);
147         if (p == NULL)
148             return NULL;
149         if (incr > INT_MAX) {
150             PyErr_SetString(PyExc_OverflowError, "input line too long");
151         }
152         if (my_fgets(p+n, (int)incr, sys_stdin) != 0)
153             break;
154         n += strlen(p+n);
155     }
156     return (char *)PyMem_REALLOC(p, n+1);
157 }
158 
159 
160 /* By initializing this function pointer, systems embedding Python can
161    override the readline function.
162 
163    Note: Python expects in return a buffer allocated with PyMem_Malloc. */
164 
165 char *(*PyOS_ReadlineFunctionPointer)(FILE *, FILE *, char *);
166 
167 
168 /* Interface used by tokenizer.c and bltinmodule.c */
169 
170 char *
PyOS_Readline(FILE * sys_stdin,FILE * sys_stdout,char * prompt)171 PyOS_Readline(FILE *sys_stdin, FILE *sys_stdout, char *prompt)
172 {
173     char *rv;
174 
175     if (_PyOS_ReadlineTState == PyThreadState_GET()) {
176         PyErr_SetString(PyExc_RuntimeError,
177                         "can't re-enter readline");
178         return NULL;
179     }
180 
181 
182     if (PyOS_ReadlineFunctionPointer == NULL) {
183 #ifdef __VMS
184         PyOS_ReadlineFunctionPointer = vms__StdioReadline;
185 #else
186         PyOS_ReadlineFunctionPointer = PyOS_StdioReadline;
187 #endif
188     }
189 
190 #ifdef WITH_THREAD
191     if (_PyOS_ReadlineLock == NULL) {
192         _PyOS_ReadlineLock = PyThread_allocate_lock();
193     }
194 #endif
195 
196     _PyOS_ReadlineTState = PyThreadState_GET();
197     Py_BEGIN_ALLOW_THREADS
198 #ifdef WITH_THREAD
199     PyThread_acquire_lock(_PyOS_ReadlineLock, 1);
200 #endif
201 
202     /* This is needed to handle the unlikely case that the
203      * interpreter is in interactive mode *and* stdin/out are not
204      * a tty.  This can happen, for example if python is run like
205      * this: python -i < test1.py
206      */
207     if (!isatty (fileno (sys_stdin)) || !isatty (fileno (sys_stdout)))
208         rv = PyOS_StdioReadline (sys_stdin, sys_stdout, prompt);
209     else
210         rv = (*PyOS_ReadlineFunctionPointer)(sys_stdin, sys_stdout,
211                                              prompt);
212     Py_END_ALLOW_THREADS
213 
214 #ifdef WITH_THREAD
215     PyThread_release_lock(_PyOS_ReadlineLock);
216 #endif
217 
218     _PyOS_ReadlineTState = NULL;
219 
220     return rv;
221 }
222