| /* input.c -- character input functions for readline. */ |
| |
| /* Copyright (C) 1994-2010 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 "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 |
| |
| /* 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; |
| |
| 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> |
| #define WIN32_LEAN_AND_MEAN 1 |
| #include <windows.h> |
| |
| int w32_isatty (int fd) |
| { |
| if (_isatty(fd)) |
| { |
| HANDLE h = (HANDLE) _get_osfhandle (fd); |
| DWORD ignored; |
| |
| if (h == 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 () |
| { |
| return any_typein; |
| } |
| |
| /* Return the amount of space available in the buffer for stuffing |
| characters. */ |
| static int |
| ibuffer_space () |
| { |
| 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 KEY if there was a key, or 0 if there wasn't. */ |
| static int |
| rl_get_char (key) |
| 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 (key) |
| int key; |
| { |
| if (ibuffer_space ()) |
| { |
| pop_index--; |
| if (pop_index < 0) |
| pop_index = ibuffer_len; |
| ibuffer[pop_index] = key; |
| return (1); |
| } |
| return (0); |
| } |
| |
| int |
| _rl_pushed_input_available () |
| { |
| return (push_index != pop_index); |
| } |
| |
| /* 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 () |
| { |
| 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; |
| 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; |
| #if defined (FIONREAD) |
| errno = 0; |
| result = ioctl (tty, FIONREAD, &chars_avail); |
| if (result == -1 && errno == EIO) |
| return -1; |
| #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 == 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 (u) |
| 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 () |
| { |
| #if defined(HAVE_SELECT) |
| fd_set readfds, exceptfds; |
| struct timeval timeout; |
| #endif |
| #if !defined (HAVE_SELECT) && defined(FIONREAD) |
| int chars_avail; |
| #endif |
| int tty; |
| |
| 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 (t) |
| 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 (c) |
| 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 (key) |
| 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 (c) |
| 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 () |
| { |
| rl_pending_input = 0; |
| RL_UNSETSTATE (RL_STATE_INPUTPENDING); |
| return 0; |
| } |
| |
| /* **************************************************************** */ |
| /* */ |
| /* Character Input */ |
| /* */ |
| /* **************************************************************** */ |
| |
| /* Read a key, including pending input. */ |
| int |
| rl_read_key () |
| { |
| int c; |
| |
| rl_key_sequence_length++; |
| |
| if (rl_pending_input) |
| { |
| c = rl_pending_input; |
| rl_clear_pending_input (); |
| } |
| else |
| { |
| /* If input is coming from a macro, then use that. */ |
| if (c = _rl_next_macro_key ()) |
| return (c); |
| |
| /* If the user has an event function, then call it periodically. */ |
| if (rl_event_hook) |
| { |
| while (rl_event_hook) |
| { |
| if (rl_gather_tyi () < 0) /* XXX - EIO */ |
| { |
| rl_done = 1; |
| return ('\n'); |
| } |
| RL_CHECK_SIGNALS (); |
| if (rl_get_char (&c) != 0) |
| break; |
| if (rl_done) /* XXX - experimental */ |
| return ('\n'); |
| (*rl_event_hook) (); |
| } |
| } |
| else |
| { |
| if (rl_get_char (&c) == 0) |
| c = (*rl_getc_function) (rl_instream); |
| RL_CHECK_SIGNALS (); |
| } |
| } |
| |
| return (c); |
| } |
| |
| int |
| rl_getc (stream) |
| FILE *stream; |
| { |
| int result; |
| unsigned char c; |
| |
| while (1) |
| { |
| RL_CHECK_SIGNALS (); |
| |
| #if defined (__MINGW32__) |
| /* Use _getch to make sure we call the function from MS runtime, |
| even if some curses library is linked in. */ |
| if (isatty (fileno (stream))) |
| return (_getch ()); |
| #endif |
| 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 |
| |
| /* If the error that we received was SIGINT, then try again, |
| this is simply an interrupted system call to read (). |
| Otherwise, some error ocurred, also signifying EOF. */ |
| if (errno != EINTR) |
| return (RL_ISSTATE (RL_STATE_READCMD) ? READERR : EOF); |
| } |
| } |
| |
| #if defined (HANDLE_MULTIBYTE) |
| /* read multibyte char */ |
| int |
| _rl_read_mbchar (mbchar, size) |
| 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 (first, mb, mlen) |
| int first; |
| char *mb; |
| int mlen; |
| { |
| int i, c; |
| 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)); |
| if (_rl_get_char_len (mb, &ps) == -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 */ |