Bash-4.3 distribution sources and documentation
[platform/upstream/bash.git] / lib / readline / display.c
index e4105ee..913e0da 100644 (file)
@@ -1,6 +1,6 @@
 /* display.c -- readline redisplay facility. */
 
-/* Copyright (C) 1987-2009 Free Software Foundation, Inc.
+/* Copyright (C) 1987-2013 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.
 
 #include <stdio.h>
 
+#ifdef __MSDOS__
+#  include <pc.h>
+#endif
+
 /* System-specific feature definitions and include files. */
 #include "rldefs.h"
 #include "rlmbutil.h"
@@ -63,6 +67,7 @@ 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 open_some_spaces PARAMS((int));
 static void cr PARAMS((void));
 
 /* State of visible and invisible lines. */
@@ -165,6 +170,7 @@ int _rl_last_v_pos = 0;
 
 static int cpos_adjusted;
 static int cpos_buffer_position;
+static int displaying_prompt_first_line;
 static int prompt_multibyte_chars;
 
 /* Number of lines currently on screen minus 1. */
@@ -176,7 +182,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;
@@ -232,6 +239,18 @@ static int saved_local_length;
 static int saved_invis_chars_first_line;
 static int saved_physical_chars;
 
+/* Return a character indicating the editing mode, for use in the prompt. */
+static int
+prompt_modechar ()
+{
+  if (rl_editing_mode == emacs_mode)
+    return '@';
+  else if (_rl_keymap == vi_insertion_keymap)
+    return '+';                /* vi insert mode */
+  else
+    return ':';                /* vi command mode */
+}
+
 /* 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
@@ -258,7 +277,16 @@ expand_prompt (pmt, lp, lip, niflp, vlp)
   /* Short-circuit if we can. */
   if ((MB_CUR_MAX <= 1 || rl_byte_oriented) && strchr (pmt, RL_PROMPT_START_IGNORE) == 0)
     {
-      r = savestring (pmt);
+      if (pmt == rl_prompt && _rl_show_mode_in_prompt)
+        {
+          l = strlen (pmt);
+          r = (char *)xmalloc (l + 2);
+          r[0] = prompt_modechar ();
+          strcpy (r + 1, pmt);
+        }
+      else
+       r = savestring (pmt);
+
       if (lp)
        *lp = strlen (r);
       if (lip)
@@ -271,13 +299,20 @@ expand_prompt (pmt, lp, lip, niflp, vlp)
     }
 
   l = strlen (pmt);
-  r = ret = (char *)xmalloc (l + 1);
+  r = ret = (char *)xmalloc (l + 2);
+
+  rl = physchars = 0;  /* move up here so mode show can set them */
+  if (pmt == rl_prompt && _rl_show_mode_in_prompt)
+    {
+      *r++ = prompt_modechar ();
+      rl = physchars = 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++)
+  for (ignoring = last = ninvis = 0, p = pmt; p && *p; p++)
     {
       /* This code strips the invisible character string markers
         RL_PROMPT_START_IGNORE and RL_PROMPT_END_IGNORE */
@@ -366,6 +401,12 @@ _rl_strip_prompt (pmt)
   return ret;
 }
 
+void
+_rl_reset_prompt ()
+{
+  rl_visible_prompt_length = rl_expand_prompt (rl_prompt);
+}
+
 /*
  * Expand the prompt string into the various display components, if
  * necessary.
@@ -707,10 +748,9 @@ rl_redisplay ()
       /* 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));
-             
+      temp += (newlines == 0) ? prompt_invis_chars_first_line
+                             : ((newlines == prompt_lines_estimate) ? wrap_offset : prompt_invis_chars_first_line);
+
       inv_lbreaks[++newlines] = temp;
 #if defined (HANDLE_MULTIBYTE)
       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0 && prompt_multibyte_chars > 0)
@@ -761,7 +801,7 @@ rl_redisplay ()
            break;                      /* Found '\0' */
          else
            {
-             temp = wcwidth (wc);
+             temp = WCWIDTH (wc);
              wc_width = (temp >= 0) ? temp : 1;
            }
        }
