does not end in a backslash, we need to return true. Fixes bug
reported by Robert Elz <kre@bmunnari.OZ.AU>
-lib/glob/gm_loop.c
+lib/glob/glob_loop.c
- INTERNAL_GLOB_PATTERN_P: same change to return TRUE for a backslash
that doesn't end the pattern
tilde expansion at all, even for the previously-special-case array
subscript expansion. Report from Bize Ma <binaryzebra@gmail.com>
- expand_word_internal: take out Q_ARRAYSUB check for tilde expansion
+
+ 12/26
+ -----
+builtins/evalstring.c
+ - parse_and_execute: if the eval builtin gets a parser error while
+ parsing a string in posix mode, don't exit the shell if the eval
+ was run by the command builtin. report from Martijn Dekker
+ <martijn@inlv.org>
+
+examples/loadables/{basename,dirname}.c
+ - dirname_builtin: skip over any `--' ending the options. Report from
+ Peng Yu <pengyu.ut@gmail.com>
+
+ 12/27
+ -----
+examples/loadables/mkdir.c
+ - make_path: add argument noting whether or not the user specified -m;
+ only attempt the chmod on an existing directory if the user did so
+ - make_path: when creating intermediate directories, perform the
+ mkdir (path, 0) and chmod separately as the posix text recommends
+
+ 12/28
+ -----
+parser.h
+ - PST_COMMENT: new state, set when the shell is reading characters
+ until newline as part of comment processing
+
+parse.y
+ - shell_getc: don't return a space at the end of a token if the parser
+ is consuming a comment. Fixes bug reported by Harald van Dijk
+ <harald@gigawatt.nl>
+
+ 12/31
+ -----
+lib/glob/glob_loop.c
+ - INTERNAL_GLOB_PATTERN_P: revert change from 4/27 that makes this
+ function return non-zero for a backslash in the string. Based on a
+ report from Tom Ryder <tom@sanctum.geek.nz>
tests/errors5.sub f
tests/errors6.sub f
tests/errors7.sub f
+tests/errors8.sub f
tests/execscript f
tests/exec.right f
tests/exec1.sub f 755
tests/glob1.sub f
tests/glob2.sub f
tests/glob3.sub f
+tests/glob4.sub f
tests/glob.right f
tests/globstar.tests f
tests/globstar.right f
}
else
{
- last_result = EXECUTION_FAILURE;
+ last_result = EX_BADUSAGE; /* was EXECUTION_FAILURE */
if (interactive_shell == 0 && this_shell_builtin &&
(this_shell_builtin == source_builtin || this_shell_builtin == eval_builtin) &&
- last_command_exit_value == EX_BADSYNTAX && posixly_correct)
+ last_command_exit_value == EX_BADSYNTAX && posixly_correct && executing_command_builtin == 0)
{
should_jump_to_top_level = 1;
code = ERREXIT;
if (no_options (list))
return (EX_USAGE);
+ list = loptend;
string = list->word->word;
suffix = (char *)NULL;
#include "builtins.h"
#include "shell.h"
#include "common.h"
+#include "bashgetopt.h"
int
dirname_builtin (list)
int slen;
char *string;
+ if (no_options (list))
+ return (EX_USAGE);
+ list = loptend;
+
if (list == 0 || list->next)
{
builtin_usage ();
return (EX_USAGE);
}
- if (no_options (list))
- return (EX_USAGE);
-
string = list->word->word;
slen = strlen (string);
mkdir_builtin (list)
WORD_LIST *list;
{
- int opt, pflag, omode, rval, nmode, parent_mode;
+ int opt, pflag, mflag, omode, rval, nmode, parent_mode;
char *mode;
WORD_LIST *l;
reset_internal_getopt ();
- pflag = 0;
+ pflag = mflag = 0;
mode = (char *)NULL;
while ((opt = internal_getopt(list, "m:p")) != -1)
switch (opt)
pflag = 1;
break;
case 'm':
+ mflag = 1;
mode = list_optarg;
break;
CASE_HELPOPT;
for (rval = EXECUTION_SUCCESS, l = list; l; l = l->next)
{
- if (pflag && make_path (l->word->word, nmode, parent_mode))
+ if (pflag && make_path (l->word->word, mflag, nmode, parent_mode))
{
rval = EXECUTION_FAILURE;
continue;
this changes the process's umask; make sure that all paths leading to a
return reset it to ORIGINAL_UMASK */
static int
-make_path (path, nmode, parent_mode)
+make_path (path, user_mode, nmode, parent_mode)
char *path;
+ int user_mode;
int nmode, parent_mode;
{
int oumask;
return 1;
}
- if (chmod (path, nmode))
+ if (user_mode && chmod (path, nmode))
{
builtin_error ("%s: %s", path, strerror (errno));
return 1;
*p = '\0';
if (stat (npath, &sb) != 0)
{
- if (mkdir (npath, parent_mode))
+ if (mkdir (npath, 0))
{
builtin_error ("cannot create directory `%s': %s", npath, strerror (errno));
umask (original_umask);
free (npath);
return 1;
}
+ if (chmod (npath, parent_mode) != 0)
+ {
+ builtin_error ("cannot chmod directory `%s': %s", npath, strerror (errno));
+ umask (original_umask);
+ free (npath);
+ return 1;
+ }
}
else if (S_ISDIR (sb.st_mode) == 0)
{
continue;
case L('\\'):
+#if 0
/* Don't let the pattern end in a backslash (GMATCH returns no match
if the pattern ends in a backslash anyway), but otherwise return 1,
since the matching engine uses backslash as an escape character
and it can be removed. */
return (*p != L('\0'));
+#else
+ /* The pattern may not end with a backslash. */
+ if (*p++ == L('\0'))
+ return 0;
+#endif
}
return 0;
only interesting in non-interactive shells */
global_command = (COMMAND *)NULL;
if (last_command_exit_value == 0)
+{
+itrace("parser: forcing EX_BADUSAGE; executing_command_builtin = %d", executing_command_builtin);
last_command_exit_value = EX_BADUSAGE; /* force error return */
+}
handle_eof_input_unit ();
if (interactive && parse_and_execute_level == 0)
{
return the space that will delimit the token and postpone the pop_string.
This set of conditions duplicates what used to be in mk_alexpansion ()
below, with the addition that we don't add a space if we're currently
- reading a quoted string. */
+ reading a quoted string or in a shell comment. */
#ifndef OLD_ALIAS_HACK
if (uc == 0 && pushed_string_list && pushed_string_list->flags != PSH_SOURCE &&
pushed_string_list->flags != PSH_DPAREN &&
+ (parser_state & PST_COMMENT) == 0 &&
shell_input_line_index > 0 &&
shell_input_line[shell_input_line_index-1] != ' ' &&
shell_input_line[shell_input_line_index-1] != '\n' &&
if MBTEST(character == '#' && (!interactive || interactive_comments))
{
/* A comment. Discard until EOL or EOF, and then return a newline. */
+ parser_state |= PST_COMMENT;
discard_until ('\n');
shell_getc (0);
+ parser_state &= ~PST_COMMENT;
character = '\n'; /* this will take the next if statement and return. */
}
#define PST_HEREDOC 0x020000 /* reading body of here-document */
#define PST_REPARSE 0x040000 /* re-parsing in parse_string_to_word_list */
#define PST_REDIRLIST 0x080000 /* parsing a list of redirections preceding a simple command name */
-
+#define PST_COMMENT 0x100000 /* parsing a shell comment; used by aliases */
/* Definition of the delimiter stack. Needed by parse.y and bashhist.c. */
struct dstack {
alias e=echo
eval '</dev/null e ok 3'
eval 'a=true e ok 4'
+
+alias comment=#
+comment
+
+alias long_comment='# for x in '
+long_comment text after
+
+# comment
+comment foo bar
after non-special builtin: 0
./errors7.sub: line 12: x: readonly variable
./errors7.sub: line 14: x: readonly variable
-./errors.tests: line 281: `!!': not a valid identifier
+./errors8.sub: eval: line 7: syntax error: unexpected end of file
+ok 1
+./errors8.sub: line 8: v: readonly variable
+ok 2
+./errors8.sub: line 9: v: readonly variable
+ok 3
+./errors8.sub: line 11: shift: 12: shift count out of range
+ok 4
+./errors8.sub: line 13: return: can only `return' from a function or sourced script
+ok 5
+./errors8.sub: line 14: set: notanoption: invalid option name
+ok 6
+./errors.tests: line 283: `!!': not a valid identifier
${THIS_SH} ./errors7.sub
${THIS_SH} -o posix ./errors7.sub
+${THIS_SH} ./errors8.sub
+
# this must be last!
# in posix mode, a function name must be a valid identifier
# this can't go in posix2.tests, since it causes the shell to exit
--- /dev/null
+# the start of a set of tests for command keeping special builtins from
+# exiting the shell on failure
+set -o posix
+readonly v
+
+command eval '( ' || echo ok 1
+
+command export v=foo || echo ok 2
+command readonly v=foo || echo ok 3
+
+command shift 12 || echo ok 4
+
+command return 16 || echo ok 5
+command set -o notanoption || echo ok 6
ok 3
ok 4
ok 5
+argv[1] = <a\?>
+a?
+argv[1] = <a\?>
+a?
+aa
argv[1] = <a>
argv[2] = <abc>
argv[3] = <abd>
argv[3] = <abd>
argv[4] = <abe>
tmp/l1 tmp/l2 tmp/*4 tmp/l3
-./glob.tests: line 46: no match: tmp/*4
+./glob.tests: line 47: no match: tmp/*4
argv[1] = <bdir/>
argv[1] = <*>
argv[1] = <a*>
${THIS_SH} ./glob1.sub
${THIS_SH} ./glob2.sub
${THIS_SH} ./glob3.sub
+${THIS_SH} ./glob4.sub
MYDIR=$PWD # save where we are
--- /dev/null
+trap "rm 'a?' aa" EXIT
+touch 'a?' aa
+
+set -- a \?; IFS=\\; var=$*;
+recho "$var"
+unset IFS; printf "%s\n" ${var}
+
+var='a\?'
+recho "$var"
+printf "%s\n" ${var}
+
+var='a\a'
+printf "%s\n" ${var}