]> git.ipfire.org Git - thirdparty/bash.git/commitdiff
commit bash-20080522 snapshot
authorChet Ramey <chet.ramey@case.edu>
Wed, 7 Dec 2011 14:24:08 +0000 (09:24 -0500)
committerChet Ramey <chet.ramey@case.edu>
Wed, 7 Dec 2011 14:24:08 +0000 (09:24 -0500)
74 files changed:
CWRU/CWRU.chlog
CWRU/CWRU.chlog~
MANIFEST
MANIFEST~
bashhist.c
bashhist.c~
bashhist.h
bashhist.h~ [new file with mode: 0644]
bashline.c
bashline.c~
bashline.h
bashline.h~
braces.c
braces.c~
builtins/common.h
builtins/common.h~
builtins/evalstring.c
builtins/evalstring.c~
builtins/fc.def
builtins/fc.def~
builtins/history.def
builtins/history.def~
command.h
command.h~ [new file with mode: 0644]
copy_cmd.c
copy_cmd.c~ [new file with mode: 0644]
dispose_cmd.c
dispose_cmd.c~ [new file with mode: 0644]
doc/bash.1
doc/bash.1~
doc/bashref.texi
doc/bashref.texi~
doc/version.texi
doc/version.texi~
execute_cmd.c
execute_cmd.c~
lib/readline/doc/rluser.texi
lib/readline/doc/rluser.texi~
lib/readline/doc/version.texi
lib/readline/doc/version.texi~
make_cmd.c
make_cmd.c~
parse.y
parse.y~
print_cmd.c
print_cmd.c~
redir.c
redir.c~
shell.c
shell.c~
sig.c
sig.c~
tests/RUN-ONE-TEST
tests/braces.right
tests/braces.tests
tests/braces.tests~ [new file with mode: 0644]
tests/case.right [new file with mode: 0644]
tests/case.tests [new file with mode: 0644]
tests/cond.right
tests/cond.tests
tests/cond.tests~
tests/redir.right
tests/redir.tests
tests/redir.tests~
tests/redir8.sub
tests/redir8.sub~ [new file with mode: 0644]
tests/redir9.sub [new file with mode: 0644]
tests/redir9.sub~ [new file with mode: 0644]
tests/run-case [new file with mode: 0644]
tests/run-case~ [new file with mode: 0644]
tests/type.right
tests/type.tests
tests/type.tests~
tests/type1.sub [new file with mode: 0644]

index 1f867449f8d3b5253ea90e6c9d7c178797fbb7d7..1e2214d4a16b2746b1bb3dc70fb6a066ffbe3bba 100644 (file)
@@ -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
index ff2d394f726aa3fbf629beb11c2327cc3ea230a5..64c42ca2b5496bd75d8c3edfb6cd3194223ce8a2 100644 (file)
@@ -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
index df394de4e18779fa258eef4010d322214e34dd66..6eb4ec7270c423d08f0230cd7249d2bd9a08c9a8 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -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
index 8be34a8a322dc747970c1a5ddabfc193f39a2067..2e09b62bd29e77dce9f78ffee494c20e6d765b5f 100644 (file)
--- a/MANIFEST~
+++ b/MANIFEST~
@@ -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
index 9e77bc5911ce28f79f3c192634e27ff3cb851894..51aa6bc09cdb921ac3523ba3ab10c0e94f8fe17f 100644 (file)
@@ -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
index bb7df07baaff3215a4fbcfed77dc4daa3db47fc6..5d15c518a12b6b65862919e5b09e394139241d7e 100644 (file)
@@ -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
index 35929aca4dcc508c25b92e641e14eea7f79e1fb7..39813e31bc876bb477748aef7ff2a19ed3033040 100644 (file)
@@ -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 *));
diff --git a/bashhist.h~ b/bashhist.h~
new file mode 100644 (file)
index 0000000..dece490
--- /dev/null
@@ -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_ */
index 4ff3590985543e9682248eedafb69d588b010d31..1d45bb0a4dc258100a97a74870487353de6d7818 100644 (file)
@@ -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,12 +3205,41 @@ 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);
+  parse_and_execute (cmd, "bash_execute_unix_command", SEVAL_NOHIST|SEVAL_NOFREE);
+  restore_parser_state (&ps);
 