@@ -925,7 +965,7 @@ rl_redisplay ()
   /* 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. */
-
+  displaying_prompt_first_line = 1;
   if (_rl_horizontal_scroll_mode == 0 && _rl_term_up && *_rl_term_up)
     {
       int nleft, pos, changed_screen_line, tx;
@@ -1179,6 +1219,8 @@ rl_redisplay ()
       else
        lmargin = last_lmargin;
 
+      displaying_prompt_first_line = lmargin < nleft;
+
       /* 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)
@@ -1204,7 +1246,8 @@ rl_redisplay ()
                       _rl_screenwidth + (lmargin ? 0 : wrap_offset),
                       0);
 
-         if ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) && OLD_CPOS_IN_PROMPT())
+         if ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) &&
+               displaying_prompt_first_line && 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
@@ -1212,7 +1255,7 @@ rl_redisplay ()
             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) &&
+             (_rl_last_c_pos == out) && displaying_prompt_first_line &&
              t < visible_first_line_len)
            {
              nleft = _rl_screenwidth - t;
@@ -1274,6 +1317,7 @@ update_line (old, new, current_line, omax, nmax, inv_botlin)
   int temp, lendiff, wsatend, od, nd, twidth, o_cpos;
   int current_invis_chars;
   int col_lendiff, col_temp;
+  int bytes_to_insert;
 #if defined (HANDLE_MULTIBYTE)
   mbstate_t ps_new, ps_old;
   int new_offset, old_offset;
@@ -1300,7 +1344,7 @@ update_line (old, new, current_line, omax, nmax, inv_botlin)
          size_t ret;
 
          /* This fixes only double-column characters, but if the wrapped
-            character comsumes more than three columns, spaces will be
+            character consumes 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]);
@@ -1315,7 +1359,7 @@ update_line (old, new, current_line, omax, nmax, inv_botlin)
          else if (MB_NULLWCH (ret))
            tempwidth = 0;
          else
-           tempwidth = wcwidth (wc);
+           tempwidth = WCWIDTH (wc);
 
          if (tempwidth > 0)
            {
@@ -1335,7 +1379,7 @@ update_line (old, new, current_line, omax, nmax, inv_botlin)
                  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++)
+                 for (i = current_line+1; i <= inv_botlin+1; i++)
                    vis_lbreaks[i] += bytes - ret;
                }
            }
@@ -1372,6 +1416,7 @@ update_line (old, new, current_line, omax, nmax, inv_botlin)
       temp = (omax < nmax) ? omax : nmax;
       if (memcmp (old, new, temp) == 0)                /* adding at the end */
        {
+         new_offset = old_offset = temp;
          ofd = old + temp;
          nfd = new + temp;
        }
@@ -1382,6 +1427,8 @@ update_line (old, new, current_line, omax, nmax, inv_botlin)
 
          if (omax == nmax && STREQN (new, old, omax))
            {
+             old_offset = omax;
+             new_offset = nmax;
              ofd = old + omax;
              nfd = new + nmax;
            }
@@ -1394,6 +1441,7 @@ update_line (old, new, current_line, omax, nmax, inv_botlin)
                {
                  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;
                }
@@ -1417,6 +1465,27 @@ update_line (old, new, current_line, omax, nmax, inv_botlin)
   if (ofd == oe && nfd == ne)
     return;
 
+#if defined (HANDLE_MULTIBYTE)
+  if (MB_CUR_MAX > 1 && rl_byte_oriented == 0 && _rl_utf8locale)
+    {
+      wchar_t wc;
+      mbstate_t ps = { 0 };
+      int t;
+
+      /* If the first character in the difference is a zero-width character,
+        assume it's a combining character and back one up so the two base
+        characters no longer compare equivalently. */
+      t = mbrtowc (&wc, ofd, MB_CUR_MAX, &ps);
+      if (t > 0 && UNICODE_COMBINING_CHAR (wc) && WCWIDTH (wc) == 0)
+       {
+         old_offset = _rl_find_prev_mbchar (old, ofd - old, MB_FIND_ANY);
+         new_offset = _rl_find_prev_mbchar (new, nfd - new, MB_FIND_ANY);
+         ofd = old + old_offset;       /* equal by definition */
+         nfd = new + new_offset;
+       }
+    }
+#endif
+
   wsatend = 1;                 /* flag for trailing whitespace */
 
 #if defined (HANDLE_MULTIBYTE)
@@ -1424,6 +1493,7 @@ update_line (old, new, current_line, omax, nmax, inv_botlin)
     {
       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));
