]> git.ipfire.org Git - thirdparty/bash.git/commitdiff
commit bash-20190731 snapshot
authorChet Ramey <chet.ramey@case.edu>
Thu, 1 Aug 2019 20:00:56 +0000 (16:00 -0400)
committerChet Ramey <chet.ramey@case.edu>
Thu, 1 Aug 2019 20:00:56 +0000 (16:00 -0400)
CWRU/CWRU.chlog
aclocal.m4
configure
lib/readline/input.c
lib/readline/isearch.c
lib/readline/kill.c
lib/readline/misc.c
lib/readline/rlprivate.h
lib/readline/text.c
lib/readline/vi_mode.c
subst.c

index f8cbc518ba2b6985dbfc1583be719bc471ea1454..5fc3f13da7eac3710e7cc4f88a841ac7a27a1350 100644 (file)
@@ -6390,3 +6390,61 @@ lib/glob/sm_loop.c
 builtins/colon.def
        - add the right includes so colon_builtin and false_builtin can take
          a WORD_LIST * argument like the prototype says they do
+
+                                  7/29
+                                  ----
+lib/readline/kill.c
+       - _rl_read_bracketed_paste_prefix: read the character prefix that
+         indicates a pasted string in bracketed paste mode. If we don't
+         read a valid bracketed paste prefix, push the other characters
+         back onto the input stack with _rl_unget_char
+       - _rl_bracketed_read_key: handle reading pasted input when bracketed
+         paste mode is enabled, including reading multibyte characters; push
+         anything beyond a single byte back onto the input stack where it
+         can be read by _rl_read_mbstring or subsequent input
+       - _rl_bracketed_read_mbstring: handle reading pasted input in bracketed
+         paste mode, using _rl_bracketed_read_key to get the pasted text,
+         then call _rl_read_mbstring to get the rest of any multibyte char
+
+
+lib/readline/vi_mode.c
+       - _rl_vi_callback_getchar: call _rl_bracketed_read_mbstring to handle
+         bracketed paste mode input. Fixes issue with vi-change-char reported
+         by <vampyrebat@gmail.com>
+       - rl_vi_domove_getchar: just call _rl_bracketed_read_key and return
+         the result -- we're not interested in multibyte-character input here
+         yet
+       - rl_vi_replace: bind BRACK_PASTE_PREF key sequence if bracketed paste
+         mode has been enabled
+       - _rl_overstrike_bracketed_paste: key binding function for the bracketed
+         paste prefix key sequence in overwrite mode; reads the pasted text
+         and uses rl_vi_overstrike to add each character in overwrite mode.
+         Fixes issue reported by <vampyrebat@gmail.com>
+
+                                  7/31
+                                  ----
+lib/readline/input.c
+       - _rl_read_mbchar: the first time through the loop (mb_len == 0), call
+         _rl_bracketed_read_key to process any bracketed paste characters
+
+lib/readline/text.c
+       - _rl_char_search: use _rl_bracketed_read_key in the non-multibyte
+         character case
+
+lib/readline/misc.c
+       - _rl_arg_dispatch: use _rl_bracketed_read_key in place of rl_read_key
+
+subst.c
+       - list_string: if string_extract_verbatim returns something, just make
+         a WORD_DESC * and add current_word directly to it, noting that we
+         don't want to free current_word (free_word = 0)
+       - string_extract_verbatim: if the separator string is the empty
+         string, don't bother with the loop -- just savestring the string,
+         update *sindex, and return the copy
+       - read_comsub: make the string we use to save the output from the pipe
+         512 bytes instead of 128 (same size as the buffer used to read from
+         the pipe); fewer calls to xrealloc in the worst case
+       - parameter_brace_expand_length: optimize the common case (non-dynamic
+         scalar variable without `set -u' in effect) and just call MB_STRLEN
+         on the variable value in that case. From a report from
+         Alkis Georgopoulos <alkisg@gmail.com>
index ff8469297790b6b9ec50c959cc7d45186be8fc48..c42dbf3b67ed9c7fdd2b1f5a420b978001b93cb1 100644 (file)
@@ -10,7 +10,7 @@ AC_DEFUN(BASH_C_LONG_LONG,
   ac_cv_c_long_long=yes
 else
 AC_TRY_RUN([
-#include "bashansi.h"
+#include <stdlib.h>
 int
 main()
 {
@@ -34,7 +34,7 @@ AC_DEFUN(BASH_C_LONG_DOUBLE,
   ac_cv_c_long_double=yes
 else
 AC_TRY_RUN([
-#include "bashansi.h"
+#include <stdlib.h>
 int
 main()
 {
@@ -138,7 +138,7 @@ typedef int (*_bashfunc)(const char *, ...);
 #else
 typedef int (*_bashfunc)();
 #endif
-#include "bashansi.h"
+#include <stdlib.h>
 main()
 {
 _bashfunc pf;
@@ -196,7 +196,7 @@ AC_CACHE_VAL(bash_cv_under_sys_siglist,
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
-#include "bashansi.h"
+#include <stdlib.h>
 #ifndef UNDER_SYS_SIGLIST_DECLARED
 extern char *_sys_siglist[];
 #endif
@@ -224,7 +224,7 @@ AC_CACHE_VAL(bash_cv_sys_siglist,
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
-#include "bashansi.h"
+#include <stdlib.h>
 #if !HAVE_DECL_SYS_SIGLIST
 extern char *sys_siglist[];
 #endif
@@ -280,7 +280,7 @@ AC_CACHE_VAL(bash_cv_dup2_broken,
 [AC_TRY_RUN([
 #include <sys/types.h>
 #include <fcntl.h>
-#include "bashansi.h"
+#include <stdlib.h>
 main()
 {
   int fd1, fd2, fl;
@@ -343,7 +343,7 @@ AC_CACHE_VAL(bash_cv_opendir_not_robust,
 #  include <ndir.h>
 # endif
 #endif /* HAVE_DIRENT_H */
-#include "bashansi.h"
+#include <stdlib.h>
 main()
 {
 DIR *dir;
@@ -523,7 +523,7 @@ AC_TRY_RUN([
 #include <sys/types.h>
 #include <sys/time.h>
 #include <sys/resource.h>
-#include "bashansi.h"
+#include <stdlib.h>
 main()
 {
 #ifdef HAVE_QUAD_T
@@ -593,7 +593,7 @@ AC_CACHE_VAL(bash_cv_getenv_redef,
 #ifdef HAVE_UNISTD_H
 #  include <unistd.h>
 #endif
-#include "bashansi.h"
+#include <stdlib.h>
 #ifndef __STDC__
 #  ifndef const
 #    define const
@@ -797,7 +797,7 @@ AC_CACHE_VAL(bash_cv_func_sigsetjmp,
 #include <sys/types.h>
 #include <signal.h>
 #include <setjmp.h>
-#include "bashansi.h"
+#include <stdlib.h>
 
 main()
 {
@@ -893,7 +893,7 @@ AC_CACHE_VAL(bash_cv_printf_a_format,
 [AC_TRY_RUN([
 #include <stdio.h>
 #include <string.h>
-#include "bashansi.h"
+#include <stdlib.h>
 
 int
 main()
@@ -1254,7 +1254,7 @@ AC_CACHE_VAL(bash_cv_pgrp_pipe,
 #ifdef HAVE_UNISTD_H
 #  include <unistd.h>
 #endif
-#include "bashansi.h"
+#include <stdlib.h>
 main()
 {
 # ifdef GETPGRP_VOID
@@ -1319,7 +1319,7 @@ AC_CACHE_VAL(bash_cv_must_reinstall_sighandlers,
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
-#include "bashansi.h"
+#include <stdlib.h>
 
 typedef RETSIGTYPE sigfunc();
 
@@ -1433,7 +1433,7 @@ AC_CACHE_VAL(bash_cv_sys_named_pipes,
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
-#include "bashansi.h"
+#include <stdlib.h>
 
 /* Add more tests in here as appropriate. */
 main()
@@ -1667,7 +1667,7 @@ AC_CACHE_VAL(bash_cv_unusable_rtsigs,
 [AC_TRY_RUN([
 #include <sys/types.h>
 #include <signal.h>
-#include "bashansi.h"
+#include <stdlib.h>
 
 #ifndef NSIG
 #  define NSIG 64
@@ -1851,7 +1851,7 @@ AC_CACHE_VAL(ac_cv_rl_version,
 [AC_TRY_RUN([
 #include <stdio.h>
 #include <readline/readline.h>
-#include "bashansi.h"
+#include <stdlib.h>
 
 extern int rl_gnu_readline_p;
 
@@ -2056,7 +2056,7 @@ AC_DEFUN([BASH_FUNC_SNPRINTF],
     AC_CACHE_CHECK([for standard-conformant snprintf], [bash_cv_func_snprintf],
       [AC_TRY_RUN([
 #include <stdio.h>
-#include "bashansi.h"
+#include <stdlib.h>
 
 main()
 {
index 9f8dadf7deb9039d4e84dd4b0c4152941d307d62..930cba0732db17d74f440a4eb7a4d4e31a2cc918 100755 (executable)
--- a/configure
+++ b/configure
@@ -5392,7 +5392,7 @@ else
 
 #include <stdio.h>
 #include <readline/readline.h>
-#include "bashansi.h"
+#include <stdlib.h>
 
 extern int rl_gnu_readline_p;
 
@@ -16916,7 +16916,7 @@ else
 
 #include <sys/types.h>
 #include <fcntl.h>
-#include "bashansi.h"
+#include <stdlib.h>
 main()
 {
   int fd1, fd2, fl;
@@ -16968,7 +16968,7 @@ else
 #ifdef HAVE_UNISTD_H
 #  include <unistd.h>
 #endif
-#include "bashansi.h"
+#include <stdlib.h>
 main()
 {
 # ifdef GETPGRP_VOID
@@ -17182,7 +17182,7 @@ else
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
-#include "bashansi.h"
+#include <stdlib.h>
 #if !HAVE_DECL_SYS_SIGLIST
 extern char *sys_siglist[];
 #endif
@@ -17264,7 +17264,7 @@ else
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
-#include "bashansi.h"
+#include <stdlib.h>
 #ifndef UNDER_SYS_SIGLIST_DECLARED
 extern char *_sys_siglist[];
 #endif
@@ -17672,7 +17672,7 @@ else
 #include <sys/types.h>
 #include <sys/time.h>
 #include <sys/resource.h>
-#include "bashansi.h"
+#include <stdlib.h>
 main()
 {
 #ifdef HAVE_QUAD_T
@@ -18586,7 +18586,7 @@ else
 #  include <ndir.h>
 # endif
 #endif /* HAVE_DIRENT_H */
-#include "bashansi.h"
+#include <stdlib.h>
 main()
 {
 DIR *dir;
@@ -18700,7 +18700,7 @@ else
 #ifdef HAVE_UNISTD_H
 #  include <unistd.h>
 #endif
-#include "bashansi.h"
+#include <stdlib.h>
 #ifndef __STDC__
 #  ifndef const
 #    define const
@@ -18822,7 +18822,7 @@ else
 #include <sys/types.h>
 #include <signal.h>
 #include <setjmp.h>
-#include "bashansi.h"
+#include <stdlib.h>
 
 main()
 {
@@ -18962,7 +18962,7 @@ else
 /* end confdefs.h.  */
 
 #include <stdio.h>
-#include "bashansi.h"
+#include <stdlib.h>
 
 main()
 {
@@ -19202,7 +19202,7 @@ else
 
 #include <stdio.h>
 #include <string.h>
-#include "bashansi.h"
+#include <stdlib.h>
 
 int
 main()
@@ -19315,7 +19315,7 @@ else
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
-#include "bashansi.h"
+#include <stdlib.h>
 
 typedef RETSIGTYPE sigfunc();
 
@@ -19467,7 +19467,7 @@ else
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
-#include "bashansi.h"
+#include <stdlib.h>
 
 /* Add more tests in here as appropriate. */
 main()
@@ -19778,7 +19778,7 @@ else
 
 #include <sys/types.h>
 #include <signal.h>
-#include "bashansi.h"
+#include <stdlib.h>
 
 #ifndef NSIG
 #  define NSIG 64
index a5573305773d6f3435763d66cda983a35f2b4744..0090e97b8b5979b31484453d2518f700d7b5ab24 100644 (file)
@@ -635,9 +635,7 @@ _rl_read_mbchar (char *mbchar, int size)
   mb_len = 0;  
   while (mb_len < size)
     {
-      RL_SETSTATE(RL_STATE_MOREINPUT);
-      c = rl_read_key ();
-      RL_UNSETSTATE(RL_STATE_MOREINPUT);
+      c = (mb_len == 0) ? _rl_bracketed_read_key () : rl_read_key ();
 
       if (c < 0)
        break;
index d6c59041772cdb539db2076c7615328d47bbcc9b..951fce57586bde1e53081859dece99eb639ead62 100644 (file)
@@ -297,6 +297,7 @@ _rl_isearch_fini (_rl_search_cxt *cxt)
   rl_clear_message ();
 }
 
+/* XXX - we could use _rl_bracketed_read_mbstring () here. */
 int
 _rl_search_getchar (_rl_search_cxt *cxt)
 {
index cf8ca93243b8b282f70c2f0b3ea7657e34c1b49c..6a2e0c6a59500eaf8a9203cd5abff004497f2e29 100644 (file)
@@ -1,6 +1,6 @@
 /* kill.c -- kill ring management. */
 
-/* Copyright (C) 1994-2017 Free Software Foundation, Inc.
+/* Copyright (C) 1994-2019 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.      
@@ -668,8 +668,7 @@ rl_yank_last_arg (int count, int key)
 
 /* Having read the special escape sequence denoting the beginning of a
    `bracketed paste' sequence, read the rest of the pasted input until the
-   closing sequence and insert the pasted text as a single unit without
-   interpretation. */
+   closing sequence and return the pasted text. */
 char *
 _rl_bracketed_text (size_t *lenp)
 {
@@ -715,6 +714,10 @@ _rl_bracketed_text (size_t *lenp)
   return (buf);
 }
 
+/* Having read the special escape sequence denoting the beginning of a
+   `bracketed paste' sequence, read the rest of the pasted input until the
+   closing sequence and insert the pasted text as a single unit without
+   interpretation. */
 int
 rl_bracketed_paste_begin (int count, int key)
 {
@@ -729,6 +732,96 @@ rl_bracketed_paste_begin (int count, int key)
   return (retval);
 }
 
+int
+_rl_read_bracketed_paste_prefix (int c)
+{
+  char pbuf[BRACK_PASTE_SLEN+1], *pbpref;
+  int key, ind, j;
+
+  pbpref = BRACK_PASTE_PREF;           /* XXX - debugging */
+  if (c != pbpref[0])
+    return (0);
+  pbuf[ind = 0] = c;
+  while (ind < BRACK_PASTE_SLEN-1 &&
+        (RL_ISSTATE (RL_STATE_INPUTPENDING|RL_STATE_MACROINPUT) == 0) &&
+         _rl_pushed_input_available () == 0 &&
+         _rl_input_queued (0))
+    {
+      key = rl_read_key ();            /* XXX - for now */
+      if (key < 0)
+       break;
+      pbuf[++ind] = key;
+      if (pbuf[ind] != pbpref[ind])
+        break;
+    }
+
+  if (ind < BRACK_PASTE_SLEN-1)                /* read incomplete sequence */
+    {
+      while (ind >= 0)
+       _rl_unget_char (pbuf[ind--]);
+      return (key < 0 ? key : 0);
+    }
+  return (key < 0 ? key : 1);
+}
+
+/* Get a character from wherever we read input, handling input in bracketed
+   paste mode. If we don't have or use bracketed paste mode, this can be
+   used in place of rl_read_key(). */
+int
+_rl_bracketed_read_key ()
+{
+  int c, r;
+  char *pbuf;
+  size_t pblen;
+
+  RL_SETSTATE(RL_STATE_MOREINPUT);
+  c = rl_read_key ();
+  RL_UNSETSTATE(RL_STATE_MOREINPUT);
+
+  if (c < 0)
+    return -1;
+
+  /* read pasted data with bracketed-paste mode enabled. */
+  if (_rl_enable_bracketed_paste && c == ESC && (r = _rl_read_bracketed_paste_prefix (c)) == 1)
+    {
+      pbuf = _rl_bracketed_text (&pblen);
+      if (pblen == 0)
+       {
+         xfree (pbuf);
+         return 0;             /* XXX */
+       }
+      c = (unsigned char)pbuf[0];
+      if (pblen > 1)
+       {
+         while (--pblen > 0)
+           _rl_unget_char ((unsigned char)pbuf[pblen]);
+       }
+      xfree (pbuf);
+    }
+
+  return c;
+}
+
+/* Get a character from wherever we read input, handling input in bracketed
+   paste mode. If we don't have or use bracketed paste mode, this can be
+   used in place of rl_read_key(). */
+int
+_rl_bracketed_read_mbstring (char *mb, int mlen)
+{
+  int c, r;
+
+  c = _rl_bracketed_read_key ();
+  if (c < 0)
+    return -1;
+
+#if defined (HANDLE_MULTIBYTE)
+  if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+    c = _rl_read_mbstring (c, mb, mlen);
+#endif
+
+  return c;
+}
+
 /* A special paste command for Windows users. */
 #if defined (_WIN32)
 #include <windows.h>
index b49d61ac2cc82bad8ab7ed72b362c21d29d111e8..e6b42ebf2bc9deb5959c4d2bc6a750bcf63501dd 100644 (file)
@@ -138,9 +138,7 @@ _rl_arg_dispatch (_rl_arg_cxt cxt, int c)
         }
       else
        {
-         RL_SETSTATE(RL_STATE_MOREINPUT);
-         key = rl_read_key ();
-         RL_UNSETSTATE(RL_STATE_MOREINPUT);
+         key = _rl_bracketed_read_key ();
          rl_restore_prompt ();
          rl_clear_message ();
          RL_UNSETSTATE(RL_STATE_NUMERICARG);
index 38e1dc79bf6fc2fd605bad56156c431662235624..76631d7ab740aaa8793d4a9dd8b13c996bbfd0ee 100644 (file)
@@ -309,7 +309,10 @@ extern int _rl_search_getchar PARAMS((_rl_search_cxt *));
 #define BRACK_PASTE_INIT       "\033[?2004h"
 #define BRACK_PASTE_FINI       "\033[?2004l\r"
 
+extern int _rl_read_bracketed_paste_prefix PARAMS((int));
 extern char *_rl_bracketed_text PARAMS((size_t *));
+extern int _rl_bracketed_read_key PARAMS((void));
+extern int _rl_bracketed_read_mbstring PARAMS((char *, int));
 
 /* macro.c */
 extern void _rl_with_macro_input PARAMS((char *));
index 43aa4d97db1efee26d82cfa92d33d64dae3aff95..ff6ab6884a922724c9e68838f30a91abc8232276 100644 (file)
@@ -1,6 +1,6 @@
 /* text.c -- text handling commands for readline. */
 
-/* Copyright (C) 1987-2017 Free Software Foundation, Inc.
+/* Copyright (C) 1987-2019 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.      
@@ -1722,10 +1722,7 @@ _rl_char_search (int count, int fdir, int bdir)
 {
   int c;
 
-  RL_SETSTATE(RL_STATE_MOREINPUT);
-  c = rl_read_key ();
-  RL_UNSETSTATE(RL_STATE_MOREINPUT);
-
+  c = _rl_bracketed_read_key ();
   if (c < 0)
     return 1;
 
index 836371c95fff755e5bb9fc2faf8998310ef286ae..dd4c3e8c4848f36d0fbd7808da373cec0cdd88cd 100644 (file)
@@ -1,7 +1,7 @@
 /* vi_mode.c -- A vi emulation mode for Bash.
    Derived from code written by Jeff Sparkes (jsparkes@bnr.ca).  */
 
-/* Copyright (C) 1987-2018 Free Software Foundation, Inc.
+/* Copyright (C) 1987-2019 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.      
@@ -1316,13 +1316,7 @@ rl_domove_read_callback (_rl_vimotion_cxt *m)
 static int
 rl_vi_domove_getchar (_rl_vimotion_cxt *m)
 {
-  int c;
-
-  RL_SETSTATE(RL_STATE_MOREINPUT);
-  c = rl_read_key ();
-  RL_UNSETSTATE(RL_STATE_MOREINPUT);
-
-  return c;
+  return (_rl_bracketed_read_key ());
 }
 
 #if defined (READLINE_CALLBACKS)
@@ -2000,21 +1994,7 @@ _rl_vi_change_char (int count, int c, char *mb)
 static int
 _rl_vi_callback_getchar (char *mb, int mlen)
 {
-  int c;
-
-  RL_SETSTATE(RL_STATE_MOREINPUT);
-  c = rl_read_key ();
-  RL_UNSETSTATE(RL_STATE_MOREINPUT);
-
-  if (c < 0)
-    return -1;
-
-#if defined (HANDLE_MULTIBYTE)
-  if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
-    c = _rl_read_mbstring (c, mb, mlen);
-#endif
-
-  return c;
+  return (_rl_bracketed_read_mbstring (mb, mlen));
 }
 
 #if defined (READLINE_CALLBACKS)
@@ -2137,6 +2117,34 @@ rl_vi_overstrike_delete (int count, int key)
   return (0);
 }
 
+/* Read bracketed paste mode pasted text and insert it in overwrite mode */
+static int
+rl_vi_overstrike_bracketed_paste (int count, int key)
+{
+  int r;
+  char *pbuf;
+  size_t pblen;
+
+  pbuf = _rl_bracketed_text (&pblen);
+  if (pblen == 0)
+    {
+      xfree (pbuf);
+      return 0;
+    }
+  r = pblen;
+  while (--r >= 0)
+    _rl_unget_char ((unsigned char)pbuf[r]);
+  xfree (pbuf);
+
+  while (_rl_pushed_input_available ())
+    {
+      key = rl_read_key ();
+      r = rl_vi_overstrike (1, key);
+    }
+
+  return r;
+}
+
 int
 rl_vi_replace (int count, int key)
 {
@@ -2179,6 +2187,9 @@ rl_vi_replace (int count, int key)
   _rl_vi_last_key_before_insert = key;
   _rl_keymap = vi_replace_map;
 
+  if (_rl_enable_bracketed_paste)
+    rl_bind_keyseq_if_unbound (BRACK_PASTE_PREF, rl_vi_overstrike_bracketed_paste);
+
   return (0);
 }
 
diff --git a/subst.c b/subst.c
index 9bfff905a36ee325c5faa45ac625b69ed039ca5a..6660fa18b505baa902b3966796ef3165f1b67539 100644 (file)
--- a/subst.c
+++ b/subst.c
@@ -1155,6 +1155,18 @@ string_extract_verbatim (string, slen, sindex, charlist, flags)
       return temp;
     }
 
