]> git.ipfire.org Git - thirdparty/bash.git/commitdiff
commit bash-20110304 snapshot
authorChet Ramey <chet.ramey@case.edu>
Thu, 29 Dec 2011 18:04:46 +0000 (13:04 -0500)
committerChet Ramey <chet.ramey@case.edu>
Thu, 29 Dec 2011 18:04:46 +0000 (13:04 -0500)
24 files changed:
CWRU/CWRU.chlog
CWRU/CWRU.chlog~
MANIFEST
doc/bashref.texi
lib/readline/bind.c
lib/readline/display.c
lib/readline/display.c~ [new file with mode: 0644]
lib/readline/rltty.c
lib/readline/rltty.c~ [new file with mode: 0644]
parse.y
patchlevel.h
patchlevel.h~ [new file with mode: 0644]
subst.c
tests/RUN-ONE-TEST
tests/dollar-at-star
tests/dollar-at4.sub [new file with mode: 0644]
tests/dollar.right
tests/heredoc.right
tests/heredoc.tests
tests/heredoc2.sub [new file with mode: 0644]
tests/printf3.sub
tests/rhs-exp.right
tests/rhs-exp1.sub
variables.c

index 883718b532a462eeb4729a644e26cd8d363fdd45..b1ae0468ef25144a3bdcf35444201aa47a3e2bab 100644 (file)
@@ -11142,3 +11142,71 @@ support/shobj-conf
        - Tandem systems should use getpwnam (getlogin()); for some reason
          they don't do well with using getuid().  Fix from Joachim Schmitz
          <jojo@schmitz-digital.de>
+
+                                   3/1
+                                   ---
+variables.c
+       - make sure that the return value from find_variable is non-null
+         before trying to use it in chkexport.  Fixes bug reported by
+         Evangelos Foutras <foutrelis@gmail.com>
+
+                                   3/3
+                                   ---
+parse.y
+       - when adding $$ to the current token buffer in read_token_word(),
+         don't xmalloc a buffer for two characters and then strcpy it, just
+         copy the characters directly into the token buffer.  Fix from
+         Michael Whitten <mfwitten@gmail.com>
+
+execute_cmd.c
+       - fix expand_word_unsplit to add the W_NOSPLIT2 flag to the word to
+         be expanded, so "" doesn't add CTLNUL.  Similar to fix of 2/18 to
+         expand_string_for_rhs.  Fixes bug reported by Nathanael D. Noblet
+         <nathanael@gnat.ca> and Matthias Klose <doko@debian.org>
+
+parse.y
+       - fix extended_glob case of read_token_word to allocate an extra
+         space in the buffer for the next character read after the extended
+         glob specification if it's a CTLESC or CTLNUL.  Report and fix from
+         Michael Witten <mfwitten@gmail.com>
+       - fix shell expansions case of read_token_word to allocate an extra
+         space in the buffer for the next character read after the shell
+         expansion if it's a CTLESC or CTLNUL.  Report and fix from
+         Michael Witten <mfwitten@gmail.com>
+       - TENTATIVE: fix read_token_word to reduce the amount of buffer space
+         required to hold the translated and double-quoted value of $"..."
+         strings.  Report and fix from Michael Witten <mfwitten@gmail.com>
+       - change code around got_character and got_escaped_character labels to
+         make sure that we call RESIZE_MALLOCED_BUFFER before adding the
+         CTLESC before a CTLESC or CTLNUL, and before adding the character if
+         we're not adding a CTLESC.  Report and fix from
+         Michael Witten <mfwitten@gmail.com>
+
+subst.c
+       - new param flags value, PF_ASSIGNRHS, mirrors W_ASSIGNRHS, noting that
+         parameter expansion is on rhs of assignment statement.  That inhibits
+         word splitting
+       - change param_expand to call string_list_dollar_at with quoted == 1
+         if PF_ASSIGNRHS is set, so it will quote IFS characters in the
+         positional parameter before separating them with the first char of
+         $IFS.  This keeps the rhs from being split inappropriately.  Fixes
+         bug reported by Andres Perera <andres.p@zoho.com>
+
+                                   3/4
+                                   ---
+lib/readline/bind.c
+       - add a missing free of `names' in rl_function_dumper.  Bug report
+         and fix from Michael Snyder <msnyder@vmware.com>
+
+                                   3/5
+                                   ---
+lib/readline/rltty.c
+       - change rl_deprep_terminal so it uses fileno (stdin) for the tty fd
+         if rl_instream is not set, like rl_prep_terminal
+
+                                   3/6
+                                   ---
+lib/readline/display.c
+       - fix rl_message to use a dynamically-allocated buffer instead of a
+         fixed-size buffer of 128 chars for the `local message prompt'.  Bug
+         report and fix from Micah Cowan <micah@cowan.name>
index 3586b01ba8889b24676dc3ecc772367bec4ee279..4193526e1f10ce4b93c2dce35edfa84cff042e50 100644 (file)
@@ -11137,3 +11137,76 @@ execute_cmd.c
 support/shobj-conf
        - add a stanza for nsk on the Tandem from Joachim Schmitz
          <jojo@schmitz-digital.de>
+
+{shell,lib/readline/shell}.c
+       - Tandem systems should use getpwnam (getlogin()); for some reason
+         they don't do well with using getuid().  Fix from Joachim Schmitz
+         <jojo@schmitz-digital.de>
+
+                                   3/1
+                                   ---
+variables.c
+       - make sure that the return value from find_variable is non-null
+         before trying to use it in chkexport.  Fixes bug reported by
+         Evangelos Foutras <foutrelis@gmail.com>
+
+                                   3/3
+                                   ---
+parse.y
+       - when adding $$ to the current token buffer in read_token_word(),
+         don't xmalloc a buffer for two characters and then strcpy it, just
+         copy the characters directly into the token buffer.  Fix from
+         Michael Whitten <mfwitten@gmail.com>
+
+execute_cmd.c
+       - fix expand_word_unsplit to add the W_NOSPLIT2 flag to the word to
+         be expanded, so "" doesn't add CTLNUL.  Similar to fix of 2/18 to
+         expand_string_for_rhs.  Fixes bug reported by Nathanael D. Noblet
+         <nathanael@gnat.ca>
+
+parse.y
+       - fix extended_glob case of read_token_word to allocate an extra
+         space in the buffer for the next character read after the extended
+         glob specification if it's a CTLESC or CTLNUL.  Report and fix from
+         Michael Witten <mfwitten@gmail.com>
+       - fix shell expansions case of read_token_word to allocate an extra
+         space in the buffer for the next character read after the shell
+         expansion if it's a CTLESC or CTLNUL.  Report and fix from
+         Michael Witten <mfwitten@gmail.com>
+       - TENTATIVE: fix read_token_word to reduce the amount of buffer space
+         required to hold the translated and double-quoted value of $"..."
+         strings.  Report and fix from Michael Witten <mfwitten@gmail.com>
+       - change code around got_character and got_escaped_character labels to
+         make sure that we call RESIZE_MALLOCED_BUFFER before adding the
+         CTLESC before a CTLESC or CTLNUL, and before adding the character if
+         we're not adding a CTLESC.  Report and fix from
+         Michael Witten <mfwitten@gmail.com>
+
+subst.c
+       - new param flags value, PF_ASSIGNRHS, mirrors W_ASSIGNRHS, noting that
+         parameter expansion is on rhs of assignment statement.  That inhibits
+         word splitting
+       - change param_expand to call string_list_dollar_at with quoted == 1
+         if PF_ASSIGNRHS is set, so it will quote IFS characters in the
+         positional parameter before separating them with the first char of
+         $IFS.  This keeps the rhs from being split inappropriately.  Fixes
+         bug reported by Andres Perera <andres.p@zoho.com>
+
+                                   3/4
+                                   ---
+lib/readline/bind.c
+       - add a missing free of `names' in rl_function_dumper.  Bug report
+         and fix from Michael Snyder <msnyder@vmware.com>
+
+                                   3/5
+                                   ---
+lib/readline/rltty.c
+       - change rl_deprep_terminal so it uses fileno (stdin) for the tty fd
+         if rl_instream is not set, like rl_prep_terminal
+
+                                   3/6
+                                   ---
+lib/readline/display.c
+       - fix rl_message to use a dynamically-allocated buffer instead of a
+         fixed-size buffer of 128 chars for the `local message prompt'.  Bug
+         report and fix from Micah Cowan <micah@cowan.name>
index 72eed78b0c107907b4015dff97f8d598cf6782f4..1cf164e539fe7d30b75f184b22394d3be2b5d679 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -828,6 +828,7 @@ tests/dollar-at-star        f
 tests/dollar-at1.sub   f
 tests/dollar-at2.sub   f
 tests/dollar-at3.sub   f
+tests/dollar-at4.sub   f
 tests/dollar-star1.sub f
 tests/dollar-star2.sub f
 tests/dollar-star3.sub f
@@ -889,6 +890,7 @@ tests/globstar1.sub f
 tests/heredoc.tests    f
 tests/heredoc.right    f
 tests/heredoc1.sub     f
+tests/heredoc2.sub     f
 tests/herestr.tests    f
 tests/herestr.right    f
 tests/histexp.tests    f
index 726b6aca1932eb8ace4cf70f149bf57b5c138a7b..732b5c79df93043bcdf7aa9f4fb7b30d874b6fc9 100644 (file)
@@ -6236,7 +6236,7 @@ There is no maximum
 limit on the size of an array, nor any requirement that members
 be indexed or assigned contiguously.
 Indexed arrays are referenced using integers (including arithmetic
-expressions (@pxref{Shell Arithmetic}) and are zero-based;
+expressions (@pxref{Shell Arithmetic})) and are zero-based;
 associative arrays use arbitrary strings.
 
 An indexed array is created automatically if any variable is assigned to
index 59e7964366f89a7e20a262f518c81a0150536f95..07797ee755afe2d800e5496cf7218c7bb332ac40 100644 (file)
@@ -2167,6 +2167,8 @@ rl_function_dumper (print_readably)
            }
        }
     }
+
+  xfree (names);
 }
 
 /* Print all of the current functions and their bindings to
index e4105ee8ab1f6bf75709b602402fe8789d926d5b..d73559714b8706129d2c3790a5c06bf891b2a2eb 100644 (file)
@@ -176,7 +176,8 @@ int _rl_vis_botlin = 0;
 static int last_lmargin;
 
 /* A buffer for `modeline' messages. */
-static char msg_buf[128];
+static char *msg_buf = 0;
+static int msg_bufsiz = 0;
 
 /* Non-zero forces the redisplay even if we thought it was unnecessary. */
 static int forced_display;
@@ -2136,6 +2137,9 @@ rl_message (va_alist)
 #if defined (PREFER_VARARGS)
   char *format;
 #endif
+#if defined (HAVE_VSNPRINTF)
+  int bneed;
+#endif
 
 #if defined (PREFER_STDARG)
   va_start (args, format);
@@ -2144,11 +2148,28 @@ rl_message (va_alist)
   format = va_arg (args, char *);
 #endif
 
+  if (msg_buf == 0)
+    msg_buf = xmalloc (msg_bufsiz = 128);
+
 #if defined (HAVE_VSNPRINTF)
-  vsnprintf (msg_buf, sizeof (msg_buf) - 1, format, args);
+  bneed = vsnprintf (msg_buf, msg_bufsiz - 1, format, args);
+  if (bneed >= msg_bufsiz - 1)
+    {
+      msg_bufsiz = bneed + 1;
+      msg_buf = xrealloc (msg_buf, msg_bufsiz);
+      va_end (args);
+
+#if defined (PREFER_STDARG)
+      va_start (args, format);
+#else
+      va_start (args);
+      format = va_arg (args, char *);
+#endif
+      vsnprintf (msg_buf, msg_bufsiz - 1, format, args);
+    }
 #else
   vsprintf (msg_buf, format, args);
-  msg_buf[sizeof(msg_buf) - 1] = '\0'; /* overflow? */
+  msg_buf[msg_bufsiz - 1] = '\0';      /* overflow? */
 #endif
   va_end (args);
 
