]> git.ipfire.org Git - thirdparty/bash.git/commitdiff
Bash-4.0 patchlevel 38 bash-4.0 bash-4.0.38
authorChet Ramey <chet.ramey@case.edu>
Tue, 22 Nov 2011 01:49:12 +0000 (20:49 -0500)
committerChet Ramey <chet.ramey@case.edu>
Tue, 22 Nov 2011 01:49:12 +0000 (20:49 -0500)
27 files changed:
arrayfunc.c
bashline.c
builtins/declare.def
builtins/exit.def
builtins/fc.def
builtins/read.def
configure
configure.in
doc/bash.1
doc/bashref.texi
execute_cmd.c
externs.h
jobs.c
jobs.h
lib/glob/glob.c
lib/readline/complete.c
lib/readline/display.c
lib/readline/readline.h
lib/readline/terminal.c
lib/sh/winsize.c
parse.y
patchlevel.h
pcomplete.c
sig.c
subst.c
trap.c
variables.c

index dbc2e20c3885003bc77e03adff27cff6d1eb1b1a..cc313d8e981cf4a60a2a4f1c624e1cbd549dc271 100644 (file)
@@ -98,7 +98,7 @@ convert_var_to_assoc (var)
   oldval = value_cell (var);
   hash = assoc_create (0);
   if (oldval)
-    assoc_insert (hash, "0", oldval);
+    assoc_insert (hash, savestring ("0"), oldval);
 
   FREE (value_cell (var));
   var_setassoc (var, hash);
@@ -604,64 +604,7 @@ quote_array_assignment_chars (list)
     }
 }
 
-/* This function assumes s[i] == '['; returns with s[ret] == ']' if
-   an array subscript is correctly parsed. */
-int
-skipsubscript (s, i)
-     const char *s;
-     int i;
-{
-  int count, c;
-#if defined (HANDLE_MULTIBYTE)
-  mbstate_t state, state_bak;
-  size_t slength, mblength;
-#endif
-
-#if defined (HANDLE_MULTIBYTE)
-  memset (&state, '\0', sizeof (mbstate_t));
-  slength = strlen (s + i);
-#endif
-  
-  count = 1;
-  while (count)
-    {
-      /* Advance one (possibly multibyte) character in S starting at I. */
-#if defined (HANDLE_MULTIBYTE)
-      if (MB_CUR_MAX > 1)
-       {
-         state_bak = state;
-         mblength = mbrlen (s + i, slength, &state);
-
-         if (MB_INVALIDCH (mblength))
-           {
-             state = state_bak;
-             i++;
-             slength--;
-           }
-         else if (MB_NULLWCH (mblength))
-           return i;
-         else
-           {
-             i += mblength;
-             slength -= mblength;
-           }
-       }
-      else
-#endif
-      ++i;
-
-      c = s[i];
-
-      if (c == 0)
-       break;
-      else if (c == '[')
-       count++;
-      else if (c == ']')
-       count--;
-    }
-
-  return i;
-}
+/* skipsubscript moved to subst.c to use private functions. 2009/02/24. */
 
 /* This function is called with SUB pointing to just after the beginning
    `[' of an array subscript and removes the array element to which SUB
index c5e8369730f01d0361ff510d25abacaf02cdf0ec..4594dcf7e340362c9ce7d4dd68e71ca1be94a0d8 100644 (file)
@@ -3388,7 +3388,6 @@ bash_execute_unix_command (count, key)
   Keymap xkmap;                /* unix command executing keymap */
   register int i;
   intmax_t mi;
-  int save_point;
   sh_parser_state_t ps;
   char *cmd, *value, *l;
   SHELL_VAR *v;
@@ -3432,7 +3431,6 @@ bash_execute_unix_command (count, key)
   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)
@@ -3450,7 +3448,7 @@ bash_execute_unix_command (count, key)
   if (v && legal_number (value_cell (v), &mi))
     {
       i = mi;
-      if (i != save_point)
+      if (i != rl_point)
        {
          rl_point = i;
          if (rl_point > rl_end)
index 9931f5e4acbbc38c6e59ba7927bb2e44d7f67717..bd7d6b6ef20b75897e1d538235d976b5ca055b80 100644 (file)
@@ -295,6 +295,13 @@ declare_internal (list, local_var)
       subscript_start = (char *)NULL;
       if (t = strchr (name, '['))      /* ] */
        {
+         /* If offset != 0 we have already validated any array reference */
+         if (offset == 0 && valid_array_reference (name) == 0)
+           {
+             sh_invalidid (name);
+             assign_error++;
+             NEXT_VARIABLE ();
+           }
          subscript_start = t;
          *t = '\0';
          making_array_special = 1;
@@ -484,7 +491,7 @@ declare_internal (list, local_var)
            }
          /* declare -a name[[n]] or declare name[n] makes name an indexed
             array variable. */
-         else if ((making_array_special || (flags_on & att_array)) && array_p (var) == 0)
+         else if ((making_array_special || (flags_on & att_array)) && array_p (var) == 0 && assoc_p (var) == 0)
            var = convert_var_to_array (var);
 #endif /* ARRAY_VARS */
 
index edf8db09d9c6774b4f9a9d3f9b3423a42cd450c8..34728ebfaaa233b8dff301a722eb9c4fbf630040 100644 (file)
@@ -113,7 +113,7 @@ exit_or_logout (list)
       for (i = stopmsg = 0; i < js.j_jobslots; i++)
        if (jobs[i] && STOPPED (i))
          stopmsg = JSTOPPED;
-       else if (check_jobs_at_exit && stopmsg == 0 && RUNNING (i))
+       else if (check_jobs_at_exit && stopmsg == 0 && jobs[i] && RUNNING (i))
          stopmsg = JRUNNING;
 
       if (stopmsg == JSTOPPED)
index 22425d70422ba742df55fe88930cfa003385f946..a378d9de099a1760bbd4266e028662ac52ea4ec3 100644 (file)
@@ -88,6 +88,7 @@ extern int errno;
 extern int current_command_line_count;
 extern int literal_history;
 extern int posixly_correct;
+extern int subshell_environment, interactive_shell;
 
 extern int unlink __P((const char *));
 
@@ -172,7 +173,7 @@ fc_builtin (list)
   register int i;
   register char *sep;
   int numbering, reverse, listing, execute;
-  int histbeg, histend, last_hist, retval, opt;
+  int histbeg, histend, last_hist, retval, opt, rh;
   FILE *stream;
   REPL *rlist, *rl;
   char *ename, *command, *newcom, *fcedit;
@@ -275,6 +276,8 @@ fc_builtin (list)
 
       fprintf (stderr, "%s\n", command);
       fc_replhist (command);   /* replace `fc -s' with command */
+      /* Posix says that the re-executed commands should be entered into the
+        history. */
       return (parse_and_execute (command, "fc", SEVAL_NOHIST));
     }
 
@@ -293,7 +296,12 @@ fc_builtin (list)
      line was actually added (HISTIGNORE may have caused it to not be),
      so we check hist_last_line_added. */
 
-  last_hist = i - remember_on_history - hist_last_line_added;
+  /* Even though command substitution through parse_and_execute turns off
+     remember_on_history, command substitution in a shell when set -o history
+     has been enabled (interactive or not) should use it in the last_hist
+     calculation as if it were on. */
+  rh = remember_on_history || ((subshell_environment & SUBSHELL_COMSUB) && enable_history_list);
+  last_hist = i - rh - hist_last_line_added;
 
   if (list)
     {
@@ -456,7 +464,7 @@ fc_gethnum (command, hlist)
      char *command;
      HIST_ENTRY **hlist;
 {
-  int sign, n, clen;
+  int sign, n, clen, rh;
   register int i, j;
   register char *s;
 
@@ -472,7 +480,12 @@ fc_gethnum (command, hlist)
      line was actually added (HISTIGNORE may have caused it to not be),
      so we check hist_last_line_added.  This needs to agree with the
      calculation of last_hist in fc_builtin above. */
-  i -= remember_on_history + hist_last_line_added;
+  /* Even though command substitution through parse_and_execute turns off
+     remember_on_history, command substitution in a shell when set -o history
+     has been enabled (interactive or not) should use it in the last_hist
+     calculation as if it were on. */
+  rh = remember_on_history || ((subshell_environment & SUBSHELL_COMSUB) && enable_history_list);
+  i -= rh + hist_last_line_added;
 
   /* No specification defaults to most recent command. */
   if (command == NULL)
index fb4366febe3353c15c409c5372470bb19cbc048f..8fc5647638a4536f3da36253c2d32fd67f98c708 100644 (file)
@@ -369,14 +369,14 @@ read_builtin (list)
       code = setjmp (alrmbuf);
       if (code)
        {
-#if 0
+         /* Tricky.  The top of the unwind-protect stack is the free of
+            input_string.  We want to run all the rest and use input_string,
+            so we have to remove it from the stack. */
+         remove_unwind_protect ();
          run_unwind_frame ("read_builtin");
-         return (EXECUTION_FAILURE);
-#else
          input_string[i] = '\0';       /* make sure it's terminated */
-         retval = 128+SIGALRM;;
+         retval = 128+SIGALRM;
          goto assign_vars;
-#endif
        }
       old_alrm = set_signal_handler (SIGALRM, sigalrm);
       add_unwind_protect (reset_alarm, (char *)NULL);
@@ -601,14 +601,15 @@ add_char:
   if (unbuffered_read == 0)
     zsyncfd (fd);
 
-  interrupt_immediately--;
-  terminate_immediately--;
   discard_unwind_frame ("read_builtin");
 
   retval = eof ? EXECUTION_FAILURE : EXECUTION_SUCCESS;
 
 assign_vars:
 
+  interrupt_immediately--;
+  terminate_immediately--;
+
 #if defined (ARRAY_VARS)
   /* If -a was given, take the string read, break it into a list of words,
      an assign them to `arrayname' in turn. */
@@ -763,7 +764,10 @@ assign_vars:
       if (*input_string == 0)
        tofree = input_string = t;
       else
-       input_string = strip_trailing_ifs_whitespace (t1, ifs_chars, saw_escape);
+       {
+         input_string = strip_trailing_ifs_whitespace (t1, ifs_chars, saw_escape);
+         tofree = t;
+       }
     }
 #endif
 
index 5f2774577ea6559b9060479f67ccc6d7137c0ac4..ea5d2e4d11f53d7bde9dc47bb73bba09864666e1 100755 (executable)
--- a/configure
+++ b/configure
@@ -5806,7 +5806,7 @@ _ACEOF
                # static version specified as -llibname to override the
                # dynamic version
                case "${host_os}" in
-               darwin[89]*)    READLINE_LIB='${READLINE_LIBRARY}' ;;
+               darwin[89]*|darwin10*) READLINE_LIB='${READLINE_LIBRARY}' ;;
                *)              READLINE_LIB=-lreadline ;;
                esac
        fi
