mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-08-07 18:52:35 +02:00
Bash-5.3-alpha release
This commit is contained in:
+510
-18
@@ -1,6 +1,6 @@
|
||||
/* text.c -- text handling commands for readline. */
|
||||
|
||||
/* Copyright (C) 1987-2021 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1987-2021,2023-2024 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.
|
||||
@@ -85,7 +85,8 @@ int _rl_optimize_typeahead = 1; /* rl_insert tries to read typeahead */
|
||||
int
|
||||
rl_insert_text (const char *string)
|
||||
{
|
||||
register int i, l;
|
||||
register int i;
|
||||
size_t l;
|
||||
|
||||
l = (string && *string) ? strlen (string) : 0;
|
||||
if (l == 0)
|
||||
@@ -704,7 +705,11 @@ static mbstate_t ps = {0};
|
||||
|
||||
/* Insert the character C at the current location, moving point forward.
|
||||
If C introduces a multibyte sequence, we read the whole sequence and
|
||||
then insert the multibyte char into the line buffer. */
|
||||
then insert the multibyte char into the line buffer.
|
||||
If C == 0, we immediately insert any pending partial multibyte character,
|
||||
assuming that we have read a character that doesn't map to self-insert.
|
||||
This doesn't completely handle characters that are part of a multibyte
|
||||
character but map to editing functions. */
|
||||
int
|
||||
_rl_insert_char (int count, int c)
|
||||
{
|
||||
@@ -718,11 +723,28 @@ _rl_insert_char (int count, int c)
|
||||
static int stored_count = 0;
|
||||
#endif
|
||||
|
||||
#if !defined (HANDLE_MULTIBYTE)
|
||||
if (count <= 0)
|
||||
return 0;
|
||||
#else
|
||||
if (count < 0)
|
||||
return 0;
|
||||
if (count == 0)
|
||||
{
|
||||
if (pending_bytes_length == 0)
|
||||
return 0;
|
||||
if (stored_count <= 0)
|
||||
stored_count = count;
|
||||
else
|
||||
count = stored_count;
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
if (MB_CUR_MAX == 1 || rl_byte_oriented)
|
||||
memcpy (incoming, pending_bytes, pending_bytes_length);
|
||||
incoming[pending_bytes_length] = '\0';
|
||||
incoming_length = pending_bytes_length;
|
||||
pending_bytes_length = 0;
|
||||
memset (&ps, 0, sizeof (mbstate_t));
|
||||
}
|
||||
else if (MB_CUR_MAX == 1 || rl_byte_oriented)
|
||||
{
|
||||
incoming[0] = c;
|
||||
incoming[1] = '\0';
|
||||
@@ -730,6 +752,9 @@ _rl_insert_char (int count, int c)
|
||||
}
|
||||
else if (_rl_utf8locale && (c & 0x80) == 0)
|
||||
{
|
||||
if (pending_bytes_length)
|
||||
_rl_insert_char (0, 0);
|
||||
|
||||
incoming[0] = c;
|
||||
incoming[1] = '\0';
|
||||
incoming_length = 1;
|
||||
@@ -764,7 +789,8 @@ _rl_insert_char (int count, int c)
|
||||
incoming[1] = '\0';
|
||||
incoming_length = 1;
|
||||
pending_bytes_length--;
|
||||
memmove (pending_bytes, pending_bytes + 1, pending_bytes_length);
|
||||
if (pending_bytes_length)
|
||||
memmove (pending_bytes, pending_bytes + 1, pending_bytes_length);
|
||||
/* Clear the state of the byte sequence, because in this case the
|
||||
effect of mbstate is undefined. */
|
||||
memset (&ps, 0, sizeof (mbstate_t));
|
||||
@@ -827,7 +853,11 @@ _rl_insert_char (int count, int c)
|
||||
rl_insert_text (string);
|
||||
xfree (string);
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
return (pending_bytes_length != 0);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (count > TEXT_COUNT_MAX)
|
||||
@@ -860,6 +890,8 @@ _rl_insert_char (int count, int c)
|
||||
xfree (string);
|
||||
incoming_length = 0;
|
||||
stored_count = 0;
|
||||
|
||||
return (pending_bytes_length != 0);
|
||||
#else /* !HANDLE_MULTIBYTE */
|
||||
char str[TEXT_COUNT_MAX+1];
|
||||
|
||||
@@ -873,9 +905,9 @@ _rl_insert_char (int count, int c)
|
||||
rl_insert_text (str);
|
||||
count -= decreaser;
|
||||
}
|
||||
#endif /* !HANDLE_MULTIBYTE */
|
||||
|
||||
return 0;
|
||||
#endif /* !HANDLE_MULTIBYTE */
|
||||
}
|
||||
|
||||
if (MB_CUR_MAX == 1 || rl_byte_oriented)
|
||||
@@ -903,9 +935,11 @@ _rl_insert_char (int count, int c)
|
||||
rl_insert_text (incoming);
|
||||
stored_count = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
return (pending_bytes_length != 0);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Overwrite the character at point (or next COUNT characters) with C.
|
||||
@@ -983,6 +1017,11 @@ rl_insert (int count, int c)
|
||||
break;
|
||||
}
|
||||
|
||||
/* If we didn't insert n and there are pending bytes, we need to insert
|
||||
them if _rl_insert_char didn't do that on its own. */
|
||||
if (r == 1 && rl_insert_mode == RL_IM_INSERT)
|
||||
r = _rl_insert_char (0, 0); /* flush partial multibyte char */
|
||||
|
||||
if (n != (unsigned short)-2) /* -2 = sentinel value for having inserted N */
|
||||
{
|
||||
/* setting rl_pending_input inhibits setting rl_last_func so we do it
|
||||
@@ -992,7 +1031,6 @@ rl_insert (int count, int c)
|
||||
rl_executing_keyseq[rl_key_sequence_length = 0] = '\0';
|
||||
r = rl_execute_next (n);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -1054,6 +1092,8 @@ _rl_insert_next_callback (_rl_callback_generic_arg *data)
|
||||
int
|
||||
rl_quoted_insert (int count, int key)
|
||||
{
|
||||
int r;
|
||||
|
||||
/* Let's see...should the callback interface futz with signal handling? */
|
||||
#if defined (HANDLE_SIGNALS)
|
||||
if (RL_ISSTATE (RL_STATE_CALLBACK) == 0)
|
||||
@@ -1072,15 +1112,17 @@ rl_quoted_insert (int count, int key)
|
||||
/* A negative count means to quote the next -COUNT characters. */
|
||||
if (count < 0)
|
||||
{
|
||||
int r;
|
||||
|
||||
do
|
||||
r = _rl_insert_next (1);
|
||||
while (r == 0 && ++count < 0);
|
||||
return r;
|
||||
}
|
||||
else
|
||||
r = _rl_insert_next (count);
|
||||
|
||||
return _rl_insert_next (count);
|
||||
if (r == 1)
|
||||
_rl_insert_char (0, 0); /* insert partial multibyte character */
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Insert a tab character. */
|
||||
@@ -1229,11 +1271,12 @@ _rl_rubout_char (int count, int key)
|
||||
c = rl_line_buffer[--rl_point];
|
||||
rl_delete_text (rl_point, orig_point);
|
||||
/* The erase-at-end-of-line hack is of questionable merit now. */
|
||||
if (rl_point == rl_end && ISPRINT ((unsigned char)c) && _rl_last_c_pos)
|
||||
if (rl_point == rl_end && ISPRINT ((unsigned char)c) && _rl_last_c_pos && _rl_last_v_pos == 0)
|
||||
{
|
||||
int l;
|
||||
l = rl_character_len (c, rl_point);
|
||||
_rl_erase_at_end_of_line (l);
|
||||
if (_rl_last_c_pos >= l)
|
||||
_rl_erase_at_end_of_line (l);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1764,8 +1807,7 @@ _rl_char_search (int count, int fdir, int bdir)
|
||||
|
||||
#if defined (READLINE_CALLBACKS)
|
||||
static int
|
||||
_rl_char_search_callback (data)
|
||||
_rl_callback_generic_arg *data;
|
||||
_rl_char_search_callback (_rl_callback_generic_arg *data)
|
||||
{
|
||||
_rl_callback_func = 0;
|
||||
_rl_want_redisplay = 1;
|
||||
@@ -1886,3 +1928,453 @@ rl_mark_active_p (void)
|
||||
{
|
||||
return (mark_active);
|
||||
}
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* Reading a string entered from the keyboard */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
/* A very simple set of functions to read a string from the keyboard using
|
||||
the line buffer as temporary storage. The caller can set a completion
|
||||
function to perform completion on TAB and SPACE. */
|
||||
|
||||
/* XXX - this is all very similar to the search stuff but with a different
|
||||
CXT. */
|
||||
|
||||
static HIST_ENTRY *_rl_saved_line_for_readstr;
|
||||
_rl_readstr_cxt *_rl_rscxt;
|
||||
|
||||
_rl_readstr_cxt *
|
||||
_rl_rscxt_alloc (int flags)
|
||||
{
|
||||
_rl_readstr_cxt *cxt;
|
||||
|
||||
cxt = (_rl_readstr_cxt *)xmalloc (sizeof (_rl_readstr_cxt));
|
||||
|
||||
cxt->flags = flags;
|
||||
|
||||
cxt->save_point = rl_point;
|
||||
cxt->save_mark = rl_mark;
|
||||
cxt->save_line = where_history ();
|
||||
|
||||
cxt->prevc = cxt->lastc = 0;
|
||||
|
||||
cxt->compfunc = NULL;
|
||||
|
||||
return cxt;
|
||||
}
|
||||
|
||||
void
|
||||
_rl_rscxt_dispose (_rl_readstr_cxt *cxt, int flags)
|
||||
{
|
||||
xfree (cxt);
|
||||
}
|
||||
|
||||
/* This isn't used yet */
|
||||
void
|
||||
_rl_free_saved_readstr_line ()
|
||||
{
|
||||
if (_rl_saved_line_for_readstr)
|
||||
/* This doesn't free any saved undo list, if it needs to,
|
||||
rl_clear_history shows how to do it. */
|
||||
_rl_free_saved_line (_rl_saved_line_for_readstr);
|
||||
_rl_saved_line_for_readstr = (HIST_ENTRY *)NULL;
|
||||
}
|
||||
|
||||
void
|
||||
_rl_unsave_saved_readstr_line ()
|
||||
{
|
||||
if (_rl_saved_line_for_readstr)
|
||||
{
|
||||
_rl_free_undo_list (rl_undo_list);
|
||||
_rl_unsave_line (_rl_saved_line_for_readstr); /* restores rl_undo_list */
|
||||
}
|
||||
_rl_saved_line_for_readstr = (HIST_ENTRY *)NULL;
|
||||
}
|
||||
|
||||
_rl_readstr_cxt *
|
||||
_rl_readstr_init (int pchar, int flags)
|
||||
{
|
||||
_rl_readstr_cxt *cxt;
|
||||
char *p;
|
||||
|
||||
cxt = _rl_rscxt_alloc (flags);
|
||||
|
||||
rl_maybe_replace_line ();
|
||||
_rl_saved_line_for_readstr = _rl_alloc_saved_line ();
|
||||
|
||||
rl_undo_list = 0;
|
||||
|
||||
rl_line_buffer[0] = 0;
|
||||
rl_end = rl_point = 0;
|
||||
|
||||
p = _rl_make_prompt_for_search (pchar ? pchar : '@');
|
||||
cxt->flags |= READSTR_FREEPMT;
|
||||
rl_message ("%s", p);
|
||||
xfree (p);
|
||||
|
||||
RL_SETSTATE (RL_STATE_READSTR);
|
||||
|
||||
_rl_rscxt = cxt;
|
||||
|
||||
return cxt;
|
||||
}
|
||||
|
||||
int
|
||||
_rl_readstr_cleanup (_rl_readstr_cxt *cxt, int r)
|
||||
{
|
||||
_rl_rscxt_dispose (cxt, 0);
|
||||
_rl_rscxt = 0;
|
||||
|
||||
RL_UNSETSTATE (RL_STATE_READSTR);
|
||||
|
||||
return (r != 1);
|
||||
}
|
||||
|
||||
void
|
||||
_rl_readstr_restore (_rl_readstr_cxt *cxt)
|
||||
{
|
||||
_rl_unsave_saved_readstr_line (); /* restores rl_undo_list */
|
||||
rl_point = cxt->save_point;
|
||||
rl_mark = cxt->save_mark;
|
||||
if (cxt->flags & READSTR_FREEPMT)
|
||||
rl_restore_prompt (); /* _rl_make_prompt_for_search saved it */
|
||||
cxt->flags &= ~READSTR_FREEPMT;
|
||||
rl_clear_message ();
|
||||
_rl_fix_point (1);
|
||||
}
|
||||
|
||||
int
|
||||
_rl_readstr_sigcleanup (_rl_readstr_cxt *cxt, int r)
|
||||
{
|
||||
if (cxt->flags & READSTR_FREEPMT)
|
||||
rl_restore_prompt (); /* _rl_make_prompt_for_search saved it */
|
||||
cxt->flags &= ~READSTR_FREEPMT;
|
||||
return (_rl_readstr_cleanup (cxt, r));
|
||||
}
|
||||
|
||||
int
|
||||
_rl_readstr_getchar (_rl_readstr_cxt *cxt)
|
||||
{
|
||||
int c;
|
||||
|
||||
cxt->prevc = cxt->lastc;
|
||||
|
||||
/* Read a key and decide how to proceed. */
|
||||
RL_SETSTATE(RL_STATE_MOREINPUT);
|
||||
c = cxt->lastc = rl_read_key ();
|
||||
RL_UNSETSTATE(RL_STATE_MOREINPUT);
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
/* This ends up with C (and LASTC) being set to the last byte of the
|
||||
multibyte character. In most cases c == lastc == mb[0] */
|
||||
if (c >= 0 && MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
c = cxt->lastc = _rl_read_mbstring (cxt->lastc, cxt->mb, MB_LEN_MAX);
|
||||
#endif
|
||||
|
||||
RL_CHECK_SIGNALS ();
|
||||
return c;
|
||||
}
|
||||
|
||||
/* Process just-read character C according to readstr context CXT. Return -1
|
||||
if the caller should abort the read, 0 if we should break out of the
|
||||
loop, and 1 if we should continue to read characters. This can perform
|
||||
completion on the string read so far (stored in rl_line_buffer) if the
|
||||
caller has set up a completion function. The completion function can
|
||||
return -1 to indicate that we should abort the read. If we return -1
|
||||
we will call _rl_readstr_restore to clean up the state, leaving the caller
|
||||
to free the context. */
|
||||
int
|
||||
_rl_readstr_dispatch (_rl_readstr_cxt *cxt, int c)
|
||||
{
|
||||
int n;
|
||||
|
||||
if (c < 0)
|
||||
c = CTRL ('C');
|
||||
|
||||
/* could consider looking up the function bound to they key and dispatching
|
||||
off that, but you want most characters inserted by default without having
|
||||
to quote. */
|
||||
switch (c)
|
||||
{
|
||||
case CTRL('W'):
|
||||
rl_unix_word_rubout (1, c);
|
||||
break;
|
||||
|
||||
case CTRL('U'):
|
||||
rl_unix_line_discard (1, c);
|
||||
break;
|
||||
|
||||
case CTRL('Q'):
|
||||
case CTRL('V'):
|
||||
n = rl_quoted_insert (1, c);
|
||||
if (n < 0)
|
||||
{
|
||||
_rl_readstr_restore (cxt);
|
||||
return -1;
|
||||
}
|
||||
cxt->lastc = (rl_point > 0) ? rl_line_buffer[rl_point - 1] : rl_line_buffer[0]; /* preserve prevc */
|
||||
break;
|
||||
|
||||
case RETURN:
|
||||
case NEWLINE:
|
||||
return 0;
|
||||
|
||||
case CTRL('H'):
|
||||
case RUBOUT:
|
||||
if (rl_point == 0)
|
||||
{
|
||||
_rl_readstr_restore (cxt);
|
||||
return -1;
|
||||
}
|
||||
_rl_rubout_char (1, c);
|
||||
break;
|
||||
|
||||
case CTRL('C'):
|
||||
case CTRL('G'):
|
||||
rl_ding ();
|
||||
_rl_readstr_restore (cxt);
|
||||
return -1;
|
||||
|
||||
case ESC:
|
||||
/* Allow users to bracketed-paste text into the string.
|
||||
Similar code is in search.c:_rl_nsearch_dispatch(). */
|
||||
if (_rl_enable_bracketed_paste && ((n = _rl_nchars_available ()) >= (BRACK_PASTE_SLEN-1)))
|
||||
{
|
||||
if (_rl_read_bracketed_paste_prefix (c) == 1)
|
||||
rl_bracketed_paste_begin (1, c);
|
||||
else
|
||||
{
|
||||
c = rl_read_key (); /* get the ESC that got pushed back */
|
||||
_rl_insert_char (1, c);
|
||||
}
|
||||
}
|
||||
else
|
||||
_rl_insert_char (1, c);
|
||||
break;
|
||||
|
||||
case ' ':
|
||||
if ((cxt->flags & READSTR_NOSPACE) == 0)
|
||||
{
|
||||
_rl_insert_char (1, c);
|
||||
break;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case TAB:
|
||||
/* Perform completion if the caller has set a completion function. */
|
||||
n = (cxt->compfunc) ? (*cxt->compfunc) (cxt, c) : _rl_insert_char (1, c);
|
||||
if (n < 0)
|
||||
{
|
||||
_rl_readstr_restore (cxt);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
#if 0
|
||||
case CTRL('_'):
|
||||
rl_do_undo ();
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
rl_insert_text (cxt->mb);
|
||||
else
|
||||
#endif
|
||||
_rl_insert_char (1, c);
|
||||
break;
|
||||
}
|
||||
|
||||
(*rl_redisplay_function) ();
|
||||
rl_deactivate_mark ();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* Reading and Executing named commands */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
/* A completion generator for bindable readline command names. */
|
||||
static char *
|
||||
readcmd_completion_function (const char *text, int state)
|
||||
{
|
||||
static const char **cmdlist = NULL;
|
||||
static size_t lind, nlen;
|
||||
const char *cmdname;
|
||||
|
||||
if (state == 0)
|
||||
{
|
||||
if (cmdlist)
|
||||
free (cmdlist);
|
||||
|
||||
cmdlist = rl_funmap_names ();
|
||||
lind = 0;
|
||||
nlen = RL_STRLEN (text);
|
||||
}
|
||||
if (cmdlist == 0 || cmdlist[lind] == 0)
|
||||
return (char *)NULL;
|
||||
|
||||
while (cmdlist[lind])
|
||||
{
|
||||
cmdname = cmdlist[lind++];
|
||||
if (STREQN (text, cmdname, nlen))
|
||||
return (savestring (cmdname));
|
||||
}
|
||||
return ((char *)NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
_rl_display_cmdname_matches (char **matches)
|
||||
{
|
||||
size_t len, max, i;
|
||||
int old;
|
||||
|
||||
old = rl_filename_completion_desired;
|
||||
rl_filename_completion_desired = 0;
|
||||
|
||||
/* There is more than one match. Find out how many there are,
|
||||
and find the maximum printed length of a single entry. */
|
||||
for (max = 0, i = 1; matches[i]; i++)
|
||||
{
|
||||
len = strlen (matches[i]);
|
||||
|
||||
if (len > max)
|
||||
max = len;
|
||||
}
|
||||
len = i - 1;
|
||||
|
||||
rl_display_match_list (matches, len, max);
|
||||
rl_filename_completion_desired = old;
|
||||
|
||||
rl_forced_update_display ();
|
||||
rl_display_fixed = 1;
|
||||
}
|
||||
|
||||
static int
|
||||
_rl_readcmd_complete (_rl_readstr_cxt *cxt, int c)
|
||||
{
|
||||
char **matches;
|
||||
char *prefix;
|
||||
size_t plen;
|
||||
|
||||
matches = rl_completion_matches (rl_line_buffer, readcmd_completion_function);
|
||||
|
||||
if (RL_SIG_RECEIVED())
|
||||
{
|
||||
_rl_free_match_list (matches);
|
||||
matches = 0;
|
||||
RL_CHECK_SIGNALS ();
|
||||
return -1;
|
||||
}
|
||||
else if (matches == 0)
|
||||
rl_ding ();
|
||||
|
||||
/* Whether or not there are multiple matches, we just want to append the
|
||||
new characters in matches[0]. We display possible matches if we didn't
|
||||
append anything. */
|
||||
if (matches)
|
||||
{
|
||||
prefix = matches[0];
|
||||
plen = strlen (prefix);
|
||||
|
||||
if (plen > rl_end)
|
||||
{
|
||||
size_t n;
|
||||
for (n = rl_end; n < plen && prefix[n]; n++)
|
||||
_rl_insert_char (1, prefix[n]);
|
||||
}
|
||||
else if (matches[1])
|
||||
_rl_display_cmdname_matches (matches);
|
||||
_rl_free_match_list (matches);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Use the readstr functions to read a bindable command name using the
|
||||
line buffer, with completion. */
|
||||
static char *
|
||||
_rl_read_command_name ()
|
||||
{
|
||||
_rl_readstr_cxt *cxt;
|
||||
char *ret;
|
||||
int c, r;
|
||||
|
||||
cxt = _rl_readstr_init ('!', READSTR_NOSPACE);
|
||||
cxt->compfunc = _rl_readcmd_complete;
|
||||
|
||||
/* skip callback stuff for now */
|
||||
r = 0;
|
||||
while (1)
|
||||
{
|
||||
c = _rl_readstr_getchar (cxt);
|
||||
|
||||
if (c < 0)
|
||||
{
|
||||
_rl_readstr_restore (cxt);
|
||||
_rl_readstr_cleanup (cxt, r);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (c == 0)
|
||||
break;
|
||||
|
||||
r = _rl_readstr_dispatch (cxt, c);
|
||||
if (r < 0)
|
||||
{
|
||||
_rl_readstr_cleanup (cxt, r);
|
||||
return NULL; /* dispatch function cleans up */
|
||||
}
|
||||
else if (r == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
ret = savestring (rl_line_buffer);
|
||||
|
||||
/* Now restore the original line and perform one final redisplay. */
|
||||
_rl_readstr_restore (cxt);
|
||||
(*rl_redisplay_function) ();
|
||||
|
||||
/* And free up the context. */
|
||||
_rl_readstr_cleanup (cxt, r);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Read a command name from the keyboard and execute it as if the bound key
|
||||
sequence had been entered. */
|
||||
int
|
||||
rl_execute_named_command (int count, int key)
|
||||
{
|
||||
char *command;
|
||||
rl_command_func_t *func;
|
||||
int r;
|
||||
|
||||
command = _rl_read_command_name ();
|
||||
if (command == 0 || *command == '\0')
|
||||
return 1;
|
||||
if (func = rl_named_function (command))
|
||||
{
|
||||
int prev, ostate;
|
||||
|
||||
prev = rl_dispatching;
|
||||
ostate = RL_ISSTATE (RL_STATE_DISPATCHING);
|
||||
rl_dispatching = 1;
|
||||
RL_SETSTATE (RL_STATE_DISPATCHING); /* make sure it's set */
|
||||
r = (*func) (count, key);
|
||||
if (ostate == 0)
|
||||
RL_UNSETSTATE (RL_STATE_DISPATCHING); /* unset it if it wasn't set */
|
||||
rl_dispatching = prev;
|
||||
}
|
||||
else
|
||||
{
|
||||
rl_ding ();
|
||||
r = 1;
|
||||
}
|
||||
|
||||
free (command);
|
||||
return r;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user