-  cmd = savestring (cmd);
-  parse_and_execute (cmd, "bash_execute_unix_command", SEVAL_NOHIST);
+  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;
+       }
+    }      
 
-  restore_parser_state (&ps);
+  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 ();
index 798315446174cec740b649afc30fc49339143963..28dd18c63af1a951a3d7286501df8dbc05677063 100644 (file)
@@ -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,12 +3203,27 @@ 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);
+  parse_and_execute (cmd, "bash_execute_unix_command", SEVAL_NOHIST|SEVAL_NOFREE);
+  restore_parser_state (&ps);
 
-  cmd = savestring (cmd);
-  parse_and_execute (cmd, "bash_execute_unix_command", SEVAL_NOHIST);
+  v = find_variable ("READLINE_LINE");
+  if (value_cell (v) != l)
+    maybe_make_readline_line (value_cell (v));
 
-  restore_parser_state (&ps);
+  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 ();
index cd84d879febace95ff0a88496a6d259fd09dde85..8cf22ff482cecf35d289695aad0a1fee86fcbd39 100644 (file)
@@ -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.
 
index eac5d3533bbb76673a25517901ba9b798dee4daa..cd84d879febace95ff0a88496a6d259fd09dde85 100644 (file)
@@ -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 *));
 
index 13270d9b46920eae95bbe53094887b2ea649e883..5810d0f5ee5a83da250c15c677452de0fd069e8f 100644 (file)
--- a/braces.c
+++ b/braces.c
@@ -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);
index 34a72be43bf26af03d28f7cbe2dfff9e3aca41c3..53498da26f3fd201308926e172b625ce5b090fd0 100644 (file)
--- a/braces.c~
+++ b/braces.c~
@@ -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);
index 3a817cc2569a7c88d50e8081cc04a9f58c5edd2a..ec1200b5ffb642fdfad0ad21f024b8056c4a9a11 100644 (file)
@@ -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 */
index 0a46d2001ec6a43333cc767699a61256b5ded331..3a817cc2569a7c88d50e8081cc04a9f58c5edd2a 100644 (file)
@@ -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));
index beffa3667d76b73be948a00b042d4e6f1ceb1aed..490fd22a7ff44b93650ea926b090abd69030b44b 100644 (file)
@@ -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,42 +90,21 @@ 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 ()
-{
-  remember_on_history = enable_history_list;
-}
-#endif
-
-/* Parse and execute the commands in STRING.  Returns whatever
-   execute_command () returns.  This frees STRING.  FLAGS is a
-   flags word; look in common.h for the possible values.  Actions
-   are:
-       (flags & SEVAL_NONINT) -> interactive = 0;
-       (flags & SEVAL_INTERACT) -> interactive = 1;
-       (flags & SEVAL_NOHIST) -> call bash_history_disable ()
-       (flags & SEVAL_NOFREE) -> don't free STRING when finished
-       (flags & SEVAL_RESETLINE) -> reset line_number to 1
-*/
-
-int
-parse_and_execute (string, from_file, flags)
+parse_prologue (string, flags, tag)
      char *string;
-     const char *from_file;
      int flags;
+     char *tag;
 {
-  int code, x, lreset;
-  volatile int should_jump_to_top_level, last_result;
   char *orig_string;
-  COMMAND *volatile command;
+  int x;
 
   orig_string = string;
   /* Unwind protect this invocation of parse_and_execute (). */
-  begin_unwind_frame ("parse_and_execute_top");
+  begin_unwind_frame (tag);
   unwind_protect_int (parse_and_execute_level);
   unwind_protect_jmp_buf (top_level);
   unwind_protect_int (indirection_level);
@@ -120,18 +113,14 @@ parse_and_execute (string, from_file, flags)
   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);