@@ -5847,7 +5847,7 @@ _ACEOF
                # static version specified as -llibname to override the
                # dynamic version
                case "${host_os}" in
-               darwin[89]*)    HISTORY_LIB='${HISTORY_LIBRARY}' ;;
+               darwin[89]*|darwin10*) HISTORY_LIB='${HISTORY_LIBRARY}' ;;
                *)              HISTORY_LIB=-lhistory ;;
                esac
        fi
index 0fd2bf7861e647c17830d3ee3e1c87a955ade96a..ee34c4b4149e8d8d0be5bd7f1d29c60ec511b77f 100644 (file)
@@ -533,7 +533,7 @@ if test $opt_readline = yes; then
                # static version specified as -llibname to override the
                # dynamic version
                case "${host_os}" in
-               darwin[[89]]* READLINE_LIB='${READLINE_LIBRARY}' ;;
+               darwin[[89]]*|darwin10*) READLINE_LIB='${READLINE_LIBRARY}' ;;
                *)              READLINE_LIB=-lreadline ;;
                esac
        fi
@@ -568,7 +568,7 @@ if test $opt_history = yes || test $opt_bang_history = yes; then
                # static version specified as -llibname to override the
                # dynamic version
                case "${host_os}" in
-               darwin[[89]]* HISTORY_LIB='${HISTORY_LIBRARY}' ;;
+               darwin[[89]]*|darwin10*) HISTORY_LIB='${HISTORY_LIBRARY}' ;;
                *)              HISTORY_LIB=-lhistory ;;
                esac
        fi
index 4308214b178a3a4883e5b485da730545fb692b8e..f0661400c5fb8331cf28ce69e2630ebc44aa0474 100644 (file)
@@ -8257,9 +8257,10 @@ and group ids to be set to the real user and group ids.
 Exit after reading and executing one command.
 .TP 8
 .B \-u
-Treat unset variables as an error when performing
+Treat unset variables and parameters other than the special
+parameters "@" and "*" as an error when performing
 parameter expansion.  If expansion is attempted on an
-unset variable, the shell prints an error message, and,
+unset variable or parameter, the shell prints an error message, and,
 if not interactive, exits with a non-zero status.
 .TP 8
 .B \-v
index 04178bc9f8015ee8dc91617bee807794417b0659..c310664c3f68e98658cc02f4ecf60354f0795400 100644 (file)
@@ -4138,7 +4138,8 @@ and group ids to be set to the real user and group ids.
 Exit after reading and executing one command.
 
 @item -u
-Treat unset variables as an error when performing parameter expansion.
+Treat unset variables and parameters other than the special parameters
+@samp{@@} or @samp{*} as an error when performing parameter expansion.
 An error message will be written to the standard error, and a non-interactive
 shell will exit.
 
index 4843f4ba69cfb118683bb4e182230bef87373e11..9761125bdb26f6c25f80652fd16cfd589ef4abc1 100644 (file)
@@ -568,6 +568,7 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
 
       /* Fork a subshell, turn off the subshell bit, turn off job
         control and call execute_command () on the command again. */
+      line_number_for_err_trap = line_number;
       paren_pid = make_child (savestring (make_command_string (command)),
                              asynchronous);
       if (paren_pid == 0)
@@ -610,7 +611,10 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
              if (user_subshell && was_error_trap && ignore_return == 0 && invert == 0 && exec_result != EXECUTION_SUCCESS)
                {
                  last_command_exit_value = exec_result;
+                 save_line_number = line_number;
+                 line_number = line_number_for_err_trap;
                  run_error_trap ();
+                 line_number = save_line_number;
                }
 
              if (user_subshell && ignore_return == 0 && invert == 0 && exit_immediately_on_error && exec_result != EXECUTION_SUCCESS)