+  /* This can never be called with charlist == NULL. If *charlist == NULL,
+     we can skip the loop and just return a copy of the string, updating
+     *sindex */
+  if (*charlist == 0)
+    {
+      temp = string + *sindex;
+      c = (*sindex == 0) ? slen : STRLEN (temp);
+      temp = savestring (temp);
+      *sindex += c;
+      return temp;
+    }
+
   i = *sindex;
 #if defined (HANDLE_MULTIBYTE)
   wcharlist = 0;
@@ -2352,7 +2364,7 @@ split_at_delims (string, slen, delims, sentinel, flags, nwp, cwp)
 
       token = substring (string, ts, te);
 
-      ret = add_string_to_list (token, ret);
+      ret = add_string_to_list (token, ret);   /* XXX */
       free (token);
       nw++;
 
@@ -2778,7 +2790,7 @@ list_string (string, separators, quoted)
   WORD_LIST *result;
   WORD_DESC *t;
   char *current_word, *s;
-  int sindex, sh_style_split, whitesep, xflags;
+  int sindex, sh_style_split, whitesep, xflags, free_word;
   size_t slen;
 
   if (!string || !*string)
@@ -2800,7 +2812,14 @@ list_string (string, separators, quoted)
      STRING is quoted or if there are no separator characters. We use the
      Posix definition of whitespace as a member of the space character
      class in the current locale. */