+    unwind_protect_int (remember_on_history);  /* can be used in scripts */
 #  if defined (BANG_HISTORY)
   if (interactive_shell)
-    {
-      unwind_protect_int (history_expansion_inhibited);
-    }
+    unwind_protect_int (history_expansion_inhibited);
 #  endif /* BANG_HISTORY */
 #endif /* HISTORY */
 
@@ -146,8 +135,42 @@ parse_and_execute (string, from_file, flags)
     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
+   execute_command () returns.  This frees STRING.  FLAGS is a
+   flags word; look in common.h for the possible values.  Actions
+   are:
+       (flags & SEVAL_NONINT) -> interactive = 0;
+       (flags & SEVAL_INTERACT) -> interactive = 1;
+       (flags & SEVAL_NOHIST) -> call bash_history_disable ()
+       (flags & SEVAL_NOFREE) -> don't free STRING when finished
+       (flags & SEVAL_RESETLINE) -> reset line_number to 1
+*/
+
+int
+parse_and_execute (string, from_file, flags)
+     char *string;
+     const char *from_file;
+     int flags;
+{
+  int code, lreset;
+  volatile int should_jump_to_top_level, last_result;
+  COMMAND *volatile command;
+
+  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. */
index a8976930dfaea0322abf40ab56b76cf3df0d3a59..190b8658ee62f5cfda90888f99e76acbeb6aafde 100644 (file)
@@ -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,40 +90,21 @@ 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 ()
-{
-  remember_on_history = enable_history_list;
-}
-
-/* Parse and execute the commands in STRING.  Returns whatever
-   execute_command () returns.  This frees STRING.  FLAGS is a
-   flags word; look in common.h for the possible values.  Actions
-   are:
-       (flags & SEVAL_NONINT) -> interactive = 0;
-       (flags & SEVAL_INTERACT) -> interactive = 1;
-       (flags & SEVAL_NOHIST) -> call bash_history_disable ()
-       (flags & SEVAL_NOFREE) -> don't free STRING when finished
-       (flags & SEVAL_RESETLINE) -> reset line_number to 1
-*/
-
-int
-parse_and_execute (string, from_file, flags)
+parse_prologue (string, flags, tag)
      char *string;
-     const char *from_file;
      int flags;
+     char *tag;
 {
-  int code, x, lreset;
-  volatile int should_jump_to_top_level, last_result;
   char *orig_string;
-  COMMAND *volatile command;
+  int x;
 
   orig_string = string;
   /* Unwind protect this invocation of parse_and_execute (). */
-  begin_unwind_frame ("parse_and_execute_top");
+  begin_unwind_frame (tag);
   unwind_protect_int (parse_and_execute_level);
   unwind_protect_jmp_buf (top_level);
   unwind_protect_int (indirection_level);
@@ -118,15 +113,14 @@ parse_and_execute (string, from_file, flags)
   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 (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);
-    }
+    unwind_protect_int (history_expansion_inhibited);
 #  endif /* BANG_HISTORY */
 #endif /* HISTORY */
 
@@ -141,8 +135,42 @@ parse_and_execute (string, from_file, flags)
     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
+   execute_command () returns.  This frees STRING.  FLAGS is a
+   flags word; look in common.h for the possible values.  Actions
+   are:
+       (flags & SEVAL_NONINT) -> interactive = 0;
+       (flags & SEVAL_INTERACT) -> interactive = 1;
+       (flags & SEVAL_NOHIST) -> call bash_history_disable ()
+       (flags & SEVAL_NOFREE) -> don't free STRING when finished
+       (flags & SEVAL_RESETLINE) -> reset line_number to 1
+*/
+
+int
+parse_and_execute (string, from_file, flags)
+     char *string;
+     const char *from_file;
+     int flags;
+{
+  int code, lreset;
+  volatile int should_jump_to_top_level, last_result;
+  COMMAND *volatile command;
+
+  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)
     {
index 32cd57acb5ef3dc4a80036923489406bab353291..e1d038be1261defbc4dc350fdf99e79b139a69d2 100644 (file)
@@ -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. */
     }
 }