@@ -766,7 +770,9 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
       if (was_error_trap && ignore_return == 0 && invert == 0 && pipe_in == NO_PIPE && pipe_out == NO_PIPE && exec_result != EXECUTION_SUCCESS)
        {
          last_command_exit_value = exec_result;
+         line_number = line_number_for_err_trap;
          run_error_trap ();
+         line_number = save_line_number;
        }
 
       if (ignore_return == 0 && invert == 0 &&
@@ -2105,6 +2111,7 @@ execute_connection (command, asynchronous, pipe_in, pipe_out, fds_to_close)
   REDIRECT *rp;
   COMMAND *tc, *second;
   int ignore_return, exec_result, was_error_trap, invert;
+  volatile int save_line_number;
 
   ignore_return = (command->flags & CMD_IGNORE_RETURN) != 0;
 
@@ -2174,12 +2181,16 @@ execute_connection (command, asynchronous, pipe_in, pipe_out, fds_to_close)
       invert = (command->flags & CMD_INVERT_RETURN) != 0;
       ignore_return = (command->flags & CMD_IGNORE_RETURN) != 0;
 
+      line_number_for_err_trap = line_number;
       exec_result = execute_pipeline (command, asynchronous, pipe_in, pipe_out, fds_to_close);
 
       if (was_error_trap && ignore_return == 0 && invert == 0 && exec_result != EXECUTION_SUCCESS)
        {
          last_command_exit_value = exec_result;
+         save_line_number = line_number;
+         line_number = line_number_for_err_trap;
          run_error_trap ();
+         line_number = save_line_number;
        }
 
       if (ignore_return == 0 && invert == 0 && exit_immediately_on_error && exec_result != EXECUTION_SUCCESS)
@@ -2930,7 +2941,7 @@ execute_case_command (case_command)
                  retval = execute_command (clauses->action);
                }
              while ((clauses->flags & CASEPAT_FALLTHROUGH) && (clauses = clauses->next));
-             if ((clauses->flags & CASEPAT_TESTNEXT) == 0)
+             if (clauses == 0 || (clauses->flags & CASEPAT_TESTNEXT) == 0)
                EXIT_CASE ();
              else
                break;
index 1079e727257a80aa2b4da89f13fa7aaa889f0e27..cafbd5fa804fe41c08eeca169f334551af429600 100644 (file)
--- a/externs.h
+++ b/externs.h
@@ -192,6 +192,8 @@ extern char *fmtullong __P((unsigned long long int, int, char *, size_t, int));
 extern char *fmtumax __P((uintmax_t, int, char *, size_t, int));
 
 /* Declarations for functions defined in lib/sh/fpurge.c */
+
+#if defined NEED_FPURGE_DECL
 #if !HAVE_DECL_FPURGE
 
 #if HAVE_FPURGE
@@ -200,7 +202,7 @@ extern char *fmtumax __P((uintmax_t, int, char *, size_t, int));
 extern int fpurge __P((FILE *stream));
 
 #endif /* HAVE_DECL_FPURGE */
-
+#endif /* NEED_FPURGE_DECL */
 
 /* Declarations for functions defined in lib/sh/getcwd.c */
 #if !defined (HAVE_GETCWD)
diff --git a/jobs.c b/jobs.c
index 24d98af5668f550689d8fb555e147f6504991c95..d8bb7ae1e7ba541b84bb161a007a00c868b774ae 100644 (file)
--- a/jobs.c
+++ b/jobs.c
@@ -442,7 +442,7 @@ restore_pipeline (discard)
   old_pipeline = the_pipeline;
   the_pipeline = saved_pipeline;
   already_making_children = saved_already_making_children;
-  if (discard)
+  if (discard && old_pipeline)
     discard_pipeline (old_pipeline);
 }
 
@@ -4202,4 +4202,23 @@ close_pgrp_pipe ()
   sh_closepipe (pgrp_pipe);
 }
 
+void
+save_pgrp_pipe (p, clear)
+     int *p;
+     int clear;
+{
+  p[0] = pgrp_pipe[0];
+  p[1] = pgrp_pipe[1];
+  if (clear)
+    pgrp_pipe[0] = pgrp_pipe[1] = -1;
+}
+
+void
+restore_pgrp_pipe (p)
+     int *p;
+{
+  pgrp_pipe[0] = p[0];
+  pgrp_pipe[1] = p[1];
+}
+
 #endif /* PGRP_PIPE */
diff --git a/jobs.h b/jobs.h
index 6e82f762c09bb001f4ca7e2bb1512d11c20b2289..65de773b856e669c2e45265124d194fb17035860 100644 (file)
--- a/jobs.h
+++ b/jobs.h
@@ -235,6 +235,8 @@ extern void default_tty_job_signals __P((void));
 extern void init_job_stats __P((void));
 
 extern void close_pgrp_pipe __P((void));
+extern void save_pgrp_pipe __P((int *, int));
+extern void restore_pgrp_pipe __P((int *));
 
 #if defined (JOB_CONTROL)
 extern int job_control;
index dceb2e57002b89aba8136533be67d57cb9e53556..3542244368c89a9b773aae8fdf2525a43ba12f4a 100644 (file)
@@ -356,7 +356,7 @@ finddirs (pat, sdir, flags, ep, np)
        *np = 0;
       if (ep)
         *ep = 0;
-      if (r)
+      if (r && r != &glob_error_return)
        free (r);
       return (struct globval *)0;
     }
@@ -665,7 +665,9 @@ glob_vector (pat, dir, flags)
       (void) closedir (d);
     }
 
-  /* compat: if GX_ALLDIRS, add the passed directory also */
+  /* compat: if GX_ADDCURDIR, add the passed directory also.  Add an empty
+     directory name as a placeholder if GX_NULLDIR (in which case the passed
+     directory name is "."). */
   if (add_current)
     {
       sdlen = strlen (dir);
@@ -917,11 +919,14 @@ glob_filename (pathname, flags)
        {
          char **temp_results;
 
+         /* XXX -- we've recursively scanned any directories resulting from
+            a `**', so turn off the flag.  We turn it on again below if
+            filename is `**' */
          /* Scan directory even on a NULL filename.  That way, `*h/'
             returns only directories ending in `h', instead of all
             files ending in `h' with a `/' appended. */
          dname = directories[i];
-         dflags = flags & ~GX_MARKDIRS;
+         dflags = flags & ~(GX_MARKDIRS|GX_ALLDIRS|GX_ADDCURDIR);
          if ((flags & GX_GLOBSTAR) && filename[0] == '*' && filename[1] == '*' && filename[2] == '\0')
            dflags |= GX_ALLDIRS|GX_ADDCURDIR;
          if (dname[0] == '\0' && filename[0])
@@ -942,7 +947,12 @@ glob_filename (pathname, flags)
              char **array;
              register unsigned int l;
 
-             array = glob_dir_to_array (directories[i], temp_results, flags);
+             /* If we're expanding **, we don't need to glue the directory
+                name to the results; we've already done it in glob_vector */
+             if ((dflags & GX_ALLDIRS) && filename[0] == '*' && filename[1] == '*' && filename[2] == '\0')
+               array = temp_results;
+             else
+               array = glob_dir_to_array (directories[i], temp_results, flags);
              l = 0;
              while (array[l] != NULL)
                ++l;
@@ -959,7 +969,8 @@ glob_filename (pathname, flags)
              result[result_size - 1] = NULL;
 
              /* Note that the elements of ARRAY are not freed.  */
-             free ((char *) array);
+             if (array != temp_results)
+               free ((char *) array);
            }
        }
       /* Free the directories.  */
@@ -1003,11 +1014,24 @@ glob_filename (pathname, flags)
 
       /* Just return what glob_vector () returns appended to the
         directory name. */
+      /* If flags & GX_ALLDIRS, we're called recursively */
       dflags = flags & ~GX_MARKDIRS;
       if (directory_len == 0)
        dflags |= GX_NULLDIR;
       if ((flags & GX_GLOBSTAR) && filename[0] == '*' && filename[1] == '*' && filename[2] == '\0')
-       dflags |= GX_ALLDIRS|GX_ADDCURDIR;
+       {
+         dflags |= GX_ALLDIRS|GX_ADDCURDIR;
+#if 0
+         /* If we want all directories (dflags & GX_ALLDIRS) and we're not
+            being called recursively as something like `echo **/*.o'
+            ((flags & GX_ALLDIRS) == 0), we want to prevent glob_vector from
+            adding a null directory name to the front of the temp_results
+            array.  We turn off ADDCURDIR if not called recursively and
+            dlen == 0 */
+#endif
+         if (directory_len == 0 && (flags & GX_ALLDIRS) == 0)
+           dflags &= ~GX_ADDCURDIR;
+       }
       temp_results = glob_vector (filename,
                                  (directory_len == 0 ? "." : directory_name),
                                  dflags);