@@ -1540,10 +1610,10 @@ update_line (old, new, current_line, omax, nmax, inv_botlin)
   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
+     cursor position 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
@@ -1553,11 +1623,10 @@ update_line (old, new, current_line, omax, nmax, inv_botlin)
       _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
+     lendiff == difference in buffer (bytes)
+     col_lendiff == difference on screen (columns)
      When not using multibyte characters, these are equal */
   lendiff = (nls - nfd) - (ols - ofd);
   if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
@@ -1583,6 +1652,10 @@ update_line (old, new, current_line, omax, nmax, inv_botlin)
        }
     }
 
+  /* We use temp as a count of the number of bytes from the first difference
+     to the end of the new line.  col_temp is the corresponding number of
+     screen columns.  A `dumb' update moves to the spot of first difference
+     and writes TEMP bytes. */
   /* Insert (diff (len (old), len (new)) ch. */
   temp = ne - nfd;
   if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
@@ -1590,6 +1663,10 @@ update_line (old, new, current_line, omax, nmax, inv_botlin)
   else
     col_temp = temp;
 
+  /* how many bytes from the new line buffer to write to the display */
+  bytes_to_insert = nls - nfd;
+
+  /* col_lendiff > 0 if we are adding characters to the line */
   if (col_lendiff > 0) /* XXX - was lendiff */
     {
       /* Non-zero if we're increasing the number of lines. */
@@ -1603,11 +1680,11 @@ update_line (old, new, current_line, omax, nmax, inv_botlin)
       if (lendiff < 0)
        {
          _rl_output_some_chars (nfd, temp);
-         _rl_last_c_pos += _rl_col_width (nfd, 0, temp, 1);
+         _rl_last_c_pos += col_temp;   /* XXX - was _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))
+         if (current_line == 0 && displaying_prompt_first_line && wrap_offset && ((nfd - new) <= prompt_last_invisible))
            {
              _rl_last_c_pos -= wrap_offset;
              cpos_adjusted = 1;
@@ -1638,57 +1715,42 @@ update_line (old, new, current_line, omax, nmax, inv_botlin)
                        (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;
+             open_some_spaces (col_lendiff);
+             _rl_output_some_chars (nfd, bytes_to_insert);
+             if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+               _rl_last_c_pos += _rl_col_width (nfd, 0, bytes_to_insert, 1);
+             else
+               _rl_last_c_pos += bytes_to_insert;
            }
-#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;
+             _rl_output_some_chars (nfd, temp);
+             _rl_last_c_pos += col_temp;
+             return;
            }
-         else
+         else  /* just write from first difference to end of new line */
            {
              _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))
+             if ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) && current_line == 0 && displaying_prompt_first_line && 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)
+
+         if (bytes_to_insert > lendiff)
            {
-             _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))
+             if ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) && current_line == 0 && displaying_prompt_first_line && wrap_offset && ((nfd - new) <= prompt_last_invisible))
                {
                  _rl_last_c_pos -= wrap_offset;
                  cpos_adjusted = 1;
@@ -1706,6 +1768,7 @@ update_line (old, new, current_line, omax, nmax, inv_botlin)
             a physical character position. */
          if ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) &&
                current_line == prompt_last_screen_line && wrap_offset &&
