doc/bash.1,lib/readline/doc/rluser.texi
- shell-expand-line: enumerate the specific expansions performed.
From a request by Alex Bochannek <alex@bochannek.com>
+
+findcmd.c
+ - path_value: new function, returns normalized version of $PATH. Takes
+ a single argument saying whether or not to look in the temporary
+ environment first. Normalizes null $PATH (PATH=) into ".". From a
+ bug-bash discussion started by Moshe Looks <moshe.looks@gmail.com>
+ - _find_user_command_in_path: use path_value()
+ - user_command_matches: use path_value()
+ - search_for_command: if PATH[0] == 0, set PATH = "." like path_value().
+ This has the side effect of calling command_not_found_handle when
+ PATH is the empty string and the command isn't in the current
+ directory
+ - search_for_command: if path == 0, but we found an executable in the
+ current directory, make sure to set dot_found_in_search before adding
+ it to the command hash table
+
+findcmd.h
+ - path_value: extern declaration
+
+bashline.c
+ - command_word_completion_function: use path_value()
+
+builtins/enable.def
+ - dyn_load_builtin: use path_value for BASH_LOADABLES_PATH; it's cleaner
+ though it doesn't change the behavior
+
+ 3/17
+ ----
+bashline.c
+ - bashline_reset: reset rl_filename_quoting_function, since there is a
+ SIGINT code path where it could remain reset by glob completion.
+ Reported by Grisha Levit <grishalevit@gmail.com>
+ - command_word_completion_function,command_subst_completion_function,
+ glob_complete_word: set some static variables to NULL
+ after freeing them so they don't potentially get freed twice after
+ a SIGINT during completion
+ Reported by Grisha Levit <grishalevit@gmail.com>
+
+parse.y
+ - read_token_word: when deciding how to quote translated strings, don't
+ free ttok before comparing it to ttrans
+ Reported by Grisha Levit <grishalevit@gmail.com>
+ - parse_matched_pair: same thing for freeing nestret
+ - read_token: if we return a newline, make sure we call set_word_top()
+ if necessary.
+ Fixes underflow reported by Grisha Levit <grishalevit@gmail.com>
rl_filename_quote_characters = default_filename_quote_characters;
set_filename_bstab (rl_filename_quote_characters);
+ rl_filename_quoting_function = bash_quote_filename;
+
set_directory_hook ();
rl_filename_stat_hook = bash_filename_stat_hook;
/* This gets an unquoted filename, so we need to quote special characters
in the filename before the completion hook gets it. */
-#if 0
- f = savestring (filename);
-#else
c = 0;
f = bash_quote_filename ((char *)filename, SINGLE_MATCH, &c);
-#endif
bash_directory_completion_hook (&f);
r = searching_path ? executable_file (f) : executable_or_directory (f);
free (dequoted_hint);
if (hint)
free (hint);
+ dequoted_hint = hint = (char *)NULL;
mapping_over = searching_path = 0;
hint_is_dir = CMD_IS_DIR (hint_text);
if (rl_completion_found_quote && rl_completion_quote_character == 0)
dequoted_hint = bash_dequote_filename (hint, 0);
- path = get_string_value ("PATH");
+ path = path_value ("PATH", 0);
path_index = dot_in_path = 0;
/* Initialize the variables for each type of command word. */
free (fnhint);
if (filename_hint)
free (filename_hint);
+ fnhint = filename_hint = (char *)NULL;
filename_hint = sh_makepath (current_path, hint, 0);
/* Need a quoted version (though it doesn't matter much in most
t1 = make_absolute (val, t);
free (t);
cval = sh_canonpath (t1, PATH_CHECKDOTDOT|PATH_CHECKEXISTS);
+ free (t1);
}
else
#endif
start_len = text - orig_start;
filename_text = savestring (text);
if (matches)
- free (matches);
+ {
+ free (matches);
+ matches = (char **)NULL;
+ }
/*
* At this point we can entertain the idea of re-parsing
{
rl_filename_completion_desired = 1;
FREE (matches);
+ matches = (char **)NULL;
if (globorig != globtext)
FREE (globorig);
FREE (globtext);
+ globorig = globtext = (char *)NULL;
ttext = bash_tilde_expand (text, 0);
This file is cd.def, from which is created cd.c. It implements the
builtins "cd" and "pwd" in Bash.
-Copyright (C) 1987-2022 Free Software Foundation, Inc.
+Copyright (C) 1987-2023 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
else
free (temp);
}
-
-#if 0
- /* changed for bash-4.2 Posix cd description steps 5-6 */
- /* POSIX.2 says that if `.' does not appear in $CDPATH, we don't
- try the current directory, so we just punt now with an error
- message if POSIXLY_CORRECT is non-zero. The check for cdpath[0]
- is so we don't mistakenly treat a CDPATH value of "" as not
- specifying the current directory. */
- if (posixly_correct && cdpath[0])
- {
- builtin_error ("%s: %s", dirname, strerror (ENOENT));
- return (EXECUTION_FAILURE);
- }
-#endif
}
else
dirname = list->word->word;
handle = 0;
if (absolute_program (filename) == 0)
{
- loadables_path = get_string_value ("BASH_LOADABLES_PATH");
+ loadables_path = path_value ("BASH_LOADABLES_PATH", 1);
if (loadables_path)
{
load_path = find_in_path (filename, loadables_path, FS_NODIRS|FS_EXEC_PREFERRED);
/* Define as 1 if you want to enable code that implements multiple coprocs
executing simultaneously */
+/* TAG: bash-5.3 */
#ifndef MULTIPLE_COPROCS
# define MULTIPLE_COPROCS 0
#endif
return (find_user_command_internal (name, FS_READABLE));
}
+/* Get $PATH and normalize it. USE_TEMPENV, if non-zero, says to look in the
+ temporary environment first. Normalizing means converting PATH= into ".". */
+char *
+path_value (const char *pathvar, int use_tempenv)
+{
+ SHELL_VAR *var;
+ char *path;
+
+ var = use_tempenv ? find_variable_tempenv (pathvar) : find_variable (pathvar);
+ path = var ? value_cell (var) : (char *)NULL;
+
+ if (path == 0 || *path)
+ return (path);
+ else /* *path == '\0' */
+ return ".";
+}
+
static char *
_find_user_command_internal (const char *name, int flags)
{
/* Search for the value of PATH in both the temporary environments and
in the regular list of variables. */
- if (var = find_variable_tempenv ("PATH")) /* XXX could be array? */
- path_list = value_cell (var);
- else
- path_list = (char *)NULL;
+ path_list = path_value ("PATH", 1);
- if (path_list == 0 || *path_list == '\0')
+ if (path_list == 0)
return (savestring (name));
cmd = find_user_command_in_path (name, path_list, flags, (int *)0);
if (flags & CMDSRCH_STDPATH)
path_list = conf_standard_path ();
else if (temp_path || path)
- path_list = value_cell (path);
+ {
+ path_list = value_cell (path);
+ if (path_list && *path_list == '\0')
+ path_list = ".";
+ }
else
path_list = 0;
table unless it's an executable file in the current directory. */
if (STREQ (command, pathname))
{
+ if (path_list == 0)
+ {
+ dot_found_in_search = 1;
+ st = file_status (pathname);
+ }
if (st & FS_EXECABLE)
phash_insert ((char *)pathname, command, dot_found_in_search, 1);
}
dot_found_in_search = 0;
if (stat (".", &dotinfo) < 0)
dotinfo.st_dev = dotinfo.st_ino = 0; /* so same_file won't match */
- path_list = get_string_value ("PATH");
- path_index = 0;
+ path_list = path_value ("PATH", 0);
+ path_index = 0;
}
while (path_list && path_list[path_index])
/* This does the dirty work for find_user_command_internal () and
user_command_matches ().
NAME is the name of the file to search for.
- PATH_LIST is a colon separated list of directories to search.
+ PATH_LIST is a colon separated list of directories to search. It is the
+ caller's responsibility to pass a non-empty path if they want an empty
+ path to be treated specially.
FLAGS contains bit fields which control the files which are eligible.
Some values are:
FS_EXEC_ONLY: The file must be an executable to be found.
extern char *find_user_command (const char *);
extern char *find_in_path (const char *, char *, int);
extern char *find_path_file (const char *);
+extern char *path_value (const char *, int);
extern char *search_for_command (const char *, int);
extern char *user_command_matches (const char *, int, int);
extern void setup_exec_ignore (const char *);
parser_state &= ~PST_ASSIGNOK;
parser_state &= ~PST_CMDBLTIN;
+ if (last_read_token == IF || last_read_token == WHILE || last_read_token == UNTIL)
+ set_word_top (last_read_token);
+
return (character);
}
/* Locale expand $"..." here. */
/* PST_NOEXPAND */
ttrans = locale_expand (nestret, 0, nestlen - 1, start_lineno, &ttranslen);
- free (nestret);
/* If we're supposed to single-quote translated strings,
check whether the translated result is different from
if (singlequote_translations &&
((nestlen - 1) != ttranslen || STREQN (nestret, ttrans, ttranslen) == 0))
{
+ free (nestret);
if ((rflags & P_DQUOTE) == 0)
nestret = sh_single_quote (ttrans);
else if ((rflags & P_DQUOTE) && (dolbrace_state == DOLBRACE_QUOTE2) && (flags & P_DOLBRACE))
nestret = sh_backslash_quote_for_double_quotes (ttrans, 0);
}
else
- nestret = sh_mkdoublequoted (ttrans, ttranslen, 0);
+ {
+ free (nestret);
+ nestret = sh_mkdoublequoted (ttrans, ttranslen, 0);
+ }
free (ttrans);
nestlen = strlen (nestret);
retind -= 2; /* back up before the $" */
/* PST_NOEXPAND */
/* Try to locale-expand the converted string. */
ttrans = locale_expand (ttok, 0, ttoklen - 1, first_line, &ttranslen);
- free (ttok);
/* Add the double quotes back (or single quotes if the user
has set that option). */
if (singlequote_translations &&
((ttoklen - 1) != ttranslen || STREQN (ttok, ttrans, ttranslen) == 0))
- ttok = sh_single_quote (ttrans);
+ {
+ free (ttok);
+ ttok = sh_single_quote (ttrans);
+ }
else
- ttok = sh_mkdoublequoted (ttrans, ttranslen, 0);
+ {
+ free (ttok);
+ ttok = sh_mkdoublequoted (ttrans, ttranslen, 0);
+ }
free (ttrans);
ttrans = ttok;
trap -- 'echo USR1' SIGUSR1
USR1
EXIT
-./execscript: line 71: notthere: No such file or directory
+./execscript: line 71: notthere: command not found
127
-./execscript: line 74: notthere: No such file or directory
+./execscript: line 73: notthere: command not found
127
-./execscript: line 77: notthere: command not found
+./execscript: line 75: notthere: command not found
+127
+./execscript: line 81: notthere: command not found
+127
+./execscript: line 83: notthere: command not found
+127
+./execscript: line 85: notthere: command not found
127
this is sh
this is sh
rm -f $TMPDIR/bashenv
unset BASH_ENV
+# these results should be the same as with an empty PATH
+PATH=.
+
+notthere
+echo $?
+command notthere
+echo $?
+command -p notthere
+echo $?
+
# we're resetting the $PATH to empty, so this should be last
PATH=
notthere
echo $?
-
command notthere
echo $?
-
command -p notthere
echo $?