index 078e24106e6db1d79a637cf5897a8e4c7c6bbb7e..32cd57acb5ef3dc4a80036923489406bab353291 100644 (file)
@@ -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))
     {
index 1c888c55a1afba90f7504e7971706d02c83aeed6..f21e7c9e3ccb73bd7c9a2c55eee1364e491008c3 100644 (file)
@@ -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)
index f3008244ee9e6f8d39b9a30e9b6bf2988a37f9a1..31f72e70be8bb3782d2da64be4e0fec38226c4a6 100644 (file)
@@ -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);
index d90a2eac50c8780e0f4f9aee28f429fb8e3bb852..2cbae8e7da9a6b7ef37a889b5c4a6fb060181feb 100644 (file)
--- a/command.h
+++ b/command.h
@@ -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. */
diff --git a/command.h~ b/command.h~
new file mode 100644 (file)
index 0000000..46e5bda
--- /dev/null
@@ -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_ */
index d36436c9c8437550b0c3bcd665849746dbcb1e1d..0adf0229e3f4a082e585d4911694a387d473f7da 100644 (file)
@@ -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:
diff --git a/copy_cmd.c~ b/copy_cmd.c~
new file mode 100644 (file)
index 0000000..d36436c
--- /dev/null
@@ -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);
+}
index ee2e68cdfaaa46f2b969edf51821681a2c7ee11d..36c195f9f9fe60ea785c4f6dc461937ec68ea8a4 100644 (file)
@@ -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:
diff --git a/dispose_cmd.c~ b/dispose_cmd.c~
new file mode 100644 (file)
index 0000000..8b8790d
--- /dev/null
@@ -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);
+    }
+}
index f5207ff755350984dccfe098437f0197a0259d51..ea532b4eeb1b024fd58675713aa93b2b601adf04 100644 (file)
@@ -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
index dafaf84a30ea5f3296f6d5a7f3c530baaf68b1b0..d0e0bed6d2ab70c60a160875f3d327a54b57a02e 100644 (file)
@@ -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
index f90cc23b27758576593f0e1e21023fe82c5f8fbb..fdd47c173aeff16c0d38acaceccea8bff139e74b 100644 (file)
@@ -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
index 5664da2b732b1ac34b3c39f94d6daaeb0cf2ad18..857b260e500038faf036d5c178198b93e777b369 100644 (file)
@@ -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.
 
index ba448d24b0d31cb1681ba789d77e43076ac10894..27ea810a99604088525cd6fb8a79388c5f5b715e 100644 (file)
@@ -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
index 314c1efc7497c9ad349b71570d77c2a4293f2f60..ba448d24b0d31cb1681ba789d77e43076ac10894 100644 (file)
@@ -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
index ee6429fd426e8fc8c5952830405c9725ad95896e..ca27b081abcc97c914075e99eaa54b0e3b4988ff 100644 (file)
@@ -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;
index 3f29e1676edf2b624ecde21c2d0fb39dc4ea449b..ee6429fd426e8fc8c5952830405c9725ad95896e 100644 (file)
@@ -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))
     {
index f096775c2fbcf4ef6942bc29733a09750e144507..81a92ebc3516f7afb681d5309675adbe1703a292 100644 (file)
@@ -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
index 4301beb24ef4608b5c1cf1ed954b61e871e7bfa1..f096775c2fbcf4ef6942bc29733a09750e144507 100644 (file)
@@ -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
index 75322efc5b9c5da3221a10963f3ee0b226ce7d15..dc4618ac6917c06f53307e5d1f9c0e4c262c8330 100644 (file)
@@ -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
index c2044522d6744aba0dbd6b749c410664812eb621..75322efc5b9c5da3221a10963f3ee0b226ce7d15 100644 (file)
@@ -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
index 48dba0887aea426aa184c6ca1772de97e93a5f57..ec914fdea6c438a2e274031ff3b61ad5f9fe96e4 100644 (file)
@@ -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;
 
index 08eed18a895b79303b4520bb8ce70216e475be28..48dba0887aea426aa184c6ca1772de97e93a5f57 100644 (file)
@@ -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;
 
diff --git a/parse.y b/parse.y
index 53b09435f52907d0990e609ae3057d3df7a4c3ca..3bc2863bb584e30d6dff7ee28032e8973fac0183 100644 (file)
--- a/parse.y
+++ b/parse.y
@@ -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
 };
 
