mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-06-27 07:43:07 +02:00
commit bash-20080522 snapshot
This commit is contained in:
+100
-2
@@ -15738,8 +15738,6 @@ lib/readline/readline.h
|
||||
|
||||
5/8
|
||||
---
|
||||
lib/readline/bind.c
|
||||
|
||||
lib/readline/complete.c
|
||||
- add support for a third argument to fnprint and print_filename,
|
||||
which supports replacing a specified portion of the pathnames
|
||||
@@ -15812,6 +15810,9 @@ lib/readline/display.c
|
||||
- in update_line, when fixing _rl_last_c_pos after drawing the first
|
||||
line of the prompt, use the number of invisible chars on the first
|
||||
line as the offset, instead of the total number of invisible chars
|
||||
- use prompt_multibyte_characters, the number of multibyte chars in
|
||||
the prompt string, to short-circuit some relatively expensive
|
||||
multibyte text processing in rl_redisplay
|
||||
|
||||
5/21
|
||||
----
|
||||
@@ -15834,3 +15835,100 @@ bashline.c
|
||||
|
||||
bashline.h
|
||||
- new extern declaration for bashline_reset()
|
||||
|
||||
5/23
|
||||
----
|
||||
bashhist.c
|
||||
- new function, bash_clear_history, clears the history and resets any
|
||||
associated internal bash state
|
||||
|
||||
bashhist.h
|
||||
- extern declaration for bash_clear_history
|
||||
|
||||
builtins/history.def
|
||||
- call bash_clear_history instead of clear_history for `history -c'.
|
||||
Fixes part of problem reported by Scott McDermott
|
||||
<scott.m.mcdermott@gmail.com>
|
||||
- decrement history_lines_this_session in delete_histent, called for
|
||||
`history -d'
|
||||
|
||||
builtins/history.def,bashhist.[ch]
|
||||
- move delete_histent() to bashhist.c; rename to bash_delete_histent
|
||||
- move delete_last_history() to bashhist.c; rename to
|
||||
bash_delete_last_history()
|
||||
|
||||
5/25
|
||||
----
|
||||
braces.c
|
||||
- add another parameter to mkseq(), the number of digits to put into
|
||||
each member of a numeric sequence (width), changes to determine
|
||||
any zero-padding go into expand_seqterm
|
||||
- changes to expand_seqterm to allow user-specified increments
|
||||
|
||||
bashline.[ch],shell.c,sig.c
|
||||
- switched names of bashline_reinitialize and bashline_reset to better
|
||||
reflect their functions
|
||||
- when searching $PATH for directories to use for command completion,
|
||||
make sure to free `current_path' before going out of scope
|
||||
- new bindable function `dabbrev-expand', which is more or less
|
||||
menu completion using dynamic history completion as the generator
|
||||
- changes to bash_execute_unix_command to set variables for the
|
||||
executed command like programmable completion: READLINE_LINE
|
||||
(rl_line_buffer) and READLINE_POINT (rl_point)
|
||||
- change to bash_execute_unix_command to allow the executed command
|
||||
to change the readline line buffer by modifying the value of
|
||||
READLINE_LINE and to change rl_point by modifying the value of
|
||||
READLINE_POINT
|
||||
|
||||
common.h
|
||||
- new SEVAL_ defines for later parse_string changes from 4.0-devel
|
||||
branch
|
||||
|
||||
command.h
|
||||
- new defines for new &>> r_append_err_and_out redirection
|
||||
|
||||
builtins/evalstring.c
|
||||
- new function, parse_string, parses a command from a passed string
|
||||
and returns the number of characters consumed. For satisfying
|
||||
Posix rules when parsing command substitutions, from bash-4.0-devel
|
||||
branch
|
||||
- split out common prolog code from parse_string and
|
||||
parse_and_execute into a separate function called from both
|
||||
|
||||
parse.y
|
||||
- small changes to add symbols needed for parse_string
|
||||
- parser change to add `|&' as synonym for `2>&1 |'; translation is
|
||||
performed at parse time so |& never shows up in output of
|
||||
print_command, for instance. Picked up from zsh, merged in from
|
||||
bash-4.0-devel branch
|
||||
|
||||
parse.y,{redir,copy_cmd,dispose_cmd,make_cmd,print_cmd}.c
|
||||
- implement new &>> r_append_err_and_out (like >>foo 2>&1); merged
|
||||
in from bash-4.0-devel branch
|
||||
|
||||
doc/{bash.1,bashref.texi},lib/readline/doc/rluser.texi
|
||||
- document new optional increment in brace expansion
|
||||
- document new zero-padded fixed-width integer brace expansion
|
||||
- document new `dabbrev-expand' bindable readline command
|
||||
- document new effects of `bind -x' setting and reading the values of
|
||||
READLINE_LINE and READLINE_POINT
|
||||
- document new |& synonym for `2>&1 |' pipeline operator
|
||||
|
||||
5/26
|
||||
----
|
||||
parse.y
|
||||
- recognize new ;& and ;;& case action list terminator tokens and
|
||||
implement them in the grammar, setting CASEPAT_FALLTHROUGH and
|
||||
CASEPAT_TESTNEXT flags as appropriate
|
||||
|
||||
print_cmd.c
|
||||
- print new ;& and ;;& case clause action list terminators as
|
||||
appropriate
|
||||
|
||||
execute_cmd.c
|
||||
- implement new case clause action list terminators:
|
||||
;& - fall through to actions associated with next pattern list
|
||||
;;& - fall through to tests in next pattern list
|
||||
|
||||
doc/{bash.1,bashref.texi}
|
||||
- document new ;& and ;;& case clause action list terminators
|
||||
|
||||
+90
-2
@@ -15738,8 +15738,6 @@ lib/readline/readline.h
|
||||
|
||||
5/8
|
||||
---
|
||||
lib/readline/bind.c
|
||||
|
||||
lib/readline/complete.c
|
||||
- add support for a third argument to fnprint and print_filename,
|
||||
which supports replacing a specified portion of the pathnames
|
||||
@@ -15812,6 +15810,9 @@ lib/readline/display.c
|
||||
- in update_line, when fixing _rl_last_c_pos after drawing the first
|
||||
line of the prompt, use the number of invisible chars on the first
|
||||
line as the offset, instead of the total number of invisible chars
|
||||
- use prompt_multibyte_characters, the number of multibyte chars in
|
||||
the prompt string, to short-circuit some relatively expensive
|
||||
multibyte text processing in rl_redisplay
|
||||
|
||||
5/21
|
||||
----
|
||||
@@ -15822,6 +15823,93 @@ variables.c
|
||||
|
||||
shell.c
|
||||
- shell_reinitialize now calls reinit_special_variables
|
||||
- shell_reinitialize now calls bashline_reset
|
||||
|
||||
variables.h
|
||||
- new extern declaration for reinit_special_variables
|
||||
|
||||
bashline.c
|
||||
- new function, bashline_reset(), called when the shell reinitializes
|
||||
in shell_reinitialize. Right now, just resets
|
||||
bash_readline_initialized to 0.
|
||||
|
||||
bashline.h
|
||||
- new extern declaration for bashline_reset()
|
||||
|
||||
5/23
|
||||
----
|
||||
bashhist.c
|
||||
- new function, bash_clear_history, clears the history and resets any
|
||||
associated internal bash state
|
||||
|
||||
bashhist.h
|
||||
- extern declaration for bash_clear_history
|
||||
|
||||
builtins/history.def
|
||||
- call bash_clear_history instead of clear_history for `history -c'.
|
||||
Fixes part of problem reported by Scott McDermott
|
||||
<scott.m.mcdermott@gmail.com>
|
||||
- decrement history_lines_this_session in delete_histent, called for
|
||||
`history -d'
|
||||
|
||||
builtins/history.def,bashhist.[ch]
|
||||
- move delete_histent() to bashhist.c; rename to bash_delete_histent
|
||||
- move delete_last_history() to bashhist.c; rename to
|
||||
bash_delete_last_history()
|
||||
|
||||
5/25
|
||||
----
|
||||
braces.c
|
||||
- add another parameter to mkseq(), the number of digits to put into
|
||||
each member of a numeric sequence (width), changes to determine
|
||||
any zero-padding go into expand_seqterm
|
||||
- changes to expand_seqterm to allow user-specified increments
|
||||
|
||||
bashline.[ch],shell.c,sig.c
|
||||
- switched names of bashline_reinitialize and bashline_reset to better
|
||||
reflect their functions
|
||||
- when searching $PATH for directories to use for command completion,
|
||||
make sure to free `current_path' before going out of scope
|
||||
- new bindable function `dabbrev-expand', which is more or less
|
||||
menu completion using dynamic history completion as the generator
|
||||
- changes to bash_execute_unix_command to set variables for the
|
||||
executed command like programmable completion: READLINE_LINE
|
||||
(rl_line_buffer) and READLINE_POINT (rl_point)
|
||||
- change to bash_execute_unix_command to allow the executed command
|
||||
to change the readline line buffer by modifying the value of
|
||||
READLINE_LINE and to change rl_point by modifying the value of
|
||||
READLINE_POINT
|
||||
|
||||
common.h
|
||||
- new SEVAL_ defines for later parse_string changes from 4.0-devel
|
||||
branch
|
||||
|
||||
command.h
|
||||
- new defines for new &>> r_append_err_and_out redirection
|
||||
|
||||
builtins/evalstring.c
|
||||
- new function, parse_string, parses a command from a passed string
|
||||
and returns the number of characters consumed. For satisfying
|
||||
Posix rules when parsing command substitutions, from bash-4.0-devel
|
||||
branch
|
||||
- split out common prolog code from parse_string and
|
||||
parse_and_execute into a separate function called from both
|
||||
|
||||
parse.y
|
||||
- small changes to add symbols needed for parse_string
|
||||
- parser change to add `|&' as synonym for `2>&1 |'; translation is
|
||||
performed at parse time so |& never shows up in output of
|
||||
print_command, for instance. Picked up from zsh, merged in from
|
||||
bash-4.0-devel branch
|
||||
|
||||
parse.y,{redir,copy_cmd,dispose_cmd,make_cmd,print_cmd}.c
|
||||
- implement new &>> r_append_err_and_out (like >>foo 2>&1); merged
|
||||
in from bash-4.0-devel branch
|
||||
|
||||
doc/{bash.1,bashref.texi},lib/readline/doc/rluser.texi
|
||||
- document new optional increment in brace expansion
|
||||
- document new zero-padded fixed-width integer brace expansion
|
||||
- document new `dabbrev-expand' bindable readline command
|
||||
- document new effects of `bind -x' setting and reading the values of
|
||||
READLINE_LINE and READLINE_POINT
|
||||
- document new |& synonym for `2>&1 |' pipeline operator
|
||||
|
||||
@@ -759,6 +759,8 @@ tests/source3.sub f
|
||||
tests/source4.sub f
|
||||
tests/source5.sub f
|
||||
tests/source6.sub f
|
||||
tests/case.tests f
|
||||
tests/case.right f
|
||||
tests/comsub.tests f
|
||||
tests/comsub.right f
|
||||
tests/cond.tests f
|
||||
@@ -906,6 +908,7 @@ tests/redir5.sub f
|
||||
tests/redir6.sub f
|
||||
tests/redir7.sub f
|
||||
tests/redir8.sub f
|
||||
tests/redir9.sub f
|
||||
tests/rhs-exp.tests f
|
||||
tests/rhs-exp.right f
|
||||
tests/rsh.tests f
|
||||
@@ -920,6 +923,7 @@ tests/run-array f
|
||||
tests/run-array2 f
|
||||
tests/run-braces f
|
||||
tests/run-builtins f
|
||||
tests/run-case f
|
||||
tests/run-comsub f
|
||||
tests/run-cond f
|
||||
tests/run-cprint f
|
||||
@@ -996,6 +1000,7 @@ tests/trap2.sub f 755
|
||||
tests/trap2a.sub f 755
|
||||
tests/type.tests f
|
||||
tests/type.right f
|
||||
tests/type1.sub f
|
||||
tests/varenv.right f
|
||||
tests/varenv.sh f
|
||||
tests/varenv1.sub f
|
||||
|
||||
@@ -552,6 +552,7 @@ doc/fdl.texi f
|
||||
doc/fdl.txt f
|
||||
support/Makefile.in f
|
||||
support/bashversion.c f
|
||||
support/checkbashisms f 755
|
||||
support/config.guess f
|
||||
support/config.rpath f 755
|
||||
support/config.sub f
|
||||
@@ -905,6 +906,7 @@ tests/redir5.sub f
|
||||
tests/redir6.sub f
|
||||
tests/redir7.sub f
|
||||
tests/redir8.sub f
|
||||
tests/redir9.sub f
|
||||
tests/rhs-exp.tests f
|
||||
tests/rhs-exp.right f
|
||||
tests/rsh.tests f
|
||||
@@ -995,6 +997,7 @@ tests/trap2.sub f 755
|
||||
tests/trap2a.sub f 755
|
||||
tests/type.tests f
|
||||
tests/type.right f
|
||||
tests/type1.sub f
|
||||
tests/varenv.right f
|
||||
tests/varenv.sh f
|
||||
tests/varenv1.sub f
|
||||
|
||||
+50
@@ -288,6 +288,56 @@ load_history ()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bash_clear_history ()
|
||||
{
|
||||
clear_history ();
|
||||
history_lines_this_session = 0;
|
||||
}
|
||||
|
||||
/* Delete and free the history list entry at offset I. */
|
||||
int
|
||||
bash_delete_histent (i)
|
||||
int i;
|
||||
{
|
||||
HIST_ENTRY *discard;
|
||||
|
||||
discard = remove_history (i);
|
||||
if (discard)
|
||||
free_history_entry (discard);
|
||||
history_lines_this_session--;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
bash_delete_last_history ()
|
||||
{
|
||||
register int i;
|
||||
HIST_ENTRY **hlist, *histent;
|
||||
int r;
|
||||
|
||||
hlist = history_list ();
|
||||
if (hlist == NULL)
|
||||
return 0;
|
||||
|
||||
for (i = 0; hlist[i]; i++)
|
||||
;
|
||||
i--;
|
||||
|
||||
/* History_get () takes a parameter that must be offset by history_base. */
|
||||
histent = history_get (history_base + i); /* Don't free this */
|
||||
if (histent == NULL)
|
||||
return 0;
|
||||
|
||||
r = bash_delete_histent (i);
|
||||
|
||||
if (where_history () > history_length)
|
||||
history_set_pos (history_length);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
#ifdef INCLUDE_UNUSED
|
||||
/* Write the existing history out to the history file. */
|
||||
void
|
||||
|
||||
+23
-1
@@ -251,7 +251,7 @@ bash_history_disable ()
|
||||
void
|
||||
bash_history_enable ()
|
||||
{
|
||||
remember_on_history = enable_history_list = 1;
|
||||
remember_on_history = 1;
|
||||
#if defined (BANG_HISTORY)
|
||||
history_expansion_inhibited = 0;
|
||||
#endif
|
||||
@@ -288,6 +288,28 @@ load_history ()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bash_clear_history ()
|
||||
{
|
||||
clear_history ();
|
||||
history_lines_this_session = 0;
|
||||
}
|
||||
|
||||
/* Delete and free the history list entry at offset I. */
|
||||
int
|
||||
bash_delete_histent (i)
|
||||
int i;
|
||||
{
|
||||
HIST_ENTRY *discard;
|
||||
|
||||
discard = remove_history (i);
|
||||
if (discard)
|
||||
free_history_entry (discard);
|
||||
history_lines_this_session--;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef INCLUDE_UNUSED
|
||||
/* Write the existing history out to the history file. */
|
||||
void
|
||||
|
||||
@@ -49,6 +49,9 @@ extern void bash_initialize_history __P((void));
|
||||
extern void bash_history_reinit __P((int));
|
||||
extern void bash_history_disable __P((void));
|
||||
extern void bash_history_enable __P((void));
|
||||
extern void bash_clear_history __P((void));
|
||||
extern int bash_delete_histent __P((int));
|
||||
extern int bash_delete_last_history __P((void));
|
||||
extern void load_history __P((void));
|
||||
extern void save_history __P((void));
|
||||
extern int maybe_append_history __P((char *));
|
||||
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
/* bashhist.h -- interface to the bash history functions in bashhist.c. */
|
||||
|
||||
/* Copyright (C) 1993 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. */
|
||||
|
||||
#if !defined (_BASHHIST_H_)
|
||||
#define _BASHHIST_H_
|
||||
|
||||
#include "stdc.h"
|
||||
|
||||
/* Flag values for history_control */
|
||||
#define HC_IGNSPACE 0x01
|
||||
#define HC_IGNDUPS 0x02
|
||||
#define HC_ERASEDUPS 0x04
|
||||
|
||||
#define HC_IGNBOTH (HC_IGNSPACE|HC_IGNDUPS)
|
||||
|
||||
extern int remember_on_history;
|
||||
extern int enable_history_list; /* value for `set -o history' */
|
||||
extern int history_lines_this_session;
|
||||
extern int history_lines_in_file;
|
||||
extern int history_expansion;
|
||||
extern int history_control;
|
||||
extern int command_oriented_history;
|
||||
extern int current_command_first_line_saved;
|
||||
extern int hist_last_line_added;
|
||||
extern int hist_last_line_pushed;
|
||||
|
||||
# if defined (BANG_HISTORY)
|
||||
extern int history_expansion_inhibited;
|
||||
# endif /* BANG_HISTORY */
|
||||
|
||||
extern void bash_initialize_history __P((void));
|
||||
extern void bash_history_reinit __P((int));
|
||||
extern void bash_history_disable __P((void));
|
||||
extern void bash_history_enable __P((void));
|
||||
extern void bash_clear_history __P((void));
|
||||
extern int bash_delete_histent __P((int));
|
||||
extern void load_history __P((void));
|
||||
extern void save_history __P((void));
|
||||
extern int maybe_append_history __P((char *));
|
||||
extern int maybe_save_shell_history __P((void));
|
||||
extern char *pre_process_line __P((char *, int, int));
|
||||
extern void maybe_add_history __P((char *));
|
||||
extern void bash_add_history __P((char *));
|
||||
extern int check_add_history __P((char *, int));
|
||||
extern int history_number __P((void));
|
||||
|
||||
extern void setup_history_ignore __P((char *));
|
||||
|
||||
extern char *last_history_line __P((void));
|
||||
|
||||
#endif /* _BASHHIST_H_ */
|
||||
+75
-11
@@ -122,6 +122,7 @@ static char *command_subst_completion_function __P((const char *, int));
|
||||
static void build_history_completion_array __P((void));
|
||||
static char *history_completion_generator __P((const char *, int));
|
||||
static int dynamic_complete_history __P((int, int));
|
||||
static int bash_dabbrev_expand __P((int, int));
|
||||
|
||||
static void initialize_hostname_list __P((void));
|
||||
static void add_host_name __P((char *));
|
||||
@@ -162,6 +163,7 @@ extern int hist_verify;
|
||||
#endif
|
||||
|
||||
extern int current_command_line_count, last_command_exit_value;
|
||||
extern int array_needs_making;
|
||||
extern int posixly_correct, no_symbolic_links;
|
||||
extern char *current_prompt_string, *ps1_prompt;
|
||||
extern STRING_INT_ALIST word_token_alist[];
|
||||
@@ -331,7 +333,7 @@ enable_hostname_completion (on_or_off)
|
||||
free (rl_completer_word_break_characters);
|
||||
rl_completer_word_break_characters = nval;
|
||||
}
|
||||
itrace("enable_hostname_completion: rl_completer_word_break_characters = %s", rl_completer_word_break_characters);
|
||||
|
||||
return (old_value);
|
||||
}
|
||||
|
||||
@@ -395,6 +397,7 @@ initialize_readline ()
|
||||
#endif
|
||||
|
||||
rl_add_defun ("dynamic-complete-history", dynamic_complete_history, -1);
|
||||
rl_add_defun ("dabbrev-expand", bash_dabbrev_expand, -1);
|
||||
|
||||
/* Bind defaults before binding our custom shell keybindings. */
|
||||
if (RL_ISSTATE(RL_STATE_INITIALIZED) == 0)
|
||||
@@ -514,7 +517,7 @@ initialize_readline ()
|
||||
}
|
||||
|
||||
void
|
||||
bashline_reset ()
|
||||
bashline_reinitialize ()
|
||||
{
|
||||
bash_readline_initialized = 0;
|
||||
}
|
||||
@@ -525,7 +528,7 @@ bashline_reset ()
|
||||
word. This just resets all the completion functions to the right thing.
|
||||
It's called from throw_to_top_level(). */
|
||||
void
|
||||
bashline_reinitialize ()
|
||||
bashline_reset ()
|
||||
{
|
||||
tilde_initialize ();
|
||||
rl_attempted_completion_function = attempt_shell_completion;
|
||||
@@ -1508,7 +1511,7 @@ globword:
|
||||
|
||||
/* Get the next directory from the path. If there is none, then we
|
||||
are all done. */
|
||||
if (!path || !path[path_index] ||
|
||||
if (path == 0 || path[path_index] == 0 ||
|
||||
(current_path = extract_colon_unit (path, &path_index)) == 0)
|
||||
return ((char *)NULL);
|
||||
|
||||
@@ -1535,6 +1538,7 @@ globword:
|
||||
free (filename_hint);
|
||||
|
||||
filename_hint = sh_makepath (current_path, hint, 0);
|
||||
free (current_path); /* XXX */
|
||||
}
|
||||
|
||||
inner:
|
||||
@@ -2427,7 +2431,7 @@ bash_directory_expansion (dirname)
|
||||
*dirname = nd;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Handle symbolic link references and other directory name
|
||||
expansions while hacking completion. */
|
||||
static int
|
||||
@@ -2614,12 +2618,12 @@ dynamic_complete_history (count, key)
|
||||
int count, key;
|
||||
{
|
||||
int r;
|
||||
|
||||
rl_compentry_func_t *orig_func;
|
||||
rl_completion_func_t *orig_attempt_func;
|
||||
|
||||
orig_func = rl_completion_entry_function;
|
||||
orig_attempt_func = rl_attempted_completion_function;
|
||||
|
||||
rl_completion_entry_function = history_completion_generator;
|
||||
rl_attempted_completion_function = (rl_completion_func_t *)NULL;
|
||||
|
||||
@@ -2634,6 +2638,33 @@ dynamic_complete_history (count, key)
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
bash_dabbrev_expand (count, key)
|
||||
int count, key;
|
||||
{
|
||||
int r;
|
||||
rl_compentry_func_t *orig_func;
|
||||
rl_completion_func_t *orig_attempt_func;
|
||||
|
||||
orig_func = rl_menu_completion_entry_function;
|
||||
orig_attempt_func = rl_attempted_completion_function;
|
||||
|
||||
rl_menu_completion_entry_function = history_completion_generator;
|
||||
rl_attempted_completion_function = (rl_completion_func_t *)NULL;
|
||||
rl_filename_completion_desired = 0;
|
||||
|
||||
/* XXX - use rl_completion_mode here? */
|
||||
if (rl_last_func == bash_dabbrev_expand)
|
||||
rl_last_func = rl_menu_complete;
|
||||
r = rl_menu_complete (count, key);
|
||||
|
||||
rl_last_func = bash_dabbrev_expand;
|
||||
rl_menu_completion_entry_function = orig_func;
|
||||
rl_attempted_completion_function = orig_attempt_func;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
#if defined (SPECIFIC_COMPLETION_FUNCTIONS)
|
||||
static int
|
||||
bash_complete_username (ignore, ignore2)
|
||||
@@ -3133,8 +3164,12 @@ bash_execute_unix_command (count, key)
|
||||
Keymap ckmap; /* current keymap */
|
||||
Keymap xkmap; /* unix command executing keymap */
|
||||
register int i;
|
||||
char *cmd;
|
||||
intmax_t mi;
|
||||
int save_point;
|
||||
sh_parser_state_t ps;
|
||||
char *cmd, *value, *l;
|
||||
SHELL_VAR *v;
|
||||
char ibuf[INT_STRLEN_BOUND(int) + 1];
|
||||
|
||||
/* First, we need to find the right command to execute. This is tricky,
|
||||
because we might have already indirected into another keymap. */
|
||||
@@ -3170,13 +3205,42 @@ bash_execute_unix_command (count, key)
|
||||
|
||||
rl_crlf (); /* move to a new line */
|
||||
|
||||
v = bind_variable ("READLINE_LINE", rl_line_buffer, 0);
|
||||
if (v)
|
||||
VSETATTR (v, att_exported);
|
||||
l = value_cell (v);
|
||||
save_point = rl_point;
|
||||
value = inttostr (rl_point, ibuf, sizeof (ibuf));
|
||||
v = bind_int_variable ("READLINE_POINT", value);
|
||||
if (v)
|
||||
VSETATTR (v, att_exported);
|
||||
array_needs_making = 1;
|
||||
|
||||
save_parser_state (&ps);
|
||||
|
||||
cmd = savestring (cmd);
|
||||
parse_and_execute (cmd, "bash_execute_unix_command", SEVAL_NOHIST);
|
||||
|
||||
parse_and_execute (cmd, "bash_execute_unix_command", SEVAL_NOHIST|SEVAL_NOFREE);
|
||||
restore_parser_state (&ps);
|
||||
|
||||
v = find_variable ("READLINE_LINE");
|
||||
if (value_cell (v) != l)
|
||||
maybe_make_readline_line (value_cell (v));
|
||||
v = find_variable ("READLINE_POINT");
|
||||
if (v && legal_number (value_cell (v), &mi))
|
||||
{
|
||||
i = mi;
|
||||
if (i != save_point)
|
||||
{
|
||||
rl_point = i;
|
||||
if (rl_point > rl_end)
|
||||
rl_point = rl_end;
|
||||
else if (rl_point < 0)
|
||||
rl_point = 0;
|
||||
}
|
||||
}
|
||||
|
||||
unbind_variable ("READLINE_LINE");
|
||||
unbind_variable ("READLINE_POINT");
|
||||
array_needs_making = 1;
|
||||
|
||||
/* and restore the readline buffer and display after command execution. */
|
||||
rl_forced_update_display ();
|
||||
return 0;
|
||||
|
||||
+64
-10
@@ -122,6 +122,7 @@ static char *command_subst_completion_function __P((const char *, int));
|
||||
static void build_history_completion_array __P((void));
|
||||
static char *history_completion_generator __P((const char *, int));
|
||||
static int dynamic_complete_history __P((int, int));
|
||||
static int bash_dabbrev_expand __P((int, int));
|
||||
|
||||
static void initialize_hostname_list __P((void));
|
||||
static void add_host_name __P((char *));
|
||||
@@ -162,6 +163,7 @@ extern int hist_verify;
|
||||
#endif
|
||||
|
||||
extern int current_command_line_count, last_command_exit_value;
|
||||
extern int array_needs_making;
|
||||
extern int posixly_correct, no_symbolic_links;
|
||||
extern char *current_prompt_string, *ps1_prompt;
|
||||
extern STRING_INT_ALIST word_token_alist[];
|
||||
@@ -331,7 +333,7 @@ enable_hostname_completion (on_or_off)
|
||||
free (rl_completer_word_break_characters);
|
||||
rl_completer_word_break_characters = nval;
|
||||
}
|
||||
itrace("enable_hostname_completion: rl_completer_word_break_characters = %s", rl_completer_word_break_characters);
|
||||
|
||||
return (old_value);
|
||||
}
|
||||
|
||||
@@ -395,6 +397,7 @@ initialize_readline ()
|
||||
#endif
|
||||
|
||||
rl_add_defun ("dynamic-complete-history", dynamic_complete_history, -1);
|
||||
rl_add_defun ("dabbrev-expand", bash_dabbrev_expand, -1);
|
||||
|
||||
/* Bind defaults before binding our custom shell keybindings. */
|
||||
if (RL_ISSTATE(RL_STATE_INITIALIZED) == 0)
|
||||
@@ -513,13 +516,19 @@ initialize_readline ()
|
||||
bash_readline_initialized = 1;
|
||||
}
|
||||
|
||||
void
|
||||
bashline_reinitialize ()
|
||||
{
|
||||
bash_readline_initialized = 0;
|
||||
}
|
||||
|
||||
/* On Sun systems at least, rl_attempted_completion_function can end up
|
||||
getting set to NULL, and rl_completion_entry_function set to do command
|
||||
word completion if Bash is interrupted while trying to complete a command
|
||||
word. This just resets all the completion functions to the right thing.
|
||||
It's called from throw_to_top_level(). */
|
||||
void
|
||||
bashline_reinitialize ()
|
||||
bashline_reset ()
|
||||
{
|
||||
tilde_initialize ();
|
||||
rl_attempted_completion_function = attempt_shell_completion;
|
||||
@@ -1502,7 +1511,7 @@ globword:
|
||||
|
||||
/* Get the next directory from the path. If there is none, then we
|
||||
are all done. */
|
||||
if (!path || !path[path_index] ||
|
||||
if (path == 0 || path[path_index] == 0 ||
|
||||
(current_path = extract_colon_unit (path, &path_index)) == 0)
|
||||
return ((char *)NULL);
|
||||
|
||||
@@ -1529,6 +1538,7 @@ globword:
|
||||
free (filename_hint);
|
||||
|
||||
filename_hint = sh_makepath (current_path, hint, 0);
|
||||
free (current_path); /* XXX */
|
||||
}
|
||||
|
||||
inner:
|
||||
@@ -2421,7 +2431,7 @@ bash_directory_expansion (dirname)
|
||||
*dirname = nd;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Handle symbolic link references and other directory name
|
||||
expansions while hacking completion. */
|
||||
static int
|
||||
@@ -2608,12 +2618,12 @@ dynamic_complete_history (count, key)
|
||||
int count, key;
|
||||
{
|
||||
int r;
|
||||
|
||||
rl_compentry_func_t *orig_func;
|
||||
rl_completion_func_t *orig_attempt_func;
|
||||
|
||||
orig_func = rl_completion_entry_function;
|
||||
orig_attempt_func = rl_attempted_completion_function;
|
||||
|
||||
rl_completion_entry_function = history_completion_generator;
|
||||
rl_attempted_completion_function = (rl_completion_func_t *)NULL;
|
||||
|
||||
@@ -2628,6 +2638,33 @@ dynamic_complete_history (count, key)
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
bash_dabbrev_expand (count, key)
|
||||
int count, key;
|
||||
{
|
||||
int r;
|
||||
rl_compentry_func_t *orig_func;
|
||||
rl_completion_func_t *orig_attempt_func;
|
||||
|
||||
orig_func = rl_menu_completion_entry_function;
|
||||
orig_attempt_func = rl_attempted_completion_function;
|
||||
|
||||
rl_menu_completion_entry_function = history_completion_generator;
|
||||
rl_attempted_completion_function = (rl_completion_func_t *)NULL;
|
||||
rl_filename_completion_desired = 0;
|
||||
|
||||
/* XXX - use rl_completion_mode here? */
|
||||
if (rl_last_func == bash_dabbrev_expand)
|
||||
rl_last_func = rl_menu_complete;
|
||||
r = rl_menu_complete (count, key);
|
||||
|
||||
rl_last_func = bash_dabbrev_expand;
|
||||
rl_menu_completion_entry_function = orig_func;
|
||||
rl_attempted_completion_function = orig_attempt_func;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
#if defined (SPECIFIC_COMPLETION_FUNCTIONS)
|
||||
static int
|
||||
bash_complete_username (ignore, ignore2)
|
||||
@@ -3127,8 +3164,10 @@ bash_execute_unix_command (count, key)
|
||||
Keymap ckmap; /* current keymap */
|
||||
Keymap xkmap; /* unix command executing keymap */
|
||||
register int i;
|
||||
char *cmd;
|
||||
sh_parser_state_t ps;
|
||||
char *cmd, *value, *l;
|
||||
SHELL_VAR *v;
|
||||
char ibuf[INT_STRLEN_BOUND(int) + 1];
|
||||
|
||||
/* First, we need to find the right command to execute. This is tricky,
|
||||
because we might have already indirected into another keymap. */
|
||||
@@ -3164,13 +3203,28 @@ bash_execute_unix_command (count, key)
|
||||
|
||||
rl_crlf (); /* move to a new line */
|
||||
|
||||
v = bind_variable ("READLINE_LINE", rl_line_buffer, 0);
|
||||
if (v)
|
||||
VSETATTR (v, att_exported);
|
||||
l = value_cell (v);
|
||||
value = inttostr (rl_point, ibuf, sizeof (ibuf));
|
||||
v = bind_int_variable ("READLINE_POINT", value);
|
||||
if (v)
|
||||
VSETATTR (v, att_exported);
|
||||
array_needs_making = 1;
|
||||
|
||||
save_parser_state (&ps);
|
||||
|
||||
cmd = savestring (cmd);
|
||||
parse_and_execute (cmd, "bash_execute_unix_command", SEVAL_NOHIST);
|
||||
|
||||
parse_and_execute (cmd, "bash_execute_unix_command", SEVAL_NOHIST|SEVAL_NOFREE);
|
||||
restore_parser_state (&ps);
|
||||
|
||||
v = find_variable ("READLINE_LINE");
|
||||
if (value_cell (v) != l)
|
||||
maybe_make_readline_line (value_cell (v));
|
||||
|
||||
unbind_variable ("READLINE_LINE");
|
||||
unbind_variable ("READLINE_POINT");
|
||||
array_needs_making = 1;
|
||||
|
||||
/* and restore the readline buffer and display after command execution. */
|
||||
rl_forced_update_display ();
|
||||
return 0;
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/* bashline.h -- interface to the bash readline functions in bashline.c. */
|
||||
|
||||
/* Copyright (C) 1993 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1993-2008 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ extern int bash_readline_initialized;
|
||||
extern void posix_readline_initialize __P((int));
|
||||
extern int enable_hostname_completion __P((int));
|
||||
extern void initialize_readline __P((void));
|
||||
extern void bashline_reset __P((void));
|
||||
extern void bashline_reinitialize __P((void));
|
||||
extern int bash_re_edit __P((char *));
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* braces.c -- code for doing word expansion in curly braces. */
|
||||
|
||||
/* Copyright (C) 1987-2003 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1987-2008 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
@@ -61,7 +61,7 @@ static const int brace_arg_separator = ',';
|
||||
static int brace_gobbler __P((char *, size_t, int *, int));
|
||||
static char **expand_amble __P((char *, size_t, int));
|
||||
static char **expand_seqterm __P((char *, size_t));
|
||||
static char **mkseq __P((int, int, int, int));
|
||||
static char **mkseq __P((int, int, int, int, int));
|
||||
static char **array_concat __P((char **, char **));
|
||||
#else
|
||||
static int brace_gobbler ();
|
||||
@@ -301,10 +301,11 @@ expand_amble (text, tlen, flags)
|
||||
#define ST_BAD 0
|
||||
#define ST_INT 1
|
||||
#define ST_CHAR 2
|
||||
#define ST_ZINT 3
|
||||
|
||||
static char **
|
||||
mkseq (start, end, incr, type)
|
||||
int start, end, incr, type;
|
||||
mkseq (start, end, incr, type, width)
|
||||
int start, end, incr, type, width;
|
||||
{
|
||||
int n, i;
|
||||
char **result, *t;
|
||||
@@ -330,6 +331,12 @@ mkseq (start, end, incr, type)
|
||||
#endif
|
||||
if (type == ST_INT)
|
||||
result[i++] = itos (n);
|
||||
else if (type == ST_ZINT)
|
||||
{
|
||||
int len;
|
||||
len = asprintf (&t, "%0*d", width, n);
|
||||
result[i++] = t;
|
||||
}
|
||||
else
|
||||
{
|
||||
t = (char *)xmalloc (2);
|
||||
@@ -337,9 +344,9 @@ mkseq (start, end, incr, type)
|
||||
t[1] = '\0';
|
||||
result[i++] = t;
|
||||
}
|
||||
if (n == end)
|
||||
break;
|
||||
n += incr;
|
||||
if ((incr < 0 && n < end) || (incr > 0 && n > end))
|
||||
break;
|
||||
}
|
||||
while (1);
|
||||
|
||||
@@ -353,17 +360,17 @@ expand_seqterm (text, tlen)
|
||||
size_t tlen;
|
||||
{
|
||||
char *t, *lhs, *rhs;
|
||||
int i, lhs_t, rhs_t, lhs_v, rhs_v;
|
||||
int i, lhs_t, rhs_t, lhs_v, rhs_v, incr, lhs_l, rhs_l, width;
|
||||
intmax_t tl, tr;
|
||||
char **result;
|
||||
char **result, *ep;
|
||||
|
||||
t = strstr (text, BRACE_SEQ_SPECIFIER);
|
||||
if (t == 0)
|
||||
return ((char **)NULL);
|
||||
|
||||
i = t - text; /* index of start of BRACE_SEQ_SPECIFIER */
|
||||
lhs = substring (text, 0, i);
|
||||
rhs = substring (text, i + sizeof(BRACE_SEQ_SPECIFIER) - 1, tlen);
|
||||
lhs_l = t - text; /* index of start of BRACE_SEQ_SPECIFIER */
|
||||
lhs = substring (text, 0, lhs_l);
|
||||
rhs = substring (text, lhs_l + sizeof(BRACE_SEQ_SPECIFIER) - 1, tlen);
|
||||
|
||||
if (lhs[0] == 0 || rhs[0] == 0)
|
||||
{
|
||||
@@ -376,8 +383,36 @@ expand_seqterm (text, tlen)
|
||||
sides have to match. */
|
||||
lhs_t = (legal_number (lhs, &tl)) ? ST_INT :
|
||||
((ISALPHA (lhs[0]) && lhs[1] == 0) ? ST_CHAR : ST_BAD);
|
||||
rhs_t = (legal_number (rhs, &tr)) ? ST_INT :
|
||||
((ISALPHA (rhs[0]) && rhs[1] == 0) ? ST_CHAR : ST_BAD);
|
||||
|
||||
/* Decide on rhs and whether or not it looks like the user specified
|
||||
an increment */
|
||||
ep = 0;
|
||||
if (ISDIGIT (rhs[0]) || ((rhs[0] == '+' || rhs[0] == '-') && ISDIGIT (rhs[1])))
|
||||
{
|
||||
rhs_t = ST_INT;
|
||||
tr = strtoimax (rhs, &ep, 10);
|
||||
if (ep && *ep != 0 && *ep != '.')
|
||||
rhs_t = ST_BAD; /* invalid */
|
||||
}
|
||||
else if (ISALPHA (rhs[0]) && (rhs[1] == 0 || rhs[1] == '.'))
|
||||
{
|
||||
rhs_t = ST_CHAR;
|
||||
ep = rhs + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
rhs_t = ST_BAD;
|
||||
ep = 0;
|
||||
}
|
||||
|
||||
incr = 1;
|
||||
if (rhs_t != ST_BAD)
|
||||
{
|
||||
if (ep && *ep == '.' && ep[1] == '.' && ep[2])
|
||||
incr = strtoimax (ep + 2, &ep, 10);
|
||||
if (*ep != 0)
|
||||
rhs_t = ST_BAD; /* invalid incr */
|
||||
}
|
||||
|
||||
if (lhs_t != rhs_t || lhs_t == ST_BAD || rhs_t == ST_BAD)
|
||||
{
|
||||
@@ -394,14 +429,27 @@ expand_seqterm (text, tlen)
|
||||
{
|
||||
lhs_v = (unsigned char)lhs[0];
|
||||
rhs_v = (unsigned char)rhs[0];
|
||||
width = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
lhs_v = tl; /* integer truncation */
|
||||
rhs_v = tr;
|
||||
|
||||
/* Decide whether or not the terms need zero-padding */
|
||||
rhs_l = tlen - lhs_l - sizeof (BRACE_SEQ_SPECIFIER) + 1;
|
||||
width = 0;
|
||||
if (lhs_l > 1 && lhs[0] == '0')
|
||||
width = lhs_l, lhs_t = ST_ZINT;
|
||||
if (lhs_l > 2 && lhs[0] == '-' && lhs[1] == '0')
|
||||
width = lhs_l, lhs_t = ST_ZINT;
|
||||
if (rhs_l > 1 && rhs[0] == '0' && width < rhs_l)
|
||||
width = rhs_l, lhs_t = ST_ZINT;
|
||||
if (rhs_l > 2 && rhs[0] == '-' && rhs[1] == '0' && width < rhs_l)
|
||||
width = rhs_l, lhs_t = ST_ZINT;
|
||||
}
|
||||
|
||||
result = mkseq (lhs_v, rhs_v, 1, lhs_t);
|
||||
result = mkseq (lhs_v, rhs_v, incr, lhs_t, width);
|
||||
|
||||
free (lhs);
|
||||
free (rhs);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* braces.c -- code for doing word expansion in curly braces. */
|
||||
|
||||
/* Copyright (C) 1987-2003 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1987-2008 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
@@ -61,7 +61,7 @@ static const int brace_arg_separator = ',';
|
||||
static int brace_gobbler __P((char *, size_t, int *, int));
|
||||
static char **expand_amble __P((char *, size_t, int));
|
||||
static char **expand_seqterm __P((char *, size_t));
|
||||
static char **mkseq __P((int, int, int, int));
|
||||
static char **mkseq __P((int, int, int, int, int));
|
||||
static char **array_concat __P((char **, char **));
|
||||
#else
|
||||
static int brace_gobbler ();
|
||||
@@ -301,10 +301,11 @@ expand_amble (text, tlen, flags)
|
||||
#define ST_BAD 0
|
||||
#define ST_INT 1
|
||||
#define ST_CHAR 2
|
||||
#define ST_ZINT 3
|
||||
|
||||
static char **
|
||||
mkseq (start, end, incr, type)
|
||||
int start, end, incr, type;
|
||||
mkseq (start, end, incr, type, width)
|
||||
int start, end, incr, type, width;
|
||||
{
|
||||
int n, i;
|
||||
char **result, *t;
|
||||
@@ -330,6 +331,12 @@ mkseq (start, end, incr, type)
|
||||
#endif
|
||||
if (type == ST_INT)
|
||||
result[i++] = itos (n);
|
||||
else if (type == ST_ZINT)
|
||||
{
|
||||
int len;
|
||||
len = asprintf (&t, "%0*d", width, n);
|
||||
result[i++] = t;
|
||||
}
|
||||
else
|
||||
{
|
||||
t = (char *)xmalloc (2);
|
||||
@@ -337,9 +344,9 @@ mkseq (start, end, incr, type)
|
||||
t[1] = '\0';
|
||||
result[i++] = t;
|
||||
}
|
||||
if (n == end)
|
||||
break;
|
||||
n += incr;
|
||||
if ((incr < 0 && n < end) || (incr > 0 && n > end))
|
||||
break;
|
||||
}
|
||||
while (1);
|
||||
|
||||
@@ -353,17 +360,17 @@ expand_seqterm (text, tlen)
|
||||
size_t tlen;
|
||||
{
|
||||
char *t, *lhs, *rhs;
|
||||
int i, lhs_t, rhs_t, lhs_v, rhs_v;
|
||||
int i, lhs_t, rhs_t, lhs_v, rhs_v, incr, lhs_l, rhs_l, width;
|
||||
intmax_t tl, tr;
|
||||
char **result;
|
||||
char **result, *ep;
|
||||
|
||||
t = strstr (text, BRACE_SEQ_SPECIFIER);
|
||||
if (t == 0)
|
||||
return ((char **)NULL);
|
||||
|
||||
i = t - text; /* index of start of BRACE_SEQ_SPECIFIER */
|
||||
lhs = substring (text, 0, i);
|
||||
rhs = substring (text, i + sizeof(BRACE_SEQ_SPECIFIER) - 1, tlen);
|
||||
lhs_l = t - text; /* index of start of BRACE_SEQ_SPECIFIER */
|
||||
lhs = substring (text, 0, lhs_l);
|
||||
rhs = substring (text, lhs_l + sizeof(BRACE_SEQ_SPECIFIER) - 1, tlen);
|
||||
|
||||
if (lhs[0] == 0 || rhs[0] == 0)
|
||||
{
|
||||
@@ -376,8 +383,37 @@ expand_seqterm (text, tlen)
|
||||
sides have to match. */
|
||||
lhs_t = (legal_number (lhs, &tl)) ? ST_INT :
|
||||
((ISALPHA (lhs[0]) && lhs[1] == 0) ? ST_CHAR : ST_BAD);
|
||||
rhs_t = (legal_number (rhs, &tr)) ? ST_INT :
|
||||
((ISALPHA (rhs[0]) && rhs[1] == 0) ? ST_CHAR : ST_BAD);
|
||||
|
||||
/* Decide on rhs and whether or not it looks like the user specified
|
||||
an increment */
|
||||
ep = 0;
|
||||
if (ISDIGIT (rhs[0]) || ((rhs[0] == '+' || rhs[0] == '-') && ISDIGIT (rhs[1])))
|
||||
{
|
||||
rhs_t = ST_INT;
|
||||
tr = strtoimax (rhs, &ep, 10);
|
||||
if (ep && *ep != 0 && *ep != '.')
|
||||
rhs_t = ST_BAD; /* invalid */
|
||||
}
|
||||
else if (ISALPHA (rhs[0]) && (rhs[1] == 0 || rhs[1] == '.'))
|
||||
{
|
||||
rhs_t = ST_CHAR;
|
||||
ep = rhs + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
rhs_t = ST_BAD;
|
||||
ep = 0;
|
||||
}
|
||||
|
||||
incr = 1;
|
||||
if (rhs_t != ST_BAD)
|
||||
{
|
||||
if (ep && *ep == '.' && ep[1] == '.' && ep[2])
|
||||
incr = strtoimax (ep + 2, &ep, 10);
|
||||
if (*ep != 0)
|
||||
rhs_t = ST_BAD; /* invalid incr */
|
||||
}
|
||||
|
||||
|
||||
if (lhs_t != rhs_t || lhs_t == ST_BAD || rhs_t == ST_BAD)
|
||||
{
|
||||
@@ -394,14 +430,27 @@ expand_seqterm (text, tlen)
|
||||
{
|
||||
lhs_v = (unsigned char)lhs[0];
|
||||
rhs_v = (unsigned char)rhs[0];
|
||||
width = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
lhs_v = tl; /* integer truncation */
|
||||
rhs_v = tr;
|
||||
|
||||
/* Decide whether or not the terms need zero-padding */
|
||||
rhs_l = tlen - lhs_l - sizeof (BRACE_SEQ_SPECIFIER) + 1;
|
||||
width = 0;
|
||||
if (lhs_l > 1 && lhs[0] == '0')
|
||||
width = lhs_l, lhs_t = ST_ZINT;
|
||||
if (lhs > 2 && lhs[0] == '-' && lhs[1] == '0')
|
||||
width = lhs_l, lhs_t = ST_ZINT;
|
||||
if (rhs_l > 1 && rhs[0] == '0' && width < rhs_l)
|
||||
width = rhs_l, lhs_t = ST_ZINT;
|
||||
if (rhs_l > 2 && rhs[0] == '-' && rhs[1] == '0' && width < rhs_l)
|
||||
width = rhs_l, lhs_t = ST_ZINT;
|
||||
}
|
||||
|
||||
result = mkseq (lhs_v, rhs_v, 1, lhs_t);
|
||||
result = mkseq (lhs_v, rhs_v, 1, lhs_t, width);
|
||||
|
||||
free (lhs);
|
||||
free (rhs);
|
||||
@@ -486,8 +535,8 @@ brace_gobbler (text, tlen, indx, satisfy)
|
||||
}
|
||||
|
||||
#if defined (SHELL)
|
||||
/* Pass new-style command substitutions through unchanged. */
|
||||
if (c == '$' && text[i+1] == '(') /* ) */
|
||||
/* Pass new-style command and process substitutions through unchanged. */
|
||||
if ((c == '$' || c == '<' || c == '>') && text[i+1] == '(') /* ) */
|
||||
{
|
||||
si = i + 2;
|
||||
t = extract_command_subst (text, &si);
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
#define SEVAL_NOHIST 0x004
|
||||
#define SEVAL_NOFREE 0x008
|
||||
#define SEVAL_RESETLINE 0x010
|
||||
#define SEVAL_PARSEONLY 0x020
|
||||
#define SEVAL_NOLONGJMP 0x040
|
||||
|
||||
/* Flags for describe_command, shared between type.def and command.def */
|
||||
#define CDESC_ALL 0x001 /* type -a */
|
||||
|
||||
@@ -142,6 +142,7 @@ extern int describe_command __P((char *, int));
|
||||
|
||||
/* Functions from setattr.def */
|
||||
extern int set_or_show_attributes __P((WORD_LIST *, int, int));
|
||||
extern int show_all_var_attributes __P((int, int));
|
||||
extern int show_var_attributes __P((SHELL_VAR *, int, int));
|
||||
extern int show_name_attributes __P((char *, int));
|
||||
extern void set_var_attribute __P((char *, int, int));
|
||||
|
||||
+172
-53
@@ -1,6 +1,6 @@
|
||||
/* Evaluate a string as one or more shell commands.
|
||||
|
||||
Copyright (C) 1996-2005 Free Software Foundation, Inc.
|
||||
Copyright (C) 1996-2008 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
@@ -44,6 +44,8 @@
|
||||
#include "../redir.h"
|
||||
#include "../trap.h"
|
||||
|
||||
#include <y.tab.h>
|
||||
|
||||
#if defined (HISTORY)
|
||||
# include "../bashhist.h"
|
||||
#endif
|
||||
@@ -58,6 +60,7 @@ extern int errno;
|
||||
|
||||
extern int indirection_level, subshell_environment;
|
||||
extern int line_number;
|
||||
extern int current_token, shell_eof_token;
|
||||
extern int last_command_exit_value;
|
||||
extern int running_trap;
|
||||
extern int loop_level;
|
||||
@@ -67,6 +70,17 @@ int parse_and_execute_level = 0;
|
||||
|
||||
static int cat_file __P((REDIRECT *));
|
||||
|
||||
#define PE_TAG "parse_and_execute top"
|
||||
#define PS_TAG "parse_string top"
|
||||
|
||||
#if defined (HISTORY)
|
||||
static void
|
||||
set_history_remembering ()
|
||||
{
|
||||
remember_on_history = enable_history_list;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* How to force parse_and_execute () to clean up after itself. */
|
||||
void
|
||||
parse_and_execute_cleanup ()
|
||||
@@ -76,16 +90,59 @@ parse_and_execute_cleanup ()
|
||||
run_trap_cleanup (running_trap - 1);
|
||||
unfreeze_jobs_list ();
|
||||
}
|
||||
run_unwind_frame ("parse_and_execute_top");
|
||||
run_unwind_frame (PE_TAG);
|
||||
}
|
||||
|
||||
#if defined (HISTORY)
|
||||
static void
|
||||
set_history_remembering ()
|
||||
parse_prologue (string, flags, tag)
|
||||
char *string;
|
||||
int flags;
|
||||
char *tag;
|
||||
{
|
||||
remember_on_history = enable_history_list;
|
||||
char *orig_string;
|
||||
int x;
|
||||
|
||||
orig_string = string;
|
||||
/* Unwind protect this invocation of parse_and_execute (). */
|
||||
begin_unwind_frame (tag);
|
||||
unwind_protect_int (parse_and_execute_level);
|
||||
unwind_protect_jmp_buf (top_level);
|
||||
unwind_protect_int (indirection_level);
|
||||
unwind_protect_int (line_number);
|
||||
unwind_protect_int (loop_level);
|
||||
if (flags & (SEVAL_NONINT|SEVAL_INTERACT))
|
||||
unwind_protect_int (interactive);
|
||||
|
||||
#if defined (HISTORY)
|
||||
if (parse_and_execute_level == 0)
|
||||
add_unwind_protect (set_history_remembering, (char *)NULL);
|
||||
else
|
||||
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 ();
|
||||
|
||||
if (flags & (SEVAL_NONINT|SEVAL_INTERACT))
|
||||
interactive = (flags & SEVAL_NONINT) ? 0 : 1;
|
||||
|
||||
#if defined (HISTORY)
|
||||
if (flags & SEVAL_NOHIST)
|
||||
bash_history_disable ();
|
||||
#endif /* HISTORY */
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Parse and execute the commands in STRING. Returns whatever
|
||||
execute_command () returns. This frees STRING. FLAGS is a
|
||||
@@ -104,50 +161,16 @@ parse_and_execute (string, from_file, flags)
|
||||
const char *from_file;
|
||||
int flags;
|
||||
{
|
||||
int code, x, lreset;
|
||||
int code, 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);
|
||||
unwind_protect_int (loop_level);
|
||||
if (flags & (SEVAL_NONINT|SEVAL_INTERACT))
|
||||
unwind_protect_int (interactive);
|
||||
|
||||
lreset = flags & SEVAL_RESETLINE;
|
||||
|
||||
#if defined (HISTORY)
|
||||
if (parse_and_execute_level == 0)
|
||||
add_unwind_protect (set_history_remembering, (char *)NULL);
|
||||
else
|
||||
unwind_protect_int (remember_on_history);
|
||||
# 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_prologue (string, flags, PE_TAG);
|
||||
|
||||
parse_and_execute_level++;
|
||||
|
||||
lreset = flags & SEVAL_RESETLINE;
|
||||
|
||||
/* 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
|
||||
@@ -157,13 +180,6 @@ parse_and_execute (string, from_file, flags)
|
||||
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;
|
||||
@@ -224,7 +240,7 @@ parse_and_execute (string, from_file, flags)
|
||||
|
||||
if (parse_command () == 0)
|
||||
{
|
||||
if (interactive_shell == 0 && read_but_dont_execute)
|
||||
if ((flags & SEVAL_PARSEONLY) || (interactive_shell == 0 && read_but_dont_execute))
|
||||
{
|
||||
last_result = EXECUTION_SUCCESS;
|
||||
dispose_command (global_command);
|
||||
@@ -303,7 +319,7 @@ parse_and_execute (string, from_file, flags)
|
||||
|
||||
out:
|
||||
|
||||
run_unwind_frame ("parse_and_execute_top");
|
||||
run_unwind_frame (PE_TAG);
|
||||
|
||||
if (interrupt_state && parse_and_execute_level == 0)
|
||||
{
|
||||
@@ -320,6 +336,109 @@ parse_and_execute (string, from_file, flags)
|
||||
return (last_result);
|
||||
}
|
||||
|
||||
/* Parse a command contained in STRING according to FLAGS and return the
|
||||
number of characters consumed from the string. If non-NULL, set *ENDP
|
||||
to the position in the string where the parse ended. Used to validate
|
||||
command substitutions during parsing to obey Posix rules about finding
|
||||
the end of the command and balancing parens. */
|
||||
int
|
||||
parse_string (string, from_file, flags, endp)
|
||||
char *string;
|
||||
const char *from_file;
|
||||
int flags;
|
||||
char **endp;
|
||||
{
|
||||
int code, nc;
|
||||
volatile int should_jump_to_top_level;
|
||||
COMMAND *volatile command, *oglobal;
|
||||
char *ostring;
|
||||
|
||||
parse_prologue (string, flags, PS_TAG);
|
||||
|
||||
/* 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 (0);
|
||||
|
||||
code = should_jump_to_top_level = 0;
|
||||
oglobal = global_command;
|
||||
|
||||
with_input_from_string (string, from_file);
|
||||
while (*(bash_input.location.string))
|
||||
{
|
||||
command = (COMMAND *)NULL;
|
||||
|
||||
#if 0
|
||||
if (interrupt_state)
|
||||
break;
|
||||
#endif
|
||||
|
||||
/* Provide a location for functions which `longjmp (top_level)' to
|
||||
jump to. */
|
||||
code = setjmp (top_level);
|
||||
|
||||
if (code)
|
||||
{
|
||||
#if defined (DEBUG)
|
||||
itrace("parse_string: longjmp executed: code = %d", code);
|
||||
#endif
|
||||
should_jump_to_top_level = 0;
|
||||
switch (code)
|
||||
{
|
||||
case FORCE_EOF:
|
||||
case ERREXIT:
|
||||
case EXITPROG:
|
||||
case DISCARD: /* XXX */
|
||||
if (command)
|
||||
dispose_command (command);
|
||||
/* Remember to call longjmp (top_level) after the old
|
||||
value for it is restored. */
|
||||
should_jump_to_top_level = 1;
|
||||
goto out;
|
||||
|
||||
default:
|
||||
command_error ("parse_string", CMDERR_BADJUMP, code, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (parse_command () == 0)
|
||||
{
|
||||
dispose_command (global_command);
|
||||
global_command = (COMMAND *)NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((flags & SEVAL_NOLONGJMP) == 0)
|
||||
{
|
||||
should_jump_to_top_level = 1;
|
||||
code = DISCARD;
|
||||
}
|
||||
else
|
||||
reset_parser (); /* XXX - sets token_to_read */
|
||||
break;
|
||||
}
|
||||
|
||||
if (current_token == yacc_EOF || current_token == shell_eof_token)
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
|
||||
global_command = oglobal;
|
||||
nc = bash_input.location.string - ostring;
|
||||
if (endp)
|
||||
*endp = bash_input.location.string;
|
||||
|
||||
run_unwind_frame (PS_TAG);
|
||||
|
||||
if (should_jump_to_top_level)
|
||||
jump_to_top_level (code);
|
||||
|
||||
return (nc);
|
||||
}
|
||||
|
||||
/* Handle a $( < file ) command substitution. This expands the filename,
|
||||
returning errors as appropriate, then just cats the file to the standard
|
||||
output. */
|
||||
|
||||
+69
-48
@@ -1,6 +1,6 @@
|
||||
/* Evaluate a string as one or more shell commands.
|
||||
|
||||
Copyright (C) 1996-2005 Free Software Foundation, Inc.
|
||||
Copyright (C) 1996-2008 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
@@ -44,6 +44,8 @@
|
||||
#include "../redir.h"
|
||||
#include "../trap.h"
|
||||
|
||||
#include <y.tab.h>
|
||||
|
||||
#if defined (HISTORY)
|
||||
# include "../bashhist.h"
|
||||
#endif
|
||||
@@ -58,6 +60,7 @@ extern int errno;
|
||||
|
||||
extern int indirection_level, subshell_environment;
|
||||
extern int line_number;
|
||||
extern int current_token, shell_eof_token;
|
||||
extern int last_command_exit_value;
|
||||
extern int running_trap;
|
||||
extern int loop_level;
|
||||
@@ -67,6 +70,17 @@ int parse_and_execute_level = 0;
|
||||
|
||||
static int cat_file __P((REDIRECT *));
|
||||
|
||||
#define PE_TAG "parse_and_execute top"
|
||||
#define PS_TAG "parse_string top"
|
||||
|
||||
#if defined (HISTORY)
|
||||
static void
|
||||
set_history_remembering ()
|
||||
{
|
||||
remember_on_history = enable_history_list;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* How to force parse_and_execute () to clean up after itself. */
|
||||
void
|
||||
parse_and_execute_cleanup ()
|
||||
@@ -76,13 +90,58 @@ parse_and_execute_cleanup ()
|
||||
run_trap_cleanup (running_trap - 1);
|
||||
unfreeze_jobs_list ();
|
||||
}
|
||||
run_unwind_frame ("parse_and_execute_top");
|
||||
run_unwind_frame (PE_TAG);
|
||||
}
|
||||
|
||||
static void
|
||||
set_history_remembering ()
|
||||
parse_prologue (string, flags, tag)
|
||||
char *string;
|
||||
int flags;
|
||||
char *tag;
|
||||
{
|
||||
remember_on_history = enable_history_list;
|
||||
char *orig_string;
|
||||
int x;
|
||||
|
||||
orig_string = string;
|
||||
/* Unwind protect this invocation of parse_and_execute (). */
|
||||
begin_unwind_frame (tag);
|
||||
unwind_protect_int (parse_and_execute_level);
|
||||
unwind_protect_jmp_buf (top_level);
|
||||
unwind_protect_int (indirection_level);
|
||||
unwind_protect_int (line_number);
|
||||
unwind_protect_int (loop_level);
|
||||
if (flags & (SEVAL_NONINT|SEVAL_INTERACT))
|
||||
unwind_protect_int (interactive);
|
||||
|
||||
#if defined (HISTORY)
|
||||
if (parse_and_execute_level == 0)
|
||||
add_unwind_protect (set_history_remembering, (char *)NULL);
|
||||
else
|
||||
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 ();
|
||||
|
||||
if (flags & (SEVAL_NONINT|SEVAL_INTERACT))
|
||||
interactive = (flags & SEVAL_NONINT) ? 0 : 1;
|
||||
|
||||
#if defined (HISTORY)
|
||||
if (flags & SEVAL_NOHIST)
|
||||
bash_history_disable ();
|
||||
#endif /* HISTORY */
|
||||
}
|
||||
|
||||
/* Parse and execute the commands in STRING. Returns whatever
|
||||
@@ -102,47 +161,16 @@ parse_and_execute (string, from_file, flags)
|
||||
const char *from_file;
|
||||
int flags;
|
||||
{
|
||||
int code, x, lreset;
|
||||
int code, 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);
|
||||
unwind_protect_int (loop_level);
|
||||
if (flags & (SEVAL_NONINT|SEVAL_INTERACT))
|
||||
unwind_protect_int (interactive);
|
||||
|
||||
lreset = flags & SEVAL_RESETLINE;
|
||||
|
||||
#if defined (HISTORY)
|
||||
add_unwind_protect (set_history_remembering, (char *)NULL);
|
||||
# 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_prologue (string, flags, PE_TAG);
|
||||
|
||||
parse_and_execute_level++;
|
||||
|
||||
lreset = flags & SEVAL_RESETLINE;
|
||||
|
||||
/* 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
|
||||
@@ -152,13 +180,6 @@ parse_and_execute (string, from_file, flags)
|
||||
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;
|
||||
@@ -219,7 +240,7 @@ parse_and_execute (string, from_file, flags)
|
||||
|
||||
if (parse_command () == 0)
|
||||
{
|
||||
if (interactive_shell == 0 && read_but_dont_execute)
|
||||
if ((flags & SEVAL_PARSEONLY) || (interactive_shell == 0 && read_but_dont_execute))
|
||||
{
|
||||
last_result = EXECUTION_SUCCESS;
|
||||
dispose_command (global_command);
|
||||
@@ -298,7 +319,7 @@ parse_and_execute (string, from_file, flags)
|
||||
|
||||
out:
|
||||
|
||||
run_unwind_frame ("parse_and_execute_top");
|
||||
run_unwind_frame (PE_TAG);
|
||||
|
||||
if (interrupt_state && parse_and_execute_level == 0)
|
||||
{
|
||||
|
||||
+2
-3
@@ -93,7 +93,6 @@ extern int posixly_correct;
|
||||
extern int unlink __P((const char *));
|
||||
|
||||
extern FILE *sh_mktmpfp __P((char *, int, char **));
|
||||
extern int delete_last_history __P((void));
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
@@ -326,7 +325,7 @@ fc_builtin (list)
|
||||
entered into the history list." */
|
||||
if (listing == 0 && hist_last_line_added)
|
||||
{
|
||||
delete_last_history ();
|
||||
bash_delete_last_history ();
|
||||
/* If we're editing a single command -- the last command in the
|
||||
history -- and we just removed the dummy command added by
|
||||
edit_and_execute_command (), we need to check whether or not we
|
||||
@@ -625,7 +624,7 @@ fc_replhist (command)
|
||||
|
||||
if (command && *command)
|
||||
{
|
||||
delete_last_history ();
|
||||
bash_delete_last_history ();
|
||||
maybe_add_history (command); /* Obeys HISTCONTROL setting. */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,8 +337,6 @@ fc_builtin (list)
|
||||
last_hist = histbeg = --histend;
|
||||
}
|
||||
|
||||
itrace ("fc: last_hist = %d histbeg = %d histend = %d", last_hist, histbeg, histend);
|
||||
|
||||
/* We print error messages for line specifications out of range. */
|
||||
if ((histbeg < 0) || (histend < 0))
|
||||
{
|
||||
|
||||
+5
-50
@@ -87,11 +87,8 @@ extern int errno;
|
||||
extern int current_command_line_count;
|
||||
extern int force_append_history; /* shopt -s histappend */
|
||||
|
||||
int delete_last_history __P((void));
|
||||
|
||||
static char *histtime __P((HIST_ENTRY *, const char *));
|
||||
static void display_history __P((WORD_LIST *));
|
||||
static int delete_histent __P((int));
|
||||
static void push_history __P((WORD_LIST *));
|
||||
static int expand_and_print_history __P((WORD_LIST *));
|
||||
|
||||
@@ -162,7 +159,7 @@ history_builtin (list)
|
||||
/* clear the history, but allow other arguments to add to it again. */
|
||||
if (flags & CFLAG)
|
||||
{
|
||||
clear_history ();
|
||||
bash_clear_history ();
|
||||
if (list == 0)
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
@@ -191,7 +188,7 @@ history_builtin (list)
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
opt = delete_offset;
|
||||
result = delete_histent (opt - history_base);
|
||||
result = bash_delete_histent (opt - history_base);
|
||||
/* Since remove_history changes history_length, this can happen if
|
||||
we delete the last history entry. */
|
||||
if (where_history () > history_length)
|
||||
@@ -310,48 +307,6 @@ display_history (list)
|
||||
}
|
||||
}
|
||||
|
||||
/* Delete and free the history list entry at offset I. */
|
||||
static int
|
||||
delete_histent (i)
|
||||
int i;
|
||||
{
|
||||
HIST_ENTRY *discard;
|
||||
|
||||
discard = remove_history (i);
|
||||
if (discard)
|
||||
free_history_entry (discard);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
delete_last_history ()
|
||||
{
|
||||
register int i;
|
||||
HIST_ENTRY **hlist, *histent;
|
||||
int r;
|
||||
|
||||
hlist = history_list ();
|
||||
if (hlist == NULL)
|
||||
return 0;
|
||||
|
||||
for (i = 0; hlist[i]; i++)
|
||||
;
|
||||
i--;
|
||||
|
||||
/* History_get () takes a parameter that must be offset by history_base. */
|
||||
histent = history_get (history_base + i); /* Don't free this */
|
||||
if (histent == NULL)
|
||||
return 0;
|
||||
|
||||
r = delete_histent (i);
|
||||
|
||||
if (where_history () > history_length)
|
||||
history_set_pos (history_length);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Remove the last entry in the history list and add each argument in
|
||||
LIST to the history. */
|
||||
static void
|
||||
@@ -367,12 +322,12 @@ push_history (list)
|
||||
If you don't want history -s to remove the compound command from the
|
||||
history, change #if 0 to #if 1 below. */
|
||||
#if 0
|
||||
if (hist_last_line_pushed == 0 && hist_last_line_added && delete_last_history () == 0)
|
||||
if (hist_last_line_pushed == 0 && hist_last_line_added && bash_delete_last_history () == 0)
|
||||
#else
|
||||
if (hist_last_line_pushed == 0 &&
|
||||
(hist_last_line_added ||
|
||||
(current_command_line_count > 0 && current_command_first_line_saved && command_oriented_history))
|
||||
&& delete_last_history () == 0)
|
||||
&& bash_delete_last_history () == 0)
|
||||
#endif
|
||||
return;
|
||||
|
||||
@@ -397,7 +352,7 @@ expand_and_print_history (list)
|
||||
char *s;
|
||||
int r, result;
|
||||
|
||||
if (hist_last_line_pushed == 0 && hist_last_line_added && delete_last_history () == 0)
|
||||
if (hist_last_line_pushed == 0 && hist_last_line_added && bash_delete_last_history () == 0)
|
||||
return EXECUTION_FAILURE;
|
||||
result = EXECUTION_SUCCESS;
|
||||
while (list)
|
||||
|
||||
+6
-18
@@ -51,6 +51,9 @@ if $HISTFILE has a value, that is used, else ~/.bash_history.
|
||||
If the $HISTTIMEFORMAT variable is set and not null, its value is used
|
||||
as a format string for strftime(3) to print the time stamp associated
|
||||
with each displayed history entry. No time stamps are printed otherwise.
|
||||
|
||||
Exit Status:
|
||||
Returns success unless an invalid option is given or an error occurs.
|
||||
$END
|
||||
|
||||
#include <config.h>
|
||||
@@ -88,7 +91,6 @@ int delete_last_history __P((void));
|
||||
|
||||
static char *histtime __P((HIST_ENTRY *, const char *));
|
||||
static void display_history __P((WORD_LIST *));
|
||||
static int delete_histent __P((int));
|
||||
static void push_history __P((WORD_LIST *));
|
||||
static int expand_and_print_history __P((WORD_LIST *));
|
||||
|
||||
@@ -159,7 +161,7 @@ history_builtin (list)
|
||||
/* clear the history, but allow other arguments to add to it again. */
|
||||
if (flags & CFLAG)
|
||||
{
|
||||
clear_history ();
|
||||
bash_clear_history ();
|
||||
if (list == 0)
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
@@ -188,7 +190,7 @@ history_builtin (list)
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
opt = delete_offset;
|
||||
result = delete_histent (opt - history_base);
|
||||
result = bash_delete_histent (opt - history_base);
|
||||
/* Since remove_history changes history_length, this can happen if
|
||||
we delete the last history entry. */
|
||||
if (where_history () > history_length)
|
||||
@@ -307,20 +309,6 @@ display_history (list)
|
||||
}
|
||||
}
|
||||
|
||||
/* Delete and free the history list entry at offset I. */
|
||||
static int
|
||||
delete_histent (i)
|
||||
int i;
|
||||
{
|
||||
HIST_ENTRY *discard;
|
||||
|
||||
discard = remove_history (i);
|
||||
if (discard)
|
||||
free_history_entry (discard);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
delete_last_history ()
|
||||
{
|
||||
@@ -341,7 +329,7 @@ delete_last_history ()
|
||||
if (histent == NULL)
|
||||
return 0;
|
||||
|
||||
r = delete_histent (i);
|
||||
r = bash_delete_histent (i);
|
||||
|
||||
if (where_history () > history_length)
|
||||
history_set_pos (history_length);
|
||||
|
||||
@@ -31,7 +31,8 @@ enum r_instruction {
|
||||
r_duplicating_input, r_duplicating_output, r_deblank_reading_until,
|
||||
r_close_this, r_err_and_out, r_input_output, r_output_force,
|
||||
r_duplicating_input_word, r_duplicating_output_word,
|
||||
r_move_input, r_move_output, r_move_input_word, r_move_output_word
|
||||
r_move_input, r_move_output, r_move_input_word, r_move_output_word,
|
||||
r_append_err_and_out
|
||||
};
|
||||
|
||||
/* Redirection errors. */
|
||||
@@ -44,7 +45,7 @@ enum r_instruction {
|
||||
(ri == r_output_direction || ri == r_err_and_out)
|
||||
|
||||
#define OUTPUT_REDIRECT(ri) \
|
||||
(ri == r_output_direction || ri == r_input_output || ri == r_err_and_out)
|
||||
(ri == r_output_direction || ri == r_input_output || ri == r_err_and_out || ri == r_append_err_and_out)
|
||||
|
||||
#define INPUT_REDIRECT(ri) \
|
||||
(ri == r_input_direction || ri == r_inputa_direction || ri == r_input_output)
|
||||
@@ -54,6 +55,7 @@ enum r_instruction {
|
||||
ri == r_input_output || \
|
||||
ri == r_err_and_out || \
|
||||
ri == r_appending_to || \
|
||||
ri == r_append_err_and_out || \
|
||||
ri == r_output_force)
|
||||
|
||||
/* redirection needs translation */
|
||||
@@ -89,6 +91,7 @@ enum command_type { cm_for, cm_case, cm_while, cm_if, cm_simple, cm_select,
|
||||
#define W_DQUOTE 0x080000 /* word should be treated as if double-quoted */
|
||||
#define W_NOPROCSUB 0x100000 /* don't perform process substitution */
|
||||
#define W_HASCTLESC 0x200000 /* word contains literal CTLESC characters */
|
||||
#define W_ASSIGNASSOC 0x400000 /* word looks like associative array assignment */
|
||||
|
||||
/* Possible values for subshell_environment */
|
||||
#define SUBSHELL_ASYNC 0x01 /* subshell caused by `command &' */
|
||||
@@ -97,6 +100,7 @@ enum command_type { cm_for, cm_case, cm_while, cm_if, cm_simple, cm_select,
|
||||
#define SUBSHELL_FORK 0x08 /* subshell caused by executing a disk command */
|
||||
#define SUBSHELL_PIPE 0x10 /* subshell from a pipeline element */
|
||||
#define SUBSHELL_PROCSUB 0x20 /* subshell caused by <(command) or >(command) */
|
||||
#define SUBSHELL_COPROC 0x40 /* subshell from a coproc pipeline */
|
||||
|
||||
/* A structure which represents a word. */
|
||||
typedef struct word_desc {
|
||||
@@ -200,6 +204,10 @@ typedef struct connection {
|
||||
|
||||
/* Structures used to represent the CASE command. */
|
||||
|
||||
/* Values for FLAGS word in a PATTERN_LIST */
|
||||
#define CASEPAT_FALLTHROUGH 0x01
|
||||
#define CASEPAT_TESTNEXT 0x02
|
||||
|
||||
/* Pattern/action structure for CASE_COM. */
|
||||
typedef struct pattern_list {
|
||||
struct pattern_list *next; /* Clause to try in case this one failed. */
|
||||
|
||||
+356
@@ -0,0 +1,356 @@
|
||||
/* command.h -- The structures used internally to represent commands, and
|
||||
the extern declarations of the functions used to create them. */
|
||||
|
||||
/* Copyright (C) 1993-2005 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. */
|
||||
|
||||
#if !defined (_COMMAND_H_)
|
||||
#define _COMMAND_H_
|
||||
|
||||
#include "stdc.h"
|
||||
|
||||
/* Instructions describing what kind of thing to do for a redirection. */
|
||||
enum r_instruction {
|
||||
r_output_direction, r_input_direction, r_inputa_direction,
|
||||
r_appending_to, r_reading_until, r_reading_string,
|
||||
r_duplicating_input, r_duplicating_output, r_deblank_reading_until,
|
||||
r_close_this, r_err_and_out, r_input_output, r_output_force,
|
||||
r_duplicating_input_word, r_duplicating_output_word,
|
||||
r_move_input, r_move_output, r_move_input_word, r_move_output_word,
|
||||
r_append_err_and_out
|
||||
};
|
||||
|
||||
/* Redirection errors. */
|
||||
#define AMBIGUOUS_REDIRECT -1
|
||||
#define NOCLOBBER_REDIRECT -2
|
||||
#define RESTRICTED_REDIRECT -3 /* can only happen in restricted shells. */
|
||||
#define HEREDOC_REDIRECT -4 /* here-doc temp file can't be created */
|
||||
|
||||
#define CLOBBERING_REDIRECT(ri) \
|
||||
(ri == r_output_direction || ri == r_err_and_out)
|
||||
|
||||
#define OUTPUT_REDIRECT(ri) \
|
||||
(ri == r_output_direction || ri == r_input_output || ri == r_err_and_out || ri == r_append_err_and_out)
|
||||
|
||||
#define INPUT_REDIRECT(ri) \
|
||||
(ri == r_input_direction || ri == r_inputa_direction || ri == r_input_output)
|
||||
|
||||
#define WRITE_REDIRECT(ri) \
|
||||
(ri == r_output_direction || \
|
||||
ri == r_input_output || \
|
||||
ri == r_err_and_out || \
|
||||
ri == r_appending_to || \
|
||||
ri == r_append_err_and_out || \
|
||||
ri == r_output_force)
|
||||
|
||||
/* redirection needs translation */
|
||||
#define TRANSLATE_REDIRECT(ri) \
|
||||
(ri == r_duplicating_input_word || ri == r_duplicating_output_word || \
|
||||
ri == r_move_input_word || ri == r_move_output_word)
|
||||
|
||||
/* Command Types: */
|
||||
enum command_type { cm_for, cm_case, cm_while, cm_if, cm_simple, cm_select,
|
||||
cm_connection, cm_function_def, cm_until, cm_group,
|
||||
cm_arith, cm_cond, cm_arith_for, cm_subshell };
|
||||
|
||||
/* Possible values for the `flags' field of a WORD_DESC. */
|
||||
#define W_HASDOLLAR 0x000001 /* Dollar sign present. */
|
||||
#define W_QUOTED 0x000002 /* Some form of quote character is present. */
|
||||
#define W_ASSIGNMENT 0x000004 /* This word is a variable assignment. */
|
||||
#define W_GLOBEXP 0x000008 /* This word is the result of a glob expansion. */
|
||||
#define W_NOSPLIT 0x000010 /* Do not perform word splitting on this word. */
|
||||
#define W_NOGLOB 0x000020 /* Do not perform globbing on this word. */
|
||||
#define W_NOSPLIT2 0x000040 /* Don't split word except for $@ expansion. */
|
||||
#define W_TILDEEXP 0x000080 /* Tilde expand this assignment word */
|
||||
#define W_DOLLARAT 0x000100 /* $@ and its special handling */
|
||||
#define W_DOLLARSTAR 0x000200 /* $* and its special handling */
|
||||
#define W_NOCOMSUB 0x000400 /* Don't perform command substitution on this word */
|
||||
#define W_ASSIGNRHS 0x000800 /* Word is rhs of an assignment statement */
|
||||
#define W_NOTILDE 0x001000 /* Don't perform tilde expansion on this word */
|
||||
#define W_ITILDE 0x002000 /* Internal flag for word expansion */
|
||||
#define W_NOEXPAND 0x004000 /* Don't expand at all -- do quote removal */
|
||||
#define W_COMPASSIGN 0x008000 /* Compound assignment */
|
||||
#define W_ASSNBLTIN 0x010000 /* word is a builtin command that takes assignments */
|
||||
#define W_ASSIGNARG 0x020000 /* word is assignment argument to command */
|
||||
#define W_HASQUOTEDNULL 0x040000 /* word contains a quoted null character */
|
||||
#define W_DQUOTE 0x080000 /* word should be treated as if double-quoted */
|
||||
#define W_NOPROCSUB 0x100000 /* don't perform process substitution */
|
||||
#define W_HASCTLESC 0x200000 /* word contains literal CTLESC characters */
|
||||
#define W_ASSIGNASSOC 0x400000 /* word looks like associative array assignment */
|
||||
|
||||
/* Possible values for subshell_environment */
|
||||
#define SUBSHELL_ASYNC 0x01 /* subshell caused by `command &' */
|
||||
#define SUBSHELL_PAREN 0x02 /* subshell caused by ( ... ) */
|
||||
#define SUBSHELL_COMSUB 0x04 /* subshell caused by `command` or $(command) */
|
||||
#define SUBSHELL_FORK 0x08 /* subshell caused by executing a disk command */
|
||||
#define SUBSHELL_PIPE 0x10 /* subshell from a pipeline element */
|
||||
#define SUBSHELL_PROCSUB 0x20 /* subshell caused by <(command) or >(command) */
|
||||
#define SUBSHELL_COPROC 0x40 /* subshell from a coproc pipeline */
|
||||
|
||||
/* A structure which represents a word. */
|
||||
typedef struct word_desc {
|
||||
char *word; /* Zero terminated string. */
|
||||
int flags; /* Flags associated with this word. */
|
||||
} WORD_DESC;
|
||||
|
||||
/* A linked list of words. */
|
||||
typedef struct word_list {
|
||||
struct word_list *next;
|
||||
WORD_DESC *word;
|
||||
} WORD_LIST;
|
||||
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* Shell Command Structs */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
/* What a redirection descriptor looks like. If the redirection instruction
|
||||
is ri_duplicating_input or ri_duplicating_output, use DEST, otherwise
|
||||
use the file in FILENAME. Out-of-range descriptors are identified by a
|
||||
negative DEST. */
|
||||
|
||||
typedef union {
|
||||
int dest; /* Place to redirect REDIRECTOR to, or ... */
|
||||
WORD_DESC *filename; /* filename to redirect to. */
|
||||
} REDIRECTEE;
|
||||
|
||||
/* Structure describing a redirection. If REDIRECTOR is negative, the parser
|
||||
(or translator in redir.c) encountered an out-of-range file descriptor. */
|
||||
typedef struct redirect {
|
||||
struct redirect *next; /* Next element, or NULL. */
|
||||
int redirector; /* Descriptor to be redirected. */
|
||||
int flags; /* Flag value for `open'. */
|
||||
enum r_instruction instruction; /* What to do with the information. */
|
||||
REDIRECTEE redirectee; /* File descriptor or filename */
|
||||
char *here_doc_eof; /* The word that appeared in <<foo. */
|
||||
} REDIRECT;
|
||||
|
||||
/* An element used in parsing. A single word or a single redirection.
|
||||
This is an ephemeral construct. */
|
||||
typedef struct element {
|
||||
WORD_DESC *word;
|
||||
REDIRECT *redirect;
|
||||
} ELEMENT;
|
||||
|
||||
/* Possible values for command->flags. */
|
||||
#define CMD_WANT_SUBSHELL 0x01 /* User wants a subshell: ( command ) */
|
||||
#define CMD_FORCE_SUBSHELL 0x02 /* Shell needs to force a subshell. */
|
||||
#define CMD_INVERT_RETURN 0x04 /* Invert the exit value. */
|
||||
#define CMD_IGNORE_RETURN 0x08 /* Ignore the exit value. For set -e. */
|
||||
#define CMD_NO_FUNCTIONS 0x10 /* Ignore functions during command lookup. */
|
||||
#define CMD_INHIBIT_EXPANSION 0x20 /* Do not expand the command words. */
|
||||
#define CMD_NO_FORK 0x40 /* Don't fork; just call execve */
|
||||
#define CMD_TIME_PIPELINE 0x80 /* Time a pipeline */
|
||||
#define CMD_TIME_POSIX 0x100 /* time -p; use POSIX.2 time output spec. */
|
||||
#define CMD_AMPERSAND 0x200 /* command & */
|
||||
#define CMD_STDIN_REDIR 0x400 /* async command needs implicit </dev/null */
|
||||
#define CMD_COMMAND_BUILTIN 0x0800 /* command executed by `command' builtin */
|
||||
|
||||
/* What a command looks like. */
|
||||
typedef struct command {
|
||||
enum command_type type; /* FOR CASE WHILE IF CONNECTION or SIMPLE. */
|
||||
int flags; /* Flags controlling execution environment. */
|
||||
int line; /* line number the command starts on */
|
||||
REDIRECT *redirects; /* Special redirects for FOR CASE, etc. */
|
||||
union {
|
||||
struct for_com *For;
|
||||
struct case_com *Case;
|
||||
struct while_com *While;
|
||||
struct if_com *If;
|
||||
struct connection *Connection;
|
||||
struct simple_com *Simple;
|
||||
struct function_def *Function_def;
|
||||
struct group_com *Group;
|
||||
#if defined (SELECT_COMMAND)
|
||||
struct select_com *Select;
|
||||
#endif
|
||||
#if defined (DPAREN_ARITHMETIC)
|
||||
struct arith_com *Arith;
|
||||
#endif
|
||||
#if defined (COND_COMMAND)
|
||||
struct cond_com *Cond;
|
||||
#endif
|
||||
#if defined (ARITH_FOR_COMMAND)
|
||||
struct arith_for_com *ArithFor;
|
||||
#endif
|
||||
struct subshell_com *Subshell;
|
||||
} value;
|
||||
} COMMAND;
|
||||
|
||||
/* Structure used to represent the CONNECTION type. */
|
||||
typedef struct connection {
|
||||
int ignore; /* Unused; simplifies make_command (). */
|
||||
COMMAND *first; /* Pointer to the first command. */
|
||||
COMMAND *second; /* Pointer to the second command. */
|
||||
int connector; /* What separates this command from others. */
|
||||
} CONNECTION;
|
||||
|
||||
/* Structures used to represent the CASE command. */
|
||||
|
||||
/* Values for FLAGS word in a PATTERN_LIST */
|
||||
#define CASEPAT_FALLTHROUGH 0x01
|
||||
#define CASEPAT_TESTNEXT 0x02
|
||||
|
||||
/* Pattern/action structure for CASE_COM. */
|
||||
typedef struct pattern_list {
|
||||
struct pattern_list *next; /* Clause to try in case this one failed. */
|
||||
WORD_LIST *patterns; /* Linked list of patterns to test. */
|
||||
COMMAND *action; /* Thing to execute if a pattern matches. */
|
||||
int flags;
|
||||
} PATTERN_LIST;
|
||||
|
||||
/* The CASE command. */
|
||||
typedef struct case_com {
|
||||
int flags; /* See description of CMD flags. */
|
||||
int line; /* line number the `case' keyword appears on */
|
||||
WORD_DESC *word; /* The thing to test. */
|
||||
PATTERN_LIST *clauses; /* The clauses to test against, or NULL. */
|
||||
} CASE_COM;
|
||||
|
||||
/* FOR command. */
|
||||
typedef struct for_com {
|
||||
int flags; /* See description of CMD flags. */
|
||||
int line; /* line number the `for' keyword appears on */
|
||||
WORD_DESC *name; /* The variable name to get mapped over. */
|
||||
WORD_LIST *map_list; /* The things to map over. This is never NULL. */
|
||||
COMMAND *action; /* The action to execute.
|
||||
During execution, NAME is bound to successive
|
||||
members of MAP_LIST. */
|
||||
} FOR_COM;
|
||||
|
||||
#if defined (ARITH_FOR_COMMAND)
|
||||
typedef struct arith_for_com {
|
||||
int flags;
|
||||
int line; /* generally used for error messages */
|
||||
WORD_LIST *init;
|
||||
WORD_LIST *test;
|
||||
WORD_LIST *step;
|
||||
COMMAND *action;
|
||||
} ARITH_FOR_COM;
|
||||
#endif
|
||||
|
||||
#if defined (SELECT_COMMAND)
|
||||
/* KSH SELECT command. */
|
||||
typedef struct select_com {
|
||||
int flags; /* See description of CMD flags. */
|
||||
int line; /* line number the `select' keyword appears on */
|
||||
WORD_DESC *name; /* The variable name to get mapped over. */
|
||||
WORD_LIST *map_list; /* The things to map over. This is never NULL. */
|
||||
COMMAND *action; /* The action to execute.
|
||||
During execution, NAME is bound to the member of
|
||||
MAP_LIST chosen by the user. */
|
||||
} SELECT_COM;
|
||||
#endif /* SELECT_COMMAND */
|
||||
|
||||
/* IF command. */
|
||||
typedef struct if_com {
|
||||
int flags; /* See description of CMD flags. */
|
||||
COMMAND *test; /* Thing to test. */
|
||||
COMMAND *true_case; /* What to do if the test returned non-zero. */
|
||||
COMMAND *false_case; /* What to do if the test returned zero. */
|
||||
} IF_COM;
|
||||
|
||||
/* WHILE command. */
|
||||
typedef struct while_com {
|
||||
int flags; /* See description of CMD flags. */
|
||||
COMMAND *test; /* Thing to test. */
|
||||
COMMAND *action; /* Thing to do while test is non-zero. */
|
||||
} WHILE_COM;
|
||||
|
||||
#if defined (DPAREN_ARITHMETIC)
|
||||
/* The arithmetic evaluation command, ((...)). Just a set of flags and
|
||||
a WORD_LIST, of which the first element is the only one used, for the
|
||||
time being. */
|
||||
typedef struct arith_com {
|
||||
int flags;
|
||||
int line;
|
||||
WORD_LIST *exp;
|
||||
} ARITH_COM;
|
||||
#endif /* DPAREN_ARITHMETIC */
|
||||
|
||||
/* The conditional command, [[...]]. This is a binary tree -- we slippped
|
||||
a recursive-descent parser into the YACC grammar to parse it. */
|
||||
#define COND_AND 1
|
||||
#define COND_OR 2
|
||||
#define COND_UNARY 3
|
||||
#define COND_BINARY 4
|
||||
#define COND_TERM 5
|
||||
#define COND_EXPR 6
|
||||
|
||||
typedef struct cond_com {
|
||||
int flags;
|
||||
int line;
|
||||
int type;
|
||||
WORD_DESC *op;
|
||||
struct cond_com *left, *right;
|
||||
} COND_COM;
|
||||
|
||||
/* The "simple" command. Just a collection of words and redirects. */
|
||||
typedef struct simple_com {
|
||||
int flags; /* See description of CMD flags. */
|
||||
int line; /* line number the command starts on */
|
||||
WORD_LIST *words; /* The program name, the arguments,
|
||||
variable assignments, etc. */
|
||||
REDIRECT *redirects; /* Redirections to perform. */
|
||||
} SIMPLE_COM;
|
||||
|
||||
/* The "function definition" command. */
|
||||
typedef struct function_def {
|
||||
int flags; /* See description of CMD flags. */
|
||||
int line; /* Line number the function def starts on. */
|
||||
WORD_DESC *name; /* The name of the function. */
|
||||
COMMAND *command; /* The parsed execution tree. */
|
||||
char *source_file; /* file in which function was defined, if any */
|
||||
} FUNCTION_DEF;
|
||||
|
||||
/* A command that is `grouped' allows pipes and redirections to affect all
|
||||
commands in the group. */
|
||||
typedef struct group_com {
|
||||
int ignore; /* See description of CMD flags. */
|
||||
COMMAND *command;
|
||||
} GROUP_COM;
|
||||
|
||||
typedef struct subshell_com {
|
||||
int flags;
|
||||
COMMAND *command;
|
||||
} SUBSHELL_COM;
|
||||
|
||||
extern COMMAND *global_command;
|
||||
|
||||
/* Possible command errors */
|
||||
#define CMDERR_DEFAULT 0
|
||||
#define CMDERR_BADTYPE 1
|
||||
#define CMDERR_BADCONN 2
|
||||
#define CMDERR_BADJUMP 3
|
||||
|
||||
#define CMDERR_LAST 3
|
||||
|
||||
/* Forward declarations of functions declared in copy_cmd.c. */
|
||||
|
||||
extern FUNCTION_DEF *copy_function_def_contents __P((FUNCTION_DEF *, FUNCTION_DEF *));
|
||||
extern FUNCTION_DEF *copy_function_def __P((FUNCTION_DEF *));
|
||||
|
||||
extern WORD_DESC *copy_word __P((WORD_DESC *));
|
||||
extern WORD_LIST *copy_word_list __P((WORD_LIST *));
|
||||
extern REDIRECT *copy_redirect __P((REDIRECT *));
|
||||
extern REDIRECT *copy_redirects __P((REDIRECT *));
|
||||
extern COMMAND *copy_command __P((COMMAND *));
|
||||
|
||||
#endif /* _COMMAND_H_ */
|
||||
@@ -85,6 +85,7 @@ copy_case_clause (clause)
|
||||
new_clause = (PATTERN_LIST *)xmalloc (sizeof (PATTERN_LIST));
|
||||
new_clause->patterns = copy_word_list (clause->patterns);
|
||||
new_clause->action = copy_command (clause->action);
|
||||
new_clause->flags = clause->flags;
|
||||
return (new_clause);
|
||||
}
|
||||
|
||||
@@ -124,6 +125,7 @@ copy_redirect (redirect)
|
||||
case r_input_direction:
|
||||
case r_inputa_direction:
|
||||
case r_err_and_out:
|
||||
case r_append_err_and_out:
|
||||
case r_input_output:
|
||||
case r_output_force:
|
||||
case r_duplicating_input_word:
|
||||
|
||||
+422
@@ -0,0 +1,422 @@
|
||||
/* copy_command.c -- copy a COMMAND structure. This is needed
|
||||
primarily for making function definitions, but I'm not sure
|
||||
that anyone else will need it. */
|
||||
|
||||
/* Copyright (C) 1987,1991 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"
|
||||
|
||||
#include "bashtypes.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "shell.h"
|
||||
|
||||
static PATTERN_LIST *copy_case_clause __P((PATTERN_LIST *));
|
||||
static PATTERN_LIST *copy_case_clauses __P((PATTERN_LIST *));
|
||||
static FOR_COM *copy_for_command __P((FOR_COM *));
|
||||
#if defined (ARITH_FOR_COMMAND)
|
||||
static ARITH_FOR_COM *copy_arith_for_command __P((ARITH_FOR_COM *));
|
||||
#endif
|
||||
static GROUP_COM *copy_group_command __P((GROUP_COM *));
|
||||
static SUBSHELL_COM *copy_subshell_command __P((SUBSHELL_COM *));
|
||||
static CASE_COM *copy_case_command __P((CASE_COM *));
|
||||
static WHILE_COM *copy_while_command __P((WHILE_COM *));
|
||||
static IF_COM *copy_if_command __P((IF_COM *));
|
||||
#if defined (DPAREN_ARITHMETIC)
|
||||
static ARITH_COM *copy_arith_command __P((ARITH_COM *));
|
||||
#endif
|
||||
#if defined (COND_COMMAND)
|
||||
static COND_COM *copy_cond_command __P((COND_COM *));
|
||||
#endif
|
||||
static SIMPLE_COM *copy_simple_command __P((SIMPLE_COM *));
|
||||
|
||||
WORD_DESC *
|
||||
copy_word (w)
|
||||
WORD_DESC *w;
|
||||
{
|
||||
WORD_DESC *new_word;
|
||||
|
||||
new_word = make_bare_word (w->word);
|
||||
new_word->flags = w->flags;
|
||||
return (new_word);
|
||||
}
|
||||
|
||||
/* Copy the chain of words in LIST. Return a pointer to
|
||||
the new chain. */
|
||||
WORD_LIST *
|
||||
copy_word_list (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
WORD_LIST *new_list;
|
||||
|
||||
for (new_list = (WORD_LIST *)NULL; list; list = list->next)
|
||||
new_list = make_word_list (copy_word (list->word), new_list);
|
||||
|
||||
return (REVERSE_LIST (new_list, WORD_LIST *));
|
||||
}
|
||||
|
||||
static PATTERN_LIST *
|
||||
copy_case_clause (clause)
|
||||
PATTERN_LIST *clause;
|
||||
{
|
||||
PATTERN_LIST *new_clause;
|
||||
|
||||
new_clause = (PATTERN_LIST *)xmalloc (sizeof (PATTERN_LIST));
|
||||
new_clause->patterns = copy_word_list (clause->patterns);
|
||||
new_clause->action = copy_command (clause->action);
|
||||
return (new_clause);
|
||||
}
|
||||
|
||||
static PATTERN_LIST *
|
||||
copy_case_clauses (clauses)
|
||||
PATTERN_LIST *clauses;
|
||||
{
|
||||
PATTERN_LIST *new_list, *new_clause;
|
||||
|
||||
for (new_list = (PATTERN_LIST *)NULL; clauses; clauses = clauses->next)
|
||||
{
|
||||
new_clause = copy_case_clause (clauses);
|
||||
new_clause->next = new_list;
|
||||
new_list = new_clause;
|
||||
}
|
||||
return (REVERSE_LIST (new_list, PATTERN_LIST *));
|
||||
}
|
||||
|
||||
/* Copy a single redirect. */
|
||||
REDIRECT *
|
||||
copy_redirect (redirect)
|
||||
REDIRECT *redirect;
|
||||
{
|
||||
REDIRECT *new_redirect;
|
||||
|
||||
new_redirect = (REDIRECT *)xmalloc (sizeof (REDIRECT));
|
||||
FASTCOPY ((char *)redirect, (char *)new_redirect, (sizeof (REDIRECT)));
|
||||
switch (redirect->instruction)
|
||||
{
|
||||
case r_reading_until:
|
||||
case r_deblank_reading_until:
|
||||
new_redirect->here_doc_eof = savestring (redirect->here_doc_eof);
|
||||
/*FALLTHROUGH*/
|
||||
case r_reading_string:
|
||||
case r_appending_to:
|
||||
case r_output_direction:
|
||||
case r_input_direction:
|
||||
case r_inputa_direction:
|
||||
case r_err_and_out:
|
||||
case r_input_output:
|
||||
case r_output_force:
|
||||
case r_duplicating_input_word:
|
||||
case r_duplicating_output_word:
|
||||
case r_move_input_word:
|
||||
case r_move_output_word:
|
||||
new_redirect->redirectee.filename = copy_word (redirect->redirectee.filename);
|
||||
break;
|
||||
case r_duplicating_input:
|
||||
case r_duplicating_output:
|
||||
case r_move_input:
|
||||
case r_move_output:
|
||||
case r_close_this:
|
||||
break;
|
||||
}
|
||||
return (new_redirect);
|
||||
}
|
||||
|
||||
REDIRECT *
|
||||
copy_redirects (list)
|
||||
REDIRECT *list;
|
||||
{
|
||||
REDIRECT *new_list, *temp;
|
||||
|
||||
for (new_list = (REDIRECT *)NULL; list; list = list->next)
|
||||
{
|
||||
temp = copy_redirect (list);
|
||||
temp->next = new_list;
|
||||
new_list = temp;
|
||||
}
|
||||
return (REVERSE_LIST (new_list, REDIRECT *));
|
||||
}
|
||||
|
||||
static FOR_COM *
|
||||
copy_for_command (com)
|
||||
FOR_COM *com;
|
||||
{
|
||||
FOR_COM *new_for;
|
||||
|
||||
new_for = (FOR_COM *)xmalloc (sizeof (FOR_COM));
|
||||
new_for->flags = com->flags;
|
||||
new_for->line = com->line;
|
||||
new_for->name = copy_word (com->name);
|
||||
new_for->map_list = copy_word_list (com->map_list);
|
||||
new_for->action = copy_command (com->action);
|
||||
return (new_for);
|
||||
}
|
||||
|
||||
#if defined (ARITH_FOR_COMMAND)
|
||||
static ARITH_FOR_COM *
|
||||
copy_arith_for_command (com)
|
||||
ARITH_FOR_COM *com;
|
||||
{
|
||||
ARITH_FOR_COM *new_arith_for;
|
||||
|
||||
new_arith_for = (ARITH_FOR_COM *)xmalloc (sizeof (ARITH_FOR_COM));
|
||||
new_arith_for->flags = com->flags;
|
||||
new_arith_for->line = com->line;
|
||||
new_arith_for->init = copy_word_list (com->init);
|
||||
new_arith_for->test = copy_word_list (com->test);
|
||||
new_arith_for->step = copy_word_list (com->step);
|
||||
new_arith_for->action = copy_command (com->action);
|
||||
return (new_arith_for);
|
||||
}
|
||||
#endif /* ARITH_FOR_COMMAND */
|
||||
|
||||
static GROUP_COM *
|
||||
copy_group_command (com)
|
||||
GROUP_COM *com;
|
||||
{
|
||||
GROUP_COM *new_group;
|
||||
|
||||
new_group = (GROUP_COM *)xmalloc (sizeof (GROUP_COM));
|
||||
new_group->command = copy_command (com->command);
|
||||
return (new_group);
|
||||
}
|
||||
|
||||
static SUBSHELL_COM *
|
||||
copy_subshell_command (com)
|
||||
SUBSHELL_COM *com;
|
||||
{
|
||||
SUBSHELL_COM *new_subshell;
|
||||
|
||||
new_subshell = (SUBSHELL_COM *)xmalloc (sizeof (SUBSHELL_COM));
|
||||
new_subshell->command = copy_command (com->command);
|
||||
new_subshell->flags = com->flags;
|
||||
return (new_subshell);
|
||||
}
|
||||
|
||||
static CASE_COM *
|
||||
copy_case_command (com)
|
||||
CASE_COM *com;
|
||||
{
|
||||
CASE_COM *new_case;
|
||||
|
||||
new_case = (CASE_COM *)xmalloc (sizeof (CASE_COM));
|
||||
new_case->flags = com->flags;
|
||||
new_case->line = com->line;
|
||||
new_case->word = copy_word (com->word);
|
||||
new_case->clauses = copy_case_clauses (com->clauses);
|
||||
return (new_case);
|
||||
}
|
||||
|
||||
static WHILE_COM *
|
||||
copy_while_command (com)
|
||||
WHILE_COM *com;
|
||||
{
|
||||
WHILE_COM *new_while;
|
||||
|
||||
new_while = (WHILE_COM *)xmalloc (sizeof (WHILE_COM));
|
||||
new_while->flags = com->flags;
|
||||
new_while->test = copy_command (com->test);
|
||||
new_while->action = copy_command (com->action);
|
||||
return (new_while);
|
||||
}
|
||||
|
||||
static IF_COM *
|
||||
copy_if_command (com)
|
||||
IF_COM *com;
|
||||
{
|
||||
IF_COM *new_if;
|
||||
|
||||
new_if = (IF_COM *)xmalloc (sizeof (IF_COM));
|
||||
new_if->flags = com->flags;
|
||||
new_if->test = copy_command (com->test);
|
||||
new_if->true_case = copy_command (com->true_case);
|
||||
new_if->false_case = com->false_case ? copy_command (com->false_case) : com->false_case;
|
||||
return (new_if);
|
||||
}
|
||||
|
||||
#if defined (DPAREN_ARITHMETIC)
|
||||
static ARITH_COM *
|
||||
copy_arith_command (com)
|
||||
ARITH_COM *com;
|
||||
{
|
||||
ARITH_COM *new_arith;
|
||||
|
||||
new_arith = (ARITH_COM *)xmalloc (sizeof (ARITH_COM));
|
||||
new_arith->flags = com->flags;
|
||||
new_arith->exp = copy_word_list (com->exp);
|
||||
new_arith->line = com->line;
|
||||
|
||||
return (new_arith);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined (COND_COMMAND)
|
||||
static COND_COM *
|
||||
copy_cond_command (com)
|
||||
COND_COM *com;
|
||||
{
|
||||
COND_COM *new_cond;
|
||||
|
||||
new_cond = (COND_COM *)xmalloc (sizeof (COND_COM));
|
||||
new_cond->flags = com->flags;
|
||||
new_cond->line = com->line;
|
||||
new_cond->type = com->type;
|
||||
new_cond->op = com->op ? copy_word (com->op) : com->op;
|
||||
new_cond->left = com->left ? copy_cond_command (com->left) : (COND_COM *)NULL;
|
||||
new_cond->right = com->right ? copy_cond_command (com->right) : (COND_COM *)NULL;
|
||||
|
||||
return (new_cond);
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_COM *
|
||||
copy_simple_command (com)
|
||||
SIMPLE_COM *com;
|
||||
{
|
||||
SIMPLE_COM *new_simple;
|
||||
|
||||
new_simple = (SIMPLE_COM *)xmalloc (sizeof (SIMPLE_COM));
|
||||
new_simple->flags = com->flags;
|
||||
new_simple->words = copy_word_list (com->words);
|
||||
new_simple->redirects = com->redirects ? copy_redirects (com->redirects) : (REDIRECT *)NULL;
|
||||
new_simple->line = com->line;
|
||||
return (new_simple);
|
||||
}
|
||||
|
||||
FUNCTION_DEF *
|
||||
copy_function_def_contents (old, new_def)
|
||||
FUNCTION_DEF *old, *new_def;
|
||||
{
|
||||
new_def->name = copy_word (old->name);
|
||||
new_def->command = old->command ? copy_command (old->command) : old->command;
|
||||
new_def->flags = old->flags;
|
||||
new_def->line = old->line;
|
||||
new_def->source_file = old->source_file ? savestring (old->source_file) : old->source_file;
|
||||
return (new_def);
|
||||
}
|
||||
|
||||
FUNCTION_DEF *
|
||||
copy_function_def (com)
|
||||
FUNCTION_DEF *com;
|
||||
{
|
||||
FUNCTION_DEF *new_def;
|
||||
|
||||
new_def = (FUNCTION_DEF *)xmalloc (sizeof (FUNCTION_DEF));
|
||||
new_def = copy_function_def_contents (com, new_def);
|
||||
return (new_def);
|
||||
}
|
||||
|
||||
/* Copy the command structure in COMMAND. Return a pointer to the
|
||||
copy. Don't you forget to dispose_command () on this pointer
|
||||
later! */
|
||||
COMMAND *
|
||||
copy_command (command)
|
||||
COMMAND *command;
|
||||
{
|
||||
COMMAND *new_command;
|
||||
|
||||
if (command == NULL)
|
||||
return (command);
|
||||
|
||||
new_command = (COMMAND *)xmalloc (sizeof (COMMAND));
|
||||
FASTCOPY ((char *)command, (char *)new_command, sizeof (COMMAND));
|
||||
new_command->flags = command->flags;
|
||||
new_command->line = command->line;
|
||||
|
||||
if (command->redirects)
|
||||
new_command->redirects = copy_redirects (command->redirects);
|
||||
|
||||
switch (command->type)
|
||||
{
|
||||
case cm_for:
|
||||
new_command->value.For = copy_for_command (command->value.For);
|
||||
break;
|
||||
|
||||
#if defined (ARITH_FOR_COMMAND)
|
||||
case cm_arith_for:
|
||||
new_command->value.ArithFor = copy_arith_for_command (command->value.ArithFor);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined (SELECT_COMMAND)
|
||||
case cm_select:
|
||||
new_command->value.Select =
|
||||
(SELECT_COM *)copy_for_command ((FOR_COM *)command->value.Select);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case cm_group:
|
||||
new_command->value.Group = copy_group_command (command->value.Group);
|
||||
break;
|
||||
|
||||
case cm_subshell:
|
||||
new_command->value.Subshell = copy_subshell_command (command->value.Subshell);
|
||||
break;
|
||||
|
||||
case cm_case:
|
||||
new_command->value.Case = copy_case_command (command->value.Case);
|
||||
break;
|
||||
|
||||
case cm_until:
|
||||
case cm_while:
|
||||
new_command->value.While = copy_while_command (command->value.While);
|
||||
break;
|
||||
|
||||
case cm_if:
|
||||
new_command->value.If = copy_if_command (command->value.If);
|
||||
break;
|
||||
|
||||
#if defined (DPAREN_ARITHMETIC)
|
||||
case cm_arith:
|
||||
new_command->value.Arith = copy_arith_command (command->value.Arith);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined (COND_COMMAND)
|
||||
case cm_cond:
|
||||
new_command->value.Cond = copy_cond_command (command->value.Cond);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case cm_simple:
|
||||
new_command->value.Simple = copy_simple_command (command->value.Simple);
|
||||
break;
|
||||
|
||||
case cm_connection:
|
||||
{
|
||||
CONNECTION *new_connection;
|
||||
|
||||
new_connection = (CONNECTION *)xmalloc (sizeof (CONNECTION));
|
||||
new_connection->connector = command->value.Connection->connector;
|
||||
new_connection->first = copy_command (command->value.Connection->first);
|
||||
new_connection->second = copy_command (command->value.Connection->second);
|
||||
new_command->value.Connection = new_connection;
|
||||
break;
|
||||
}
|
||||
|
||||
case cm_function_def:
|
||||
new_command->value.Function_def = copy_function_def (command->value.Function_def);
|
||||
break;
|
||||
}
|
||||
return (new_command);
|
||||
}
|
||||
+2
-1
@@ -1,6 +1,6 @@
|
||||
/* dispose_command.c -- dispose of a COMMAND structure. */
|
||||
|
||||
/* Copyright (C) 1987-2005 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1987-2008 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
@@ -313,6 +313,7 @@ dispose_redirects (list)
|
||||
case r_inputa_direction:
|
||||
case r_appending_to:
|
||||
case r_err_and_out:
|
||||
case r_append_err_and_out:
|
||||
case r_input_output:
|
||||
case r_output_force:
|
||||
case r_duplicating_input_word:
|
||||
|
||||
+330
@@ -0,0 +1,330 @@
|
||||
/* dispose_command.c -- dispose of a COMMAND structure. */
|
||||
|
||||
/* Copyright (C) 1987-2005 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"
|
||||
|
||||
#include "bashtypes.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "bashansi.h"
|
||||
#include "shell.h"
|
||||
|
||||
extern sh_obj_cache_t wdcache, wlcache;
|
||||
|
||||
/* Dispose of the command structure passed. */
|
||||
void
|
||||
dispose_command (command)
|
||||
COMMAND *command;
|
||||
{
|
||||
if (command == 0)
|
||||
return;
|
||||
|
||||
if (command->redirects)
|
||||
dispose_redirects (command->redirects);
|
||||
|
||||
switch (command->type)
|
||||
{
|
||||
case cm_for:
|
||||
#if defined (SELECT_COMMAND)
|
||||
case cm_select:
|
||||
#endif
|
||||
{
|
||||
register FOR_COM *c;
|
||||
#if defined (SELECT_COMMAND)
|
||||
if (command->type == cm_select)
|
||||
c = (FOR_COM *)command->value.Select;
|
||||
else
|
||||
#endif
|
||||
c = command->value.For;
|
||||
dispose_word (c->name);
|
||||
dispose_words (c->map_list);
|
||||
dispose_command (c->action);
|
||||
free (c);
|
||||
break;
|
||||
}
|
||||
|
||||
#if defined (ARITH_FOR_COMMAND)
|
||||
case cm_arith_for:
|
||||
{
|
||||
register ARITH_FOR_COM *c;
|
||||
|
||||
c = command->value.ArithFor;
|
||||
dispose_words (c->init);
|
||||
dispose_words (c->test);
|
||||
dispose_words (c->step);
|
||||
dispose_command (c->action);
|
||||
free (c);
|
||||
break;
|
||||
}
|
||||
#endif /* ARITH_FOR_COMMAND */
|
||||
|
||||
case cm_group:
|
||||
{
|
||||
dispose_command (command->value.Group->command);
|
||||
free (command->value.Group);
|
||||
break;
|
||||
}
|
||||
|
||||
case cm_subshell:
|
||||
{
|
||||
dispose_command (command->value.Subshell->command);
|
||||
free (command->value.Subshell);
|
||||
break;
|
||||
}
|
||||
|
||||
case cm_case:
|
||||
{
|
||||
register CASE_COM *c;
|
||||
PATTERN_LIST *t, *p;
|
||||
|
||||
c = command->value.Case;
|
||||
dispose_word (c->word);
|
||||
|
||||
for (p = c->clauses; p; )
|
||||
{
|
||||
dispose_words (p->patterns);
|
||||
dispose_command (p->action);
|
||||
t = p;
|
||||
p = p->next;
|
||||
free (t);
|
||||
}
|
||||
free (c);
|
||||
break;
|
||||
}
|
||||
|
||||
case cm_until:
|
||||
case cm_while:
|
||||
{
|
||||
register WHILE_COM *c;
|
||||
|
||||
c = command->value.While;
|
||||
dispose_command (c->test);
|
||||
dispose_command (c->action);
|
||||
free (c);
|
||||
break;
|
||||
}
|
||||
|
||||
case cm_if:
|
||||
{
|
||||
register IF_COM *c;
|
||||
|
||||
c = command->value.If;
|
||||
dispose_command (c->test);
|
||||
dispose_command (c->true_case);
|
||||
dispose_command (c->false_case);
|
||||
free (c);
|
||||
break;
|
||||
}
|
||||
|
||||
case cm_simple:
|
||||
{
|
||||
register SIMPLE_COM *c;
|
||||
|
||||
c = command->value.Simple;
|
||||
dispose_words (c->words);
|
||||
dispose_redirects (c->redirects);
|
||||
free (c);
|
||||
break;
|
||||
}
|
||||
|
||||
case cm_connection:
|
||||
{
|
||||
register CONNECTION *c;
|
||||
|
||||
c = command->value.Connection;
|
||||
dispose_command (c->first);
|
||||
dispose_command (c->second);
|
||||
free (c);
|
||||
break;
|
||||
}
|
||||
|
||||
#if defined (DPAREN_ARITHMETIC)
|
||||
case cm_arith:
|
||||
{
|
||||
register ARITH_COM *c;
|
||||
|
||||
c = command->value.Arith;
|
||||
dispose_words (c->exp);
|
||||
free (c);
|
||||
break;
|
||||
}
|
||||
#endif /* DPAREN_ARITHMETIC */
|
||||
|
||||
#if defined (COND_COMMAND)
|
||||
case cm_cond:
|
||||
{
|
||||
register COND_COM *c;
|
||||
|
||||
c = command->value.Cond;
|
||||
dispose_cond_node (c);
|
||||
break;
|
||||
}
|
||||
#endif /* COND_COMMAND */
|
||||
|
||||
case cm_function_def:
|
||||
{
|
||||
register FUNCTION_DEF *c;
|
||||
|
||||
c = command->value.Function_def;
|
||||
dispose_function_def (c);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
command_error ("dispose_command", CMDERR_BADTYPE, command->type, 0);
|
||||
break;
|
||||
}
|
||||
free (command);
|
||||
}
|
||||
|
||||
#if defined (COND_COMMAND)
|
||||
/* How to free a node in a conditional command. */
|
||||
void
|
||||
dispose_cond_node (cond)
|
||||
COND_COM *cond;
|
||||
{
|
||||
if (cond)
|
||||
{
|
||||
if (cond->left)
|
||||
dispose_cond_node (cond->left);
|
||||
if (cond->right)
|
||||
dispose_cond_node (cond->right);
|
||||
if (cond->op)
|
||||
dispose_word (cond->op);
|
||||
free (cond);
|
||||
}
|
||||
}
|
||||
#endif /* COND_COMMAND */
|
||||
|
||||
void
|
||||
dispose_function_def_contents (c)
|
||||
FUNCTION_DEF *c;
|
||||
{
|
||||
dispose_word (c->name);
|
||||
dispose_command (c->command);
|
||||
FREE (c->source_file);
|
||||
}
|
||||
|
||||
void
|
||||
dispose_function_def (c)
|
||||
FUNCTION_DEF *c;
|
||||
{
|
||||
dispose_function_def_contents (c);
|
||||
free (c);
|
||||
}
|
||||
|
||||
/* How to free a WORD_DESC. */
|
||||
void
|
||||
dispose_word (w)
|
||||
WORD_DESC *w;
|
||||
{
|
||||
FREE (w->word);
|
||||
ocache_free (wdcache, WORD_DESC, w);
|
||||
}
|
||||
|
||||
/* Free a WORD_DESC, but not the word contained within. */
|
||||
void
|
||||
dispose_word_desc (w)
|
||||
WORD_DESC *w;
|
||||
{
|
||||
w->word = 0;
|
||||
ocache_free (wdcache, WORD_DESC, w);
|
||||
}
|
||||
|
||||
/* How to get rid of a linked list of words. A WORD_LIST. */
|
||||
void
|
||||
dispose_words (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
WORD_LIST *t;
|
||||
|
||||
while (list)
|
||||
{
|
||||
t = list;
|
||||
list = list->next;
|
||||
dispose_word (t->word);
|
||||
#if 0
|
||||
free (t);
|
||||
#else
|
||||
ocache_free (wlcache, WORD_LIST, t);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef INCLUDE_UNUSED
|
||||
/* How to dispose of an array of pointers to char. This is identical to
|
||||
free_array in stringlib.c. */
|
||||
void
|
||||
dispose_word_array (array)
|
||||
char **array;
|
||||
{
|
||||
register int count;
|
||||
|
||||
if (array == 0)
|
||||
return;
|
||||
|
||||
for (count = 0; array[count]; count++)
|
||||
free (array[count]);
|
||||
|
||||
free (array);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* How to dispose of an list of redirections. A REDIRECT. */
|
||||
void
|
||||
dispose_redirects (list)
|
||||
REDIRECT *list;
|
||||
{
|
||||
register REDIRECT *t;
|
||||
|
||||
while (list)
|
||||
{
|
||||
t = list;
|
||||
list = list->next;
|
||||
switch (t->instruction)
|
||||
{
|
||||
case r_reading_until:
|
||||
case r_deblank_reading_until:
|
||||
free (t->here_doc_eof);
|
||||
/*FALLTHROUGH*/
|
||||
case r_reading_string:
|
||||
case r_output_direction:
|
||||
case r_input_direction:
|
||||
case r_inputa_direction:
|
||||
case r_appending_to:
|
||||
case r_err_and_out:
|
||||
case r_append_err_and_out:
|
||||
case r_input_output:
|
||||
case r_output_force:
|
||||
case r_duplicating_input_word:
|
||||
case r_duplicating_output_word:
|
||||
case r_move_input_word:
|
||||
case r_move_output_word:
|
||||
dispose_word (t->redirectee.filename);
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
free (t);
|
||||
}
|
||||
}
|
||||
+70
-16
@@ -5,12 +5,12 @@
|
||||
.\" Case Western Reserve University
|
||||
.\" chet@po.cwru.edu
|
||||
.\"
|
||||
.\" Last Change: Thu May 8 09:32:34 EDT 2008
|
||||
.\" Last Change: Sun May 25 10:41:29 EDT 2008
|
||||
.\"
|
||||
.\" bash_builtins, strip all but Built-Ins section
|
||||
.if \n(zZ=1 .ig zZ
|
||||
.if \n(zY=1 .ig zY
|
||||
.TH BASH 1 "2008 May 8" "GNU Bash-4.0"
|
||||
.TH BASH 1 "2008 May 25" "GNU Bash-4.0"
|
||||
.\"
|
||||
.\" There's some problem with having a `@'
|
||||
.\" in a tagged paragraph with the BSD man macros.
|
||||
@@ -471,8 +471,8 @@ A \fItoken\fP that performs a control function. It is one of the following
|
||||
symbols:
|
||||
.RS
|
||||
.PP
|
||||
.if t \fB\(bv\(bv & && ; ;; ( ) | <newline>\fP
|
||||
.if n \fB|| & && ; ;; ( ) | <newline>\fP
|
||||
.if t \fB\(bv\(bv & && ; ;; ( ) | |& <newline>\fP
|
||||
.if n \fB|| & && ; ;; ( ) | |& <newline>\fP
|
||||
.RE
|
||||
.PD
|
||||
.SH "RESERVED WORDS"
|
||||
@@ -507,12 +507,13 @@ The return value of a \fIsimple command\fP is its exit status, or
|
||||
.SS Pipelines
|
||||
.PP
|
||||
A \fIpipeline\fP is a sequence of one or more commands separated by
|
||||
the character
|
||||
.BR | .
|
||||
one of the control operators
|
||||
.B |
|
||||
or \fB|&\fP.
|
||||
The format for a pipeline is:
|
||||
.RS
|
||||
.PP
|
||||
[\fBtime\fP [\fB\-p\fP]] [ ! ] \fIcommand\fP [ \fB|\fP \fIcommand2\fP ... ]
|
||||
[\fBtime\fP [\fB\-p\fP]] [ ! ] \fIcommand\fP [ [\fB|\fP\(bv\fB|&\fP] \fIcommand2\fP ... ]
|
||||
.RE
|
||||
.PP
|
||||
The standard output of
|
||||
@@ -524,6 +525,11 @@ command (see
|
||||
.SM
|
||||
.B REDIRECTION
|
||||
below).
|
||||
If \fB|&\fP is used, the standard error of \fIcommand\fP is connected to
|
||||
\fIcommand2\fP's standard input through the pipe; it is shorthand for
|
||||
\fB2>&1 |\fP.
|
||||
This implicit redirection of the standard error is performed after any
|
||||
redirections specified by the command.
|
||||
.PP
|
||||
The return status of a pipeline is the exit status of the last
|
||||
command, unless the \fBpipefail\fP option is enabled.
|
||||
@@ -820,9 +826,15 @@ If the shell option
|
||||
.B nocasematch
|
||||
is enabled, the match is performed without regard to the case
|
||||
of alphabetic characters.
|
||||
When a match is found, the
|
||||
corresponding \fIlist\fP is executed. After the first match, no
|
||||
subsequent matches are attempted. The exit status is zero if no
|
||||
When a match is found, the corresponding \fIlist\fP is executed.
|
||||
If the \fB;;\fP operator is used, no subsequent matches are attempted after
|
||||
the first pattern match.
|
||||
Using \fB;&\fP in place of \fB;;\fP causes execution to continue with
|
||||
the \fIlist\fP associated with the next set of patterns.
|
||||
Using \fB;;&\fP in place of \fB;;\fP causes the shell to test the next
|
||||
pattern list in the statement, if any, and execute any associated \fIlist\fP
|
||||
on a successful match.
|
||||
The exit status is zero if no
|
||||
pattern matches. Otherwise, it is the exit status of the
|
||||
last command executed in \fIlist\fP.
|
||||
.TP
|
||||
@@ -2224,13 +2236,21 @@ Brace expansions may be nested. The results of each expanded
|
||||
string are not sorted; left to right order is preserved.
|
||||
For example, a\fB{\fPd,c,b\fB}\fPe expands into `ade ace abe'.
|
||||
.PP
|
||||
A sequence expression takes the form \fB{\fP\fIx\fP\fB..\fP\fIy\fP\fB}\fP,
|
||||
where \fIx\fP and \fIy\fP are either integers or single characters.
|
||||
A sequence expression takes the form
|
||||
\fB{\fP\fIx\fP\fB..\fP\fIy\fP\fB[..\fIincr\fP]}\fP,
|
||||
where \fIx\fP and \fIy\fP are either integers or single characters,
|
||||
and \fIincr\fP, an optional increment, is an integer.
|
||||
When integers are supplied, the expression expands to each number between
|
||||
\fIx\fP and \fIy\fP, inclusive.
|
||||
Supplied integers may be prefixed with \fI0\fP to force each term to have the
|
||||
same width. When either \fIx\fP or \fPy\fP begins with a zero, the shell
|
||||
attempts to force all generated terms to contain the same number of digits,
|
||||
zero-padding where necessary.
|
||||
When characters are supplied, the expression expands to each character
|
||||
lexicographically between \fIx\fP and \fIy\fP, inclusive. Note that
|
||||
both \fIx\fP and \fIy\fP must be of the same type.
|
||||
When the increment is supplied, it is used as the difference between
|
||||
each term. The default increment is 1 or -1 as appropriate.
|
||||
.PP
|
||||
Brace expansion is performed before any other expansions,
|
||||
and any characters special to other expansions are preserved
|
||||
@@ -3141,14 +3161,12 @@ The general format for appending output is:
|
||||
.PP
|
||||
.SS Redirecting Standard Output and Standard Error
|
||||
.PP
|
||||
.B Bash
|
||||
allows both the
|
||||
This construct allows both the
|
||||
standard output (file descriptor 1) and
|
||||
the standard error output (file descriptor 2)
|
||||
to be redirected to the file whose name is the
|
||||
expansion of
|
||||
.I word
|
||||
with this construct.
|
||||
.IR word .
|
||||
.PP
|
||||
There are two formats for redirecting standard output and
|
||||
standard error:
|
||||
@@ -3167,6 +3185,27 @@ This is semantically equivalent to
|
||||
.PP
|
||||
\fB>\fP\fIword\fP 2\fB>&\fP1
|
||||
.RE
|
||||
.PP
|
||||
.SS Appending Standard Output and Standard Error
|
||||
.PP
|
||||
This construct allows both the
|
||||
standard output (file descriptor 1) and
|
||||
the standard error output (file descriptor 2)
|
||||
to be appended to the file whose name is the
|
||||
expansion of
|
||||
.IR word .
|
||||
.PP
|
||||
The format for appending standard output and standard error is:
|
||||
.RS
|
||||
.PP
|
||||
\fB&>>\fP\fIword\fP
|
||||
.RE
|
||||
.PP
|
||||
This is semantically equivalent to
|
||||
.RS
|
||||
.PP
|
||||
\fB>>\fP\fIword\fP 2\fB>&\fP1
|
||||
.RE
|
||||
.SS Here Documents
|
||||
.PP
|
||||
This type of redirection instructs the shell to read input from the
|
||||
@@ -5338,6 +5377,11 @@ Attempt completion on the text before point, comparing
|
||||
the text against lines from the history list for possible
|
||||
completion matches.
|
||||
.TP
|
||||
.B dabbrev\-expand
|
||||
Attempt menu completion on the text before point, comparing
|
||||
the text against lines from the history list for possible
|
||||
completion matches.
|
||||
.TP
|
||||
.B complete\-into\-braces (M\-{)
|
||||
Perform filename completion and insert the list of possible completions
|
||||
enclosed within braces so the list is available to the shell (see
|
||||
@@ -6175,6 +6219,16 @@ Remove any current binding for \fIkeyseq\fP.
|
||||
.B \-x \fIkeyseq\fP:\fIshell\-command\fP
|
||||
Cause \fIshell\-command\fP to be executed whenever \fIkeyseq\fP is
|
||||
entered.
|
||||
When \fIshell\-command\fP is executed, the shell sets the
|
||||
.B READLINE_LINE
|
||||
variable to the contents of the \fBreadline\fP line buffer and the
|
||||
.B READLINE_POINT
|
||||
variable to the current location of the insertion point.
|
||||
If the executed command changes the value of
|
||||
.B READLINE_LINE
|
||||
or
|
||||
.BR READLINE_POINT ,
|
||||
those new values will be reflected in the editing state.
|
||||
.PD
|
||||
.PP
|
||||
The return value is 0 unless an unrecognized option is given or an
|
||||
|
||||
+74
-24
@@ -5,12 +5,12 @@
|
||||
.\" Case Western Reserve University
|
||||
.\" chet@po.cwru.edu
|
||||
.\"
|
||||
.\" Last Change: Thu May 8 09:32:34 EDT 2008
|
||||
.\" Last Change: Sun May 25 10:41:29 EDT 2008
|
||||
.\"
|
||||
.\" bash_builtins, strip all but Built-Ins section
|
||||
.if \n(zZ=1 .ig zZ
|
||||
.if \n(zY=1 .ig zY
|
||||
.TH BASH 1 "2008 May 8" "GNU Bash-4.0"
|
||||
.TH BASH 1 "2008 May 25" "GNU Bash-4.0"
|
||||
.\"
|
||||
.\" There's some problem with having a `@'
|
||||
.\" in a tagged paragraph with the BSD man macros.
|
||||
@@ -471,8 +471,8 @@ A \fItoken\fP that performs a control function. It is one of the following
|
||||
symbols:
|
||||
.RS
|
||||
.PP
|
||||
.if t \fB\(bv\(bv & && ; ;; ( ) | <newline>\fP
|
||||
.if n \fB|| & && ; ;; ( ) | <newline>\fP
|
||||
.if t \fB\(bv\(bv & && ; ;; ( ) | |& <newline>\fP
|
||||
.if n \fB|| & && ; ;; ( ) | |& <newline>\fP
|
||||
.RE
|
||||
.PD
|
||||
.SH "RESERVED WORDS"
|
||||
@@ -507,12 +507,13 @@ The return value of a \fIsimple command\fP is its exit status, or
|
||||
.SS Pipelines
|
||||
.PP
|
||||
A \fIpipeline\fP is a sequence of one or more commands separated by
|
||||
the character
|
||||
.BR | .
|
||||
one of the control operators
|
||||
.B |
|
||||
or \fB|&\fP.
|
||||
The format for a pipeline is:
|
||||
.RS
|
||||
.PP
|
||||
[\fBtime\fP [\fB\-p\fP]] [ ! ] \fIcommand\fP [ \fB|\fP \fIcommand2\fP ... ]
|
||||
[\fBtime\fP [\fB\-p\fP]] [ ! ] \fIcommand\fP [ [\fB|\fP\(bv\fB|&\fP] \fIcommand2\fP ... ]
|
||||
.RE
|
||||
.PP
|
||||
The standard output of
|
||||
@@ -524,6 +525,11 @@ command (see
|
||||
.SM
|
||||
.B REDIRECTION
|
||||
below).
|
||||
If \fB|&\fP is used, the standard error of \fIcommand\fP is connected to
|
||||
\fIcommand2\fP's standard input through the pipe; it is shorthand for
|
||||
\fB2>&1 |\fP.
|
||||
This implicit redirection of the standard error is performed after any
|
||||
redirections specified by the command.
|
||||
.PP
|
||||
The return status of a pipeline is the exit status of the last
|
||||
command, unless the \fBpipefail\fP option is enabled.
|
||||
@@ -820,9 +826,15 @@ If the shell option
|
||||
.B nocasematch
|
||||
is enabled, the match is performed without regard to the case
|
||||
of alphabetic characters.
|
||||
When a match is found, the
|
||||
corresponding \fIlist\fP is executed. After the first match, no
|
||||
subsequent matches are attempted. The exit status is zero if no
|
||||
When a match is found, the corresponding \fIlist\fP is executed.
|
||||
If the \fB;;\fP operator is used, no subsequent matches are attempted after
|
||||
the first pattern match.
|
||||
Using \fB;&\fP in place of \fB;;\fP causes execution to continue with
|
||||
the \fIlist\fP associated with the next set of patterns.
|
||||
Using \fB;;\fP in place of \fB;;\fP causes the shell to test the next
|
||||
pattern list in the statement, if any, and execute any associated \fIlist\fP
|
||||
on a successful match.
|
||||
The exit status is zero if no
|
||||
pattern matches. Otherwise, it is the exit status of the
|
||||
last command executed in \fIlist\fP.
|
||||
.TP
|
||||
@@ -2224,13 +2236,21 @@ Brace expansions may be nested. The results of each expanded
|
||||
string are not sorted; left to right order is preserved.
|
||||
For example, a\fB{\fPd,c,b\fB}\fPe expands into `ade ace abe'.
|
||||
.PP
|
||||
A sequence expression takes the form \fB{\fP\fIx\fP\fB..\fP\fIy\fP\fB}\fP,
|
||||
where \fIx\fP and \fIy\fP are either integers or single characters.
|
||||
A sequence expression takes the form
|
||||
\fB{\fP\fIx\fP\fB..\fP\fIy\fP\fB[..\fIincr\fP]}\fP,
|
||||
where \fIx\fP and \fIy\fP are either integers or single characters,
|
||||
and \fIincr\fP, an optional increment, is an integer.
|
||||
When integers are supplied, the expression expands to each number between
|
||||
\fIx\fP and \fIy\fP, inclusive.
|
||||
Supplied integers may be prefixed with \fI0\fP to force each term to have the
|
||||
same width. When either \fIx\fP or \fPy\fP begins with a zero, the shell
|
||||
attempts to force all generated terms to contain the same number of digits,
|
||||
zero-padding where necessary.
|
||||
When characters are supplied, the expression expands to each character
|
||||
lexicographically between \fIx\fP and \fIy\fP, inclusive. Note that
|
||||
both \fIx\fP and \fIy\fP must be of the same type.
|
||||
When the increment is supplied, it is used as the difference between
|
||||
each term. The default increment is 1 or -1 as appropriate.
|
||||
.PP
|
||||
Brace expansion is performed before any other expansions,
|
||||
and any characters special to other expansions are preserved
|
||||
@@ -3141,14 +3161,12 @@ The general format for appending output is:
|
||||
.PP
|
||||
.SS Redirecting Standard Output and Standard Error
|
||||
.PP
|
||||
.B Bash
|
||||
allows both the
|
||||
This construct allows both the
|
||||
standard output (file descriptor 1) and
|
||||
the standard error output (file descriptor 2)
|
||||
to be redirected to the file whose name is the
|
||||
expansion of
|
||||
.I word
|
||||
with this construct.
|
||||
.IR word .
|
||||
.PP
|
||||
There are two formats for redirecting standard output and
|
||||
standard error:
|
||||
@@ -3167,6 +3185,27 @@ This is semantically equivalent to
|
||||
.PP
|
||||
\fB>\fP\fIword\fP 2\fB>&\fP1
|
||||
.RE
|
||||
.PP
|
||||
.SS Appending Standard Output and Standard Error
|
||||
.PP
|
||||
This construct allows both the
|
||||
standard output (file descriptor 1) and
|
||||
the standard error output (file descriptor 2)
|
||||
to be appended to the file whose name is the
|
||||
expansion of
|
||||
.IR word .
|
||||
.PP
|
||||
The format for appending standard output and standard error is:
|
||||
.RS
|
||||
.PP
|
||||
\fB&>>\fP\fIword\fP
|
||||
.RE
|
||||
.PP
|
||||
This is semantically equivalent to
|
||||
.RS
|
||||
.PP
|
||||
\fB>>\fP\fIword\fP 2\fB>&\fP1
|
||||
.RE
|
||||
.SS Here Documents
|
||||
.PP
|
||||
This type of redirection instructs the shell to read input from the
|
||||
@@ -5338,6 +5377,11 @@ Attempt completion on the text before point, comparing
|
||||
the text against lines from the history list for possible
|
||||
completion matches.
|
||||
.TP
|
||||
.B dabbrev\-expand
|
||||
Attempt menu completion on the text before point, comparing
|
||||
the text against lines from the history list for possible
|
||||
completion matches.
|
||||
.TP
|
||||
.B complete\-into\-braces (M\-{)
|
||||
Perform filename completion and insert the list of possible completions
|
||||
enclosed within braces so the list is available to the shell (see
|
||||
@@ -6175,6 +6219,16 @@ Remove any current binding for \fIkeyseq\fP.
|
||||
.B \-x \fIkeyseq\fP:\fIshell\-command\fP
|
||||
Cause \fIshell\-command\fP to be executed whenever \fIkeyseq\fP is
|
||||
entered.
|
||||
When \fIshell\-command\fP is executed, the shell sets the
|
||||
.B READLINE_LINE
|
||||
variable to the contents of the \fBreadline\fP line buffer and the
|
||||
.B READLINE_POINT
|
||||
variable to the current location of the insertion point.
|
||||
If the executed command changes the value of
|
||||
.B READLINE_LINE
|
||||
or
|
||||
.BR READLINE_POINT ,
|
||||
those new values will be reflected in the editing state.
|
||||
.PD
|
||||
.PP
|
||||
The return value is 0 unless an unrecognized option is given or an
|
||||
@@ -6193,10 +6247,8 @@ loop. If \fIn\fP is specified, break \fIn\fP levels.
|
||||
must be \(>= 1. If
|
||||
.I n
|
||||
is greater than the number of enclosing loops, all enclosing loops
|
||||
are exited. The return value is 0 unless the shell is not executing
|
||||
a loop when
|
||||
.B break
|
||||
is executed.
|
||||
are exited.
|
||||
The return value is 0 unless \fIn\fP is not greater than or equal to 1.
|
||||
.TP
|
||||
\fBbuiltin\fP \fIshell\-builtin\fP [\fIarguments\fP]
|
||||
Execute the specified shell builtin, passing it
|
||||
@@ -6552,10 +6604,8 @@ is specified, resume at the \fIn\fPth enclosing loop.
|
||||
must be \(>= 1. If
|
||||
.I n
|
||||
is greater than the number of enclosing loops, the last enclosing loop
|
||||
(the ``top-level'' loop) is resumed. The return value is 0 unless the
|
||||
shell is not executing a loop when
|
||||
.B continue
|
||||
is executed.
|
||||
(the ``top-level'' loop) is resumed.
|
||||
The return value is 0 unless \fIn\fP is not greater than or equal to 1.
|
||||
.TP
|
||||
\fBdeclare\fP [\fB\-afFirtx\fP] [\fB\-p\fP] [\fIname\fP[=\fIvalue\fP] ...]
|
||||
.PD 0
|
||||
|
||||
+61
-12
@@ -229,7 +229,7 @@ than by an executable program somewhere in the file system.
|
||||
A @code{token} that performs a control function. It is a @code{newline}
|
||||
or one of the following:
|
||||
@samp{||}, @samp{&&}, @samp{&}, @samp{;}, @samp{;;},
|
||||
@samp{|}, @samp{(}, or @samp{)}.
|
||||
@samp{|}, @samp{|&}, @samp{(}, or @samp{)}.
|
||||
|
||||
@item exit status
|
||||
@cindex exit status
|
||||
@@ -606,21 +606,28 @@ the command was terminated by signal @var{n}.
|
||||
@cindex pipeline
|
||||
@cindex commands, pipelines
|
||||
|
||||
A @code{pipeline} is a sequence of simple commands separated by
|
||||
@samp{|}.
|
||||
A @code{pipeline} is a sequence of simple commands separated by one of
|
||||
the control operators @samp{|} or @samp{|&}.
|
||||
|
||||
@rwindex time
|
||||
@rwindex !
|
||||
@cindex command timing
|
||||
The format for a pipeline is
|
||||
@example
|
||||
[@code{time} [@code{-p}]] [@code{!}] @var{command1} [@code{|} @var{command2} @dots{}]
|
||||
[@code{time} [@code{-p}]] [@code{!}] @var{command1} [ [@code{|} or @code{|&}] @var{command2} @dots{}]
|
||||
@end example
|
||||
|
||||
@noindent
|
||||
The output of each command in the pipeline is connected via a pipe
|
||||
to the input of the next command.
|
||||
That is, each command reads the previous command's output.
|
||||
That is, each command reads the previous command's output. This
|
||||
connection is performed before any redirections specified by the
|
||||
command.
|
||||
|
||||
If @samp{|&} is used, the standard error of @var{command1} is connected to
|
||||
@var{command2}'s standard input through the pipe; it is shorthand for
|
||||
@code{2>&1 |}. This implicit redirection of the standard error is
|
||||
performed after any redirections specified by the command.
|
||||
|
||||
The reserved word @code{time} causes timing statistics
|
||||
to be printed for the pipeline once it finishes.
|
||||
@@ -852,14 +859,17 @@ of alphabetic characters.
|
||||
The @samp{|} is used to separate multiple patterns, and the @samp{)}
|
||||
operator terminates a pattern list.
|
||||
A list of patterns and an associated command-list is known
|
||||
as a @var{clause}. Each clause must be terminated with @samp{;;}.
|
||||
as a @var{clause}.
|
||||
|
||||
Each clause must be terminated with @samp{;;}, @samp{,&}, or @samp{;;&}.
|
||||
The @var{word} undergoes tilde expansion, parameter expansion, command
|
||||
substitution, arithmetic expansion, and quote removal before matching is
|
||||
attempted. Each @var{pattern} undergoes tilde expansion, parameter
|
||||
expansion, command substitution, and arithmetic expansion.
|
||||
|
||||
There may be an arbitrary number of @code{case} clauses, each terminated
|
||||
by a @samp{;;}. The first pattern that matches determines the
|
||||
by a @samp{;;}, @samp{;&}, or @samp{;;&}.
|
||||
The first pattern that matches determines the
|
||||
command-list that is executed.
|
||||
|
||||
Here is an example using @code{case} in a script that could be used to
|
||||
@@ -878,6 +888,15 @@ echo " legs."
|
||||
@end example
|
||||
|
||||
@noindent
|
||||
|
||||
If the @samp{;;} operator is used, no subsequent matches are attempted after
|
||||
the first pattern match.
|
||||
Using @samp{;&} in place of @samp{;;} causes execution to continue with
|
||||
the @var{command-list} associated with the next clause, if any.
|
||||
Using @samp{;;&} in place of @samp{;;} causes the shell to test the patterns
|
||||
in the next clause, if any, and execute any associated @var{command-list}
|
||||
on a successful match.
|
||||
|
||||
The return status is zero if no @var{pattern} is matched. Otherwise, the
|
||||
return status is the exit status of the @var{command-list} executed.
|
||||
|
||||
@@ -1395,13 +1414,20 @@ bash$ echo a@{d,c,b@}e
|
||||
ade ace abe
|
||||
@end example
|
||||
|
||||
A sequence expression takes the form @code{@{@var{x}..@var{y}@}},
|
||||
where @var{x} and @var{y} are either integers or single characters.
|
||||
A sequence expression takes the form @code{@{@var{x}..@var{y}[@var{incr}]@}},
|
||||
where @var{x} and @var{y} are either integers or single characters,
|
||||
and @var{incr}, an optional increment, is an integer.
|
||||
When integers are supplied, the expression expands to each number between
|
||||
@var{x} and @var{y}, inclusive.
|
||||
Supplied integers may be prefixed with @samp{0} to force each term to have the
|
||||
same width. When either @var{x} or @var{y} begins with a zero, the shell
|
||||
attempts to force all generated terms to contain the same number of digits,
|
||||
zero-padding where necessary.
|
||||
When characters are supplied, the expression expands to each character
|
||||
lexicographically between @var{x} and @var{y}, inclusive. Note that
|
||||
both @var{x} and @var{y} must be of the same type.
|
||||
When the increment is supplied, it is used as the difference between
|
||||
each term. The default increment is 1 or -1 as appropriate.
|
||||
|
||||
Brace expansion is performed before any other expansions,
|
||||
and any characters special to other expansions are preserved
|
||||
@@ -2094,11 +2120,11 @@ The general format for appending output is:
|
||||
@end example
|
||||
|
||||
@subsection Redirecting Standard Output and Standard Error
|
||||
Bash allows both the
|
||||
This construct allows both the
|
||||
standard output (file descriptor 1) and
|
||||
the standard error output (file descriptor 2)
|
||||
to be redirected to the file whose name is the
|
||||
expansion of @var{word} with this construct.
|
||||
expansion of @var{word}.
|
||||
|
||||
There are two formats for redirecting standard output and
|
||||
standard error:
|
||||
@@ -2117,6 +2143,23 @@ This is semantically equivalent to
|
||||
>@var{word} 2>&1
|
||||
@end example
|
||||
|
||||
@subsection Appending Standard Output and Standard Error
|
||||
This construct allows both the
|
||||
standard output (file descriptor 1) and
|
||||
the standard error output (file descriptor 2)
|
||||
to be appended to the file whose name is the
|
||||
expansion of @var{word}.
|
||||
|
||||
The format for appending standard output and standard error is:
|
||||
@example
|
||||
&>>@var{word}
|
||||
@end example
|
||||
@noindent
|
||||
This is semantically equivalent to
|
||||
@example
|
||||
>>@var{word} 2>&1
|
||||
@end example
|
||||
|
||||
@subsection Here Documents
|
||||
This type of redirection instructs the shell to read input from the
|
||||
current source until a line containing only @var{word}
|
||||
@@ -3202,7 +3245,13 @@ Remove any current binding for @var{keyseq}.
|
||||
@item -x @var{keyseq:shell-command}
|
||||
Cause @var{shell-command} to be executed whenever @var{keyseq} is
|
||||
entered.
|
||||
|
||||
When @var{shell-command} is executed, the shell sets the
|
||||
@code{READLINE_LINE} variable to the contents of the Readline line
|
||||
buffer and the @code{READLINE_POINT} variable to the current location
|
||||
of the insertion point.
|
||||
If the executed command changes the value of @code{READLINE_LINE} or
|
||||
@code{READLINE_POINT}, those new values will be reflected in the
|
||||
editing state.
|
||||
@end table
|
||||
|
||||
@noindent
|
||||
|
||||
+49
-10
@@ -229,7 +229,7 @@ than by an executable program somewhere in the file system.
|
||||
A @code{token} that performs a control function. It is a @code{newline}
|
||||
or one of the following:
|
||||
@samp{||}, @samp{&&}, @samp{&}, @samp{;}, @samp{;;},
|
||||
@samp{|}, @samp{(}, or @samp{)}.
|
||||
@samp{|}, @samp{|&}, @samp{(}, or @samp{)}.
|
||||
|
||||
@item exit status
|
||||
@cindex exit status
|
||||
@@ -606,21 +606,28 @@ the command was terminated by signal @var{n}.
|
||||
@cindex pipeline
|
||||
@cindex commands, pipelines
|
||||
|
||||
A @code{pipeline} is a sequence of simple commands separated by
|
||||
@samp{|}.
|
||||
A @code{pipeline} is a sequence of simple commands separated by one of
|
||||
the control operators @samp{|} or @samp{|&}.
|
||||
|
||||
@rwindex time
|
||||
@rwindex !
|
||||
@cindex command timing
|
||||
The format for a pipeline is
|
||||
@example
|
||||
[@code{time} [@code{-p}]] [@code{!}] @var{command1} [@code{|} @var{command2} @dots{}]
|
||||
[@code{time} [@code{-p}]] [@code{!}] @var{command1} [ [@code{|} or @code{|&}] @var{command2} @dots{}]
|
||||
@end example
|
||||
|
||||
@noindent
|
||||
The output of each command in the pipeline is connected via a pipe
|
||||
to the input of the next command.
|
||||
That is, each command reads the previous command's output.
|
||||
That is, each command reads the previous command's output. This
|
||||
connection is performed before any redirections specified by the
|
||||
command.
|
||||
|
||||
If @samp{|&} is used, the standard error of @var{command1} is connected to
|
||||
@var{command2}'s standard input through the pipe; it is shorthand for
|
||||
@code{2>&1 |}. This implicit redirection of the standard error is
|
||||
performed after any redirections specified by the command.
|
||||
|
||||
The reserved word @code{time} causes timing statistics
|
||||
to be printed for the pipeline once it finishes.
|
||||
@@ -1395,13 +1402,20 @@ bash$ echo a@{d,c,b@}e
|
||||
ade ace abe
|
||||
@end example
|
||||
|
||||
A sequence expression takes the form @code{@{@var{x}..@var{y}@}},
|
||||
where @var{x} and @var{y} are either integers or single characters.
|
||||
A sequence expression takes the form @code{@{@var{x}..@var{y}[@var{incr}]@}},
|
||||
where @var{x} and @var{y} are either integers or single characters,
|
||||
and @var{incr}, an optional increment, is an integer.
|
||||
When integers are supplied, the expression expands to each number between
|
||||
@var{x} and @var{y}, inclusive.
|
||||
Supplied integers may be prefixed with @samp{0} to force each term to have the
|
||||
same width. When either @var{x} or @var{y} begins with a zero, the shell
|
||||
attempts to force all generated terms to contain the same number of digits,
|
||||
zero-padding where necessary.
|
||||
When characters are supplied, the expression expands to each character
|
||||
lexicographically between @var{x} and @var{y}, inclusive. Note that
|
||||
both @var{x} and @var{y} must be of the same type.
|
||||
When the increment is supplied, it is used as the difference between
|
||||
each term. The default increment is 1 or -1 as appropriate.
|
||||
|
||||
Brace expansion is performed before any other expansions,
|
||||
and any characters special to other expansions are preserved
|
||||
@@ -2094,11 +2108,11 @@ The general format for appending output is:
|
||||
@end example
|
||||
|
||||
@subsection Redirecting Standard Output and Standard Error
|
||||
Bash allows both the
|
||||
This construct allows both the
|
||||
standard output (file descriptor 1) and
|
||||
the standard error output (file descriptor 2)
|
||||
to be redirected to the file whose name is the
|
||||
expansion of @var{word} with this construct.
|
||||
expansion of @var{word}.
|
||||
|
||||
There are two formats for redirecting standard output and
|
||||
standard error:
|
||||
@@ -2117,6 +2131,23 @@ This is semantically equivalent to
|
||||
>@var{word} 2>&1
|
||||
@end example
|
||||
|
||||
@subsection Appending Standard Output and Standard Error
|
||||
This construct allows both the
|
||||
standard output (file descriptor 1) and
|
||||
the standard error output (file descriptor 2)
|
||||
to be appended to the file whose name is the
|
||||
expansion of @var{word}.
|
||||
|
||||
The format for appending standard output and standard error is:
|
||||
@example
|
||||
&>>@var{word}
|
||||
@end example
|
||||
@noindent
|
||||
This is semantically equivalent to
|
||||
@example
|
||||
>>@var{word} 2>&1
|
||||
@end example
|
||||
|
||||
@subsection Here Documents
|
||||
This type of redirection instructs the shell to read input from the
|
||||
current source until a line containing only @var{word}
|
||||
@@ -3202,7 +3233,13 @@ Remove any current binding for @var{keyseq}.
|
||||
@item -x @var{keyseq:shell-command}
|
||||
Cause @var{shell-command} to be executed whenever @var{keyseq} is
|
||||
entered.
|
||||
|
||||
When @var{shell-command} is executed, the shell sets the
|
||||
@code{READLINE_LINE} variable to the contents of the Readline line
|
||||
buffer and the @code{READLINE_POINT} variable to the current location
|
||||
of the insertion point.
|
||||
If the executed command changes the value of @code{READLINE_LINE} or
|
||||
@code{READLINE_POINT}, those new values will be reflected in the
|
||||
editing state.
|
||||
@end table
|
||||
|
||||
@noindent
|
||||
@@ -3610,6 +3647,8 @@ not echoed.
|
||||
@item -t @var{timeout}
|
||||
Cause @code{read} to time out and return failure if a complete line of
|
||||
input is not read within @var{timeout} seconds.
|
||||
@var{timeout} may be a decimal number with a fractional portion following
|
||||
the decimal point.
|
||||
This option has no effect if @code{read} is not reading input from the
|
||||
terminal or a pipe.
|
||||
|
||||
|
||||
+2
-2
@@ -2,9 +2,9 @@
|
||||
Copyright (C) 1988-2008 Free Software Foundation, Inc.
|
||||
@end ignore
|
||||
|
||||
@set LASTCHANGE Sun May 4 22:23:58 EDT 2008
|
||||
@set LASTCHANGE Sun May 25 10:48:26 EDT 2008
|
||||
|
||||
@set EDITION 4.0
|
||||
@set VERSION 4.0
|
||||
@set UPDATED 4 May 2008
|
||||
@set UPDATED 25 May 2008
|
||||
@set UPDATED-MONTH May 2008
|
||||
|
||||
+3
-3
@@ -2,9 +2,9 @@
|
||||
Copyright (C) 1988-2008 Free Software Foundation, Inc.
|
||||
@end ignore
|
||||
|
||||
@set LASTCHANGE Fri Apr 25 12:33:01 EDT 2008
|
||||
@set LASTCHANGE Sun May 4 22:23:58 EDT 2008
|
||||
|
||||
@set EDITION 4.0
|
||||
@set VERSION 4.0
|
||||
@set UPDATED 25 April 2008
|
||||
@set UPDATED-MONTH April 2008
|
||||
@set UPDATED 4 May 2008
|
||||
@set UPDATED-MONTH May 2008
|
||||
|
||||
+11
-4
@@ -2292,10 +2292,17 @@ execute_case_command (case_command)
|
||||
|
||||
if (match)
|
||||
{
|
||||
if (clauses->action && ignore_return)
|
||||
clauses->action->flags |= CMD_IGNORE_RETURN;
|
||||
retval = execute_command (clauses->action);
|
||||
EXIT_CASE ();
|
||||
do
|
||||
{
|
||||
if (clauses->action && ignore_return)
|
||||
clauses->action->flags |= CMD_IGNORE_RETURN;
|
||||
retval = execute_command (clauses->action);
|
||||
}
|
||||
while ((clauses->flags & CASEPAT_FALLTHROUGH) && (clauses = clauses->next));
|
||||
if ((clauses->flags & CASEPAT_TESTNEXT) == 0)
|
||||
EXIT_CASE ();
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
QUIT;
|
||||
|
||||
+1
-1
@@ -3138,7 +3138,7 @@ execute_builtin (builtin, words, flags, subshell)
|
||||
eval builtin is being called, and we're supposed to ignore the exit
|
||||
value of the command, we turn the -e flag off ourselves, then
|
||||
restore it when the command completes. This is also a problem (as
|
||||
below) for the command and source builtins. */
|
||||
below) for the command and source/. builtins. */
|
||||
if (subshell == 0 && (flags & CMD_IGNORE_RETURN) &&
|
||||
(builtin == eval_builtin || builtin == command_builtin || builtin == source_builtin))
|
||||
{
|
||||
|
||||
@@ -1316,6 +1316,11 @@ Attempt completion on the text before point, comparing
|
||||
the text against lines from the history list for possible
|
||||
completion matches.
|
||||
|
||||
@item dabbrev-expand ()
|
||||
Attempt menu completion on the text before point, comparing
|
||||
the text against lines from the history list for possible
|
||||
completion matches.
|
||||
|
||||
@item complete-into-braces (M-@{)
|
||||
Perform filename completion and insert the list of possible completions
|
||||
enclosed within braces so the list is available to the shell
|
||||
|
||||
@@ -574,7 +574,7 @@ The default is @samp{off}.
|
||||
@vindex revert-all-at-newline
|
||||
If set to @samp{on}, Readline will undo all changes to history lines
|
||||
before returning when @code{accept-line} is executed. By default,
|
||||
history lines may be edited and retain individual undo lists across
|
||||
history lines may be modified and retain individual undo lists across
|
||||
calls to @code{readline}. The default is @samp{off}.
|
||||
|
||||
@item show-all-if-ambiguous
|
||||
|
||||
@@ -4,7 +4,7 @@ Copyright (C) 1988-2008 Free Software Foundation, Inc.
|
||||
|
||||
@set EDITION 5.2
|
||||
@set VERSION 5.2
|
||||
@set UPDATED 8 May 2008
|
||||
@set UPDATED 25 May 2008
|
||||
@set UPDATED-MONTH May 2008
|
||||
|
||||
@set LASTCHANGE Thu May 8 09:29:33 EDT 2008
|
||||
@set LASTCHANGE Sun May 25 12:00:28 EDT 2008
|
||||
|
||||
@@ -4,7 +4,7 @@ Copyright (C) 1988-2008 Free Software Foundation, Inc.
|
||||
|
||||
@set EDITION 5.2
|
||||
@set VERSION 5.2
|
||||
@set UPDATED 7 April 2008
|
||||
@set UPDATED-MONTH April 2008
|
||||
@set UPDATED 8 May 2008
|
||||
@set UPDATED-MONTH May 2008
|
||||
|
||||
@set LASTCHANGE Mon Apr 7 23:00:49 EDT 2008
|
||||
@set LASTCHANGE Thu May 8 09:29:33 EDT 2008
|
||||
|
||||
+2
-1
@@ -1,7 +1,7 @@
|
||||
/* make_cmd.c -- Functions for making instances of the various
|
||||
parser constructs. */
|
||||
|
||||
/* Copyright (C) 1989-2007 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1989-2008 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
@@ -690,6 +690,7 @@ make_redirection (source, instruction, dest_and_filename)
|
||||
break;
|
||||
|
||||
case r_appending_to: /* >>foo */
|
||||
case r_append_err_and_out: /* &>> filename */
|
||||
temp->flags = O_APPEND | O_WRONLY | O_CREAT;
|
||||
break;
|
||||
|
||||
|
||||
+1
-1
@@ -685,7 +685,7 @@ make_redirection (source, instruction, dest_and_filename)
|
||||
|
||||
case r_output_direction: /* >foo */
|
||||
case r_output_force: /* >| foo */
|
||||
case r_err_and_out: /* command &>filename */
|
||||
case r_err_and_out: /* &>filename */
|
||||
temp->flags = O_TRUNC | O_WRONLY | O_CREAT;
|
||||
break;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Yacc grammar for bash. */
|
||||
|
||||
/* Copyright (C) 1989-2007 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1989-2008 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
@@ -251,6 +251,12 @@ static char *current_decoded_prompt;
|
||||
/* The number of lines read from input while creating the current command. */
|
||||
int current_command_line_count;
|
||||
|
||||
/* The token that currently denotes the end of parse. */
|
||||
int shell_eof_token;
|
||||
|
||||
/* The token currently being read. */
|
||||
int current_token;
|
||||
|
||||
/* Variables to manage the task of reading here documents, because we need to
|
||||
defer the reading until after a complete command has been collected. */
|
||||
static REDIRECT *redir_stack[10];
|
||||
@@ -275,6 +281,19 @@ static int function_bstart;
|
||||
/* The line number in a script at which an arithmetic for command starts. */
|
||||
static int arith_for_lineno;
|
||||
|
||||
/* The current parser state. */
|
||||
static int parser_state;
|
||||
|
||||
/* The last read token, or NULL. read_token () uses this for context
|
||||
checking. */
|
||||
static int last_read_token;
|
||||
|
||||
/* The token read prior to last_read_token. */
|
||||
static int token_before_that;
|
||||
|
||||
/* The token read prior to token_before_that. */
|
||||
static int two_tokens_ago;
|
||||
|
||||
/* The line number in a script where the word in a `case WORD', `select WORD'
|
||||
or `for WORD' begins. This is a nested command maximum, since the array
|
||||
index is decremented after a case, select, or for command is parsed. */
|
||||
@@ -316,8 +335,9 @@ static REDIRECTEE redir;
|
||||
%token <word_list> ARITH_CMD ARITH_FOR_EXPRS
|
||||
%token <command> COND_CMD
|
||||
%token AND_AND OR_OR GREATER_GREATER LESS_LESS LESS_AND LESS_LESS_LESS
|
||||
%token GREATER_AND SEMI_SEMI LESS_LESS_MINUS AND_GREATER LESS_GREATER
|
||||
%token GREATER_BAR
|
||||
%token GREATER_AND SEMI_SEMI SEMI_AND SEMI_SEMI_AND
|
||||
%token LESS_LESS_MINUS AND_GREATER AND_GREATER_GREATER LESS_GREATER
|
||||
%token GREATER_BAR BAR_AND
|
||||
|
||||
/* The types that the various syntactical units return. */
|
||||
|
||||
@@ -340,7 +360,7 @@ static REDIRECTEE redir;
|
||||
|
||||
%left '&' ';' '\n' yacc_EOF
|
||||
%left AND_AND OR_OR
|
||||
%right '|'
|
||||
%right '|' BAR_AND
|
||||
%%
|
||||
|
||||
inputunit: simple_list simple_list_terminator
|
||||
@@ -521,6 +541,11 @@ redirection: '>' WORD
|
||||
redir.filename = $2;
|
||||
$$ = make_redirection (1, r_err_and_out, redir);
|
||||
}
|
||||
| AND_GREATER_GREATER WORD
|
||||
{
|
||||
redir.filename = $2;
|
||||
$$ = make_redirection (1, r_append_err_and_out, redir);
|
||||
}
|
||||
| NUMBER LESS_GREATER WORD
|
||||
{
|
||||
redir.filename = $3;
|
||||
@@ -829,8 +854,17 @@ pattern_list: newline_list pattern ')' compound_list
|
||||
;
|
||||
|
||||
case_clause_sequence: pattern_list SEMI_SEMI
|
||||
{ $$ = $1; }
|
||||
| case_clause_sequence pattern_list SEMI_SEMI
|
||||
{ $2->next = $1; $$ = $2; }
|
||||
| pattern_list SEMI_AND
|
||||
{ $1->flags |= CASEPAT_FALLTHROUGH; $$ = $1; }
|
||||
| case_clause_sequence pattern_list SEMI_AND
|
||||
{ $2->flags |= CASEPAT_FALLTHROUGH; $2->next = $1; $$ = $2; }
|
||||
| pattern_list SEMI_SEMI_AND
|
||||
{ $1->flags |= CASEPAT_TESTNEXT; $$ = $1; }
|
||||
| case_clause_sequence pattern_list SEMI_SEMI_AND
|
||||
{ $2->flags |= CASEPAT_TESTNEXT; $2->next = $1; $$ = $2; }
|
||||
;
|
||||
|
||||
pattern: WORD
|
||||
@@ -999,9 +1033,30 @@ pipeline_command: pipeline
|
||||
|
||||
;
|
||||
|
||||
pipeline:
|
||||
pipeline '|' newline_list pipeline
|
||||
pipeline: pipeline '|' newline_list pipeline
|
||||
{ $$ = command_connect ($1, $4, '|'); }
|
||||
| pipeline BAR_AND newline_list pipeline
|
||||
{
|
||||
/* Make cmd1 |& cmd2 equivalent to cmd1 2>&1 | cmd2 */
|
||||
COMMAND *tc;
|
||||
REDIRECTEE rd;
|
||||
REDIRECT *r;
|
||||
|
||||
tc = $1;
|
||||
rd.dest = 1;
|
||||
r = make_redirection (2, r_duplicating_output, rd);
|
||||
if (tc->redirects)
|
||||
{
|
||||
register REDIRECT *t;
|
||||
for (t = tc->redirects; t->next; t = t->next)
|
||||
;
|
||||
t->next = r;
|
||||
}
|
||||
else
|
||||
tc->redirects = r;
|
||||
|
||||
$$ = command_connect ($1, $4, '|');
|
||||
}
|
||||
| command
|
||||
{ $$ = $1; }
|
||||
;
|
||||
@@ -1028,22 +1083,6 @@ timespec: TIME
|
||||
# define expanding_alias() 0
|
||||
#endif
|
||||
|
||||
/* The token currently being read. */
|
||||
static int current_token;
|
||||
|
||||
/* The last read token, or NULL. read_token () uses this for context
|
||||
checking. */
|
||||
static int last_read_token;
|
||||
|
||||
/* The token read prior to last_read_token. */
|
||||
static int token_before_that;
|
||||
|
||||
/* The token read prior to token_before_that. */
|
||||
static int two_tokens_ago;
|
||||
|
||||
/* The current parser state. */
|
||||
static int parser_state;
|
||||
|
||||
/* Global var is non-zero when end of file has been reached. */
|
||||
int EOF_Reached = 0;
|
||||
|
||||
@@ -1779,11 +1818,15 @@ STRING_INT_ALIST other_token_alist[] = {
|
||||
{ "<&", LESS_AND },
|
||||
{ ">&", GREATER_AND },
|
||||
{ ";;", SEMI_SEMI },
|
||||
{ ";&", SEMI_AND },
|
||||
{ ";;&", SEMI_SEMI_AND },
|
||||
{ "<<-", LESS_LESS_MINUS },
|
||||
{ "<<<", LESS_LESS_LESS },
|
||||
{ "&>", AND_GREATER },
|
||||
{ "&>>", AND_GREATER_GREATER },
|
||||
{ "<>", LESS_GREATER },
|
||||
{ ">|", GREATER_BAR },
|
||||
{ "|&", BAR_AND },
|
||||
{ "EOF", yacc_EOF },
|
||||
/* Tokens whose value is the character itself */
|
||||
{ ">", '>' },
|
||||
@@ -2212,7 +2255,7 @@ static int open_brace_count;
|
||||
|
||||
#define command_token_position(token) \
|
||||
(((token) == ASSIGNMENT_WORD) || \
|
||||
((token) != SEMI_SEMI && reserved_word_acceptable(token)))
|
||||
((token) != SEMI_SEMI && (token) != SEMI_AND && (token) != SEMI_SEMI_AND && reserved_word_acceptable(token)))
|
||||
|
||||
#define assignment_acceptable(token) \
|
||||
(command_token_position(token) && ((parser_state & PST_CASEPAT) == 0))
|
||||
@@ -2616,8 +2659,14 @@ read_token (command)
|
||||
#if defined (ALIAS)
|
||||
parser_state &= ~PST_ALEXPNEXT;
|
||||
#endif /* ALIAS */
|
||||
|
||||
return (SEMI_SEMI);
|
||||
peek_char = shell_getc (1);
|
||||
if MBTEST(peek_char == '&')
|
||||
return (SEMI_SEMI_AND);
|
||||
else
|
||||
{
|
||||
shell_ungetc (peek_char);
|
||||
return (SEMI_SEMI);
|
||||
}
|
||||
|
||||
case '&':
|
||||
return (AND_AND);
|
||||
@@ -2643,8 +2692,27 @@ read_token (command)
|
||||
return (LESS_GREATER);
|
||||
else if MBTEST(character == '>' && peek_char == '|')
|
||||
return (GREATER_BAR);
|
||||
else if MBTEST(peek_char == '>' && character == '&')
|
||||
return (AND_GREATER);
|
||||
else if MBTEST(character == '&' && peek_char == '>')
|
||||
{
|
||||
peek_char = shell_getc (1);
|
||||
if MBTEST(peek_char == '>')
|
||||
return (AND_GREATER_GREATER);
|
||||
else
|
||||
{
|
||||
shell_ungetc (peek_char);
|
||||
return (AND_GREATER);
|
||||
}
|
||||
}
|
||||
else if MBTEST(character == '|' && peek_char == '&')
|
||||
return (BAR_AND);
|
||||
else if MBTEST(character == ';' && peek_char == '&')
|
||||
{
|
||||
parser_state |= PST_CASEPAT;
|
||||
#if defined (ALIAS)
|
||||
parser_state &= ~PST_ALEXPNEXT;
|
||||
#endif /* ALIAS */
|
||||
return (SEMI_AND);
|
||||
}
|
||||
|
||||
shell_ungetc (peek_char);
|
||||
|
||||
@@ -2707,7 +2775,41 @@ tokword:
|
||||
#define P_COMMAND 0x08 /* parsing a command, so look for comments */
|
||||
#define P_BACKQUOTE 0x10 /* parsing a backquoted command substitution */
|
||||
|
||||
/* Lexical state while parsing a grouping construct or $(...). */
|
||||
#define LEX_WASDOL 0x001
|
||||
#define LEX_CKCOMMENT 0x002
|
||||
#define LEX_INCOMMENT 0x004
|
||||
#define LEX_PASSNEXT 0x008
|
||||
#define LEX_RESWDOK 0x010
|
||||
#define LEX_CKCASE 0x020
|
||||
#define LEX_INCASE 0x040
|
||||
#define LEX_INHEREDOC 0x080
|
||||
#define LEX_HEREDELIM 0x100 /* reading here-doc delimiter */
|
||||
#define LEX_STRIPDOC 0x200 /* <<- strip tabs from here doc delim */
|
||||
|
||||
#define COMSUB_META(ch) ((ch) == ';' || (ch) == '&' || (ch) = '|')
|
||||
|
||||
#define CHECK_NESTRET_ERROR() \
|
||||
do { \
|
||||
if (nestret == &matched_pair_error) \
|
||||
{ \
|
||||
free (ret); \
|
||||
return &matched_pair_error; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define APPEND_NESTRET() \
|
||||
do { \
|
||||
if (nestlen) \
|
||||
{ \
|
||||
RESIZE_MALLOCED_BUFFER (ret, retind, nestlen, retsize, 64); \
|
||||
strcpy (ret + retind, nestret); \
|
||||
retind += nestlen; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static char matched_pair_error;
|
||||
|
||||
static char *
|
||||
parse_matched_pair (qc, open, close, lenp, flags)
|
||||
int qc; /* `"' if this construct is within double quotes */
|
||||
@@ -3785,6 +3887,8 @@ reserved_word_acceptable (toksym)
|
||||
case IF:
|
||||
case OR_OR:
|
||||
case SEMI_SEMI:
|
||||
case SEMI_AND:
|
||||
case SEMI_SEMI_AND:
|
||||
case THEN:
|
||||
case TIME:
|
||||
case TIMEOPT:
|
||||
@@ -3845,7 +3949,8 @@ reset_readline_prompt ()
|
||||
newline separator for such tokens is replaced with a space. */
|
||||
static const int no_semi_successors[] = {
|
||||
'\n', '{', '(', ')', ';', '&', '|',
|
||||
CASE, DO, ELSE, IF, SEMI_SEMI, THEN, UNTIL, WHILE, AND_AND, OR_OR, IN,
|
||||
CASE, DO, ELSE, IF, SEMI_SEMI, SEMI_AND, SEMI_SEMI_AND, THEN, UNTIL,
|
||||
WHILE, AND_AND, OR_OR, IN,
|
||||
0
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Yacc grammar for bash. */
|
||||
|
||||
/* Copyright (C) 1989-2007 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1989-2008 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
@@ -251,6 +251,12 @@ static char *current_decoded_prompt;
|
||||
/* The number of lines read from input while creating the current command. */
|
||||
int current_command_line_count;
|
||||
|
||||
/* The token that currently denotes the end of parse. */
|
||||
int shell_eof_token;
|
||||
|
||||
/* The token currently being read. */
|
||||
int current_token;
|
||||
|
||||
/* Variables to manage the task of reading here documents, because we need to
|
||||
defer the reading until after a complete command has been collected. */
|
||||
static REDIRECT *redir_stack[10];
|
||||
@@ -275,6 +281,19 @@ static int function_bstart;
|
||||
/* The line number in a script at which an arithmetic for command starts. */
|
||||
static int arith_for_lineno;
|
||||
|
||||
/* The current parser state. */
|
||||
static int parser_state;
|
||||
|
||||
/* The last read token, or NULL. read_token () uses this for context
|
||||
checking. */
|
||||
static int last_read_token;
|
||||
|
||||
/* The token read prior to last_read_token. */
|
||||
static int token_before_that;
|
||||
|
||||
/* The token read prior to token_before_that. */
|
||||
static int two_tokens_ago;
|
||||
|
||||
/* The line number in a script where the word in a `case WORD', `select WORD'
|
||||
or `for WORD' begins. This is a nested command maximum, since the array
|
||||
index is decremented after a case, select, or for command is parsed. */
|
||||
@@ -316,8 +335,9 @@ static REDIRECTEE redir;
|
||||
%token <word_list> ARITH_CMD ARITH_FOR_EXPRS
|
||||
%token <command> COND_CMD
|
||||
%token AND_AND OR_OR GREATER_GREATER LESS_LESS LESS_AND LESS_LESS_LESS
|
||||
%token GREATER_AND SEMI_SEMI LESS_LESS_MINUS AND_GREATER LESS_GREATER
|
||||
%token GREATER_BAR
|
||||
%token GREATER_AND SEMI_SEMI SEMI_AND SEMI_SEMI_AND
|
||||
%token LESS_LESS_MINUS AND_GREATER AND_GREATER_GREATER LESS_GREATER
|
||||
%token GREATER_BAR BAR_AND
|
||||
|
||||
/* The types that the various syntactical units return. */
|
||||
|
||||
@@ -340,7 +360,7 @@ static REDIRECTEE redir;
|
||||
|
||||
%left '&' ';' '\n' yacc_EOF
|
||||
%left AND_AND OR_OR
|
||||
%right '|'
|
||||
%right '|' BAR_AND
|
||||
%%
|
||||
|
||||
inputunit: simple_list simple_list_terminator
|
||||
@@ -521,6 +541,11 @@ redirection: '>' WORD
|
||||
redir.filename = $2;
|
||||
$$ = make_redirection (1, r_err_and_out, redir);
|
||||
}
|
||||
| AND_GREATER_GREATER WORD
|
||||
{
|
||||
redir.filename = $2;
|
||||
$$ = make_redirection (1, r_append_err_and_out, redir);
|
||||
}
|
||||
| NUMBER LESS_GREATER WORD
|
||||
{
|
||||
redir.filename = $3;
|
||||
@@ -829,8 +854,17 @@ pattern_list: newline_list pattern ')' compound_list
|
||||
;
|
||||
|
||||
case_clause_sequence: pattern_list SEMI_SEMI
|
||||
{ $$ = $1; }
|
||||
| case_clause_sequence pattern_list SEMI_SEMI
|
||||
{ $2->next = $1; $$ = $2; }
|
||||
| pattern_list SEMI_AND
|
||||
{ $1->flags |= CASEPAT_FALLTHROUGH; $$ = $1; }
|
||||
| case_clause_sequence pattern_list SEMI_AND
|
||||
{ $2->flags |= CASEPAT_FALLTHROUGH; $2->next = $1; $$ = $2; }
|
||||
| pattern_list SEMI_SEMI_AND
|
||||
{ $1->flags |= CASEPAT_TESTNEXT; $$ = $1; }
|
||||
| case_clause_sequence pattern_list SEMI_SEMI_AND
|
||||
{ $2->flags |= CASEPAT_TESTNEXT; $2->next = $1; $$ = $2; }
|
||||
;
|
||||
|
||||
pattern: WORD
|
||||
@@ -999,9 +1033,30 @@ pipeline_command: pipeline
|
||||
|
||||
;
|
||||
|
||||
pipeline:
|
||||
pipeline '|' newline_list pipeline
|
||||
pipeline: pipeline '|' newline_list pipeline
|
||||
{ $$ = command_connect ($1, $4, '|'); }
|
||||
| pipeline BAR_AND newline_list pipeline
|
||||
{
|
||||
/* Make cmd1 |& cmd2 equivalent to cmd1 2>&1 | cmd2 */
|
||||
COMMAND *tc;
|
||||
REDIRECTEE rd;
|
||||
REDIRECT *r;
|
||||
|
||||
tc = $1;
|
||||
rd.dest = 1;
|
||||
r = make_redirection (2, r_duplicating_output, rd);
|
||||
if (tc->redirects)
|
||||
{
|
||||
register REDIRECT *t;
|
||||
for (t = tc->redirects; t->next; t = t->next)
|
||||
;
|
||||
t->next = r;
|
||||
}
|
||||
else
|
||||
tc->redirects = r;
|
||||
|
||||
$$ = command_connect ($1, $4, '|');
|
||||
}
|
||||
| command
|
||||
{ $$ = $1; }
|
||||
;
|
||||
@@ -1013,24 +1068,6 @@ timespec: TIME
|
||||
;
|
||||
%%
|
||||
|
||||
/* Possible states for the parser that require it to do special things. */
|
||||
#define PST_CASEPAT 0x0001 /* in a case pattern list */
|
||||
#define PST_ALEXPNEXT 0x0002 /* expand next word for aliases */
|
||||
#define PST_ALLOWOPNBRC 0x0004 /* allow open brace for function def */
|
||||
#define PST_NEEDCLOSBRC 0x0008 /* need close brace */
|
||||
#define PST_DBLPAREN 0x0010 /* double-paren parsing */
|
||||
#define PST_SUBSHELL 0x0020 /* ( ... ) subshell */
|
||||
#define PST_CMDSUBST 0x0040 /* $( ... ) command substitution */
|
||||
#define PST_CASESTMT 0x0080 /* parsing a case statement */
|
||||
#define PST_CONDCMD 0x0100 /* parsing a [[...]] command */
|
||||
#define PST_CONDEXPR 0x0200 /* parsing the guts of [[...]] */
|
||||
#define PST_ARITHFOR 0x0400 /* parsing an arithmetic for command */
|
||||
#define PST_ALEXPAND 0x0800 /* OK to expand aliases - unused */
|
||||
#define PST_CMDTOKEN 0x1000 /* command token OK - unused */
|
||||
#define PST_COMPASSIGN 0x2000 /* parsing x=(...) compound assignment */
|
||||
#define PST_ASSIGNOK 0x4000 /* assignment statement ok in this context */
|
||||
#define PST_REGEXP 0x8000 /* parsing an ERE/BRE as a single word */
|
||||
|
||||
/* Initial size to allocate for tokens, and the
|
||||
amount to grow them by. */
|
||||
#define TOKEN_DEFAULT_INITIAL_SIZE 496
|
||||
@@ -1046,22 +1083,6 @@ timespec: TIME
|
||||
# define expanding_alias() 0
|
||||
#endif
|
||||
|
||||
/* The token currently being read. */
|
||||
static int current_token;
|
||||
|
||||
/* The last read token, or NULL. read_token () uses this for context
|
||||
checking. */
|
||||
static int last_read_token;
|
||||
|
||||
/* The token read prior to last_read_token. */
|
||||
static int token_before_that;
|
||||
|
||||
/* The token read prior to token_before_that. */
|
||||
static int two_tokens_ago;
|
||||
|
||||
/* The current parser state. */
|
||||
static int parser_state;
|
||||
|
||||
/* Global var is non-zero when end of file has been reached. */
|
||||
int EOF_Reached = 0;
|
||||
|
||||
@@ -1797,11 +1818,15 @@ STRING_INT_ALIST other_token_alist[] = {
|
||||
{ "<&", LESS_AND },
|
||||
{ ">&", GREATER_AND },
|
||||
{ ";;", SEMI_SEMI },
|
||||
{ ";&", SEMI_AND },
|
||||
{ ";;&", SEMI_SEMI_AND },
|
||||
{ "<<-", LESS_LESS_MINUS },
|
||||
{ "<<<", LESS_LESS_LESS },
|
||||
{ "&>", AND_GREATER },
|
||||
{ "&>>", AND_GREATER_GREATER },
|
||||
{ "<>", LESS_GREATER },
|
||||
{ ">|", GREATER_BAR },
|
||||
{ "|&", BAR_AND },
|
||||
{ "EOF", yacc_EOF },
|
||||
/* Tokens whose value is the character itself */
|
||||
{ ">", '>' },
|
||||
@@ -2230,7 +2255,7 @@ static int open_brace_count;
|
||||
|
||||
#define command_token_position(token) \
|
||||
(((token) == ASSIGNMENT_WORD) || \
|
||||
((token) != SEMI_SEMI && reserved_word_acceptable(token)))
|
||||
((token) != SEMI_SEMI && (token) != SEMI_AND && (token) != SEMI_SEMI_AND && reserved_word_acceptable(token)))
|
||||
|
||||
#define assignment_acceptable(token) \
|
||||
(command_token_position(token) && ((parser_state & PST_CASEPAT) == 0))
|
||||
@@ -2634,8 +2659,14 @@ read_token (command)
|
||||
#if defined (ALIAS)
|
||||
parser_state &= ~PST_ALEXPNEXT;
|
||||
#endif /* ALIAS */
|
||||
|
||||
return (SEMI_SEMI);
|
||||
peek_char = shell_getc (1);
|
||||
if MBTEST(peek_char == '&')
|
||||
return (SEMI_SEMI_AND);
|
||||
else
|
||||
{
|
||||
shell_ungetc (peek_char);
|
||||
return (SEMI_SEMI);
|
||||
}
|
||||
|
||||
case '&':
|
||||
return (AND_AND);
|
||||
@@ -2661,8 +2692,27 @@ read_token (command)
|
||||
return (LESS_GREATER);
|
||||
else if MBTEST(character == '>' && peek_char == '|')
|
||||
return (GREATER_BAR);
|
||||
else if MBTEST(peek_char == '>' && character == '&')
|
||||
return (AND_GREATER);
|
||||
else if MBTEST(character == '&' && peek_char == '>')
|
||||
{
|
||||
peek_char = shell_getc (1);
|
||||
if MBTEST(peek_char == '>')
|
||||
return (AND_GREATER_GREATER);
|
||||
else
|
||||
{
|
||||
shell_ungetc (peek_char);
|
||||
return (AND_GREATER);
|
||||
}
|
||||
}
|
||||
else if MBTEST(character == '|' && peek_char == '&')
|
||||
return (BAR_AND);
|
||||
else if MBTEST(character == ';' && peek_char == '&')
|
||||
{
|
||||
parser_state |= PST_CASEPAT;
|
||||
#if defined (ALIAS)
|
||||
parser_state &= ~PST_ALEXPNEXT;
|
||||
#endif /* ALIAS */
|
||||
return (SEMI_AND);
|
||||
}
|
||||
|
||||
shell_ungetc (peek_char);
|
||||
|
||||
@@ -2725,7 +2775,41 @@ tokword:
|
||||
#define P_COMMAND 0x08 /* parsing a command, so look for comments */
|
||||
#define P_BACKQUOTE 0x10 /* parsing a backquoted command substitution */
|
||||
|
||||
/* Lexical state while parsing a grouping construct or $(...). */
|
||||
#define LEX_WASDOL 0x001
|
||||
#define LEX_CKCOMMENT 0x002
|
||||
#define LEX_INCOMMENT 0x004
|
||||
#define LEX_PASSNEXT 0x008
|
||||
#define LEX_RESWDOK 0x010
|
||||
#define LEX_CKCASE 0x020
|
||||
#define LEX_INCASE 0x040
|
||||
#define LEX_INHEREDOC 0x080
|
||||
#define LEX_HEREDELIM 0x100 /* reading here-doc delimiter */
|
||||
#define LEX_STRIPDOC 0x200 /* <<- strip tabs from here doc delim */
|
||||
|
||||
#define COMSUB_META(ch) ((ch) == ';' || (ch) == '&' || (ch) = '|')
|
||||
|
||||
#define CHECK_NESTRET_ERROR() \
|
||||
do { \
|
||||
if (nestret == &matched_pair_error) \
|
||||
{ \
|
||||
free (ret); \
|
||||
return &matched_pair_error; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define APPEND_NESTRET() \
|
||||
do { \
|
||||
if (nestlen) \
|
||||
{ \
|
||||
RESIZE_MALLOCED_BUFFER (ret, retind, nestlen, retsize, 64); \
|
||||
strcpy (ret + retind, nestret); \
|
||||
retind += nestlen; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static char matched_pair_error;
|
||||
|
||||
static char *
|
||||
parse_matched_pair (qc, open, close, lenp, flags)
|
||||
int qc; /* `"' if this construct is within double quotes */
|
||||
@@ -3803,6 +3887,8 @@ reserved_word_acceptable (toksym)
|
||||
case IF:
|
||||
case OR_OR:
|
||||
case SEMI_SEMI:
|
||||
case SEMI_AND:
|
||||
case SEMI_SEMI_AND:
|
||||
case THEN:
|
||||
case TIME:
|
||||
case TIMEOPT:
|
||||
@@ -3863,7 +3949,8 @@ reset_readline_prompt ()
|
||||
newline separator for such tokens is replaced with a space. */
|
||||
static const int no_semi_successors[] = {
|
||||
'\n', '{', '(', ')', ';', '&', '|',
|
||||
CASE, DO, ELSE, IF, SEMI_SEMI, THEN, UNTIL, WHILE, AND_AND, OR_OR, IN,
|
||||
CASE, DO, ELSE, IF, SEMI_SEMI, SEMI_AND, SEMI_SEMI_AND, THEN, UNTIL,
|
||||
WHILE, AND_AND, OR_OR, IN,
|
||||
0
|
||||
};
|
||||
|
||||
|
||||
+11
-2
@@ -1,6 +1,6 @@
|
||||
/* print_command -- A way to make readable commands from a command tree. */
|
||||
|
||||
/* Copyright (C) 1989-2005 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1989-2008 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
@@ -609,7 +609,12 @@ print_case_clauses (clauses)
|
||||
indentation += indentation_amount;
|
||||
make_command_string_internal (clauses->action);
|
||||
indentation -= indentation_amount;
|
||||
newline (";;");
|
||||
if (clauses->flags & CASEPAT_FALLTHROUGH)
|
||||
newline (";&");
|
||||
else if (clauses->flags & CASEPAT_TESTNEXT)
|
||||
newline (";;&");
|
||||
else
|
||||
newline (";;");
|
||||
clauses = clauses->next;
|
||||
}
|
||||
indentation -= indentation_amount;
|
||||
@@ -972,6 +977,10 @@ print_redirection (redirect)
|
||||
cprintf ("&>%s", redirectee->word);
|
||||
break;
|
||||
|
||||
case r_append_err_and_out:
|
||||
cprintf ("&>>%s", redirectee->word);
|
||||
break;
|
||||
|
||||
case r_input_output:
|
||||
if (redirector != 1)
|
||||
cprintf ("%d", redirector);
|
||||
|
||||
+6
-2
@@ -1,6 +1,6 @@
|
||||
/* print_command -- A way to make readable commands from a command tree. */
|
||||
|
||||
/* Copyright (C) 1989-2005 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1989-2008 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
@@ -969,7 +969,11 @@ print_redirection (redirect)
|
||||
break;
|
||||
|
||||
case r_err_and_out:
|
||||
cprintf (">&%s", redirectee->word);
|
||||
cprintf ("&>%s", redirectee->word);
|
||||
break;
|
||||
|
||||
case r_append_err_and_out:
|
||||
cprintf ("&>>%s", redirectee->word);
|
||||
break;
|
||||
|
||||
case r_input_output:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* redir.c -- Functions to perform input and output redirection. */
|
||||
|
||||
/* Copyright (C) 1997-2007 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1997-2008 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
@@ -217,6 +217,7 @@ expandable_redirection_filename (redirect)
|
||||
case r_input_direction:
|
||||
case r_inputa_direction:
|
||||
case r_err_and_out:
|
||||
case r_append_err_and_out:
|
||||
case r_input_output:
|
||||
case r_output_force:
|
||||
case r_duplicating_input_word:
|
||||
@@ -724,6 +725,7 @@ do_redirection_internal (redirect, flags)
|
||||
case r_input_direction:
|
||||
case r_inputa_direction:
|
||||
case r_err_and_out: /* command &>filename */
|
||||
case r_append_err_and_out: /* command &>> filename */
|
||||
case r_input_output:
|
||||
case r_output_force:
|
||||
if (posixly_correct && interactive_shell == 0)
|
||||
@@ -821,7 +823,7 @@ do_redirection_internal (redirect, flags)
|
||||
|
||||
/* If we are hacking both stdout and stderr, do the stderr
|
||||
redirection here. */
|
||||
if (ri == r_err_and_out)
|
||||
if (ri == r_err_and_out || ri == r_append_err_and_out)
|
||||
{
|
||||
if (flags & RX_ACTIVE)
|
||||
{
|
||||
@@ -1081,6 +1083,7 @@ stdin_redirection (ri, redirector)
|
||||
case r_appending_to:
|
||||
case r_duplicating_output:
|
||||
case r_err_and_out:
|
||||
case r_append_err_and_out:
|
||||
case r_output_force:
|
||||
case r_duplicating_output_word:
|
||||
return (0);
|
||||
|
||||
@@ -156,7 +156,7 @@ redirection_error (temp, error)
|
||||
#endif /* RESTRICTED_SHELL */
|
||||
|
||||
case HEREDOC_REDIRECT:
|
||||
internal_error (_("cannot create temp file for here document: %s"), strerror (heredoc_errno));
|
||||
internal_error (_("cannot create temp file for here-document: %s"), strerror (heredoc_errno));
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -1747,7 +1747,7 @@ shell_reinitialize ()
|
||||
reinit_special_variables ();
|
||||
|
||||
#if defined (READLINE)
|
||||
bashline_reset ();
|
||||
bashline_reinitialize ();
|
||||
#endif
|
||||
|
||||
shell_reinitialized = 1;
|
||||
|
||||
@@ -1747,7 +1747,7 @@ shell_reinitialize ()
|
||||
reinit_special_variables ();
|
||||
|
||||
#if defined (READLINE)
|
||||
bash_readline_initialized = 0;
|
||||
bashline_reset ();
|
||||
#endif
|
||||
|
||||
shell_reinitialized = 1;
|
||||
|
||||
@@ -408,7 +408,7 @@ throw_to_top_level ()
|
||||
|
||||
#if defined (READLINE)
|
||||
if (interactive)
|
||||
bashline_reinitialize ();
|
||||
bashline_reset ();
|
||||
#endif /* READLINE */
|
||||
|
||||
#if defined (PROCESS_SUBSTITUTION)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* sig.c - interface for shell signal handlers and signal initialization. */
|
||||
|
||||
/* Copyright (C) 1994-2006 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1994-2007 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
@@ -350,6 +350,25 @@ reset_terminating_signals ()
|
||||
#undef XSIG
|
||||
#undef XHANDLER
|
||||
|
||||
/* Run some of the cleanups that should be performed when we run
|
||||
jump_to_top_level from a builtin command context. XXX - might want to
|
||||
also call reset_parser here. */
|
||||
void
|
||||
top_level_cleanup ()
|
||||
{
|
||||
/* Clean up string parser environment. */
|
||||
while (parse_and_execute_level)
|
||||
parse_and_execute_cleanup ();
|
||||
|
||||
#if defined (PROCESS_SUBSTITUTION)
|
||||
unlink_fifo_list ();
|
||||
#endif /* PROCESS_SUBSTITUTION */
|
||||
|
||||
run_unwind_protects ();
|
||||
loop_level = continuing = breaking = 0;
|
||||
return_catch_flag = 0;
|
||||
}
|
||||
|
||||
/* What to do when we've been interrupted, and it is safe to handle it. */
|
||||
void
|
||||
throw_to_top_level ()
|
||||
@@ -372,7 +391,7 @@ throw_to_top_level ()
|
||||
/* Run any traps set on SIGINT. */
|
||||
run_interrupt_trap ();
|
||||
|
||||
/* Cleanup string parser environment. */
|
||||
/* Clean up string parser environment. */
|
||||
while (parse_and_execute_level)
|
||||
parse_and_execute_cleanup ();
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
BUILD_DIR=/usr/local/build/chet/bash/bash-current
|
||||
BUILD_DIR=/usr/local/build/bash/bash-current
|
||||
THIS_SH=$BUILD_DIR/bash
|
||||
PATH=$PATH:$BUILD_DIR
|
||||
|
||||
|
||||
@@ -43,3 +43,31 @@ f
|
||||
-20 -19 -18 -17 -16 -15 -14 -13 -12 -11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 0
|
||||
a-{bd}-c a-{be}-c
|
||||
a-{bdef-g-c a-{bdef-i-c
|
||||
{klklkl}1 {klklkl}2 {klklkl}3
|
||||
{x,x}
|
||||
1 3 5 7 9
|
||||
-1 -3 -5 -7 -9
|
||||
-1 -3 -5 -7 -9
|
||||
10 8 6 4 2
|
||||
10 8 6 4 2
|
||||
1 3 5 7 9 11 13 15 17 19
|
||||
1
|
||||
0100 0095 0090 0085 0080 0075 0070 0065 0060 0055 0050 0045 0040 0035 0030 0025 0020 0015 0010 0005 0000
|
||||
00100 00095 00090 00085 00080 00075 00070 00065 00060 00055 00050 00045 00040 00035 00030 00025 00020 00015 00010 00005 00000
|
||||
a b c d e f g h i j k l m n o p q r s t u v w x y z
|
||||
a c e g i k m o q s u w y
|
||||
z x v t r p n l j h f d b
|
||||
{1..10.f}
|
||||
{1..ff}
|
||||
{1..10..ff}
|
||||
{1.20..2}
|
||||
{1..20..f2}
|
||||
{1..20..2f}
|
||||
{1..2f..2}
|
||||
{1..ff..2}
|
||||
{1..ff}
|
||||
{1..f}
|
||||
{1..0f}
|
||||
{1..10f}
|
||||
{1..10.f}
|
||||
{1..10.f}
|
||||
|
||||
@@ -73,3 +73,39 @@ echo {-20..0}
|
||||
echo a-{b{d,e}}-c
|
||||
|
||||
echo a-{bdef-{g,i}-c
|
||||
|
||||
echo {"klklkl"}{1,2,3}
|
||||
echo {"x,x"}
|
||||
|
||||
echo {1..10..2}
|
||||
echo {-1..-10..2}
|
||||
echo {-1..-10..-2}
|
||||
|
||||
echo {10..1..-2}
|
||||
echo {10..1..2}
|
||||
|
||||
echo {1..20..2}
|
||||
echo {1..20..20}
|
||||
|
||||
echo {100..0..5}
|
||||
echo {100..0..-5}
|
||||
|
||||
echo {a..z}
|
||||
echo {a..z..2}
|
||||
echo {z..a..-2}
|
||||
|
||||
# bad
|
||||
echo {1..10.f}
|
||||
echo {1..ff}
|
||||
echo {1..10..ff}
|
||||
echo {1.20..2}
|
||||
echo {1..20..f2}
|
||||
echo {1..20..2f}
|
||||
echo {1..2f..2}
|
||||
echo {1..ff..2}
|
||||
echo {1..ff}
|
||||
echo {1..f}
|
||||
echo {1..0f}
|
||||
echo {1..10f}
|
||||
echo {1..10.f}
|
||||
echo {1..10.f}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
echo ff{c,b,a}
|
||||
echo f{d,e,f}g
|
||||
echo {l,n,m}xyz
|
||||
echo {abc\,def}
|
||||
echo {abc}
|
||||
|
||||
echo \{a,b,c,d,e}
|
||||
echo {x,y,\{a,b,c}}
|
||||
echo {x\,y,\{abc\},trie}
|
||||
|
||||
echo /usr/{ucb/{ex,edit},lib/{ex,how_ex}}
|
||||
|
||||
echo XXXX\{`echo a b c | tr ' ' ','`\}
|
||||
eval echo XXXX\{`echo a b c | tr ' ' ','`\}
|
||||
|
||||
echo {}
|
||||
echo { }
|
||||
echo }
|
||||
echo {
|
||||
echo abcd{efgh
|
||||
|
||||
echo foo {1,2} bar
|
||||
echo `zecho foo {1,2} bar`
|
||||
echo $(zecho foo {1,2} bar)
|
||||
|
||||
var=baz
|
||||
varx=vx
|
||||
vary=vy
|
||||
|
||||
echo foo{bar,${var}.}
|
||||
echo foo{bar,${var}}
|
||||
|
||||
echo "${var}"{x,y}
|
||||
echo $var{x,y}
|
||||
echo ${var}{x,y}
|
||||
|
||||
unset var varx vary
|
||||
|
||||
# new sequence brace operators
|
||||
echo {1..10}
|
||||
|
||||
# this doesn't work yet
|
||||
echo {0..10,braces}
|
||||
# but this does
|
||||
echo {{0..10},braces}
|
||||
echo x{{0..10},braces}y
|
||||
|
||||
echo {3..3}
|
||||
echo x{3..3}y
|
||||
echo {10..1}
|
||||
echo {10..1}y
|
||||
echo x{10..1}y
|
||||
|
||||
echo {a..f}
|
||||
echo {f..a}
|
||||
|
||||
echo {a..A}
|
||||
echo {A..a}
|
||||
|
||||
echo {f..f}
|
||||
|
||||
# mixes are incorrectly-formed brace expansions
|
||||
echo {1..f}
|
||||
echo {f..1}
|
||||
|
||||
echo 0{1..9} {10..20}
|
||||
|
||||
# do negative numbers work?
|
||||
echo {-1..-10}
|
||||
echo {-20..0}
|
||||
|
||||
# weirdly-formed brace expansions -- fixed in post-bash-3.1
|
||||
echo a-{b{d,e}}-c
|
||||
|
||||
echo a-{bdef-{g,i}-c
|
||||
|
||||
echo {"klklkl"}{1,2,3}
|
||||
echo {"x,x"}
|
||||
@@ -0,0 +1,5 @@
|
||||
fallthrough
|
||||
to here
|
||||
and here
|
||||
retest
|
||||
and match
|
||||
@@ -0,0 +1,14 @@
|
||||
case foo in
|
||||
bar) echo skip ;;
|
||||
foo) echo fallthrough ;&
|
||||
bax) echo to here ;&
|
||||
qux) echo and here;;
|
||||
fop) echo but not here;;
|
||||
esac
|
||||
|
||||
case foobar in
|
||||
bar) echo skip ;;
|
||||
foo*) echo retest ;;&
|
||||
*bar) echo and match ;;&
|
||||
qux) echo but not this ;;
|
||||
esac
|
||||
@@ -34,6 +34,7 @@ returns: 1
|
||||
returns: 0
|
||||
ok
|
||||
jbig2dec
|
||||
|
||||
found 1
|
||||
libc
|
||||
found 2
|
||||
|
||||
@@ -158,6 +158,10 @@ fi
|
||||
[[ jbig2dec-0.9-i586-001.tgz =~ ([^-]+)-([^-]+)-([^-]+)-0*([1-9][0-9]*)\.tgz ]]
|
||||
echo ${BASH_REMATCH[1]}
|
||||
|
||||
# this shouldn't echo anything
|
||||
[[ jbig2dec-0.9-i586-001.tgz =~ \([^-]+\)-\([^-]+\)-\([^-]+\)-0*\([1-9][0-9]*\)\.tgz ]]
|
||||
echo ${BASH_REMATCH[1]}
|
||||
|
||||
LDD_BASH=" linux-gate.so.1 => (0xffffe000)
|
||||
libreadline.so.5 => /lib/libreadline.so.5 (0xb7f91000)
|
||||
libhistory.so.5 => /lib/libhistory.so.5 (0xb7f8a000)
|
||||
|
||||
@@ -158,6 +158,22 @@ fi
|
||||
[[ jbig2dec-0.9-i586-001.tgz =~ ([^-]+)-([^-]+)-([^-]+)-0*([1-9][0-9]*)\.tgz ]]
|
||||
echo ${BASH_REMATCH[1]}
|
||||
|
||||
LDD_BASH=" linux-gate.so.1 => (0xffffe000)
|
||||
libreadline.so.5 => /lib/libreadline.so.5 (0xb7f91000)
|
||||
libhistory.so.5 => /lib/libhistory.so.5 (0xb7f8a000)
|
||||
libncurses.so.5 => /lib/libncurses.so.5 (0xb7f55000)
|
||||
libdl.so.2 => /lib/libdl.so.2 (0xb7f51000)
|
||||
libc.so.6 => /lib/libc.so.6 (0xb7e34000)
|
||||
/lib/ld-linux.so.2 (0xb7fd0000)"
|
||||
|
||||
[[ "$LDD_BASH" =~ "libc" ]] && echo "found 1"
|
||||
echo ${BASH_REMATCH[@]}
|
||||
|
||||
[[ "$LDD_BASH" =~ libc ]] && echo "found 2"
|
||||
echo ${BASH_REMATCH[@]}
|
||||
|
||||
# bug in all versions up to and including bash-2.05b
|
||||
if [[ "123abc" == *?(a)bc ]]; then echo ok 42; else echo bad 42; fi
|
||||
if [[ "123abc" == *?(a)bc ]]; then echo ok 43; else echo bad 43; fi
|
||||
|
||||
${THIS_SH} ./cond-regexp.sub
|
||||
|
||||
+28
-3
@@ -1,9 +1,9 @@
|
||||
abc
|
||||
./redir.tests: line 13: /tmp/redir-test: cannot overwrite existing file
|
||||
./redir.tests: line 15: /tmp/redir-test: cannot overwrite existing file
|
||||
abc
|
||||
def
|
||||
def
|
||||
./redir.tests: line 29: $z: ambiguous redirect
|
||||
./redir.tests: line 31: $z: ambiguous redirect
|
||||
Point 1
|
||||
Point 2
|
||||
to a
|
||||
@@ -44,7 +44,7 @@ kl
|
||||
ab
|
||||
cd
|
||||
cd
|
||||
./redir.tests: line 152: redir1.*: No such file or directory
|
||||
./redir.tests: line 154: redir1.*: No such file or directory
|
||||
# tests of ksh93-like dup-and-close redirection operators
|
||||
exec 9<$0
|
||||
|
||||
@@ -114,3 +114,28 @@ fd 8
|
||||
4
|
||||
cat /tmp/foo
|
||||
whatsis
|
||||
hey
|
||||
to stdout
|
||||
to stderr
|
||||
|
||||
to stdout
|
||||
to stderr
|
||||
|
||||
to stderr
|
||||
to stdout
|
||||
|
||||
to stderr
|
||||
hey
|
||||
to stdout
|
||||
logfunc is a function
|
||||
logfunc ()
|
||||
{
|
||||
echo "$@" &>>$TMPDIR/log
|
||||
}
|
||||
foo
|
||||
bix is a function
|
||||
bix ()
|
||||
{
|
||||
echo foo 2>&1 | cat
|
||||
}
|
||||
foo
|
||||
|
||||
+33
-29
@@ -1,3 +1,5 @@
|
||||
: ${TMPDIR:=/tmp}
|
||||
|
||||
export LC_ALL=C
|
||||
export LANG=C
|
||||
|
||||
@@ -31,31 +33,31 @@ cat < $z
|
||||
echo "Point 1"
|
||||
|
||||
exec 3</etc/passwd
|
||||
exec 4>/tmp/bash-a
|
||||
exec 5>/tmp/bash-b
|
||||
exec 4>$TMPDIR/bash-a
|
||||
exec 5>$TMPDIR/bash-b
|
||||
echo "Point 2"
|
||||
|
||||
echo to a 1>&4
|
||||
echo to b 1>&5
|
||||
cat /tmp/bash-a
|
||||
cat /tmp/bash-b
|
||||
cat $TMPDIR/bash-a
|
||||
cat $TMPDIR/bash-b
|
||||
exec 11</dev/null
|
||||
echo "Point 3"
|
||||
|
||||
echo to a 1>&4
|
||||
echo to b 1>&5
|
||||
cat /tmp/bash-a
|
||||
cat /tmp/bash-b
|
||||
cat $TMPDIR/bash-a
|
||||
cat $TMPDIR/bash-b
|
||||
|
||||
exec 11<&-
|
||||
echo "Point 4"
|
||||
|
||||
exec 6<>/tmp/bash-c
|
||||
exec 6<>$TMPDIR/bash-c
|
||||
echo to c 1>&6
|
||||
cat /tmp/bash-c
|
||||
cat $TMPDIR/bash-c
|
||||
echo "Point 5"
|
||||
|
||||
rm -f /tmp/bash-a /tmp/bash-b /tmp/bash-c
|
||||
rm -f $TMPDIR/bash-a $TMPDIR/bash-b $TMPDIR/bash-c
|
||||
|
||||
#
|
||||
# Test the effect of input buffering on the shell's input
|
||||
@@ -78,34 +80,34 @@ testf()
|
||||
fi
|
||||
}
|
||||
|
||||
> /tmp/null-redir-a
|
||||
testf /tmp/null-redir-a
|
||||
> $TMPDIR/null-redir-a
|
||||
testf $TMPDIR/null-redir-a
|
||||
|
||||
$EXIT > /tmp/null-redir-b
|
||||
testf /tmp/null-redir-b
|
||||
$EXIT > $TMPDIR/null-redir-b
|
||||
testf $TMPDIR/null-redir-b
|
||||
|
||||
( > /tmp/null-redir-c )
|
||||
testf /tmp/null-redir-c
|
||||
( > $TMPDIR/null-redir-c )
|
||||
testf $TMPDIR/null-redir-c
|
||||
|
||||
$EXIT > /tmp/null-redir-d &
|
||||
$EXIT > $TMPDIR/null-redir-d &
|
||||
wait
|
||||
testf /tmp/null-redir-d
|
||||
testf $TMPDIR/null-redir-d
|
||||
|
||||
exit 3 | $EXIT > /tmp/null-redir-e
|
||||
exit 3 | $EXIT > $TMPDIR/null-redir-e
|
||||
echo $? -- ${PIPESTATUS[@]}
|
||||
testf /tmp/null-redir-e
|
||||
testf $TMPDIR/null-redir-e
|
||||
|
||||
exit 4 | > /tmp/null-redir-f
|
||||
exit 4 | > $TMPDIR/null-redir-f
|
||||
echo $? -- ${PIPESTATUS[@]}
|
||||
testf /tmp/null-redir-f
|
||||
testf $TMPDIR/null-redir-f
|
||||
|
||||
> /tmp/null-redir-g &
|
||||
> $TMPDIR/null-redir-g &
|
||||
wait
|
||||
testf /tmp/null-redir-g
|
||||
testf $TMPDIR/null-redir-g
|
||||
|
||||
exec >/tmp/null-redir-h &
|
||||
exec >$TMPDIR/null-redir-h &
|
||||
wait
|
||||
testf /tmp/null-redir-h
|
||||
testf $TMPDIR/null-redir-h
|
||||
|
||||
# make sure async commands don't get /dev/null as stdin when an explicit
|
||||
# input redirection is supplied
|
||||
@@ -158,7 +160,7 @@ ${THIS_SH} ./redir5.sub
|
||||
${THIS_SH} ./redir6.sub
|
||||
|
||||
# problem with redirections using fds bash uses internally
|
||||
: ${TMPDIR:=/tmp}
|
||||
: ${TMPDIR:=$TMPDIR}
|
||||
|
||||
trap 'rm -f $TMPDIR/bash-redir-$$' 0 1 2 3 6 15
|
||||
|
||||
@@ -176,10 +178,12 @@ ${THIS_SH} ./redir7.sub
|
||||
${THIS_SH} ./redir8.sub
|
||||
|
||||
exec 9>&2
|
||||
command exec 2>/tmp/foo
|
||||
command exec 2>$TMPDIR/foo
|
||||
echo whatsis >&2
|
||||
echo cat /tmp/foo
|
||||
cat /tmp/foo
|
||||
rm -f /tmp/foo
|
||||
cat $TMPDIR/foo
|
||||
rm -f $TMPDIR/foo
|
||||
exec 2>&9
|
||||
exec 9>&-
|
||||
|
||||
${THIS_SH} ./redir9.sub
|
||||
|
||||
+39
-26
@@ -1,3 +1,5 @@
|
||||
: ${TMPDIR:=/tmp}
|
||||
|
||||
export LC_ALL=C
|
||||
export LANG=C
|
||||
|
||||
@@ -31,31 +33,31 @@ cat < $z
|
||||
echo "Point 1"
|
||||
|
||||
exec 3</etc/passwd
|
||||
exec 4>/tmp/bash-a
|
||||
exec 5>/tmp/bash-b
|
||||
exec 4>$TMPDIR/bash-a
|
||||
exec 5>$TMPDIR/bash-b
|
||||
echo "Point 2"
|
||||
|
||||
echo to a 1>&4
|
||||
echo to b 1>&5
|
||||
cat /tmp/bash-a
|
||||
cat /tmp/bash-b
|
||||
cat $TMPDIR/bash-a
|
||||
cat $TMPDIR/bash-b
|
||||
exec 11</dev/null
|
||||
echo "Point 3"
|
||||
|
||||
echo to a 1>&4
|
||||
echo to b 1>&5
|
||||
cat /tmp/bash-a
|
||||
cat /tmp/bash-b
|
||||
cat $TMPDIR/bash-a
|
||||
cat $TMPDIR/bash-b
|
||||
|
||||
exec 11<&-
|
||||
echo "Point 4"
|
||||
|
||||
exec 6<>/tmp/bash-c
|
||||
exec 6<>$TMPDIR/bash-c
|
||||
echo to c 1>&6
|
||||
cat /tmp/bash-c
|
||||
cat $TMPDIR/bash-c
|
||||
echo "Point 5"
|
||||
|
||||
rm -f /tmp/bash-a /tmp/bash-b /tmp/bash-c
|
||||
rm -f $TMPDIR/bash-a $TMPDIR/bash-b $TMPDIR/bash-c
|
||||
|
||||
#
|
||||
# Test the effect of input buffering on the shell's input
|
||||
@@ -78,34 +80,34 @@ testf()
|
||||
fi
|
||||
}
|
||||
|
||||
> /tmp/null-redir-a
|
||||
testf /tmp/null-redir-a
|
||||
> $TMPDIR/null-redir-a
|
||||
testf $TMPDIR/null-redir-a
|
||||
|
||||
$EXIT > /tmp/null-redir-b
|
||||
testf /tmp/null-redir-b
|
||||
$EXIT > $TMPDIR/null-redir-b
|
||||
testf $TMPDIR/null-redir-b
|
||||
|
||||
( > /tmp/null-redir-c )
|
||||
testf /tmp/null-redir-c
|
||||
( > $TMPDIR/null-redir-c )
|
||||
testf $TMPDIR/null-redir-c
|
||||
|
||||
$EXIT > /tmp/null-redir-d &
|
||||
$EXIT > $TMPDIR/null-redir-d &
|
||||
wait
|
||||
testf /tmp/null-redir-d
|
||||
testf $TMPDIR/null-redir-d
|
||||
|
||||
exit 3 | $EXIT > /tmp/null-redir-e
|
||||
exit 3 | $EXIT > $TMPDIR/null-redir-e
|
||||
echo $? -- ${PIPESTATUS[@]}
|
||||
testf /tmp/null-redir-e
|
||||
testf $TMPDIR/null-redir-e
|
||||
|
||||
exit 4 | > /tmp/null-redir-f
|
||||
exit 4 | > $TMPDIR/null-redir-f
|
||||
echo $? -- ${PIPESTATUS[@]}
|
||||
testf /tmp/null-redir-f
|
||||
testf $TMPDIR/null-redir-f
|
||||
|
||||
> /tmp/null-redir-g &
|
||||
> $TMPDIR/null-redir-g &
|
||||
wait
|
||||
testf /tmp/null-redir-g
|
||||
testf $TMPDIR/null-redir-g
|
||||
|
||||
exec >/tmp/null-redir-h &
|
||||
exec >$TMPDIR/null-redir-h &
|
||||
wait
|
||||
testf /tmp/null-redir-h
|
||||
testf $TMPDIR/null-redir-h
|
||||
|
||||
# make sure async commands don't get /dev/null as stdin when an explicit
|
||||
# input redirection is supplied
|
||||
@@ -158,7 +160,7 @@ ${THIS_SH} ./redir5.sub
|
||||
${THIS_SH} ./redir6.sub
|
||||
|
||||
# problem with redirections using fds bash uses internally
|
||||
: ${TMPDIR:=/tmp}
|
||||
: ${TMPDIR:=$TMPDIR}
|
||||
|
||||
trap 'rm -f $TMPDIR/bash-redir-$$' 0 1 2 3 6 15
|
||||
|
||||
@@ -174,3 +176,14 @@ echo after block
|
||||
${THIS_SH} ./redir7.sub
|
||||
|
||||
${THIS_SH} ./redir8.sub
|
||||
|
||||
exec 9>&2
|
||||
command exec 2>$TMPDIR/foo
|
||||
echo whatsis >&2
|
||||
echo cat $TMPDIR/foo
|
||||
cat $TMPDIR/foo
|
||||
rm -f $TMPDIR/foo
|
||||
exec 2>&9
|
||||
exec 9>&-
|
||||
|
||||
${THIS_SH} ./redir9.sub
|
||||
|
||||
@@ -55,6 +55,3 @@ exec 0<&7
|
||||
exec 7<&-
|
||||
|
||||
exit 0
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
rm -f u
|
||||
|
||||
${THIS_SH} -c 'exec 10>&1; echo fd 10 >&10' 10>u
|
||||
cat u
|
||||
rm -f u
|
||||
|
||||
${THIS_SH} -c 'exec 8>&1; echo fd 8 >&8' 8>u
|
||||
cat u
|
||||
rm -f u
|
||||
|
||||
exec 10>u
|
||||
exec 10>&1; echo 'fd 10' >&10
|
||||
cat u
|
||||
rm -f u
|
||||
exec 10>&-
|
||||
|
||||
exec 8>u
|
||||
exec 8>&1; echo 'fd 8' >&8
|
||||
cat u
|
||||
rm -f u
|
||||
exec 8>&-
|
||||
|
||||
rm -f infile
|
||||
cat > infile <<EOF
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
EOF
|
||||
|
||||
exec 7<&0
|
||||
exec 10<infile
|
||||
exec 0<&10; cat <&10
|
||||
exec 0<&7
|
||||
exec 7<&-
|
||||
|
||||
exec 7<&0
|
||||
exec 8<infile
|
||||
exec 0<&8 ; cat <&8
|
||||
exec 0<&7
|
||||
exec 7<&-
|
||||
|
||||
exec 7<&0
|
||||
exec 0</dev/null
|
||||
exec 10<infile
|
||||
exec 10<&0; cat <&10
|
||||
exec 0<&7
|
||||
exec 7<&-
|
||||
|
||||
exec 7<&0
|
||||
exec 0</dev/null
|
||||
exec 8<infile
|
||||
exec 8<&0; cat <&8
|
||||
exec 0<&7
|
||||
exec 7<&-
|
||||
|
||||
exit 0
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
: ${TMPDIR:=/tmp}
|
||||
|
||||
func()
|
||||
{
|
||||
echo "to stdout"
|
||||
echo "to stderr" >&2
|
||||
}
|
||||
|
||||
rm -f $TMPDIR/foo
|
||||
|
||||
echo hey > $TMPDIR/foo
|
||||
func &>> $TMPDIR/foo
|
||||
|
||||
cat $TMPDIR/foo
|
||||
|
||||
echo
|
||||
func &> $TMPDIR/foo
|
||||
|
||||
cat $TMPDIR/foo
|
||||
|
||||
echo
|
||||
func >$TMPDIR/foo
|
||||
cat $TMPDIR/foo
|
||||
|
||||
echo
|
||||
echo hey > $TMPDIR/foo
|
||||
func >> $TMPDIR/foo
|
||||
cat $TMPDIR/foo
|
||||
|
||||
rm -f $TMPDIR/foo
|
||||
|
||||
logfunc()
|
||||
{
|
||||
echo "$@" &>> $TMPDIR/log
|
||||
}
|
||||
|
||||
type logfunc
|
||||
|
||||
echo foo 2>&1
|
||||
|
||||
bix()
|
||||
{
|
||||
echo foo |& cat
|
||||
}
|
||||
|
||||
type bix
|
||||
|
||||
bix
|
||||
@@ -0,0 +1,37 @@
|
||||
: ${TMPDIR:=/tmp}
|
||||
|
||||
func()
|
||||
{
|
||||
echo "to stdout"
|
||||
echo "to stderr" >&2
|
||||
}
|
||||
|
||||
rm -f $TMPDIR/foo
|
||||
|
||||
echo hey > $TMPDIR/foo
|
||||
func &>> $TMPDIR/foo
|
||||
|
||||
cat $TMPDIR/foo
|
||||
|
||||
echo
|
||||
func &> $TMPDIR/foo
|
||||
|
||||
cat $TMPDIR/foo
|
||||
|
||||
echo
|
||||
func >$TMPDIR/foo
|
||||
cat $TMPDIR/foo
|
||||
|
||||
echo
|
||||
echo hey > $TMPDIR/foo
|
||||
func >> $TMPDIR/foo
|
||||
cat $TMPDIR/foo
|
||||
|
||||
rm -f $TMPDIR/foo
|
||||
|
||||
logfunc()
|
||||
{
|
||||
echo "$@" &>> $TMPDIR/log
|
||||
}
|
||||
|
||||
type logfunc
|
||||
@@ -0,0 +1,2 @@
|
||||
${THIS_SH} ./case.tests > /tmp/xx 2>&1
|
||||
diff /tmp/xx case.right && rm -f /tmp/xx
|
||||
@@ -0,0 +1,6 @@
|
||||
echo "warning: all of these tests will fail if arrays have not" >&2
|
||||
echo "warning: been compiled into the shell" >&2
|
||||
echo "warning: the BASH_ARGC and BASH_ARGV tests will fail if debugging support" >&2
|
||||
echo "warning: has not been compiled into the shell" >&2
|
||||
${THIS_SH} ./array.tests > /tmp/xx 2>&1
|
||||
diff /tmp/xx array.right && rm -f /tmp/xx
|
||||
@@ -51,3 +51,13 @@ f ()
|
||||
{
|
||||
v='^A'
|
||||
}
|
||||
foo is a function
|
||||
foo ()
|
||||
{
|
||||
echo $(<x1)
|
||||
}
|
||||
bar is a function
|
||||
bar ()
|
||||
{
|
||||
echo $(<x1)
|
||||
}
|
||||
|
||||
@@ -87,3 +87,5 @@ f() {
|
||||
}
|
||||
|
||||
type f | cat -v
|
||||
|
||||
${THIS_SH} type1.sub
|
||||
|
||||
@@ -80,3 +80,10 @@ type -t $SHBASE
|
||||
|
||||
# make sure the hash table looks right
|
||||
hash
|
||||
|
||||
# bug in versions of bash up to and including bash-3.2
|
||||
f() {
|
||||
v=$'\001'
|
||||
}
|
||||
|
||||
type f | cat -v
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
foo()
|
||||
{
|
||||
echo $(<x1)
|
||||
}
|
||||
|
||||
type foo
|
||||
|
||||
eval "$(declare -f foo | sed 's:foo:bar:')"
|
||||
|
||||
type bar
|
||||
Reference in New Issue
Block a user