index 20bb1eaacd2a0de096fd7007a0d39839f763b2db..59b486ad05103cb0d92e8a7188c0ef15e40be690 100644 (file)
@@ -2208,7 +2208,7 @@ rl_old_menu_complete (count, invoking_key)
 
   /* The first time through, we generate the list of matches and set things
      up to insert them. */
-  if (rl_last_func != rl_menu_complete)
+  if (rl_last_func != rl_old_menu_complete)
     {
       /* Clean up from previous call, if any. */
       FREE (orig_text);
@@ -2220,6 +2220,8 @@ rl_old_menu_complete (count, invoking_key)
 
       rl_completion_invoking_key = invoking_key;
 
+      RL_SETSTATE(RL_STATE_COMPLETING);
+
       /* Only the completion entry function can change these. */
       set_completion_defaults ('%');
 
@@ -2259,9 +2261,12 @@ rl_old_menu_complete (count, invoking_key)
          FREE (orig_text);
          orig_text = (char *)0;
          completion_changed_buffer = 0;
+         RL_UNSETSTATE(RL_STATE_COMPLETING);
           return (0);
        }
 
+      RL_UNSETSTATE(RL_STATE_COMPLETING);
+
       for (match_list_size = 0; matches[match_list_size]; match_list_size++)
         ;
       /* matches[0] is lcd if match_list_size > 1, but the circular buffer
@@ -2337,6 +2342,8 @@ rl_menu_complete (count, ignore)
 
       full_completion = 0;
 
+      RL_SETSTATE(RL_STATE_COMPLETING);
+
       /* Only the completion entry function can change these. */
       set_completion_defaults ('%');
 
@@ -2378,9 +2385,12 @@ rl_menu_complete (count, ignore)
          FREE (orig_text);
          orig_text = (char *)0;
          completion_changed_buffer = 0;
+         RL_UNSETSTATE(RL_STATE_COMPLETING);
           return (0);
        }
 
+      RL_UNSETSTATE(RL_STATE_COMPLETING);
+
       for (match_list_size = 0; matches[match_list_size]; match_list_size++)
         ;
 
index e941c78ac7a35ab6750f9785454a637ac9e32ab0..c58d4f7e929bd28d6ed412ded05401d1a594801f 100644 (file)
@@ -512,6 +512,7 @@ rl_redisplay ()
   /* Block keyboard interrupts because this function manipulates global
      data structures. */
   _rl_block_sigint ();  
+  RL_SETSTATE (RL_STATE_REDISPLAYING);
 
   if (!rl_display_prompt)
     rl_display_prompt = "";
@@ -1188,9 +1189,11 @@ rl_redisplay ()
       if (t < out)
        line[t - 1] = '>';
 
-      if (!rl_display_fixed || forced_display || lmargin != last_lmargin)
+      if (rl_display_fixed == 0 || forced_display || lmargin != last_lmargin)
        {
          forced_display = 0;
+         o_cpos = _rl_last_c_pos;
+         cpos_adjusted = 0;
          update_line (&visible_line[last_lmargin],
                       &invisible_line[lmargin],
                       0,
@@ -1198,6 +1201,13 @@ rl_redisplay ()
                       _rl_screenwidth + (lmargin ? 0 : wrap_offset),
                       0);
 
+         if ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) &&
+             cpos_adjusted == 0 &&
+             _rl_last_c_pos != o_cpos &&
+             _rl_last_c_pos > wrap_offset &&
+             o_cpos < prompt_last_invisible)
+               _rl_last_c_pos -= prompt_invis_chars_first_line;        /* XXX - was wrap_offset */
+
          /* If the visible new line is shorter than the old, but the number
             of invisible characters is greater, and we are at the end of
             the new line, we need to clear to eol. */
@@ -1236,6 +1246,7 @@ rl_redisplay ()
       visible_wrap_offset = wrap_offset;
   }
 
+  RL_UNSETSTATE (RL_STATE_REDISPLAYING);
   _rl_release_sigint ();
 }
 
@@ -1772,7 +1783,7 @@ update_line (old, new, current_line, omax, nmax, inv_botlin)
             space_to_eol will insert too many spaces.  XXX - maybe we should
             adjust col_lendiff based on the difference between _rl_last_c_pos
             and _rl_screenwidth */
