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 #ifdef MS_WINDOWS
44 int i;
45 #endif
46
47 while (1) {
48 if (PyOS_InputHook != NULL)
49 (void)(PyOS_InputHook)();
50 errno = 0;
51 clearerr(fp);
52 p = fgets(buf, len, fp);
53 if (p != NULL)
54 return 0; /* No error */
55 #ifdef MS_WINDOWS
56 /* Ctrl-C anywhere on the line or Ctrl-Z if the only character
57 on a line will set ERROR_OPERATION_ABORTED. Under normal
58 circumstances Ctrl-C will also have caused the SIGINT handler
59 to fire. This signal fires in another thread and is not
60 guaranteed to have occurred before this point in the code.
61
62 Therefore: check in a small loop to see if the trigger has
63 fired, in which case assume this is a Ctrl-C event. If it
64 hasn't fired within 10ms assume that this is a Ctrl-Z on its
65 own or that the signal isn't going to fire for some other
66 reason and drop through to check for EOF.
67 */
68 if (GetLastError()==ERROR_OPERATION_ABORTED) {
69 for (i = 0; i < 10; i++) {
70 if (PyOS_InterruptOccurred())
71 return 1;
72 Sleep(1);
73 }
74 }
75 #endif /* MS_WINDOWS */
76 if (feof(fp)) {
77 clearerr(fp);
78 return -1; /* EOF */
79 }
80 #ifdef EINTR
81 if (errno == EINTR) {
82 int s;
83 #ifdef WITH_THREAD
84 PyEval_RestoreThread(_PyOS_ReadlineTState);
85 #endif
86 s = PyErr_CheckSignals();
87 #ifdef WITH_THREAD
88 PyEval_SaveThread();
89 #endif
90 if (s < 0)
91 return 1;
92 /* try again */
93 continue;
94 }
95 #endif
96 if (PyOS_InterruptOccurred()) {
97 return 1; /* Interrupt */
98 }
99 return -2; /* Error */
100 }
101 /* NOTREACHED */
102 }
103
104
105 /* Readline implementation using fgets() */
106
107 char *
PyOS_StdioReadline(FILE * sys_stdin,FILE * sys_stdout,char * prompt)108 PyOS_StdioReadline(FILE *sys_stdin, FILE *sys_stdout, char *prompt)
109 {
110 size_t n;
111 char *p;
112 n = 100;
113 if ((p = (char *)PyMem_MALLOC(n)) == NULL)
114 return NULL;
115 fflush(sys_stdout);
116 #ifndef RISCOS
117 if (prompt)
118 fprintf(stderr, "%s", prompt);
119 #else
120 if (prompt) {
121 if(Py_RISCOSWimpFlag)
122 fprintf(stderr, "\x0cr%s\x0c", prompt);
123 else
124 fprintf(stderr, "%s", prompt);
125 }
126 #endif
127 fflush(stderr);
128 switch (my_fgets(p, (int)n, sys_stdin)) {
129 case 0: /* Normal case */
130 break;
131 case 1: /* Interrupt */
132 PyMem_FREE(p);
133 return NULL;
134 case -1: /* EOF */
135 case -2: /* Error */
136 default: /* Shouldn't happen */
137 *p = '\0';
138 break;
139 }
140 n = strlen(p);
141 while (n > 0 && p[n-1] != '\n') {
142 size_t incr = n+2;
143 p = (char *)PyMem_REALLOC(p, n + incr);
144 if (p == NULL)
145 return NULL;
146 if (incr > INT_MAX) {
147 PyErr_SetString(PyExc_OverflowError, "input line too long");
148 }
149 if (my_fgets(p+n, (int)incr, sys_stdin) != 0)
150 break;
151 n += strlen(p+n);
152 }
153 return (char *)PyMem_REALLOC(p, n+1);
154 }
155
156
157 /* By initializing this function pointer, systems embedding Python can
158 override the readline function.
159
160 Note: Python expects in return a buffer allocated with PyMem_Malloc. */
161
162 char *(*PyOS_ReadlineFunctionPointer)(FILE *, FILE *, char *);
163
164
165 /* Interface used by tokenizer.c and bltinmodule.c */
166
167 char *
PyOS_Readline(FILE * sys_stdin,FILE * sys_stdout,char * prompt)168 PyOS_Readline(FILE *sys_stdin, FILE *sys_stdout, char *prompt)
169 {
170 char *rv;
171
172 if (_PyOS_ReadlineTState == PyThreadState_GET()) {
173 PyErr_SetString(PyExc_RuntimeError,
174 "can't re-enter readline");
175 return NULL;
176 }
177
178
179 if (PyOS_ReadlineFunctionPointer == NULL) {
180 #ifdef __VMS
181 PyOS_ReadlineFunctionPointer = vms__StdioReadline;
182 #else
183 PyOS_ReadlineFunctionPointer = PyOS_StdioReadline;
184 #endif
185 }
186
187 #ifdef WITH_THREAD
188 if (_PyOS_ReadlineLock == NULL) {
189 _PyOS_ReadlineLock = PyThread_allocate_lock();
190 }
191 #endif
192
193 _PyOS_ReadlineTState = PyThreadState_GET();
194 Py_BEGIN_ALLOW_THREADS
195 #ifdef WITH_THREAD
196 PyThread_acquire_lock(_PyOS_ReadlineLock, 1);
197 #endif
198
199 /* This is needed to handle the unlikely case that the
200 * interpreter is in interactive mode *and* stdin/out are not
201 * a tty. This can happen, for example if python is run like
202 * this: python -i < test1.py
203 */
204 if (!isatty (fileno (sys_stdin)) || !isatty (fileno (sys_stdout)))
205 rv = PyOS_StdioReadline (sys_stdin, sys_stdout, prompt);
206 else
207 rv = (*PyOS_ReadlineFunctionPointer)(sys_stdin, sys_stdout,
208 prompt);
209 Py_END_ALLOW_THREADS
210
211 #ifdef WITH_THREAD
212 PyThread_release_lock(_PyOS_ReadlineLock);
213 #endif
214
215 _PyOS_ReadlineTState = NULL;
216
217 return rv;
218 }
219