commit bash-20170120 snapshot

This commit is contained in:
Chet Ramey
2017-01-30 15:48:59 -05:00
parent 3e8a02a689
commit 571ba52b71
15 changed files with 324 additions and 383 deletions
+32 -2
View File
@@ -12988,12 +12988,42 @@ lib/glob/glob.c
lib/glob/glob_loop.c
- CHAR -> GCHAR (unsigned char); change uses of CHAR to GCHAR
- extglob_skipname: move here from gmisc.c, generalize for regular
and wide-char versions
lib/glob/glob.c
- wchkname -> wskipname
- wskipname: now takes a third `flags' argument, like the other variants
of skipname
1/17
----
redir.c
- here_document_to_fd: set the file descriptor open for writing to the
here document to be close-on-exec. Fixes bug reported by
Siteshwar Vashisht <svashisht@redhat.com>
1/18
----
{gmisc,gm_loop}.c
- match_pattern_char,match_pattern_wchar: moved to gm_loop.c (new file),
compile twice for single and wide characters as with the rest of
the functions
- umatchlen,wmatchlen: ditto
- extglob_pattern_p: move to gm_loop.c, generalize for regular and
wide-char versions
1/19
----
lib/readline/complete.c
- stat_char: fix small memory leak if stat/lstat returns -1
bashline.c
- bash_filename_stat_hook,bash_directory_completion_hook: make sure
expand_prompt_string is caled wth W_NOPROCSUB flag
- directory_exists: don't dequote the filename passed as an argument;
this function should never get quoted pathnames
subst.c
- expand_word_internal: when calling expand_word_internal recursively
after reading a double-quoted string, make sure the W_NOCOMSUB and
W_NOPROCSUB flags make it to the recursive invocation. Fixes bug
reported by Jens Heyens <jens.heyens@cispa.saarland>
+1
View File
@@ -239,6 +239,7 @@ lib/glob/glob.c f
lib/glob/glob.h f
lib/glob/glob_loop.c f
lib/glob/gmisc.c f
lib/glob/gm_loop.c f
lib/glob/xmbsrtowcs.c f
lib/glob/collsyms.h f
lib/glob/doc/Makefile f
+13 -11
View File
@@ -143,7 +143,7 @@ static int executable_completion __P((const char *, int));
static rl_icppfunc_t *save_directory_hook __P((void));
static void restore_directory_hook __P((rl_icppfunc_t));
static int directory_exists __P((const char *));
static int directory_exists __P((const char *, int));
static void cleanup_expansion_error __P((void));
static void maybe_make_readline_line __P((char *));
@@ -1157,7 +1157,7 @@ bash_backward_shellword (count, key)
size_t slen;
int sindex, c, p;
DECLARE_MBSTATE;
if (count < 0)
return (bash_forward_shellword (-count, key));
@@ -3106,18 +3106,20 @@ restore_directory_hook (hookf)
rl_directory_rewrite_hook = hookf;
}
/* Check whether not the (dequoted) version of DIRNAME, with any trailing slash
removed, exists. */
/* Check whether not DIRNAME, with any trailing slash removed, exists. If
SHOULD_DEQUOTE is non-zero, we dequote the directory name first. */
static int
directory_exists (dirname)
directory_exists (dirname, should_dequote)
const char *dirname;
int should_dequote;
{
char *new_dirname;
int dirlen, r;
struct stat sb;
/* First, dequote the directory name */
new_dirname = bash_dequote_filename ((char *)dirname, rl_completion_quote_character);
/* We save the string and chop the trailing slash because stat/lstat behave
inconsistently if one is present. */
new_dirname = should_dequote ? bash_dequote_filename ((char *)dirname, rl_completion_quote_character) : savestring (dirname);
dirlen = STRLEN (new_dirname);
if (new_dirname[dirlen - 1] == '/')
new_dirname[dirlen - 1] = '\0';
@@ -3149,7 +3151,7 @@ bash_filename_stat_hook (dirname)
else if (t = mbschr (local_dirname, '`')) /* XXX */
should_expand_dirname = '`';
if (should_expand_dirname && directory_exists (local_dirname))
if (should_expand_dirname && directory_exists (local_dirname, 0))
should_expand_dirname = 0;
if (should_expand_dirname)
@@ -3159,7 +3161,7 @@ bash_filename_stat_hook (dirname)
have to worry about restoring this setting. */
global_nounset = unbound_vars_is_error;
unbound_vars_is_error = 0;
wl = expand_prompt_string (new_dirname, 0, W_NOCOMSUB|W_COMPLETE); /* does the right thing */
wl = expand_prompt_string (new_dirname, 0, W_NOCOMSUB|W_NOPROCSUB|W_COMPLETE); /* does the right thing */
unbound_vars_is_error = global_nounset;
if (wl)
{
@@ -3259,13 +3261,13 @@ bash_directory_completion_hook (dirname)
should_expand_dirname = '`';
}
if (should_expand_dirname && directory_exists (local_dirname))
if (should_expand_dirname && directory_exists (local_dirname, 1))
should_expand_dirname = 0;
if (should_expand_dirname)
{
new_dirname = savestring (local_dirname);
wl = expand_prompt_string (new_dirname, 0, W_NOCOMSUB|W_COMPLETE); /* does the right thing */
wl = expand_prompt_string (new_dirname, 0, W_NOCOMSUB|W_NOPROCSUB|W_COMPLETE); /* does the right thing */
if (wl)
{
*dirname = string_list (wl);
+8
View File
@@ -445,6 +445,14 @@ sh_unset_nodelay_mode (fd)
return 0;
}
/* Just a wrapper for the define in include/filecntl.h */
int
sh_setclexec (fd)
int fd;
{
return (SET_CLOSE_ON_EXEC (fd));
}
/* Return 1 if file descriptor FD is valid; 0 otherwise. */
int
sh_validfd (fd)
+1
View File
@@ -295,6 +295,7 @@ extern int legal_alias_name __P((const char *, int));
extern int assignment __P((const char *, int));
extern int sh_unset_nodelay_mode __P((int));
extern int sh_setclexec __P((int));
extern int sh_validfd __P((int));
extern int fd_ispipe __P((int));
extern void check_dev_tty __P((void));
+1
View File
@@ -164,4 +164,5 @@ xmbsrtowcs.o: xmbsrtowcs.c
# dependencies for C files that include other C files
glob.o: glob_loop.c
gmisc.o: gm_loop.c
smatch.o: sm_loop.c
+13 -12
View File
@@ -1,6 +1,6 @@
/* glob.c -- file-name wildcard pattern matching for Bash.
Copyright (C) 1985-2009 Free Software Foundation, Inc.
Copyright (C) 1985-2017 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne-Again SHell.
@@ -123,6 +123,9 @@ static char **glob_dir_to_array __P((char *, char **, int));
extern char *glob_patscan __P((char *, char *, int));
extern wchar_t *glob_patscan_wc __P((wchar_t *, wchar_t *, int));
/* And this from gmisc.c/gm_loop.c */
extern int wextglob_pattern_p __P((wchar_t *));
extern char *glob_dirscan __P((char *, int));
/* Compile `glob_loop.c' for single-byte characters. */
@@ -131,7 +134,6 @@ extern char *glob_dirscan __P((char *, int));
#define INT int
#define L(CS) CS
#define INTERNAL_GLOB_PATTERN_P internal_glob_pattern_p
#define EXTGLOB_PATTERN_P extglob_pattern_p
#include "glob_loop.c"
/* Compile `glob_loop.c' again for multibyte characters. */
@@ -142,7 +144,6 @@ extern char *glob_dirscan __P((char *, int));
#define INT wint_t
#define L(CS) L##CS
#define INTERNAL_GLOB_PATTERN_P internal_glob_wpattern_p
#define EXTGLOB_PATTERN_P wextglob_pattern_p
#include "glob_loop.c"
#endif /* HANDLE_MULTIBYTE */
@@ -275,23 +276,23 @@ skipname (pat, dname, flags)
#if HANDLE_MULTIBYTE
static int
wskipname (pat_wc, dn_wc, flags)
wchar_t *pat_wc, *dn_wc;
wskipname (pat, dname, flags)
wchar_t *pat, *dname;
int flags;
{
/* If a leading dot need not be explicitly matched, and the
pattern doesn't start with a `.', don't match `.' or `..' */
if (noglob_dot_filenames == 0 && pat_wc[0] != L'.' &&
(pat_wc[0] != L'\\' || pat_wc[1] != L'.') &&
(dn_wc[0] == L'.' &&
(dn_wc[1] == L'\0' || (dn_wc[1] == L'.' && dn_wc[2] == L'\0'))))
if (noglob_dot_filenames == 0 && pat[0] != L'.' &&
(pat[0] != L'\\' || pat[1] != L'.') &&
(dname[0] == L'.' &&
(dname[1] == L'\0' || (dname[1] == L'.' && dname[2] == L'\0'))))
return 1;
/* If a leading dot must be explicitly matched, check to see if the
pattern and dirname both have one. */
else if (noglob_dot_filenames && dn_wc[0] == L'.' &&
pat_wc[0] != L'.' &&
(pat_wc[0] != L'\\' || pat_wc[1] != L'.'))
else if (noglob_dot_filenames && dname[0] == L'.' &&
pat[0] != L'.' &&
(pat[0] != L'\\' || pat[1] != L'.'))
return 1;
return 0;
+1 -23
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 1991-2005 Free Software Foundation, Inc.
/* Copyright (C) 1991-2017 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -61,28 +61,6 @@ INTERNAL_GLOB_PATTERN_P (pattern)
return 0;
}
#if EXTENDED_GLOB
int
EXTGLOB_PATTERN_P (pat)
const CHAR *pat;
{
switch (pat[0])
{
case L('*'):
case L('+'):
case L('!'):
case L('@'):
case L('?'):
return (pat[1] == L('(')); /* ) */
default:
return 0;
}
return 0;
}
#endif
#undef EXTGLOB_PATTERN_P
#undef INTERNAL_GLOB_PATTERN_P
#undef L
#undef INT
+208
View File
@@ -0,0 +1,208 @@
/* Copyright (C) 1991-2017 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash 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.
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
*/
#if EXTENDED_GLOB
int
EXTGLOB_PATTERN_P (pat)
const CHAR *pat;
{
switch (pat[0])
{
case L('*'):
case L('+'):
case L('!'):
case L('@'):
case L('?'):
return (pat[1] == L('(')); /* ) */
default:
return 0;
}
return 0;
}
#endif
/* Return 1 of the first character of STRING could match the first
character of pattern PAT. Compiled to both single and wiide character
versions. FLAGS is a subset of strmatch flags; used to do case-insensitive
matching for now. */
int
MATCH_PATTERN_CHAR (pat, string, flags)
CHAR *pat, *string;
int flags;
{
CHAR c;
if (*string == 0)
return (*pat == L('*')); /* XXX - allow only * to match empty string */
switch (c = *pat++)
{
default:
return (FOLD(*string) == FOLD(c));
case L('\\'):
return (FOLD(*string) == FOLD(*pat));
case L('?'):
return (*pat == L('(') ? 1 : (*string != L'\0'));
case L('*'):
return (1);
case L('+'):
case L('!'):
case L('@'):
return (*pat == L('(') ? 1 : (FOLD(*string) == FOLD(c)));
case L('['):
return (*string != L('\0'));
}
}
int
MATCHLEN (pat, max)
CHAR *pat;
size_t max;
{
CHAR c;
int matlen, bracklen, t, in_cclass, in_collsym, in_equiv;
if (*pat == 0)
return (0);
matlen = in_cclass = in_collsym = in_equiv = 0;
while (c = *pat++)
{
switch (c)
{
default:
matlen++;
break;
case L('\\'):
if (*pat == 0)
return ++matlen;
else
{
matlen++;
pat++;
}
break;
case L('?'):
if (*pat == LPAREN)
return (matlen = -1); /* XXX for now */
else
matlen++;
break;
case L('*'):
return (matlen = -1);
case L('+'):
case L('!'):
case L('@'):
if (*pat == LPAREN)
return (matlen = -1); /* XXX for now */
else
matlen++;
break;
case L('['):
/* scan for ending `]', skipping over embedded [:...:] */
bracklen = 1;
c = *pat++;
do
{
if (c == 0)
{
pat--; /* back up to NUL */
matlen += bracklen;
goto bad_bracket;
}
else if (c == L('\\'))
{
/* *pat == backslash-escaped character */
bracklen++;
/* If the backslash or backslash-escape ends the string,
bail. The ++pat skips over the backslash escape */
if (*pat == 0 || *++pat == 0)
{
matlen += bracklen;
goto bad_bracket;
}
}
else if (c == L('[') && *pat == L(':')) /* character class */
{
pat++;
bracklen++;
in_cclass = 1;
}
else if (in_cclass && c == L(':') && *pat == L(']'))
{
pat++;
bracklen++;
in_cclass = 0;
}
else if (c == L('[') && *pat == L('.')) /* collating symbol */
{
pat++;
bracklen++;
if (*pat == L(']')) /* right bracket can appear as collating symbol */
{
pat++;
bracklen++;
}
in_collsym = 1;
}
else if (in_collsym && c == L('.') && *pat == L(']'))
{
pat++;
bracklen++;
in_collsym = 0;
}
else if (c == L('[') && *pat == L('=')) /* equivalence class */
{
pat++;
bracklen++;
if (*pat == L(']')) /* right bracket can appear as equivalence class */
{
pat++;
bracklen++;
}
in_equiv = 1;
}
else if (in_equiv && c == L('=') && *pat == L(']'))
{
pat++;
bracklen++;
in_equiv = 0;
}
else
bracklen++;
}
while ((c = *pat++) != L(']'));
matlen++; /* bracket expression can only match one char */
bad_bracket:
break;
}
}
return matlen;
}
#undef EXTGLOB_PATTERN_P
#undef MATCH_PATTERN_CHAR
#undef MATCHLEN
#undef FOLD
#undef L
#undef LPAREN
#undef RPAREN
#undef INT
#undef CHAR
+27 -331
View File
@@ -1,6 +1,6 @@
/* gmisc.c -- miscellaneous pattern matching utility functions for Bash.
Copyright (C) 2010 Free Software Foundation, Inc.
Copyright (C) 2010-2017 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne-Again SHell.
@@ -35,348 +35,44 @@
#ifndef FNM_CASEFOLD
# include "strmatch.h"
#endif
#ifndef LPAREN
# define LPAREN '('
#endif
#ifndef RPAREN
# define RPAREN ')'
#endif
#if defined (HANDLE_MULTIBYTE)
#define WLPAREN L'('
#define WRPAREN L')'
#include "glob.h"
/* Make sure these names continue to agree with what's in smatch.c */
extern char *glob_patscan __P((char *, char *, int));
extern wchar_t *glob_patscan_wc __P((wchar_t *, wchar_t *, int));
#define FOLD(c) ((flags & FNM_CASEFOLD) && iswupper (c) ? towlower (c) : (c))
/* Return 1 of the first character of WSTRING could match the first
character of pattern WPAT. Wide character version. FLAGS is a
subset of strmatch flags; used to do case-insensitive matching for now. */
int
match_pattern_wchar (wpat, wstring, flags)
wchar_t *wpat, *wstring;
int flags;
{
wchar_t wc;
if (*wstring == 0)
return (*wpat == L'*'); /* XXX - allow only * to match empty string */
switch (wc = *wpat++)
{
default:
return (FOLD(*wstring) == FOLD(wc));
case L'\\':
return (FOLD(*wstring) == FOLD(*wpat));
case L'?':
return (*wpat == WLPAREN ? 1 : (*wstring != L'\0'));
case L'*':
return (1);
case L'+':
case L'!':
case L'@':
return (*wpat == WLPAREN ? 1 : (FOLD(*wstring) == FOLD(wc)));
case L'[':
return (*wstring != L'\0');
}
}
int
wmatchlen (wpat, wmax)
wchar_t *wpat;
size_t wmax;
{
wchar_t wc;
int matlen, bracklen, t, in_cclass, in_collsym, in_equiv;
if (*wpat == 0)
return (0);
matlen = in_cclass = in_collsym = in_equiv = 0;
while (wc = *wpat++)
{
switch (wc)
{
default:
matlen++;
break;
case L'\\':
if (*wpat == 0)
return ++matlen;
else
{
matlen++;
wpat++;
}
break;
case L'?':
if (*wpat == WLPAREN)
return (matlen = -1); /* XXX for now */
else
matlen++;
break;
case L'*':
return (matlen = -1);
case L'+':
case L'!':
case L'@':
if (*wpat == WLPAREN)
return (matlen = -1); /* XXX for now */
else
matlen++;
break;
case L'[':
/* scan for ending `]', skipping over embedded [:...:] */
bracklen = 1;
wc = *wpat++;
do
{
if (wc == 0)
{
wpat--; /* back up to NUL */
matlen += bracklen;
goto bad_bracket;
}
else if (wc == L'\\')
{
/* *wpat == backslash-escaped character */
bracklen++;
/* If the backslash or backslash-escape ends the string,
bail. The ++wpat skips over the backslash escape */
if (*wpat == 0 || *++wpat == 0)
{
matlen += bracklen;
goto bad_bracket;
}
}
else if (wc == L'[' && *wpat == L':') /* character class */
{
wpat++;
bracklen++;
in_cclass = 1;
}
else if (in_cclass && wc == L':' && *wpat == L']')
{
wpat++;
bracklen++;
in_cclass = 0;
}
else if (wc == L'[' && *wpat == L'.') /* collating symbol */
{
wpat++;
bracklen++;
if (*wpat == L']') /* right bracket can appear as collating symbol */
{
wpat++;
bracklen++;
}
in_collsym = 1;
}
else if (in_collsym && wc == L'.' && *wpat == L']')
{
wpat++;
bracklen++;
in_collsym = 0;
}
else if (wc == L'[' && *wpat == L'=') /* equivalence class */
{
wpat++;
bracklen++;
if (*wpat == L']') /* right bracket can appear as equivalence class */
{
wpat++;
bracklen++;
}
in_equiv = 1;
}
else if (in_equiv && wc == L'=' && *wpat == L']')
{
wpat++;
bracklen++;
in_equiv = 0;
}
else
bracklen++;
}
while ((wc = *wpat++) != L']');
matlen++; /* bracket expression can only match one char */
bad_bracket:
break;
}
}
return matlen;
}
#endif
#undef FOLD
/* Compile `gm_loop.c' for single-byte characters. */
#define CHAR char
#define INT int
#define L(CS) CS
#define EXTGLOB_PATTERN_P extglob_pattern_p
#define MATCH_PATTERN_CHAR match_pattern_char
#define MATCHLEN umatchlen
#define FOLD(c) ((flags & FNM_CASEFOLD) \
? TOLOWER ((unsigned char)c) \
: ((unsigned char)c))
#ifndef LPAREN
#define LPAREN '('
#define RPAREN ')'
#endif
#include "gm_loop.c"
/* Return 1 of the first character of STRING could match the first
character of pattern PAT. Used to avoid n2 calls to strmatch().
FLAGS is a subset of strmatch flags; used to do case-insensitive
matching for now. */
int
match_pattern_char (pat, string, flags)
char *pat, *string;
int flags;
{
char c;
/* Compile `gm_loop.c' again for multibyte characters. */
#if HANDLE_MULTIBYTE
if (*string == 0)
return (*pat == '*'); /* XXX - allow only * to match empty string */
#define CHAR wchar_t
#define INT wint_t
#define L(CS) L##CS
#define EXTGLOB_PATTERN_P wextglob_pattern_p
#define MATCH_PATTERN_CHAR match_pattern_wchar
#define MATCHLEN wmatchlen
switch (c = *pat++)
{
default:
return (FOLD(*string) == FOLD(c));
case '\\':
return (FOLD(*string) == FOLD(*pat));
case '?':
return (*pat == LPAREN ? 1 : (*string != '\0'));
case '*':
return (1);
case '+':
case '!':
case '@':
return (*pat == LPAREN ? 1 : (FOLD(*string) == FOLD(c)));
case '[':
return (*string != '\0');
}
}
#define FOLD(c) ((flags & FNM_CASEFOLD) && iswupper (c) ? towlower (c) : (c))
#define LPAREN L'('
#define RPAREN L')'
#include "gm_loop.c"
int
umatchlen (pat, max)
char *pat;
size_t max;
{
char c;
int matlen, bracklen, t, in_cclass, in_collsym, in_equiv;
#endif /* HANDLE_MULTIBYTE */
if (*pat == 0)
return (0);
matlen = in_cclass = in_collsym = in_equiv = 0;
while (c = *pat++)
{
switch (c)
{
default:
matlen++;
break;
case '\\':
if (*pat == 0)
return ++matlen;
else
{
matlen++;
pat++;
}
break;
case '?':
if (*pat == LPAREN)
return (matlen = -1); /* XXX for now */
else
matlen++;
break;
case '*':
return (matlen = -1);
case '+':
case '!':
case '@':
if (*pat == LPAREN)
return (matlen = -1); /* XXX for now */
else
matlen++;
break;
case '[':
/* scan for ending `]', skipping over embedded [:...:] */
bracklen = 1;
c = *pat++;
do
{
if (c == 0)
{
pat--; /* back up to NUL */
matlen += bracklen;
goto bad_bracket;
}
else if (c == '\\')
{
/* *pat == backslash-escaped character */
bracklen++;
/* If the backslash or backslash-escape ends the string,
bail. The ++pat skips over the backslash escape */
if (*pat == 0 || *++pat == 0)
{
matlen += bracklen;
goto bad_bracket;
}
}
else if (c == '[' && *pat == ':') /* character class */
{
pat++;
bracklen++;
in_cclass = 1;
}
else if (in_cclass && c == ':' && *pat == ']')
{
pat++;
bracklen++;
in_cclass = 0;
}
else if (c == '[' && *pat == '.') /* collating symbol */
{
pat++;
bracklen++;
if (*pat == ']') /* right bracket can appear as collating symbol */
{
pat++;
bracklen++;
}
in_collsym = 1;
}
else if (in_collsym && c == '.' && *pat == ']')
{
pat++;
bracklen++;
in_collsym = 0;
}
else if (c == '[' && *pat == '=') /* equivalence class */
{
pat++;
bracklen++;
if (*pat == ']') /* right bracket can appear as equivalence class */
{
pat++;
bracklen++;
}
in_equiv = 1;
}
else if (in_equiv && c == '=' && *pat == ']')
{
pat++;
bracklen++;
in_equiv = 0;
}
else
bracklen++;
}
while ((c = *pat++) != ']');
matlen++; /* bracket expression can only match one char */
bad_bracket:
break;
}
}
return matlen;
}
#if defined (EXTENDED_GLOB)
/* Skip characters in PAT and return the final occurrence of DIRSEP. This
+4 -1
View File
@@ -625,7 +625,10 @@ stat_char (filename)
#endif
if (r == -1)
return (0);
{
xfree (f);
return (0);
}
character = 0;
if (S_ISDIR (finfo.st_mode))
+2
View File
@@ -466,6 +466,8 @@ here_document_to_fd (redirectee, ri)
return (fd);
}
SET_CLOSE_ON_EXEC (fd);
errno = r = 0; /* XXX */
/* write_here_document returns 0 on success, errno on failure. */
if (redirectee->word)
+4
View File
@@ -9612,6 +9612,10 @@ add_twochars:
tword->flags |= word->flags & (W_ASSIGNARG|W_ASSIGNRHS); /* affects $@ */
if (word->flags & W_COMPLETE)
tword->flags |= W_COMPLETE; /* for command substitutions */
if (word->flags & W_NOCOMSUB)
tword->flags |= W_NOCOMSUB;
if (word->flags & W_NOPROCSUB)
tword->flags |= W_NOPROCSUB;
temp = (char *)NULL;
+1 -1
View File
@@ -1,4 +1,4 @@
BUILD_DIR=/usr/local/build/bash/bash-current
BUILD_DIR=/usr/local/build/chet/bash/bash-current
THIS_SH=$BUILD_DIR/bash
PATH=$PATH:$BUILD_DIR
+8 -2
View File
@@ -16,8 +16,14 @@ export PATH
# unset BASH_ENV only if it is set
[ "${BASH_ENV+set}" = "set" ] && unset BASH_ENV
# ditto for SHELLOPTS
[ "${SHELLOPTS+set}" = "set" ] && unset SHELLOPTS
# can't reliably do it for SHELLOPTS; SHELLOPTS is readonly in bash
if [ "${BASH_VERSION+set}" = "set" ]; then
export -n SHELLOPTS # just make sure its not exported
set +o posix
typeset -p SHELLOPTS
else
[ "${SHELLOPTS+set}" = "set" ] && unset SHELLOPTS 2>/dev/null
fi
: ${THIS_SH:=../bash}
export THIS_SH