]> git.ipfire.org Git - thirdparty/bash.git/commitdiff
commit bash-20090903 snapshot
authorChet Ramey <chet.ramey@case.edu>
Fri, 9 Dec 2011 01:15:12 +0000 (20:15 -0500)
committerChet Ramey <chet.ramey@case.edu>
Fri, 9 Dec 2011 01:15:12 +0000 (20:15 -0500)
38 files changed:
CWRU/CWRU.chlog
CWRU/CWRU.chlog~
MANIFEST
NOTES
arrayfunc.c
arrayfunc.c~
bashline.c
bashline.c~
builtins/mapfile.def
builtins/mapfile.def~
builtins/printf.def
doc/bash.1
general.c
general.c~
lib/glob/glob.c
lib/glob/glob.c~
lib/readline/bind.c
lib/readline/doc/readline.3
lib/readline/doc/rluser.texi
lib/readline/doc/version.texi
lib/readline/histexpand.c
lib/readline/readline.c
lib/readline/rlprivate.h
lib/readline/signals.c
lib/readline/text.c
lib/readline/text.c~
lib/readline/undo.c
lib/readline/undo.c~ [new file with mode: 0644]
lib/sh/uconvert.c
lib/sh/uconvert.c~ [new file with mode: 0644]
patchlevel.h
subst.c
subst.c~
tests/nquote.right
tests/nquote.tests
tests/nquote1.sub [new file with mode: 0644]
variables.c
variables.c~

index 629780b8ede35bea75326aa78465ef819e5f409b..e55ecd83c0a926a55d26b081e94c80273c9df93e 100644 (file)
@@ -8702,3 +8702,68 @@ subst.c
 execute_cmd.c
        - add fflush(stdout) and fflush(stderr) to child coproc code before
          calling exit after execute_in_subshell
+
+                                  8/31
+                                  ----
+lib/readline/{{bind,readline}.c,rlprivate.h}
+       - new bindable variable, "echo-control-characters", enabled by default.
+         This controls whether or not readline honors the tty ECHOCTL bit
+         and displays characters corresponding to keyboard-generated signals.
+         Controlled by _rl_echo_control_chars variable, declared in readline.c
+
+lib/readline/signals.c
+       - if _rl_echo_control_chars == 0, don't go through _rl_echo_signal_char
+
+
+lib/readline/doc/{readline.3,rluser.texi}
+       - document "echo-control-characters" bindable variable
+
+                                   9/1
+                                   ---
+lib/readline/histexpand.c
+       - hist_string_extract_single_quoted now takes an additional argument:
+         a flags word.  The only defined value (flags & 1) allows backslash
+         to quote the single quote.  This is to inhibit history expansion
+         inside $'...' containing an escaped single quote.
+       - change history_expand to call hist_string_extract_single_quoted
+         with flags == 1 if it sees $'.  Fixes bug reported by Sean
+         Donner <sean.donner@gmail.com>
+
+                                   9/2
+                                   ---
+builtins/printf.def
+       - add a call to sh_wrerror if ferror() succeeds in the PRETURN macro,
+         to print an error message in the case that the final fflush fails
+         (for instance, because it attempts to write data that didn't have a
+         trailing newline).  Fixes bug reported by Stefano Lattarini
+         <stefano.lattarini@gmail.com>
+
+                                   9/7
+                                   ---
+arrayfunc.c
+       - some fixes to assign_compound_array_list to avoid null pointer
+         dereferences pointed out by clang/scan-build
+
+lib/glob/glob.c
+       - fixes to udequote_pathname and wdequote_pathname to avoid possible
+         null pointer dereferences pointed out by clang/scan-build
+
+lib/readline/undo.c
+       - fix to _rl_copy_undo_list (function unused) to avoid deref of
+         uninitialized pointer pointed out by clang/scan-build
+
+general.c
+       - fix string_to_rlimtype so it works if passed a null pointer (though
+         it never is)
+
+builtins/mapfile.def
+       - fix to mapfile() to avoid possible null pointer dereference pointed   
+         out by clang/scan-build
+
+variables.c
+       - fix to valid_exportstr to avoid possible null pointer dereferences
+         pointed out by clang/scan-build
+
+bashline.c
+       - fix to bash_execute_unix_command to avoid possible null pointer
+         dereference if READLINE_LINE or READLINE_POINT is not bound
index eb755bf8dad2b7878e7d6dca0a5d7abe18ad2795..61731efee8e3c512352a1ace09c567887143b94e 100644 (file)
@@ -8128,7 +8128,7 @@ lib/sh/casemod.c
          multibyte character
 
 lib/readline/mbutil.c
-       - fix _rl_find_next_mbchar_internalto not call mbrtowc at the end of
+       - fix _rl_find_next_mbchar_internal to not call mbrtowc at the end of
          the string, since implementations return different values -- just
          break the loop immediately
 
@@ -8702,3 +8702,64 @@ subst.c
 execute_cmd.c
        - add fflush(stdout) and fflush(stderr) to child coproc code before
          calling exit after execute_in_subshell
+
+                                  8/31
+                                  ----
+lib/readline/{{bind,readline}.c,rlprivate.h}
+       - new bindable variable, "echo-control-characters", enabled by default.
+         This controls whether or not readline honors the tty ECHOCTL bit
+         and displays characters corresponding to keyboard-generated signals.
+         Controlled by _rl_echo_control_chars variable, declared in readline.c
+
+lib/readline/signals.c
+       - if _rl_echo_control_chars == 0, don't go through _rl_echo_signal_char
+
+
+lib/readline/doc/{readline.3,rluser.texi}
+       - document "echo-control-characters" bindable variable
+
+                                   9/1
+                                   ---
+lib/readline/histexpand.c
+       - hist_string_extract_single_quoted now takes an additional argument:
+         a flags word.  The only defined value (flags & 1) allows backslash
+         to quote the single quote.  This is to inhibit history expansion
+         inside $'...' containing an escaped single quote.
+       - change history_expand to call hist_string_extract_single_quoted
+         with flags == 1 if it sees $'.  Fixes bug reported by Sean
+         Donner <sean.donner@gmail.com>
+
+                                   9/2
+                                   ---
+builtins/printf.def
+       - add a call to sh_wrerror if ferror() succeeds in the PRETURN macro,
+         to print an error message in the case that the final fflush fails
+         (for instance, because it attempts to write data that didn't have a
+         trailing newline).  Fixes bug reported by Stefano Lattarini
+         <stefano.lattarini@gmail.com>
+
+                                   9/7
+                                   ---
+arrayfunc.c
+       - some fixes to assign_compound_array_list to avoid null pointer
+         dereferences pointed out by clang/scan-build
+
+lib/glob/glob.c
+       - fixes to udequote_pathname and wdequote_pathname to avoid possible
+         null pointer dereferences pointed out by clang/scan-build
+
+lib/readline/undo.c
+       - fix to _rl_copy_undo_list (function unused) to avoid deref of
+         uninitialized pointer pointed out by clang/scan-build
+
+general.c
+       - fix string_to_rlimtype so it works if passed a null pointer (though
+         it never is)
+
+builtins/mapfile.def
+       - fix to mapfile() to avoid possible null pointer dereference pointed   
+         out by clang/scan-build
+
+variables.c
+       - fix to valid_exportstr to avoid possible null pointer dereferences
+         pointed out by clang/scan-build
index 2aa418347dce01a2ae4bcb0176459ae68979e6be..3d553028ef852cc471d81d4ea340b530812d2119 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -907,6 +907,7 @@ tests/new-exp7.sub  f
 tests/new-exp.right    f
 tests/nquote.tests     f
 tests/nquote.right     f