index 2b710a6de3165d2a0a8707673bcd9e6e764a7ad2..3bc2863bb584e30d6dff7ee28032e8973fac0183 100644 (file)
--- a/parse.y~
+++ b/parse.y~
@@ -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
 };
 
index d3cf08098740937e09d3716ce183b46fde68f38a..05bb7a8387a5384380a385973d7e0ab88f470651 100644 (file)
@@ -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);
index 0386a78a32348a78674d3278578d2d891177e80a..b35ecbc4694e40f31879c0cc6e749534dc41cec5 100644 (file)
@@ -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:
diff --git a/redir.c b/redir.c
index 2baf5041b4df881b58068c61b9a69697f571ede0..ca10d572aa8276f45c24274882f1a8d604783718 100644 (file)
--- a/redir.c
+++ b/redir.c
@@ -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);
index 47a6097c842ca46803258742e0f7978329fcfbca..2baf5041b4df881b58068c61b9a69697f571ede0 100644 (file)
--- a/redir.c~
+++ b/redir.c~
@@ -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:
diff --git a/shell.c b/shell.c
index fac78dcad2e4c6fc5cee72fef0e8a917159e214a..a64da180dd9fdd3ee0f2eb93b78ef4f399888ca3 100644 (file)
--- a/shell.c
+++ b/shell.c
@@ -1747,7 +1747,7 @@ shell_reinitialize ()
   reinit_special_variables ();
 
 #if defined (READLINE)
-  bashline_reset ();
+  bashline_reinitialize ();
 #endif
 
   shell_reinitialized = 1;
index b69204f71f91ac882265ecff1fbe9cbc3b024e11..fac78dcad2e4c6fc5cee72fef0e8a917159e214a 100644 (file)
--- a/shell.c~
+++ b/shell.c~
@@ -1747,7 +1747,7 @@ shell_reinitialize ()
   reinit_special_variables ();
 
 #if defined (READLINE)
-  bash_readline_initialized = 0;
+  bashline_reset ();
 #endif
 
   shell_reinitialized = 1;
diff --git a/sig.c b/sig.c
index f6c4b42c94b2653e9521fb4b82d7834fa2e6a2cb..3f08f457dbe19f781148452db611e748b7f25100 100644 (file)
--- a/sig.c
+++ b/sig.c
@@ -408,7 +408,7 @@ throw_to_top_level ()
 
 #if defined (READLINE)
   if (interactive)
-    bashline_reinitialize ();
+    bashline_reset ();
 #endif /* READLINE */
 
 #if defined (PROCESS_SUBSTITUTION)
diff --git a/sig.c~ b/sig.c~
index 2bd6cae606dd8c24a01f2f897636036f79627b3b..f6c4b42c94b2653e9521fb4b82d7834fa2e6a2cb 100644 (file)
--- a/sig.c~
+++ b/sig.c~
@@ -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 ();
 
index 3efcf32d68e9722024b6ca9d67f9e81b2aa5ac04..72ec06a2c1fd8dde92acea5e8ac773e35f1d061b 100755 (executable)
@@ -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
 
