Home | History | Annotate | Download | only in Parser
      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     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 *
    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 *
    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