mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-07-01 17:39:56 +02:00
commit bash-20050310 snapshot
This commit is contained in:
@@ -11166,3 +11166,20 @@ configure.in
|
||||
bashline.c
|
||||
- make bash_directory_expansion a void function, since it doesn't have
|
||||
any return value
|
||||
|
||||
3/9
|
||||
---
|
||||
builtins/read.def
|
||||
- when testing for a pipe, use `fd' instead of hard-coding 0, since we
|
||||
can read from other file descriptors now
|
||||
|
||||
lib/sh/zread.c
|
||||
- in zsyncfd, only set lind and lused to 0 if the lseek succeeds.
|
||||
If the lseek fails, we might steal input from other programs, but
|
||||
a failed lseek won't cause us to erroneously discard input
|
||||
|
||||
3/11
|
||||
----
|
||||
builtins/evalstring.c
|
||||
- don't allow parse_and_execute to short-circuit and call exec() if
|
||||
the command's return value is being inverted
|
||||
|
||||
+25
-1
@@ -11151,5 +11151,29 @@ builtins/read.def
|
||||
the input (including any trailing field delimiters), falling back
|
||||
to the previous behavior if it does not. This is what POSIX.2
|
||||
specifies, I believe (and the consensus of the austin-group list).
|
||||
This requires a few tests in read.tests to be changed
|
||||
This requires a few tests in read.tests to be changed: backslashes
|
||||
escaping IFS whitespace characters at the end of input cause the
|
||||
whitespace characters to be preserved in the value assigned to the
|
||||
variable, and the trailing non-whitespace field delimiter issue
|
||||
|
||||
3/7
|
||||
---
|
||||
configure.in
|
||||
- add -D_POSIX_SOURCE to the LOCAL_CFLAGS for Interix
|
||||
|
||||
3/8
|
||||
---
|
||||
bashline.c
|
||||
- make bash_directory_expansion a void function, since it doesn't have
|
||||
any return value
|
||||
|
||||
3/9
|
||||
---
|
||||
builtins/read.def
|
||||
- when testing for a pipe, use `fd' instead of hard-coding 0, since we
|
||||
can read from other file descriptors now
|
||||
|
||||
lib/sh/zread.c
|
||||
- in zsyncfd, only set lind and lused to 0 if the lseek succeeds.
|
||||
If the lseek fails, we might steal input from other programs, but
|
||||
a failed lseek won't cause us to erroneously discard input
|
||||
|
||||
@@ -233,7 +233,8 @@ parse_and_execute (string, from_file, flags)
|
||||
* parse_and_execute has not been called recursively AND
|
||||
* we have parsed the full command (string == '\0') AND
|
||||
* we have a simple command without redirections AND
|
||||
* the command is not being timed
|
||||
* the command is not being timed AND
|
||||
* the command's return status is not being inverted
|
||||
* THEN
|
||||
* tell the execution code that we don't need to fork
|
||||
*/
|
||||
@@ -241,7 +242,8 @@ parse_and_execute (string, from_file, flags)
|
||||
*bash_input.location.string == '\0' &&
|
||||
command->type == cm_simple &&
|
||||
!command->redirects && !command->value.Simple->redirects &&
|
||||
((command->flags & CMD_TIME_PIPELINE) == 0))
|
||||
((command->flags & CMD_TIME_PIPELINE) == 0) &&
|
||||
((command->flags & CMD_INVERT_RETURN) == 0))
|
||||
{
|
||||
command->flags |= CMD_NO_FORK;
|
||||
command->value.Simple->flags |= CMD_NO_FORK;
|
||||
|
||||
@@ -0,0 +1,346 @@
|
||||
/* Copyright (C) 1996 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 2, 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; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "filecntl.h"
|
||||
#include "../bashansi.h"
|
||||
|
||||
#include "../shell.h"
|
||||
#include "../jobs.h"
|
||||
#include "../builtins.h"
|
||||
#include "../flags.h"
|
||||
#include "../input.h"
|
||||
#include "../execute_cmd.h"
|
||||
#include "../redir.h"
|
||||
#include "../trap.h"
|
||||
|
||||
#if defined (HISTORY)
|
||||
# include "../bashhist.h"
|
||||
#endif
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
#define IS_BUILTIN(s) (builtin_address_internal(s, 0) != (struct builtin *)NULL)
|
||||
|
||||
extern int indirection_level, startup_state, subshell_environment;
|
||||
extern int line_number;
|
||||
extern int last_command_exit_value;
|
||||
extern int running_trap;
|
||||
extern int posixly_correct;
|
||||
|
||||
int parse_and_execute_level = 0;
|
||||
|
||||
static int cat_file __P((REDIRECT *));
|
||||
|
||||
/* How to force parse_and_execute () to clean up after itself. */
|
||||
void
|
||||
parse_and_execute_cleanup ()
|
||||
{
|
||||
if (running_trap)
|
||||
{
|
||||
run_trap_cleanup (running_trap - 1);
|
||||
unfreeze_jobs_list ();
|
||||
}
|
||||
run_unwind_frame ("parse_and_execute_top");
|
||||
}
|
||||
|
||||
/* Parse and execute the commands in STRING. Returns whatever
|
||||
execute_command () returns. This frees STRING. FLAGS is a
|
||||
flags word; look in common.h for the possible values. Actions
|
||||
are:
|
||||
(flags & SEVAL_NONINT) -> interactive = 0;
|
||||
(flags & SEVAL_INTERACT) -> interactive = 1;
|
||||
(flags & SEVAL_NOHIST) -> call bash_history_disable ()
|
||||
(flags & SEVAL_NOFREE) -> don't free STRING when finished
|
||||
(flags & SEVAL_RESETLINE) -> reset line_number to 1
|
||||
*/
|
||||
|
||||
int
|
||||
parse_and_execute (string, from_file, flags)
|
||||
char *string;
|
||||
const char *from_file;
|
||||
int flags;
|
||||
{
|
||||
int code, x, lreset;
|
||||
volatile int should_jump_to_top_level, last_result;
|
||||
char *orig_string;
|
||||
COMMAND *volatile command;
|
||||
|
||||
orig_string = string;
|
||||
/* Unwind protect this invocation of parse_and_execute (). */
|
||||
begin_unwind_frame ("parse_and_execute_top");
|
||||
unwind_protect_int (parse_and_execute_level);
|
||||
unwind_protect_jmp_buf (top_level);
|
||||
unwind_protect_int (indirection_level);
|
||||
unwind_protect_int (line_number);
|
||||
if (flags & (SEVAL_NONINT|SEVAL_INTERACT))
|
||||
unwind_protect_int (interactive);
|
||||
|
||||
lreset = flags & SEVAL_RESETLINE;
|
||||
|
||||
#if defined (HISTORY)
|
||||
unwind_protect_int (remember_on_history); /* can be used in scripts */
|
||||
# if defined (BANG_HISTORY)
|
||||
if (interactive_shell)
|
||||
{
|
||||
unwind_protect_int (history_expansion_inhibited);
|
||||
}
|
||||
# endif /* BANG_HISTORY */
|
||||
#endif /* HISTORY */
|
||||
|
||||
if (interactive_shell)
|
||||
{
|
||||
x = get_current_prompt_level ();
|
||||
add_unwind_protect (set_current_prompt_level, x);
|
||||
}
|
||||
|
||||
add_unwind_protect (pop_stream, (char *)NULL);
|
||||
if (orig_string && ((flags & SEVAL_NOFREE) == 0))
|
||||
add_unwind_protect (xfree, orig_string);
|
||||
end_unwind_frame ();
|
||||
|
||||
parse_and_execute_level++;
|
||||
|
||||
/* Reset the line number if the caller wants us to. If we don't reset the
|
||||
line number, we have to subtract one, because we will add one just
|
||||
before executing the next command (resetting the line number sets it to
|
||||
0; the first line number is 1). */
|
||||
push_stream (lreset);
|
||||
if (lreset == 0)
|
||||
line_number--;
|
||||
|
||||
indirection_level++;
|
||||
if (flags & (SEVAL_NONINT|SEVAL_INTERACT))
|
||||
interactive = (flags & SEVAL_NONINT) ? 0 : 1;
|
||||
|
||||
#if defined (HISTORY)
|
||||
if (flags & SEVAL_NOHIST)
|
||||
bash_history_disable ();
|
||||
#endif /* HISTORY */
|
||||
|
||||
code = should_jump_to_top_level = 0;
|
||||
last_result = EXECUTION_SUCCESS;
|
||||
|
||||
with_input_from_string (string, from_file);
|
||||
while (*(bash_input.location.string))
|
||||
{
|
||||
command = (COMMAND *)NULL;
|
||||
|
||||
if (interrupt_state)
|
||||
{
|
||||
last_result = EXECUTION_FAILURE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Provide a location for functions which `longjmp (top_level)' to
|
||||
jump to. This prevents errors in substitution from restarting
|
||||
the reader loop directly, for example. */
|
||||
code = setjmp (top_level);
|
||||
|
||||
if (code)
|
||||
{
|
||||
should_jump_to_top_level = 0;
|
||||
switch (code)
|
||||
{
|
||||
case FORCE_EOF:
|
||||
case ERREXIT:
|
||||
case EXITPROG:
|
||||
if (command)
|
||||
run_unwind_frame ("pe_dispose");
|
||||
/* Remember to call longjmp (top_level) after the old
|
||||
value for it is restored. */
|
||||
should_jump_to_top_level = 1;
|
||||
goto out;
|
||||
|
||||
case DISCARD:
|
||||
if (command)
|
||||
run_unwind_frame ("pe_dispose");
|
||||
last_result = last_command_exit_value = EXECUTION_FAILURE; /* XXX */
|
||||
if (subshell_environment)
|
||||
{
|
||||
should_jump_to_top_level = 1;
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if 0
|
||||
dispose_command (command); /* pe_dispose does this */
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
default:
|
||||
command_error ("parse_and_execute", CMDERR_BADJUMP, code, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (parse_command () == 0)
|
||||
{
|
||||
if (interactive_shell == 0 && read_but_dont_execute)
|
||||
{
|
||||
last_result = EXECUTION_SUCCESS;
|
||||
dispose_command (global_command);
|
||||
global_command = (COMMAND *)NULL;
|
||||
}
|
||||
else if (command = global_command)
|
||||
{
|
||||
struct fd_bitmap *bitmap;
|
||||
|
||||
bitmap = new_fd_bitmap (FD_BITMAP_SIZE);
|
||||
begin_unwind_frame ("pe_dispose");
|
||||
add_unwind_protect (dispose_fd_bitmap, bitmap);
|
||||
add_unwind_protect (dispose_command, command); /* XXX */
|
||||
|
||||
global_command = (COMMAND *)NULL;
|
||||
|
||||
#if defined (ONESHOT)
|
||||
/*
|
||||
* IF
|
||||
* we were invoked as `bash -c' (startup_state == 2) AND
|
||||
* parse_and_execute has not been called recursively AND
|
||||
* we have parsed the full command (string == '\0') AND
|
||||
* we have a simple command without redirections AND
|
||||
* the command is not being timed
|
||||
* THEN
|
||||
* tell the execution code that we don't need to fork
|
||||
*/
|
||||
if (startup_state == 2 && parse_and_execute_level == 1 &&
|
||||
*bash_input.location.string == '\0' &&
|
||||
command->type == cm_simple &&
|
||||
!command->redirects && !command->value.Simple->redirects &&
|
||||
((command->flags & CMD_TIME_PIPELINE) == 0) &&
|
||||
((command->flags & CMD_INVERT_RETURN) == 0))
|
||||
{
|
||||
command->flags |= CMD_NO_FORK;
|
||||
command->value.Simple->flags |= CMD_NO_FORK;
|
||||
}
|
||||
#endif /* ONESHOT */
|
||||
|
||||
/* See if this is a candidate for $( <file ). */
|
||||
if (startup_state == 2 &&
|
||||
(subshell_environment & SUBSHELL_COMSUB) &&
|
||||
*bash_input.location.string == '\0' &&
|
||||
command->type == cm_simple && !command->redirects &&
|
||||
(command->flags & CMD_TIME_PIPELINE) == 0 &&
|
||||
command->value.Simple->words == 0 &&
|
||||
command->value.Simple->redirects &&
|
||||
command->value.Simple->redirects->next == 0 &&
|
||||
command->value.Simple->redirects->instruction == r_input_direction)
|
||||
{
|
||||
int r;
|
||||
r = cat_file (command->value.Simple->redirects);
|
||||
last_result = (r < 0) ? EXECUTION_FAILURE : EXECUTION_SUCCESS;
|
||||
}
|
||||
else
|
||||
last_result = execute_command_internal
|
||||
(command, 0, NO_PIPE, NO_PIPE, bitmap);
|
||||
|
||||
dispose_command (command);
|
||||
dispose_fd_bitmap (bitmap);
|
||||
discard_unwind_frame ("pe_dispose");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
last_result = EXECUTION_FAILURE;
|
||||
|
||||
/* Since we are shell compatible, syntax errors in a script
|
||||
abort the execution of the script. Right? */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
|
||||
run_unwind_frame ("parse_and_execute_top");
|
||||
|
||||
if (interrupt_state && parse_and_execute_level == 0)
|
||||
{
|
||||
/* An interrupt during non-interactive execution in an
|
||||
interactive shell (e.g. via $PROMPT_COMMAND) should
|
||||
not cause the shell to exit. */
|
||||
interactive = interactive_shell;
|
||||
throw_to_top_level ();
|
||||
}
|
||||
|
||||
if (should_jump_to_top_level)
|
||||
jump_to_top_level (code);
|
||||
|
||||
return (last_result);
|
||||
}
|
||||
|
||||
/* Handle a $( < file ) command substitution. This expands the filename,
|
||||
returning errors as appropriate, then just cats the file to the standard
|
||||
output. */
|
||||
static int
|
||||
cat_file (r)
|
||||
REDIRECT *r;
|
||||
{
|
||||
char lbuf[128], *fn;
|
||||
int fd, rval;
|
||||
ssize_t nr;
|
||||
|
||||
if (r->instruction != r_input_direction)
|
||||
return -1;
|
||||
|
||||
/* Get the filename. */
|
||||
if (posixly_correct && !interactive_shell)
|
||||
disallow_filename_globbing++;
|
||||
fn = redirection_expand (r->redirectee.filename);
|
||||
if (posixly_correct && !interactive_shell)
|
||||
disallow_filename_globbing--;
|
||||
|
||||
if (fn == 0)
|
||||
{
|
||||
redirection_error (r, AMBIGUOUS_REDIRECT);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fd = open(fn, O_RDONLY);
|
||||
if (fd < 0)
|
||||
{
|
||||
file_error (fn);
|
||||
free (fn);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rval = zcatfd (fd, 1, fn);
|
||||
|
||||
free (fn);
|
||||
close (fd);
|
||||
|
||||
return (rval);
|
||||
}
|
||||
+1
-1
@@ -276,7 +276,7 @@ read_builtin (list)
|
||||
input_is_tty = isatty (fd);
|
||||
if (input_is_tty == 0)
|
||||
#ifndef __CYGWIN__
|
||||
input_is_pipe = (lseek (0, 0L, SEEK_CUR) < 0) && (errno == ESPIPE);
|
||||
input_is_pipe = (lseek (fd, 0L, SEEK_CUR) < 0) && (errno == ESPIPE);
|
||||
#else
|
||||
input_is_pipe = 1;
|
||||
#endif
|
||||
|
||||
+6
-2
@@ -124,9 +124,13 @@ zsyncfd (fd)
|
||||
int fd;
|
||||
{
|
||||
off_t off;
|
||||
int r;
|
||||
|
||||
off = lused - lind;
|
||||
r = 0;
|
||||
if (off > 0)
|
||||
lseek (fd, -off, SEEK_CUR);
|
||||
lused = lind = 0;
|
||||
r = lseek (fd, -off, SEEK_CUR);
|
||||
|
||||
if (r >= 0)
|
||||
lused = lind = 0;
|
||||
}
|
||||
|
||||
@@ -3,5 +3,6 @@
|
||||
|
||||
echo "warning: some of these tests will fail if you do not have UTF-8" >&2
|
||||
echo "warning: locales installed on your system." >&2
|
||||
echo "warning: please ignore any differences consisting only of white space" >&2
|
||||
${THIS_SH} ./intl.tests > /tmp/xx
|
||||
diff $AFLAG /tmp/xx intl.right && rm -f /tmp/xx
|
||||
|
||||
+4
-1
@@ -1,4 +1,7 @@
|
||||
# See whether or not we can use `diff -a'
|
||||
( diff -a ./intl.right ./intl.right >/dev/null 2>&1 ) && AFLAG=-a
|
||||
|
||||
echo "warning: some of these tests will fail if you do not have UTF-8" >&2
|
||||
echo "warning: locales installed on your system." >&2
|
||||
${THIS_SH} ./intl.tests > /tmp/xx
|
||||
diff /tmp/xx intl.right && rm -f /tmp/xx
|
||||
diff $AFLAG /tmp/xx intl.right && rm -f /tmp/xx
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
echo "warning: different versions of wc put differing amounts of whitespace" >&2
|
||||
echo "warning: before their output. Please do not consider this an error." >&2
|
||||
echo "warning: please do not consider output differing only in the amount of" >&2
|
||||
echo "warning: white space to be an error." >&2
|
||||
${THIS_SH} ./read.tests > /tmp/xx 2>&1
|
||||
diff /tmp/xx read.right && rm -f /tmp/xx
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
echo "warning: different versions of wc put differing amounts of whitespace" >&2
|
||||
echo "warning: before their output. Please do not consider this an error." >&2
|
||||
${THIS_SH} ./read.tests > /tmp/xx 2>&1
|
||||
diff /tmp/xx read.right && rm -f /tmp/xx
|
||||
Reference in New Issue
Block a user