+               displaying_prompt_first_line &&
                wrap_offset != prompt_invis_chars_first_line &&
                ((nfd-new) < (prompt_last_invisible-(current_line*_rl_screenwidth))))
            {
@@ -1723,32 +1786,47 @@ update_line (old, new, current_line, omax, nmax, inv_botlin)
             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 &&
+             displaying_prompt_first_line &&
              -lendiff == visible_wrap_offset)
            col_lendiff = 0;
 
+         /* If we have moved lmargin and we're shrinking the line, we've
+            already moved the cursor to the first character of the new line,
+            so deleting -col_lendiff characters will mess up the cursor
+            position calculation */
+         if (_rl_horizontal_scroll_mode && displaying_prompt_first_line == 0 &&
+               col_lendiff && _rl_last_c_pos < -col_lendiff)
+           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)
+         /* Copy (new) chars to screen from first diff to last match,
+            overwriting what is there. */
+         if (bytes_to_insert > 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_output_some_chars (nfd, bytes_to_insert);
              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 += _rl_col_width (nfd, 0, bytes_to_insert, 1);
+                 if (current_line == 0 && wrap_offset &&
+                       displaying_prompt_first_line &&
+                       _rl_last_c_pos > wrap_offset &&
+                       ((nfd - new) <= prompt_last_invisible))
                    {
                      _rl_last_c_pos -= wrap_offset;
                      cpos_adjusted = 1;
                    }
                }
              else
-               _rl_last_c_pos += temp;
+               _rl_last_c_pos += bytes_to_insert;
+
+             if (_rl_horizontal_scroll_mode && ((oe-old) > (ne-new)))
+               goto clear_rest_of_line;
            }
        }
       /* Otherwise, print over the existing material. */
@@ -1764,29 +1842,29 @@ update_line (old, new, current_line, omax, nmax, inv_botlin)
              _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))
+                 if (current_line == 0 && wrap_offset &&
+                       displaying_prompt_first_line &&
+                       _rl_last_c_pos > wrap_offset &&
+                       ((nfd - new) <= prompt_last_invisible))
                    {
                      _rl_last_c_pos -= wrap_offset;
                      cpos_adjusted = 1;
                    }
                }
            }
+clear_rest_of_line:
          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);
@@ -1938,6 +2016,9 @@ _rl_move_cursor_relative (new, data)
       else
         dpos = _rl_col_width (data, 0, new, 1);
 
+      if (displaying_prompt_first_line == 0)
+       adjust = 0;
+
       /* 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. */
@@ -2056,9 +2137,18 @@ _rl_move_vert (to)
     }
   else
     {                  /* delta < 0 */
+#ifdef __DJGPP__
+      int row, col;
+
+      fflush (rl_outstream);
+      ScreenGetCursor (&row, &col);
+      ScreenSetCursor (row + delta, col);
+      i = -delta;
+#else
       if (_rl_term_up && *_rl_term_up)
        for (i = 0; i < -delta; i++)
          tputs (_rl_term_up, 1, _rl_output_character_function);
+#endif /* !__DJGPP__ */
     }
 
   _rl_last_v_pos = to;         /* Now TO is here */
@@ -2136,6 +2226,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 +2237,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);
 
@@ -2157,6 +2267,12 @@ rl_message (va_alist)
       rl_save_prompt ();
       msg_saved_prompt = 1;
     }
+  else if (local_prompt != saved_local_prompt)
+    {
+      FREE (local_prompt);
+      FREE (local_prompt_prefix);
+      local_prompt = (char *)NULL;
+    }
   rl_display_prompt = msg_buf;
   local_prompt = expand_prompt (msg_buf, &prompt_visible_length,
                                         &prompt_last_invisible,
@@ -2173,8 +2289,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)
@@ -2182,6 +2301,12 @@ rl_message (format, arg1, arg2)
       rl_save_prompt ();
       msg_saved_prompt = 1;
     }