+tests/nquote1.sub      f
 tests/nquote1.tests    f
 tests/nquote1.right    f
 tests/nquote2.tests    f
diff --git a/NOTES b/NOTES
index b938d02bb0627e716ad1b1176a31a73dc4063733..4fe9e6ca21489b04487e5f88ff34eea350d572e4 100644 (file)
--- a/NOTES
+++ b/NOTES
@@ -344,4 +344,8 @@ Platform-Specific Configuration and Operation Notes
      Apple ships inadequate dynamic libreadline and libhistory "replacements"
      as standard libraries.
 
-  
+20.  If you're on a system like SGI Irix, and you get an error about not
+     being able to refer to a dynamic symbol
+     (ld: non-dynamic relocations refer to dynamic symbol PC), add
+     -DNEED_EXTERN_PC to the LOCAL_CFLAGS variable in lib/readline/Makefile.in
+     and rebuild.
index b5941096eeec784ea24c40be5d150476d883aca1..218faf3dd5fce1037cb3dbd6efd5a1c829225077 100644 (file)
@@ -407,6 +407,7 @@ expand_compound_array_assignment (var, value, flags)
   return nlist;
 }
 
+/* Callers ensure that VAR is not NULL */
 void
 assign_compound_array_list (var, nlist, flags)
      SHELL_VAR *var;
@@ -431,9 +432,9 @@ assign_compound_array_list (var, nlist, flags)
      value. */
   if ((flags & ASS_APPEND) == 0)
     {
-      if (array_p (var) && a)
+      if (a && array_p (var))
        array_flush (a);
-      else if (assoc_p (var) && h)
+      else if (h && assoc_p (var))
        assoc_flush (h);
     }
 
@@ -447,7 +448,7 @@ assign_compound_array_list (var, nlist, flags)
       /* We have a word of the form [ind]=value */
       if ((list->word->flags & W_ASSIGNMENT) && w[0] == '[')
        {
-         len = skipsubscript (w, 0, assoc_p (var) != 0);
+         len = skipsubscript (w, 0, (var && assoc_p (var) != 0));
 
          /* XXX - changes for `+=' */
          if (w[len] != ']' || (w[len+1] != '=' && (w[len+1] != '+' || w[len+2] != '=')))
index 88b56d5a508f43f2de3cc11184883b3feb68bd12..06e40a548828edb5a7340ada614a5791b3523827 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);
@@ -431,9 +431,9 @@ assign_compound_array_list (var, nlist, flags)
      value. */
   if ((flags & ASS_APPEND) == 0)
     {
-      if (array_p (var) && a)
+      if (a && array_p (var))
        array_flush (a);
-      else if (assoc_p (var) && h)
+      else if (h && assoc_p (var))
        assoc_flush (h);
     }
 