index f00d39a76361541efc2a00b65dfd2cf905c4c624..5369a7e3a7f3a0efc9a0472e3426b3c1a7011e24 100644 (file)
@@ -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}
index 5a57f2844e9d716258cb50792fc972a1e7887ca5..25b07b6a27d715328b432f63561c395b28462799 100644 (file)
@@ -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}
diff --git a/tests/braces.tests~ b/tests/braces.tests~
new file mode 100644 (file)
index 0000000..5f15f5f
--- /dev/null
@@ -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"}
diff --git a/tests/case.right b/tests/case.right
new file mode 100644 (file)
index 0000000..b82ad9a
--- /dev/null
@@ -0,0 +1,5 @@
+fallthrough
+to here
+and here
+retest
+and match
diff --git a/tests/case.tests b/tests/case.tests
new file mode 100644 (file)
index 0000000..d85dc3e
--- /dev/null
@@ -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
index 39fac2fcb3897b0b0884d60c38e3b088b35fd978..377523080073d96a41dfa268f5356bf44607b7d6 100644 (file)
@@ -34,6 +34,7 @@ returns: 1
 returns: 0
 ok
 jbig2dec
+
 found 1
 libc
 found 2
index 5ba18561c2e3a9d2913c4caa6fbda305565ab954..b053e48221abc714260751cff619895228a17e6c 100755 (executable)
@@ -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)
index c04b0a2504348686b34f72751cf7e1838ff91d9b..5ba18561c2e3a9d2913c4caa6fbda305565ab954 100755 (executable)
@@ -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
index 45fb384c076031ca72688525a1e640a6fd750e3f..f816c63b734b0f76f5cc004c47c1d90016064979 100644 (file)
@@ -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
index 08b485479e1f597c204e4d96736ab1defc9f8cb6..2091a1f538a003d91182391b3c0fbc335e92c85a 100644 (file)
@@ -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
index 644e435cadbd0fbfd0d4102021858d1aa1042cc4..5d88357c26d8941949ac8d9258377524a334ad30 100644 (file)
@@ -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
index da12cc76685a2a830e8d0a89c0028ca4aa34b1ae..cf8862ae90e3fb10934c490254dae7dc5530b4d0 100644 (file)
@@ -55,6 +55,3 @@ exec 0<&7
 exec 7<&-
 
 exit 0
-
-
-
diff --git a/tests/redir8.sub~ b/tests/redir8.sub~
new file mode 100644 (file)
index 0000000..da12cc7
--- /dev/null
@@ -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
+
+
+
diff --git a/tests/redir9.sub b/tests/redir9.sub
new file mode 100644 (file)
index 0000000..c49e039
--- /dev/null
@@ -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
diff --git a/tests/redir9.sub~ b/tests/redir9.sub~
new file mode 100644 (file)
index 0000000..a60d5c9
--- /dev/null
@@ -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
diff --git a/tests/run-case b/tests/run-case
new file mode 100644 (file)
index 0000000..71d9b83
--- /dev/null
@@ -0,0 +1,2 @@
+${THIS_SH} ./case.tests > /tmp/xx 2>&1
+diff /tmp/xx case.right && rm -f /tmp/xx
diff --git a/tests/run-case~ b/tests/run-case~
new file mode 100644 (file)
index 0000000..6fdbae4
--- /dev/null
@@ -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
index abdd02fbff2cb227f809b0a73c8a964c5929d8aa..18208d13289def95b0422a13689d989df6a1b19b 100644 (file)
@@ -51,3 +51,13 @@ f ()
 { 
     v='^A'
 }
+foo is a function
+foo () 
+{ 
+    echo $(<x1)
+}
+bar is a function
+bar () 
+{ 
+    echo $(<x1)
+}
index 15106f0f3d8e7ce1f5d2c3570d18d6722a3f2be2..6a3e80794794560be3d89913b8c1fdf3ed6f1fae 100644 (file)
@@ -87,3 +87,5 @@ f() {
     }
 
 type f | cat -v
+
+${THIS_SH} type1.sub
index d47ae647bf364827f9bd1074662c46eb8bd968a0..15106f0f3d8e7ce1f5d2c3570d18d6722a3f2be2 100644 (file)
@@ -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
diff --git a/tests/type1.sub b/tests/type1.sub
new file mode 100644 (file)
index 0000000..95f96ae
--- /dev/null
@@ -0,0 +1,10 @@
+foo()
+{
+       echo $(<x1)
+}
+
+type foo
+
+eval "$(declare -f foo | sed 's:foo:bar:')"
+
+type bar