+  else if (local_prompt != saved_local_prompt)
+    {
+      FREE (local_prompt);
+      FREE (local_prompt_prefix);
+      local_prompt = (char *)NULL;
+    }
   local_prompt = expand_prompt (msg_buf, &prompt_visible_length,
                                         &prompt_last_invisible,
                                         &prompt_invis_chars_first_line,
@@ -2318,10 +2443,13 @@ void
 _rl_clear_to_eol (count)
      int count;
 {
+#ifndef __MSDOS__
   if (_rl_term_clreol)
     tputs (_rl_term_clreol, 1, _rl_output_character_function);
-  else if (count)
-    space_to_eol (count);
+  else
+#endif
+    if (count)
+      space_to_eol (count);
 }
 
 /* Clear to the end of the line using spaces.  COUNT is the minimum
@@ -2341,10 +2469,15 @@ space_to_eol (count)
 void
 _rl_clear_screen ()
 {
+#ifndef __DJGPP__
   if (_rl_term_clrpag)
     tputs (_rl_term_clrpag, 1, _rl_output_character_function);
   else
     rl_crlf ();
+#else
+  ScreenClear ();
+  ScreenSetCursor (0, 0);
+#endif /* __DJGPP__ */
 }
 
 /* Insert COUNT characters from STRING to the output stream at column COL. */
@@ -2353,48 +2486,47 @@ insert_some_chars (string, count, col)
      char *string;
      int count, col;
 {
-#if defined (__MSDOS__) || defined (__MINGW32__)
+  open_some_spaces (col);
   _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);
+}
+
+/* Insert COL spaces, keeping the cursor at the same position.  We follow the
+   ncurses documentation and use either im/ei with explicit spaces, or IC/ic
+   by itself.  We assume there will either be ei or we don't need to use it. */
+static void
+open_some_spaces (col)
+     int col;
+{
+#if !defined (__MSDOS__) && !defined (__MINGW32__)
+  char *buffer;
+  register int i;
 
   /* 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
+  else if (_rl_term_im && *_rl_term_im)
     {
-      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. */
+      tputs (_rl_term_im, 1, _rl_output_character_function);
+      /* just output the desired number of spaces */
+      for (i = col; i--; )
+       _rl_output_character_function (' ');
+      /* If there is a string to turn off insert mode, use it now. */
       if (_rl_term_ei && *_rl_term_ei)
        tputs (_rl_term_ei, 1, _rl_output_character_function);
+      /* and move back the right number of spaces */
+      _rl_backspace (col);
+    }
+  else if (_rl_term_ic && *_rl_term_ic)
+    {
+      /* If there is a special command for inserting characters, then
+        use that first to open up the space. */
+      for (i = col; i--; )
+       tputs (_rl_term_ic, 1, _rl_output_character_function);
     }
-#endif /* __MSDOS__ || __MINGW32__ */
+#endif /* !__MSDOS__ && !__MINGW32__ */
 }
 
 /* Delete COUNT characters from the display line. */
@@ -2599,10 +2731,8 @@ _rl_col_width (str, start, end, flags)
   if (end <= start)
     return 0;
   if (MB_CUR_MAX == 1 || rl_byte_oriented)
-{
-_rl_ttymsg ("_rl_col_width: called with MB_CUR_MAX == 1");
+    /* this can happen in some cases where it's inconvenient to check */
     return (end - start);
-}
 
   memset (&ps, 0, sizeof (mbstate_t));
 
@@ -2676,7 +2806,7 @@ _rl_ttymsg ("_rl_col_width: called with MB_CUR_MAX == 1");
        {
          point += tmp;
          max -= tmp;
-         tmp = wcwidth(wc);
+         tmp = WCWIDTH(wc);
          width += (tmp >= 0) ? tmp : 1;
        }
     }