]> git.ipfire.org Git - thirdparty/bash.git/commitdiff
commit bash-20040928 snapshot
authorChet Ramey <chet.ramey@case.edu>
Sat, 3 Dec 2011 18:37:34 +0000 (13:37 -0500)
committerChet Ramey <chet.ramey@case.edu>
Sat, 3 Dec 2011 18:37:34 +0000 (13:37 -0500)
18 files changed:
CWRU/CWRU.chlog~
MANIFEST
builtins/common.c~
command.h~
doc/bash.1~
doc/bashref.texi~
doc/version.texi~
execute_cmd.c~
general.h~
jobs.c~
lib/readline/complete.c~
subst.c~
subst.h~
tests/RUN-ONE-TEST
tests/run-tilde
variables.c~
variables.h~ [new file with mode: 0644]
wifcontinued-test.c [new file with mode: 0644]

index a65e1eaa9330c1c5dc4d7d78ccdd6d051ac5d88a..17f6c575d3228c45c450aafe32092618392f30fe 100644 (file)
@@ -10149,3 +10149,129 @@ subst.c
 execute_cmd.c
        - take out calls to bash_tilde_expand before calling word expansion
          functions
+
+                                  9/26
+                                  ----
+execute_cmd.c
+       - make sure to call UNBLOCK_CHILD before returning on a pipe creation
+         failure in execute_pipeline
+
+                                  9/27
+                                  ----
+variables.c
+       - change get_bash_command to deal with the_printed_command_except_trap
+         being NULL
+
+execute_cmd.c
+       - fix execute_simple_command to deal with the_printed_command being
+         NULL when assigning to the_printed_command_except_trap -- fixes
+         seg fault in savestring()
+
+parse.y
+       - change the parser so that the closing `)' in a compound variable
+         assignment delimits a token -- ksh93 does it this way
+
+doc/{bash.1,bashref.texi}
+       - change description of tilde expansion to note that expansion is
+         attempted only after the first =~ in an assignment statement
+
+builtins/declare.def
+       - when assigning to an array variable with declare -a x=(...), make
+         sure the last character in the rhs  of the variable assignment is
+         `)', not just that it appears somewhere
+
+                                  9/28
+                                  ----
+command.h
+       - add a `W_NOEXPAND' flag to inhibit all expansion except quote removal
+       - add a `W_COMPASSIGN' flag to denote a word is a compound assignment
+         statement
+
+parse.y
+       - set W_COMPASSIGN on words that appear to be compound assignments
+
+subst.c
+       - pass W_NOXPAND and W_COMPASSIGN through end of expand_word_internal
+
+subst.[ch]
+       - new function, expand_assignment_string_to_string, calls
+         expand_string_assignment and then string_list on the result
+
+variables.c
+       - assign_in_env now calls expand_assignment_string_to_string
+
+                                  9/30
+                                  ----
+builtins/common.c
+       - change get_job_spec so the null job `%' once again means the current
+         job
+
+                                  10/1
+                                  ----
+subst.c
+       - do_assignment_internal now takes a WORD_DESC * as its first
+         argument, and uses its `word' member as the assignment string
+       - change expand_word_list_internal to call do_word_assignment instead
+         of do_assignment, passing it `word' instead of, e.g., `word->word'
+       - change extract_array_assignment_list to just return the passed
+         string minus a trailing `)' if the last character is a right
+         paren
+       - change do_assignment_internal to call extract_array_assignment_list
+
+subst.[ch]
+       - change do_assignment and do_assignment_no_expand to take a `char *'
+         instead of `const char *' first argument; change extern prototypes
+       - new function, do_word_assignment, takes a WORD_DESC * and calls
+         do_assignment_internal on it; add extern declaration with prototype
+
+general.h
+       - new typedef, sh_wassign_func_t, like sh_assign_func_t but takes a
+         WORD_DESC * as its first argument
+
+variables.[ch]
+       - assign_in_env now takes a WORD_DESC * as its first argument
+
+                                  10/2
+                                  ----
+command.h
+       - new word flag, W_ASSNBLTIN, denotes that the word is a builtin
+         command (in a command position) that takes assignment statements
+         as arguments, like `declare'
+       - new word flags, W_ASSIGNARG, denotes that word is an assignment
+         statement given as argument to assignment builtin
+
+execute_cmd.c
+       - set W_ASSNBLTIN flag in fix_assignment_words if necessary (if there
+         are any arguments that are assignment statements)
+       - set W_ASSIGNARG flag in fix_assignment_words if necessary
+
+subst.c
+       - new function, do_compound_assignment, encapsulates the necessary
+         code to perform a compound array assignment (including creation of
+         local variables); called from do_assignment_internal
+       - to fix the double-expansion problem with compound array assignments
+         that are arguments to builtins like `declare', changed
+         shell_expand_word_list to treat those arguments like assignment
+         statements (with proper creation of local variables inside shell
+         functions) and pass the attribute-setting portion of the statement
+         onto the builtin.  This is what ksh93 appears to do, from inspection
+         of the `ksh93 -x' output
+
+execute_cmd.c
+       - fix execute_simple_command:  in case of pipeline or async command,
+         when forking early, set `subshell_environment' so that it can contain
+         both SUBSHELL_PIPE and SUBSHELL_ASYNC -- the two should not be
+         mutually exclusive.  Fixes bug reported by pierre.humblet@ieee.org
+       - remove references to last_pid, old_command_subst_pid; use NO_PID as
+         a sentinel value to decide whether or not a child process has been
+         created and needs to be waited for.  Submitted by
+         pierre.humblet@ieee.org to fix recycling-pid problem on cygwin
+
+doc/{bash.1,bashref.texi}
+       - fixed documentation of `@(pattern)' extended globbing operator --
+         it succeeds if the string matches one of the patterns, not exactly
+         one.  This is what ksh93 does, too
+
+lib/readline/complete.c
+       - fixed rl_menu_complete so that a negative argument cycles backwards
+         through the list
index 2985f5402517bc3e6754aa7619f71b9bee23a27d..398d522df6bfff5ad666e876e96cdf8a2426479c 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -731,8 +731,6 @@ tests/extglob.tests f
 tests/extglob.right    f
 tests/extglob2.tests   f
 tests/extglob2.right   f
-tests/extglob3.tests   f
-tests/extglob3.right   f
 tests/func.tests       f
 tests/func.right       f
 tests/func1.sub                f
@@ -842,7 +840,6 @@ tests/run-execscript        f
 tests/run-exp-tests    f
 tests/run-extglob      f
 tests/run-extglob2     f
-tests/run-extglob3     f
 tests/run-func         f
 tests/run-getopts      f
 tests/run-glob-test    f
