Bash-5.3-alpha release

This commit is contained in:
Chet Ramey
2024-04-22 10:33:38 -04:00
parent f3b6bd1945
commit 622d318652
700 changed files with 136534 additions and 96420 deletions
+510 -18
View File
@@ -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;
}