allows a trap action to see the same exit status that the read
builtin would return when it exits on a signal (e.g., SIGINT == 130).
From a suggestion by <gentoo_eshoes@tutanota.com>
+
+ 4/20
+ ----
+hashlib.c
+ - hash_rehash: function to rehash a table, after increasing or decreasing
+ the number of buckets. From patches from Thomas Kremer
+ (https://savannah.gnu.org/patch/?9850) and Koichi Murase
+ <myoga.murase@gmail.com>
+ - hash_grow,hash_shrink: grow or shrink a hash table by a factor of
+ HASH_REHASH_MULTIPLIER (4)
+ - hash_insert,hash_search: call hash_grow if necessary
+
+arrayfunc.c
+ - convert_var_to_{array,assoc}: if the original variable had no value
+ (it was unset), the array variable should be unset as well. Reported
+ by andrej@podzimek.org
+
+ 4/21
+ ----
+bashline.c
+ - set_saved_history: change logic used to decide where in the history
+ operate_and_get_next should start by using a logical offset into the
+ history list that is an offset from history_base. This avoids having
+ to take whether or not the history is stifled and full into account.
+ Report and fix from Greg Price <gnprice@gmail.com>
+ - operate_and_get_next: just calculate the logical offset of where we
+ should be in the history instead of an absolute offset
+
+lib/readline/input.c
+ - _rl_nchars_available: new function, returns the number of characters
+ available to be read if FIONREAD is available
+
+ 4/22
+ ----
+lib/readline/{readline.c,rlprivate.h}
+ - _rl_pending_command: new struct to hold information about a pending
+ command for readline to execute when the current command completes.
+ A command can set this up so that it gets executed like a
+ continuation before redisplay
+
+lib/readline/readline.c
+ - readline_internal_charloop: after _rl_dispatch returns, check
+ _rl_command_to_execute, and, if it's non-zero, redisplay and then
+ execute it as a command
+ - added a small set of library-private functions for managing the
+ executing key sequence (not used yet)
+
+lib/readline/isearch.c
+ - _rl_isearch_dispatch: if we have found an opcode or have added a
+ character to the search string and searched for it, reset the keymap
+ and okeymap members of the search context in preparation for reading
+ another key sequence/opcode
+ - _rl_isearch_dispatch: if we read a key sequence bound to an editing
+ command that is not an `opcode', set up _rl_command_to_execute to
+ execute it after the searching returns and arrange to break out of
+ the search
+ - _rl_isearch_dispatch: if we paste in text from bracketed paste, set
+ the mark as active so we can highlight it when we display the search
+ string
+ - _rl_isearch_dispatch: if we've found the search string, activate the
+ mark and set rl_point and rl_mark so the search string is highlighted
+ when we display the search results
+ - _rl_isearch_dispatch: do translation for keys that map to
+ rl_do_lowercase_version like we do when dispatching while reading a
+ key sequence
tests/history1.sub f
tests/history2.sub f
tests/history3.sub f
+tests/history4.sub f
tests/ifs.tests f
tests/ifs.right f
tests/ifs1.sub f
array_needs_making++;
VSETATTR (var, att_array);
- VUNSETATTR (var, att_invisible);
+ if (oldval)
+ VUNSETATTR (var, att_invisible);
/* Make sure it's not marked as an associative array any more */
VUNSETATTR (var, att_assoc);
array_needs_making++;
VSETATTR (var, att_assoc);
- VUNSETATTR (var, att_invisible);
+ if (oldval)
+ VUNSETATTR (var, att_invisible);
/* Make sure it's not marked as an indexed array any more */
VUNSETATTR (var, att_array);
/* The equivalent of the Korn shell C-o operate-and-get-next-history-line
editing command. */
-static int saved_history_line_to_use = -1;
-static int last_saved_history_line = -1;
+static int saved_history_logical_offset = -1;
#define HISTORY_FULL() (history_is_stifled () && history_length >= history_max_entries)
static int
set_saved_history ()
{
- /* XXX - compensate for assumption that history was `shuffled' if it was
- actually not. */
- if (HISTORY_FULL () &&
- hist_last_line_added == 0 &&
- saved_history_line_to_use < history_length - 1)
- saved_history_line_to_use++;
-
- if (saved_history_line_to_use >= 0)
+ int absolute_offset, count;
+
+ if (saved_history_logical_offset >= 0)
{
- rl_get_previous_history (history_length - saved_history_line_to_use, 0);
- last_saved_history_line = saved_history_line_to_use;
+ absolute_offset = saved_history_logical_offset - history_base;
+ count = where_history () - absolute_offset;
+ rl_get_previous_history (count, 0);
}
- saved_history_line_to_use = -1;
+ saved_history_logical_offset = -1;
rl_startup_hook = old_rl_startup_hook;
return (0);
}
operate_and_get_next (count, c)
int count, c;
{
- int where;
-
/* Accept the current line. */
rl_newline (1, c);
- /* Find the current line, and find the next line to use. */
- where = rl_explicit_arg ? count : where_history ();
-
- if (HISTORY_FULL () || (where >= history_length - 1) || rl_explicit_arg)
- saved_history_line_to_use = where;
- else
- saved_history_line_to_use = where + 1;
+ saved_history_logical_offset = rl_explicit_arg ? count : where_history () + history_base + 1;
old_rl_startup_hook = rl_startup_hook;
rl_startup_hook = set_saved_history;
Substring indexing is zero-based unless the positional parameters
are used, in which case the indexing starts at 1 by default.
-If @var{offset} is 0, and the positional parameters are used, @code{$@@} is
+If @var{offset} is 0, and the positional parameters are used, @code{$0} is
prefixed to the list.
@item $@{!@var{prefix}*@}
-/* lcut - extract specified fields from a line and assign them to an array or
- print them to the standard output */
+/* cut,lcut - extract specified fields from a line and assign them to an array
+ or print them to the standard output */
/*
Copyright (C) 2020 Free Software Foundation, Inc.
return (cut_internal (1, list));
}
-/* Called when builtin is enabled and loaded from the shared object. If this
- function returns 0, the load fails. */
-int
-lcut_builtin_load (name)
- char *name;
-{
- return (1);
-}
-
-/* Called when builtin is disabled. */
-void
-lcut_builtin_unload (name)
- char *name;
-{
-}
-
char *lcut_doc[] = {
"Extract selected fields from a string.",
"",
*/
/*
- Copyright (C) 1999-2009 Free Software Foundation, Inc.
+ Copyright (C) 1999-2020 Free Software Foundation, Inc.
This file is part of GNU Bash.
Bash is free software: you can redistribute it and/or modify
else
{
stop_pipeline (0, (COMMAND *)NULL);
- xstatus = wait_for (pid);
+ xstatus = wait_for (pid, 0);
return (xstatus);
}
}
#include "shell.h"
#include "hashlib.h"
+/* tunable constants for rehashing */
+#define HASH_REHASH_MULTIPLIER 4
+#define HASH_REHASH_FACTOR 2
+
+#define HASH_SHOULDGROW(table) \
+ ((table)->nentries >= (table)->nbuckets * HASH_REHASH_FACTOR)
+
+/* an initial approximation */
+#define HASH_SHOULDSHRINK(table) \
+ (((table)->nbuckets > DEFAULT_HASH_BUCKETS) && \
+ ((table)->nentries < (table)->nbuckets / HASH_REHASH_MULTIPLIER))
+
/* Rely on properties of unsigned division (unsigned/int -> unsigned) and
don't discard the upper 32 bits of the value, if present. */
#define HASH_BUCKET(s, t, h) (((h) = hash_string (s)) & ((t)->nbuckets - 1))
-static BUCKET_CONTENTS *copy_bucket_array __P((BUCKET_CONTENTS *, sh_string_func_t *));
+static BUCKET_CONTENTS *copy_bucket_array PARAMS((BUCKET_CONTENTS *, sh_string_func_t *));
+
+static void hash_rehash PARAMS((HASH_TABLE *, int));
+static void hash_grow PARAMS((HASH_TABLE *));
+static void hash_shrink PARAMS((HASH_TABLE *));
/* Make a new hash table with BUCKETS number of buckets. Initialize
each slot in the table to NULL. */
return new_bucket;
}
+static void
+hash_rehash (table, nsize)
+ HASH_TABLE *table;
+ int nsize;
+{
+ int osize, i, j;
+ BUCKET_CONTENTS **old_bucket_array, *item, *next;
+
+ if (table == NULL || nsize == table->nbuckets)
+ return;
+
+ osize = table->nbuckets;
+ old_bucket_array = table->bucket_array;
+
+ table->nbuckets = nsize;
+ table->bucket_array = (BUCKET_CONTENTS **)xmalloc (table->nbuckets * sizeof (BUCKET_CONTENTS *));
+ for (i = 0; i < table->nbuckets; i++)
+ table->bucket_array[i] = (BUCKET_CONTENTS *)NULL;
+
+ for (j = 0; j < osize; j++)
+ {
+ for (item = old_bucket_array[j]; item; item = next)
+ {
+ next = item->next;
+ i = item->khash & (table->nbuckets - 1);
+ item->next = table->bucket_array[i];
+ table->bucket_array[i] = item;
+ }
+ }
+
+ free (old_bucket_array);
+}
+
+static void
+hash_grow (table)
+ HASH_TABLE *table;
+{
+ int nsize;
+
+ nsize = table->nbuckets * HASH_REHASH_MULTIPLIER;
+ if (nsize > 0) /* overflow */
+ hash_rehash (table, nsize);
+}
+
+static void
+hash_shrink (table)
+ HASH_TABLE *table;
+{
+ int nsize;
+
+ nsize = table->nbuckets / HASH_REHASH_MULTIPLIER;
+ hash_rehash (table, nsize);
+}
+
HASH_TABLE *
hash_copy (table, cpdata)
HASH_TABLE *table;
/* If you want to use 64 bits, use
FNV_OFFSET 14695981039346656037
-FNV_PRIMT 1099511628211
+FNV_PRIME 1099511628211
*/
/* The `khash' check below requires that strings that compare equally with
if (flags & HASH_CREATE)
{
+ if (HASH_SHOULDGROW (table))
+ {
+ hash_grow (table);
+ bucket = HASH_BUCKET (string, table, hv);
+ }
+
list = (BUCKET_CONTENTS *)xmalloc (sizeof (BUCKET_CONTENTS));
list->next = table->bucket_array[bucket];
table->bucket_array[bucket] = list;
if (item == 0)
{
+ if (HASH_SHOULDGROW (table))
+ hash_grow (table);
+
bucket = HASH_BUCKET (string, table, hv);
item = (BUCKET_CONTENTS *)xmalloc (sizeof (BUCKET_CONTENTS));
/* hashlib.h -- the data structures used in hashing in Bash. */
-/* Copyright (C) 1993-2009 Free Software Foundation, Inc.
+/* Copyright (C) 1993-2020 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
int nentries; /* How many entries does this table have. */
} HASH_TABLE;
-typedef int hash_wfunc __P((BUCKET_CONTENTS *));
+typedef int hash_wfunc PARAMS((BUCKET_CONTENTS *));
/* Operations on tables as a whole */
-extern HASH_TABLE *hash_create __P((int));
-extern HASH_TABLE *hash_copy __P((HASH_TABLE *, sh_string_func_t *));
-extern void hash_flush __P((HASH_TABLE *, sh_free_func_t *));
-extern void hash_dispose __P((HASH_TABLE *));
-extern void hash_walk __P((HASH_TABLE *, hash_wfunc *));
+extern HASH_TABLE *hash_create PARAMS((int));
+extern HASH_TABLE *hash_copy PARAMS((HASH_TABLE *, sh_string_func_t *));
+extern void hash_flush PARAMS((HASH_TABLE *, sh_free_func_t *));
+extern void hash_dispose PARAMS((HASH_TABLE *));
+extern void hash_walk PARAMS((HASH_TABLE *, hash_wfunc *));
/* Operations to extract information from or pieces of tables */
-extern int hash_bucket __P((const char *, HASH_TABLE *));
-extern int hash_size __P((HASH_TABLE *));
+extern int hash_bucket PARAMS((const char *, HASH_TABLE *));
+extern int hash_size PARAMS((HASH_TABLE *));
/* Operations on hash table entries */
-extern BUCKET_CONTENTS *hash_search __P((const char *, HASH_TABLE *, int));
-extern BUCKET_CONTENTS *hash_insert __P((char *, HASH_TABLE *, int));
-extern BUCKET_CONTENTS *hash_remove __P((const char *, HASH_TABLE *, int));
+extern BUCKET_CONTENTS *hash_search PARAMS((const char *, HASH_TABLE *, int));
+extern BUCKET_CONTENTS *hash_insert PARAMS((char *, HASH_TABLE *, int));
+extern BUCKET_CONTENTS *hash_remove PARAMS((const char *, HASH_TABLE *, int));
/* Miscellaneous */
-extern unsigned int hash_string __P((const char *));
+extern unsigned int hash_string PARAMS((const char *));
/* Redefine the function as a macro for speed. */
#define hash_items(bucket, table) \
FD_ZERO (&exceptfds);
FD_SET (tty, &readfds);
FD_SET (tty, &exceptfds);
- timeout.tv_sec = 0;
- timeout.tv_usec = _keyboard_input_timeout;
+ USEC_TO_TIMEVAL (_keyboard_input_timeout, timeout);
return (select (tty + 1, &readfds, (fd_set *)NULL, &exceptfds, &timeout) > 0);
#else
return 0;
}
+int
+_rl_nchars_available ()
+{
+ int chars_avail, fd, result;
+
+ chars_avail = 0;
+
+#if defined (FIONREAD)
+ fd = fileno (rl_instream);
+ errno = 0;
+ result = ioctl (fd, FIONREAD, &chars_avail);
+ if (result == -1 && errno == EIO)
+ return -1;
+#endif
+
+ return chars_avail;
+}
+
int
_rl_input_queued (int t)
{
/* */
/* **************************************************************** */
-/* Copyright (C) 1987-2017 Free Software Foundation, Inc.
+/* Copyright (C) 1987-2020 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.
_rl_iscxt = cxt; /* save globally */
+ /* experimental right now */
+ _rl_init_executing_keyseq ();
+
return cxt;
}
else
cxt->sline_index = strlen (rl_line_buffer);
rl_mark = cxt->save_mark;
+ rl_deactivate_mark ();
}
rl_point = cxt->sline_index;
/* Don't worry about where to put the mark here; rl_get_previous_history
- and rl_get_next_history take care of it. */
+ and rl_get_next_history take care of it.
+ If we want to highlight the search string, this is where to set the
+ point and mark to do it. */
_rl_fix_point (0);
+ rl_deactivate_mark ();
/* _rl_optimize_redisplay (); */
rl_clear_message ();
return -1;
}
+ _rl_add_executing_keyseq (c);
+
/* If we are moving into a new keymap, modify cxt->keymap and go on.
This can be a problem if c == ESC and we want to terminate the
incremental search, so we check */
if (cxt->mb[1])
f = rl_function_of_keyseq (cxt->mb, cxt->keymap, (int *)NULL);
else
- f = cxt->keymap[c].function;
+ {
+ f = cxt->keymap[c].function;
+ if (f == rl_do_lowercase_version)
+ f = cxt->keymap[_rl_to_lower (c)].function;
+ }
if (f == rl_reverse_search_history)
cxt->lastc = (cxt->sflags & SF_REVERSE) ? -1 : -2;
}
else if (cxt->lastc > 0 && cxt->prevc > 0 && f && f != rl_insert)
{
- rl_stuff_char (cxt->lastc);
- rl_execute_next (cxt->prevc);
- /* XXX - do we insert everything in cxt->pmb? */
+ _rl_term_executing_keyseq (); /* should this go in the caller? */
+
+ _rl_pending_command.map = cxt->keymap;
+ _rl_pending_command.count = 1; /* XXX */
+ _rl_pending_command.key = cxt->lastc;
+ _rl_pending_command.func = f;
+ _rl_command_to_execute = &_rl_pending_command;
+
return (0);
}
}
return (0);
}
+ _rl_init_executing_keyseq ();
+
/* Now dispatch on the character. `Opcodes' affect the search string or
state. Other characters are added to the string. */
switch (cxt->lastc)
rl_display_search (cxt->search_string, cxt->sflags, -1);
break;
}
+ /* XXX - restore keymap here? */
return (1);
}
else if ((cxt->sflags & SF_REVERSE) && cxt->sline_index >= 0)
rl_replace_line (cxt->lines[cxt->save_line], 0);
rl_point = cxt->save_point;
rl_mark = cxt->save_mark;
+ rl_deactivate_mark ();
rl_restore_prompt();
rl_clear_message ();
free (paste);
break;
}
+ rl_activate_mark ();
if (cxt->search_string_index + pastelen + 1 >= cxt->search_string_size)
{
cxt->search_string_size += pastelen + 2;
cxt->sline_index = (cxt->sflags & SF_REVERSE) ? cxt->sline_len - cxt->search_string_index : 0;
}
+ /* reset the keymaps for the next time through the loop */
+ cxt->keymap = cxt->okeymap = _rl_keymap;
+
if (cxt->sflags & SF_FAILED)
{
/* We cannot find the search string. Ding the bell. */
rl_ding ();
cxt->history_pos = cxt->last_found_line;
+ rl_deactivate_mark ();
rl_display_search (cxt->search_string, cxt->sflags, (cxt->history_pos == cxt->save_line) ? -1 : cxt->history_pos);
return 1;
}
{
cxt->prev_line_found = cxt->lines[cxt->history_pos];
rl_replace_line (cxt->lines[cxt->history_pos], 0);
+ rl_activate_mark ();
rl_point = cxt->sline_index;
+ if (rl_mark_active_p () && cxt->search_string_index > 0)
+ rl_mark = rl_point + cxt->search_string_index;
cxt->last_found_line = cxt->history_pos;
rl_display_search (cxt->search_string, cxt->sflags, (cxt->history_pos == cxt->save_line) ? -1 : cxt->history_pos);
}
#include "xmalloc.h"
#ifndef RL_LIBRARY_VERSION
-# define RL_LIBRARY_VERSION "5.1"
+# define RL_LIBRARY_VERSION "8.0"
#endif
#ifndef RL_READLINE_VERSION
-# define RL_READLINE_VERSION 0x0501
+# define RL_READLINE_VERSION 0x0800
#endif
extern void _rl_free_history_entry PARAMS((HIST_ENTRY *));
char *rl_executing_keyseq = 0;
int _rl_executing_keyseq_size = 0;
+struct _rl_cmd _rl_pending_command;
+struct _rl_cmd *_rl_command_to_execute = (struct _rl_cmd *)NULL;
+
/* Timeout (specified in milliseconds) when reading characters making up an
ambiguous multiple-key sequence */
int _rl_keyseq_timeout = 500;
r = _rl_dispatch ((unsigned char)c, _rl_keymap);
RL_CHECK_SIGNALS ();
+ if (_rl_command_to_execute)
+ {
+ (*rl_redisplay_function) ();
+
+ rl_executing_keymap = _rl_command_to_execute->map;
+ rl_executing_key = _rl_command_to_execute->key;
+
+ rl_dispatching = 1;
+ RL_SETSTATE(RL_STATE_DISPATCHING);
+ r = (*(_rl_command_to_execute->func)) (_rl_command_to_execute->count, _rl_command_to_execute->key);
+ _rl_command_to_execute = 0;
+ RL_UNSETSTATE(RL_STATE_DISPATCHING);
+ rl_dispatching = 0;
+
+ RL_CHECK_SIGNALS ();
+ }
+
/* If there was no change in _rl_last_command_was_kill, then no kill
has taken place. Note that if input is pending we are reading
a prefix command, so nothing has changed yet. */
rl_executing_keyseq = malloc (_rl_executing_keyseq_size = 16);
if (rl_executing_keyseq)
- rl_executing_keyseq[0] = '\0';
+ rl_executing_keyseq[rl_key_sequence_length = 0] = '\0';
}
/* If this system allows us to look at the values of the regular
return (0);
}
+
+/* Functions to manage the string that is the current key sequence. */
+
+void
+_rl_init_executing_keyseq (void)
+{
+ rl_executing_keyseq[rl_key_sequence_length = 0] = '\0';
+}
+
+void
+_rl_term_executing_keyseq (void)
+{
+ rl_executing_keyseq[rl_key_sequence_length] = '\0';
+}
+
+void
+_rl_end_executing_keyseq (void)
+{
+ if (rl_key_sequence_length > 0)
+ rl_executing_keyseq[--rl_key_sequence_length] = '\0';
+}
+
+void
+_rl_add_executing_keyseq (int key)
+{
+ RESIZE_KEYSEQ_BUFFER ();
+ rl_executing_keyseq[rl_key_sequence_length++] = key;
+}
/* Readline.h -- the names of functions callable from within readline. */
-/* Copyright (C) 1987-2016 Free Software Foundation, Inc.
+/* Copyright (C) 1987-2020 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.
char *search_terminators;
} _rl_search_cxt;
+struct _rl_cmd {
+ Keymap map;
+ int count;
+ int key;
+ rl_command_func_t *func;
+};
+extern struct _rl_cmd _rl_pending_command;
+extern struct _rl_cmd *_rl_command_to_execute;
+
/* Callback data for reading numeric arguments */
#define NUM_SAWMINUS 0x01
#define NUM_SAWDIGITS 0x02
/* input.c */
extern int _rl_any_typein PARAMS((void));
extern int _rl_input_available PARAMS((void));
+extern int _rl_nchars_available PARAMS((void));
extern int _rl_input_queued PARAMS((int));
extern void _rl_insert_typein PARAMS((int));
extern int _rl_unget_char PARAMS((int));
extern int _rl_dispatch_subseq PARAMS((int, Keymap, int));
extern void _rl_internal_char_cleanup PARAMS((void));
+extern void _rl_init_executing_keyseq PARAMS((void));
+extern void _rl_term_executing_keyseq PARAMS((void));
+extern void _rl_end_executing_keyseq PARAMS((void));
+extern void _rl_add_executing_keyseq PARAMS((int));
+
/* rltty.c */
extern int _rl_disable_tty_signals PARAMS((void));
extern int _rl_restore_tty_signals PARAMS((void));
4 echo g
5 echo h
+
+0
+1
+2
+(left
+mid
+right)
+A
+B
+
+(left
+mid
+right)
+A
+B
+
+(left
+mid
+right)
+A
+B
+
+0
+1
+2
+(left
+mid
+right)
+A
+B
+(left
+mid
+right)
+A
+B
+
+0
+1
+2
+(left
+mid
+right)
+A
+B
+(left
+mid
+right)
+A
+B
${THIS_SH} ./history2.sub
${THIS_SH} ./history3.sub
+${THIS_SH} ./history4.sub
--- /dev/null
+# This program 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.
+#
+# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+#
+HISTFILE=$TMPDIR/newhistory-$$
+export HISTFILE
+
+HISTSIZE=32
+HISTFILESIZE=32
+echo
+set -o history
+history -c
+echo 0
+echo 1
+echo 2
+echo "(left
+mid
+right)"
+echo A
+echo B
+history -w
+set +o history
+
+echo
+printf $'HISTFILE=\n\cRleft\cO\cO\cO\cO\n' | HISTSIZE= ${THIS_SH} --norc -i 2>/dev/null
+echo
+printf $'HISTFILE=\n\cRleft\cO\cO\cO\cO\n' | HISTSIZE=8 ${THIS_SH} --norc -i 2>/dev/null
+
+input="$(cat $HISTFILE)
+"$'\cP\cP\cP\cO\cO
+'
+
+echo
+printf "$input" | HISTSIZE= HISTFILE= ${THIS_SH} --norc -i 2>/dev/null
+echo
+printf "$input" | HISTSIZE=6 HISTFILE= ${THIS_SH} --norc -i 2>/dev/null
+