@@ -876,7 +873,6 @@ tests/run-shopt             f
 tests/run-strip                f
 tests/run-test         f
 tests/run-tilde                f
-tests/run-tilde2       f
 tests/run-trap         f
 tests/run-type         f
 tests/run-varenv       f
@@ -890,10 +886,8 @@ tests/strip.tests  f
 tests/strip.right      f
 tests/test.tests       f
 tests/test.right       f
-tests/tilde.tests      f
+tests/tilde-tests      f
 tests/tilde.right      f
-tests/tilde2.tests     f
-tests/tilde2.right     f
 tests/trap.tests       f
 tests/trap.right       f
 tests/trap1.sub                f       755
index 3d3dd5947c4505ed6176443211b89ca3882ba064..8c2dde4a2f9a6a1c11c4417f9aff02f41714b97d 100644 (file)
@@ -270,6 +270,12 @@ sh_notbuiltin (s)
   builtin_error (_("%s: not a shell builtin"), s);
 }
 
+void
+sh_wrerror ()
+{
+  builtin_error (_("write error: %s"), strerror (errno));
+}
+
 /* **************************************************************** */
 /*                                                                 */
 /*          Shell positional parameter manipulation                */
index 83aeea0d7293161727605f5eeb7879cf5eeb69d3..dbdcd47aeaf4967779593a8c9e0efd3ddb0dabe2 100644 (file)
@@ -67,19 +67,23 @@ enum command_type { cm_for, cm_case, cm_while, cm_if, cm_simple, cm_select,
                    cm_arith, cm_cond, cm_arith_for, cm_subshell };
 
 /* Possible values for the `flags' field of a WORD_DESC. */
-#define W_HASDOLLAR    0x0001  /* Dollar sign present. */
-#define W_QUOTED       0x0002  /* Some form of quote character is present. */
-#define W_ASSIGNMENT   0x0004  /* This word is a variable assignment. */
-#define W_GLOBEXP      0x0008  /* This word is the result of a glob expansion. */
-#define W_NOSPLIT      0x0010  /* Do not perform word splitting on this word. */
-#define W_NOGLOB       0x0020  /* Do not perform globbing on this word. */
-#define W_NOSPLIT2     0x0040  /* Don't split word except for $@ expansion. */
-#define W_TILDEEXP     0x0080  /* Tilde expand this assignment word */
-#define W_DOLLARAT     0x0100  /* $@ and its special handling */
-#define W_DOLLARSTAR   0x0200  /* $* and its special handling */
-#define W_NOCOMSUB     0x0400  /* Don't perform command substitution on this word */
-#define W_ASSIGNRHS    0x0800  /* Word is rhs of an assignment statement */
-#define W_NOTILDE      0x1000  /* Don't perform tilde expansion on this word */
+#define W_HASDOLLAR    0x00001 /* Dollar sign present. */
+#define W_QUOTED       0x00002 /* Some form of quote character is present. */
+#define W_ASSIGNMENT   0x00004 /* This word is a variable assignment. */
+#define W_GLOBEXP      0x00008 /* This word is the result of a glob expansion. */
+#define W_NOSPLIT      0x00010 /* Do not perform word splitting on this word. */
+#define W_NOGLOB       0x00020 /* Do not perform globbing on this word. */
+#define W_NOSPLIT2     0x00040 /* Don't split word except for $@ expansion. */
+#define W_TILDEEXP     0x00080 /* Tilde expand this assignment word */
+#define W_DOLLARAT     0x00100 /* $@ and its special handling */
+#define W_DOLLARSTAR   0x00200 /* $* and its special handling */
+#define W_NOCOMSUB     0x00400 /* Don't perform command substitution on this word */
+#define W_ASSIGNRHS    0x00800 /* Word is rhs of an assignment statement */
+#define W_NOTILDE      0x01000 /* Don't perform tilde expansion on this word */
+#define W_ITILDE       0x02000 /* Internal flag for word expansion */
+#define W_NOEXPAND     0x04000 /* Don't expand at all -- do quote removal */
+#define W_COMPASSIGN   0x08000 /* Compound assignment */
+#define W_ASSNBLTIN    0x10000 /* word is a builtin command that takes assignments */
 
 /* Possible values for subshell_environment */
 #define SUBSHELL_ASYNC 0x01    /* subshell caused by `command &' */
index cf7a9d030788e3c350e3d61638509f855c1750fe..e95567fa68be5ce87eceb57a43c18ba556ff8448 100644 (file)
@@ -6,12 +6,12 @@
 .\"    Case Western Reserve University
 .\"    chet@po.CWRU.Edu
 .\"
-.\"    Last Change: Fri Sep 17 22:44:17 EDT 2004
+.\"    Last Change: Thu Sep 30 22:29:05 EDT 2004
 .\"
 .\" bash_builtins, strip all but Built-Ins section
 .if \n(zZ=1 .ig zZ
 .if \n(zY=1 .ig zY
-.TH BASH 1 "2004 Sep 17" "GNU Bash-3.0"
+.TH BASH 1 "2004 Sep 30" "GNU Bash-3.0"
 .\"
 .\" There's some problem with having a `@'
 .\" in a tagged paragraph with the BSD man macros.
@@ -2236,7 +2236,7 @@ is unchanged.
 Each variable assignment is checked for unquoted tilde-prefixes immediately
 following a
 .B :
-or
+or the first
 .BR = .
 In these cases, tilde expansion is also performed.
 Consequently, one may use file names with tildes in assignments to
@@ -4063,6 +4063,8 @@ command), the current job is always flagged with a
 .BR + ,
 and the previous job with a
 .BR \- .
+A single % (with no accompanying job specification) also refers to the
+current job.
 .PP
 Simply naming a job can be used to bring it into the
 foreground:
@@ -5285,7 +5287,7 @@ of an \fIinputrc\fP file.
 .TP
 .B dump\-macros
 Print all of the readline key sequences bound to macros and the
-strings they ouput.  If a numeric argument is supplied,
+strings they output.  If a numeric argument is supplied,
 the output is formatted in such a way that it can be made part
 of an \fIinputrc\fP file.
 .TP
index 5bfee31a9da091cbfc4d643828c434df43279845..1e0e446da474dda366a62187d478f30ba69358e7 100644 (file)
@@ -1456,7 +1456,7 @@ If the login name is invalid, or the tilde expansion fails, the word is
 left unchanged.
 
 Each variable assignment is checked for unquoted tilde-prefixes immediately
-following a @samp{:} or @samp{=}.
+following a @samp{:} or the first @samp{=}.
 In these cases, tilde expansion is also performed.
 Consequently, one may use file names with tildes in assignments to
 @env{PATH}, @env{MAILPATH}, and @env{CDPATH},
@@ -4787,7 +4787,7 @@ option).
 
 @item --dump-po-strings
 A list of all double-quoted strings preceded by @samp{$}
