Move readline to the readline/readline subdirectory
[deliverable/binutils-gdb.git] / readline / readline / input.c
diff --git a/readline/readline/input.c b/readline/readline/input.c
new file mode 100644 (file)
index 0000000..95ace84
--- /dev/null
@@ -0,0 +1,694 @@
+/* input.c -- character input functions for readline. */
+
+/* Copyright (C) 1994-2017 Free Software Foundation, Inc.
+
+   This file is part of the GNU Readline Library (Readline), a library
+   for reading lines of text with interactive input and history editing.      
+
+   Readline is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   Readline is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with Readline.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#define READLINE_LIBRARY
+
+#if defined (__TANDEM)
+#  include <floss.h>
+#endif
+
+#if defined (HAVE_CONFIG_H)
+#  include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <fcntl.h>
+#if defined (HAVE_SYS_FILE_H)
+#  include <sys/file.h>
+#endif /* HAVE_SYS_FILE_H */
+
+#if defined (HAVE_UNISTD_H)
+#  include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#if defined (HAVE_STDLIB_H)
+#  include <stdlib.h>
+#else
+#  include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+
+#include <signal.h>
+
+#include "posixselect.h"
+
+#if defined (FIONREAD_IN_SYS_IOCTL)
+#  include <sys/ioctl.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+/* System-specific feature definitions and include files. */
+#include "rldefs.h"
+#include "rlmbutil.h"
+
+/* Some standard library routines. */
+#include "readline.h"
+
+#include "rlprivate.h"
+#include "rlshell.h"
+#include "xmalloc.h"
+
+/* What kind of non-blocking I/O do we have? */
+#if !defined (O_NDELAY) && defined (O_NONBLOCK)
+#  define O_NDELAY O_NONBLOCK  /* Posix style */
+#endif
+
+#if defined (HAVE_PSELECT)
+extern sigset_t _rl_orig_sigset;
+#endif
+
+/* Non-null means it is a pointer to a function to run while waiting for
+   character input. */
+rl_hook_func_t *rl_event_hook = (rl_hook_func_t *)NULL;
+
+/* A function to call if a read(2) is interrupted by a signal. */
+rl_hook_func_t *rl_signal_event_hook = (rl_hook_func_t *)NULL;
+
+/* A function to replace _rl_input_available for applications using the
+   callback interface. */
+rl_hook_func_t *rl_input_available_hook = (rl_hook_func_t *)NULL;
+
+rl_getc_func_t *rl_getc_function = rl_getc;
+
+static int _keyboard_input_timeout = 100000;           /* 0.1 seconds; it's in usec */
+
+static int ibuffer_space PARAMS((void));
+static int rl_get_char PARAMS((int *));
+static int rl_gather_tyi PARAMS((void));
+
+#if defined (_WIN32) && !defined (__CYGWIN__)
+
+/* 'isatty' in the Windows runtime returns non-zero for every
+   character device, including the null device.  Repair that.  */
+#include <io.h>
+#include <conio.h>
+#define WIN32_LEAN_AND_MEAN 1
+#include <windows.h>
+
+int w32_isatty (int fd)
+{
+  if (_isatty(fd))
+    {
+      HANDLE h;
+      DWORD ignored;
+
+      if ((h = (HANDLE) _get_osfhandle (fd)) == INVALID_HANDLE_VALUE)
+       {
+         errno = EBADF;
+         return 0;
+       }
+      if (GetConsoleMode (h, &ignored) != 0)
+       return 1;
+    }
+  errno = ENOTTY;
+  return 0;
+}
+
+#define isatty(x)  w32_isatty(x)
+#endif
+
+/* **************************************************************** */
+/*                                                                 */
+/*                     Character Input Buffering                   */
+/*                                                                 */
+/* **************************************************************** */
+
+static int pop_index, push_index;
+static unsigned char ibuffer[512];
+static int ibuffer_len = sizeof (ibuffer) - 1;
+
+#define any_typein (push_index != pop_index)
+
+int
+_rl_any_typein (void)
+{
+  return any_typein;
+}
+
+int
+_rl_pushed_input_available (void)
+{
+  return (push_index != pop_index);
+}
+
+/* Return the amount of space available in the buffer for stuffing
+   characters. */
+static int
+ibuffer_space (void)
+{
+  if (pop_index > push_index)
+    return (pop_index - push_index - 1);
+  else
+    return (ibuffer_len - (push_index - pop_index));
+}
+
+/* Get a key from the buffer of characters to be read.
+   Return the key in KEY.
+   Result is non-zero if there was a key, or 0 if there wasn't. */
+static int
+rl_get_char (int *key)
+{
+  if (push_index == pop_index)
+    return (0);
+
+  *key = ibuffer[pop_index++];
+#if 0
+  if (pop_index >= ibuffer_len)
+#else
+  if (pop_index > ibuffer_len)
+#endif
+    pop_index = 0;
+
+  return (1);
+}
+
+/* Stuff KEY into the *front* of the input buffer.
+   Returns non-zero if successful, zero if there is
+   no space left in the buffer. */
+int
+_rl_unget_char (int key)
+{
+  if (ibuffer_space ())
+    {
+      pop_index--;
+      if (pop_index < 0)
+       pop_index = ibuffer_len;
+      ibuffer[pop_index] = key;
+      return (1);
+    }
+  return (0);
+}
+
+/* If a character is available to be read, then read it and stuff it into
+   IBUFFER.  Otherwise, just return.  Returns number of characters read
+   (0 if none available) and -1 on error (EIO). */
+static int
+rl_gather_tyi (void)
+{
+  int tty;
+  register int tem, result;
+  int chars_avail, k;
+  char input;
+#if defined(HAVE_SELECT)
+  fd_set readfds, exceptfds;
+  struct timeval timeout;
+#endif
+
+  chars_avail = 0;
+  input = 0;
+  tty = fileno (rl_instream);
+
+#if defined (HAVE_SELECT)
+  FD_ZERO (&readfds);
+  FD_ZERO (&exceptfds);
+  FD_SET (tty, &readfds);
+  FD_SET (tty, &exceptfds);
+  USEC_TO_TIMEVAL (_keyboard_input_timeout, timeout);
+  result = select (tty + 1, &readfds, (fd_set *)NULL, &exceptfds, &timeout);
+  if (result <= 0)
+    return 0;  /* Nothing to read. */
+#endif
+
+  result = -1;
+  errno = 0;
+#if defined (FIONREAD)
+  result = ioctl (tty, FIONREAD, &chars_avail);
+  if (result == -1 && errno == EIO)
+    return -1;
+  if (result == -1)
+    chars_avail = 0;
+#endif
+
+#if defined (O_NDELAY)
+  if (result == -1)
+    {
+      tem = fcntl (tty, F_GETFL, 0);
+
+      fcntl (tty, F_SETFL, (tem | O_NDELAY));
+      chars_avail = read (tty, &input, 1);
+
+      fcntl (tty, F_SETFL, tem);
+      if (chars_avail == -1 && errno == EAGAIN)
+       return 0;
+      if (chars_avail == -1 && errno == EIO)
+       return -1;
+      if (chars_avail == 0)    /* EOF */
+       {
+         rl_stuff_char (EOF);
+         return (0);
+       }
+    }
+#endif /* O_NDELAY */
+
+#if defined (__MINGW32__)
+  /* Use getch/_kbhit to check for available console input, in the same way
+     that we read it normally. */
+   chars_avail = isatty (tty) ? _kbhit () : 0;
+   result = 0;
+#endif
+
+  /* If there's nothing available, don't waste time trying to read
+     something. */
+  if (chars_avail <= 0)
+    return 0;
+
+  tem = ibuffer_space ();
+
+  if (chars_avail > tem)
+    chars_avail = tem;
+
+  /* One cannot read all of the available input.  I can only read a single
+     character at a time, or else programs which require input can be
+     thwarted.  If the buffer is larger than one character, I lose.
+     Damn! */
+  if (tem < ibuffer_len)
+    chars_avail = 0;
+
+  if (result != -1)
+    {
+      while (chars_avail--)
+       {
+         RL_CHECK_SIGNALS ();
+         k = (*rl_getc_function) (rl_instream);
+         if (rl_stuff_char (k) == 0)
+           break;                      /* some problem; no more room */
+         if (k == NEWLINE || k == RETURN)
+           break;
+       }
+    }
+  else
+    {
+      if (chars_avail)
+       rl_stuff_char (input);
+    }
+
+  return 1;
+}
+
+int
+rl_set_keyboard_input_timeout (int u)
+{
+  int o;
+
+  o = _keyboard_input_timeout;
+  if (u >= 0)
+    _keyboard_input_timeout = u;
+  return (o);
+}
+
+/* Is there input available to be read on the readline input file
+   descriptor?  Only works if the system has select(2) or FIONREAD.
+   Uses the value of _keyboard_input_timeout as the timeout; if another
+   readline function wants to specify a timeout and not leave it up to
+   the user, it should use _rl_input_queued(timeout_value_in_microseconds)
+   instead. */
+int
+_rl_input_available (void)
+{
+#if defined(HAVE_SELECT)
+  fd_set readfds, exceptfds;
+  struct timeval timeout;
+#endif
+#if !defined (HAVE_SELECT) && defined(FIONREAD)
+  int chars_avail;
+#endif
+  int tty;
+
+  if (rl_input_available_hook)
+    return (*rl_input_available_hook) ();
+
+  tty = fileno (rl_instream);
+
+#if defined (HAVE_SELECT)
+  FD_ZERO (&readfds);
+  FD_ZERO (&exceptfds);
+  FD_SET (tty, &readfds);
+  FD_SET (tty, &exceptfds);
+  timeout.tv_sec = 0;
+  timeout.tv_usec = _keyboard_input_timeout;
+  return (select (tty + 1, &readfds, (fd_set *)NULL, &exceptfds, &timeout) > 0);
+#else
+
+#if defined (FIONREAD)
+  if (ioctl (tty, FIONREAD, &chars_avail) == 0)
+    return (chars_avail);
+#endif
+
+#endif
+
+#if defined (__MINGW32__)
+  if (isatty (tty))
+    return (_kbhit ());
+#endif
+
+  return 0;
+}
+
+int
+_rl_input_queued (int t)
+{
+  int old_timeout, r;
+
+  old_timeout = rl_set_keyboard_input_timeout (t);
+  r = _rl_input_available ();
+  rl_set_keyboard_input_timeout (old_timeout);
+  return r;
+}
+
+void
+_rl_insert_typein (int c)
+{      
+  int key, t, i;
+  char *string;
+
+  i = key = 0;
+  string = (char *)xmalloc (ibuffer_len + 1);
+  string[i++] = (char) c;
+
+  while ((t = rl_get_char (&key)) &&
+        _rl_keymap[key].type == ISFUNC &&
+        _rl_keymap[key].function == rl_insert)
+    string[i++] = key;
+
+  if (t)
+    _rl_unget_char (key);
+
+  string[i] = '\0';
+  rl_insert_text (string);
+  xfree (string);
+}
+
+/* Add KEY to the buffer of characters to be read.  Returns 1 if the
+   character was stuffed correctly; 0 otherwise. */
+int
+rl_stuff_char (int key)
+{
+  if (ibuffer_space () == 0)
+    return 0;
+
+  if (key == EOF)
+    {
+      key = NEWLINE;
+      rl_pending_input = EOF;
+      RL_SETSTATE (RL_STATE_INPUTPENDING);
+    }
+  ibuffer[push_index++] = key;
+#if 0
+  if (push_index >= ibuffer_len)
+#else
+  if (push_index > ibuffer_len)
+#endif
+    push_index = 0;
+
+  return 1;
+}
+
+/* Make C be the next command to be executed. */
+int
+rl_execute_next (int c)
+{
+  rl_pending_input = c;
+  RL_SETSTATE (RL_STATE_INPUTPENDING);
+  return 0;
+}
+
+/* Clear any pending input pushed with rl_execute_next() */
+int
+rl_clear_pending_input (void)
+{
+  rl_pending_input = 0;
+  RL_UNSETSTATE (RL_STATE_INPUTPENDING);
+  return 0;
+}
+
+/* **************************************************************** */
+/*                                                                 */
+/*                          Character Input                        */
+/*                                                                 */
+/* **************************************************************** */
+
+/* Read a key, including pending input. */
+int
+rl_read_key (void)
+{
+  int c, r;
+
+  if (rl_pending_input)
+    {
+      c = rl_pending_input;    /* XXX - cast to unsigned char if > 0? */
+      rl_clear_pending_input ();
+    }
+  else
+    {
+      /* If input is coming from a macro, then use that. */
+      if (c = _rl_next_macro_key ())
+       return ((unsigned char)c);
+
+      /* If the user has an event function, then call it periodically. */
+      if (rl_event_hook)
+       {
+         while (rl_event_hook)
+           {
+             if (rl_get_char (&c) != 0)
+               break;
+               
+             if ((r = rl_gather_tyi ()) < 0)   /* XXX - EIO */
+               {
+                 rl_done = 1;
+                 return (errno == EIO ? (RL_ISSTATE (RL_STATE_READCMD) ? READERR : EOF) : '\n');
+               }
+             else if (r > 0)                   /* read something */
+               continue;
+
+             RL_CHECK_SIGNALS ();
+             if (rl_done)              /* XXX - experimental */
+               return ('\n');
+             (*rl_event_hook) ();
+           }
+       }
+      else
+       {
+         if (rl_get_char (&c) == 0)
+           c = (*rl_getc_function) (rl_instream);
+/* fprintf(stderr, "rl_read_key: calling RL_CHECK_SIGNALS: _rl_caught_signal = %d", _rl_caught_signal); */
+         RL_CHECK_SIGNALS ();
+       }
+    }
+
+  return (c);
+}
+
+int
+rl_getc (FILE *stream)
+{
+  int result;
+  unsigned char c;
+#if defined (HAVE_PSELECT)
+  sigset_t empty_set;
+  fd_set readfds;
+#endif
+
+  while (1)
+    {
+      RL_CHECK_SIGNALS ();
+
+      /* We know at this point that _rl_caught_signal == 0 */
+
+#if defined (__MINGW32__)
+      if (isatty (fileno (stream)))
+       return (_getch ());     /* "There is no error return." */
+#endif
+      result = 0;
+#if defined (HAVE_PSELECT)
+      FD_ZERO (&readfds);
+      FD_SET (fileno (stream), &readfds);
+#  if defined (HANDLE_SIGNALS)
+      result = pselect (fileno (stream) + 1, &readfds, NULL, NULL, NULL, &_rl_orig_sigset);
+#  else
+      sigemptyset (&empty_set);
+      sigprocmask (SIG_BLOCK, (sigset_t *)NULL, &empty_set);
+      result = pselect (fileno (stream) + 1, &readfds, NULL, NULL, NULL, &empty_set);
+#  endif /* HANDLE_SIGNALS */
+#endif
+      if (result >= 0)
+       result = read (fileno (stream), &c, sizeof (unsigned char));
+
+      if (result == sizeof (unsigned char))
+       return (c);
+
+      /* If zero characters are returned, then the file that we are
+        reading from is empty!  Return EOF in that case. */
+      if (result == 0)
+       return (EOF);
+
+#if defined (__BEOS__)
+      if (errno == EINTR)
+       continue;
+#endif
+
+#if defined (EWOULDBLOCK)
+#  define X_EWOULDBLOCK EWOULDBLOCK
+#else
+#  define X_EWOULDBLOCK -99
+#endif
+
+#if defined (EAGAIN)
+#  define X_EAGAIN EAGAIN
+#else
+#  define X_EAGAIN -99
+#endif
+
+      if (errno == X_EWOULDBLOCK || errno == X_EAGAIN)
+       {
+         if (sh_unset_nodelay_mode (fileno (stream)) < 0)
+           return (EOF);
+         continue;
+       }
+
+#undef X_EWOULDBLOCK
+#undef X_EAGAIN
+
+/* fprintf(stderr, "rl_getc: result = %d errno = %d\n", result, errno); */
+
+handle_error:
+      /* If the error that we received was EINTR, then try again,
+        this is simply an interrupted system call to read ().  We allow
+        the read to be interrupted if we caught SIGHUP, SIGTERM, or any
+        of the other signals readline treats specially. If the
+        application sets an event hook, call it for other signals.
+        Otherwise (not EINTR), some error occurred, also signifying EOF. */
+      if (errno != EINTR)
+       return (RL_ISSTATE (RL_STATE_READCMD) ? READERR : EOF);
+      /* fatal signals of interest */
+#if defined (SIGHUP)
+      else if (_rl_caught_signal == SIGHUP || _rl_caught_signal == SIGTERM)
+#else
+      else if (_rl_caught_signal == SIGTERM)
+#endif
+       return (RL_ISSTATE (RL_STATE_READCMD) ? READERR : EOF);
+      /* keyboard-generated signals of interest */
+#if defined (SIGQUIT)
+      else if (_rl_caught_signal == SIGINT || _rl_caught_signal == SIGQUIT)
+#else
+      else if (_rl_caught_signal == SIGINT)
+#endif
+        RL_CHECK_SIGNALS ();
+      /* non-keyboard-generated signals of interest */
+#if defined (SIGWINCH)
+      else if (_rl_caught_signal == SIGWINCH)
+       RL_CHECK_SIGNALS ();
+#endif /* SIGWINCH */
+#if defined (SIGALRM)
+      else if (_rl_caught_signal == SIGALRM
+#  if defined (SIGVTALRM)
+               || _rl_caught_signal == SIGVTALRM
+#  endif
+             )
+        RL_CHECK_SIGNALS ();
+#endif  /* SIGALRM */
+
+      if (rl_signal_event_hook)
+       (*rl_signal_event_hook) ();
+    }
+}
+
+#if defined (HANDLE_MULTIBYTE)
+/* read multibyte char */
+int
+_rl_read_mbchar (char *mbchar, int size)
+{
+  int mb_len, c;
+  size_t mbchar_bytes_length;
+  wchar_t wc;
+  mbstate_t ps, ps_back;
+
+  memset(&ps, 0, sizeof (mbstate_t));
+  memset(&ps_back, 0, sizeof (mbstate_t));
+
+  mb_len = 0;  
+  while (mb_len < size)
+    {
+      RL_SETSTATE(RL_STATE_MOREINPUT);
+      c = rl_read_key ();
+      RL_UNSETSTATE(RL_STATE_MOREINPUT);
+
+      if (c < 0)
+       break;
+
+      mbchar[mb_len++] = c;
+
+      mbchar_bytes_length = mbrtowc (&wc, mbchar, mb_len, &ps);
+      if (mbchar_bytes_length == (size_t)(-1))
+       break;          /* invalid byte sequence for the current locale */
+      else if (mbchar_bytes_length == (size_t)(-2))
+       {
+         /* shorted bytes */
+         ps = ps_back;
+         continue;
+       } 
+      else if (mbchar_bytes_length == 0)
+       {
+         mbchar[0] = '\0';     /* null wide character */
+         mb_len = 1;
+         break;
+       }
+      else if (mbchar_bytes_length > (size_t)(0))
+       break;
+    }
+
+  return mb_len;
+}
+
+/* Read a multibyte-character string whose first character is FIRST into
+   the buffer MB of length MLEN.  Returns the last character read, which
+   may be FIRST.  Used by the search functions, among others.  Very similar
+   to _rl_read_mbchar. */
+int
+_rl_read_mbstring (int first, char *mb, int mlen)
+{
+  int i, c, n;
+  mbstate_t ps;
+
+  c = first;
+  memset (mb, 0, mlen);
+  for (i = 0; c >= 0 && i < mlen; i++)
+    {
+      mb[i] = (char)c;
+      memset (&ps, 0, sizeof (mbstate_t));
+      n = _rl_get_char_len (mb, &ps);
+      if (n == -2)
+       {
+         /* Read more for multibyte character */
+         RL_SETSTATE (RL_STATE_MOREINPUT);
+         c = rl_read_key ();
+         RL_UNSETSTATE (RL_STATE_MOREINPUT);
+       }
+      else
+       break;
+    }
+  return c;
+}
+#endif /* HANDLE_MULTIBYTE */
This page took 0.051499 seconds and 4 git commands to generate.