@@ -2173,8 +2194,11 @@ int
 rl_message (format, arg1, arg2)
      char *format;
 {
+  if (msg_buf == 0)
+    msg_buf = xmalloc (msg_bufsiz = 128);
+
   sprintf (msg_buf, format, arg1, arg2);
-  msg_buf[sizeof(msg_buf) - 1] = '\0'; /* overflow? */
+  msg_buf[msg_bufsiz - 1] = '\0';      /* overflow? */
 
   rl_display_prompt = msg_buf;
   if (saved_local_prompt == 0)
diff --git a/lib/readline/display.c~ b/lib/readline/display.c~
new file mode 100644 (file)
index 0000000..e4105ee
--- /dev/null
@@ -0,0 +1,2688 @@
+/* display.c -- readline redisplay facility. */
+
+/* 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>
+#endif /* HAVE_UNISTD_H */
+
+#include "posixstat.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"
+#include "rlmbutil.h"
+
+/* Termcap library stuff. */
+#include "tcap.h"
+
+/* Some standard library routines. */
+#include "readline.h"
+#include "history.h"
+
+#include "rlprivate.h"
+#include "xmalloc.h"
+
+#if !defined (strchr) && !defined (__STDC__)
+extern char *strchr (), *strrchr ();
+#endif /* !strchr && !__STDC__ */
+
+static void update_line PARAMS((char *, char *, int, int, int, int));
+static void space_to_eol PARAMS((int));
+static void delete_chars PARAMS((int));
+static void insert_some_chars PARAMS((char *, int, int));
+static void cr PARAMS((void));
+
+/* State of visible and invisible lines. */
+struct line_state
+  {
+    char *line;
+    int *lbreaks;
+    int lbsize;
+#if defined (HANDLE_MULTIBYTE)
+    int *wrapped_line;
+    int wbsize;
+#endif
+  };
+
+/* The line display buffers.  One is the line currently displayed on
+   the screen.  The other is the line about to be displayed. */
+static struct line_state line_state_array[2];
+static struct line_state *line_state_visible = &line_state_array[0];
+static struct line_state *line_state_invisible = &line_state_array[1];
+static int line_structures_initialized = 0;
+
+/* Backwards-compatible names. */
+#define inv_lbreaks    (line_state_invisible->lbreaks)
+#define inv_lbsize     (line_state_invisible->lbsize)
+#define vis_lbreaks    (line_state_visible->lbreaks)
+#define vis_lbsize     (line_state_visible->lbsize)
+
+#define visible_line   (line_state_visible->line)
+#define invisible_line (line_state_invisible->line)
+
+#if defined (HANDLE_MULTIBYTE)
+static int _rl_col_width PARAMS((const char *, int, int, int));
+#else
+#  define _rl_col_width(l, s, e, f)    (((e) <= (s)) ? 0 : (e) - (s))
+#endif
+
+/* Heuristic used to decide whether it is faster to move from CUR to NEW
+   by backing up or outputting a carriage return and moving forward.  CUR
+   and NEW are either both buffer positions or absolute screen positions. */
+#define CR_FASTER(new, cur) (((new) + 1) < ((cur) - (new)))
+
+/* _rl_last_c_pos is an absolute cursor position in multibyte locales and a
+   buffer index in others.  This macro is used when deciding whether the
+   current cursor position is in the middle of a prompt string containing
+   invisible characters.  XXX - might need to take `modmark' into account. */
+#define PROMPT_ENDING_INDEX \
+  ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) ? prompt_physical_chars : prompt_last_invisible+1)
+  
+
+/* **************************************************************** */
+/*                                                                 */
+/*                     Display stuff                               */
+/*                                                                 */
+/* **************************************************************** */
+
+/* This is the stuff that is hard for me.  I never seem to write good
+   display routines in C.  Let's see how I do this time. */
+
+/* (PWP) Well... Good for a simple line updater, but totally ignores
+   the problems of input lines longer than the screen width.
+
+   update_line and the code that calls it makes a multiple line,
+   automatically wrapping line update.  Careful attention needs
+   to be paid to the vertical position variables. */
+
+/* Keep two buffers; one which reflects the current contents of the
+   screen, and the other to draw what we think the new contents should
+   be.  Then compare the buffers, and make whatever changes to the
+   screen itself that we should.  Finally, make the buffer that we
+   just drew into be the one which reflects the current contents of the
+   screen, and place the cursor where it belongs.
+
+   Commands that want to can fix the display themselves, and then let
+   this function know that the display has been fixed by setting the
+   RL_DISPLAY_FIXED variable.  This is good for efficiency. */
+
+/* Application-specific redisplay function. */
+rl_voidfunc_t *rl_redisplay_function = rl_redisplay;
+
+/* Global variables declared here. */
+/* What YOU turn on when you have handled all redisplay yourself. */
+int rl_display_fixed = 0;
+
+int _rl_suppress_redisplay = 0;
+int _rl_want_redisplay = 0;
+
+/* The stuff that gets printed out before the actual text of the line.
+   This is usually pointing to rl_prompt. */
+char *rl_display_prompt = (char *)NULL;
+
+/* Pseudo-global variables declared here. */
+
+/* The visible cursor position.  If you print some text, adjust this. */
+/* NOTE: _rl_last_c_pos is used as a buffer index when not in a locale
+   supporting multibyte characters, and an absolute cursor position when
+   in such a locale.  This is an artifact of the donated multibyte support.
+   Care must be taken when modifying its value. */
+int _rl_last_c_pos = 0;
+int _rl_last_v_pos = 0;
+
+static int cpos_adjusted;
+static int cpos_buffer_position;
+static int prompt_multibyte_chars;
+
+/* Number of lines currently on screen minus 1. */
+int _rl_vis_botlin = 0;
+
+/* Variables used only in this file. */
+/* The last left edge of text that was displayed.  This is used when
+   doing horizontal scrolling.  It shifts in thirds of a screenwidth. */
+static int last_lmargin;
+
+/* A buffer for `modeline' messages. */
+static char msg_buf[128];
+
+/* Non-zero forces the redisplay even if we thought it was unnecessary. */
+static int forced_display;
+
+/* Default and initial buffer size.  Can grow. */
+static int line_size = 1024;
+
+/* Variables to keep track of the expanded prompt string, which may
+   include invisible characters. */
+
+static char *local_prompt, *local_prompt_prefix;
+static int local_prompt_len;
+static int prompt_visible_length, prompt_prefix_length;
+
+/* The number of invisible characters in the line currently being
+   displayed on the screen. */
+static int visible_wrap_offset;
+
+/* The number of invisible characters in the prompt string.  Static so it
+   can be shared between rl_redisplay and update_line */
+static int wrap_offset;
+
+/* The index of the last invisible character in the prompt string. */
+static int prompt_last_invisible;
+
+/* The length (buffer offset) of the first line of the last (possibly
+   multi-line) buffer displayed on the screen. */
+static int visible_first_line_len;
+
+/* Number of invisible characters on the first physical line of the prompt.
+   Only valid when the number of physical characters in the prompt exceeds
+   (or is equal to) _rl_screenwidth. */
+static int prompt_invis_chars_first_line;
+
+static int prompt_last_screen_line;
+
+static int prompt_physical_chars;
+
+/* set to a non-zero value by rl_redisplay if we are marking modified history
+   lines and the current line is so marked. */
+static int modmark;
+
+/* Variables to save and restore prompt and display information. */
+
+/* These are getting numerous enough that it's time to create a struct. */
+
+static char *saved_local_prompt;
+static char *saved_local_prefix;
+static int saved_last_invisible;
+static int saved_visible_length;
+static int saved_prefix_length;
+static int saved_local_length;
+static int saved_invis_chars_first_line;
+static int saved_physical_chars;
+
+/* Expand the prompt string S and return the number of visible
+   characters in *LP, if LP is not null.  This is currently more-or-less
+   a placeholder for expansion.  LIP, if non-null is a place to store the
+   index of the last invisible character in the returned string. NIFLP,
+   if non-zero, is a place to store the number of invisible characters in
+   the first prompt line.  The previous are used as byte counts -- indexes
+   into a character buffer. */
+
+/* Current implementation:
+       \001 (^A) start non-visible characters
+       \002 (^B) end non-visible characters
+   all characters except \001 and \002 (following a \001) are copied to
+   the returned string; all characters except those between \001 and
+   \002 are assumed to be `visible'. */        
+
+static char *
+expand_prompt (pmt, lp, lip, niflp, vlp)
+     char *pmt;
+     int *lp, *lip, *niflp, *vlp;
+{
+  char *r, *ret, *p, *igstart;
+  int l, rl, last, ignoring, ninvis, invfl, invflset, ind, pind, physchars;
+
+  /* Short-circuit if we can. */
+  if ((MB_CUR_MAX <= 1 || rl_byte_oriented) && strchr (pmt, RL_PROMPT_START_IGNORE) == 0)
+    {
+      r = savestring (pmt);
+      if (lp)
+       *lp = strlen (r);
+      if (lip)
+       *lip = 0;
+      if (niflp)
+       *niflp = 0;
+      if (vlp)
+       *vlp = lp ? *lp : strlen (r);
+      return r;
+    }
+
+  l = strlen (pmt);
+  r = ret = (char *)xmalloc (l + 1);
+
+  invfl = 0;   /* invisible chars in first line of prompt */
+  invflset = 0;        /* we only want to set invfl once */
+
+  igstart = 0;
+  for (rl = ignoring = last = ninvis = physchars = 0, p = pmt; p && *p; p++)
+    {
+      /* This code strips the invisible character string markers
+        RL_PROMPT_START_IGNORE and RL_PROMPT_END_IGNORE */
+      if (ignoring == 0 && *p == RL_PROMPT_START_IGNORE)               /* XXX - check ignoring? */
+       {
+         ignoring = 1;
+         igstart = p;
+         continue;
+       }
+      else if (ignoring && *p == RL_PROMPT_END_IGNORE)
+       {
+         ignoring = 0;
+         if (p != (igstart + 1))
+           last = r - ret - 1;
+         continue;
+       }
+      else
+       {
+#if defined (HANDLE_MULTIBYTE)
+         if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+           {
+             pind = p - pmt;
+             ind = _rl_find_next_mbchar (pmt, pind, 1, MB_FIND_NONZERO);
+             l = ind - pind;
+             while (l--)
+               *r++ = *p++;
+             if (!ignoring)
+               {
+                 /* rl ends up being assigned to prompt_visible_length,
+                    which is the number of characters in the buffer that
+                    contribute to characters on the screen, which might
+                    not be the same as the number of physical characters
+                    on the screen in the presence of multibyte characters */
+                 rl += ind - pind;
+                 physchars += _rl_col_width (pmt, pind, ind, 0);
+               }
+             else
+               ninvis += ind - pind;
+             p--;                      /* compensate for later increment */
+           }
+         else
+#endif
+           {
+             *r++ = *p;
+             if (!ignoring)
+               {
+                 rl++;                 /* visible length byte counter */
+                 physchars++;
+               }
+             else
+               ninvis++;               /* invisible chars byte counter */
+           }
+
+         if (invflset == 0 && rl >= _rl_screenwidth)
+           {
+             invfl = ninvis;
+             invflset = 1;
+           }
+       }
+    }
+
+  if (rl < _rl_screenwidth)
+    invfl = ninvis;
+
+  *r = '\0';
+  if (lp)
+    *lp = rl;
+  if (lip)
+    *lip = last;
+  if (niflp)
+    *niflp = invfl;
+  if  (vlp)
+    *vlp = physchars;
+  return ret;
+}
+
+/* Just strip out RL_PROMPT_START_IGNORE and RL_PROMPT_END_IGNORE from
+   PMT and return the rest of PMT. */
+char *
+_rl_strip_prompt (pmt)
+     char *pmt;
+{
+  char *ret;
+
+  ret = expand_prompt (pmt, (int *)NULL, (int *)NULL, (int *)NULL, (int *)NULL);
+  return ret;
+}
+
+/*
+ * Expand the prompt string into the various display components, if
+ * necessary.
+ *
+ * local_prompt = expanded last line of string in rl_display_prompt
+ *               (portion after the final newline)
+ * local_prompt_prefix = portion before last newline of rl_display_prompt,
+ *                      expanded via expand_prompt
+ * prompt_visible_length = number of visible characters in local_prompt
+ * prompt_prefix_length = number of visible characters in local_prompt_prefix
+ *
+ * This function is called once per call to readline().  It may also be
+ * called arbitrarily to expand the primary prompt.
+ *
+ * The return value is the number of visible characters on the last line
+ * of the (possibly multi-line) prompt.
+ */
+int
+rl_expand_prompt (prompt)
+     char *prompt;
+{
+  char *p, *t;
+  int c;
+
+  /* Clear out any saved values. */
+  FREE (local_prompt);
+  FREE (local_prompt_prefix);
+
+  local_prompt = local_prompt_prefix = (char *)0;
+  local_prompt_len = 0;
+  prompt_last_invisible = prompt_invis_chars_first_line = 0;
+  prompt_visible_length = prompt_physical_chars = 0;
+
+  if (prompt == 0 || *prompt == 0)
+    return (0);
+
+  p = strrchr (prompt, '\n');
+  if (!p)
+    {
+      /* The prompt is only one logical line, though it might wrap. */
+      local_prompt = expand_prompt (prompt, &prompt_visible_length,
+                                           &prompt_last_invisible,
+                                           &prompt_invis_chars_first_line,
+                                           &prompt_physical_chars);
+      local_prompt_prefix = (char *)0;
+      local_prompt_len = local_prompt ? strlen (local_prompt) : 0;
+      return (prompt_visible_length);
+    }
+  else
+    {
+      /* The prompt spans multiple lines. */
+      t = ++p;
+      local_prompt = expand_prompt (p, &prompt_visible_length,
+                                      &prompt_last_invisible,
+                                      &prompt_invis_chars_first_line,
+                                      &prompt_physical_chars);
+      c = *t; *t = '\0';
+      /* The portion of the prompt string up to and including the
+        final newline is now null-terminated. */
+      local_prompt_prefix = expand_prompt (prompt, &prompt_prefix_length,
+                                                  (int *)NULL,
+                                                  (int *)NULL,
+                                                  (int *)NULL);
+      *t = c;
+      local_prompt_len = local_prompt ? strlen (local_prompt) : 0;
+      return (prompt_prefix_length);
+    }
+}
+
+/* Initialize the VISIBLE_LINE and INVISIBLE_LINE arrays, and their associated
+   arrays of line break markers.  MINSIZE is the minimum size of VISIBLE_LINE
+   and INVISIBLE_LINE; if it is greater than LINE_SIZE, LINE_SIZE is
+   increased.  If the lines have already been allocated, this ensures that
+   they can hold at least MINSIZE characters. */
+static void
+init_line_structures (minsize)
+      int minsize;
+{
+  register int n;
+
+  if (invisible_line == 0)     /* initialize it */
+    {
+      if (line_size < minsize)
+       line_size = minsize;
+      visible_line = (char *)xmalloc (line_size);
+      invisible_line = (char *)xmalloc (line_size);
+    }
+  else if (line_size < minsize)        /* ensure it can hold MINSIZE chars */
+    {
+      line_size *= 2;
+      if (line_size < minsize)
+       line_size = minsize;
+      visible_line = (char *)xrealloc (visible_line, line_size);
+      invisible_line = (char *)xrealloc (invisible_line, line_size);
+    }
+
+  for (n = minsize; n < line_size; n++)
+    {
+      visible_line[n] = 0;
+      invisible_line[n] = 1;
+    }
+
+  if (vis_lbreaks == 0)
+    {
+      /* should be enough. */
+      inv_lbsize = vis_lbsize = 256;
+
+#if defined (HANDLE_MULTIBYTE)
+      line_state_visible->wbsize = vis_lbsize;
+      line_state_visible->wrapped_line = (int *)xmalloc (line_state_visible->wbsize * sizeof (int));
+
+      line_state_invisible->wbsize = inv_lbsize;
+      line_state_invisible->wrapped_line = (int *)xmalloc (line_state_invisible->wbsize * sizeof (int));
+#endif
+
+      inv_lbreaks = (int *)xmalloc (inv_lbsize * sizeof (int));
+      vis_lbreaks = (int *)xmalloc (vis_lbsize * sizeof (int));
+      inv_lbreaks[0] = vis_lbreaks[0] = 0;
+    }
+
+  line_structures_initialized = 1;
+}
+  
+/* Basic redisplay algorithm. */
+void
+rl_redisplay ()
+{
+  register int in, out, c, linenum, cursor_linenum;
+  register char *line;
+  int inv_botlin, lb_botlin, lb_linenum, o_cpos;
+  int newlines, lpos, temp, n0, num, prompt_lines_estimate;
+  char *prompt_this_line;
+#if defined (HANDLE_MULTIBYTE)
+  wchar_t wc;
+  size_t wc_bytes;
+  int wc_width;
+  mbstate_t ps;
+  int _rl_wrapped_multicolumn = 0;
+#endif
+
+  if (_rl_echoing_p == 0)
+    return;
+
+  /* Block keyboard interrupts because this function manipulates global
+     data structures. */
+  _rl_block_sigint ();  
+  RL_SETSTATE (RL_STATE_REDISPLAYING);
+
+  if (!rl_display_prompt)
+    rl_display_prompt = "";
+
+  if (line_structures_initialized == 0)
+    {
+      init_line_structures (0);
+      rl_on_new_line ();
+    }
+
+  /* Draw the line into the buffer. */
+  cpos_buffer_position = -1;
+
+  prompt_multibyte_chars = prompt_visible_length - prompt_physical_chars;
+
+  line = invisible_line;
+  out = inv_botlin = 0;
+
+  /* Mark the line as modified or not.  We only do this for history
+     lines. */
+  modmark = 0;
+  if (_rl_mark_modified_lines && current_history () && rl_undo_list)
+    {
+      line[out++] = '*';
+      line[out] = '\0';
+      modmark = 1;
+    }
+
+  /* If someone thought that the redisplay was handled, but the currently
+     visible line has a different modification state than the one about
+     to become visible, then correct the caller's misconception. */
+  if (visible_line[0] != invisible_line[0])
+    rl_display_fixed = 0;
+
+  /* If the prompt to be displayed is the `primary' readline prompt (the
+     one passed to readline()), use the values we have already expanded.
+     If not, use what's already in rl_display_prompt.  WRAP_OFFSET is the
+     number of non-visible characters in the prompt string. */
+  if (rl_display_prompt == rl_prompt || local_prompt)
+    {
+      if (local_prompt_prefix && forced_display)
+       _rl_output_some_chars (local_prompt_prefix, strlen (local_prompt_prefix));
+
+      if (local_prompt_len > 0)
+       {
+         temp = local_prompt_len + out + 2;
+         if (temp >= line_size)
+           {
+             line_size = (temp + 1024) - (temp % 1024);
+             visible_line = (char *)xrealloc (visible_line, line_size);
+             line = invisible_line = (char *)xrealloc (invisible_line, line_size);
+           }
+         strncpy (line + out, local_prompt, local_prompt_len);
+         out += local_prompt_len;
+       }
+      line[out] = '\0';
+      wrap_offset = local_prompt_len - prompt_visible_length;
+    }
+  else
+    {
+      int pmtlen;
+      prompt_this_line = strrchr (rl_display_prompt, '\n');
+      if (!prompt_this_line)
+       prompt_this_line = rl_display_prompt;
+      else
+       {
+         prompt_this_line++;
+         pmtlen = prompt_this_line - rl_display_prompt;        /* temp var */
+         if (forced_display)
+           {
+             _rl_output_some_chars (rl_display_prompt, pmtlen);
+             /* Make sure we are at column zero even after a newline,
+                regardless of the state of terminal output processing. */
+             if (pmtlen < 2 || prompt_this_line[-2] != '\r')
+               cr ();
+           }
+       }
+
+      prompt_physical_chars = pmtlen = strlen (prompt_this_line);
+      temp = pmtlen + out + 2;
+      if (temp >= line_size)
+       {
+         line_size = (temp + 1024) - (temp % 1024);
+         visible_line = (char *)xrealloc (visible_line, line_size);
+         line = invisible_line = (char *)xrealloc (invisible_line, line_size);
+       }
+      strncpy (line + out,  prompt_this_line, pmtlen);
+      out += pmtlen;
+      line[out] = '\0';
+      wrap_offset = prompt_invis_chars_first_line = 0;
+    }
+
+#define CHECK_INV_LBREAKS() \
+      do { \
+       if (newlines >= (inv_lbsize - 2)) \
+         { \
+           inv_lbsize *= 2; \
+           inv_lbreaks = (int *)xrealloc (inv_lbreaks, inv_lbsize * sizeof (int)); \
+         } \
+      } while (0)
+
+#if defined (HANDLE_MULTIBYTE)   
+#define CHECK_LPOS() \
+      do { \
+       lpos++; \
+       if (lpos >= _rl_screenwidth) \
+         { \
+           if (newlines >= (inv_lbsize - 2)) \
+             { \
+               inv_lbsize *= 2; \
+               inv_lbreaks = (int *)xrealloc (inv_lbreaks, inv_lbsize * sizeof (int)); \
+             } \
+           inv_lbreaks[++newlines] = out; \
+           if (newlines >= (line_state_invisible->wbsize - 1)) \
+             { \
+               line_state_invisible->wbsize *= 2; \
+               line_state_invisible->wrapped_line = (int *)xrealloc (line_state_invisible->wrapped_line, line_state_invisible->wbsize * sizeof(int)); \
+             } \
+           line_state_invisible->wrapped_line[newlines] = _rl_wrapped_multicolumn; \
+           lpos = 0; \
+         } \
+      } while (0)
+#else
+#define CHECK_LPOS() \
+      do { \
+       lpos++; \
+       if (lpos >= _rl_screenwidth) \
+         { \
+           if (newlines >= (inv_lbsize - 2)) \
+             { \
+               inv_lbsize *= 2; \
+               inv_lbreaks = (int *)xrealloc (inv_lbreaks, inv_lbsize * sizeof (int)); \
+             } \
+           inv_lbreaks[++newlines] = out; \
+           lpos = 0; \
+         } \
+      } while (0)
+#endif
+
+  /* inv_lbreaks[i] is where line i starts in the buffer. */
+  inv_lbreaks[newlines = 0] = 0;
+  lpos = prompt_physical_chars + modmark;
+
+#if defined (HANDLE_MULTIBYTE)
+  memset (line_state_invisible->wrapped_line, 0, line_state_invisible->wbsize * sizeof (int));
+  num = 0;
+#endif
+
+  /* prompt_invis_chars_first_line is the number of invisible characters in
+     the first physical line of the prompt.
+     wrap_offset - prompt_invis_chars_first_line is the number of invis
+     chars on the second (or, more generally, last) line. */
+
+  /* This is zero-based, used to set the newlines */
+  prompt_lines_estimate = lpos / _rl_screenwidth;
+
+  /* what if lpos is already >= _rl_screenwidth before we start drawing the
+     contents of the command line? */
+  while (lpos >= _rl_screenwidth)
+    {
+      int z;
+      /* fix from Darin Johnson <darin@acuson.com> for prompt string with
+         invisible characters that is longer than the screen width.  The
+         prompt_invis_chars_first_line variable could be made into an array
+         saying how many invisible characters there are per line, but that's
+         probably too much work for the benefit gained.  How many people have
+         prompts that exceed two physical lines?
+         Additional logic fix from Edward Catmur <ed@catmur.co.uk> */
+#if defined (HANDLE_MULTIBYTE)
+      if (MB_CUR_MAX > 1 && rl_byte_oriented == 0 && prompt_multibyte_chars > 0)
+       {
+         n0 = num;
+          temp = local_prompt_len;
+          while (num < temp)
+           {
+             z = _rl_col_width  (local_prompt, n0, num, 1);
+             if (z > _rl_screenwidth)
+               {
+                 num = _rl_find_prev_mbchar (local_prompt, num, MB_FIND_ANY);
+                 break;
+               }
+             else if (z == _rl_screenwidth)
+               break;
+             num++;
+           }
+          temp = num;
+       }
+      else
+#endif /* !HANDLE_MULTIBYTE */
+       temp = ((newlines + 1) * _rl_screenwidth);
+
+      /* Now account for invisible characters in the current line. */
+      /* XXX - this assumes that the invisible characters may be split, but only
+        between the first and the last lines. */
+      temp += ((local_prompt_prefix == 0) ? ((newlines == 0) ? prompt_invis_chars_first_line
+                                                            : ((newlines == prompt_lines_estimate) ? wrap_offset : prompt_invis_chars_first_line))
+                                         : ((newlines == 0) ? wrap_offset : 0));
+             
+      inv_lbreaks[++newlines] = temp;
+#if defined (HANDLE_MULTIBYTE)
+      if (MB_CUR_MAX > 1 && rl_byte_oriented == 0 && prompt_multibyte_chars > 0)
+       lpos -= _rl_col_width (local_prompt, n0, num, 1);
+      else
+#endif
+       lpos -= _rl_screenwidth;
+    }
+
+  prompt_last_screen_line = newlines;
+
+  /* Draw the rest of the line (after the prompt) into invisible_line, keeping
+     track of where the cursor is (cpos_buffer_position), the number of the line containing
+     the cursor (lb_linenum), the last line number (lb_botlin and inv_botlin).
+     It maintains an array of line breaks for display (inv_lbreaks).
+     This handles expanding tabs for display and displaying meta characters. */
+  lb_linenum = 0;
+#if defined (HANDLE_MULTIBYTE)
+  in = 0;
+  if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+    {
+      memset (&ps, 0, sizeof (mbstate_t));
+      /* XXX - what if wc_bytes ends up <= 0? check for MB_INVALIDCH */
+      wc_bytes = mbrtowc (&wc, rl_line_buffer, rl_end, &ps);
+    }
+  else
+    wc_bytes = 1;
+  while (in < rl_end)
+#else
+  for (in = 0; in < rl_end; in++)
+#endif
+    {
+      c = (unsigned char)rl_line_buffer[in];
+
+#if defined (HANDLE_MULTIBYTE)
+      if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+       {
+         if (MB_INVALIDCH (wc_bytes))
+           {
+             /* Byte sequence is invalid or shortened.  Assume that the
+                first byte represents a character. */
+             wc_bytes = 1;
+             /* Assume that a character occupies a single column. */
+             wc_width = 1;
+             memset (&ps, 0, sizeof (mbstate_t));
+           }
+         else if (MB_NULLWCH (wc_bytes))
+           break;                      /* Found '\0' */
+         else
+           {
+             temp = wcwidth (wc);
+             wc_width = (temp >= 0) ? temp : 1;
+           }
+       }
+#endif
+
+      if (out + 8 >= line_size)                /* XXX - 8 for \t */
+       {
+         line_size *= 2;
+         visible_line = (char *)xrealloc (visible_line, line_size);
+         invisible_line = (char *)xrealloc (invisible_line, line_size);
+         line = invisible_line;
+       }
+
+      if (in == rl_point)
+       {
+         cpos_buffer_position = out;
+         lb_linenum = newlines;
+       }
+
+#if defined (HANDLE_MULTIBYTE)
+      if (META_CHAR (c) && _rl_output_meta_chars == 0) /* XXX - clean up */
+#else
+      if (META_CHAR (c))
+#endif
+       {
+         if (_rl_output_meta_chars == 0)
+           {
+             sprintf (line + out, "\\%o", c);
+
+             if (lpos + 4 >= _rl_screenwidth)
+               {
+                 temp = _rl_screenwidth - lpos;
+                 CHECK_INV_LBREAKS ();
+                 inv_lbreaks[++newlines] = out + temp;
+                 lpos = 4 - temp;
+               }
+             else
+               lpos += 4;
+
+             out += 4;
+           }
+         else
+           {
+             line[out++] = c;
+             CHECK_LPOS();
+           }
+       }
+#if defined (DISPLAY_TABS)
+      else if (c == '\t')
+       {
+         register int newout;
+
+#if 0
+         newout = (out | (int)7) + 1;
+#else
+         newout = out + 8 - lpos % 8;
+#endif
+         temp = newout - out;
+         if (lpos + temp >= _rl_screenwidth)
+           {
+             register int temp2;
+             temp2 = _rl_screenwidth - lpos;
+             CHECK_INV_LBREAKS ();
+             inv_lbreaks[++newlines] = out + temp2;
+             lpos = temp - temp2;
+             while (out < newout)
+               line[out++] = ' ';
+           }
+         else
+           {
+             while (out < newout)
+               line[out++] = ' ';
+             lpos += temp;
+           }
+       }
+#endif
+      else if (c == '\n' && _rl_horizontal_scroll_mode == 0 && _rl_term_up && *_rl_term_up)
+       {
+         line[out++] = '\0';   /* XXX - sentinel */
+         CHECK_INV_LBREAKS ();
+         inv_lbreaks[++newlines] = out;
+         lpos = 0;
+       }
+      else if (CTRL_CHAR (c) || c == RUBOUT)
+       {
+         line[out++] = '^';
+         CHECK_LPOS();
+         line[out++] = CTRL_CHAR (c) ? UNCTRL (c) : '?';
+         CHECK_LPOS();
+       }
+      else
+       {
+#if defined (HANDLE_MULTIBYTE)
+         if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+           {
+             register int i;
+
+             _rl_wrapped_multicolumn = 0;
+
+             if (_rl_screenwidth < lpos + wc_width)
+               for (i = lpos; i < _rl_screenwidth; i++)
+                 {
+                   /* The space will be removed in update_line() */
+                   line[out++] = ' ';
+                   _rl_wrapped_multicolumn++;
+                   CHECK_LPOS();
+                 }
+             if (in == rl_point)
+               {
+                 cpos_buffer_position = out;
+                 lb_linenum = newlines;
+               }
+             for (i = in; i < in+wc_bytes; i++)
+               line[out++] = rl_line_buffer[i];
+             for (i = 0; i < wc_width; i++)
+               CHECK_LPOS();
+           }
+         else
+           {
+             line[out++] = c;
+             CHECK_LPOS();
+           }
+#else
+         line[out++] = c;
+         CHECK_LPOS();
+#endif
+       }
+
+#if defined (HANDLE_MULTIBYTE)
+      if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+       {
+         in += wc_bytes;
+         /* XXX - what if wc_bytes ends up <= 0? check for MB_INVALIDCH */
+         wc_bytes = mbrtowc (&wc, rl_line_buffer + in, rl_end - in, &ps);
+       }
+      else
+        in++;
+#endif
+
+    }
+  line[out] = '\0';
+  if (cpos_buffer_position < 0)
+    {
+      cpos_buffer_position = out;
+      lb_linenum = newlines;
+    }
+
+  inv_botlin = lb_botlin = newlines;
+  CHECK_INV_LBREAKS ();
+  inv_lbreaks[newlines+1] = out;
+  cursor_linenum = lb_linenum;
+
+  /* CPOS_BUFFER_POSITION == position in buffer where cursor should be placed.
+     CURSOR_LINENUM == line number where the cursor should be placed. */
+
+  /* PWP: now is when things get a bit hairy.  The visible and invisible
+     line buffers are really multiple lines, which would wrap every
+     (screenwidth - 1) characters.  Go through each in turn, finding
+     the changed region and updating it.  The line order is top to bottom. */
+
+  /* If we can move the cursor up and down, then use multiple lines,
+     otherwise, let long lines display in a single terminal line, and
+     horizontally scroll it. */
+
+  if (_rl_horizontal_scroll_mode == 0 && _rl_term_up && *_rl_term_up)
+    {
+      int nleft, pos, changed_screen_line, tx;
+
+      if (!rl_display_fixed || forced_display)
+       {
+         forced_display = 0;
+
+         /* If we have more than a screenful of material to display, then
+            only display a screenful.  We should display the last screen,
+            not the first.  */
+         if (out >= _rl_screenchars)
+           {
+             if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+               out = _rl_find_prev_mbchar (line, _rl_screenchars, MB_FIND_ANY);
+             else
+               out = _rl_screenchars - 1;
+           }
+
+         /* The first line is at character position 0 in the buffer.  The
+            second and subsequent lines start at inv_lbreaks[N], offset by
+            OFFSET (which has already been calculated above).  */
+
+#define INVIS_FIRST()  (prompt_physical_chars > _rl_screenwidth ? prompt_invis_chars_first_line : wrap_offset)
+#define WRAP_OFFSET(line, offset)  ((line == 0) \
+                                       ? (offset ? INVIS_FIRST() : 0) \
+                                       : ((line == prompt_last_screen_line) ? wrap_offset-prompt_invis_chars_first_line : 0))
+#define W_OFFSET(line, offset) ((line) == 0 ? offset : 0)
+#define VIS_LLEN(l)    ((l) > _rl_vis_botlin ? 0 : (vis_lbreaks[l+1] - vis_lbreaks[l]))
+#define INV_LLEN(l)    (inv_lbreaks[l+1] - inv_lbreaks[l])
+#define VIS_CHARS(line) (visible_line + vis_lbreaks[line])
+#define VIS_LINE(line) ((line) > _rl_vis_botlin) ? "" : VIS_CHARS(line)
+#define INV_LINE(line) (invisible_line + inv_lbreaks[line])
+
+#define OLD_CPOS_IN_PROMPT() (cpos_adjusted == 0 && \
+                       _rl_last_c_pos != o_cpos && \
+                       _rl_last_c_pos > wrap_offset && \
+                       o_cpos < prompt_last_invisible)
+
+         /* For each line in the buffer, do the updating display. */
+         for (linenum = 0; linenum <= inv_botlin; linenum++)
+           {
+             /* This can lead us astray if we execute a program that changes
+                the locale from a non-multibyte to a multibyte one. */
+             o_cpos = _rl_last_c_pos;
+             cpos_adjusted = 0;
+             update_line (VIS_LINE(linenum), INV_LINE(linenum), linenum,
+                          VIS_LLEN(linenum), INV_LLEN(linenum), inv_botlin);
+
+             /* update_line potentially changes _rl_last_c_pos, but doesn't
+                take invisible characters into account, since _rl_last_c_pos
+                is an absolute cursor position in a multibyte locale.  See
+                if compensating here is the right thing, or if we have to
+                change update_line itself.  There are several cases in which
+                update_line adjusts _rl_last_c_pos itself (so it can pass
+                _rl_move_cursor_relative accurate values); it communicates
+                this back by setting cpos_adjusted.  If we assume that
+                _rl_last_c_pos is correct (an absolute cursor position) each
+                time update_line is called, then we can assume in our
+                calculations that o_cpos does not need to be adjusted by
+                wrap_offset. */
+             if (linenum == 0 && (MB_CUR_MAX > 1 && rl_byte_oriented == 0) && OLD_CPOS_IN_PROMPT())
+               _rl_last_c_pos -= prompt_invis_chars_first_line;        /* XXX - was wrap_offset */
+             else if (linenum == prompt_last_screen_line && prompt_physical_chars > _rl_screenwidth &&
+                       (MB_CUR_MAX > 1 && rl_byte_oriented == 0) &&
+                       cpos_adjusted == 0 &&
+                       _rl_last_c_pos != o_cpos &&
+                       _rl_last_c_pos > (prompt_last_invisible - _rl_screenwidth - prompt_invis_chars_first_line))
+               _rl_last_c_pos -= (wrap_offset-prompt_invis_chars_first_line);
+                 
+             /* If this is the line with the prompt, we might need to
+                compensate for invisible characters in the new line. Do
+                this only if there is not more than one new line (which
+                implies that we completely overwrite the old visible line)
+                and the new line is shorter than the old.  Make sure we are
+                at the end of the new line before clearing. */
+             if (linenum == 0 &&
+                 inv_botlin == 0 && _rl_last_c_pos == out &&
+                 (wrap_offset > visible_wrap_offset) &&
+                 (_rl_last_c_pos < visible_first_line_len))
+               {
+                 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+                   nleft = _rl_screenwidth - _rl_last_c_pos;
+                 else
+                   nleft = _rl_screenwidth + wrap_offset - _rl_last_c_pos;
+                 if (nleft)
+                   _rl_clear_to_eol (nleft);
+               }
+#if 0
+             /* This segment is intended to handle the case where the prompt
+                has invisible characters on the second line and the new line
+                to be displayed needs to clear the rest of the old characters
+                out (e.g., when printing the i-search prompt).  In general,
+                the case of the new line being shorter than the old.
+                Incomplete */
+             else if (linenum == prompt_last_screen_line &&
+                      prompt_physical_chars > _rl_screenwidth &&
+                      wrap_offset != prompt_invis_chars_first_line &&
+                      _rl_last_c_pos == out &&
+#endif
+
+
+             /* Since the new first line is now visible, save its length. */
+             if (linenum == 0)
+               visible_first_line_len = (inv_botlin > 0) ? inv_lbreaks[1] : out - wrap_offset;
+           }
+
+         /* We may have deleted some lines.  If so, clear the left over
+            blank ones at the bottom out. */
+         if (_rl_vis_botlin > inv_botlin)
+           {
+             char *tt;
+             for (; linenum <= _rl_vis_botlin; linenum++)
+               {
+                 tt = VIS_CHARS (linenum);
+                 _rl_move_vert (linenum);
+                 _rl_move_cursor_relative (0, tt);
+                 _rl_clear_to_eol
+                   ((linenum == _rl_vis_botlin) ? strlen (tt) : _rl_screenwidth);
+               }
+           }
+         _rl_vis_botlin = inv_botlin;
+
+         /* CHANGED_SCREEN_LINE is set to 1 if we have moved to a
+            different screen line during this redisplay. */
+         changed_screen_line = _rl_last_v_pos != cursor_linenum;
+         if (changed_screen_line)
+           {
+             _rl_move_vert (cursor_linenum);
+             /* If we moved up to the line with the prompt using _rl_term_up,
+                the physical cursor position on the screen stays the same,
+                but the buffer position needs to be adjusted to account
+                for invisible characters. */
+             if ((MB_CUR_MAX == 1 || rl_byte_oriented) && cursor_linenum == 0 && wrap_offset)
+               _rl_last_c_pos += wrap_offset;
+           }
+
+         /* We have to reprint the prompt if it contains invisible
+            characters, since it's not generally OK to just reprint
+            the characters from the current cursor position.  But we
+            only need to reprint it if the cursor is before the last
+            invisible character in the prompt string. */
+         nleft = prompt_visible_length + wrap_offset;
+         if (cursor_linenum == 0 && wrap_offset > 0 && _rl_last_c_pos > 0 &&
+#if 0
+             _rl_last_c_pos <= PROMPT_ENDING_INDEX && local_prompt)
+#else
+             _rl_last_c_pos < PROMPT_ENDING_INDEX && local_prompt)
+#endif
+           {
+#if defined (__MSDOS__)
+             putc ('\r', rl_outstream);
+#else
+             if (_rl_term_cr)
+               tputs (_rl_term_cr, 1, _rl_output_character_function);
+#endif
+             if (modmark)
+               _rl_output_some_chars ("*", 1);
+
+             _rl_output_some_chars (local_prompt, nleft);
+             if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+               _rl_last_c_pos = _rl_col_width (local_prompt, 0, nleft, 1) - wrap_offset + modmark;
+             else
+               _rl_last_c_pos = nleft + modmark;
+           }
+
+         /* Where on that line?  And where does that line start
+            in the buffer? */
+         pos = inv_lbreaks[cursor_linenum];
+         /* nleft == number of characters in the line buffer between the
+            start of the line and the desired cursor position. */
+         nleft = cpos_buffer_position - pos;
+
+         /* NLEFT is now a number of characters in a buffer.  When in a
+            multibyte locale, however, _rl_last_c_pos is an absolute cursor
+            position that doesn't take invisible characters in the prompt
+            into account.  We use a fudge factor to compensate. */
+
+         /* Since _rl_backspace() doesn't know about invisible characters in the
+            prompt, and there's no good way to tell it, we compensate for
+            those characters here and call _rl_backspace() directly. */
+         if (wrap_offset && cursor_linenum == 0 && nleft < _rl_last_c_pos)
+           {
+             /* TX == new physical cursor position in multibyte locale. */
+             if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+               tx = _rl_col_width (&visible_line[pos], 0, nleft, 1) - visible_wrap_offset;
+             else
+               tx = nleft;
+             if (tx >= 0 && _rl_last_c_pos > tx)
+               {
+                 _rl_backspace (_rl_last_c_pos - tx);  /* XXX */
+                 _rl_last_c_pos = tx;
+               }
+           }
+
+         /* We need to note that in a multibyte locale we are dealing with
+            _rl_last_c_pos as an absolute cursor position, but moving to a
+            point specified by a buffer position (NLEFT) that doesn't take
+            invisible characters into account. */
+         if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+           _rl_move_cursor_relative (nleft, &invisible_line[pos]);
+         else if (nleft != _rl_last_c_pos)
+           _rl_move_cursor_relative (nleft, &invisible_line[pos]);
+       }
+    }
+  else                         /* Do horizontal scrolling. */
+    {
+#define M_OFFSET(margin, offset) ((margin) == 0 ? offset : 0)
+      int lmargin, ndisp, nleft, phys_c_pos, t;
+
+      /* Always at top line. */
+      _rl_last_v_pos = 0;
+
+      /* Compute where in the buffer the displayed line should start.  This
+        will be LMARGIN. */
+
+      /* The number of characters that will be displayed before the cursor. */
+      ndisp = cpos_buffer_position - wrap_offset;
+      nleft  = prompt_visible_length + wrap_offset;
+      /* Where the new cursor position will be on the screen.  This can be
+        longer than SCREENWIDTH; if it is, lmargin will be adjusted. */
+      phys_c_pos = cpos_buffer_position - (last_lmargin ? last_lmargin : wrap_offset);
+      t = _rl_screenwidth / 3;
+
+      /* If the number of characters had already exceeded the screenwidth,
+        last_lmargin will be > 0. */
+
+      /* If the number of characters to be displayed is more than the screen
+        width, compute the starting offset so that the cursor is about
+        two-thirds of the way across the screen. */
+      if (phys_c_pos > _rl_screenwidth - 2)
+       {
+         lmargin = cpos_buffer_position - (2 * t);
+         if (lmargin < 0)
+           lmargin = 0;
+         /* If the left margin would be in the middle of a prompt with
+            invisible characters, don't display the prompt at all. */
+         if (wrap_offset && lmargin > 0 && lmargin < nleft)
+           lmargin = nleft;
+       }
+      else if (ndisp < _rl_screenwidth - 2)            /* XXX - was -1 */
+       lmargin = 0;
+      else if (phys_c_pos < 1)
+       {
+         /* If we are moving back towards the beginning of the line and
+            the last margin is no longer correct, compute a new one. */
+         lmargin = ((cpos_buffer_position - 1) / t) * t;       /* XXX */
+         if (wrap_offset && lmargin > 0 && lmargin < nleft)
+           lmargin = nleft;
+       }
+      else
+       lmargin = last_lmargin;
+
+      /* If the first character on the screen isn't the first character
+        in the display line, indicate this with a special character. */
+      if (lmargin > 0)
+       line[lmargin] = '<';
+
+      /* If SCREENWIDTH characters starting at LMARGIN do not encompass
+        the whole line, indicate that with a special character at the
+        right edge of the screen.  If LMARGIN is 0, we need to take the
+        wrap offset into account. */
+      t = lmargin + M_OFFSET (lmargin, wrap_offset) + _rl_screenwidth;
+      if (t < out)
+       line[t - 1] = '>';
+
+      if (rl_display_fixed == 0 || forced_display || lmargin != last_lmargin)
+       {
+         forced_display = 0;
+         o_cpos = _rl_last_c_pos;
+         cpos_adjusted = 0;
+         update_line (&visible_line[last_lmargin],
+                      &invisible_line[lmargin],
+                      0,
+                      _rl_screenwidth + visible_wrap_offset,
+                      _rl_screenwidth + (lmargin ? 0 : wrap_offset),
+                      0);
+
+         if ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) && OLD_CPOS_IN_PROMPT())
+           _rl_last_c_pos -= prompt_invis_chars_first_line;    /* XXX - was wrap_offset */
+
+         /* If the visible new line is shorter than the old, but the number
+            of invisible characters is greater, and we are at the end of
+            the new line, we need to clear to eol. */
+         t = _rl_last_c_pos - M_OFFSET (lmargin, wrap_offset);
+         if ((M_OFFSET (lmargin, wrap_offset) > visible_wrap_offset) &&
+             (_rl_last_c_pos == out) &&
+             t < visible_first_line_len)
+           {
+             nleft = _rl_screenwidth - t;
+             _rl_clear_to_eol (nleft);
+           }
+         visible_first_line_len = out - lmargin - M_OFFSET (lmargin, wrap_offset);
+         if (visible_first_line_len > _rl_screenwidth)
+           visible_first_line_len = _rl_screenwidth;
+
+         _rl_move_cursor_relative (cpos_buffer_position - lmargin, &invisible_line[lmargin]);
+         last_lmargin = lmargin;
+       }
+    }
+  fflush (rl_outstream);
+
+  /* Swap visible and non-visible lines. */
+  {
+    struct line_state *vtemp = line_state_visible;
+
+    line_state_visible = line_state_invisible;
+    line_state_invisible = vtemp;
+
+    rl_display_fixed = 0;
+    /* If we are displaying on a single line, and last_lmargin is > 0, we
+       are not displaying any invisible characters, so set visible_wrap_offset
+       to 0. */
+    if (_rl_horizontal_scroll_mode && last_lmargin)
+      visible_wrap_offset = 0;
+    else
+      visible_wrap_offset = wrap_offset;
+  }
+
+  RL_UNSETSTATE (RL_STATE_REDISPLAYING);
+  _rl_release_sigint ();
+}
+
+/* PWP: update_line() is based on finding the middle difference of each
+   line on the screen; vis:
+
+                            /old first difference
+       /beginning of line   |        /old last same       /old EOL
+       v                    v        v             v
+old:   eddie> Oh, my little gruntle-buggy is to me, as lurgid as
+new:   eddie> Oh, my little buggy says to me, as lurgid as
+       ^                    ^  ^                          ^
+       \beginning of line   |  \new last same     \new end of line
+                            \new first difference
+
+   All are character pointers for the sake of speed.  Special cases for
+   no differences, as well as for end of line additions must be handled.
+
+   Could be made even smarter, but this works well enough */
+static void
+update_line (old, new, current_line, omax, nmax, inv_botlin)
+     register char *old, *new;
+     int current_line, omax, nmax, inv_botlin;
+{
+  register char *ofd, *ols, *oe, *nfd, *nls, *ne;
+  int temp, lendiff, wsatend, od, nd, twidth, o_cpos;
+  int current_invis_chars;
+  int col_lendiff, col_temp;
+#if defined (HANDLE_MULTIBYTE)
+  mbstate_t ps_new, ps_old;
+  int new_offset, old_offset;
+#endif
+
+  /* If we're at the right edge of a terminal that supports xn, we're
+     ready to wrap around, so do so.  This fixes problems with knowing
+     the exact cursor position and cut-and-paste with certain terminal
+     emulators.  In this calculation, TEMP is the physical screen
+     position of the cursor. */
+  if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+    temp = _rl_last_c_pos;
+  else
+    temp = _rl_last_c_pos - WRAP_OFFSET (_rl_last_v_pos, visible_wrap_offset);
+  if (temp == _rl_screenwidth && _rl_term_autowrap && !_rl_horizontal_scroll_mode
+       && _rl_last_v_pos == current_line - 1)
+    {
+#if defined (HANDLE_MULTIBYTE)
+      if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+       {
+         wchar_t wc;
+         mbstate_t ps;
+         int tempwidth, bytes;
+         size_t ret;
+
+         /* This fixes only double-column characters, but if the wrapped
+            character comsumes more than three columns, spaces will be
+            inserted in the string buffer. */
+         if (current_line < line_state_visible->wbsize && line_state_visible->wrapped_line[current_line] > 0)
+           _rl_clear_to_eol (line_state_visible->wrapped_line[current_line]);
+
+         memset (&ps, 0, sizeof (mbstate_t));
+         ret = mbrtowc (&wc, new, MB_CUR_MAX, &ps);
+         if (MB_INVALIDCH (ret))
+           {
+             tempwidth = 1;
+             ret = 1;
+           }
+         else if (MB_NULLWCH (ret))
+           tempwidth = 0;
+         else
+           tempwidth = wcwidth (wc);
+
+         if (tempwidth > 0)
+           {
+             int count, i;
+             bytes = ret;
+             for (count = 0; count < bytes; count++)
+               putc (new[count], rl_outstream);
+             _rl_last_c_pos = tempwidth;
+             _rl_last_v_pos++;
+             memset (&ps, 0, sizeof (mbstate_t));
+             ret = mbrtowc (&wc, old, MB_CUR_MAX, &ps);
+             if (ret != 0 && bytes != 0)
+               {
+                 if (MB_INVALIDCH (ret))
+                   ret = 1;
+                 memmove (old+bytes, old+ret, strlen (old+ret));
+                 memcpy (old, new, bytes);
+                 /* Fix up indices if we copy data from one line to another */
+                 omax += bytes - ret;
+                 for (i = current_line+1; i < inv_botlin+1; i++)
+                   vis_lbreaks[i] += bytes - ret;
+               }
+           }
+         else
+           {
+             putc (' ', rl_outstream);
+             _rl_last_c_pos = 1;
+             _rl_last_v_pos++;
+             if (old[0] && new[0])
+               old[0] = new[0];
+           }
+       }
+      else
+#endif
+       {
+         if (new[0])
+           putc (new[0], rl_outstream);
+         else
+           putc (' ', rl_outstream);
+         _rl_last_c_pos = 1;
+         _rl_last_v_pos++;
+         if (old[0] && new[0])
+           old[0] = new[0];
+       }
+    }
+
+      
+  /* Find first difference. */
+#if defined (HANDLE_MULTIBYTE)
+  if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+    {
+      /* See if the old line is a subset of the new line, so that the
+        only change is adding characters. */
+      temp = (omax < nmax) ? omax : nmax;
+      if (memcmp (old, new, temp) == 0)                /* adding at the end */
+       {
+         ofd = old + temp;
+         nfd = new + temp;
+       }
+      else
+       {      
+         memset (&ps_new, 0, sizeof(mbstate_t));
+         memset (&ps_old, 0, sizeof(mbstate_t));
+
+         if (omax == nmax && STREQN (new, old, omax))
+           {
+             ofd = old + omax;
+             nfd = new + nmax;
+           }
+         else
+           {
+             new_offset = old_offset = 0;
+             for (ofd = old, nfd = new;
+                   (ofd - old < omax) && *ofd &&
+                   _rl_compare_chars(old, old_offset, &ps_old, new, new_offset, &ps_new); )
+               {
+                 old_offset = _rl_find_next_mbchar (old, old_offset, 1, MB_FIND_ANY);
+                 new_offset = _rl_find_next_mbchar (new, new_offset, 1, MB_FIND_ANY);
+                 ofd = old + old_offset;
+                 nfd = new + new_offset;
+               }
+           }
+       }
+    }
+  else
+#endif
+  for (ofd = old, nfd = new;
+       (ofd - old < omax) && *ofd && (*ofd == *nfd);
+       ofd++, nfd++)
+    ;
+
+  /* Move to the end of the screen line.  ND and OD are used to keep track
+     of the distance between ne and new and oe and old, respectively, to
+     move a subtraction out of each loop. */
+  for (od = ofd - old, oe = ofd; od < omax && *oe; oe++, od++);
+  for (nd = nfd - new, ne = nfd; nd < nmax && *ne; ne++, nd++);
+
+  /* If no difference, continue to next line. */
+  if (ofd == oe && nfd == ne)
+    return;
+
+  wsatend = 1;                 /* flag for trailing whitespace */
+
+#if defined (HANDLE_MULTIBYTE)
+  if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+    {
+      ols = old + _rl_find_prev_mbchar (old, oe - old, MB_FIND_ANY);
+      nls = new + _rl_find_prev_mbchar (new, ne - new, MB_FIND_ANY);
+      while ((ols > ofd) && (nls > nfd))
+       {
+         memset (&ps_old, 0, sizeof (mbstate_t));
+         memset (&ps_new, 0, sizeof (mbstate_t));
+
+#if 0
+         /* On advice from jir@yamato.ibm.com */
+         _rl_adjust_point (old, ols - old, &ps_old);
+         _rl_adjust_point (new, nls - new, &ps_new);
+#endif
+
+         if (_rl_compare_chars (old, ols - old, &ps_old, new, nls - new, &ps_new) == 0)
+           break;
+
+         if (*ols == ' ')
+           wsatend = 0;
+
+         ols = old + _rl_find_prev_mbchar (old, ols - old, MB_FIND_ANY);
+         nls = new + _rl_find_prev_mbchar (new, nls - new, MB_FIND_ANY);
+       }
+    }
+  else
+    {
+#endif /* HANDLE_MULTIBYTE */
+  ols = oe - 1;                        /* find last same */
+  nls = ne - 1;
+  while ((ols > ofd) && (nls > nfd) && (*ols == *nls))
+    {
+      if (*ols != ' ')
+       wsatend = 0;
+      ols--;
+      nls--;
+    }
+#if defined (HANDLE_MULTIBYTE)
+    }
+#endif
+
+  if (wsatend)
+    {
+      ols = oe;
+      nls = ne;
+    }
+#if defined (HANDLE_MULTIBYTE)
+  /* This may not work for stateful encoding, but who cares?  To handle
+     stateful encoding properly, we have to scan each string from the
+     beginning and compare. */
+  else if (_rl_compare_chars (ols, 0, NULL, nls, 0, NULL) == 0)
+#else
+  else if (*ols != *nls)
+#endif
+    {
+      if (*ols)                        /* don't step past the NUL */
+       {
+         if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+           ols = old + _rl_find_next_mbchar (old, ols - old, 1, MB_FIND_ANY);
+         else
+           ols++;
+       }
+      if (*nls)
+       {
+         if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+           nls = new + _rl_find_next_mbchar (new, nls - new, 1, MB_FIND_ANY);
+         else
+           nls++;
+       }
+    }
+
+  /* count of invisible characters in the current invisible line. */
+  current_invis_chars = W_OFFSET (current_line, wrap_offset);
+  if (_rl_last_v_pos != current_line)
+    {
+      _rl_move_vert (current_line);
+      if ((MB_CUR_MAX == 1 || rl_byte_oriented) && current_line == 0 && visible_wrap_offset)
+       _rl_last_c_pos += visible_wrap_offset;
+    }
+
+  /* If this is the first line and there are invisible characters in the
+     prompt string, and the prompt string has not changed, and the current
+     cursor position is before the last invisible character in the prompt,
+     and the index of the character to move to is past the end of the prompt
+     string, then redraw the entire prompt string.  We can only do this
+     reliably if the terminal supports a `cr' capability.
+
+     This is not an efficiency hack -- there is a problem with redrawing
+     portions of the prompt string if they contain terminal escape
+     sequences (like drawing the `unbold' sequence without a corresponding
+     `bold') that manifests itself on certain terminals. */
+
+  lendiff = local_prompt_len;
+  od = ofd - old;      /* index of first difference in visible line */
+  if (current_line == 0 && !_rl_horizontal_scroll_mode &&
+      _rl_term_cr && lendiff > prompt_visible_length && _rl_last_c_pos > 0 &&
+      od >= lendiff && _rl_last_c_pos < PROMPT_ENDING_INDEX)
+    {
+#if defined (__MSDOS__)
+      putc ('\r', rl_outstream);
+#else
+      tputs (_rl_term_cr, 1, _rl_output_character_function);
+#endif
+      if (modmark)
+       _rl_output_some_chars ("*", 1);
+      _rl_output_some_chars (local_prompt, lendiff);
+      if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+       {
+         /* We take wrap_offset into account here so we can pass correct
+            information to _rl_move_cursor_relative. */
+         _rl_last_c_pos = _rl_col_width (local_prompt, 0, lendiff, 1) - wrap_offset + modmark;
+         cpos_adjusted = 1;
+       }
+      else
+       _rl_last_c_pos = lendiff + modmark;
+    }
+
+  o_cpos = _rl_last_c_pos;
+
+  /* When this function returns, _rl_last_c_pos is correct, and an absolute
+     cursor postion in multibyte mode, but a buffer index when not in a
+     multibyte locale. */
+  _rl_move_cursor_relative (od, old);
+#if 1
+#if defined (HANDLE_MULTIBYTE)
+  /* We need to indicate that the cursor position is correct in the presence of
+     invisible characters in the prompt string.  Let's see if setting this when
+     we make sure we're at the end of the drawn prompt string works. */
+  if (current_line == 0 && MB_CUR_MAX > 1 && rl_byte_oriented == 0 &&
+      (_rl_last_c_pos > 0 || o_cpos > 0) &&
+      _rl_last_c_pos == prompt_physical_chars)
+    cpos_adjusted = 1;
+#endif
+#endif
+
+  /* if (len (new) > len (old))
+     lendiff == difference in buffer
+     col_lendiff == difference on screen
+     When not using multibyte characters, these are equal */
+  lendiff = (nls - nfd) - (ols - ofd);
+  if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+    col_lendiff = _rl_col_width (new, nfd - new, nls - new, 1) - _rl_col_width (old, ofd - old, ols - old, 1);
+  else
+    col_lendiff = lendiff;
+
+  /* If we are changing the number of invisible characters in a line, and
+     the spot of first difference is before the end of the invisible chars,
+     lendiff needs to be adjusted. */
+  if (current_line == 0 && !_rl_horizontal_scroll_mode &&
+      current_invis_chars != visible_wrap_offset)
+    {
+      if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+       {
+         lendiff += visible_wrap_offset - current_invis_chars;
+         col_lendiff += visible_wrap_offset - current_invis_chars;
+       }
+      else
+       {
+         lendiff += visible_wrap_offset - current_invis_chars;
+         col_lendiff = lendiff;
+       }
+    }
+
+  /* Insert (diff (len (old), len (new)) ch. */
+  temp = ne - nfd;
+  if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+    col_temp = _rl_col_width (new, nfd - new, ne - new, 1);
+  else
+    col_temp = temp;
+
+  if (col_lendiff > 0) /* XXX - was lendiff */
+    {
+      /* Non-zero if we're increasing the number of lines. */
+      int gl = current_line >= _rl_vis_botlin && inv_botlin > _rl_vis_botlin;
+      /* If col_lendiff is > 0, implying that the new string takes up more
+        screen real estate than the old, but lendiff is < 0, meaning that it
+        takes fewer bytes, we need to just output the characters starting
+        from the first difference.  These will overwrite what is on the
+        display, so there's no reason to do a smart update.  This can really
+        only happen in a multibyte environment. */
+      if (lendiff < 0)
+       {
+         _rl_output_some_chars (nfd, temp);
+         _rl_last_c_pos += _rl_col_width (nfd, 0, temp, 1);
+         /* If nfd begins before any invisible characters in the prompt,
+            adjust _rl_last_c_pos to account for wrap_offset and set
+            cpos_adjusted to let the caller know. */
+         if (current_line == 0 && wrap_offset && ((nfd - new) <= prompt_last_invisible))
+           {
+             _rl_last_c_pos -= wrap_offset;
+             cpos_adjusted = 1;
+           }
+         return;
+       }
+      /* Sometimes it is cheaper to print the characters rather than
+        use the terminal's capabilities.  If we're growing the number
+        of lines, make sure we actually cause the new line to wrap
+        around on auto-wrapping terminals. */
+      else if (_rl_terminal_can_insert && ((2 * col_temp) >= col_lendiff || _rl_term_IC) && (!_rl_term_autowrap || !gl))
+       {
+         /* If lendiff > prompt_visible_length and _rl_last_c_pos == 0 and
+            _rl_horizontal_scroll_mode == 1, inserting the characters with
+            _rl_term_IC or _rl_term_ic will screw up the screen because of the
+            invisible characters.  We need to just draw them. */
+         /* The same thing happens if we're trying to draw before the last
+            invisible character in the prompt string or we're increasing the
+            number of invisible characters in the line and we're not drawing
+            the entire prompt string. */
+         if (*ols && ((_rl_horizontal_scroll_mode &&
+                       _rl_last_c_pos == 0 &&
+                       lendiff > prompt_visible_length &&
+                       current_invis_chars > 0) == 0) &&
+                     (((MB_CUR_MAX > 1 && rl_byte_oriented == 0) &&
+                       current_line == 0 && wrap_offset &&
+                       ((nfd - new) <= prompt_last_invisible) &&
+                       (col_lendiff < prompt_visible_length)) == 0) &&
+                     (visible_wrap_offset >= current_invis_chars))
+           {
+             insert_some_chars (nfd, lendiff, col_lendiff);
+             _rl_last_c_pos += col_lendiff;
+           }
+#if 0          /* XXX - for now */
+         else if ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) && _rl_last_c_pos == 0 && wrap_offset && (nfd-new) <= prompt_last_invisible && col_lendiff < prompt_visible_length && visible_wrap_offset >= current_invis_chars)
+           {
+             _rl_output_some_chars (nfd, lendiff);
+             _rl_last_c_pos += col_lendiff;
+           }
+#endif
+         else if ((MB_CUR_MAX == 1 || rl_byte_oriented != 0) && *ols == 0 && lendiff > 0)
+           {
+             /* At the end of a line the characters do not have to
+                be "inserted".  They can just be placed on the screen. */
+             /* However, this screws up the rest of this block, which
+                assumes you've done the insert because you can. */
+             _rl_output_some_chars (nfd, lendiff);
+             _rl_last_c_pos += col_lendiff;
+           }
+         else
+           {
+             _rl_output_some_chars (nfd, temp);
+             _rl_last_c_pos += col_temp;
+             /* If nfd begins before the last invisible character in the
+                prompt, adjust _rl_last_c_pos to account for wrap_offset
+                and set cpos_adjusted to let the caller know. */
+             if ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) && current_line == 0 && wrap_offset && ((nfd - new) <= prompt_last_invisible))
+               {
+                 _rl_last_c_pos -= wrap_offset;
+                 cpos_adjusted = 1;
+               }
+             return;
+           }
+         /* Copy (new) chars to screen from first diff to last match. */
+         temp = nls - nfd;
+         if ((temp - lendiff) > 0)
+           {
+             _rl_output_some_chars (nfd + lendiff, temp - lendiff);
+            /* XXX -- this bears closer inspection.  Fixes a redisplay bug
+               reported against bash-3.0-alpha by Andreas Schwab involving
+               multibyte characters and prompt strings with invisible
+               characters, but was previously disabled. */
+             if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+               twidth = _rl_col_width (nfd+lendiff, 0, temp-col_lendiff, 1);
+             else
+               twidth = temp - lendiff;
+             _rl_last_c_pos += twidth;
+             /* If nfd begins before the last invisible character in the
+                prompt, adjust _rl_last_c_pos to account for wrap_offset
+                and set cpos_adjusted to let the caller know. */
+             if ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) && current_line == 0 && wrap_offset && ((nfd - new) <= prompt_last_invisible))
+               {
+                 _rl_last_c_pos -= wrap_offset;
+                 cpos_adjusted = 1;
+               }
+           }
+       }
+      else
+       {
+         /* cannot insert chars, write to EOL */
+         _rl_output_some_chars (nfd, temp);
+         _rl_last_c_pos += col_temp;
+         /* If we're in a multibyte locale and were before the last invisible
+            char in the current line (which implies we just output some invisible
+            characters) we need to adjust _rl_last_c_pos, since it represents
+            a physical character position. */
+         if ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) &&
+               current_line == prompt_last_screen_line && wrap_offset &&
+               wrap_offset != prompt_invis_chars_first_line &&
+               ((nfd-new) < (prompt_last_invisible-(current_line*_rl_screenwidth))))
+           {
+             _rl_last_c_pos -= wrap_offset - prompt_invis_chars_first_line;
+             cpos_adjusted = 1;
+           }
+       }
+    }
+  else                         /* Delete characters from line. */
+    {
+      /* If possible and inexpensive to use terminal deletion, then do so. */
+      if (_rl_term_dc && (2 * col_temp) >= -col_lendiff)
+       {
+         /* If all we're doing is erasing the invisible characters in the
+            prompt string, don't bother.  It screws up the assumptions
+            about what's on the screen. */
+         if (_rl_horizontal_scroll_mode && _rl_last_c_pos == 0 &&
+             -lendiff == visible_wrap_offset)
+           col_lendiff = 0;
+
+         if (col_lendiff)
+           delete_chars (-col_lendiff); /* delete (diff) characters */
+
+         /* Copy (new) chars to screen from first diff to last match */
+         temp = nls - nfd;
+         if (temp > 0)
+           {
+             /* If nfd begins at the prompt, or before the invisible
+                characters in the prompt, we need to adjust _rl_last_c_pos
+                in a multibyte locale to account for the wrap offset and
+                set cpos_adjusted accordingly. */
+             _rl_output_some_chars (nfd, temp);
+             if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+               {
+                 _rl_last_c_pos += _rl_col_width (nfd, 0, temp, 1);
+                 if (current_line == 0 && wrap_offset &&  ((nfd - new) <= prompt_last_invisible))
+                   {
+                     _rl_last_c_pos -= wrap_offset;
+                     cpos_adjusted = 1;
+                   }
+               }
+             else
+               _rl_last_c_pos += temp;
+           }
+       }
+      /* Otherwise, print over the existing material. */
+      else
+       {
+         if (temp > 0)
+           {
+             /* If nfd begins at the prompt, or before the invisible
+                characters in the prompt, we need to adjust _rl_last_c_pos
+                in a multibyte locale to account for the wrap offset and
+                set cpos_adjusted accordingly. */
+             _rl_output_some_chars (nfd, temp);
+             _rl_last_c_pos += col_temp;               /* XXX */
+             if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+               {
+                 if (current_line == 0 && wrap_offset &&  ((nfd - new) <= prompt_last_invisible))
+                   {
+                     _rl_last_c_pos -= wrap_offset;
+                     cpos_adjusted = 1;
+                   }
+               }
+           }
+         lendiff = (oe - old) - (ne - new);
+         if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+           col_lendiff = _rl_col_width (old, 0, oe - old, 1) - _rl_col_width (new, 0, ne - new, 1);
+         else
+           col_lendiff = lendiff;
+
+#if 0
+         if (col_lendiff)
+#else
+         /* If we've already printed over the entire width of the screen,
+            including the old material, then col_lendiff doesn't matter and
+            space_to_eol will insert too many spaces.  XXX - maybe we should
+            adjust col_lendiff based on the difference between _rl_last_c_pos
+            and _rl_screenwidth */
+         if (col_lendiff && ((MB_CUR_MAX == 1 || rl_byte_oriented) || (_rl_last_c_pos < _rl_screenwidth)))
+#endif
+           {     
+             if (_rl_term_autowrap && current_line < inv_botlin)
+               space_to_eol (col_lendiff);
+             else
+               _rl_clear_to_eol (col_lendiff);
+           }
+       }
+    }
+}
+
+/* Tell the update routines that we have moved onto a new (empty) line. */
+int
+rl_on_new_line ()
+{
+  if (visible_line)
+    visible_line[0] = '\0';
+
+  _rl_last_c_pos = _rl_last_v_pos = 0;
+  _rl_vis_botlin = last_lmargin = 0;
+  if (vis_lbreaks)
+    vis_lbreaks[0] = vis_lbreaks[1] = 0;
+  visible_wrap_offset = 0;
+  return 0;
+}
+
+/* Tell the update routines that we have moved onto a new line with the
+   prompt already displayed.  Code originally from the version of readline
+   distributed with CLISP.  rl_expand_prompt must have already been called
+   (explicitly or implicitly).  This still doesn't work exactly right. */
+int
+rl_on_new_line_with_prompt ()
+{
+  int prompt_size, i, l, real_screenwidth, newlines;
+  char *prompt_last_line, *lprompt;
+
+  /* Initialize visible_line and invisible_line to ensure that they can hold
+     the already-displayed prompt. */
+  prompt_size = strlen (rl_prompt) + 1;
+  init_line_structures (prompt_size);
+
+  /* Make sure the line structures hold the already-displayed prompt for
+     redisplay. */
+  lprompt = local_prompt ? local_prompt : rl_prompt;
+  strcpy (visible_line, lprompt);
+  strcpy (invisible_line, lprompt);
+
+  /* If the prompt contains newlines, take the last tail. */
+  prompt_last_line = strrchr (rl_prompt, '\n');
+  if (!prompt_last_line)
+    prompt_last_line = rl_prompt;
+
+  l = strlen (prompt_last_line);
+  if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+    _rl_last_c_pos = _rl_col_width (prompt_last_line, 0, l, 1);        /* XXX */
+  else
+    _rl_last_c_pos = l;
+
+  /* Dissect prompt_last_line into screen lines. Note that here we have
+     to use the real screenwidth. Readline's notion of screenwidth might be
+     one less, see terminal.c. */
+  real_screenwidth = _rl_screenwidth + (_rl_term_autowrap ? 0 : 1);
+  _rl_last_v_pos = l / real_screenwidth;
+  /* If the prompt length is a multiple of real_screenwidth, we don't know
+     whether the cursor is at the end of the last line, or already at the
+     beginning of the next line. Output a newline just to be safe. */
+  if (l > 0 && (l % real_screenwidth) == 0)
+    _rl_output_some_chars ("\n", 1);
+  last_lmargin = 0;
+
+  newlines = 0; i = 0;
+  while (i <= l)
+    {
+      _rl_vis_botlin = newlines;
+      vis_lbreaks[newlines++] = i;
+      i += real_screenwidth;
+    }
+  vis_lbreaks[newlines] = l;
+  visible_wrap_offset = 0;
+
+  rl_display_prompt = rl_prompt;       /* XXX - make sure it's set */
+
+  return 0;
+}
+
+/* Actually update the display, period. */
+int
+rl_forced_update_display ()
+{
+  register char *temp;
+
+  if (visible_line)
+    {
+      temp = visible_line;
+      while (*temp)
+       *temp++ = '\0';
+    }
+  rl_on_new_line ();
+  forced_display++;
+  (*rl_redisplay_function) ();
+  return 0;
+}
+
+/* Move the cursor from _rl_last_c_pos to NEW, which are buffer indices.
+   (Well, when we don't have multibyte characters, _rl_last_c_pos is a
+   buffer index.)
+   DATA is the contents of the screen line of interest; i.e., where
+   the movement is being done. */
+void
+_rl_move_cursor_relative (new, data)
+     int new;
+     const char *data;
+{
+  register int i;
+  int woff;                    /* number of invisible chars on current line */
+  int cpos, dpos;              /* current and desired cursor positions */
+  int adjust;
+
+  woff = WRAP_OFFSET (_rl_last_v_pos, wrap_offset);
+  cpos = _rl_last_c_pos;
+
+  if (cpos == 0 && cpos == new)
+    return;
+
+#if defined (HANDLE_MULTIBYTE)
+  /* If we have multibyte characters, NEW is indexed by the buffer point in
+     a multibyte string, but _rl_last_c_pos is the display position.  In
+     this case, NEW's display position is not obvious and must be
+     calculated.  We need to account for invisible characters in this line,
+     as long as we are past them and they are counted by _rl_col_width. */
+  if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+    {
+      adjust = 1;
+      /* Try to short-circuit common cases and eliminate a bunch of multibyte
+        character function calls. */
+      /* 1.  prompt string */
+      if (new == local_prompt_len && memcmp (data, local_prompt, new) == 0)
+       {
+         dpos = prompt_physical_chars;
+         cpos_adjusted = 1;
+         adjust = 0;
+       }
+      /* 2.  prompt_string + line contents */
+      else if (new > local_prompt_len && local_prompt && memcmp (data, local_prompt, local_prompt_len) == 0)
+       {
+         dpos = prompt_physical_chars + _rl_col_width (data, local_prompt_len, new, 1);
+         cpos_adjusted = 1;
+         adjust = 0;
+       }
+      else
+        dpos = _rl_col_width (data, 0, new, 1);
+
+      /* Use NEW when comparing against the last invisible character in the
+        prompt string, since they're both buffer indices and DPOS is a
+        desired display position. */
+      if (adjust && ((new > prompt_last_invisible) ||          /* XXX - don't use woff here */
+         (prompt_physical_chars >= _rl_screenwidth &&
+          _rl_last_v_pos == prompt_last_screen_line &&
+          wrap_offset >= woff && dpos >= woff &&
+          new > (prompt_last_invisible-(_rl_screenwidth*_rl_last_v_pos)-wrap_offset))))
+          /* XXX last comparison might need to be >= */
+       {
+         dpos -= woff;
+         /* Since this will be assigned to _rl_last_c_pos at the end (more
+            precisely, _rl_last_c_pos == dpos when this function returns),
+            let the caller know. */
+         cpos_adjusted = 1;
+       }
+    }
+  else
+#endif
+    dpos = new;
+
+  /* If we don't have to do anything, then return. */
+  if (cpos == dpos)
+    return;
+
+  /* It may be faster to output a CR, and then move forwards instead
+     of moving backwards. */
+  /* i == current physical cursor position. */
+#if defined (HANDLE_MULTIBYTE)
+  if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+    i = _rl_last_c_pos;
+  else
+#endif
+  i = _rl_last_c_pos - woff;
+  if (dpos == 0 || CR_FASTER (dpos, _rl_last_c_pos) ||
+      (_rl_term_autowrap && i == _rl_screenwidth))
+    {
+#if defined (__MSDOS__)
+      putc ('\r', rl_outstream);
+#else
+      tputs (_rl_term_cr, 1, _rl_output_character_function);
+#endif /* !__MSDOS__ */
+      cpos = _rl_last_c_pos = 0;
+    }
+
+  if (cpos < dpos)
+    {
+      /* Move the cursor forward.  We do it by printing the command
+        to move the cursor forward if there is one, else print that
+        portion of the output buffer again.  Which is cheaper? */
+
+      /* The above comment is left here for posterity.  It is faster
+        to print one character (non-control) than to print a control
+        sequence telling the terminal to move forward one character.
+        That kind of control is for people who don't know what the
+        data is underneath the cursor. */
+
+      /* However, we need a handle on where the current display position is
+        in the buffer for the immediately preceding comment to be true.
+        In multibyte locales, we don't currently have that info available.
+        Without it, we don't know where the data we have to display begins
+        in the buffer and we have to go back to the beginning of the screen
+        line.  In this case, we can use the terminal sequence to move forward
+        if it's available. */
+      if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+       {
+         if (_rl_term_forward_char)
+           {
+             for (i = cpos; i < dpos; i++)
+               tputs (_rl_term_forward_char, 1, _rl_output_character_function);
+           }
+         else
+           {
+             tputs (_rl_term_cr, 1, _rl_output_character_function);
+             for (i = 0; i < new; i++)
+               putc (data[i], rl_outstream);
+           }
+       }
+      else
+       for (i = cpos; i < new; i++)
+         putc (data[i], rl_outstream);
+    }
+
+#if defined (HANDLE_MULTIBYTE)
+  /* NEW points to the buffer point, but _rl_last_c_pos is the display point.
+     The byte length of the string is probably bigger than the column width
+     of the string, which means that if NEW == _rl_last_c_pos, then NEW's
+     display point is less than _rl_last_c_pos. */
+#endif
+  else if (cpos > dpos)
+    _rl_backspace (cpos - dpos);
+
+  _rl_last_c_pos = dpos;
+}
+
+/* PWP: move the cursor up or down. */
+void
+_rl_move_vert (to)
+     int to;
+{
+  register int delta, i;
+
+  if (_rl_last_v_pos == to || to > _rl_screenheight)
+    return;
+
+  if ((delta = to - _rl_last_v_pos) > 0)
+    {
+      for (i = 0; i < delta; i++)
+       putc ('\n', rl_outstream);
+#if defined (__MSDOS__)
+      putc ('\r', rl_outstream);
+#else
+      tputs (_rl_term_cr, 1, _rl_output_character_function);
+#endif
+      _rl_last_c_pos = 0;
+    }
+  else
+    {                  /* delta < 0 */
+      if (_rl_term_up && *_rl_term_up)
+       for (i = 0; i < -delta; i++)
+         tputs (_rl_term_up, 1, _rl_output_character_function);
+    }
+
+  _rl_last_v_pos = to;         /* Now TO is here */
+}
+
+/* Physically print C on rl_outstream.  This is for functions which know
+   how to optimize the display.  Return the number of characters output. */
+int
+rl_show_char (c)
+     int c;
+{
+  int n = 1;
+  if (META_CHAR (c) && (_rl_output_meta_chars == 0))
+    {
+      fprintf (rl_outstream, "M-");
+      n += 2;
+      c = UNMETA (c);
+    }
+
+#if defined (DISPLAY_TABS)
+  if ((CTRL_CHAR (c) && c != '\t') || c == RUBOUT)
+#else
+  if (CTRL_CHAR (c) || c == RUBOUT)
+#endif /* !DISPLAY_TABS */
+    {
+      fprintf (rl_outstream, "C-");
+      n += 2;
+      c = CTRL_CHAR (c) ? UNCTRL (c) : '?';
+    }
+
+  putc (c, rl_outstream);
+  fflush (rl_outstream);
+  return n;
+}
+
+int
+rl_character_len (c, pos)
+     register int c, pos;
+{
+  unsigned char uc;
+
+  uc = (unsigned char)c;
+
+  if (META_CHAR (uc))
+    return ((_rl_output_meta_chars == 0) ? 4 : 1);
+
+  if (uc == '\t')
+    {
+#if defined (DISPLAY_TABS)
+      return (((pos | 7) + 1) - pos);
+#else
+      return (2);
+#endif /* !DISPLAY_TABS */
+    }
+
+  if (CTRL_CHAR (c) || c == RUBOUT)
+    return (2);
+
+  return ((ISPRINT (uc)) ? 1 : 2);
+}
+/* How to print things in the "echo-area".  The prompt is treated as a
+   mini-modeline. */
+static int msg_saved_prompt = 0;
+
+#if defined (USE_VARARGS)
+int
+#if defined (PREFER_STDARG)
+rl_message (const char *format, ...)
+#else
+rl_message (va_alist)
+     va_dcl
+#endif
+{
+  va_list args;
+#if defined (PREFER_VARARGS)
+  char *format;
+#endif
+
+#if defined (PREFER_STDARG)
+  va_start (args, format);
+#else
+  va_start (args);
+  format = va_arg (args, char *);
+#endif
+
+#if defined (HAVE_VSNPRINTF)
+  vsnprintf (msg_buf, sizeof (msg_buf) - 1, format, args);
+#else
+  vsprintf (msg_buf, format, args);
+  msg_buf[sizeof(msg_buf) - 1] = '\0'; /* overflow? */
+#endif
+  va_end (args);
+
+  if (saved_local_prompt == 0)
+    {
+      rl_save_prompt ();
+      msg_saved_prompt = 1;
+    }
+  rl_display_prompt = msg_buf;
+  local_prompt = expand_prompt (msg_buf, &prompt_visible_length,
+                                        &prompt_last_invisible,
+                                        &prompt_invis_chars_first_line,
+                                        &prompt_physical_chars);
+  local_prompt_prefix = (char *)NULL;
+  local_prompt_len = local_prompt ? strlen (local_prompt) : 0;
+  (*rl_redisplay_function) ();
+
+  return 0;
+}
+#else /* !USE_VARARGS */
+int
+rl_message (format, arg1, arg2)
+     char *format;
+{
+  sprintf (msg_buf, format, arg1, arg2);
+  msg_buf[sizeof(msg_buf) - 1] = '\0'; /* overflow? */
+
+  rl_display_prompt = msg_buf;
+  if (saved_local_prompt == 0)
+    {
+      rl_save_prompt ();
+      msg_saved_prompt = 1;
+    }
+  local_prompt = expand_prompt (msg_buf, &prompt_visible_length,
+                                        &prompt_last_invisible,
+                                        &prompt_invis_chars_first_line,
+                                        &prompt_physical_chars);
+  local_prompt_prefix = (char *)NULL;
+  local_prompt_len = local_prompt ? strlen (local_prompt) : 0;
+  (*rl_redisplay_function) ();
+      
+  return 0;
+}
+#endif /* !USE_VARARGS */
+
+/* How to clear things from the "echo-area". */
+int
+rl_clear_message ()
+{
+  rl_display_prompt = rl_prompt;
+  if (msg_saved_prompt)
+    {
+      rl_restore_prompt ();
+      msg_saved_prompt = 0;
+    }
+  (*rl_redisplay_function) ();
+  return 0;
+}
+
+int
+rl_reset_line_state ()
+{
+  rl_on_new_line ();
+
+  rl_display_prompt = rl_prompt ? rl_prompt : "";
+  forced_display = 1;
+  return 0;
+}
+
+void
+rl_save_prompt ()
+{
+  saved_local_prompt = local_prompt;
+  saved_local_prefix = local_prompt_prefix;
+  saved_prefix_length = prompt_prefix_length;
+  saved_local_length = local_prompt_len;
+  saved_last_invisible = prompt_last_invisible;
+  saved_visible_length = prompt_visible_length;
+  saved_invis_chars_first_line = prompt_invis_chars_first_line;
+  saved_physical_chars = prompt_physical_chars;
+
+  local_prompt = local_prompt_prefix = (char *)0;
+  local_prompt_len = 0;
+  prompt_last_invisible = prompt_visible_length = prompt_prefix_length = 0;
+  prompt_invis_chars_first_line = prompt_physical_chars = 0;
+}
+
+void
+rl_restore_prompt ()
+{
+  FREE (local_prompt);
+  FREE (local_prompt_prefix);
+
+  local_prompt = saved_local_prompt;
+  local_prompt_prefix = saved_local_prefix;
+  local_prompt_len = saved_local_length;
+  prompt_prefix_length = saved_prefix_length;
+  prompt_last_invisible = saved_last_invisible;
+  prompt_visible_length = saved_visible_length;
+  prompt_invis_chars_first_line = saved_invis_chars_first_line;
+  prompt_physical_chars = saved_physical_chars;
+
+  /* can test saved_local_prompt to see if prompt info has been saved. */
+  saved_local_prompt = saved_local_prefix = (char *)0;
+  saved_local_length = 0;
+  saved_last_invisible = saved_visible_length = saved_prefix_length = 0;
+  saved_invis_chars_first_line = saved_physical_chars = 0;
+}
+
+char *
+_rl_make_prompt_for_search (pchar)
+     int pchar;
+{
+  int len;
+  char *pmt, *p;
+
+  rl_save_prompt ();
+
+  /* We've saved the prompt, and can do anything with the various prompt
+     strings we need before they're restored.  We want the unexpanded
+     portion of the prompt string after any final newline. */
+  p = rl_prompt ? strrchr (rl_prompt, '\n') : 0;
+  if (p == 0)
+    {
+      len = (rl_prompt && *rl_prompt) ? strlen (rl_prompt) : 0;
+      pmt = (char *)xmalloc (len + 2);
+      if (len)
+       strcpy (pmt, rl_prompt);
+      pmt[len] = pchar;
+      pmt[len+1] = '\0';
+    }
+  else
+    {
+      p++;
+      len = strlen (p);
+      pmt = (char *)xmalloc (len + 2);
+      if (len)
+       strcpy (pmt, p);
+      pmt[len] = pchar;
+      pmt[len+1] = '\0';
+    }  
+
+  /* will be overwritten by expand_prompt, called from rl_message */
+  prompt_physical_chars = saved_physical_chars + 1;
+  return pmt;
+}
+
+/* Quick redisplay hack when erasing characters at the end of the line. */
+void
+_rl_erase_at_end_of_line (l)
+     int l;
+{
+  register int i;
+
+  _rl_backspace (l);
+  for (i = 0; i < l; i++)
+    putc (' ', rl_outstream);
+  _rl_backspace (l);
+  for (i = 0; i < l; i++)
+    visible_line[--_rl_last_c_pos] = '\0';
+  rl_display_fixed++;
+}
+
+/* Clear to the end of the line.  COUNT is the minimum
+   number of character spaces to clear, */
+void
+_rl_clear_to_eol (count)
+     int count;
+{
+  if (_rl_term_clreol)
+    tputs (_rl_term_clreol, 1, _rl_output_character_function);
+  else if (count)
+    space_to_eol (count);
+}
+
+/* Clear to the end of the line using spaces.  COUNT is the minimum
+   number of character spaces to clear, */
+static void
+space_to_eol (count)
+     int count;
+{
+  register int i;
+
+  for (i = 0; i < count; i++)
+   putc (' ', rl_outstream);
+
+  _rl_last_c_pos += count;
+}
+
+void
+_rl_clear_screen ()
+{
+  if (_rl_term_clrpag)
+    tputs (_rl_term_clrpag, 1, _rl_output_character_function);
+  else
+    rl_crlf ();
+}
+
+/* Insert COUNT characters from STRING to the output stream at column COL. */
+static void
+insert_some_chars (string, count, col)
+     char *string;
+     int count, col;
+{
+#if defined (__MSDOS__) || defined (__MINGW32__)
+  _rl_output_some_chars (string, count);
+#else
+  /* DEBUGGING */
+  if (MB_CUR_MAX == 1 || rl_byte_oriented)
+    if (count != col)
+      _rl_ttymsg ("debug: insert_some_chars: count (%d) != col (%d)", count, col);
+
+  /* If IC is defined, then we do not have to "enter" insert mode. */
+  if (_rl_term_IC)
+    {
+      char *buffer;
+
+      buffer = tgoto (_rl_term_IC, 0, col);
+      tputs (buffer, 1, _rl_output_character_function);
+      _rl_output_some_chars (string, count);
+    }
+  else
+    {
+      register int i;
+
+      /* If we have to turn on insert-mode, then do so. */
+      if (_rl_term_im && *_rl_term_im)
+       tputs (_rl_term_im, 1, _rl_output_character_function);
+
+      /* If there is a special command for inserting characters, then
+        use that first to open up the space. */
+      if (_rl_term_ic && *_rl_term_ic)
+       {
+         for (i = col; i--; )
+           tputs (_rl_term_ic, 1, _rl_output_character_function);
+       }
+
+      /* Print the text. */
+      _rl_output_some_chars (string, count);
+
+      /* If there is a string to turn off insert mode, we had best use
+        it now. */
+      if (_rl_term_ei && *_rl_term_ei)
+       tputs (_rl_term_ei, 1, _rl_output_character_function);
+    }
+#endif /* __MSDOS__ || __MINGW32__ */
+}
+
+/* Delete COUNT characters from the display line. */
+static void
+delete_chars (count)
+     int count;
+{
+  if (count > _rl_screenwidth) /* XXX */
+    return;
+
+#if !defined (__MSDOS__) && !defined (__MINGW32__)
+  if (_rl_term_DC && *_rl_term_DC)
+    {
+      char *buffer;
+      buffer = tgoto (_rl_term_DC, count, count);
+      tputs (buffer, count, _rl_output_character_function);
+    }
+  else
+    {
+      if (_rl_term_dc && *_rl_term_dc)
+       while (count--)
+         tputs (_rl_term_dc, 1, _rl_output_character_function);
+    }
+#endif /* !__MSDOS__ && !__MINGW32__ */
+}
+
+void
+_rl_update_final ()
+{
+  int full_lines;
+
+  full_lines = 0;
+  /* If the cursor is the only thing on an otherwise-blank last line,
+     compensate so we don't print an extra CRLF. */
+  if (_rl_vis_botlin && _rl_last_c_pos == 0 &&
+       visible_line[vis_lbreaks[_rl_vis_botlin]] == 0)
+    {
+      _rl_vis_botlin--;
+      full_lines = 1;
+    }
+  _rl_move_vert (_rl_vis_botlin);
+  /* If we've wrapped lines, remove the final xterm line-wrap flag. */
+  if (full_lines && _rl_term_autowrap && (VIS_LLEN(_rl_vis_botlin) == _rl_screenwidth))
+    {
+      char *last_line;
+
+      last_line = &visible_line[vis_lbreaks[_rl_vis_botlin]];
+      cpos_buffer_position = -1;       /* don't know where we are in buffer */
+      _rl_move_cursor_relative (_rl_screenwidth - 1, last_line);       /* XXX */
+      _rl_clear_to_eol (0);
+      putc (last_line[_rl_screenwidth - 1], rl_outstream);
+    }
+  _rl_vis_botlin = 0;
+  rl_crlf ();
+  fflush (rl_outstream);
+  rl_display_fixed++;
+}
+
+/* Move to the start of the current line. */
+static void
+cr ()
+{
+  if (_rl_term_cr)
+    {
+#if defined (__MSDOS__)
+      putc ('\r', rl_outstream);
+#else
+      tputs (_rl_term_cr, 1, _rl_output_character_function);
+#endif
+      _rl_last_c_pos = 0;
+    }
+}
+
+/* Redraw the last line of a multi-line prompt that may possibly contain
+   terminal escape sequences.  Called with the cursor at column 0 of the
+   line to draw the prompt on. */
+static void
+redraw_prompt (t)
+     char *t;
+{
+  char *oldp;
+
+  oldp = rl_display_prompt;
+  rl_save_prompt ();
+
+  rl_display_prompt = t;
+  local_prompt = expand_prompt (t, &prompt_visible_length,
+                                  &prompt_last_invisible,
+                                  &prompt_invis_chars_first_line,
+                                  &prompt_physical_chars);
+  local_prompt_prefix = (char *)NULL;
+  local_prompt_len = local_prompt ? strlen (local_prompt) : 0;
+
+  rl_forced_update_display ();
+
+  rl_display_prompt = oldp;
+  rl_restore_prompt();
+}
+      
+/* Redisplay the current line after a SIGWINCH is received. */
+void
+_rl_redisplay_after_sigwinch ()
+{
+  char *t;
+
+  /* Clear the last line (assuming that the screen size change will result in
+     either more or fewer characters on that line only) and put the cursor at
+     column 0.  Make sure the right thing happens if we have wrapped to a new
+     screen line. */
+  if (_rl_term_cr)
+    {
+      _rl_move_vert (_rl_vis_botlin);
+
+#if defined (__MSDOS__)
+      putc ('\r', rl_outstream);
+#else
+      tputs (_rl_term_cr, 1, _rl_output_character_function);
+#endif
+      _rl_last_c_pos = 0;
+#if defined (__MSDOS__)
+      space_to_eol (_rl_screenwidth);
+      putc ('\r', rl_outstream);
+#else
+      if (_rl_term_clreol)
+       tputs (_rl_term_clreol, 1, _rl_output_character_function);
+      else
+       {
+         space_to_eol (_rl_screenwidth);
+         tputs (_rl_term_cr, 1, _rl_output_character_function);
+       }
+#endif
+      if (_rl_last_v_pos > 0)
+       _rl_move_vert (0);
+    }
+  else
+    rl_crlf ();
+
+  /* Redraw only the last line of a multi-line prompt. */
+  t = strrchr (rl_display_prompt, '\n');
+  if (t)
+    redraw_prompt (++t);
+  else
+    rl_forced_update_display ();
+}
+
+void
+_rl_clean_up_for_exit ()
+{
+  if (_rl_echoing_p)
+    {
+      _rl_move_vert (_rl_vis_botlin);
+      _rl_vis_botlin = 0;
+      fflush (rl_outstream);
+      rl_restart_output (1, 0);
+    }
+}
+
+void
+_rl_erase_entire_line ()
+{
+  cr ();
+  _rl_clear_to_eol (0);
+  cr ();
+  fflush (rl_outstream);
+}
+
+/* return the `current display line' of the cursor -- the number of lines to
+   move up to get to the first screen line of the current readline line. */
+int
+_rl_current_display_line ()
+{
+  int ret, nleft;
+
+  /* Find out whether or not there might be invisible characters in the
+     editing buffer. */
+  if (rl_display_prompt == rl_prompt)
+    nleft = _rl_last_c_pos - _rl_screenwidth - rl_visible_prompt_length;
+  else
+    nleft = _rl_last_c_pos - _rl_screenwidth;
+
+  if (nleft > 0)
+    ret = 1 + nleft / _rl_screenwidth;
+  else
+    ret = 0;
+
+  return ret;
+}
+
+#if defined (HANDLE_MULTIBYTE)
+/* Calculate the number of screen columns occupied by STR from START to END.
+   In the case of multibyte characters with stateful encoding, we have to
+   scan from the beginning of the string to take the state into account. */
+static int
+_rl_col_width (str, start, end, flags)
+     const char *str;
+     int start, end, flags;
+{
+  wchar_t wc;
+  mbstate_t ps;
+  int tmp, point, width, max;
+
+  if (end <= start)
+    return 0;
+  if (MB_CUR_MAX == 1 || rl_byte_oriented)
+{
+_rl_ttymsg ("_rl_col_width: called with MB_CUR_MAX == 1");
+    return (end - start);
+}
+
+  memset (&ps, 0, sizeof (mbstate_t));
+
+  point = 0;
+  max = end;
+
+  /* Try to short-circuit common cases.  The adjustment to remove wrap_offset
+     is done by the caller. */
+  /* 1.  prompt string */
+  if (flags && start == 0 && end == local_prompt_len && memcmp (str, local_prompt, local_prompt_len) == 0)
+    return (prompt_physical_chars + wrap_offset);
+  /* 2.  prompt string + line contents */
+  else if (flags && start == 0 && local_prompt_len > 0 && end > local_prompt_len && local_prompt && memcmp (str, local_prompt, local_prompt_len) == 0)
+    {
+      tmp = prompt_physical_chars + wrap_offset;
+      /* XXX - try to call ourselves recursively with non-prompt portion */
+      tmp += _rl_col_width (str, local_prompt_len, end, flags);
+      return (tmp);
+    }
+
+  while (point < start)
+    {
+      tmp = mbrlen (str + point, max, &ps);
+      if (MB_INVALIDCH ((size_t)tmp))
+       {
+         /* In this case, the bytes are invalid or too short to compose a
+            multibyte character, so we assume that the first byte represents
+            a single character. */
+         point++;
+         max--;
+
+         /* Clear the state of the byte sequence, because in this case the
+            effect of mbstate is undefined. */
+         memset (&ps, 0, sizeof (mbstate_t));
+       }
+      else if (MB_NULLWCH (tmp))
+       break;          /* Found '\0' */
+      else
+       {
+         point += tmp;
+         max -= tmp;
+       }
+    }
+
+  /* If START is not a byte that starts a character, then POINT will be
+     greater than START.  In this case, assume that (POINT - START) gives
+     a byte count that is the number of columns of difference. */
+  width = point - start;
+
+  while (point < end)
+    {
+      tmp = mbrtowc (&wc, str + point, max, &ps);
+      if (MB_INVALIDCH ((size_t)tmp))
+       {
+         /* In this case, the bytes are invalid or too short to compose a
+            multibyte character, so we assume that the first byte represents
+            a single character. */
+         point++;
+         max--;
+
+         /* and assume that the byte occupies a single column. */
+         width++;
+
+         /* Clear the state of the byte sequence, because in this case the
+            effect of mbstate is undefined. */
+         memset (&ps, 0, sizeof (mbstate_t));
+       }
+      else if (MB_NULLWCH (tmp))
+       break;                  /* Found '\0' */
+      else
+       {
+         point += tmp;
+         max -= tmp;
+         tmp = wcwidth(wc);
+         width += (tmp >= 0) ? tmp : 1;
+       }
+    }
+
+  width += point - end;
+
+  return width;
+}
+#endif /* HANDLE_MULTIBYTE */
index d237b1c00487dce38e5a49b4701e3f547ca03d93..47574cf1dd17c249ce012367ea70c634740c0718 100644 (file)
@@ -678,7 +678,7 @@ rl_deprep_terminal ()
   /* Try to keep this function from being interrupted. */
   _rl_block_sigint ();
 
