• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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