-is printed on the standard ouput
+is printed on the standard output
 in the @sc{gnu} @code{gettext} PO (portable object) file format.
 Equivalent to @option{-D} except for the output format.
 
@@ -4874,7 +4874,7 @@ when invoking an interactive shell.
 
 @item -D
 A list of all double-quoted strings preceded by @samp{$}
-is printed on the standard ouput.
+is printed on the standard output.
 These are the strings that
 are subject to language translation when the current locale
 is not @code{C} or @code{POSIX} (@pxref{Locale Translation}).
@@ -6118,11 +6118,12 @@ There are a number of ways to refer to a job in the shell.  The
 character @samp{%} introduces a job name.
 
 Job number @code{n} may be referred to as @samp{%n}.
-The symbols @samp{%%} and
-@samp{%+} refer to the shell's notion of the current job, which
-is the last job stopped while it was in the foreground or started
-in the background.  The
-previous job may be referenced using @samp{%-}.  In output
+The symbols @samp{%%} and  @samp{%+} refer to the shell's notion of the
+current job, which is the last job stopped while it was in the foreground
+or started in the background.
+A single @samp{%} (with no accompanying job specification) also refers
+to the current job.
+The previous job may be referenced using @samp{%-}.  In output
 pertaining to jobs (e.g., the output of the @code{jobs} command),
 the current job is always flagged with a @samp{+}, and the
 previous job with a @samp{-}. 
index 559af1e30e512fab239cbec7fb84f02bf6f19b44..9dd2c46a0cfba3f845944bba15102df09d7f3f33 100644 (file)
@@ -4,7 +4,7 @@ Copyright (C) 1988-2004 Free Software Foundation, Inc.
 
 @set EDITION 3.0
 @set VERSION 3.0
-@set UPDATED 11 September 2004
-@set UPDATED-MONTH September 2004
+@set UPDATED 2 October 2004
+@set UPDATED-MONTH October 2004
 
-@set LASTCHANGE Sat Sep 11 10:13:36 EDT 2004
+@set LASTCHANGE Sat Oct  2 18:05:41 EDT 2004
index 7873ec5eef67bebba8b03cffb000092c280e2b34..cea110aba04c8f3e03e05b6841769019c616386f 100644 (file)
@@ -1360,14 +1360,12 @@ execute_pipeline (command, asynchronous, pipe_in, pipe_out, fds_to_close)
 #if defined (JOB_CONTROL)
          terminate_current_pipeline ();
          kill_current_pipeline ();
+         UNBLOCK_CHILD (oset);
 #endif /* JOB_CONTROL */
          last_command_exit_value = EXECUTION_FAILURE;
          /* The unwind-protects installed below will take care
             of closing all of the open file descriptors. */
          throw_to_top_level ();
-#if defined (JOB_CONTROL)
-         UNBLOCK_CHILD (oset);
-#endif
          return (EXECUTION_FAILURE);   /* XXX */
        }
 
@@ -2663,8 +2661,10 @@ fix_assignment_words (words)
            b = builtin_address_internal (words->word->word, 0);
            if (b == 0 || (b->flags & ASSIGNMENT_BUILTIN) == 0)
              return;
+           else if (b && (b->flags & ASSIGNMENT_BUILTIN))
+             words->word->flags |= W_ASSNBLTIN;
          }
-       w->word->flags |= (W_NOSPLIT|W_NOGLOB|W_TILDEEXP);
+       w->word->flags |= (W_NOSPLIT|W_NOGLOB|W_TILDEEXP|W_ASSIGNARG);
       }
 }
 
@@ -2699,7 +2699,7 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close)
   if (this_command_name == 0 || (STREQ (this_command_name, "trap") == 0))
     {
       FREE (the_printed_command_except_trap);
-      the_printed_command_except_trap = savestring (the_printed_command);
+      the_printed_command_except_trap = the_printed_command ? savestring (the_printed_command) : (char *)0;
     }
 
   /* Run the debug trap before each simple command, but do it after we
@@ -2754,9 +2754,17 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close)
          already_forked = 1;
          simple_command->flags |= CMD_NO_FORK;
 
+#if 0
          subshell_environment = (pipe_in != NO_PIPE || pipe_out != NO_PIPE)
                                        ? (SUBSHELL_PIPE|SUBSHELL_FORK)
                                        : (SUBSHELL_ASYNC|SUBSHELL_FORK);
+#else
+         subshell_environment = SUBSHELL_FORK;
+         if (pipe_in != NO_PIPE || pipe_out != NO_PIPE)
+           subshell_environment |= SUBSHELL_PIPE;
+         if (async)
+           subshell_environment |= SUBSHELL_ASYNC;
+#endif
 
          /* We need to do this before piping to handle some really
             pathological cases where one of the pipe file descriptors
index c0eabd7537b728a44c56eab526acfaa5e1aea1ae..ce76e1633e5dfe43d0cbe382f2ce5e82d6c3acb6 100644 (file)
@@ -303,7 +303,6 @@ extern char *polite_directory_format __P((char *));
 extern char *extract_colon_unit __P((char *, int *));
 
 extern void tilde_initialize __P((void));
-extern int unquoted_tilde_word __P((const char *));
 extern char *bash_tilde_find_word __P((const char *, int, int *));
 extern char *bash_tilde_expand __P((const char *, int));
 
diff --git a/jobs.c~ b/jobs.c~
index c1b1c24187c1763be22245838faa9dd294ea7cbc..b89cf242762be60d0396968f91ec82550679bcb7 100644 (file)
--- a/jobs.c~
+++ b/jobs.c~
@@ -1433,7 +1433,9 @@ make_child (command, async_p)
 
       last_made_pid = pid;
 
-      /* Unblock SIGINT and SIGCHLD. */
+      /* Unblock SIGINT and SIGCHLD unless creating a pipeline, in which case
+        SIGCHLD remains blocked until all commands in the pipeline have been
+        created. */
       sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL);
     }
 
