(root)/
Python-3.12.0/
Parser/
myreadline.c
       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  #include "pycore_fileutils.h"     // _Py_BEGIN_SUPPRESS_IPH
      14  #include "pycore_pystate.h"   // _PyThreadState_GET()
      15  #ifdef MS_WINDOWS
      16  #  ifndef WIN32_LEAN_AND_MEAN
      17  #  define WIN32_LEAN_AND_MEAN
      18  #  endif
      19  #  include "windows.h"
      20  #endif /* MS_WINDOWS */
      21  
      22  
      23  PyThreadState* _PyOS_ReadlineTState = NULL;
      24  
      25  static PyThread_type_lock _PyOS_ReadlineLock = NULL;
      26  
      27  int (*PyOS_InputHook)(void) = NULL;
      28  
      29  /* This function restarts a fgets() after an EINTR error occurred
      30     except if _PyOS_InterruptOccurred() returns true. */
      31  
      32  static int
      33  my_fgets(PyThreadState* tstate, char *buf, int len, FILE *fp)
      34  {
      35  #ifdef MS_WINDOWS
      36      HANDLE handle;
      37      _Py_BEGIN_SUPPRESS_IPH
      38      handle = (HANDLE)_get_osfhandle(fileno(fp));
      39      _Py_END_SUPPRESS_IPH
      40  
      41      /* bpo-40826: fgets(fp) does crash if fileno(fp) is closed */
      42      if (handle == INVALID_HANDLE_VALUE) {
      43          return -1; /* EOF */
      44      }
      45  #endif
      46  
      47      while (1) {
      48          if (PyOS_InputHook != NULL &&
      49              // GH-104668: See PyOS_ReadlineFunctionPointer's comment below...
      50              _Py_IsMainInterpreter(tstate->interp))
      51          {
      52              (void)(PyOS_InputHook)();
      53          }
      54  
      55          errno = 0;
      56          clearerr(fp);
      57          char *p = fgets(buf, len, fp);
      58          if (p != NULL) {
      59              return 0; /* No error */
      60          }
      61          int err = errno;
      62  
      63  #ifdef MS_WINDOWS
      64          /* Ctrl-C anywhere on the line or Ctrl-Z if the only character
      65             on a line will set ERROR_OPERATION_ABORTED. Under normal
      66             circumstances Ctrl-C will also have caused the SIGINT handler
      67             to fire which will have set the event object returned by
      68             _PyOS_SigintEvent. This signal fires in another thread and
      69             is not guaranteed to have occurred before this point in the
      70             code.
      71  
      72             Therefore: check whether the event is set with a small timeout.
      73             If it is, assume this is a Ctrl-C and reset the event. If it
      74             isn't set assume that this is a Ctrl-Z on its own and drop
      75             through to check for EOF.
      76          */
      77          if (GetLastError()==ERROR_OPERATION_ABORTED) {
      78              HANDLE hInterruptEvent = _PyOS_SigintEvent();
      79              switch (WaitForSingleObjectEx(hInterruptEvent, 10, FALSE)) {
      80              case WAIT_OBJECT_0:
      81                  ResetEvent(hInterruptEvent);
      82                  return 1; /* Interrupt */
      83              case WAIT_FAILED:
      84                  return -2; /* Error */
      85              }
      86          }
      87  #endif /* MS_WINDOWS */
      88  
      89          if (feof(fp)) {
      90              clearerr(fp);
      91              return -1; /* EOF */
      92          }
      93  
      94  #ifdef EINTR
      95          if (err == EINTR) {
      96              PyEval_RestoreThread(tstate);
      97              int s = PyErr_CheckSignals();
      98              PyEval_SaveThread();
      99  
     100              if (s < 0) {
     101                  return 1;
     102              }
     103              /* try again */
     104              continue;
     105          }
     106  #endif
     107  
     108          if (_PyOS_InterruptOccurred(tstate)) {
     109              return 1; /* Interrupt */
     110          }
     111          return -2; /* Error */
     112      }
     113      /* NOTREACHED */
     114  }
     115  
     116  #ifdef HAVE_WINDOWS_CONSOLE_IO
     117  /* Readline implementation using ReadConsoleW */
     118  
     119  extern char _get_console_type(HANDLE handle);
     120  
     121  char *
     122  _PyOS_WindowsConsoleReadline(PyThreadState *tstate, HANDLE hStdIn)
     123  {
     124      static wchar_t wbuf_local[1024 * 16];
     125      const DWORD chunk_size = 1024;
     126  
     127      DWORD n_read, total_read, wbuflen, u8len;
     128      wchar_t *wbuf;
     129      char *buf = NULL;
     130      int err = 0;
     131  
     132      n_read = (DWORD)-1;
     133      total_read = 0;
     134      wbuf = wbuf_local;
     135      wbuflen = sizeof(wbuf_local) / sizeof(wbuf_local[0]) - 1;
     136      while (1) {
     137          if (PyOS_InputHook != NULL &&
     138              // GH-104668: See PyOS_ReadlineFunctionPointer's comment below...
     139              _Py_IsMainInterpreter(tstate->interp))
     140          {
     141              (void)(PyOS_InputHook)();
     142          }
     143          if (!ReadConsoleW(hStdIn, &wbuf[total_read], wbuflen - total_read, &n_read, NULL)) {
     144              err = GetLastError();
     145              goto exit;
     146          }
     147          if (n_read == (DWORD)-1 && (err = GetLastError()) == ERROR_OPERATION_ABORTED) {
     148              break;
     149          }
     150          if (n_read == 0) {
     151              int s;
     152              err = GetLastError();
     153              if (err != ERROR_OPERATION_ABORTED)
     154                  goto exit;
     155              err = 0;
     156              HANDLE hInterruptEvent = _PyOS_SigintEvent();
     157              if (WaitForSingleObjectEx(hInterruptEvent, 100, FALSE)
     158                      == WAIT_OBJECT_0) {
     159                  ResetEvent(hInterruptEvent);
     160                  PyEval_RestoreThread(tstate);
     161                  s = PyErr_CheckSignals();
     162                  PyEval_SaveThread();
     163                  if (s < 0) {
     164                      goto exit;
     165                  }
     166              }
     167              break;
     168          }
     169  
     170          total_read += n_read;
     171          if (total_read == 0 || wbuf[total_read - 1] == L'\n') {
     172              break;
     173          }
     174          wbuflen += chunk_size;
     175          if (wbuf == wbuf_local) {
     176              wbuf[total_read] = '\0';
     177              wbuf = (wchar_t*)PyMem_RawMalloc(wbuflen * sizeof(wchar_t));
     178              if (wbuf) {
     179                  wcscpy_s(wbuf, wbuflen, wbuf_local);
     180              }
     181              else {
     182                  PyEval_RestoreThread(tstate);
     183                  PyErr_NoMemory();
     184                  PyEval_SaveThread();
     185                  goto exit;
     186              }
     187          }
     188          else {
     189              wchar_t *tmp = PyMem_RawRealloc(wbuf, wbuflen * sizeof(wchar_t));
     190              if (tmp == NULL) {
     191                  PyEval_RestoreThread(tstate);
     192                  PyErr_NoMemory();
     193                  PyEval_SaveThread();
     194                  goto exit;
     195              }
     196              wbuf = tmp;
     197          }
     198      }
     199  
     200      if (wbuf[0] == '\x1a') {
     201          buf = PyMem_RawMalloc(1);
     202          if (buf) {
     203              buf[0] = '\0';
     204          }
     205          else {
     206              PyEval_RestoreThread(tstate);
     207              PyErr_NoMemory();
     208              PyEval_SaveThread();
     209          }
     210          goto exit;
     211      }
     212  
     213      u8len = WideCharToMultiByte(CP_UTF8, 0,
     214                                  wbuf, total_read,
     215                                  NULL, 0,
     216                                  NULL, NULL);
     217      buf = PyMem_RawMalloc(u8len + 1);
     218      if (buf == NULL) {
     219          PyEval_RestoreThread(tstate);
     220          PyErr_NoMemory();
     221          PyEval_SaveThread();
     222          goto exit;
     223      }
     224  
     225      u8len = WideCharToMultiByte(CP_UTF8, 0,
     226                                  wbuf, total_read,
     227                                  buf, u8len,
     228                                  NULL, NULL);
     229      buf[u8len] = '\0';
     230  
     231  exit:
     232      if (wbuf != wbuf_local) {
     233          PyMem_RawFree(wbuf);
     234      }
     235  
     236      if (err) {
     237          PyEval_RestoreThread(tstate);
     238          PyErr_SetFromWindowsErr(err);
     239          PyEval_SaveThread();
     240      }
     241      return buf;
     242  }
     243  
     244  #endif /* HAVE_WINDOWS_CONSOLE_IO */
     245  
     246  
     247  /* Readline implementation using fgets() */
     248  
     249  char *
     250  PyOS_StdioReadline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt)
     251  {
     252      size_t n;
     253      char *p, *pr;
     254      PyThreadState *tstate = _PyOS_ReadlineTState;
     255      assert(tstate != NULL);
     256  
     257  #ifdef HAVE_WINDOWS_CONSOLE_IO
     258      const PyConfig *config = _PyInterpreterState_GetConfig(tstate->interp);
     259      if (!config->legacy_windows_stdio && sys_stdin == stdin) {
     260          HANDLE hStdIn, hStdErr;
     261  
     262          hStdIn = _Py_get_osfhandle_noraise(fileno(sys_stdin));
     263          hStdErr = _Py_get_osfhandle_noraise(fileno(stderr));
     264  
     265          if (_get_console_type(hStdIn) == 'r') {
     266              fflush(sys_stdout);
     267              if (prompt) {
     268                  if (_get_console_type(hStdErr) == 'w') {
     269                      wchar_t *wbuf;
     270                      int wlen;
     271                      wlen = MultiByteToWideChar(CP_UTF8, 0, prompt, -1,
     272                              NULL, 0);
     273                      if (wlen) {
     274                          wbuf = PyMem_RawMalloc(wlen * sizeof(wchar_t));
     275                          if (wbuf == NULL) {
     276                              PyEval_RestoreThread(tstate);
     277                              PyErr_NoMemory();
     278                              PyEval_SaveThread();
     279                              return NULL;
     280                          }
     281                          wlen = MultiByteToWideChar(CP_UTF8, 0, prompt, -1,
     282                                  wbuf, wlen);
     283                          if (wlen) {
     284                              DWORD n;
     285                              fflush(stderr);
     286                              /* wlen includes null terminator, so subtract 1 */
     287                              WriteConsoleW(hStdErr, wbuf, wlen - 1, &n, NULL);
     288                          }
     289                          PyMem_RawFree(wbuf);
     290                      }
     291                  } else {
     292                      fprintf(stderr, "%s", prompt);
     293                      fflush(stderr);
     294                  }
     295              }
     296              clearerr(sys_stdin);
     297              return _PyOS_WindowsConsoleReadline(tstate, hStdIn);
     298          }
     299      }
     300  #endif
     301  
     302      fflush(sys_stdout);
     303      if (prompt) {
     304          fprintf(stderr, "%s", prompt);
     305      }
     306      fflush(stderr);
     307  
     308      n = 0;
     309      p = NULL;
     310      do {
     311          size_t incr = (n > 0) ? n + 2 : 100;
     312          if (incr > INT_MAX) {
     313              PyMem_RawFree(p);
     314              PyEval_RestoreThread(tstate);
     315              PyErr_SetString(PyExc_OverflowError, "input line too long");
     316              PyEval_SaveThread();
     317              return NULL;
     318          }
     319          pr = (char *)PyMem_RawRealloc(p, n + incr);
     320          if (pr == NULL) {
     321              PyMem_RawFree(p);
     322              PyEval_RestoreThread(tstate);
     323              PyErr_NoMemory();
     324              PyEval_SaveThread();
     325              return NULL;
     326          }
     327          p = pr;
     328          int err = my_fgets(tstate, p + n, (int)incr, sys_stdin);
     329          if (err == 1) {
     330              // Interrupt
     331              PyMem_RawFree(p);
     332              return NULL;
     333          } else if (err != 0) {
     334              // EOF or error
     335              p[n] = '\0';
     336              break;
     337          }
     338          n += strlen(p + n);
     339      } while (p[n-1] != '\n');
     340  
     341      pr = (char *)PyMem_RawRealloc(p, n+1);
     342      if (pr == NULL) {
     343          PyMem_RawFree(p);
     344          PyEval_RestoreThread(tstate);
     345          PyErr_NoMemory();
     346          PyEval_SaveThread();
     347          return NULL;
     348      }
     349      return pr;
     350  }
     351  
     352  
     353  /* By initializing this function pointer, systems embedding Python can
     354     override the readline function.
     355  
     356     Note: Python expects in return a buffer allocated with PyMem_Malloc. */
     357  
     358  char *(*PyOS_ReadlineFunctionPointer)(FILE *, FILE *, const char *) = NULL;
     359  
     360  
     361  /* Interface used by tokenizer.c and bltinmodule.c */
     362  
     363  char *
     364  PyOS_Readline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt)
     365  {
     366      char *rv, *res;
     367      size_t len;
     368  
     369      PyThreadState *tstate = _PyThreadState_GET();
     370      if (_PyOS_ReadlineTState == tstate) {
     371          PyErr_SetString(PyExc_RuntimeError,
     372                          "can't re-enter readline");
     373          return NULL;
     374      }
     375  
     376  
     377      if (PyOS_ReadlineFunctionPointer == NULL) {
     378          PyOS_ReadlineFunctionPointer = PyOS_StdioReadline;
     379      }
     380  
     381      if (_PyOS_ReadlineLock == NULL) {
     382          _PyOS_ReadlineLock = PyThread_allocate_lock();
     383          if (_PyOS_ReadlineLock == NULL) {
     384              PyErr_SetString(PyExc_MemoryError, "can't allocate lock");
     385              return NULL;
     386          }
     387      }
     388  
     389      _PyOS_ReadlineTState = tstate;
     390      Py_BEGIN_ALLOW_THREADS
     391      PyThread_acquire_lock(_PyOS_ReadlineLock, 1);
     392  
     393      /* This is needed to handle the unlikely case that the
     394       * interpreter is in interactive mode *and* stdin/out are not
     395       * a tty.  This can happen, for example if python is run like
     396       * this: python -i < test1.py
     397       */
     398      if (!isatty(fileno(sys_stdin)) || !isatty(fileno(sys_stdout)) ||
     399          // GH-104668: Don't call global callbacks like PyOS_InputHook or
     400          // PyOS_ReadlineFunctionPointer from subinterpreters, since it seems
     401          // like there's no good way for users (like readline and tkinter) to
     402          // avoid using global state to manage them. Plus, we generally don't
     403          // want to cause trouble for libraries that don't know/care about
     404          // subinterpreter support. If libraries really need better APIs that
     405          // work per-interpreter and have ways to access module state, we can
     406          // certainly add them later (but for now we'll cross our fingers and
     407          // hope that nobody actually cares):
     408          !_Py_IsMainInterpreter(tstate->interp))
     409      {
     410          rv = PyOS_StdioReadline(sys_stdin, sys_stdout, prompt);
     411      }
     412      else {
     413          rv = (*PyOS_ReadlineFunctionPointer)(sys_stdin, sys_stdout, prompt);
     414      }
     415      Py_END_ALLOW_THREADS
     416  
     417      PyThread_release_lock(_PyOS_ReadlineLock);
     418  
     419      _PyOS_ReadlineTState = NULL;
     420  
     421      if (rv == NULL)
     422          return NULL;
     423  
     424      len = strlen(rv) + 1;
     425      res = PyMem_Malloc(len);
     426      if (res != NULL) {
     427          memcpy(res, rv, len);
     428      }
     429      else {
     430          PyErr_NoMemory();
     431      }
     432      PyMem_RawFree(rv);
     433  
     434      return res;
     435  }