myreadline.c 5.77 KB
Newer Older
Guido van Rossum's avatar
Guido van Rossum committed
1

2 3 4 5
/* 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.
Guido van Rossum's avatar
Guido van Rossum committed
6 7 8 9 10 11
   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
*/

12
#include "Python.h"
13 14 15 16
#ifdef MS_WINDOWS
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#endif /* MS_WINDOWS */
Guido van Rossum's avatar
Guido van Rossum committed
17

18 19 20 21
#ifdef __VMS
extern char* vms__StdioReadline(FILE *sys_stdin, FILE *sys_stdout, char *prompt);
#endif

Michael W. Hudson's avatar
Michael W. Hudson committed
22 23 24

PyThreadState* _PyOS_ReadlineTState;

25
#ifdef WITH_THREAD
Michael W. Hudson's avatar
Michael W. Hudson committed
26 27 28 29
#include "pythread.h"
static PyThread_type_lock _PyOS_ReadlineLock = NULL;
#endif

Thomas Wouters's avatar
Thomas Wouters committed
30
int (*PyOS_InputHook)(void) = NULL;
31 32 33 34 35

/* This function restarts a fgets() after an EINTR error occurred
   except if PyOS_InterruptOccurred() returns true. */

static int
Thomas Wouters's avatar
Thomas Wouters committed
36
my_fgets(char *buf, int len, FILE *fp)
37
{
38 39 40
#ifdef MS_WINDOWS
    HANDLE hInterruptEvent;
#endif
41
    char *p;
42
    int err;
43
    while (1) {
44 45 46
        if (PyOS_InputHook != NULL)
            (void)(PyOS_InputHook)();
        errno = 0;
47
        clearerr(fp);
48 49 50 51
        if (_PyVerify_fd(fileno(fp)))
            p = fgets(buf, len, fp);
        else
            p = NULL;
52 53
        if (p != NULL)
            return 0; /* No error */
54
        err = errno;
55
#ifdef MS_WINDOWS
56 57 58 59 60 61 62 63 64 65 66 67
        /* 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 which will have set the event object returned by
           _PyOS_SigintEvent. This signal fires in another thread and
           is not guaranteed to have occurred before this point in the
           code.

           Therefore: check whether the event is set with a small timeout.
           If it is, assume this is a Ctrl-C and reset the event. If it
           isn't set assume that this is a Ctrl-Z on its own and drop
           through to check for EOF.
68
        */
69
        if (GetLastError()==ERROR_OPERATION_ABORTED) {
70 71 72 73
            hInterruptEvent = _PyOS_SigintEvent();
            switch (WaitForSingleObject(hInterruptEvent, 10)) {
            case WAIT_OBJECT_0:
                ResetEvent(hInterruptEvent);
74
                return 1; /* Interrupt */
75 76
            case WAIT_FAILED:
                return -2; /* Error */
77
            }
78
        }
79
#endif /* MS_WINDOWS */
80
        if (feof(fp)) {
81
            clearerr(fp);
82 83
            return -1; /* EOF */
        }
84
#ifdef EINTR
85
        if (err == EINTR) {
86
            int s;
87
#ifdef WITH_THREAD
88
            PyEval_RestoreThread(_PyOS_ReadlineTState);
89
#endif
90
            s = PyErr_CheckSignals();
91
#ifdef WITH_THREAD
92
            PyEval_SaveThread();
93
#endif
94 95
            if (s < 0)
                    return 1;
96
        /* try again */
97
            continue;
98
        }
99
#endif
100 101 102 103
        if (PyOS_InterruptOccurred()) {
            return 1; /* Interrupt */
        }
        return -2; /* Error */
104
    }
105
    /* NOTREACHED */
106 107 108 109 110 111
}


/* Readline implementation using fgets() */

char *
112
PyOS_StdioReadline(FILE *sys_stdin, FILE *sys_stdout, char *prompt)
113
{
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
    size_t n;
    char *p;
    n = 100;
    if ((p = (char *)PyMem_MALLOC(n)) == NULL)
        return NULL;
    fflush(sys_stdout);
    if (prompt)
        fprintf(stderr, "%s", prompt);
    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);
149 150 151 152
}


/* By initializing this function pointer, systems embedding Python can
153 154 155
   override the readline function.

   Note: Python expects in return a buffer allocated with PyMem_Malloc. */
156

157
char *(*PyOS_ReadlineFunctionPointer)(FILE *, FILE *, char *);
158 159 160 161 162


/* Interface used by tokenizer.c and bltinmodule.c */

char *
163
PyOS_Readline(FILE *sys_stdin, FILE *sys_stdout, char *prompt)
164
{
165
    char *rv;
166

167 168 169 170 171
    if (_PyOS_ReadlineTState == PyThreadState_GET()) {
        PyErr_SetString(PyExc_RuntimeError,
                        "can't re-enter readline");
        return NULL;
    }
Michael W. Hudson's avatar
Michael W. Hudson committed
172

173 174

    if (PyOS_ReadlineFunctionPointer == NULL) {
175
#ifdef __VMS
176
        PyOS_ReadlineFunctionPointer = vms__StdioReadline;
177
#else
178
        PyOS_ReadlineFunctionPointer = PyOS_StdioReadline;
179
#endif
180 181
    }

182
#ifdef WITH_THREAD
183 184 185
    if (_PyOS_ReadlineLock == NULL) {
        _PyOS_ReadlineLock = PyThread_allocate_lock();
    }
Michael W. Hudson's avatar
Michael W. Hudson committed
186
#endif
187

188 189
    _PyOS_ReadlineTState = PyThreadState_GET();
    Py_BEGIN_ALLOW_THREADS
190
#ifdef WITH_THREAD
191
    PyThread_acquire_lock(_PyOS_ReadlineLock, 1);
Michael W. Hudson's avatar
Michael W. Hudson committed
192
#endif
193

194 195 196 197 198 199 200 201 202 203 204
    /* 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
Michael W. Hudson's avatar
Michael W. Hudson committed
205

206
#ifdef WITH_THREAD
207
    PyThread_release_lock(_PyOS_ReadlineLock);
Michael W. Hudson's avatar
Michael W. Hudson committed
208 209
#endif

210
    _PyOS_ReadlineTState = NULL;
Michael W. Hudson's avatar
Michael W. Hudson committed
211

212
    return rv;
Guido van Rossum's avatar
Guido van Rossum committed
213
}