-  tty = rl_instream ? fileno (rl_instream) : fileno (stdout);
+  tty = rl_instream ? fileno (rl_instream) : fileno (stdin);
 
   if (_rl_enable_keypad)
     _rl_control_keypad (0);
diff --git a/lib/readline/rltty.c~ b/lib/readline/rltty.c~
new file mode 100644 (file)
index 0000000..d237b1c
--- /dev/null
@@ -0,0 +1,975 @@
+/* rltty.c -- functions to prepare and restore the terminal for readline's
+   use. */
+
+/* Copyright (C) 1992-2005 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>
+#include <signal.h>
+#include <errno.h>
+#include <stdio.h>
+
+#if defined (HAVE_UNISTD_H)
+#  include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#include "rldefs.h"
+
+#if defined (GWINSZ_IN_SYS_IOCTL)
+#  include <sys/ioctl.h>
+#endif /* GWINSZ_IN_SYS_IOCTL */
+
+#include "rltty.h"
+#include "readline.h"
+#include "rlprivate.h"
+
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+rl_vintfunc_t *rl_prep_term_function = rl_prep_terminal;
+rl_voidfunc_t *rl_deprep_term_function = rl_deprep_terminal;
+
+static void set_winsize PARAMS((int));
+
+/* **************************************************************** */
+/*                                                                 */
+/*                   Saving and Restoring the TTY                  */
+/*                                                                 */
+/* **************************************************************** */
+
+/* Non-zero means that the terminal is in a prepped state. */
+static int terminal_prepped;
+
+static _RL_TTY_CHARS _rl_tty_chars, _rl_last_tty_chars;
+
+/* If non-zero, means that this process has called tcflow(fd, TCOOFF)
+   and output is suspended. */
+#if defined (__ksr1__)
+static int ksrflow;
+#endif
+
+/* Dummy call to force a backgrounded readline to stop before it tries
+   to get the tty settings. */
+static void
+set_winsize (tty)
+     int tty;
+{
+#if defined (TIOCGWINSZ)
+  struct winsize w;
+
+  if (ioctl (tty, TIOCGWINSZ, &w) == 0)
+      (void) ioctl (tty, TIOCSWINSZ, &w);
+#endif /* TIOCGWINSZ */
+}
+
+#if defined (NO_TTY_DRIVER)
+/* Nothing */
+#elif defined (NEW_TTY_DRIVER)
+
+/* Values for the `flags' field of a struct bsdtty.  This tells which
+   elements of the struct bsdtty have been fetched from the system and
+   are valid. */
+#define SGTTY_SET      0x01
+#define LFLAG_SET      0x02
+#define TCHARS_SET     0x04
+#define LTCHARS_SET    0x08
+
+struct bsdtty {
+  struct sgttyb sgttyb;        /* Basic BSD tty driver information. */
+  int lflag;           /* Local mode flags, like LPASS8. */
+#if defined (TIOCGETC)
+  struct tchars tchars;        /* Terminal special characters, including ^S and ^Q. */
+#endif
+#if defined (TIOCGLTC)
+  struct ltchars ltchars; /* 4.2 BSD editing characters */
+#endif
+  int flags;           /* Bitmap saying which parts of the struct are valid. */
+};
+
+#define TIOTYPE struct bsdtty
+
+static TIOTYPE otio;
+
+static void save_tty_chars PARAMS((TIOTYPE *));
+static int _get_tty_settings PARAMS((int, TIOTYPE *));
+static int get_tty_settings PARAMS((int, TIOTYPE *));
+static int _set_tty_settings PARAMS((int, TIOTYPE *));
+static int set_tty_settings PARAMS((int, TIOTYPE *));
+
+static void prepare_terminal_settings PARAMS((int, TIOTYPE, TIOTYPE *));
+
+static void set_special_char PARAMS((Keymap, TIOTYPE *, int, rl_command_func_t));
+
+static void
+save_tty_chars (tiop)
+     TIOTYPE *tiop;
+{
+  _rl_last_tty_chars = _rl_tty_chars;
+
+  if (tiop->flags & SGTTY_SET)
+    {
+      _rl_tty_chars.t_erase = tiop->sgttyb.sg_erase;
+      _rl_tty_chars.t_kill = tiop->sgttyb.sg_kill;
+    }
+
+  if (tiop->flags & TCHARS_SET)
+    {
+      _rl_intr_char = _rl_tty_chars.t_intr = tiop->tchars.t_intrc;
+      _rl_quit_char = _rl_tty_chars.t_quit = tiop->tchars.t_quitc;
+
+      _rl_tty_chars.t_start = tiop->tchars.t_startc;
+      _rl_tty_chars.t_stop = tiop->tchars.t_stopc;
+      _rl_tty_chars.t_eof = tiop->tchars.t_eofc;
+      _rl_tty_chars.t_eol = '\n';
+      _rl_tty_chars.t_eol2 = tiop->tchars.t_brkc;
+    }
+
+  if (tiop->flags & LTCHARS_SET)
+    {
+      _rl_susp_char = _rl_tty_chars.t_susp = tiop->ltchars.t_suspc;
+
+      _rl_tty_chars.t_dsusp = tiop->ltchars.t_dsuspc;
+      _rl_tty_chars.t_reprint = tiop->ltchars.t_rprntc;
+      _rl_tty_chars.t_flush = tiop->ltchars.t_flushc;
+      _rl_tty_chars.t_werase = tiop->ltchars.t_werasc;
+      _rl_tty_chars.t_lnext = tiop->ltchars.t_lnextc;
+    }
+
+  _rl_tty_chars.t_status = -1;
+}
+
+static int
+get_tty_settings (tty, tiop)
+     int tty;
+     TIOTYPE *tiop;
+{
+  set_winsize (tty);
+
+  tiop->flags = tiop->lflag = 0;
+
+  errno = 0;
+  if (ioctl (tty, TIOCGETP, &(tiop->sgttyb)) < 0)
+    return -1;
+  tiop->flags |= SGTTY_SET;
+
+#if defined (TIOCLGET)
+  if (ioctl (tty, TIOCLGET, &(tiop->lflag)) == 0)
+    tiop->flags |= LFLAG_SET;
+#endif
+
+#if defined (TIOCGETC)
+  if (ioctl (tty, TIOCGETC, &(tiop->tchars)) == 0)
+    tiop->flags |= TCHARS_SET;
+#endif
+
+#if defined (TIOCGLTC)
+  if (ioctl (tty, TIOCGLTC, &(tiop->ltchars)) == 0)
+    tiop->flags |= LTCHARS_SET;
+#endif
+
+  return 0;
+}
+
+static int
+set_tty_settings (tty, tiop)
+     int tty;
+     TIOTYPE *tiop;
+{
+  if (tiop->flags & SGTTY_SET)
+    {
+      ioctl (tty, TIOCSETN, &(tiop->sgttyb));
+      tiop->flags &= ~SGTTY_SET;
+    }
+  _rl_echoing_p = 1;
+
+#if defined (TIOCLSET)
+  if (tiop->flags & LFLAG_SET)
+    {
+      ioctl (tty, TIOCLSET, &(tiop->lflag));
+      tiop->flags &= ~LFLAG_SET;
+    }
+#endif
+
+#if defined (TIOCSETC)
+  if (tiop->flags & TCHARS_SET)
+    {
+      ioctl (tty, TIOCSETC, &(tiop->tchars));
+      tiop->flags &= ~TCHARS_SET;
+    }
+#endif
+
+#if defined (TIOCSLTC)
+  if (tiop->flags & LTCHARS_SET)
+    {
+      ioctl (tty, TIOCSLTC, &(tiop->ltchars));
+      tiop->flags &= ~LTCHARS_SET;
+    }
+#endif
+
+  return 0;
+}
+
+static void
+prepare_terminal_settings (meta_flag, oldtio, tiop)
+     int meta_flag;
+     TIOTYPE oldtio, *tiop;
+{
+  _rl_echoing_p = (oldtio.sgttyb.sg_flags & ECHO);
+  _rl_echoctl = (oldtio.sgttyb.sg_flags & ECHOCTL);
+
+  /* Copy the original settings to the structure we're going to use for
+     our settings. */
+  tiop->sgttyb = oldtio.sgttyb;
+  tiop->lflag = oldtio.lflag;
+#if defined (TIOCGETC)
+  tiop->tchars = oldtio.tchars;
+#endif
+#if defined (TIOCGLTC)
+  tiop->ltchars = oldtio.ltchars;
+#endif
+  tiop->flags = oldtio.flags;
+
+  /* First, the basic settings to put us into character-at-a-time, no-echo
+     input mode. */
+  tiop->sgttyb.sg_flags &= ~(ECHO | CRMOD);
+  tiop->sgttyb.sg_flags |= CBREAK;
+
+  /* If this terminal doesn't care how the 8th bit is used, then we can
+     use it for the meta-key.  If only one of even or odd parity is
+     specified, then the terminal is using parity, and we cannot. */
+#if !defined (ANYP)
+#  define ANYP (EVENP | ODDP)
+#endif
+  if (((oldtio.sgttyb.sg_flags & ANYP) == ANYP) ||
+      ((oldtio.sgttyb.sg_flags & ANYP) == 0))
+    {
+      tiop->sgttyb.sg_flags |= ANYP;
+
+      /* Hack on local mode flags if we can. */
+#if defined (TIOCLGET)
+#  if defined (LPASS8)
+      tiop->lflag |= LPASS8;
+#  endif /* LPASS8 */
+#endif /* TIOCLGET */
+    }
+
+#if defined (TIOCGETC)
+#  if defined (USE_XON_XOFF)
+  /* Get rid of terminal output start and stop characters. */
+  tiop->tchars.t_stopc = -1; /* C-s */
+  tiop->tchars.t_startc = -1; /* C-q */
+
+  /* If there is an XON character, bind it to restart the output. */
+  if (oldtio.tchars.t_startc != -1)
+    rl_bind_key (oldtio.tchars.t_startc, rl_restart_output);
+#  endif /* USE_XON_XOFF */
+
+  /* If there is an EOF char, bind _rl_eof_char to it. */
+  if (oldtio.tchars.t_eofc != -1)
+    _rl_eof_char = oldtio.tchars.t_eofc;
+
+#  if defined (NO_KILL_INTR)
+  /* Get rid of terminal-generated SIGQUIT and SIGINT. */
+  tiop->tchars.t_quitc = -1; /* C-\ */
+  tiop->tchars.t_intrc = -1; /* C-c */
+#  endif /* NO_KILL_INTR */
+#endif /* TIOCGETC */
+
+#if defined (TIOCGLTC)
+  /* Make the interrupt keys go away.  Just enough to make people happy. */
+  tiop->ltchars.t_dsuspc = -1; /* C-y */
+  tiop->ltchars.t_lnextc = -1; /* C-v */
+#endif /* TIOCGLTC */
+}
+
+#else  /* !defined (NEW_TTY_DRIVER) */
+
+#if !defined (VMIN)
+#  define VMIN VEOF
+#endif
+
+#if !defined (VTIME)
+#  define VTIME VEOL
+#endif
+
+#if defined (TERMIOS_TTY_DRIVER)
+#  define TIOTYPE struct termios
+#  define DRAIN_OUTPUT(fd)     tcdrain (fd)
+#  define GETATTR(tty, tiop)   (tcgetattr (tty, tiop))
+#  ifdef M_UNIX
+#    define SETATTR(tty, tiop) (tcsetattr (tty, TCSANOW, tiop))
+#  else
+#    define SETATTR(tty, tiop) (tcsetattr (tty, TCSADRAIN, tiop))
+#  endif /* !M_UNIX */
+#else
+#  define TIOTYPE struct termio
+#  define DRAIN_OUTPUT(fd)
+#  define GETATTR(tty, tiop)   (ioctl (tty, TCGETA, tiop))
+#  define SETATTR(tty, tiop)   (ioctl (tty, TCSETAW, tiop))
+#endif /* !TERMIOS_TTY_DRIVER */
+
+static TIOTYPE otio;
+
+static void save_tty_chars PARAMS((TIOTYPE *));
+static int _get_tty_settings PARAMS((int, TIOTYPE *));
+static int get_tty_settings PARAMS((int, TIOTYPE *));
+static int _set_tty_settings PARAMS((int, TIOTYPE *));
+static int set_tty_settings PARAMS((int, TIOTYPE *));
+
+static void prepare_terminal_settings PARAMS((int, TIOTYPE, TIOTYPE *));
+
+static void set_special_char PARAMS((Keymap, TIOTYPE *, int, rl_command_func_t));
+static void _rl_bind_tty_special_chars PARAMS((Keymap, TIOTYPE));
+
+#if defined (FLUSHO)
+#  define OUTPUT_BEING_FLUSHED(tp)  (tp->c_lflag & FLUSHO)
+#else
+#  define OUTPUT_BEING_FLUSHED(tp)  0
+#endif
+
+static void
+save_tty_chars (tiop)
+     TIOTYPE *tiop;
+{
+  _rl_last_tty_chars = _rl_tty_chars;
+
+  _rl_tty_chars.t_eof = tiop->c_cc[VEOF];
+  _rl_tty_chars.t_eol = tiop->c_cc[VEOL];
+#ifdef VEOL2
+  _rl_tty_chars.t_eol2 = tiop->c_cc[VEOL2];
+#endif
+  _rl_tty_chars.t_erase = tiop->c_cc[VERASE];
+#ifdef VWERASE
+  _rl_tty_chars.t_werase = tiop->c_cc[VWERASE];
+#endif
+  _rl_tty_chars.t_kill = tiop->c_cc[VKILL];
+#ifdef VREPRINT
+  _rl_tty_chars.t_reprint = tiop->c_cc[VREPRINT];
+#endif
+  _rl_intr_char = _rl_tty_chars.t_intr = tiop->c_cc[VINTR];
+  _rl_quit_char = _rl_tty_chars.t_quit = tiop->c_cc[VQUIT];
+#ifdef VSUSP
+  _rl_susp_char = _rl_tty_chars.t_susp = tiop->c_cc[VSUSP];
+#endif
+#ifdef VDSUSP
+  _rl_tty_chars.t_dsusp = tiop->c_cc[VDSUSP];
+#endif
+#ifdef VSTART
+  _rl_tty_chars.t_start = tiop->c_cc[VSTART];
+#endif
+#ifdef VSTOP
+  _rl_tty_chars.t_stop = tiop->c_cc[VSTOP];
+#endif
+#ifdef VLNEXT
+  _rl_tty_chars.t_lnext = tiop->c_cc[VLNEXT];
+#endif
+#ifdef VDISCARD
+  _rl_tty_chars.t_flush = tiop->c_cc[VDISCARD];
+#endif
+#ifdef VSTATUS
+  _rl_tty_chars.t_status = tiop->c_cc[VSTATUS];
+#endif
+}
+
+#if defined (_AIX) || defined (_AIX41)
+/* Currently this is only used on AIX */
+static void
+rltty_warning (msg)
+     char *msg;
+{
+  _rl_errmsg ("warning: %s", msg);
+}
+#endif
+
+#if defined (_AIX)
+void
+setopost(tp)
+TIOTYPE *tp;
+{
+  if ((tp->c_oflag & OPOST) == 0)
+    {
+      _rl_errmsg ("warning: turning on OPOST for terminal\r");
+      tp->c_oflag |= OPOST|ONLCR;
+    }
+}
+#endif
+
+static int
+_get_tty_settings (tty, tiop)
+     int tty;
+     TIOTYPE *tiop;
+{
+  int ioctl_ret;
+
+  while (1)
+    {
+      ioctl_ret = GETATTR (tty, tiop);
+      if (ioctl_ret < 0)
+       {
+         if (errno != EINTR)
+           return -1;
+         else
+           continue;
+       }
+      if (OUTPUT_BEING_FLUSHED (tiop))
+       {
+#if defined (FLUSHO)
+         _rl_errmsg ("warning: turning off output flushing");
+         tiop->c_lflag &= ~FLUSHO;
+         break;
+#else
+         continue;
+#endif
+       }
+      break;
+    }
+
+  return 0;
+}
+
+static int
+get_tty_settings (tty, tiop)
+     int tty;
+     TIOTYPE *tiop;
+{
+  set_winsize (tty);
+
+  errno = 0;
+  if (_get_tty_settings (tty, tiop) < 0)
+    return -1;
+
+#if defined (_AIX)
+  setopost(tiop);
+#endif
+
+  return 0;
+}
+
+static int
+_set_tty_settings (tty, tiop)
+     int tty;
+     TIOTYPE *tiop;
+{
+  while (SETATTR (tty, tiop) < 0)
+    {
+      if (errno != EINTR)
+       return -1;
+      errno = 0;
+    }
+  return 0;
+}
+
+static int
+set_tty_settings (tty, tiop)
+     int tty;
+     TIOTYPE *tiop;
+{
+  if (_set_tty_settings (tty, tiop) < 0)
+    return -1;
+    
+#if 0
+
+#if defined (TERMIOS_TTY_DRIVER)
+#  if defined (__ksr1__)
+  if (ksrflow)
+    {
+      ksrflow = 0;
+      tcflow (tty, TCOON);
+    }
+#  else /* !ksr1 */
+  tcflow (tty, TCOON);         /* Simulate a ^Q. */
+#  endif /* !ksr1 */
+#else
+  ioctl (tty, TCXONC, 1);      /* Simulate a ^Q. */
+#endif /* !TERMIOS_TTY_DRIVER */
+
+#endif /* 0 */
+
+  return 0;
+}
+
+static void
+prepare_terminal_settings (meta_flag, oldtio, tiop)
+     int meta_flag;
+     TIOTYPE oldtio, *tiop;
+{
+  _rl_echoing_p = (oldtio.c_lflag & ECHO);
+#if defined (ECHOCTL)
+  _rl_echoctl = (oldtio.c_lflag & ECHOCTL);
+#endif
+
+  tiop->c_lflag &= ~(ICANON | ECHO);
+
+  if ((unsigned char) oldtio.c_cc[VEOF] != (unsigned char) _POSIX_VDISABLE)
+    _rl_eof_char = oldtio.c_cc[VEOF];
+
+#if defined (USE_XON_XOFF)
+#if defined (IXANY)
+  tiop->c_iflag &= ~(IXON | IXOFF | IXANY);
+#else
+  /* `strict' Posix systems do not define IXANY. */
+  tiop->c_iflag &= ~(IXON | IXOFF);
+#endif /* IXANY */
+#endif /* USE_XON_XOFF */
+
+  /* Only turn this off if we are using all 8 bits. */
+  if (((tiop->c_cflag & CSIZE) == CS8) || meta_flag)
+    tiop->c_iflag &= ~(ISTRIP | INPCK);
+
+  /* Make sure we differentiate between CR and NL on input. */
+  tiop->c_iflag &= ~(ICRNL | INLCR);
+
+#if !defined (HANDLE_SIGNALS)
+  tiop->c_lflag &= ~ISIG;
+#else
+  tiop->c_lflag |= ISIG;
+#endif
+
+  tiop->c_cc[VMIN] = 1;
+  tiop->c_cc[VTIME] = 0;
+
+#if defined (FLUSHO)
+  if (OUTPUT_BEING_FLUSHED (tiop))
+    {
+      tiop->c_lflag &= ~FLUSHO;
+      oldtio.c_lflag &= ~FLUSHO;
+    }
+#endif
+
+  /* Turn off characters that we need on Posix systems with job control,
+     just to be sure.  This includes ^Y and ^V.  This should not really
+     be necessary.  */
+#if defined (TERMIOS_TTY_DRIVER) && defined (_POSIX_VDISABLE)
+
+#if defined (VLNEXT)
+  tiop->c_cc[VLNEXT] = _POSIX_VDISABLE;
+#endif
+
+#if defined (VDSUSP)
+  tiop->c_cc[VDSUSP] = _POSIX_VDISABLE;
+#endif
+
+#endif /* TERMIOS_TTY_DRIVER && _POSIX_VDISABLE */
+}
+#endif  /* !NEW_TTY_DRIVER */
+
+/* Put the terminal in CBREAK mode so that we can detect key presses. */
+#if defined (NO_TTY_DRIVER)
+void
+rl_prep_terminal (meta_flag)
+     int meta_flag;
+{
+  _rl_echoing_p = 1;
+}
+
+void
+rl_deprep_terminal ()
+{
+}
+
+#else /* ! NO_TTY_DRIVER */
+void
+rl_prep_terminal (meta_flag)
+     int meta_flag;
+{
+  int tty;
+  TIOTYPE tio;
+
+  if (terminal_prepped)
+    return;
+
+  /* Try to keep this function from being INTerrupted. */
+  _rl_block_sigint ();
+
+  tty = rl_instream ? fileno (rl_instream) : fileno (stdin);
+
+  if (get_tty_settings (tty, &tio) < 0)
+    {
+#if defined (ENOTSUP)
+      /* MacOS X and Linux, at least, lie about the value of errno if
+        tcgetattr fails. */
+      if (errno == ENOTTY || errno == EINVAL || errno == ENOTSUP)
+#else
+      if (errno == ENOTTY || errno == EINVAL)
+#endif
+       _rl_echoing_p = 1;              /* XXX */
+
+      _rl_release_sigint ();
+      return;
+    }
+
+  otio = tio;
+
+  if (_rl_bind_stty_chars)
+    {
+#if defined (VI_MODE)
+      /* If editing in vi mode, make sure we restore the bindings in the
+        insertion keymap no matter what keymap we ended up in. */
+      if (rl_editing_mode == vi_mode)
+       rl_tty_unset_default_bindings (vi_insertion_keymap);
+      else
+#endif
+       rl_tty_unset_default_bindings (_rl_keymap);
+    }
+  save_tty_chars (&otio);
+  RL_SETSTATE(RL_STATE_TTYCSAVED);
+  if (_rl_bind_stty_chars)
+    {
+#if defined (VI_MODE)
+      /* If editing in vi mode, make sure we set the bindings in the
+        insertion keymap no matter what keymap we ended up in. */
+      if (rl_editing_mode == vi_mode)
+       _rl_bind_tty_special_chars (vi_insertion_keymap, tio);  
+      else
+#endif
+       _rl_bind_tty_special_chars (_rl_keymap, tio);
+    }
+
+  prepare_terminal_settings (meta_flag, otio, &tio);
+
+  if (set_tty_settings (tty, &tio) < 0)
+    {
+      _rl_release_sigint ();
+      return;
+    }
+
+  if (_rl_enable_keypad)
+    _rl_control_keypad (1);
+
+  fflush (rl_outstream);
+  terminal_prepped = 1;
+  RL_SETSTATE(RL_STATE_TERMPREPPED);
+
+  _rl_release_sigint ();
+}
+
+/* Restore the terminal's normal settings and modes. */
+void
+rl_deprep_terminal ()
+{
+  int tty;
+
+  if (!terminal_prepped)
+    return;
+
+  /* Try to keep this function from being interrupted. */
+  _rl_block_sigint ();
+
+  tty = rl_instream ? fileno (rl_instream) : fileno (stdout);
+
+  if (_rl_enable_keypad)
+    _rl_control_keypad (0);
+
+  fflush (rl_outstream);
+
+  if (set_tty_settings (tty, &otio) < 0)
+    {
+      _rl_release_sigint ();
+      return;
+    }
+
+  terminal_prepped = 0;
+  RL_UNSETSTATE(RL_STATE_TERMPREPPED);
+
+  _rl_release_sigint ();
+}
+#endif /* !NO_TTY_DRIVER */
+\f
+/* **************************************************************** */
+/*                                                                 */
+/*                     Bogus Flow Control                          */
+/*                                                                 */
+/* **************************************************************** */
+
+int
+rl_restart_output (count, key)
+     int count, key;
+{
+#if defined (__MINGW32__)
+  return 0;
+#else /* !__MING32__ */
+
+  int fildes = fileno (rl_outstream);
+#if defined (TIOCSTART)
+#if defined (apollo)
+  ioctl (&fildes, TIOCSTART, 0);
+#else
+  ioctl (fildes, TIOCSTART, 0);
+#endif /* apollo */
+
+#else /* !TIOCSTART */
+#  if defined (TERMIOS_TTY_DRIVER)
+#    if defined (__ksr1__)
+  if (ksrflow)
+    {
+      ksrflow = 0;
+      tcflow (fildes, TCOON);
+    }
+#    else /* !ksr1 */
+  tcflow (fildes, TCOON);              /* Simulate a ^Q. */
+#    endif /* !ksr1 */
+#  else /* !TERMIOS_TTY_DRIVER */
+#    if defined (TCXONC)
+  ioctl (fildes, TCXONC, TCOON);
+#    endif /* TCXONC */
+#  endif /* !TERMIOS_TTY_DRIVER */
+#endif /* !TIOCSTART */
+
+  return 0;
+#endif /* !__MINGW32__ */
+}
+
+int
+rl_stop_output (count, key)
+     int count, key;
+{
+#if defined (__MINGW32__)
+  return 0;
+#else
+
+  int fildes = fileno (rl_instream);
+
+#if defined (TIOCSTOP)
+# if defined (apollo)
+  ioctl (&fildes, TIOCSTOP, 0);
+# else
+  ioctl (fildes, TIOCSTOP, 0);
+# endif /* apollo */
+#else /* !TIOCSTOP */
+# if defined (TERMIOS_TTY_DRIVER)
+#  if defined (__ksr1__)
+  ksrflow = 1;
+#  endif /* ksr1 */
+  tcflow (fildes, TCOOFF);
+# else
+#   if defined (TCXONC)
+  ioctl (fildes, TCXONC, TCOON);
+#   endif /* TCXONC */
+# endif /* !TERMIOS_TTY_DRIVER */
+#endif /* !TIOCSTOP */
+
+  return 0;
+#endif /* !__MINGW32__ */
+}
+
+/* **************************************************************** */
+/*                                                                 */
+/*                     Default Key Bindings                        */
+/*                                                                 */
+/* **************************************************************** */
+
+#if !defined (NO_TTY_DRIVER)
+#define SET_SPECIAL(sc, func)  set_special_char(kmap, &ttybuff, sc, func)
+#endif
+
+#if defined (NO_TTY_DRIVER)
+
+#define SET_SPECIAL(sc, func)
+#define RESET_SPECIAL(c)
+
+#elif defined (NEW_TTY_DRIVER)
+static void
+set_special_char (kmap, tiop, sc, func)
+     Keymap kmap;
+     TIOTYPE *tiop;
+     int sc;
+     rl_command_func_t *func;
+{
+  if (sc != -1 && kmap[(unsigned char)sc].type == ISFUNC)
+    kmap[(unsigned char)sc].function = func;
+}
+
+#define RESET_SPECIAL(c) \
+  if (c != -1 && kmap[(unsigned char)c].type == ISFUNC) \
+    kmap[(unsigned char)c].function = rl_insert;
+
+static void
+_rl_bind_tty_special_chars (kmap, ttybuff)
+     Keymap kmap;
+     TIOTYPE ttybuff;
+{
+  if (ttybuff.flags & SGTTY_SET)
+    {
+      SET_SPECIAL (ttybuff.sgttyb.sg_erase, rl_rubout);
+      SET_SPECIAL (ttybuff.sgttyb.sg_kill, rl_unix_line_discard);
+    }
+
+#  if defined (TIOCGLTC)
+  if (ttybuff.flags & LTCHARS_SET)
+    {
+      SET_SPECIAL (ttybuff.ltchars.t_werasc, rl_unix_word_rubout);
+      SET_SPECIAL (ttybuff.ltchars.t_lnextc, rl_quoted_insert);
+    }
+#  endif /* TIOCGLTC */
+}
+
+#else /* !NEW_TTY_DRIVER */
+static void
+set_special_char (kmap, tiop, sc, func)
+     Keymap kmap;
+     TIOTYPE *tiop;
+     int sc;
+     rl_command_func_t *func;
+{
+  unsigned char uc;
+
+  uc = tiop->c_cc[sc];
+  if (uc != (unsigned char)_POSIX_VDISABLE && kmap[uc].type == ISFUNC)
+    kmap[uc].function = func;
+}
+
+/* used later */
+#define RESET_SPECIAL(uc) \
+  if (uc != (unsigned char)_POSIX_VDISABLE && kmap[uc].type == ISFUNC) \
+    kmap[uc].function = rl_insert;
+
+static void
+_rl_bind_tty_special_chars (kmap, ttybuff)
+     Keymap kmap;
+     TIOTYPE ttybuff;
+{
+  SET_SPECIAL (VERASE, rl_rubout);
+  SET_SPECIAL (VKILL, rl_unix_line_discard);
+
+#  if defined (VLNEXT) && defined (TERMIOS_TTY_DRIVER)
+  SET_SPECIAL (VLNEXT, rl_quoted_insert);
+#  endif /* VLNEXT && TERMIOS_TTY_DRIVER */
+
+#  if defined (VWERASE) && defined (TERMIOS_TTY_DRIVER)
+  SET_SPECIAL (VWERASE, rl_unix_word_rubout);
+#  endif /* VWERASE && TERMIOS_TTY_DRIVER */
+}
+
+#endif /* !NEW_TTY_DRIVER */
+
+/* Set the system's default editing characters to their readline equivalents
+   in KMAP.  Should be static, now that we have rl_tty_set_default_bindings. */
+void
+rltty_set_default_bindings (kmap)
+     Keymap kmap;
+{
+#if !defined (NO_TTY_DRIVER)
+  TIOTYPE ttybuff;
+  int tty;
+
+  tty = fileno (rl_instream);
+
+  if (get_tty_settings (tty, &ttybuff) == 0)
+    _rl_bind_tty_special_chars (kmap, ttybuff);
+#endif
+}
+
+/* New public way to set the system default editing chars to their readline
+   equivalents. */
+void
+rl_tty_set_default_bindings (kmap)
+     Keymap kmap;
+{
+  rltty_set_default_bindings (kmap);
+}
+
+/* Rebind all of the tty special chars that readline worries about back
+   to self-insert.  Call this before saving the current terminal special
+   chars with save_tty_chars().  This only works on POSIX termios or termio
+   systems. */
+void
+rl_tty_unset_default_bindings (kmap)
+     Keymap kmap;
+{
+  /* Don't bother before we've saved the tty special chars at least once. */
+  if (RL_ISSTATE(RL_STATE_TTYCSAVED) == 0)
+    return;
+
+  RESET_SPECIAL (_rl_tty_chars.t_erase);
+  RESET_SPECIAL (_rl_tty_chars.t_kill);
+
+#  if defined (VLNEXT) && defined (TERMIOS_TTY_DRIVER)
+  RESET_SPECIAL (_rl_tty_chars.t_lnext);
+#  endif /* VLNEXT && TERMIOS_TTY_DRIVER */
+
+#  if defined (VWERASE) && defined (TERMIOS_TTY_DRIVER)
+  RESET_SPECIAL (_rl_tty_chars.t_werase);
+#  endif /* VWERASE && TERMIOS_TTY_DRIVER */
+}
+
+#if defined (HANDLE_SIGNALS)
+
+#if defined (NEW_TTY_DRIVER) || defined (NO_TTY_DRIVER)
+int
+_rl_disable_tty_signals ()
+{
+  return 0;
+}
+
+int
+_rl_restore_tty_signals ()
+{
+  return 0;
+}
+#else
+
+static TIOTYPE sigstty, nosigstty;
+static int tty_sigs_disabled = 0;
+
+int
+_rl_disable_tty_signals ()
+{
+  if (tty_sigs_disabled)
+    return 0;
+
+  if (_get_tty_settings (fileno (rl_instream), &sigstty) < 0)
+    return -1;
+
+  nosigstty = sigstty;
+
+  nosigstty.c_lflag &= ~ISIG;
+  nosigstty.c_iflag &= ~IXON;
+
+  if (_set_tty_settings (fileno (rl_instream), &nosigstty) < 0)
+    return (_set_tty_settings (fileno (rl_instream), &sigstty));
+
+  tty_sigs_disabled = 1;
+  return 0;
+}
+
+int
+_rl_restore_tty_signals ()
+{
+  int r;
+
+  if (tty_sigs_disabled == 0)
+    return 0;
+
+  r = _set_tty_settings (fileno (rl_instream), &sigstty);
+
+  if (r == 0)
+    tty_sigs_disabled = 0;
+
+  return r;
+}
+#endif /* !NEW_TTY_DRIVER */
+
+#endif /* HANDLE_SIGNALS */
diff --git a/parse.y b/parse.y
index 65ec86aaeb8f9e330b83e448f371a76b14f112af..3c6a74baae1da729708485b34f36475e68491fa3 100644 (file)
--- a/parse.y
+++ b/parse.y
@@ -4431,7 +4431,7 @@ read_token_word (character)
              pop_delimiter (dstack);
              if (ttok == &matched_pair_error)
                return -1;              /* Bail immediately. */