index f0149a3e273c785bb3ac706ccb19789b193e6f70..d7009e87426894349f239f4a02bfc9c36bf83172 100644 (file)
@@ -1543,7 +1543,7 @@ append_to_match (text, delimiter, quote_char, nontrivial_match)
                : stat (filename, &finfo);
       if (s == 0 && S_ISDIR (finfo.st_mode))
        {
-         if (_rl_complete_mark_directories && rl_completion_suppress_append == 0)
+         if (_rl_complete_mark_directories /* && rl_completion_suppress_append == 0 */)
            {
              /* This is clumsy.  Avoid putting in a double slash if point
                 is at the end of the line and the previous character is a
@@ -2178,9 +2178,17 @@ rl_menu_complete (count, ignore)
       return (0);
     }
 
+#if 0
   match_list_index = (match_list_index + count) % match_list_size;
   if (match_list_index < 0)
     match_list_index += match_list_size;
+#else
+  match_list_index += count;
+  if (match_list_index < 0)
+    match_list_index += match_list_size;
+  else
+    match_list_index %= match_list_size;
+#endif
 
   if (match_list_index == 0 && match_list_size > 1)
     {
index 49de9af70e32a90755065464c1faaa495e352294..9ba8aa6cdf6cf227371082220b323d7d81c24b52 100644 (file)
--- a/subst.c~
+++ b/subst.c~
@@ -204,7 +204,10 @@ static char *remove_quoted_nulls __P((char *));
 static int unquoted_substring __P((char *, char *));
 static int unquoted_member __P((int, char *));
 
-static int do_assignment_internal __P((const char *, int));
+#if defined (ARRAY_VARS)
+static SHELL_VAR *do_compound_assignment __P((char *, char *, int));
+#endif
+static int do_assignment_internal __P((const WORD_DESC *, int));
 
 static char *string_extract_verbatim __P((char *, int *, char *));
 static char *string_extract __P((char *, int *, char *, int));
@@ -983,12 +986,28 @@ extract_process_subst (string, starter, sindex)
 #endif /* PROCESS_SUBSTITUTION */
 
 #if defined (ARRAY_VARS)
+/* This can be fooled by unquoted right parens in the passed string. If
+   each caller verifies that the last character in STRING is a right paren,
+   we don't even need to call extract_delimited_string. */
 char *
 extract_array_assignment_list (string, sindex)
      char *string;
      int *sindex;
 {
+#if 0
   return (extract_delimited_string (string, sindex, "(", (char *)NULL, ")", 0));
+#else
+  int slen;
+  char *ret;
+
+  slen = strlen (string);      /* ( */
+  if (string[slen - 1] == ')')
+   {
+      ret = substring (string, *sindex, slen - 1);
+      *sindex = slen - 1;
+      return ret;
+    }
+#endif
 }
 #endif
 
@@ -2122,17 +2141,40 @@ list_string_with_quotes (string)
 /*                                                     */
 /********************************************************/
 
+#if defined (ARRAY_VARS)
+static SHELL_VAR *
+do_compound_assignment (name, value, mklocal)
+     char *name, *value;
+     int mklocal;
+{
+  SHELL_VAR *v;
+  int off;
+
+  if (mklocal && variable_context)
+    {
+      v = find_variable (name);
+      if (v == 0 || array_p (v) == 0)
+        v = make_local_array_variable (name);
+      v = assign_array_var_from_string (v, value);
+    }
+  else
+    v = assign_array_from_string (name, value);
+
+  return (v);
+}
+#endif
+
 /* Given STRING, an assignment string, get the value of the right side
    of the `=', and bind it to the left side.  If EXPAND is true, then
    perform parameter expansion, command substitution, and arithmetic
    expansion on the right-hand side.  Perform tilde expansion in any
    case.  Do not perform word splitting on the result of expansion. */
 static int
-do_assignment_internal (string, expand)
-     const char *string;
+do_assignment_internal (word, expand)
+     const WORD_DESC *word;
      int expand;
 {
-  int offset;
+  int offset, tlen;
   char *name, *value;
   SHELL_VAR *entry;
 #if defined (ARRAY_VARS)
@@ -2140,7 +2182,12 @@ do_assignment_internal (string, expand)
   int ni;
 #endif
   int assign_list = 0;
+  const char *string;
 
+  if (word == 0 || word->word == 0)
+    return 0;
+
+  string = word->word;
   offset = assignment (string, 0);
   name = savestring (string);
   value = (char *)NULL;
@@ -2151,17 +2198,17 @@ do_assignment_internal (string, expand)
 
       name[offset] = 0;
       temp = name + offset + 1;
+      tlen = STRLEN (temp);
 
 #if defined (ARRAY_VARS)
-      if (expand && temp[0] == LPAREN && xstrchr (temp, RPAREN))
+      if (expand && temp[0] == LPAREN && temp[tlen-1] == RPAREN)
        {
          assign_list = ni = 1;
-         value = extract_delimited_string (temp, &ni, "(", (char *)NULL, ")", 0);
+         value = extract_array_assignment_list (temp, &ni);
        }
       else
 #endif
 
-      /* Perform tilde expansion. */
       if (expand && temp[0])
        value = expand_string_if_necessary (temp, 0, expand_string_assignment);
       else
@@ -2192,7 +2239,7 @@ do_assignment_internal (string, expand)
        ASSIGN_RETURN (0);
     }
   else if (assign_list)
-    entry = assign_array_from_string (name, value);
+    entry = do_compound_assignment (name, value, (word->flags & W_ASSIGNARG));
   else
 #endif /* ARRAY_VARS */
   entry = bind_variable (name, value);
@@ -2207,22 +2254,39 @@ do_assignment_internal (string, expand)
 }
 
 /* Perform the assignment statement in STRING, and expand the
-   right side by doing command and parameter expansion. */
+   right side by doing tilde, command and parameter expansion. */
 int
 do_assignment (string)
-     const char *string;
+     char *string;
+{
+  WORD_DESC td;
+
+  td.flags = W_ASSIGNMENT;
+  td.word = string;
+
+  return do_assignment_internal (&td, 1);
+}
+
+int
+do_word_assignment (word)
+     WORD_DESC *word;
 {
-  return do_assignment_internal (string, 1);
+  return do_assignment_internal (word, 1);
 }
 
 /* Given STRING, an assignment string, get the value of the right side
-   of the `=', and bind it to the left side.  Do not do command and
-   parameter substitution on the right hand side. */
+   of the `=', and bind it to the left side.  Do not perform any word
+   expansions on the right hand side. */
 int
 do_assignment_no_expand (string)
-     const char *string;
+     char *string;
 {
-  return do_assignment_internal (string, 0);
+  WORD_DESC td;
+
+  td.flags = W_ASSIGNMENT;
+  td.word = string;
+
+  do_assignment_internal (&td, 0);
 }
 
 /***************************************************
@@ -2445,6 +2509,14 @@ expand_string_unsplit_to_string (string, quoted)
   return (expand_string_to_string_internal (string, quoted, expand_string_unsplit));
 }
 
+char *
+expand_assignment_string_to_string (string, quoted)
+     char *string;
+     int quoted;
+{
+  return (expand_string_to_string_internal (string, quoted, expand_string_assignment));
+}
+
 #if defined (COND_COMMAND)
 /* Just remove backslashes in STRING.  Returns a new string. */
 char *
@@ -6430,8 +6502,8 @@ add_string:
          if (word->flags & W_NOTILDE)
            goto add_character;
          if ((word->flags & (W_ASSIGNMENT|W_ASSIGNRHS)) &&
-                  (posixly_correct == 0 || (word->flags & W_TILDEEXP)) &&
-                  string[sindex+1] == '~')
+             (posixly_correct == 0 || (word->flags & W_TILDEEXP)) &&
+             string[sindex+1] == '~')
            word->flags |= W_ITILDE;
          goto add_character;
 
@@ -6845,8 +6917,12 @@ finished_with_string:
       list = make_word_list (tword, (WORD_LIST *)NULL);
       if (word->flags & W_ASSIGNMENT)
        tword->flags |= W_ASSIGNMENT;   /* XXX */
+      if (word->flags & W_COMPASSIGN)
+       tword->flags |= W_COMPASSIGN;   /* XXX */
       if (word->flags & W_NOGLOB)
        tword->flags |= W_NOGLOB;       /* XXX */
+      if (word->flags & W_NOEXPAND)
+       tword->flags |= W_NOEXPAND;     /* XXX */
       if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
        tword->flags |= W_QUOTED;
     }
@@ -6872,8 +6948,12 @@ finished_with_string:
            tword->flags |= W_QUOTED;
          if (word->flags & W_ASSIGNMENT)
            tword->flags |= W_ASSIGNMENT;
+         if (word->flags & W_COMPASSIGN)
+           tword->flags |= W_COMPASSIGN;
          if (word->flags & W_NOGLOB)
            tword->flags |= W_NOGLOB;
+         if (word->flags & W_NOEXPAND)
+           tword->flags |= W_NOEXPAND;
        }
     }
 
@@ -7435,6 +7515,31 @@ shell_expand_word_list (tlist, eflags)
 
       next = tlist->next;
 
+#if defined (ARRAY_VARS)
+      /* If this is a compound array assignment to a builtin that accepts
+         such assignments (e.g., `declare'), take the assignment and perform
+         it separately, handling the semantics of declarations inside shell
+         functions.  This avoids the double-evaluation of such arguments,
+         because `declare' does some evaluation of compound assignments on
+         its own. */
+      if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG))
+       {
+         int t;
+
+         t = do_word_assignment (tlist->word);
+         if (t == 0)
+           {
+             last_command_exit_value = EXECUTION_FAILURE;
+             exp_jump_to_top_level (DISCARD);
+           }
+
+         /* Now transform the word as ksh93 appears to do and go on */
+         t = assignment (tlist->word->word, 0);
+         tlist->word->word[t] = '\0';
+         tlist->word->flags &= ~(W_ASSIGNMENT|W_NOSPLIT|W_COMPASSIGN|W_ASSIGNARG); 
+       }
+#endif
+
       expanded_something = 0;
       expanded = expand_word_internal
        (tlist->word, 0, 0, &has_dollar_at, &expanded_something);
@@ -7521,7 +7626,7 @@ expand_word_list_internal (list, eflags)
              for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next)
                {
                  this_command_name = (char *)NULL;     /* no arithmetic errors */
-                 tint = do_assignment (temp_list->word->word);
+                 tint = do_word_assignment (temp_list->word);
                  /* Variable assignment errors in non-interactive shells
                     running in Posix.2 mode cause the shell to exit. */
                  if (tint == 0)
@@ -7569,23 +7674,23 @@ expand_word_list_internal (list, eflags)
 
   if ((eflags & WEXP_VARASSIGN) && subst_assign_varlist)
     {
-      sh_assign_func_t *assign_func;
+      sh_wassign_func_t *assign_func;
 
       /* If the remainder of the words expand to nothing, Posix.2 requires
         that the variable and environment assignments affect the shell's
         environment. */
-      assign_func = new_list ? assign_in_env : do_assignment;
+      assign_func = new_list ? assign_in_env : do_word_assignment;
       tempenv_assign_error = 0;
 
       for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next)
        {
          this_command_name = (char *)NULL;
-         tint = (*assign_func) (temp_list->word->word);
+         tint = (*assign_func) (temp_list->word);
          /* Variable assignment errors in non-interactive shells running
             in Posix.2 mode cause the shell to exit. */
          if (tint == 0)
            {
-             if (assign_func == do_assignment)
+             if (assign_func == do_word_assignment)
                {
                  last_command_exit_value = EXECUTION_FAILURE;
                  if (interactive_shell == 0 && posixly_correct)
index c725df501de438ea2221f2b853b4d6bf28e910b1..350e82aa7088d92d8b13fccf480401232a47f708 100644 (file)
--- a/subst.h~
+++ b/subst.h~
@@ -93,11 +93,11 @@ extern char *strip_trailing_ifs_whitespace __P((char *, char *, int));
 
 /* Given STRING, an assignment string, get the value of the right side
    of the `=', and bind it to the left side.  If EXPAND is true, then
-   perform parameter expansion, command substitution, and arithmetic
-   expansion on the right-hand side.  Perform tilde expansion in any
-   case.  Do not perform word splitting on the result of expansion. */
-extern int do_assignment __P((const char *));
-extern int do_assignment_no_expand __P((const char *));
+   perform tilde expansion, parameter expansion, command substitution,
+   and arithmetic expansion on the right-hand side.  Do not perform word
+   splitting on the result of expansion. */
+extern int do_assignment __P((char *));
+extern int do_assignment_no_expand __P((char *));
 
 /* Append SOURCE to TARGET at INDEX.  SIZE is the current amount
    of space allocated to TARGET.  SOURCE can be NULL, in which
@@ -126,6 +126,9 @@ extern int number_of_args __P((void));
    takes care of quote removal. */
 extern WORD_LIST *expand_string_unsplit __P((char *, int));
 
+/* Expand the rhs of an assignment statement. */
+extern WORD_LIST *expand_string_assignment __P((char *, int));
+
 /* Expand a prompt string. */
 extern WORD_LIST *expand_prompt_string __P((char *, int));
 
@@ -141,6 +144,7 @@ extern WORD_LIST *expand_string __P((char *, int));
    to a string and deallocating the WORD_LIST *. */
 extern char *expand_string_to_string __P((char *, int));
 extern char *expand_string_unsplit_to_string __P((char *, int));
+extern char *expand_assignment_string_to_string __P((char *, int));
 
 /* De-quoted quoted characters in STRING. */
 extern char *dequote_string __P((char *));
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 b8569c11cd60a3b820a9275628467a3b0d15de61..ecb7e9a2539900a4a8e5a1b926a27484a07fdefd 100644 (file)
@@ -1,2 +1,2 @@
-${THIS_SH} ./tilde.tests > /tmp/xx
+${THIS_SH} ./tilde-tests > /tmp/xx
 diff /tmp/xx tilde.right && rm -f /tmp/xx
index 75f16cd9f85255435ca6a2dc8eb63b50e06f5bb6..cdf1a195b98750a1da047d500dc06393d0d7f4de 100644 (file)
@@ -1228,7 +1228,14 @@ get_bash_command (var)
 {
   char *p;
 
-  p = savestring (the_printed_command_except_trap);
+  
+  if (the_printed_command_except_trap)
+    p = savestring (the_printed_command_except_trap);
+  else
+    {
+      p = (char *)xmalloc (1);
+      p[0] = '\0';
+    }
   FREE (value_cell (var));
   var_setvalue (var, p);
   return (var);
@@ -1419,11 +1426,11 @@ initialize_dynamic_variables ()
   v = init_dynamic_array_var ("GROUPS", get_groupset, null_array_assign, att_noassign);
 
 #  if defined (DEBUGGER)
-  v = init_dynamic_array_var ("BASH_ARGC", get_self, null_array_assign, (att_invisible|att_noassign));
-  v = init_dynamic_array_var ("BASH_ARGV", get_self, null_array_assign, (att_invisible|att_noassign));
+  v = init_dynamic_array_var ("BASH_ARGC", get_self, null_array_assign, att_noassign|att_nounset);
+  v = init_dynamic_array_var ("BASH_ARGV", get_self, null_array_assign, att_noassign|att_nounset);
 #  endif /* DEBUGGER */
-  v = init_dynamic_array_var ("BASH_SOURCE", get_self, null_array_assign, (att_invisible|att_noassign));
-  v = init_dynamic_array_var ("BASH_LINENO", get_self, null_array_assign, (att_invisible|att_noassign));
+  v = init_dynamic_array_var ("BASH_SOURCE", get_self, null_array_assign, att_noassign|att_nounset);
+  v = init_dynamic_array_var ("BASH_LINENO", get_self, null_array_assign, att_noassign|att_nounset);
 #endif
 
   v = init_funcname_var ();
@@ -1599,7 +1606,10 @@ make_local_variable (name)
   /* local foo; local foo;  is a no-op. */
   old_var = find_variable (name);
   if (old_var && local_p (old_var) && old_var->context == variable_context)
-    return (old_var);
+    {
+      VUNSETATTR (old_var, att_invisible);
+      return (old_var);
+    }
 
   was_tmpvar = old_var && tempvar_p (old_var);
   if (was_tmpvar)
@@ -2064,12 +2074,15 @@ bind_function_def (name, value)
    responsible for moving the main temporary env to one of the other
    temporary environments.  The expansion code in subst.c calls this. */
 int
-assign_in_env (string)
-     const char *string;
+assign_in_env (word)
+     WORD_DESC *word;
 {
   int offset;
   char *name, *temp, *value;
   SHELL_VAR *var;
+  const char *string;
+
+  string = word->word;
 
   offset = assignment (string, 0);
   name = savestring (string);
@@ -2089,10 +2102,13 @@ assign_in_env (string)
        }
 
       temp = name + offset + 1;
+#if 0
       temp = (xstrchr (temp, '~') != 0) ? bash_tilde_expand (temp, 1) : savestring (temp);
-
       value = expand_string_unsplit_to_string (temp, 0);
       free (temp);
+#else
+      value = expand_assignment_string_to_string (temp, 0);
+#endif
     }
 
   if (temporary_env == 0)
diff --git a/variables.h~ b/variables.h~
new file mode 100644 (file)
index 0000000..cd11fd9
--- /dev/null
@@ -0,0 +1,359 @@
+/* variables.h -- data structures for shell variables. */
+
+/* Copyright (C) 1987-2002 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 (_VARIABLES_H_)
+#define _VARIABLES_H_
+
+#include "stdc.h"
+#include "array.h"
+
+/* Shell variables and functions are stored in hash tables. */
+#include "hashlib.h"
+
+#include "conftypes.h"
+
+/* A variable context. */
+typedef struct var_context {
+  char *name;          /* empty or NULL means global context */
+  int scope;           /* 0 means global context */
+  int flags;
+  struct var_context *up;      /* previous function calls */
+  struct var_context *down;    /* down towards global context */
+  HASH_TABLE *table;           /* variables at this scope */
+} VAR_CONTEXT;
+
+/* Flags for var_context->flags */
+#define VC_HASLOCAL    0x01
+#define VC_HASTMPVAR   0x02
+#define VC_FUNCENV     0x04    /* also function if name != NULL */
+#define VC_BLTNENV     0x08    /* builtin_env */
+#define VC_TEMPENV     0x10    /* temporary_env */
+
+#define VC_TEMPFLAGS   (VC_FUNCENV|VC_BLTNENV|VC_TEMPENV)
+
+/* Accessing macros */
+#define vc_isfuncenv(vc)       (((vc)->flags & VC_FUNCENV) != 0)
+#define vc_isbltnenv(vc)       (((vc)->flags & VC_BLTNENV) != 0)
+#define vc_istempenv(vc)       (((vc)->flags & (VC_TEMPFLAGS)) == VC_TEMPENV)
+
+#define vc_istempscope(vc)     (((vc)->flags & (VC_TEMPENV|VC_BLTNENV)) != 0)
+
+#define vc_haslocals(vc)       (((vc)->flags & VC_HASLOCAL) != 0)
+#define vc_hastmpvars(vc)      (((vc)->flags & VC_HASTMPVAR) != 0)
+
+/* What a shell variable looks like. */
+
+typedef struct variable *sh_var_value_func_t __P((struct variable *));
+typedef struct variable *sh_var_assign_func_t __P((struct variable *, char *, arrayind_t));
+
+/* For the future */
+union _value {
+  char *s;                     /* string value */
+  intmax_t i;                  /* int value */
+  COMMAND *f;                  /* function */
+  ARRAY *a;                    /* array */
+  HASH_TABLE *h;               /* associative array */
+  double d;                    /* floating point number */
+#if defined (HAVE_LONG_DOUBLE)
+  long double ld;              /* long double */
+#endif
+  struct variable *v;          /* possible indirect variable use */
+  void *opaque;                        /* opaque data for future use */
+};
+
+typedef struct variable {
+  char *name;                  /* Symbol that the user types. */
+  char *value;                 /* Value that is returned. */
+  char *exportstr;             /* String for the environment. */
+  sh_var_value_func_t *dynamic_value;  /* Function called to return a `dynamic'
+                                  value for a variable, like $SECONDS
+                                  or $RANDOM. */
+  sh_var_assign_func_t *assign_func; /* Function called when this `special
+                                  variable' is assigned a value in
+                                  bind_variable. */
+  int attributes;              /* export, readonly, array, invisible... */
+  int context;                 /* Which context this variable belongs to. */
+} SHELL_VAR;
+
+typedef struct _vlist {
+  SHELL_VAR **list;
+  int list_size;       /* allocated size */
+  int list_len;                /* current number of entries */
+} VARLIST;
+
+/* The various attributes that a given variable can have. */
+/* First, the user-visible attributes */
+#define att_exported   0x0000001       /* export to environment */
+#define att_readonly   0x0000002       /* cannot change */
+#define att_array      0x0000004       /* value is an array */
+#define att_function   0x0000008       /* value is a function */
+#define att_integer    0x0000010       /* internal representation is int */
+#define att_local      0x0000020       /* variable is local to a function */
+#define att_assoc      0x0000040       /* variable is an associative array */
+#define att_trace      0x0000080       /* function is traced with DEBUG trap */
+
+#define attmask_user   0x0000fff
+
+/* Internal attributes used for bookkeeping */
+#define att_invisible  0x0001000       /* cannot see */
+#define att_nounset    0x0002000       /* cannot unset */
+#define att_noassign   0x0004000       /* assignment not allowed */
+#define att_imported   0x0008000       /* came from environment */
+#define att_special    0x0010000       /* requires special handling */
+
+#define        attmask_int     0x00ff000
+
+/* Internal attributes used for variable scoping. */
+#define att_tempvar    0x0100000       /* variable came from the temp environment */
+#define att_propagate  0x0200000       /* propagate to previous scope */
+
+#define attmask_scope  0x0f00000
+
+#define exported_p(var)                ((((var)->attributes) & (att_exported)))
+#define readonly_p(var)                ((((var)->attributes) & (att_readonly)))
+#define array_p(var)           ((((var)->attributes) & (att_array)))
+#define function_p(var)                ((((var)->attributes) & (att_function)))
+#define integer_p(var)         ((((var)->attributes) & (att_integer)))
+#define local_p(var)           ((((var)->attributes) & (att_local)))
+#define assoc_p(var)           ((((var)->attributes) & (att_assoc)))
+#define trace_p(var)           ((((var)->attributes) & (att_trace)))
+
+#define invisible_p(var)       ((((var)->attributes) & (att_invisible)))
+#define non_unsettable_p(var)  ((((var)->attributes) & (att_nounset)))
+#define noassign_p(var)                ((((var)->attributes) & (att_noassign)))
+#define imported_p(var)                ((((var)->attributes) & (att_imported)))
+#define specialvar_p(var)      ((((var)->attributes) & (att_special)))
+
+#define tempvar_p(var)         ((((var)->attributes) & (att_tempvar)))
+
+/* Acessing variable values: rvalues */
+#define value_cell(var)                ((var)->value)
+#define function_cell(var)     (COMMAND *)((var)->value)
+#define array_cell(var)                (ARRAY *)((var)->value)
+
+#define var_isnull(var)                ((var)->value == 0)
+#define var_isset(var)         ((var)->value != 0)
+
+/* Assigning variable values: lvalues */
+#define var_setvalue(var, str) ((var)->value = (str))
+#define var_setfunc(var, func) ((var)->value = (char *)(func))
+#define var_setarray(var, arr) ((var)->value = (char *)(arr))
+
+/* Make VAR be auto-exported. */
+#define set_auto_export(var) \
+  do { (var)->attributes |= att_exported; array_needs_making = 1; } while (0)
+
+#define SETVARATTR(var, attr, undo) \
+       ((undo == 0) ? ((var)->attributes |= (attr)) \
+                    : ((var)->attributes &= ~(attr)))
+
+#define VSETATTR(var, attr)    ((var)->attributes |= (attr))
+#define VUNSETATTR(var, attr)  ((var)->attributes &= ~(attr))
+
+#define VGETFLAGS(var)         ((var)->attributes)
+
+#define VSETFLAGS(var, flags)  ((var)->attributes = (flags))
+#define VCLRFLAGS(var)         ((var)->attributes = 0)
+
+/* Macros to perform various operations on `exportstr' member of a SHELL_VAR. */
+#define CLEAR_EXPORTSTR(var)   (var)->exportstr = (char *)NULL
+#define COPY_EXPORTSTR(var)    ((var)->exportstr) ? savestring ((var)->exportstr) : (char *)NULL
+#define SET_EXPORTSTR(var, value)  (var)->exportstr = (value)
+#define SAVE_EXPORTSTR(var, value) (var)->exportstr = (value) ? savestring (value) : (char *)NULL
+
+#define FREE_EXPORTSTR(var) \
+       do { if ((var)->exportstr) free ((var)->exportstr); } while (0)
+
+#define CACHE_IMPORTSTR(var, value) \
+       (var)->exportstr = savestring (value)
+
+#define INVALIDATE_EXPORTSTR(var) \
+       do { \
+         if ((var)->exportstr) \
+           { \
+             free ((var)->exportstr); \
+             (var)->exportstr = (char *)NULL; \
+           } \
+       } while (0)
+       
+/* Stuff for hacking variables. */
+typedef int sh_var_map_func_t __P((SHELL_VAR *));
+
+/* Where we keep the variables and functions */
+extern VAR_CONTEXT *global_variables;
+extern VAR_CONTEXT *shell_variables;
+
+extern HASH_TABLE *shell_functions;
+extern HASH_TABLE *temporary_env;
+
+extern int variable_context;
+extern char *dollar_vars[];
+extern char **export_env;
+
+extern void initialize_shell_variables __P((char **, int));
+extern SHELL_VAR *set_if_not __P((char *, char *));
+
+extern void sh_set_lines_and_columns __P((int, int));
+extern void set_pwd __P((void));
+extern void set_ppid __P((void));
+extern void make_funcname_visible __P((int));
+
+extern SHELL_VAR *var_lookup __P((const char *, VAR_CONTEXT *));
+
+extern SHELL_VAR *find_function __P((const char *));
+extern FUNCTION_DEF *find_function_def __P((const char *));
+extern SHELL_VAR *find_variable __P((const char *));
+extern SHELL_VAR *find_variable_internal __P((const char *, int));
+extern SHELL_VAR *find_tempenv_variable __P((const char *));
+extern SHELL_VAR *copy_variable __P((SHELL_VAR *));
+extern SHELL_VAR *make_local_variable __P((const char *));
+extern SHELL_VAR *bind_variable __P((const char *, char *));
+extern SHELL_VAR *bind_function __P((const char *, COMMAND *));
+
+extern void bind_function_def __P((const char *, FUNCTION_DEF *));
+
+extern SHELL_VAR **map_over __P((sh_var_map_func_t *, VAR_CONTEXT *));
+SHELL_VAR **map_over_funcs __P((sh_var_map_func_t *));
+     
+extern SHELL_VAR **all_shell_variables __P((void));
+extern SHELL_VAR **all_shell_functions __P((void));
+extern SHELL_VAR **all_visible_variables __P((void));
+extern SHELL_VAR **all_visible_functions __P((void));
+extern SHELL_VAR **all_exported_variables __P((void));
+extern SHELL_VAR **local_exported_variables __P((void));
+extern SHELL_VAR **all_local_variables __P((void));
+#if defined (ARRAY_VARS)
+extern SHELL_VAR **all_array_variables __P((void));
+#endif
+extern char **all_variables_matching_prefix __P((const char *));
+
+extern char **make_var_array __P((HASH_TABLE *));
+extern char **add_or_supercede_exported_var __P((char *, int));
+
+extern char *get_variable_value __P((SHELL_VAR *));
+extern char *get_string_value __P((const char *));
+extern char *sh_get_env_value __P((const char *));
+extern char *make_variable_value __P((SHELL_VAR *, char *));
+
+extern SHELL_VAR *bind_variable_value __P((SHELL_VAR *, char *));
+extern SHELL_VAR *bind_int_variable __P((char *, char *));
+extern SHELL_VAR *bind_var_to_int __P((char *, intmax_t));
+
+extern int assign_in_env __P((const char *));
+extern int unbind_variable __P((const char *));
+extern int unbind_func __P((const char *));
+extern int unbind_function_def __P((const char *));
+extern int makunbound __P((const char *, VAR_CONTEXT *));
+extern int kill_local_variable __P((const char *));
+extern void delete_all_variables __P((HASH_TABLE *));
+extern void delete_all_contexts __P((VAR_CONTEXT *));
+
+extern VAR_CONTEXT *new_var_context __P((char *, int));
+extern void dispose_var_context __P((VAR_CONTEXT *));
+extern VAR_CONTEXT *push_var_context __P((char *, int, HASH_TABLE *));
+extern void pop_var_context __P((void));
+extern VAR_CONTEXT *push_scope __P((int, HASH_TABLE *));
+extern void pop_scope __P((int));
+
+extern void push_context __P((char *, int, HASH_TABLE *));
+extern void pop_context __P((void));
+extern void push_dollar_vars __P((void));
+extern void pop_dollar_vars __P((void));
+extern void dispose_saved_dollar_vars __P((void));
+
+extern void push_args __P((WORD_LIST *));
+extern void pop_args __P((void));
+
+extern void adjust_shell_level __P((int));
+extern void non_unsettable __P((char *));
+extern void dispose_variable __P((SHELL_VAR *));
+extern void dispose_used_env_vars __P((void));
+extern void dispose_function_env __P((void));
+extern void dispose_builtin_env __P((void));
+extern void merge_temporary_env __P((void));
+extern void merge_builtin_env __P((void));
+extern void kill_all_local_variables __P((void));
+
+extern void set_var_read_only __P((char *));
+extern void set_func_read_only __P((const char *));
+extern void set_var_auto_export __P((char *));
+extern void set_func_auto_export __P((const char *));
+
+extern void sort_variables __P((SHELL_VAR **));
+
+extern void maybe_make_export_env __P((void));
+extern void update_export_env_inplace __P((char *, int, char *));
+extern void put_command_name_into_env __P((char *));
+extern void put_gnu_argv_flags_into_env __P((intmax_t, char *));
+
+extern void print_var_list __P((SHELL_VAR **));
+extern void print_func_list __P((SHELL_VAR **));
+extern void print_assignment __P((SHELL_VAR *));
+extern void print_var_value __P((SHELL_VAR *, int));
+extern void print_var_function __P((SHELL_VAR *));
+
+#if defined (ARRAY_VARS)
+extern SHELL_VAR *make_new_array_variable __P((char *));
+extern SHELL_VAR *make_local_array_variable __P((char *));
+
+extern void set_pipestatus_array __P((int *, int));
+#endif
+
+extern void set_pipestatus_from_exit __P((int));
+
+/* The variable in NAME has just had its state changed.  Check to see if it
+   is one of the special ones where something special happens. */
+extern void stupidly_hack_special_variables __P((char *));
+
+extern int get_random_number __P((void));
+
+/* The `special variable' functions that get called when a particular
+   variable is set. */
+extern void sv_ifs __P((char *));
+extern void sv_path __P((char *));
+extern void sv_mail __P((char *));
+extern void sv_globignore __P((char *));
+extern void sv_ignoreeof __P((char *));
+extern void sv_strict_posix __P((char *));
+extern void sv_optind __P((char *));
+extern void sv_opterr __P((char *));
+extern void sv_locale __P((char *));
+
+#if defined (READLINE)
+extern void sv_comp_wordbreaks __P((char *));
+extern void sv_terminal __P((char *));
+extern void sv_hostfile __P((char *));
+#endif
+
+#if defined (HAVE_TZSET) && defined (PROMPT_STRING_DECODE)
+extern void sv_tz __P((char *));
+#endif
+
+#if defined (HISTORY)
+extern void sv_histsize __P((char *));
+extern void sv_histignore __P((char *));
+extern void sv_history_control __P((char *));
+#  if defined (BANG_HISTORY)
+extern void sv_histchars __P((char *));
+#  endif
+extern void sv_histtimefmt __P((char *));
+#endif /* HISTORY */
+
+#endif /* !_VARIABLES_H_ */
diff --git a/wifcontinued-test.c b/wifcontinued-test.c
new file mode 100644 (file)
index 0000000..4c2c6e0
--- /dev/null
@@ -0,0 +1,18 @@
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <errno.h>
+
+#ifndef errno
+extern int errno;
+#endif
+main()
+{
+       int     x;
+
+       x = waitpid(-1, (int *)0, WNOHANG|WCONTINUED);
+       if (x == -1 && errno == ECHILD)
+               exit (0);
+       else
+               exit (1);
+}