-         if (col_lendiff && (_rl_last_c_pos < _rl_screenwidth))
+         if (col_lendiff && ((MB_CUR_MAX == 1 || rl_byte_oriented) || (_rl_last_c_pos < _rl_screenwidth)))
 #endif
            {     
              if (_rl_term_autowrap && current_line < inv_botlin)
@@ -1892,6 +1903,10 @@ _rl_move_cursor_relative (new, data)
 
   woff = WRAP_OFFSET (_rl_last_v_pos, wrap_offset);
   cpos = _rl_last_c_pos;
+
+  if (cpos == 0 && cpos == new)
+    return;
+
 #if defined (HANDLE_MULTIBYTE)
   /* If we have multibyte characters, NEW is indexed by the buffer point in
      a multibyte string, but _rl_last_c_pos is the display position.  In
@@ -1905,9 +1920,9 @@ _rl_move_cursor_relative (new, data)
         prompt string, since they're both buffer indices and DPOS is a
         desired display position. */
       if ((new > prompt_last_invisible) ||             /* XXX - don't use woff here */
-         (prompt_physical_chars > _rl_screenwidth &&
+         (prompt_physical_chars >= _rl_screenwidth &&
           _rl_last_v_pos == prompt_last_screen_line &&
-          wrap_offset >= woff &&
+          wrap_offset >= woff && dpos >= woff &&
           new > (prompt_last_invisible-(_rl_screenwidth*_rl_last_v_pos)-wrap_offset)))
           /* XXX last comparison might need to be >= */
        {
index ba0d5d624588868aef6baebcbf7b3b7e6f02f404..fa02dec0de8ee4c7068079c51f36a9d5711d7883 100644 (file)
@@ -814,8 +814,9 @@ extern int rl_inhibit_completion;
 #define RL_STATE_VIMOTION      0x100000        /* reading vi motion arg */
 #define RL_STATE_MULTIKEY      0x200000        /* reading multiple-key command */
 #define RL_STATE_VICMDONCE     0x400000        /* entered vi command mode at least once */
+#define RL_STATE_REDISPLAYING  0x800000        /* updating terminal display */
 
-#define RL_STATE_DONE          0x800000        /* done; accepted line */
+#define RL_STATE_DONE          0x1000000       /* done; accepted line */
 
 #define RL_SETSTATE(x)         (rl_readline_state |= (x))
 #define RL_UNSETSTATE(x)       (rl_readline_state &= ~(x))
index 87fdf1012e69cd5f72d01fac4e4ccab66ebc8848..768ec9bbdece750c7f2e1978c0ec9630f6f85689 100644 (file)
@@ -355,7 +355,7 @@ rl_resize_terminal ()
       _rl_get_screen_size (fileno (rl_instream), 1);
       if (CUSTOM_REDISPLAY_FUNC ())
        rl_forced_update_display ();
-      else
+      else if (RL_ISSTATE(RL_STATE_REDISPLAYING) == 0)
        _rl_redisplay_after_sigwinch ();
     }
 }
index 81ebb378c0c6bde52766d0136c6e8f16ad69a9bb..64a985844793533e2b1724a14db9d512ade6aadb 100644 (file)
 
 #include <sys/ioctl.h>
 
-#if !defined (STRUCT_WINSIZE_IN_SYS_IOCTL)
-/* For struct winsize on SCO */
-/*   sys/ptem.h has winsize but needs mblk_t from sys/stream.h */
-#  if defined (HAVE_SYS_PTEM_H) && defined (TIOCGWINSZ) && defined (SIGWINCH)
-#    if defined (HAVE_SYS_STREAM_H)
-#      include <sys/stream.h>
-#    endif
+/* Try to find the definitions of `struct winsize' and TIOGCWINSZ */
+
+#if defined (GWINSZ_IN_SYS_IOCTL) && !defined (TIOCGWINSZ)
+#  include <sys/ioctl.h>
+#endif /* GWINSZ_IN_SYS_IOCTL && !TIOCGWINSZ */
+
+#if defined (STRUCT_WINSIZE_IN_TERMIOS) && !defined (STRUCT_WINSIZE_IN_SYS_IOCTL)
+#  include <termios.h>
+#endif /* STRUCT_WINSIZE_IN_TERMIOS && !STRUCT_WINSIZE_IN_SYS_IOCTL */
+
+/* Not in either of the standard places, look around. */
+#if !defined (STRUCT_WINSIZE_IN_TERMIOS) && !defined (STRUCT_WINSIZE_IN_SYS_IOCTL)
+#  if defined (HAVE_SYS_STREAM_H)
+#    include <sys/stream.h>
+#  endif /* HAVE_SYS_STREAM_H */
+#  if defined (HAVE_SYS_PTEM_H) /* SVR4.2, at least, has it here */
 #    include <sys/ptem.h>
-#  endif /* HAVE_SYS_PTEM_H && TIOCGWINSZ && SIGWINCH */
-#endif /* !STRUCT_WINSIZE_IN_SYS_IOCTL */
+#    define _IO_PTEM_H          /* work around SVR4.2 1.1.4 bug */
+#  endif /* HAVE_SYS_PTEM_H */
+#  if defined (HAVE_SYS_PTE_H)  /* ??? */
+#    include <sys/pte.h>
+#  endif /* HAVE_SYS_PTE_H */
+#endif /* !STRUCT_WINSIZE_IN_TERMIOS && !STRUCT_WINSIZE_IN_SYS_IOCTL */
 
 #include <stdio.h>
 
diff --git a/parse.y b/parse.y
index 8461337eed87db6cddd33119740a0af9d24cd112..eebd54953ace9ab77b46ad85f97d7e479a2a8844 100644 (file)
--- a/parse.y
+++ b/parse.y
@@ -1122,7 +1122,7 @@ pipeline: pipeline '|' newline_list pipeline
                          REDIRECTEE rd;
                          REDIRECT *r;
 
-                         tc = $1;
+                         tc = $1->type == cm_simple ? (COMMAND *)$1->value.Simple : $1;
                          rd.dest = 1;
                          r = make_redirection (2, r_duplicating_output, rd);
                          if (tc->redirects)
@@ -1615,10 +1615,11 @@ save_token_state ()
 {
   int *ret;
 
-  ret = (int *)xmalloc (3 * sizeof (int));
+  ret = (int *)xmalloc (4 * sizeof (int));
   ret[0] = last_read_token;
   ret[1] = token_before_that;
   ret[2] = two_tokens_ago;
+  ret[3] = current_token;
   return ret;
 }
 
@@ -1631,6 +1632,7 @@ restore_token_state (ts)
   last_read_token = ts[0];
   token_before_that = ts[1];
   two_tokens_ago = ts[2];
+  current_token = ts[3];
 }
 
 /*
@@ -1877,7 +1879,7 @@ read_secondary_line (remove_quoted_newline)
     prompt_again ();
   ret = read_a_line (remove_quoted_newline);
 #if defined (HISTORY)
-  if (remember_on_history && (parser_state & PST_HEREDOC))
+  if (ret && remember_on_history && (parser_state & PST_HEREDOC))
     {
       /* To make adding the the here-document body right, we need to rely
         on history_delimiting_chars() returning \n for the first line of
@@ -2668,6 +2670,7 @@ reset_parser ()
   FREE (word_desc_to_read);
   word_desc_to_read = (WORD_DESC *)NULL;
 
+  current_token = '\n';                /* XXX */
   last_read_token = '\n';
   token_to_read = '\n';
 }
@@ -2915,6 +2918,7 @@ tokword:
 #define P_DQUOTE       0x04
 #define P_COMMAND      0x08    /* parsing a command, so look for comments */
 #define P_BACKQUOTE    0x10    /* parsing a backquoted command substitution */
+#define P_ARRAYSUB     0x20    /* parsing a [...] array subscript for assignment */
 
 /* Lexical state while parsing a grouping construct or $(...). */
 #define LEX_WASDOL     0x001
@@ -2927,6 +2931,7 @@ tokword:
 #define LEX_INHEREDOC  0x080
 #define LEX_HEREDELIM  0x100           /* reading here-doc delimiter */
 #define LEX_STRIPDOC   0x200           /* <<- strip tabs from here doc delim */
+#define LEX_INWORD     0x400
 
 #define COMSUB_META(ch)                ((ch) == ';' || (ch) == '&' || (ch) == '|')
 
@@ -3129,6 +3134,8 @@ parse_matched_pair (qc, open, close, lenp, flags)
              APPEND_NESTRET ();
              FREE (nestret);
            }
+         else if ((flags & P_ARRAYSUB) && (tflags & LEX_WASDOL) && (ch == '(' || ch == '{' || ch == '['))      /* ) } ] */
+           goto parse_dollar_word;
        }
       /* Parse an old-style command substitution within double quotes as a
         single word. */
@@ -3145,6 +3152,7 @@ parse_matched_pair (qc, open, close, lenp, flags)
       else if MBTEST(open != '`' && (tflags & LEX_WASDOL) && (ch == '(' || ch == '{' || ch == '['))    /* ) } ] */
        /* check for $(), $[], or ${} inside quoted string. */
        {
+parse_dollar_word:
          if (open == ch)       /* undo previous increment */
            count--;
          if (ch == '(')                /* ) */
@@ -3179,7 +3187,7 @@ parse_comsub (qc, open, close, lenp, flags)
      int open, close;
      int *lenp, flags;
 {
-  int count, ch, peekc, tflags, lex_rwlen, lex_firstind;
+  int count, ch, peekc, tflags, lex_rwlen, lex_wlen, lex_firstind;
   int nestlen, ttranslen, start_lineno;
   char *ret, *nestret, *ttrans, *heredelim;
   int retind, retsize, rflags, hdlen;
@@ -3200,7 +3208,7 @@ parse_comsub (qc, open, close, lenp, flags)
   retind = 0;
 
   start_lineno = line_number;
-  lex_rwlen = 0;
+  lex_rwlen = lex_wlen = 0;
 
   heredelim = 0;
   lex_firstind = -1;
@@ -3267,6 +3275,46 @@ eof_error:
          continue;
        }
 
+      if (tflags & LEX_PASSNEXT)               /* last char was backslash */
+       {
+/*itrace("parse_comsub:%d: lex_passnext -> 0 ch = `%c' (%d)", line_number, ch, __LINE__);*/
+         tflags &= ~LEX_PASSNEXT;
+         if (qc != '\'' && ch == '\n') /* double-quoted \<newline> disappears. */
+           {
+             if (retind > 0)
+               retind--;       /* swallow previously-added backslash */
+             continue;
+           }
+
+         RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64);
+         if MBTEST(ch == CTLESC || ch == CTLNUL)
+           ret[retind++] = CTLESC;
+         ret[retind++] = ch;
+         continue;
+       }
+
+      /* If this is a shell break character, we are not in a word.  If not,
+        we either start or continue a word. */
+      if MBTEST(shellbreak (ch))
+       {
+         tflags &= ~LEX_INWORD;
+/*itrace("parse_comsub:%d: lex_inword -> 0 ch = `%c' (%d)", line_number, ch, __LINE__);*/
+       }
+      else
+       {
+         if (tflags & LEX_INWORD)
+           {
+             lex_wlen++;
+/*itrace("parse_comsub:%d: lex_inword == 1 ch = `%c' lex_wlen = %d (%d)", line_number, ch, lex_wlen, __LINE__);*/
+           }         
+         else
+           {
+/*itrace("parse_comsub:%d: lex_inword -> 1 ch = `%c' (%d)", line_number, ch, __LINE__);*/
+             tflags |= LEX_INWORD;
+             lex_wlen = 0;
+           }
+       }
+
       /* Skip whitespace */
       if MBTEST(shellblank (ch) && lex_rwlen == 0)
         {
@@ -3306,7 +3354,7 @@ eof_error:
        }
 
       /* Meta-characters that can introduce a reserved word.  Not perfect yet. */