-             RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 2,
+             RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 3,
                                      token_buffer_size,
                                      TOKEN_DEFAULT_GROW_SIZE);
              token[token_index++] = character;
@@ -4453,7 +4453,7 @@ read_token_word (character)
        {
          peek_char = shell_getc (1);
          /* $(...), <(...), >(...), $((...)), ${...}, and $[...] constructs */
-         if MBTEST(peek_char == '(' || \
+         if MBTEST(peek_char == '(' ||
                ((peek_char == '{' || peek_char == '[') && character == '$'))   /* ) ] } */
            {
              if (peek_char == '{')             /* } */
@@ -4473,7 +4473,7 @@ read_token_word (character)
                ttok = parse_matched_pair (cd, '[', ']', &ttoklen, 0);
              if (ttok == &matched_pair_error)
                return -1;              /* Bail immediately. */
-             RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 2,
+             RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 3,
                                      token_buffer_size,
                                      TOKEN_DEFAULT_GROW_SIZE);
              token[token_index++] = character;
@@ -4524,7 +4524,7 @@ read_token_word (character)
                  ttrans = ttok;
                }
 
-             RESIZE_MALLOCED_BUFFER (token, token_index, ttranslen + 2,
+             RESIZE_MALLOCED_BUFFER (token, token_index, ttranslen + 1,
                                      token_buffer_size,
                                      TOKEN_DEFAULT_GROW_SIZE);
              strcpy (token + token_index, ttrans);
@@ -4538,17 +4538,13 @@ read_token_word (character)
             shell's single-character parameter expansions, and set flags.*/
          else if MBTEST(character == '$' && peek_char == '$')
            {
-             ttok = (char *)xmalloc (3);
-             ttok[0] = ttok[1] = '$';
-             ttok[2] = '\0';
              RESIZE_MALLOCED_BUFFER (token, token_index, 3,
                                      token_buffer_size,
                                      TOKEN_DEFAULT_GROW_SIZE);
-             strcpy (token + token_index, ttok);
-             token_index += 2;
+             token[token_index++] = '$';
+             token[token_index++] = peek_char;
              dollar_present = 1;
              all_digit_token = 0;
-             FREE (ttok);
              goto next_character;
            }
          else
@@ -4618,21 +4614,24 @@ read_token_word (character)
          goto got_token;
        }
 
-    got_character:
+got_character:
 
       if (character == CTLESC || character == CTLNUL)
-       token[token_index++] = CTLESC;
+       {
+         RESIZE_MALLOCED_BUFFER (token, token_index, 2, token_buffer_size,
+                                 TOKEN_DEFAULT_GROW_SIZE);
+         token[token_index++] = CTLESC;
+       }
+      else
+got_escaped_character:
+       RESIZE_MALLOCED_BUFFER (token, token_index, 1, token_buffer_size,
+                               TOKEN_DEFAULT_GROW_SIZE);
 
-    got_escaped_character:
+      token[token_index++] = character;
 
       all_digit_token &= DIGIT (character);
       dollar_present |= character == '$';
 
-      token[token_index++] = character;
-
-      RESIZE_MALLOCED_BUFFER (token, token_index, 1, token_buffer_size,
-                             TOKEN_DEFAULT_GROW_SIZE);
-
     next_character:
       if (character == '\n' && SHOULD_PROMPT ())
        prompt_again ();
@@ -4646,14 +4645,15 @@ read_token_word (character)
 
 got_token:
 
+  /* Calls to RESIZE_MALLOCED_BUFFER ensure there is sufficient room. */
   token[token_index] = '\0';
 
   /* Check to see what thing we should return.  If the last_read_token
      is a `<', or a `&', or the character which ended this token is
      a '>' or '<', then, and ONLY then, is this input token a NUMBER.
      Otherwise, it is just a word, and should be returned as such. */
-  if MBTEST(all_digit_token && (character == '<' || character == '>' || \
-                   last_read_token == LESS_AND || \
+  if MBTEST(all_digit_token && (character == '<' || character == '>' ||
+                   last_read_token == LESS_AND ||
                    last_read_token == GREATER_AND))
       {
        if (legal_number (token, &lvalue) && (int)lvalue == lvalue)
index 2c576f58a36bdbc28fc0c5b1b854e65777a872a5..52efbd769e9fc000eb9e0685a0ec6aacca062f6b 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 1
+#define PATCHLEVEL 7
 
 #endif /* _PATCHLEVEL_H_ */
diff --git a/patchlevel.h~ b/patchlevel.h~
new file mode 100644 (file)
index 0000000..2c576f5
--- /dev/null
@@ -0,0 +1,30 @@
+/* patchlevel.h -- current bash patch level */
+
+/* Copyright (C) 2001-2010 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/>.
+*/
+
+#if !defined (_PATCHLEVEL_H_)
+#define _PATCHLEVEL_H_
+
+/* It's important that there be no other strings in this file that match the
+   regexp `^#define[   ]*PATCHLEVEL', since that's what support/mkversion.sh
+   looks for to find the patch level (for the sccs version string). */
+
+#define PATCHLEVEL 1
+
+#endif /* _PATCHLEVEL_H_ */
diff --git a/subst.c b/subst.c
index 7ac4768d4086dbb6dbfa8ddcb7a0b8aeaf1b8aa6..7e1a2edf55cc28a6196ba4b14ea3cb0c9eed4355 100644 (file)
--- a/subst.c
+++ b/subst.c
@@ -89,6 +89,7 @@ extern int errno;
 #define PF_NOCOMSUB    0x01    /* Do not perform command substitution */
 #define PF_IGNUNBOUND  0x02    /* ignore unbound vars even if -u set */
 #define PF_NOSPLIT2    0x04    /* same as W_NOSPLIT2 */
+#define PF_ASSIGNRHS   0x08    /* same as W_ASSIGNRHS */
 
 /* These defs make it easier to use the editor. */
 #define LBRACE         '{'
@@ -4611,6 +4612,7 @@ expand_word_unsplit (word, quoted)
   if (ifs_firstc == 0)
 #endif
     word->flags |= W_NOSPLIT;
+  word->flags |= W_NOSPLIT2;
   result = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL);
   expand_no_split_dollar_star = 0;
 
@@ -7609,17 +7611,16 @@ param_expand (string, sindex, quoted, expanded_something,
       if (contains_dollar_at)
        *contains_dollar_at = 1;
 
-#if 0
-      if (pflags & PF_NOSPLIT2)
-       temp = string_list_internal (quoted ? quote_list (list) : list, " ");
-      else
-#endif
       /* We want to separate the positional parameters with the first
         character of $IFS in case $IFS is something other than a space.
         We also want to make sure that splitting is done no matter what --
         according to POSIX.2, this expands to a list of the positional
         parameters no matter what IFS is set to. */
+#if 0
       temp = string_list_dollar_at (list, quoted);
+#else
+      temp = string_list_dollar_at (list, (pflags & PF_ASSIGNRHS) ? (quoted|Q_DOUBLE_QUOTES) : quoted);
+#endif
 
       dispose_words (list);
       break;
@@ -8113,6 +8114,8 @@ add_string:
          pflags = (word->flags & W_NOCOMSUB) ? PF_NOCOMSUB : 0;
          if (word->flags & W_NOSPLIT2)
            pflags |= PF_NOSPLIT2;
+         if (word->flags & W_ASSIGNRHS)
+           pflags |= PF_ASSIGNRHS;
          tword = param_expand (string, &sindex, quoted, expanded_something,
                               &has_dollar_at, &quoted_dollar_at,
                               &had_quoted_null, pflags);
index 72ec06a2c1fd8dde92acea5e8ac773e35f1d061b..3efcf32d68e9722024b6ca9d67f9e81b2aa5ac04 100755 (executable)
@@ -1,4 +1,4 @@
-BUILD_DIR=/usr/local/build/bash/bash-current
+BUILD_DIR=/usr/local/build/chet/bash/bash-current
 THIS_SH=$BUILD_DIR/bash
 PATH=$PATH:$BUILD_DIR
 
index 54e499d91bdd00aeefc6dd02dbcaff5ccde7ad87..042d58ded81a4b962b8f2b9296b4b352c60bf577 100755 (executable)
@@ -235,4 +235,7 @@ ${THIS_SH} ./dollar-star4.sub
 # tests for expansions of $* when IFS is null
 ${THIS_SH} ./dollar-star5.sub
 
+# tests for inappropriate word splitting through bash-4.2
+${THIS_SH} ./dollar-at4.sub
+
 exit 0
diff --git a/tests/dollar-at4.sub b/tests/dollar-at4.sub
new file mode 100644 (file)
index 0000000..c8de866
--- /dev/null
@@ -0,0 +1,10 @@
+set 'a  b' 'c  d'
+
+recho "$@"
+recho $@
+
+quoted="$@"
+unquoted=$@
+
+recho "$quoted"
+recho "$unquoted"
index 13db8e2c704ff3bf8ac0eaf0522b2500ecf1df9a..56e3e23b76c471f99e04605fd96c57765df28b55 100644 (file)
@@ -166,3 +166,11 @@ ab
 cd
 ok 1
 ok 2
+argv[1] = <a  b>
+argv[2] = <c  d>
+argv[1] = <a>
+argv[2] = <b>
+argv[3] = <c>
+argv[4] = <d>
+argv[1] = <a  b c  d>
+argv[1] = <a  b c  d>
index b8754dec7d56794aa0a3f542abd69738062f5773..cf9cb2aed7e3fa7098cd6b5fa3188f2c5ebc1b4e 100644 (file)
@@ -58,7 +58,8 @@ qux
 
 bar
 qux
+abc def geh
 comsub here-string
-./heredoc.tests: line 100: warning: here-document at line 98 delimited by end-of-file (wanted `EOF')
+./heredoc.tests: line 103: warning: here-document at line 101 delimited by end-of-file (wanted `EOF')
 hi
 there
index 79bf4ce72255b5860fc1f8e8dcc0bf36ad6dd476..b5773d77eeb6baad9232ec6c48578f0a3f058521 100644 (file)
@@ -88,6 +88,9 @@ ${THIS_SH} -c 'type fff'
 
 ${THIS_SH} ./heredoc1.sub
 
+# test heredocs in command substitutions
+${THIS_SH} ./heredoc2.sub
+
 echo $(
        cat <<< "comsub here-string"
 )
diff --git a/tests/heredoc2.sub b/tests/heredoc2.sub
new file mode 100644 (file)
index 0000000..7e97ed8
--- /dev/null
@@ -0,0 +1,9 @@
+TEST=$(cat <<EOF | sort -u
+abc
+geh
+def
+abc
+EOF
+)
+
+echo $TEST
index 85a2705c22b08785fe1ba68538412d7ad5a8d7f7..1925dd52325b1a87d3fb0ef4e5c94dec1722275d 100644 (file)
@@ -51,3 +51,7 @@ printf "%-40.50(%a %b %e %H:%M:%S %Z %Y)T date-style time\n" $SECS
 
 # test fieldwidth, justification, precision, embedded parens
 printf "%-40.50(%x (foo) %X)T date-style time\n" $SECS
+
+# problem introduced in bash-4.2 patch 5
+unset TZ
+printf '%(%Y-%m-%d %H:%M:%S %Z)T\n' >/dev/null
index f9d59a44de1e602f38909c7e861318725d50e408..08df3df5ff2a685097185cfa5bde93587c5c70e5 100644 (file)
@@ -90,3 +90,12 @@ argv[1] = <>
 good 1
 good 2
 good 3
+good 4
+good 5
+ok 1
+ok 2
+ok 3
+ok 4
+ok 5
+ok 6
+ok 7
index cae1487cbd548aa1bb69ba4d3fb1b81165c26797..421e97dbc2f6f34a782d7284cdb8d0194c646c8e 100644 (file)
@@ -37,3 +37,54 @@ if [ "$var"X == ""X"" ]; then
        echo good 3
 fi
 
+if [ X"" == X ]; then
+       echo good 4
+fi
+
+if [[ X"" == X ]]; then
+       echo good 5
+fi
+
+case x"" in
+  x) echo 'ok 1'
+     ;;
+  x??) echo 'this would be really odd'
+     ;;
+  x?) echo 'does this prove anything?'
+      echo x""x
+     ;;
+  *) echo 'no match'
+     ;;
+esac
+
+if [[ x"" == x ]]; then
+       echo ok 2
+fi
+
+if [[ x"\ 1" == x"\ 1" ]]; then
+       echo ok 3
+else
+       echo bad 3
+fi
+
+case x"\ 1" in
+x"\ 1")  echo ok 4 ;;
+*)     echo bad 4;;
+esac
+
+if [[ x"\7f" == x"\7f" ]]; then
+       echo ok 5
+else
+       echo bad 5
+fi
+
+case x"\7f" in
+"x\7f")  echo ok 6 ;;
+*)     echo bad 6;;
+esac
+
+case x"" in
+"x\7f")  echo CTLNUL 7 ;;
+x)     echo ok 7 ;;
+*)     echo bad 7 ;;
+esac
index daacdbf0ecb8f78d4c2fa3bf93a9e760f1fd68b9..7bb850fabdf2a5bb553256cbc6760078f9fc80fb 100644 (file)
@@ -3660,7 +3660,7 @@ chkexport (name)
   SHELL_VAR *v;
 
   v = find_variable (name);
-  if (exported_p (v))
+  if (v && exported_p (v))
     {
       array_needs_making = 1;
       maybe_make_export_env ();