+#if 0
   if (!quoted || !separators || !*separators)
+#else
+  /* issep() requires that separators be non-null, and always returns 0 if
+     separator is the empty string, so don't bother if we get an empty string
+     for separators. We already returned NULL above if STRING is empty. */
+  if (!quoted && separators && *separators)
+#endif
     {
       for (s = string; *s && issep (*s) && ifs_whitespace (*s); s++);
 
@@ -2824,6 +2843,8 @@ list_string (string, separators, quoted)
       if (current_word == 0)
        break;
 
+      free_word = 1;   /* If non-zero, we free current_word */
+
       /* If we have a quoted empty string, add a quoted null argument.  We
         want to preserve the quoted null character iff this is a quoted
         empty string; otherwise the quoted null characters are removed
@@ -2840,7 +2861,15 @@ list_string (string, separators, quoted)
          /* If we have something, then add it regardless.  However,
             perform quoted null character removal on the current word. */
          remove_quoted_nulls (current_word);
-         result = add_string_to_list (current_word, result);
+
+         /* We don't want to set the word flags based on the string contents
+            here -- that's mostly for the parser -- so we just allocate a
+            WORD_DESC *, assign current_word (noting that we don't want to
+            free it), and skip all of make_word. */
+         t = alloc_word_desc ();
+         t->word = current_word;
+         result = make_word_list (t, result);
+         free_word = 0;
          result->word->flags &= ~W_HASQUOTEDNULL;      /* just to be sure */
          if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
            result->word->flags |= W_QUOTED;
@@ -2860,7 +2889,8 @@ list_string (string, separators, quoted)
          result = make_word_list (t, result);
        }
 