-      if MBTEST((tflags & LEX_RESWDOK) == 0 && (tflags & LEX_CKCASE) && (tflags & LEX_INCOMMENT) == 0 && shellmeta(ch))
+      if MBTEST((tflags & LEX_RESWDOK) == 0 && (tflags & LEX_CKCASE) && (tflags & LEX_INCOMMENT) == 0 && (shellmeta(ch) || ch == '\n'))
        {
          /* Add this character. */
          RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64);
@@ -3364,9 +3412,21 @@ eof_error:
 }              
              tflags &= ~LEX_RESWDOK;
            }
-         else if (shellbreak (ch) == 0)
+         else if MBTEST((tflags & LEX_CKCOMMENT) && ch == '#' && (lex_rwlen == 0 || ((tflags & LEX_INWORD) && lex_wlen == 0)))
+           ;   /* don't modify LEX_RESWDOK if we're starting a comment */
+         else if MBTEST((tflags & LEX_INCASE) && ch != '\n')
+           /* If we can read a reserved word and we're in case, we're at the
+              point where we can read a new pattern list or an esac.  We
+              handle the esac case above.  If we read a newline, we want to
+              leave LEX_RESWDOK alone.  If we read anything else, we want to
+              turn off LEX_RESWDOK, since we're going to read a pattern list. */
 {
-             tflags &= ~LEX_RESWDOK;
+           tflags &= ~LEX_RESWDOK;
+/*itrace("parse_comsub:%d: lex_incase == 1 found `%c', lex_reswordok -> 0", line_number, ch);*/
+}
+         else if MBTEST(shellbreak (ch) == 0)
+{
+           tflags &= ~LEX_RESWDOK;
 /*itrace("parse_comsub:%d: found `%c', lex_reswordok -> 0", line_number, ch);*/
 }
        }
@@ -3394,36 +3454,23 @@ eof_error:
                }
              else
                shell_ungetc (peekc);
-             tflags |= LEX_HEREDELIM;
-             lex_firstind = -1;
+             if (peekc != '<')
+               {
+                 tflags |= LEX_HEREDELIM;
+                 lex_firstind = -1;
+               }
              continue;
            }
          else
-           ch = peekc;         /* fall through and continue XXX - this skips comments if peekc == '#' */
+           ch = peekc;         /* fall through and continue XXX */
        }
-      /* Not exactly right yet, should handle shell metacharacters, too.  If
-        any changes are made to this test, make analogous changes to subst.c:
-        extract_delimited_string(). */
-      else if MBTEST((tflags & LEX_CKCOMMENT) && (tflags & LEX_INCOMMENT) == 0 && ch == '#' && (retind == 0 || ret[retind-1] == '\n' || shellblank (ret[retind - 1])))
+      else if MBTEST((tflags & LEX_CKCOMMENT) && (tflags & LEX_INCOMMENT) == 0 && ch == '#' && (((tflags & LEX_RESWDOK) && lex_rwlen == 0) || ((tflags & LEX_INWORD) && lex_wlen == 0)))
+{
+/*itrace("parse_comsub:%d: lex_incomment -> 1 (%d)", line_number, __LINE__);*/
        tflags |= LEX_INCOMMENT;
+}
 
-      if (tflags & LEX_PASSNEXT)               /* last char was backslash */
-       {
-         tflags &= ~LEX_PASSNEXT;
-         if (qc != '\'' && ch == '\n') /* double-quoted \<newline> disappears. */
-           {
-             if (retind > 0)
-               retind--;       /* swallow previously-added backslash */
-             continue;
-           }
-
-         RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64);
-         if MBTEST(ch == CTLESC || ch == CTLNUL)
-           ret[retind++] = CTLESC;
-         ret[retind++] = ch;
-         continue;
-       }
-      else if MBTEST(ch == CTLESC || ch == CTLNUL)     /* special shell escapes */
+      if MBTEST(ch == CTLESC || ch == CTLNUL)  /* special shell escapes */
        {
          RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64);
          ret[retind++] = CTLESC;