@@ -447,7 +447,7 @@ assign_compound_array_list (var, nlist, flags)
       /* We have a word of the form [ind]=value */
       if ((list->word->flags & W_ASSIGNMENT) && w[0] == '[')
        {
-         len = skipsubscript (w, 0);
+         len = skipsubscript (w, 0, (var && assoc_p (var) != 0));
 
          /* XXX - changes for `+=' */
          if (w[len] != ']' || (w[len+1] != '=' && (w[len+1] != '+' || w[len+2] != '=')))
@@ -560,8 +560,9 @@ quote_assign (string)
 {
   size_t slen;
   int saw_eq;
-  char *temp, *t;
+  char *temp, *t, *subs;
   const char *s, *send;
+  int ss, se;
   DECLARE_MBSTATE;
 
   slen = strlen (string);
@@ -573,6 +574,20 @@ quote_assign (string)
     {
       if (*s == '=')
        saw_eq = 1;
+      if (saw_eq == 0 && *s == '[')            /* looks like a subscript */
+       {
+         ss = s - string;
+         se = skipsubscript (string, ss, 0);
+         subs = substring (s, ss, se);
+         *t++ = '\\';
+         strcpy (t, subs);
+         t += se - ss;
+         *t++ = '\\';
+         *t++ = ']';
+         s += se + 1;
+         free (subs);
+         continue;
+       }
       if (saw_eq == 0 && (glob_char_p (s) || isifs (*s)))
        *t++ = '\\';
 
@@ -596,7 +611,7 @@ quote_array_assignment_chars (list)
       if (l->word == 0 || l->word->word == 0 || l->word->word[0] == '\0')
        continue;       /* should not happen, but just in case... */
       /* Don't bother if it doesn't look like [ind]=value */
-      if (l->word->word[0] != '[' || xstrchr (l->word->word, '=') == 0) /* ] */
+      if (l->word->word[0] != '[' || mbschr (l->word->word, '=') == 0) /* ] */
        continue;
       nword = quote_assign (l->word->word);
       free (l->word->word);
@@ -619,7 +634,7 @@ unbind_array_element (var, sub)
   char *akey;
   ARRAY_ELEMENT *ae;
 
-  len = skipsubscript (sub, 0);
+  len = skipsubscript (sub, 0, 0);
   if (sub[len] != ']' || len == 0)
     {
       builtin_error ("%s[%s: %s", var->name, sub, _(bash_badsub_errmsg));
@@ -713,7 +728,7 @@ valid_array_reference (name)
   char *t;
   int r, len;
 
-  t = xstrchr (name, '[');     /* ] */
+  t = mbschr (name, '[');      /* ] */
   if (t)
     {
       *t = '\0';
@@ -722,7 +737,7 @@ valid_array_reference (name)
       if (r == 0)
        return 0;
       /* Check for a properly-terminated non-blank subscript. */
-      len = skipsubscript (t, 0);
+      len = skipsubscript (t, 0, 0);
       if (t[len] != ']' || len == 1)
        return 0;
       for (r = 1; r < len; r++)
@@ -773,7 +788,7 @@ array_variable_name (s, subp, lenp)
   char *t, *ret;
   int ind, ni;
 
-  t = xstrchr (s, '[');
+  t = mbschr (s, '[');
   if (t == 0)
     {
       if (subp)
@@ -783,7 +798,7 @@ array_variable_name (s, subp, lenp)
       return ((char *)NULL);
     }
   ind = t - s;
-  ni = skipsubscript (s, ind);
+  ni = skipsubscript (s, ind, 0);
   if (ni <= ind + 1 || s[ni] != ']')
     {
       err_badarraysub (s);
index a2e55c8706fdff5d20883ae9321461afd8f510ff..1e0f8e3d6fc6a2cfa37dc24bffaf087d8af80d67 100644 (file)
@@ -3433,7 +3433,7 @@ bash_execute_unix_command (count, key)
   register int i, r;
   intmax_t mi;
   sh_parser_state_t ps;
-  char *cmd, *value, *l, *ce;
+  char *cmd, *value, *l, *l1, *ce;
   SHELL_VAR *v;
   char ibuf[INT_STRLEN_BOUND(int) + 1];
 
@@ -3482,7 +3482,7 @@ bash_execute_unix_command (count, key)
   v = bind_variable ("READLINE_LINE", rl_line_buffer, 0);
   if (v)
     VSETATTR (v, att_exported);
-  l = value_cell (v);
+  l = v ? value_cell (v) : 0;
   value = inttostr (rl_point, ibuf, sizeof (ibuf));
   v = bind_int_variable ("READLINE_POINT", value);
   if (v)
@@ -3494,7 +3494,8 @@ bash_execute_unix_command (count, key)
   restore_parser_state (&ps);
 
   v = find_variable ("READLINE_LINE");
-  if (value_cell (v) != l)
+  l1 = v ? value_cell (v) : 0;
+  if (l1 != l)
     maybe_make_readline_line (value_cell (v));
   v = find_variable ("READLINE_POINT");
   if (v && legal_number (value_cell (v), &mi))
index b5313351e9ae4d91bd2f3608eef815c65d2d0ec8..a2e55c8706fdff5d20883ae9321461afd8f510ff 100644 (file)
@@ -502,6 +502,8 @@ initialize_readline ()
      do other expansion on directory names. */
   rl_directory_completion_hook = bash_directory_completion_hook;
 
+  rl_filename_rewrite_hook = bash_filename_rewrite_hook;
+
   /* Tell the filename completer we want a chance to ignore some names. */
   rl_ignore_some_completions_function = filename_completion_ignore;
 
index 62f66c47664f704d0e180f9103f790ab5f87994d..a1682f76e62805bb577f532204df2de8cae8b4dc 100644 (file)
@@ -153,7 +153,7 @@ mapfile (fd, line_count_goal, origin, nskip, callback_quantum, callback, array_n
   entry = find_or_make_array_variable (array_name, 1);
   if (entry == 0 || readonly_p (entry) || noassign_p (entry))
     {
-      if (readonly_p (entry))
+      if (entry && readonly_p (entry))
        err_readonly (array_name);
        
       return (EXECUTION_FAILURE);
index e37cd22701d18bc3790487d2d82ccf560ce0943a..62f66c47664f704d0e180f9103f790ab5f87994d 100644 (file)
@@ -281,7 +281,7 @@ mapfile_builtin (list)
          break;
        case 'c':
          code = legal_number (list_optarg, &intval);
-         if (code == 0 || intval < 0 || intval != (unsigned)intval)
+         if (code == 0 || intval <= 0 || intval != (unsigned)intval)
            {
              builtin_error (_("%s: invalid callback quantum"), list_optarg);
              return (EXECUTION_FAILURE);
index 8740bf70503286ccd6e342e5c995d210eeb186d5..b33fda8df9c7c835de2b4ab506c30ad4414cf51d 100644 (file)
@@ -156,6 +156,7 @@ extern int errno;
       fflush (stdout); \
       if (ferror (stdout)) \
        { \
+         sh_wrerror (); \
          clearerr (stdout); \
          return (EXECUTION_FAILURE); \
        } \
index 5d891a7212e0a2c31bb584ded55c905195182d3f..26d46b13c1d80d37aa3b3cc9539626d33c206399 100644 (file)
@@ -5,12 +5,12 @@
 .\"    Case Western Reserve University
 .\"    chet@po.cwru.edu
 .\"
-.\"    Last Change: Sat Aug 22 12:02:47 EDT 2009
+.\"    Last Change: Mon Aug 31 08:59:57 EDT 2009
 .\"
 .\" bash_builtins, strip all but Built-Ins section
 .if \n(zZ=1 .ig zZ
 .if \n(zY=1 .ig zY
-.TH BASH 1 "2009 August 22" "GNU Bash-4.0"
+.TH BASH 1 "2009 August 31" "GNU Bash-4.0"
 .\"
 .\" There's some problem with having a `@'
 .\" in a tagged paragraph with the BSD man macros.
@@ -4947,6 +4947,11 @@ can be set to either
 or
 .BR vi .
 .TP
+.B echo\-control\-characters (On)
+When set to \fBOn\fP, on operating systems that indicate they support it,
+readline echoes a character corresponding to a signal generated from the
+keyboard.
+.TP
 .B enable\-keypad (Off)
 When set to \fBOn\fP, readline will try to enable the application
 keypad when it is called.  Some systems need this to enable the
index 7fc71187fa71f882378bce8b1eb317d80d144987..36b2f5b3a3ef76958661cfd807158b4926b7fa4d 100644 (file)
--- a/general.c
+++ b/general.c
@@ -98,7 +98,7 @@ string_to_rlimtype (s)
   neg = 0;
   while (s && *s && whitespace (*s))
     s++;
-  if (*s == '-' || *s == '+')
+  if (s && (*s == '-' || *s == '+'))
     {
       neg = *s == '-';
       s++;
index 4cf877fdefdd8451a5956aa611b5eeffaa782868..7fc71187fa71f882378bce8b1eb317d80d144987 100644 (file)
@@ -285,7 +285,7 @@ assignment (string, flags)
 #if defined (ARRAY_VARS)
       if (c == '[')
        {
-         newi = skipsubscript (string, indx);
+         newi = skipsubscript (string, indx, 0);
          if (string[newi++] != ']')
            return (0);
          if (string[newi] == '+' && string[newi+1] == '=')
@@ -577,7 +577,7 @@ int
 absolute_program (string)
      const char *string;
 {
-  return ((char *)xstrchr (string, '/') != (char *)NULL);
+  return ((char *)mbschr (string, '/') != (char *)NULL);
 }
 
 /* **************************************************************** */
index 52362495ae4da7462c4c3ea7874af3997ee52816..72242a3b0462a0737bfb2445094172ad7db50ca3 100644 (file)
@@ -246,7 +246,8 @@ udequote_pathname (pathname)
       if (pathname[i - 1] == 0)
        break;
     }
-  pathname[j] = '\0';
+  if (pathname)
+    pathname[j] = '\0';
 }
 
 #if HANDLE_MULTIBYTE
@@ -279,7 +280,8 @@ wdequote_pathname (pathname)
       if (wpathname[i - 1] == L'\0')
        break;
     }
-  wpathname[j] = L'\0';
+  if (wpathname)
+    wpathname[j] = L'\0';
 
   /* Convert the wide character string into unibyte character set. */
   memset (&ps, '\0', sizeof(mbstate_t));
index ffe7b316d1909bbc7b040cd7243a1b86916b24b0..52362495ae4da7462c4c3ea7874af3997ee52816 100644 (file)
@@ -637,7 +637,7 @@ glob_vector (pat, dir, flags)
              continue;
            }
 
-         convfn = fnxform (dp->d_name, D_NAMLEN (dp));
+         convfn = fnx_fromfs (dp->d_name, D_NAMLEN (dp));
          if (strmatch (pat, convfn, mflags) != FNM_NOMATCH)
            {
              if (nalloca < ALLOCA_MAX)
index 77b018ab875e1fccaad8a4612a038055588ab651..580346cca5c55c22a6ed811adfa53201c9677998 100644 (file)
@@ -1426,6 +1426,7 @@ static const struct {
   { "completion-ignore-case",  &_rl_completion_case_fold,      0 },
   { "convert-meta",            &_rl_convert_meta_chars_to_ascii, 0 },
   { "disable-completion",      &rl_inhibit_completion,         0 },
+  { "echo-control-characters", &_rl_echo_control_chars,        0 },
   { "enable-keypad",           &_rl_enable_keypad,             0 },
   { "expand-tilde",            &rl_complete_with_tilde_expansion, 0 },
   { "history-preserve-point",  &_rl_history_preserve_point,    0 },
index 84bc4eb35f052be6d4439311b21a4daaa563f08f..6bdca19dc68e5a9bd6ee07f740b4c70e1d98f769 100644 (file)
@@ -401,6 +401,11 @@ can be set to either
 or
 .BR vi .
 .TP
+.B echo\-control\-characters (On)
+When set to \fBOn\fP, on operating systems that indicate they support it,
+readline echoes a character corresponding to a signal generated from the
+keyboard.
+.TP
 .B enable\-keypad (Off)
 When set to \fBOn\fP, readline will try to enable the application
 keypad when it is called.  Some systems need this to enable the
index e499e41da9901b85e93c17ad6a0476c67de337b1..619de1d2d0016aefb7ca6bdfb3e209f33f8a56e6 100644 (file)
@@ -474,6 +474,11 @@ key bindings is used.  By default, Readline starts up in Emacs editing
 mode, where the keystrokes are most similar to Emacs.  This variable can be
 set to either @samp{emacs} or @samp{vi}.
 
+@item echo-control-characters
+When set to @samp{on}, on operating systems that indicate they support it,
+readline echoes a character corresponding to a signal generated from the
+keyboard.  The default is @samp{on}.
+
 @item enable-keypad
 @vindex enable-keypad
 When set to @samp{on}, Readline will try to enable the application
index b9fac6b8e4e179a24d6eca431128d615c79613ed..d8474adba899de31d2073e61390e5541a42aa49e 100644 (file)
@@ -4,7 +4,7 @@ Copyright (C) 1988-2009 Free Software Foundation, Inc.
 
 @set EDITION 6.0
 @set VERSION 6.0
-@set UPDATED 22 August 2009
+@set UPDATED 31 August 2009
 @set UPDATED-MONTH August 2009
 
-@set LASTCHANGE Sat Aug 22 12:02:34 EDT 2009
+@set LASTCHANGE Mon Aug 31 09:01:30 EDT 2009
index bf5ac0ed5f20f8759eea2b4b7cd5d91739792d56..c209a85058d9c580a6f848cd13b8a77408592756 100644 (file)
@@ -305,16 +305,20 @@ get_history_event (string, caller_index, delimiting_quote)
 /* Extract the contents of STRING as if it is enclosed in single quotes.
    SINDEX, when passed in, is the offset of the character immediately
    following the opening single quote; on exit, SINDEX is left pointing
-   to the closing single quote. */
+   to the closing single quote.  FLAGS currently used to allow backslash
+   to escape a single quote (e.g., for bash $'...'). */
 static void
-hist_string_extract_single_quoted (string, sindex)
+hist_string_extract_single_quoted (string, sindex, flags)
      char *string;
-     int *sindex;
+     int *sindex, flags;
 {
   register int i;
 
   for (i = *sindex; string[i] && string[i] != '\''; i++)
-    ;
+    {
+      if ((flags & 1) && string[i] == '\\' && string[i+1])
+        i++;
+    }
 
   *sindex = i;
 }
@@ -924,7 +928,7 @@ history_expand (hstring, output)
      char **output;
 {
   register int j;
-  int i, r, l, passc, cc, modified, eindex, only_printing, dquote;
+  int i, r, l, passc, cc, modified, eindex, only_printing, dquote, flag;
   char *string;
 
   /* The output string, and its length. */
@@ -1044,8 +1048,9 @@ history_expand (hstring, output)
          else if (dquote == 0 && history_quotes_inhibit_expansion && string[i] == '\'')
            {
              /* If this is bash, single quotes inhibit history expansion. */
+             flag = (i > 0 && string[i - 1] == '$');
              i++;
-             hist_string_extract_single_quoted (string, &i);
+             hist_string_extract_single_quoted (string, &i, flag);
            }
          else if (history_quotes_inhibit_expansion && string[i] == '\\')
            {
@@ -1130,8 +1135,9 @@ history_expand (hstring, output)
              {
                int quote, slen;
 
+               flag = (i > 0 && string[i - 1] == '$');
                quote = i++;
-               hist_string_extract_single_quoted (string, &i);
+               hist_string_extract_single_quoted (string, &i, flag);
 
                slen = i - quote + 2;
                temp = (char *)xmalloc (slen);
@@ -1435,17 +1441,21 @@ history_tokenize_word (string, ind)
          i += 2;
          return i;
        }
-      else
+      else if ((peek == '&' && (string[i] == '>' || string[i] == '<')) ||
+               (peek == '>' && string[i] == '&') ||
+               (peek == '(' && (string[i] == '>' || string[i] == '<')) || /* ) */
+               (peek == '(' && string[i] == '$')) /* ) */
        {
-         if ((peek == '&' && (string[i] == '>' || string[i] == '<')) ||
-             (peek == '>' && string[i] == '&') ||
-             (peek == '(' && (string[i] == '>' || string[i] == '<')) || /* ) */
-             (peek == '(' && string[i] == '$')) /* ) */
-           {
-             i += 2;
-             return i;
-           }
+         i += 2;
+         return i;
        }
+#if 0
+      else if (peek == '\'' && string[i] == '$')
+        {
+         i += 2;       /* XXX */
+         return i;
+        }
+#endif
 
       if (string[i] != '$')
        {
index b12ae1f2dfcf957fa4325bef43b60e6660241f78..c0e78d4fe3134ac62081863f022b416d5e2c4ca8 100644 (file)
@@ -275,6 +275,10 @@ int _rl_bind_stty_chars = 1;
    its initial state. */
 int _rl_revert_all_at_newline = 0;
 
+/* Non-zero means to honor the termios ECHOCTL bit and echo control
+   characters corresponding to keyboard-generated signals. */
+int _rl_echo_control_chars = 1;
+
 /* **************************************************************** */
 /*                                                                 */
 /*                     Top Level Functions                         */
index b09f45e0b4eb7f6d5c614c2c65c91d5e0122eec1..819f1278a4af3cc4ce9a16e78b1f6b4d37892c8c 100644 (file)
@@ -421,6 +421,7 @@ extern int _rl_convert_meta_chars_to_ascii;
 extern int _rl_output_meta_chars;
 extern int _rl_bind_stty_chars;
 extern int _rl_revert_all_at_newline;
+extern int _rl_echo_control_chars;
 extern char *_rl_comment_begin;
 extern unsigned char _rl_parsing_conditionalized_out;
 extern Keymap _rl_keymap;
index 8cad338b880355e17ab3746f36c4b090073e8ba5..11c92d2c299fe6fdf77a2b802711b17dc6f875cf 100644 (file)
@@ -101,7 +101,8 @@ int rl_catch_sigwinch = 0;  /* for the readline state struct in readline.c */
 int _rl_interrupt_immediately = 0;
 int volatile _rl_caught_signal = 0;    /* should be sig_atomic_t, but that requires including <signal.h> everywhere */
 
-/* If non-zero, print characters corresponding to received signals. */
+/* If non-zero, print characters corresponding to received signals as long as
+   the user has indicated his desire to do so (_rl_echo_control_chars). */
 int _rl_echoctl = 0;
 
 int _rl_intr_char = 0;
@@ -637,7 +638,7 @@ rl_echo_signal_char (sig)
   char cstr[3];
   int cslen, c;
 
-  if (_rl_echoctl == 0)
+  if (_rl_echoctl == 0 || _rl_echo_control_chars == 0)
     return;
 
   switch (sig)
index 4e1aa0cb7d481589d0213fd5fdc8447453c0cd8e..fc391894f18b14f90406a8aceb63259ecf120d55 100644 (file)
@@ -1151,7 +1151,7 @@ int
 rl_delete_horizontal_space (count, ignore)
      int count, ignore;
 {
-  int start = rl_point;
+  int start;
 
   while (rl_point && whitespace (rl_line_buffer[rl_point - 1]))
     rl_point--;
index a8c0a53886b6cdf0effd50c0c436e12bebace5db..4e1aa0cb7d481589d0213fd5fdc8447453c0cd8e 100644 (file)
@@ -189,10 +189,13 @@ _rl_replace_text (text, start, end)
 {
   int n;
 
+  n = 0;
   rl_begin_undo_group ();
-  rl_delete_text (start, end + 1);
+  if (start <= end)
+    rl_delete_text (start, end + 1);
   rl_point = start;
-  n = rl_insert_text (text);
+  if (*text)
+    n = rl_insert_text (text);
   rl_end_undo_group ();
 
   return n;
@@ -583,7 +586,7 @@ rl_skip_csi_sequence (count, key)
   RL_SETSTATE (RL_STATE_MOREINPUT);
   do
     ch = rl_read_key ();
-  while (ch >= 0x20 && ch < 0x40)
+  while (ch >= 0x20 && ch < 0x40);
   RL_UNSETSTATE (RL_STATE_MOREINPUT);
 
   return 0;
index c0ba631f13189f764c0fc86d554801f380eb91cf..eb042b29fd966e7261a8735f9709fc9627beec57 100644 (file)
@@ -139,6 +139,9 @@ _rl_copy_undo_list (head)
 {
   UNDO_LIST *list, *new, *roving, *c;
 
+  if (head == 0)
+    return head;
+
   list = head;
   new = 0;
   while (list)
diff --git a/lib/readline/undo.c~ b/lib/readline/undo.c~
new file mode 100644 (file)
index 0000000..c0ba631
--- /dev/null
@@ -0,0 +1,328 @@
+/* readline.c -- a general facility for reading lines of input
+   with emacs style editing and completion. */
+
+/* Copyright (C) 1987-2009 Free Software Foundation, Inc.
+
+   This file is part of the GNU Readline Library (Readline), a library
+   for reading lines of text with interactive input and history editing.      
+
+   Readline 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 3 of the License, or
+   (at your option) any later version.
+
+   Readline 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 Readline.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#define READLINE_LIBRARY
+
+#if defined (HAVE_CONFIG_H)
+#  include <config.h>
+#endif
+
+#include <sys/types.h>
+
+#if defined (HAVE_UNISTD_H)
+#  include <unistd.h>           /* for _POSIX_VERSION */
+#endif /* HAVE_UNISTD_H */
+
+#if defined (HAVE_STDLIB_H)
+#  include <stdlib.h>
+#else
+#  include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+
+#include <stdio.h>
+
+/* System-specific feature definitions and include files. */
+#include "rldefs.h"
+
+/* Some standard library routines. */
+#include "readline.h"
+#include "history.h"
+
+#include "rlprivate.h"
+#include "xmalloc.h"
+
+extern void replace_history_data PARAMS((int, histdata_t *, histdata_t *));
+
+/* Non-zero tells rl_delete_text and rl_insert_text to not add to
+   the undo list. */
+int _rl_doing_an_undo = 0;
+
+/* How many unclosed undo groups we currently have. */
+int _rl_undo_group_level = 0;
+
+/* The current undo list for THE_LINE. */
+UNDO_LIST *rl_undo_list = (UNDO_LIST *)NULL;
+
+/* **************************************************************** */
+/*                                                                 */
+/*                     Undo, and Undoing                           */
+/*                                                                 */
+/* **************************************************************** */
+
+static UNDO_LIST *
+alloc_undo_entry (what, start, end, text)
+     enum undo_code what;
+     int start, end;
+     char *text;
+{
+  UNDO_LIST *temp;
+
+  temp = (UNDO_LIST *)xmalloc (sizeof (UNDO_LIST));
+  temp->what = what;
+  temp->start = start;
+  temp->end = end;
+  temp->text = text;
+
+  temp->next = (UNDO_LIST *)NULL;
+  return temp;
+}
+
+/* Remember how to undo something.  Concatenate some undos if that
+   seems right. */
+void
+rl_add_undo (what, start, end, text)
+     enum undo_code what;
+     int start, end;
+     char *text;
+{
+  UNDO_LIST *temp;
+
+  temp = alloc_undo_entry (what, start, end, text);
+  temp->next = rl_undo_list;
+  rl_undo_list = temp;
+}
+
+/* Free the existing undo list. */
+void
+rl_free_undo_list ()
+{
+  UNDO_LIST *release, *orig_list;
+
+  orig_list = rl_undo_list;
+  while (rl_undo_list)
+    {
+      release = rl_undo_list;
+      rl_undo_list = rl_undo_list->next;
+
+      if (release->what == UNDO_DELETE)
+       xfree (release->text);
+
+      xfree (release);
+    }
+  rl_undo_list = (UNDO_LIST *)NULL;
+  replace_history_data (-1, (histdata_t *)orig_list, (histdata_t *)NULL);
+}
+
+UNDO_LIST *
+_rl_copy_undo_entry (entry)
+     UNDO_LIST *entry;
+{
+  UNDO_LIST *new;
+
+  new = alloc_undo_entry (entry->what, entry->start, entry->end, (char *)NULL);
+  new->text = entry->text ? savestring (entry->text) : 0;
+  return new;
+}
+
+UNDO_LIST *
+_rl_copy_undo_list (head)
+     UNDO_LIST *head;
+{
+  UNDO_LIST *list, *new, *roving, *c;
+
+  list = head;
+  new = 0;
+  while (list)
+    {
+      c = _rl_copy_undo_entry (list);
+      if (new == 0)
+       roving = new = c;
+      else
+       {
+         roving->next = c;
+         roving = roving->next;
+       }
+      list = list->next;
+    }
+
+  roving->next = 0;
+  return new;
+}
+
+/* Undo the next thing in the list.  Return 0 if there
+   is nothing to undo, or non-zero if there was. */
+int
+rl_do_undo ()
+{
+  UNDO_LIST *release;
+  int waiting_for_begin, start, end;
+
+#define TRANS(i) ((i) == -1 ? rl_point : ((i) == -2 ? rl_end : (i)))
+
+  start = end = waiting_for_begin = 0;
+  do
+    {
+      if (rl_undo_list == 0)
+       return (0);
+
+      _rl_doing_an_undo = 1;
+      RL_SETSTATE(RL_STATE_UNDOING);
+
+      /* To better support vi-mode, a start or end value of -1 means
+        rl_point, and a value of -2 means rl_end. */
+      if (rl_undo_list->what == UNDO_DELETE || rl_undo_list->what == UNDO_INSERT)
+       {
+         start = TRANS (rl_undo_list->start);
+         end = TRANS (rl_undo_list->end);
+       }
+
+      switch (rl_undo_list->what)
+       {
+       /* Undoing deletes means inserting some text. */
+       case UNDO_DELETE:
+         rl_point = start;
+         rl_insert_text (rl_undo_list->text);
+         xfree (rl_undo_list->text);
+         break;
+
+       /* Undoing inserts means deleting some text. */
+       case UNDO_INSERT:
+         rl_delete_text (start, end);
+         rl_point = start;
+         break;
+
+       /* Undoing an END means undoing everything 'til we get to a BEGIN. */
+       case UNDO_END:
+         waiting_for_begin++;
+         break;
+
+       /* Undoing a BEGIN means that we are done with this group. */
+       case UNDO_BEGIN:
+         if (waiting_for_begin)
+           waiting_for_begin--;
+         else
+           rl_ding ();
+         break;
+       }
+
+      _rl_doing_an_undo = 0;
+      RL_UNSETSTATE(RL_STATE_UNDOING);
+
+      release = rl_undo_list;
+      rl_undo_list = rl_undo_list->next;
+      replace_history_data (-1, (histdata_t *)release, (histdata_t *)rl_undo_list);
+
+      xfree (release);
+    }
+  while (waiting_for_begin);
+
+  return (1);
+}
+#undef TRANS
+
+int
+_rl_fix_last_undo_of_type (type, start, end)
+     int type, start, end;
+{
+  UNDO_LIST *rl;
+
+  for (rl = rl_undo_list; rl; rl = rl->next)
+    {
+      if (rl->what == type)
+       {
+         rl->start = start;
+         rl->end = end;
+         return 0;
+       }
+    }
+  return 1;
+}
+
+/* Begin a group.  Subsequent undos are undone as an atomic operation. */
+int
+rl_begin_undo_group ()
+{
+  rl_add_undo (UNDO_BEGIN, 0, 0, 0);
+  _rl_undo_group_level++;
+  return 0;
+}
+
+/* End an undo group started with rl_begin_undo_group (). */
+int
+rl_end_undo_group ()
+{
+  rl_add_undo (UNDO_END, 0, 0, 0);
+  _rl_undo_group_level--;
+  return 0;
+}
+
+/* Save an undo entry for the text from START to END. */
+int
+rl_modifying (start, end)
+     int start, end;
+{
+  if (start > end)
+    {
+      SWAP (start, end);
+    }
+
+  if (start != end)
+    {
+      char *temp = rl_copy_text (start, end);
+      rl_begin_undo_group ();
+      rl_add_undo (UNDO_DELETE, start, end, temp);
+      rl_add_undo (UNDO_INSERT, start, end, (char *)NULL);
+      rl_end_undo_group ();
+    }
+  return 0;
+}
+
+/* Revert the current line to its previous state. */
+int
+rl_revert_line (count, key)
+     int count, key;
+{
+  if (rl_undo_list == 0)
+    rl_ding ();
+  else
+    {
+      while (rl_undo_list)
+       rl_do_undo ();
+#if defined (VI_MODE)
+      if (rl_editing_mode == vi_mode)
+       rl_point = rl_mark = 0;         /* rl_end should be set correctly */
+#endif
+    }
+    
+  return 0;
+}
+
+/* Do some undoing of things that were done. */
+int
+rl_undo_command (count, key)
+     int count, key;
+{
+  if (count < 0)
+    return 0;  /* Nothing to do. */
+
+  while (count)
+    {
+      if (rl_do_undo ())
+       count--;
+      else
+       {
+         rl_ding ();
+         break;
+       }
+    }
+  return 0;
+}
index 1009565328d39713ab3ea7b400ef5c879eb7a235..3d656df09e22458e259a4bee64338602c83b8652 100644 (file)
@@ -92,7 +92,7 @@ uconvert(s, ip, up)
       ipart = (ipart * 10) + (*p - '0');
     }
 
-  if (*p == 0)
+  if (p == 0 || *p == 0)       /* callers ensure p can never be 0; this is to shut up clang */
     RETURN(1);
 
   if (*p == DECIMAL)
diff --git a/lib/sh/uconvert.c~ b/lib/sh/uconvert.c~
new file mode 100644 (file)
index 0000000..1009565
--- /dev/null
@@ -0,0 +1,116 @@
+/* uconvert - convert string representations of decimal numbers into whole
+             number/fractional value pairs. */
+
+/* Copyright (C) 2008,2009 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 3 of the License, 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.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "config.h"
+
+#include "bashtypes.h"
+
+#if defined (TIME_WITH_SYS_TIME)
+#  include <sys/time.h>
+#  include <time.h>
+#else
+#  if defined (HAVE_SYS_TIME_H)
+#    include <sys/time.h>
+#  else
+#    include <time.h>
+#  endif
+#endif
+
+#if defined (HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include "chartypes.h"
+
+#include "shell.h"
+#include "builtins.h"
+
+#define DECIMAL        '.'             /* XXX - should use locale */
+
+#define RETURN(x) \
+do { \
+  if (ip) *ip = ipart * mult; \
+  if (up) *up = upart; \
+  return (x); \
+} while (0)
+
+/*
+ * An incredibly simplistic floating point converter.
+ */
+static int multiplier[7] = { 1, 100000, 10000, 1000, 100, 10, 1 };
+
+/* Take a decimal number int-part[.[micro-part]] and convert it to the whole
+   and fractional portions.  The fractional portion is returned in
+   millionths (micro); callers are responsible for multiplying appropriately.
+   Return 1 if value converted; 0 if invalid integer for either whole or
+   fractional parts. */
+int
+uconvert(s, ip, up)
+     char *s;
+     long *ip, *up;
+{
+  int n, mult;
+  long ipart, upart;
+  char *p;
+
+  ipart = upart = 0;
+  mult = 1;
+
+  if (s && (*s == '-' || *s == '+'))
+    {
+      mult = (*s == '-') ? -1 : 1;
+      p = s + 1;
+    }
+  else
+    p = s;
+
+  for ( ; p && *p; p++)
+    {
+      if (*p == DECIMAL)               /* decimal point */
+       break;
+      if (DIGIT(*p) == 0)
+       RETURN(0);
+      ipart = (ipart * 10) + (*p - '0');
+    }
+
+  if (*p == 0)
+    RETURN(1);
+
+  if (*p == DECIMAL)
+    p++;
+
+  /* Look for up to six digits past a decimal point. */
+  for (n = 0; n < 6 && p[n]; n++)
+    {
+      if (DIGIT(p[n]) == 0)
+       RETURN(0);
+      upart = (upart * 10) + (p[n] - '0');
+    }
+
+  /* Now convert to millionths */
+  upart *= multiplier[n];
+
+  if (n == 6 && p[6] >= '5' && p[6] <= '9')
+    upart++;                   /* round up 1 */
+
+  RETURN(1);
+}
index 325b37d6a14e49cb726cc361f1e366d16c86250e..c10ac99e9730574aee937c5769cbc3077c82369a 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 28
+#define PATCHLEVEL 33
 
 #endif /* _PATCHLEVEL_H_ */
diff --git a/subst.c b/subst.c
index 3e91f1c66e52525accc0becd1522de8c15506bc5..e715e7370bc09aa8ebda158e8d0acf81abfed567 100644 (file)
--- a/subst.c
+++ b/subst.c
@@ -1031,7 +1031,7 @@ string_extract_verbatim (string, slen, sindex, charlist, flags)
      char *charlist;
      int flags;
 {
-  register int i = *sindex;
+  register int i;
 #if defined (HANDLE_MULTIBYTE)
   size_t clen;
   wchar_t *wcharlist;
@@ -2662,7 +2662,6 @@ do_assignment_internal (word, expand)
        }
       else
 #endif
-
       if (expand && temp[0])
        value = expand_string_if_necessary (temp, 0, expand_string_assignment);
       else
index c8d1cf4995b831047f8252233babb031508581fc..b7cafb6722cd07f8d4889fce37ada52b34a890ab 100644 (file)
--- a/subst.c~
+++ b/subst.c~
@@ -314,6 +314,135 @@ static WORD_LIST *expand_word_list_internal __P((WORD_LIST *, int));
 /*                                                                 */
 /* **************************************************************** */
 
+#if defined (DEBUG)
+void
+dump_word_flags (flags)
+     int flags;
+{
+  int f;
+
+  f = flags;
+  fprintf (stderr, "%d -> ", f);
+  if (f & W_ASSIGNASSOC)
+    {
+      f &= ~W_ASSIGNASSOC;
+      fprintf (stderr, "W_ASSIGNASSOC%s", f ? "|" : "");
+    }
+  if (f & W_HASCTLESC)
+    {
+      f &= ~W_HASCTLESC;
+      fprintf (stderr, "W_HASCTLESC%s", f ? "|" : "");
+    }
+  if (f & W_NOPROCSUB)
+    {
+      f &= ~W_NOPROCSUB;
+      fprintf (stderr, "W_NOPROCSUB%s", f ? "|" : "");
+    }
+  if (f & W_DQUOTE)
+    {
+      f &= ~W_DQUOTE;
+      fprintf (stderr, "W_DQUOTE%s", f ? "|" : "");
+    }
+  if (f & W_HASQUOTEDNULL)
+    {
+      f &= ~W_HASQUOTEDNULL;
+      fprintf (stderr, "W_HASQUOTEDNULL%s", f ? "|" : "");
+    }
+  if (f & W_ASSIGNARG)
+    {
+      f &= ~W_ASSIGNARG;
+      fprintf (stderr, "W_ASSIGNARG%s", f ? "|" : "");
+    }
+  if (f & W_ASSNBLTIN)
+    {
+      f &= ~W_ASSNBLTIN;
+      fprintf (stderr, "W_ASSNBLTIN%s", f ? "|" : "");
+    }
+  if (f & W_COMPASSIGN)
+    {
+      f &= ~W_COMPASSIGN;
+      fprintf (stderr, "W_COMPASSIGN%s", f ? "|" : "");
+    }
+  if (f & W_NOEXPAND)
+    {
+      f &= ~W_NOEXPAND;
+      fprintf (stderr, "W_NOEXPAND%s", f ? "|" : "");
+    }
+  if (f & W_ITILDE)
+    {
+      f &= ~W_ITILDE;
+      fprintf (stderr, "W_ITILDE%s", f ? "|" : "");
+    }
+  if (f & W_NOTILDE)
+    {
+      f &= ~W_NOTILDE;
+      fprintf (stderr, "W_NOTILDE%s", f ? "|" : "");
+    }
+  if (f & W_ASSIGNRHS)
+    {
+      f &= ~W_ASSIGNRHS;
+      fprintf (stderr, "W_ASSIGNRHS%s", f ? "|" : "");
+    }
+  if (f & W_NOCOMSUB)
+    {
+      f &= ~W_NOCOMSUB;
+      fprintf (stderr, "W_NOCOMSUB%s", f ? "|" : "");
+    }
+  if (f & W_DOLLARSTAR)
+    {
+      f &= ~W_DOLLARSTAR;
+      fprintf (stderr, "W_DOLLARSTAR%s", f ? "|" : "");
+    }
+  if (f & W_DOLLARAT)
+    {
+      f &= ~W_DOLLARAT;
+      fprintf (stderr, "W_DOLLARAT%s", f ? "|" : "");
+    }
+  if (f & W_TILDEEXP)
+    {
+      f &= ~W_TILDEEXP;
+      fprintf (stderr, "W_TILDEEXP%s", f ? "|" : "");
+    }
+  if (f & W_NOSPLIT2)
+    {
+      f &= ~W_NOSPLIT2;
+      fprintf (stderr, "W_NOSPLIT2%s", f ? "|" : "");
+    }
+  if (f & W_NOGLOB)
+    {
+      f &= ~W_NOGLOB;
+      fprintf (stderr, "W_NOGLOB%s", f ? "|" : "");
+    }
+  if (f & W_NOSPLIT)
+    {
+      f &= ~W_NOSPLIT;
+      fprintf (stderr, "W_NOSPLIT%s", f ? "|" : "");
+    }
+  if (f & W_GLOBEXP)
+    {
+      f &= ~W_GLOBEXP;
+      fprintf (stderr, "W_GLOBEXP%s", f ? "|" : "");
+    }
+  if (f & W_ASSIGNMENT)
+    {
+      f &= ~W_ASSIGNMENT;
+      fprintf (stderr, "W_ASSIGNMENT%s", f ? "|" : "");
+    }
+  if (f & W_QUOTED)
+    {
+      f &= ~W_QUOTED;
+      fprintf (stderr, "W_QUOTED%s", f ? "|" : "");
+    }
+  if (f & W_HASDOLLAR)
+    {
+      f &= ~W_HASDOLLAR;
+      fprintf (stderr, "W_HASDOLLAR%s", f ? "|" : "");
+    }
+  fprintf (stderr, "\n");
+  fflush (stderr);
+}
+#endif
+
 #ifdef INCLUDE_UNUSED
 static char *
 quoted_substring (string, start, end)
@@ -588,7 +717,7 @@ string_extract (string, sindex, charlist, flags)
        {
          int ni;
          /* If this is an array subscript, skip over it and continue. */
-         ni = skipsubscript (string, i);
+         ni = skipsubscript (string, i, 0);
          if (string[ni] == ']')
            i = ni;
        }
@@ -902,7 +1031,7 @@ string_extract_verbatim (string, slen, sindex, charlist, flags)
      char *charlist;
      int flags;
 {
-  register int i = *sindex;
+  register int i;
 #if defined (HANDLE_MULTIBYTE)
   size_t clen;
   wchar_t *wcharlist;
@@ -1380,7 +1509,10 @@ 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. */
+   parse array subscripts.  FLAGS & 1 means to not attempt to skip over
+   matched pairs of quotes or backquotes, or skip word expansions; it is
+   intended to be used after expansion has been performed and during final
+   assignment parsing (see arrayfunc.c:assign_compound_array_list()). */
 static int
 skip_matched_pair (string, start, open, close, flags)
      const char *string;
@@ -1421,13 +1553,13 @@ skip_matched_pair (string, start, open, close, flags)
          ADVANCE_CHAR (string, slen, i);
          continue;
        }
-      else if (c == '`')
+      else if ((flags & 1) == 0 && c == '`')
        {
          backq = 1;
          i++;
          continue;
        }
-      else if (c == open)
+      else if ((flags & 1) == 0 && c == open)
        {
          count++;
          i++;
@@ -1441,13 +1573,13 @@ skip_matched_pair (string, start, open, close, flags)
          i++;
          continue;
        }
-      else if (c == '\'' || c == '"')
+      else if ((flags & 1) == 0 && (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))
+      else if ((flags&1) == 0 && c == '$' && (string[i+1] == LPAREN || string[i+1] == LBRACE))
        {
          si = i + 2;
          if (string[si] == '\0')
@@ -1472,11 +1604,11 @@ skip_matched_pair (string, start, open, close, flags)
 
 #if defined (ARRAY_VARS)
 int
-skipsubscript (string, start)
+skipsubscript (string, start, flags)
      const char *string;
-     int start;
+     int start, flags;
 {
-  return (skip_matched_pair (string, start, '[', ']', 0));
+  return (skip_matched_pair (string, start, '[', ']', flags));
 }
 #endif
 
@@ -1810,8 +1942,9 @@ split_at_delims (string, slen, delims, sentinel, nwp, cwp)
 
   /* Special case for SENTINEL at the end of STRING.  If we haven't found
      the word containing SENTINEL yet, and the index we're looking for is at
-     the end of STRING, add an additional null argument and set the current
-     word pointer to that. */
+     the end of STRING (or past the end of the previously-found token,
+     possible if the end of the line is composed solely of IFS whitespace)
+     add an additional null argument and set the current word pointer to that. */
   if (cwp && cw == -1 && (sentinel >= slen || sentinel >= te))
     {
       if (whitespace (string[sentinel - 1]))
@@ -4865,7 +4998,7 @@ command_substitute (string, quoted)
 
   if (wordexp_only && read_but_dont_execute)
     {
-      last_command_exit_value = 125;
+      last_command_exit_value = EX_WEXPCOMSUB;
       jump_to_top_level (EXITPROG);
     }
 
@@ -6635,7 +6768,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;
 
index 6d936d5e143972b92bc2254b6a58c2574cd88123..267f0e7fdebfee96982affa82ff8233c4133d46f 100644 (file)
@@ -35,3 +35,6 @@ argv[1] = <hello, $world>
 ;foo
 argv[1] = <^I>
 argv[1] = <'A^IB'>
+hello' world
+hello world!
+hello' world!
index 62d90b99a13b64bd932511261c0ca438640ab366..720c3e157bc8b3e8835f27c1271261cad88e95c9 100644 (file)
@@ -114,3 +114,5 @@ args ()
 unset mytab
 recho "${mytab:-$'\t'}"
 recho "$( args $'A\tB' )"
+
+${THIS_SH} ./nquote1.sub
diff --git a/tests/nquote1.sub b/tests/nquote1.sub
new file mode 100644 (file)
index 0000000..b3bc0db
--- /dev/null
@@ -0,0 +1,6 @@
+set -o history
+set -H
+
+echo $'hello\' world'
+echo $'hello world!'
+echo $'hello\' world!'
index bdc27c7ed2e262e1e18688d07f0bbfe14779e00c..b178661ea43d2fb291848173f7de89dd8074c578 100644 (file)
@@ -3366,6 +3366,11 @@ valid_exportstr (v)
   char *s;
 
   s = v->exportstr;
+  if (s == 0)
+    {
+      internal_error (_("%s has null exportstr"), v->name);
+      return (0);
+    }
   if (legal_variable_starter ((unsigned char)*s) == 0)
     {
       internal_error (_("invalid character %d in exportstr for %s"), *s, v->name);
index 1223b058f52075795b56e1c37a42d52ccf4fd96e..bdc27c7ed2e262e1e18688d07f0bbfe14779e00c 100644 (file)
@@ -2226,7 +2226,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
@@ -4644,11 +4644,32 @@ sv_xtracefd (name)
      char *name;
 {
   SHELL_VAR *v;
+  char *t, *e;
+  int fd;
+  FILE *fp;
 
   v = find_variable (name);
   if (v == 0)
+    {
+      xtrace_reset ();
+      return;
+    }
+
+  t = value_cell (v);
+  if (t == 0 || *t == 0)
     xtrace_reset ();
   else
     {
+      fd = (int)strtol (t, &e, 10);
+      if (e != t && *e == '\0' && sh_validfd (fd))
+       {
+         fp = fdopen (fd, "w");
+         if (fp == 0)
+           internal_error (_("%s: %s: cannot open as FILE"), name, value_cell (v));
+         else
+           xtrace_set (fd, fp);
+       }
+      else
+       internal_error (_("%s: %s: invalid value for trace file descriptor"), name, value_cell (v));
     }
 }