-      free (current_word);
+      if (free_word)
+       free (current_word);
 
       /* Note whether or not the separator is IFS whitespace, used later. */
       whitesep = string[sindex] && ifs_whitesep (string[sindex]);
@@ -6119,7 +6149,7 @@ read_comsub (fd, quoted, flags, rflag)
        }
 
       /* Add the character to ISTRING, possibly after resizing it. */
-      RESIZE_MALLOCED_BUFFER (istring, istring_index, mb_cur_max+1, istring_size, DEFAULT_ARRAY_SIZE);
+      RESIZE_MALLOCED_BUFFER (istring, istring_index, mb_cur_max+1, istring_size, 512);
 
       /* This is essentially quote_string inline */
       if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) /* || c == CTLESC || c == CTLNUL */)
@@ -7191,9 +7221,9 @@ parameter_brace_expand_length (name)
   char *t, *newname;
   intmax_t number, arg_index;
   WORD_LIST *list;
-#if defined (ARRAY_VARS)
   SHELL_VAR *var;
-#endif
+
+  var = (SHELL_VAR *)NULL;
 
   if (name[1] == '\0')                 /* ${#} */
     number = number_of_args ();
@@ -7254,6 +7284,15 @@ parameter_brace_expand_length (name)
          number = MB_STRLEN (t);
        }
 #endif
+      /* Fast path for the common case of taking the length of a non-dynamic
+        scalar variable value. */
+      else if ((var || (var = find_variable (name + 1))) &&
+               invisible_p (var) == 0 &&
+               array_p (var) == 0 && assoc_p (var) == 0 &&
+               var->dynamic_value == 0)
+       number = value_cell (var) ? MB_STRLEN (value_cell (var)) : 0;
+      else if (var == 0 && unbound_vars_is_error == 0)
+       number = 0;
       else                             /* ${#PS1} */
        {
          newname = savestring (name);