@@ -4248,7 +4295,7 @@ read_token_word (character)
                     ((token_index > 0 && assignment_acceptable (last_read_token) && token_is_ident (token, token_index)) ||
                      (token_index == 0 && (parser_state&PST_COMPASSIGN))))
         {
-         ttok = parse_matched_pair (cd, '[', ']', &ttoklen, 0);
+         ttok = parse_matched_pair (cd, '[', ']', &ttoklen, P_ARRAYSUB);
          if (ttok == &matched_pair_error)
            return -1;          /* Bail immediately. */
          RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 2,
@@ -4449,6 +4496,7 @@ reserved_word_acceptable (toksym)
     case '}':          /* XXX */
     case AND_AND:
     case BANG:
+    case BAR_AND:
     case DO:
     case DONE:
     case ELIF:
index 2af2f568bfa11f0324f8b7a55e50fe876f584b15..233b2c197f030d2dc4b48427df5f5fc97c4d5a48 100644 (file)
@@ -25,6 +25,6 @@
    regexp `^#define[   ]*PATCHLEVEL', since that's what support/mkversion.sh
    looks for to find the patch level (for the sccs version string). */
 
-#define PATCHLEVEL 0
+#define PATCHLEVEL 38
 
 #endif /* _PATCHLEVEL_H_ */
index e1ccaac8678ed6cbd3c2b2496fb6ad258954482c..40fcc34f8325303455a38c81148bec760c9eb9a6 100644 (file)
@@ -1032,6 +1032,7 @@ gen_shell_function_matches (cs, text, line, ind, lwords, nw, cw)
   cmdlist = build_arg_list (funcname, text, lwords, cw);
 
   pps = &ps;
+  save_parser_state (pps);
   begin_unwind_frame ("gen-shell-function-matches");
   add_unwind_protect (restore_parser_state, (char *)pps);
   add_unwind_protect (dispose_words, (char *)cmdlist);
@@ -1174,13 +1175,15 @@ command_line_to_word_list (line, llen, sentinel, nwp, cwp)
 {
   WORD_LIST *ret;
   char *delims;
+  int i, j;
 
-#if 0
-  delims = "()<>;&| \t\n";     /* shell metacharacters break words */
-#else
-  delims = rl_completer_word_break_characters;
-#endif
+  delims = xmalloc (strlen (rl_completer_word_break_characters) + 1);
+  for (i = j = 0; rl_completer_word_break_characters[i]; i++)
+    if (rl_completer_word_break_characters[i] != '\'' && rl_completer_word_break_characters[i] != '"')
+      delims[j++] = rl_completer_word_break_characters[i];
+  delims[j] = '\0';
   ret = split_at_delims (line, llen, delims, sentinel, nwp, cwp);
+  free (delims);
   return (ret);
 }
 
diff --git a/sig.c b/sig.c
index f9beee144d98500043f73ece0715d388c4a60496..e876a2b26747b83e21eaaf6805e3bacf20c79db4 100644 (file)
--- a/sig.c
+++ b/sig.c
@@ -448,6 +448,48 @@ sighandler
 termsig_sighandler (sig)
      int sig;
 {
+  /* If we get called twice with the same signal before handling it,
+     terminate right away. */
+  if (
+#ifdef SIGHUP
+    sig != SIGHUP &&
+#endif
+#ifdef SIGINT
+    sig != SIGINT &&
+#endif
+#ifdef SIGDANGER
+    sig != SIGDANGER &&
+#endif
+#ifdef SIGPIPE
+    sig != SIGPIPE &&
+#endif
+#ifdef SIGALRM
+    sig != SIGALRM &&
+#endif
+#ifdef SIGTERM
+    sig != SIGTERM &&
+#endif
+#ifdef SIGXCPU
+    sig != SIGXCPU &&
+#endif
+#ifdef SIGXFSZ
+    sig != SIGXFSZ &&
+#endif
+#ifdef SIGVTALRM
+    sig != SIGVTALRM &&
+#endif
+#ifdef SIGLOST
+    sig != SIGLOST &&
+#endif
+#ifdef SIGUSR1
+    sig != SIGUSR1 &&
+#endif
+#ifdef SIGUSR2
+   sig != SIGUSR2 &&
+#endif
+   sig == terminating_signal)
+    terminate_immediately = 1;
+
   terminating_signal = sig;
 
   /* XXX - should this also trigger when interrupt_immediately is set? */
diff --git a/subst.c b/subst.c
index 62a3d028e45b9831cb7f597bf4a7ea6e4d927c9b..78f217cabb2a045f6444d07ff56f9deddd1ab5a3 100644 (file)
--- a/subst.c
+++ b/subst.c
@@ -85,6 +85,7 @@ extern int errno;
 
 /* Flags for the `pflags' argument to param_expand() */
 #define PF_NOCOMSUB    0x01    /* Do not perform command substitution */
+#define PF_IGNUNBOUND  0x02    /* ignore unbound vars even if -u set */
 
 /* These defs make it easier to use the editor. */
 #define LBRACE         '{'
@@ -222,6 +223,7 @@ static inline int skip_single_quoted __P((const char *, size_t, int));
 static int skip_double_quoted __P((char *, size_t, int));
 static char *extract_delimited_string __P((char *, int *, char *, char *, char *, int));
 static char *extract_dollar_brace_string __P((char *, int *, int, int));
+static int skip_matched_pair __P((const char *, int, int, int, int));
 
 static char *pos_params __P((char *, int, int, int));
 
@@ -262,7 +264,7 @@ static int valid_brace_expansion_word __P((char *, int));
 static int chk_atstar __P((char *, int, int *, int *));
 static int chk_arithsub __P((const char *, int));
 
-static WORD_DESC *parameter_brace_expand_word __P((char *, int, int));
+static WORD_DESC *parameter_brace_expand_word __P((char *, int, int, int));
 static WORD_DESC *parameter_brace_expand_indir __P((char *, int, int, int *, int *));
 static WORD_DESC *parameter_brace_expand_rhs __P((char *, char *, int, int, int *, int *));
 static void parameter_brace_expand_error __P((char *, char *));
@@ -1374,6 +1376,107 @@ unquote_bang (string)
 
 #define CQ_RETURN(x) do { no_longjmp_on_fatal_error = 0; return (x); } while (0)
 
+/* This function assumes s[i] == open; returns with s[ret] == close; used to
+   parse array subscripts.  FLAGS currently unused. */
+static int
+skip_matched_pair (string, start, open, close, flags)
+     const char *string;
+     int start, open, close, flags;
+{
+  int i, pass_next, backq, si, c, count;
+  size_t slen;
+  char *temp, *ss;
+  DECLARE_MBSTATE;
+
+  slen = strlen (string + start) + start;
+  no_longjmp_on_fatal_error = 1;
+
+  i = start + 1;               /* skip over leading bracket */
+  count = 1;
+  pass_next = backq = 0;
+  ss = (char *)string;
+  while (c = string[i])
+    {
+      if (pass_next)
+       {
+         pass_next = 0;
+         if (c == 0)
+           CQ_RETURN(i);
+         ADVANCE_CHAR (string, slen, i);
+         continue;
+       }
+      else if (c == '\\')
+       {
+         pass_next = 1;
+         i++;
+         continue;
+       }
+      else if (backq)
+       {
+         if (c == '`')
+           backq = 0;
+         ADVANCE_CHAR (string, slen, i);
+         continue;
+       }
+      else if (c == '`')
+       {
+         backq = 1;
+         i++;
+         continue;
+       }
+      else if (c == open)
+       {
+         count++;
+         i++;
+         continue;
+       }
+      else if (c == close)
+       {
+         count--;
+         if (count == 0)
+           break;
+         i++;
+         continue;
+       }
+      else if (c == '\'' || c == '"')
+       {
+         i = (c == '\'') ? skip_single_quoted (ss, slen, ++i)
+                         : skip_double_quoted (ss, slen, ++i);
+         /* no increment, the skip functions increment past the closing quote. */
+       }
+      else if (c == '$' && (string[i+1] == LPAREN || string[i+1] == LBRACE))
+       {
+         si = i + 2;
+         if (string[si] == '\0')
+           CQ_RETURN(si);
+
+         if (string[i+1] == LPAREN)
+           temp = extract_delimited_string (ss, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */
+         else
+           temp = extract_dollar_brace_string (ss, &si, 0, SX_NOALLOC);
+         i = si;
+         if (string[i] == '\0')        /* don't increment i past EOS in loop */
+           break;
+         i++;
+         continue;
+       }
+      else
+       ADVANCE_CHAR (string, slen, i);
+    }
+
+  CQ_RETURN(i);
+}
+
+#if defined (ARRAY_VARS)
+int
+skipsubscript (string, start)
+     const char *string;
+     int start;
+{
+  return (skip_matched_pair (string, start, '[', ']', 0));
+}
+#endif
+
 /* Skip characters in STRING until we find a character in DELIMS, and return
    the index of that character.  START is the index into string at which we
    begin.  This is similar in spirit to strpbrk, but it returns an index into
@@ -5093,9 +5196,9 @@ chk_atstar (name, quoted, quoted_dollar_atp, contains_dollar_at)
    the shell, e.g., "@", "$", "*", etc.  QUOTED, if non-zero, means that
    NAME was found inside of a double-quoted expression. */
 static WORD_DESC *
-parameter_brace_expand_word (name, var_is_special, quoted)
+parameter_brace_expand_word (name, var_is_special, quoted, pflags)
      char *name;
-     int var_is_special, quoted;
+     int var_is_special, quoted, pflags;
 {
   WORD_DESC *ret;
   char *temp, *tt;
@@ -5127,7 +5230,7 @@ parameter_brace_expand_word (name, var_is_special, quoted)
       strcpy (tt + 1, name);
 
       ret = param_expand (tt, &sindex, quoted, (int *)NULL, (int *)NULL,
-                         (int *)NULL, (int *)NULL, 0);
+                         (int *)NULL, (int *)NULL, pflags);
       free (tt);
     }
 #if defined (ARRAY_VARS)
@@ -5188,7 +5291,7 @@ parameter_brace_expand_indir (name, var_is_special, quoted, quoted_dollar_atp, c
   char *temp, *t;
   WORD_DESC *w;
 
-  w = parameter_brace_expand_word (name, var_is_special, quoted);
+  w = parameter_brace_expand_word (name, var_is_special, quoted, PF_IGNUNBOUND);
   t = w->word;
   /* Have to dequote here if necessary */
   if (t)
@@ -5205,7 +5308,7 @@ parameter_brace_expand_indir (name, var_is_special, quoted, quoted_dollar_atp, c
   if (t == 0)
     return (WORD_DESC *)NULL;
 
-  w = parameter_brace_expand_word (t, SPECIAL_VAR(t, 0), quoted);
+  w = parameter_brace_expand_word (t, SPECIAL_VAR(t, 0), quoted, 0);
   free (t);
 
   return w;
@@ -6503,7 +6606,7 @@ parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_doll
            *contains_dollar_at = 1;
        }
       free (x);
-      free (xlist);
+      dispose_words (xlist);
       free (temp1);
       *indexp = sindex;
 
@@ -6556,7 +6659,7 @@ parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_doll
   if (want_indir)
     tdesc = parameter_brace_expand_indir (name + 1, var_is_special, quoted, quoted_dollar_atp, contains_dollar_at);
   else
-    tdesc = parameter_brace_expand_word (name, var_is_special, quoted);
+    tdesc = parameter_brace_expand_word (name, var_is_special, quoted, PF_IGNUNBOUND);
 
   if (tdesc)
     {
@@ -6664,13 +6767,13 @@ parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_doll
       return &expand_wdesc_error;
 
     case RBRACE:
-      if (var_is_set == 0 && unbound_vars_is_error)
+      if (var_is_set == 0 && unbound_vars_is_error && ((name[0] != '@' && name[0] != '*') || name[1]))
        {
+         last_command_exit_value = EXECUTION_FAILURE;
          err_unboundvar (name);
          FREE (value);
          FREE (temp);
          free (name);
-         last_command_exit_value = EXECUTION_FAILURE;
          return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
        }
       break;
@@ -6887,15 +6990,25 @@ param_expand (string, sindex, quoted, expanded_something,
     case '*':          /* `$*' */
       list = list_rest_of_args ();
 
-      if (list == 0 && unbound_vars_is_error)
+#if 0
+      /* According to austin-group posix proposal by Geoff Clare in
+        <20090505091501.GA10097@squonk.masqnet> of 5 May 2009:
+
+       "The shell shall write a message to standard error and
+        immediately exit when it tries to expand an unset parameter
+        other than the '@' and '*' special parameters."
+      */
+
+      if (list == 0 && unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0)
        {
          uerror[0] = '$';
          uerror[1] = '*';
          uerror[2] = '\0';
-         err_unboundvar (uerror);
          last_command_exit_value = EXECUTION_FAILURE;
+         err_unboundvar (uerror);
          return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
        }
+#endif
 
       /* If there are no command-line arguments, this should just
         disappear if there are other characters in the expansion,
@@ -6949,15 +7062,25 @@ param_expand (string, sindex, quoted, expanded_something,
     case '@':          /* `$@' */
       list = list_rest_of_args ();
 
-      if (list == 0 && unbound_vars_is_error)
+#if 0
+      /* According to austin-group posix proposal by Geoff Clare in
+        <20090505091501.GA10097@squonk.masqnet> of 5 May 2009:
+
+       "The shell shall write a message to standard error and
+        immediately exit when it tries to expand an unset parameter
+        other than the '@' and '*' special parameters."
+      */
+
+      if (list == 0 && unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0)
        {
          uerror[0] = '$';
          uerror[1] = '@';
          uerror[2] = '\0';
-         err_unboundvar (uerror);
          last_command_exit_value = EXECUTION_FAILURE;
+         err_unboundvar (uerror);
          return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
        }
+#endif
 
       /* We want to flag the fact that we saw this.  We can't turn
         off quoting entirely, because other characters in the
diff --git a/trap.c b/trap.c
index bfc96e71e088957e4864a444015666c57a34c5a3..940dcfdbccd5d9832c0778051b6391a52b540a7b 100644 (file)
--- a/trap.c
+++ b/trap.c
@@ -755,7 +755,7 @@ _run_trap_internal (sig, tag)
        }
 
       flags = SEVAL_NONINT|SEVAL_NOHIST;
-      if (sig != DEBUG_TRAP && sig != RETURN_TRAP)
+      if (sig != DEBUG_TRAP && sig != RETURN_TRAP && sig != ERROR_TRAP)
        flags |= SEVAL_RESETLINE;
       if (function_code == 0)
        parse_and_execute (trap_command, tag, flags);
@@ -798,12 +798,36 @@ int
 run_debug_trap ()
 {
   int trap_exit_value;
+  pid_t save_pgrp;
+  int save_pipe[2];
 
   /* XXX - question:  should the DEBUG trap inherit the RETURN trap? */
   trap_exit_value = 0;
   if ((sigmodes[DEBUG_TRAP] & SIG_TRAPPED) && ((sigmodes[DEBUG_TRAP] & SIG_IGNORED) == 0) && ((sigmodes[DEBUG_TRAP] & SIG_INPROGRESS) == 0))
     {
+#if defined (JOB_CONTROL)
+      save_pgrp = pipeline_pgrp;
+      pipeline_pgrp = 0;
+      save_pipeline (1);
+#  if defined (PGRP_PIPE)
+      save_pgrp_pipe (save_pipe, 1);
+#  endif
+      stop_making_children ();
+#endif
+
       trap_exit_value = _run_trap_internal (DEBUG_TRAP, "debug trap");
+
+#if defined (JOB_CONTROL)
+      pipeline_pgrp = save_pgrp;
+      restore_pipeline (1);
+#  if defined (PGRP_PIPE)
+      close_pgrp_pipe ();
+      restore_pgrp_pipe (save_pipe);
+#  endif
+      if (pipeline_pgrp > 0)
+       give_terminal_to (pipeline_pgrp, 1);
+      notify_and_cleanup ();
+#endif
       
 #if defined (DEBUGGER)
       /* If we're in the debugger and the DEBUG trap returns 2 while we're in
index 8920bad1dd398c43f2b33d7264a96efe94767971..657101bd5172f9cf3be18aaff41c44c7ccb78b75 100644 (file)
@@ -252,6 +252,7 @@ static SHELL_VAR **fapply __P((sh_var_map_func_t *));
 
 static int visible_var __P((SHELL_VAR *));
 static int visible_and_exported __P((SHELL_VAR *));
+static int export_environment_candidate __P((SHELL_VAR *));
 static int local_and_exported __P((SHELL_VAR *));
 static int variable_in_context __P((SHELL_VAR *));
 #if defined (ARRAY_VARS)
@@ -375,10 +376,17 @@ initialize_shell_variables (env, privmode)
        }
 #  endif
 #endif
+#if 0
       else if (legal_identifier (name))
+#else
+      else
+#endif
        {
          temp_var = bind_variable (name, string, 0);
-         VSETATTR (temp_var, (att_exported | att_imported));
+         if (legal_identifier (name))
+           VSETATTR (temp_var, (att_exported | att_imported));
+         else
+           VSETATTR (temp_var, (att_exported | att_imported | att_invisible));
          array_needs_making = 1;
        }
 
@@ -2209,7 +2217,7 @@ bind_variable_internal (name, value, table, hflags, aflags)
        }
       else if (assoc_p (entry))
        {
-         assoc_insert (assoc_cell (entry), "0", newval);
+         assoc_insert (assoc_cell (entry), savestring ("0"), newval);
          free (newval);
        }
       else
@@ -3082,6 +3090,16 @@ visible_and_exported (var)
   return (invisible_p (var) == 0 && exported_p (var));
 }
 
+/* Candidate variables for the export environment are either valid variables
+   with the export attribute or invalid variables inherited from the initial
+   environment and simply passed through. */
+static int
+export_environment_candidate (var)
+     SHELL_VAR *var;
+{
+  return (exported_p (var) && (invisible_p (var) == 0 || imported_p (var)));
+}
+
 /* Return non-zero if VAR is a local variable in the current context and
    is exported. */
 static int
@@ -3438,7 +3456,11 @@ make_var_export_array (vcxt)
   char **list;
   SHELL_VAR **vars;
 
+#if 0
   vars = map_over (visible_and_exported, vcxt);
+#else
+  vars = map_over (export_environment_candidate, vcxt);
+#endif
 
   if (vars == 0)
     return (char **)NULL;