- mark_dead_jobs_as_notified: call set_maxchild to set js.c_childmax
if it hasn't been set yet
-
+ 9/30
+ ----
+lib/glob/xmbsrtowcs.c
+ - xwcsrtombs: implementation of wcsrtombs from gnulib, modified to
+ treat invalid wide characters (or wide characters that can't be
+ converted to multibyte character sequences) as bytes. Should be
+ used only in unusual circumstances where wcsrtombs fails.
+
+lib/glob/glob.c
+ - wdequote_pathname: if wcsrtombs fails to convert the dequoted wide
+ character pathname back to a sequence of multibyte characters, call
+ xwcsrtombs to try to treat the invalid wide characters as bytes --
+ the call to xdupmbstowcs treats bytes that don't convert to wide
+ characters as just bytes, which kind of causes this problem in the
+ first place. Inspired by report from Geoff Kuenning <geoff@cs.hmc.edu>
+
+lib/readline/complete.c
+ - compute_lcd_of_matches: use the case-folding code (which performs
+ character-by-character checking and compares invalid multibyte
+ sequences as bytes) instead of the old case-sensitive code (which
+ used _rl_compare_chars), converting characters to lowercase as
+ needed. Fixes bug with invalid sequences in common filename prefixes
+ reported by Grisha Levit <grishalevit@gmail.com>
+
+ 10/1
+ ----
+builtins/shopt.def
+ - reset_shopt_options: add in resets for some missing shopt options.
+ Report and fix from Grisha Levit <grishalevit@gmail.com>
+
+execute_cmd.c
+ - execute_command_internal: make sure a failed attempt to define a
+ shell function causes the shell to exit if -e is enabled. Report
+ from Andreas Kusalananda Kähäri <andreas.kahari@abc.se>
+ - execute_command_internal: combine cm_function_def, cm_arith, and
+ cm_cond cases into one switch case, since the code is virtually
+ identical across all three
+
+ 10/3
+ ----
+pathexp.[ch],lib/glob/glob.c,lib/glob/glob_loop.c
+ - remove all references to posix_glob_backslash in preparation for
+ implementing austin group interpretation #1234
+
+pathexp.c
+ - unquoted_glob_pattern_p: revert to bash-4.4 behavior of returning 1
+ only if there is an unquoted `*', `?', or bracket expression, as
+ per austin group interpretation #1234
+
+lib/glob/glob_loop.c
+ - INTERNAL_GLOB_PATTERN_P: revert to bash-4.4 behavior of returning 1
+ only if there is an unquoted `*', `?', or bracket expression, as
+ per austin group interpretation #1234
+
+ 10/4
+ ----
+variables.c
+ - assign_seconds,get_seconds: use the tv_sec value returned from
+ gettimeofday() instead of time() to get a better approximation of
+ the number of seconds since the epoch for future calculations.
+ From a report by Stephane Chazelas <stephane.chazelas@gmail.com>
+
+pathexp.[ch],{bashline,subst}.c
+ - shell_glob_filename: now takes an additional flags argument to pass
+ to quote_string_for_globbing
+
+ 10/6
+ ----
+subst.c
+ - glob_expand_word_list: call shell_glob_filename with QGLOB_CTLESC
+ because quote removal hasn't been performed yet
tests/set-x.tests f
tests/set-x1.sub f
tests/set-x.right f
-tests/shopt.tests f
+tests/shopt.tests f
+tests/shopt1.sub f
tests/shopt.right f
tests/strip.tests f
tests/strip.right f
if (state == 0)
{
glob_ignore_case = igncase;
- glob_matches = shell_glob_filename (hint);
+ glob_matches = shell_glob_filename (hint, 0);
glob_ignore_case = old_glob_ignore_case;
if (GLOB_FAILED (glob_matches) || glob_matches == 0)
if (ttext != text)
free (ttext);
- matches = shell_glob_filename (globtext);
+ matches = shell_glob_filename (globtext, 0);
if (GLOB_FAILED (matches))
matches = (char **)NULL;
ind = 0;
inherit_errexit = 0;
interactive_comments = 1;
lastpipe_opt = 0;
+ localvar_inherit = localvar_unset = 0;
mail_warning = 0;
glob_ignore_case = match_ignore_case = 0;
print_shift_error = 0;
extended_glob = EXTGLOB_DEFAULT;
#endif
+#if defined (ARRAY_VARS)
+ assoc_expand_once = 0;
+#endif
+
#if defined (HISTORY)
literal_history = 0;
force_append_history = 0;
#if defined (PROGRAMMABLE_COMPLETION)
prog_completion_enabled = 1;
+# if defined (ALIAS)
+ progcomp_alias = 0;
+# endif
#endif
#if defined (DEFAULT_ECHO_TO_XPG) || defined (STRICT_POSIX)
#if defined (DPAREN_ARITHMETIC)
case cm_arith:
- was_error_trap = signal_is_trapped (ERROR_TRAP) && signal_is_ignored (ERROR_TRAP) == 0;
- if (ignore_return)
- command->value.Arith->flags |= CMD_IGNORE_RETURN;
- line_number_for_err_trap = save_line_number = line_number;
- exec_result = execute_arith_command (command->value.Arith);
- line_number = save_line_number;
-
- if (was_error_trap && ignore_return == 0 && invert == 0 && exec_result != EXECUTION_SUCCESS)
- {
- last_command_exit_value = exec_result;
- save_line_number = line_number;
- line_number = line_number_for_err_trap;
- run_error_trap ();
- line_number = save_line_number;
- }
-
- if (ignore_return == 0 && invert == 0 && exit_immediately_on_error && exec_result != EXECUTION_SUCCESS)
- {
- last_command_exit_value = exec_result;
- run_pending_traps ();
- jump_to_top_level (ERREXIT);
- }
-
- break;
#endif
-
#if defined (COND_COMMAND)
case cm_cond:
+#endif
+ case cm_function_def:
was_error_trap = signal_is_trapped (ERROR_TRAP) && signal_is_ignored (ERROR_TRAP) == 0;
- if (ignore_return)
+#if defined (DPAREN_ARITHMETIC)
+ if (ignore_return && command->type == cm_arith)
+ command->value.Arith->flags |= CMD_IGNORE_RETURN;
+#endif
+#if defined (COND_COMMAND)
+ if (ignore_return && command->type == cm_cond)
command->value.Cond->flags |= CMD_IGNORE_RETURN;
+#endif
line_number_for_err_trap = save_line_number = line_number;
- exec_result = execute_cond_command (command->value.Cond);
+#if defined (DPAREN_ARITHMETIC)
+ if (command->type == cm_arith)
+ exec_result = execute_arith_command (command->value.Arith);
+ else
+#endif
+#if defined (COND_COMMAND)
+ if (command->type == cm_cond)
+ exec_result = execute_cond_command (command->value.Cond);
+ else
+#endif
+ if (command->type == cm_function_def)
+ exec_result = execute_intern_function (command->value.Function_def->name,
+ command->value.Function_def);
line_number = save_line_number;
if (was_error_trap && ignore_return == 0 && invert == 0 && exec_result != EXECUTION_SUCCESS)
}
break;
-#endif
-
- case cm_function_def:
- exec_result = execute_intern_function (command->value.Function_def->name,
- command->value.Function_def);
- break;
default:
command_error ("execute_command", CMDERR_BADTYPE, command->type, 0);
#endif /* SH_FUNCTION_TYPEDEF */
#define NOW ((time_t) time ((time_t *) 0))
+#define GETTIME(tv) gettimeofday(&(tv), NULL)
/* Some defines for calling file status functions. */
#define FS_EXISTS 0x1
int fail;
WAIT ret;
-#if 0
- if (pipefail_opt)
-#else
if (jobs[job]->flags & J_PIPEFAIL)
-#endif
{
fail = 0;
p = jobs[job]->pipe;
extern void run_pending_traps __P((void));
extern int extended_glob;
-extern int posix_glob_backslash;
/* Global variable which controls whether or not * matches .*.
Non-zero means don't match .*. */
/* Convert the wide character string into unibyte character set. */
memset (&ps, '\0', sizeof(mbstate_t));
n = wcsrtombs(pathname, (const wchar_t **)&wpathname, len, &ps);
+ if (n == (size_t)-1 || *wpathname != 0) /* what? now you tell me? */
+ {
+ wpathname = orig_wpathname;
+ memset (&ps, '\0', sizeof(mbstate_t));
+ n = xwcsrtombs (pathname, (const wchar_t **)&wpathname, len, &ps);
+ }
pathname[len] = '\0';
/* Can't just free wpathname here; wcsrtombs changes it in many cases. */
if (directory_len > 0 && hasglob == 2 && (flags & GX_RECURSE) == 0)
{
-#if 1
dequote_pathname (directory_name);
if (glob_testdir (directory_name, 0) < 0)
{
free (directory_name);
return ((char **)&glob_error_return);
}
-#else
- return ((char **)&glob_error_return);
-#endif
}
/* Handle GX_MARKDIRS here. */
return 0;
}
- return ((bsquote && posix_glob_backslash) ? 2 : 0);
+#if 0
+ return bsquote ? 2 : 0;
+#else
+ return (0);
+#endif
}
#undef INTERNAL_GLOB_PATTERN_P
/* xmbsrtowcs.c -- replacement function for mbsrtowcs */
-/* Copyright (C) 2002-2013 Free Software Foundation, Inc.
+/* Copyright (C) 2002-2019 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
#if HANDLE_MULTIBYTE
+#include <errno.h>
+#if !defined (errno)
+extern int errno;
+#endif
+
#define WSBUF_INC 32
#ifndef FREE
return (wcnum - 1);
}
+/* Convert wide character string to multibyte character string. Treat invalid
+ wide characters as bytes. Used only in unusual circumstances.
+
+ Written by Bruno Haible <bruno@clisp.org>, 2008, adapted by Chet Ramey
+ for use in Bash. */
+
+/* Convert wide character string *SRCP to a multibyte character string and
+ store the result in DEST. Store at most LEN bytes in DEST. */
+size_t
+xwcsrtombs (char *dest, const wchar_t **srcp, size_t len, mbstate_t *ps)
+{
+ const wchar_t *src;
+ size_t cur_max; /* XXX - locale_cur_max */
+ char buf[64], *destptr, *tmp_dest;
+ unsigned char uc;
+ mbstate_t prev_state;
+
+ cur_max = MB_CUR_MAX;
+ if (cur_max > sizeof (buf)) /* Holy cow. */
+ return (size_t)-1;
+
+ src = *srcp;
+
+ if (dest != NULL)
+ {
+ destptr = dest;
+
+ for (; len > 0; src++)
+ {
+ wchar_t wc;
+ size_t ret;
+
+ wc = *src;
+ /* If we have room, store directly into DEST. */
+ tmp_dest = destptr;
+ ret = wcrtomb (len >= cur_max ? destptr : buf, wc, ps);
+
+ if (ret == (size_t)(-1)) /* XXX */
+ {
+ /* Since this is used for globbing and other uses of filenames,
+ treat invalid wide character sequences as bytes. This is
+ intended to be symmetric with xdupmbstowcs2. */
+handle_byte:
+ destptr = tmp_dest; /* in case wcrtomb modified it */
+ uc = wc;
+ ret = 1;
+ if (len >= cur_max)
+ *destptr = uc;
+ else
+ buf[0] = uc;
+ if (ps)
+ memset (ps, 0, sizeof (mbstate_t));
+ }
+
+ if (ret > cur_max) /* Holy cow */
+ goto bad_input;
+
+ if (len < ret)
+ break;
+
+ if (len < cur_max)
+ memcpy (destptr, buf, ret);
+
+ if (wc == 0)
+ {
+ src = NULL;
+ /* Here mbsinit (ps). */
+ break;
+ }
+ destptr += ret;
+ len -= ret;
+ }
+ *srcp = src;
+ return destptr - dest;
+ }
+ else
+ {
+ /* Ignore dest and len, don't store *srcp at the end, and
+ don't clobber *ps. */
+ mbstate_t state = *ps;
+ size_t totalcount = 0;
+
+ for (;; src++)
+ {
+ wchar_t wc;
+ size_t ret;
+
+ wc = *src;
+ ret = wcrtomb (buf, wc, &state);
+
+ if (ret == (size_t)(-1))
+ goto bad_input2;
+ if (wc == 0)
+ {
+ /* Here mbsinit (&state). */
+ break;
+ }
+ totalcount += ret;
+ }
+ return totalcount;
+ }
+
+bad_input:
+ *srcp = src;
+bad_input2:
+ errno = EILSEQ;
+ return (size_t)(-1);
+}
+
#endif /* HANDLE_MULTIBYTE */
memset (&ps2, 0, sizeof (mbstate_t));
}
#endif
- if (_rl_completion_case_fold)
+ for (si = 0; (c1 = match_list[i][si]) && (c2 = match_list[i + 1][si]); si++)
{
- for (si = 0;
- (c1 = _rl_to_lower(match_list[i][si])) &&
- (c2 = _rl_to_lower(match_list[i + 1][si]));
- si++)
+ if (_rl_completion_case_fold)
+ {
+ c1 = _rl_to_lower (c1);
+ c2 = _rl_to_lower (c2);
+ }
#if defined (HANDLE_MULTIBYTE)
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
{
break;
continue;
}
- wc1 = towlower (wc1);
- wc2 = towlower (wc2);
+ if (_rl_completion_case_fold)
+ {
+ wc1 = towlower (wc1);
+ wc2 = towlower (wc2);
+ }
if (wc1 != wc2)
break;
else if (v1 > 1)
si += v1 - 1;
}
else
-#endif
- if (c1 != c2)
- break;
- }
- else
- {
- for (si = 0;
- (c1 = match_list[i][si]) &&
- (c2 = match_list[i + 1][si]);
- si++)
-#if defined (HANDLE_MULTIBYTE)
- if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
- {
- mbstate_t ps_back;
- ps_back = ps1;
- if (!_rl_compare_chars (match_list[i], si, &ps1, match_list[i+1], si, &ps2))
- break;
- else if ((v = _rl_get_char_len (&match_list[i][si], &ps_back)) > 1)
- si += v - 1;
- }
- else
#endif
if (c1 != c2)
break;
/* pathexp.c -- The shell interface to the globbing library. */
-/* Copyright (C) 1995-2014 Free Software Foundation, Inc.
+/* Copyright (C) 1995-2019 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
/* Control enabling special handling of `**' */
int glob_star = 0;
-/* Do we handle backslashes in patterns the way Posix specifies? */
-int posix_glob_backslash = 1;
-
/* Return nonzero if STRING has any unquoted special globbing chars in it.
This is supposed to be called when pathname expansion is performed, so
it implements the rules in Posix 2.13.3, specifically that an unquoted
continue;
/* A pattern can't end with a backslash, but a backslash in the pattern
- can be removed by the matching engine, so we have to run it through
- globbing. */
+ can be special to the matching engine, so we note it in case we
+ need it later. */
case '\\':
if (*string != '\0' && *string != '/')
{
#endif
}
- return ((bsquote && posix_glob_backslash) ? 2 : 0);
+#if 0
+ return (bsquote ? 2 : 0);
+#else
+ return (0);
+#endif
}
/* Return 1 if C is a character that is `special' in a POSIX ERE and needs to
else if (pathname[i] == '\\' && (qflags & QGLOB_REGEXP) == 0)
{
/* XXX - if not quoting regexp, use backslash as quote char. Should
- we just pass it through without treating it as special? That is
+ We just pass it through without treating it as special? That is
what ksh93 seems to do. */
/* If we want to pass through backslash unaltered, comment out these
/* Call the glob library to do globbing on PATHNAME. */
char **
-shell_glob_filename (pathname)
+shell_glob_filename (pathname, qflags)
const char *pathname;
+ int qflags;
{
#if defined (USE_POSIX_GLOB_LIBRARY)
register int i;
glob_t filenames;
int glob_flags;
- temp = quote_string_for_globbing (pathname, QGLOB_FILENAME);
+ temp = quote_string_for_globbing (pathname, QGLOB_FILENAME|qflags);
filenames.gl_offs = 0;
noglob_dot_filenames = glob_dot_filenames == 0;
- temp = quote_string_for_globbing (pathname, QGLOB_FILENAME);
- quoted_pattern = STREQ (pathname, temp) == 0;
+ temp = quote_string_for_globbing (pathname, QGLOB_FILENAME|qflags);
gflags = glob_star ? GX_GLOBSTAR : 0;
results = glob_filename (temp, gflags);
free (temp);
extern int extended_glob;
extern int glob_star;
extern int match_ignore_case; /* doesn't really belong here */
-extern int posix_glob_backslash;
extern int unquoted_glob_pattern_p __P((char *));
extern int glob_char_p __P((const char *));
extern char *quote_globbing_chars __P((const char *));
-/* Call the glob library to do globbing on PATHNAME. */
-extern char **shell_glob_filename __P((const char *));
+/* Call the glob library to do globbing on PATHNAME. FLAGS is additional
+ flags to pass to QUOTE_STRING_FOR_GLOBBING, mostly having to do with
+ whether or not we've already performed quote removal. */
+extern char **shell_glob_filename __P((const char *, int));
/* Filename completion ignore. Used to implement the "fignore" facility of
tcsh, GLOBIGNORE (like ksh-93 FIGNORE), and EXECIGNORE.
if ((tlist->word->flags & W_NOGLOB) == 0 &&
unquoted_glob_pattern_p (tlist->word->word))
{
- glob_array = shell_glob_filename (tlist->word->word);
+ glob_array = shell_glob_filename (tlist->word->word, QGLOB_CTLESC); /* XXX */
/* Handle error cases.
I don't think we should report errors like "No such file
ok 4
ok 5
argv[1] = <a\?>
-a?
+a\?
argv[1] = <a\?>
-a?
-aa
+a\?
+a\a
<define\/\
/>
./tmp/a/b/c ./tmp/a/b/c ./tmp/a/b/c
argv[1] = <./tmp/a/b/c>
argv[1] = <./tmp/a/>
argv[1] = <./tmp/a/b/>
-argv[1] = <./tmp/a/>
-argv[1] = <./tmp/a/b/>
+argv[1] = <./t\mp/a/>
+argv[1] = <./t\mp/a/b/>
argv[1] = <./tmp/a/*>
argv[1] = <./tmp/a/b/c>
argv[1] = <./tmp/a>
argv[2] = <\$foo>
argv[1] = <mixed\$foo/>
<abcdefg>
-<.>
+<\.>
*abc.c
-searchable/.
-searchable/./.
+searchable/\.
+searchable/\./.
readable/\.
readable/\./.
searchable/\.
builtin printf -- "--\n"
shopt -p xyz1
shopt -o -p xyz1
+
+${THIS_SH} ./shopt1.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/>.
+#
+
+# verify all shopt options are reset properly when the shell is reinitialized
+
+: ${TMPDIR:=/var/tmp} ${THIS_SH:=$PWD/bash}
+
+t1=$(mktemp)
+t2=$(mktemp)
+
+if [ ! -e "$t1" ] ; then
+ S1=$RANDOM
+ S2=$RANDOM
+ t1=$TMPDIR/s-$S1
+ t2=$TMPDIR/s-$S2
+ touch "$t1" "$t2"
+fi
+
+chmod +x "$t1" "$t2"
+
+echo "shopt" > "$t1"
+
+echo "#!${THIS_SH}" > "$t2"
+echo "shopt" >> "$t2"
+
+for o in $(compgen -A shopt)
+do
+ case $o in
+ extdebug) ;;
+ *) shopt -s $o ;;
+ esac
+done
+diff <("$t1") <("$t2")
+
+for o in $(compgen -A shopt)
+do
+ shopt -u $o;
+done
+diff <("$t1") <("$t2")
+
+rm "$t1" "$t2"
arrayind_t unused;
char *key;
{
+ struct timeval tv;
if (legal_number (value, &seconds_value_assigned) == 0)
seconds_value_assigned = 0;
- shell_start_time = NOW;
+ gettimeofday (&tv, NULL);
+ shell_start_time = tv.tv_sec;
return (self);
}
{
time_t time_since_start;
char *p;
+ struct timeval tv;
- time_since_start = NOW - shell_start_time;
+ gettimeofday(&tv, NULL);
+ time_since_start = tv.tv_sec - shell_start_time;
p = itos(seconds_value_assigned + time_since_start);
FREE (value_cell (var));