display.c revision 26497
121308Sache/* display.c -- readline redisplay facility. */
221308Sache
321308Sache/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
421308Sache
521308Sache   This file is part of the GNU Readline Library, a library for
621308Sache   reading lines of text with interactive input and history editing.
721308Sache
821308Sache   The GNU Readline Library is free software; you can redistribute it
921308Sache   and/or modify it under the terms of the GNU General Public License
1021308Sache   as published by the Free Software Foundation; either version 1, or
1121308Sache   (at your option) any later version.
1221308Sache
1321308Sache   The GNU Readline Library is distributed in the hope that it will be
1421308Sache   useful, but WITHOUT ANY WARRANTY; without even the implied warranty
1521308Sache   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1621308Sache   GNU General Public License for more details.
1721308Sache
1821308Sache   The GNU General Public License is often shipped with GNU software, and
1921308Sache   is generally kept in a file called COPYING or LICENSE.  If you do not
2021308Sache   have a copy of the license, write to the Free Software Foundation,
2121308Sache   675 Mass Ave, Cambridge, MA 02139, USA. */
2221308Sache#define READLINE_LIBRARY
2321308Sache
2421308Sache#if defined (HAVE_CONFIG_H)
2521308Sache#  include <config.h>
2621308Sache#endif
2721308Sache
2821308Sache#include <sys/types.h>
2921308Sache
3021308Sache#if defined (HAVE_UNISTD_H)
3121308Sache#  include <unistd.h>
3221308Sache#endif /* HAVE_UNISTD_H */
3321308Sache
3426497Sache#include "posixstat.h"
3526497Sache
3621308Sache#if defined (HAVE_STDLIB_H)
3721308Sache#  include <stdlib.h>
3821308Sache#else
3921308Sache#  include "ansi_stdlib.h"
4021308Sache#endif /* HAVE_STDLIB_H */
4121308Sache
4226497Sache#include <stdio.h>
4321308Sache
4426497Sache#if defined (__GO32__)
4526497Sache#  include <go32.h>
4626497Sache#  include <pc.h>
4726497Sache#endif /* __GO32__ */
4826497Sache
4921308Sache/* System-specific feature definitions and include files. */
5021308Sache#include "rldefs.h"
5121308Sache
5221308Sache/* Termcap library stuff. */
5321308Sache#include "tcap.h"
5421308Sache
5521308Sache/* Some standard library routines. */
5621308Sache#include "readline.h"
5721308Sache#include "history.h"
5821308Sache
5921308Sache#if !defined (strchr) && !defined (__STDC__)
6021308Sacheextern char *strchr (), *strrchr ();
6121308Sache#endif /* !strchr && !__STDC__ */
6221308Sache
6321308Sache/* Global and pseudo-global variables and functions
6421308Sache   imported from readline.c. */
6521308Sacheextern char *rl_prompt;
6621308Sacheextern int readline_echoing_p;
6721308Sache
6821308Sacheextern int _rl_output_meta_chars;
6921308Sacheextern int _rl_horizontal_scroll_mode;
7021308Sacheextern int _rl_mark_modified_lines;
7121308Sacheextern int _rl_prefer_visible_bell;
7221308Sache
7321308Sache/* Variables and functions imported from terminal.c */
7421308Sacheextern void _rl_output_some_chars ();
7521308Sacheextern int _rl_output_character_function ();
7621308Sacheextern int _rl_backspace ();
7721308Sache
7826497Sacheextern char *term_clreol, *term_clrpag;
7926497Sacheextern char *term_im, *term_ic,  *term_ei, *term_DC;
8021308Sacheextern char *term_up, *term_dc, *term_cr, *term_IC;
8121308Sacheextern int screenheight, screenwidth, screenchars;
8221308Sacheextern int terminal_can_insert, _rl_term_autowrap;
8321308Sache
8421308Sache/* Pseudo-global functions (local to the readline library) exported
8521308Sache   by this file. */
8621308Sachevoid _rl_move_cursor_relative (), _rl_output_some_chars ();
8721308Sachevoid _rl_move_vert ();
8826497Sachevoid _rl_clear_to_eol (), _rl_clear_screen ();
8921308Sache
9026497Sachestatic void update_line (), space_to_eol ();
9121308Sachestatic void delete_chars (), insert_some_chars ();
9221308Sachestatic void cr ();
9321308Sache
9421308Sachestatic int *inv_lbreaks, *vis_lbreaks;
9521308Sache
9621308Sacheextern char *xmalloc (), *xrealloc ();
9721308Sache
9821308Sache/* Heuristic used to decide whether it is faster to move from CUR to NEW
9921308Sache   by backing up or outputting a carriage return and moving forward. */
10021308Sache#define CR_FASTER(new, cur) (((new) + 1) < ((cur) - (new)))
10121308Sache
10221308Sache/* **************************************************************** */
10321308Sache/*								    */
10421308Sache/*			Display stuff				    */
10521308Sache/*								    */
10621308Sache/* **************************************************************** */
10721308Sache
10821308Sache/* This is the stuff that is hard for me.  I never seem to write good
10921308Sache   display routines in C.  Let's see how I do this time. */
11021308Sache
11121308Sache/* (PWP) Well... Good for a simple line updater, but totally ignores
11221308Sache   the problems of input lines longer than the screen width.
11321308Sache
11421308Sache   update_line and the code that calls it makes a multiple line,
11521308Sache   automatically wrapping line update.  Careful attention needs
11621308Sache   to be paid to the vertical position variables. */
11721308Sache
11821308Sache/* Keep two buffers; one which reflects the current contents of the
11921308Sache   screen, and the other to draw what we think the new contents should
12021308Sache   be.  Then compare the buffers, and make whatever changes to the
12121308Sache   screen itself that we should.  Finally, make the buffer that we
12221308Sache   just drew into be the one which reflects the current contents of the
12321308Sache   screen, and place the cursor where it belongs.
12421308Sache
12521308Sache   Commands that want to can fix the display themselves, and then let
12621308Sache   this function know that the display has been fixed by setting the
12721308Sache   RL_DISPLAY_FIXED variable.  This is good for efficiency. */
12821308Sache
12921308Sache/* Application-specific redisplay function. */
13021308SacheVFunction *rl_redisplay_function = rl_redisplay;
13121308Sache
13221308Sache/* Global variables declared here. */
13321308Sache/* What YOU turn on when you have handled all redisplay yourself. */
13421308Sacheint rl_display_fixed = 0;
13521308Sache
13621308Sacheint _rl_suppress_redisplay = 0;
13721308Sache
13821308Sache/* The stuff that gets printed out before the actual text of the line.
13921308Sache   This is usually pointing to rl_prompt. */
14021308Sachechar *rl_display_prompt = (char *)NULL;
14121308Sache
14221308Sache/* Pseudo-global variables declared here. */
14321308Sache/* The visible cursor position.  If you print some text, adjust this. */
14421308Sacheint _rl_last_c_pos = 0;
14521308Sacheint _rl_last_v_pos = 0;
14621308Sache
14721308Sache/* Number of lines currently on screen minus 1. */
14821308Sacheint _rl_vis_botlin = 0;
14921308Sache
15021308Sache/* Variables used only in this file. */
15121308Sache/* The last left edge of text that was displayed.  This is used when
15221308Sache   doing horizontal scrolling.  It shifts in thirds of a screenwidth. */
15321308Sachestatic int last_lmargin;
15421308Sache
15521308Sache/* The line display buffers.  One is the line currently displayed on
15621308Sache   the screen.  The other is the line about to be displayed. */
15721308Sachestatic char *visible_line = (char *)NULL;
15821308Sachestatic char *invisible_line = (char *)NULL;
15921308Sache
16021308Sache/* A buffer for `modeline' messages. */
16121308Sachestatic char msg_buf[128];
16221308Sache
16321308Sache/* Non-zero forces the redisplay even if we thought it was unnecessary. */
16421308Sachestatic int forced_display;
16521308Sache
16621308Sache/* Default and initial buffer size.  Can grow. */
16721308Sachestatic int line_size = 1024;
16821308Sache
16921308Sachestatic char *local_prompt, *local_prompt_prefix;
17021308Sachestatic int visible_length, prefix_length;
17121308Sache
17221308Sache/* The number of invisible characters in the line currently being
17321308Sache   displayed on the screen. */
17421308Sachestatic int visible_wrap_offset;
17521308Sache
17621308Sache/* static so it can be shared between rl_redisplay and update_line */
17721308Sachestatic int wrap_offset;
17821308Sache
17921308Sache/* The index of the last invisible_character in the prompt string. */
18021308Sachestatic int last_invisible;
18121308Sache
18221308Sache/* The length (buffer offset) of the first line of the last (possibly
18321308Sache   multi-line) buffer displayed on the screen. */
18421308Sachestatic int visible_first_line_len;
18521308Sache
18621308Sache/* Expand the prompt string S and return the number of visible
18721308Sache   characters in *LP, if LP is not null.  This is currently more-or-less
18821308Sache   a placeholder for expansion.  LIP, if non-null is a place to store the
18921308Sache   index of the last invisible character in ther eturned string. */
19021308Sache
19121308Sache/* Current implementation:
19221308Sache	\001 (^A) start non-visible characters
19321308Sache	\002 (^B) end non-visible characters
19421308Sache   all characters except \001 and \002 (following a \001) are copied to
19521308Sache   the returned string; all characters except those between \001 and
19621308Sache   \002 are assumed to be `visible'. */
19721308Sache
19821308Sachestatic char *
19921308Sacheexpand_prompt (pmt, lp, lip)
20021308Sache     char *pmt;
20121308Sache     int *lp, *lip;
20221308Sache{
20321308Sache  char *r, *ret, *p;
20421308Sache  int l, rl, last, ignoring;
20521308Sache
20621308Sache  /* Short-circuit if we can. */
20721308Sache  if (strchr (pmt, RL_PROMPT_START_IGNORE) == 0)
20821308Sache    {
20921308Sache      r = savestring (pmt);
21021308Sache      if (lp)
21121308Sache	*lp = strlen (r);
21221308Sache      return r;
21321308Sache    }
21421308Sache
21521308Sache  l = strlen (pmt);
21621308Sache  r = ret = xmalloc (l + 1);
21721308Sache
21821308Sache  for (rl = ignoring = last = 0, p = pmt; p && *p; p++)
21921308Sache    {
22021308Sache      /* This code strips the invisible character string markers
22121308Sache	 RL_PROMPT_START_IGNORE and RL_PROMPT_END_IGNORE */
22221308Sache      if (*p == RL_PROMPT_START_IGNORE)
22321308Sache	{
22421308Sache	  ignoring++;
22521308Sache	  continue;
22621308Sache	}
22721308Sache      else if (ignoring && *p == RL_PROMPT_END_IGNORE)
22821308Sache	{
22921308Sache	  ignoring = 0;
23021308Sache	  last = r - ret - 1;
23121308Sache	  continue;
23221308Sache	}
23321308Sache      else
23421308Sache	{
23521308Sache	  *r++ = *p;
23621308Sache	  if (!ignoring)
23721308Sache	    rl++;
23821308Sache	}
23921308Sache    }
24021308Sache
24121308Sache  *r = '\0';
24221308Sache  if (lp)
24321308Sache    *lp = rl;
24421308Sache  if (lip)
24521308Sache    *lip = last;
24621308Sache  return ret;
24721308Sache}
24821308Sache
24921308Sache/*
25021308Sache * Expand the prompt string into the various display components, if
25121308Sache * necessary.
25221308Sache *
25321308Sache * local_prompt = expanded last line of string in rl_display_prompt
25421308Sache *		  (portion after the final newline)
25521308Sache * local_prompt_prefix = portion before last newline of rl_display_prompt,
25621308Sache *			 expanded via expand_prompt
25721308Sache * visible_length = number of visible characters in local_prompt
25821308Sache * prefix_length = number of visible characters in local_prompt_prefix
25921308Sache *
26021308Sache * This function is called once per call to readline().  It may also be
26121308Sache * called arbitrarily to expand the primary prompt.
26221308Sache *
26321308Sache * The return value is the number of visible characters on the last line
26421308Sache * of the (possibly multi-line) prompt.
26521308Sache */
26621308Sacheint
26721308Sacherl_expand_prompt (prompt)
26821308Sache     char *prompt;
26921308Sache{
27021308Sache  char *p, *t;
27121308Sache  int c;
27221308Sache
27321308Sache  /* Clear out any saved values. */
27421308Sache  if (local_prompt)
27521308Sache    free (local_prompt);
27621308Sache  if (local_prompt_prefix)
27721308Sache    free (local_prompt_prefix);
27821308Sache  local_prompt = local_prompt_prefix = (char *)0;
27921308Sache  last_invisible = 0;
28021308Sache
28121308Sache  if (prompt == 0 || *prompt == 0)
28221308Sache    return (0);
28321308Sache
28421308Sache  p = strrchr (prompt, '\n');
28521308Sache  if (!p)
28621308Sache    {
28721308Sache      /* The prompt is only one line. */
28821308Sache      local_prompt = expand_prompt (prompt, &visible_length, &last_invisible);
28921308Sache      local_prompt_prefix = (char *)0;
29021308Sache      return (visible_length);
29121308Sache    }
29221308Sache  else
29321308Sache    {
29421308Sache      /* The prompt spans multiple lines. */
29521308Sache      t = ++p;
29621308Sache      local_prompt = expand_prompt (p, &visible_length, &last_invisible);
29721308Sache      c = *t; *t = '\0';
29821308Sache      /* The portion of the prompt string up to and including the
29921308Sache	 final newline is now null-terminated. */
30021308Sache      local_prompt_prefix = expand_prompt (prompt, &prefix_length, (int *)NULL);
30121308Sache      *t = c;
30221308Sache      return (prefix_length);
30321308Sache    }
30421308Sache}
30521308Sache
30621308Sache/* Basic redisplay algorithm. */
30721308Sachevoid
30821308Sacherl_redisplay ()
30921308Sache{
31021308Sache  register int in, out, c, linenum, cursor_linenum;
31121308Sache  register char *line;
31221308Sache  int c_pos, inv_botlin, lb_botlin, lb_linenum;
31326497Sache  int newlines, lpos, temp;
31421308Sache  char *prompt_this_line;
31521308Sache
31621308Sache  if (!readline_echoing_p)
31721308Sache    return;
31821308Sache
31921308Sache  if (!rl_display_prompt)
32021308Sache    rl_display_prompt = "";
32121308Sache
32221308Sache  if (invisible_line == 0)
32321308Sache    {
32421308Sache      visible_line = xmalloc (line_size);
32521308Sache      invisible_line = xmalloc (line_size);
32621308Sache      for (in = 0; in < line_size; in++)
32721308Sache	{
32821308Sache	  visible_line[in] = 0;
32921308Sache	  invisible_line[in] = 1;
33021308Sache	}
33121308Sache
33221308Sache      /* should be enough, but then again, this is just for testing. */
33321308Sache      inv_lbreaks = (int *)malloc (256 * sizeof (int));
33421308Sache      vis_lbreaks = (int *)malloc (256 * sizeof (int));
33521308Sache      inv_lbreaks[0] = vis_lbreaks[0] = 0;
33621308Sache
33721308Sache      rl_on_new_line ();
33821308Sache    }
33921308Sache
34021308Sache  /* Draw the line into the buffer. */
34121308Sache  c_pos = -1;
34221308Sache
34321308Sache  line = invisible_line;
34421308Sache  out = inv_botlin = 0;
34521308Sache
34621308Sache  /* Mark the line as modified or not.  We only do this for history
34721308Sache     lines. */
34821308Sache  if (_rl_mark_modified_lines && current_history () && rl_undo_list)
34921308Sache    {
35021308Sache      line[out++] = '*';
35121308Sache      line[out] = '\0';
35221308Sache    }
35321308Sache
35421308Sache  /* If someone thought that the redisplay was handled, but the currently
35521308Sache     visible line has a different modification state than the one about
35621308Sache     to become visible, then correct the caller's misconception. */
35721308Sache  if (visible_line[0] != invisible_line[0])
35821308Sache    rl_display_fixed = 0;
35921308Sache
36021308Sache  /* If the prompt to be displayed is the `primary' readline prompt (the
36121308Sache     one passed to readline()), use the values we have already expanded.
36221308Sache     If not, use what's already in rl_display_prompt.  WRAP_OFFSET is the
36321308Sache     number of non-visible characters in the prompt string. */
36421308Sache  if (rl_display_prompt == rl_prompt || local_prompt)
36521308Sache    {
36621308Sache      int local_len = local_prompt ? strlen (local_prompt) : 0;
36721308Sache      if (local_prompt_prefix && forced_display)
36821308Sache	_rl_output_some_chars (local_prompt_prefix, strlen (local_prompt_prefix));
36921308Sache
37021308Sache      if (local_len > 0)
37121308Sache	{
37221308Sache	  strncpy (line + out, local_prompt, local_len);
37321308Sache	  out += local_len;
37421308Sache	}
37521308Sache      line[out] = '\0';
37621308Sache      wrap_offset = local_len - visible_length;
37721308Sache    }
37821308Sache  else
37921308Sache    {
38021308Sache      int pmtlen;
38121308Sache      prompt_this_line = strrchr (rl_display_prompt, '\n');
38221308Sache      if (!prompt_this_line)
38321308Sache	prompt_this_line = rl_display_prompt;
38421308Sache      else
38521308Sache	{
38621308Sache	  prompt_this_line++;
38721308Sache	  if (forced_display)
38821308Sache	    {
38921308Sache	      _rl_output_some_chars (rl_display_prompt, prompt_this_line - rl_display_prompt);
39021308Sache	      /* Make sure we are at column zero even after a newline,
39121308Sache		 regardless of the state of terminal output processing. */
39221308Sache	      if (prompt_this_line[-2] != '\r')
39321308Sache		cr ();
39421308Sache	    }
39521308Sache	}
39621308Sache
39721308Sache      pmtlen = strlen (prompt_this_line);
39821308Sache      strncpy (line + out,  prompt_this_line, pmtlen);
39921308Sache      out += pmtlen;
40021308Sache      line[out] = '\0';
40121308Sache      wrap_offset = 0;
40221308Sache    }
40321308Sache
40421308Sache#define CHECK_LPOS() \
40521308Sache      do { \
40621308Sache        lpos++; \
40721308Sache        if (lpos >= screenwidth) \
40821308Sache          { \
40921308Sache            inv_lbreaks[++newlines] = out; \
41021308Sache            lpos = 0; \
41121308Sache          } \
41221308Sache      } while (0)
41321308Sache
41421308Sache  /* inv_lbreaks[i] is where line i starts in the buffer. */
41521308Sache  inv_lbreaks[newlines = 0] = 0;
41626497Sache  lpos = out - wrap_offset;
41721308Sache
41826497Sache  /* XXX - what if lpos is already >= screenwidth before we start drawing the
41926497Sache     contents of the command line? */
42026497Sache  while (lpos >= screenwidth)
42121308Sache    {
42226497Sache      temp = ((newlines + 1) * screenwidth) - ((newlines == 0) ? wrap_offset : 0);
42326497Sache      inv_lbreaks[++newlines] = temp;
42426497Sache      lpos -= screenwidth;
42526497Sache    }
42626497Sache
42726497Sache  lb_linenum = 0;
42826497Sache  for (in = 0; in < rl_end; in++)
42926497Sache    {
43021308Sache      c = (unsigned char)rl_line_buffer[in];
43121308Sache
43221308Sache      if (out + 8 >= line_size)		/* XXX - 8 for \t */
43321308Sache	{
43421308Sache	  line_size *= 2;
43521308Sache	  visible_line = xrealloc (visible_line, line_size);
43621308Sache	  invisible_line = xrealloc (invisible_line, line_size);
43721308Sache	  line = invisible_line;
43821308Sache	}
43921308Sache
44021308Sache      if (in == rl_point)
44121308Sache	{
44221308Sache	  c_pos = out;
44321308Sache	  lb_linenum = newlines;
44421308Sache	}
44521308Sache
44621308Sache      if (META_CHAR (c))
44721308Sache	{
44821308Sache	  if (_rl_output_meta_chars == 0)
44921308Sache	    {
45021308Sache	      sprintf (line + out, "\\%o", c);
45121308Sache
45221308Sache	      if (lpos + 4 >= screenwidth)
45321308Sache		{
45421308Sache		  temp = screenwidth - lpos;
45521308Sache		  inv_lbreaks[++newlines] = out + temp;
45621308Sache		  lpos = 4 - temp;
45721308Sache		}
45821308Sache	      else
45921308Sache		lpos += 4;
46021308Sache
46121308Sache	      out += 4;
46221308Sache	    }
46321308Sache	  else
46421308Sache	    {
46521308Sache	      line[out++] = c;
46621308Sache	      CHECK_LPOS();
46721308Sache	    }
46821308Sache	}
46921308Sache#if defined (DISPLAY_TABS)
47021308Sache      else if (c == '\t')
47121308Sache	{
47221308Sache	  register int temp, newout;
47321308Sache	  newout = (out | (int)7) + 1;
47421308Sache	  temp = newout - out;
47521308Sache	  if (lpos + temp >= screenwidth)
47621308Sache	    {
47721308Sache	      register int temp2;
47821308Sache	      temp2 = screenwidth - lpos;
47921308Sache	      inv_lbreaks[++newlines] = out + temp2;
48021308Sache	      lpos = temp - temp2;
48121308Sache	      while (out < newout)
48221308Sache		line[out++] = ' ';
48321308Sache	    }
48421308Sache	  else
48521308Sache	    {
48621308Sache	      while (out < newout)
48721308Sache		line[out++] = ' ';
48821308Sache	      lpos += temp;
48921308Sache	    }
49021308Sache	}
49121308Sache#endif
49221308Sache      else if (c == '\n' && _rl_horizontal_scroll_mode == 0 && term_up && *term_up)
49321308Sache        {
49421308Sache          line[out++] = '\0';	/* XXX - sentinel */
49521308Sache          inv_lbreaks[++newlines] = out;
49621308Sache          lpos = 0;
49721308Sache        }
49821308Sache      else if (CTRL_CHAR (c) || c == RUBOUT)
49921308Sache	{
50021308Sache	  line[out++] = '^';
50121308Sache	  CHECK_LPOS();
50221308Sache	  line[out++] = CTRL_CHAR (c) ? UNCTRL (c) : '?';
50321308Sache	  CHECK_LPOS();
50421308Sache	}
50521308Sache      else
50621308Sache	{
50721308Sache	  line[out++] = c;
50821308Sache	  CHECK_LPOS();
50921308Sache	}
51021308Sache    }
51121308Sache  line[out] = '\0';
51221308Sache  if (c_pos < 0)
51321308Sache    {
51421308Sache      c_pos = out;
51521308Sache      lb_linenum = newlines;
51621308Sache    }
51721308Sache
51821308Sache  inv_botlin = lb_botlin = newlines;
51921308Sache  inv_lbreaks[newlines+1] = out;
52021308Sache  cursor_linenum = lb_linenum;
52121308Sache
52221308Sache  /* C_POS == position in buffer where cursor should be placed. */
52321308Sache
52421308Sache  /* PWP: now is when things get a bit hairy.  The visible and invisible
52521308Sache     line buffers are really multiple lines, which would wrap every
52621308Sache     (screenwidth - 1) characters.  Go through each in turn, finding
52721308Sache     the changed region and updating it.  The line order is top to bottom. */
52821308Sache
52921308Sache  /* If we can move the cursor up and down, then use multiple lines,
53021308Sache     otherwise, let long lines display in a single terminal line, and
53121308Sache     horizontally scroll it. */
53221308Sache
53321308Sache  if (_rl_horizontal_scroll_mode == 0 && term_up && *term_up)
53421308Sache    {
53521308Sache      int nleft, pos, changed_screen_line;
53621308Sache
53721308Sache      if (!rl_display_fixed || forced_display)
53821308Sache	{
53921308Sache	  forced_display = 0;
54021308Sache
54121308Sache	  /* If we have more than a screenful of material to display, then
54221308Sache	     only display a screenful.  We should display the last screen,
54321308Sache	     not the first.  */
54421308Sache	  if (out >= screenchars)
54521308Sache	    out = screenchars - 1;
54621308Sache
54721308Sache	  /* The first line is at character position 0 in the buffer.  The
54821308Sache	     second and subsequent lines start at inv_lbreaks[N], offset by
54921308Sache	     OFFSET (which has already been calculated above).  */
55021308Sache
55121308Sache#define W_OFFSET(line, offset) ((line) == 0 ? offset : 0)
55221308Sache#define VIS_LLEN(l)	((l) > _rl_vis_botlin ? 0 : (vis_lbreaks[l+1] - vis_lbreaks[l]))
55321308Sache#define INV_LLEN(l)	(inv_lbreaks[l+1] - inv_lbreaks[l])
55421308Sache#define VIS_CHARS(line) (visible_line + vis_lbreaks[line])
55521308Sache#define VIS_LINE(line) ((line) > _rl_vis_botlin) ? "" : VIS_CHARS(line)
55621308Sache#define INV_LINE(line) (invisible_line + inv_lbreaks[line])
55721308Sache
55821308Sache	  /* For each line in the buffer, do the updating display. */
55921308Sache	  for (linenum = 0; linenum <= inv_botlin; linenum++)
56021308Sache	    {
56121308Sache	      update_line (VIS_LINE(linenum), INV_LINE(linenum), linenum,
56221308Sache			   VIS_LLEN(linenum), INV_LLEN(linenum), inv_botlin);
56321308Sache
56421308Sache	      /* If this is the line with the prompt, we might need to
56521308Sache		 compensate for invisible characters in the new line. Do
56621308Sache		 this only if there is not more than one new line (which
56721308Sache		 implies that we completely overwrite the old visible line)
56821308Sache		 and the new line is shorter than the old.  Make sure we are
56921308Sache		 at the end of the new line before clearing. */
57021308Sache	      if (linenum == 0 &&
57121308Sache		  inv_botlin == 0 && _rl_last_c_pos == out &&
57221308Sache		  (wrap_offset > visible_wrap_offset) &&
57321308Sache		  (_rl_last_c_pos < visible_first_line_len))
57421308Sache		{
57521308Sache		  nleft = screenwidth + wrap_offset - _rl_last_c_pos;
57621308Sache		  if (nleft)
57726497Sache		    _rl_clear_to_eol (nleft);
57821308Sache		}
57921308Sache
58021308Sache	      /* Since the new first line is now visible, save its length. */
58121308Sache	      if (linenum == 0)
58221308Sache		visible_first_line_len = (inv_botlin > 0) ? inv_lbreaks[1] : out - wrap_offset;
58321308Sache	    }
58421308Sache
58521308Sache	  /* We may have deleted some lines.  If so, clear the left over
58621308Sache	     blank ones at the bottom out. */
58721308Sache	  if (_rl_vis_botlin > inv_botlin)
58821308Sache	    {
58921308Sache	      char *tt;
59021308Sache	      for (; linenum <= _rl_vis_botlin; linenum++)
59121308Sache		{
59221308Sache		  tt = VIS_CHARS (linenum);
59321308Sache		  _rl_move_vert (linenum);
59421308Sache		  _rl_move_cursor_relative (0, tt);
59526497Sache		  _rl_clear_to_eol
59621308Sache		    ((linenum == _rl_vis_botlin) ? strlen (tt) : screenwidth);
59721308Sache		}
59821308Sache	    }
59921308Sache	  _rl_vis_botlin = inv_botlin;
60021308Sache
60121308Sache	  /* CHANGED_SCREEN_LINE is set to 1 if we have moved to a
60221308Sache	     different screen line during this redisplay. */
60321308Sache	  changed_screen_line = _rl_last_v_pos != cursor_linenum;
60421308Sache	  if (changed_screen_line)
60521308Sache	    {
60621308Sache	      _rl_move_vert (cursor_linenum);
60721308Sache	      /* If we moved up to the line with the prompt using term_up,
60821308Sache	         the physical cursor position on the screen stays the same,
60921308Sache	         but the buffer position needs to be adjusted to account
61021308Sache	         for invisible characters. */
61121308Sache	      if (cursor_linenum == 0 && wrap_offset)
61221308Sache	        _rl_last_c_pos += wrap_offset;
61321308Sache	    }
61421308Sache
61521308Sache	  /* We have to reprint the prompt if it contains invisible
61621308Sache	     characters, since it's not generally OK to just reprint
61721308Sache	     the characters from the current cursor position.  But we
61821308Sache	     only need to reprint it if the cursor is before the last
61921308Sache	     invisible character in the prompt string. */
62021308Sache	  nleft = visible_length + wrap_offset;
62121308Sache	  if (cursor_linenum == 0 && wrap_offset > 0 && _rl_last_c_pos > 0 &&
62221308Sache	      _rl_last_c_pos <= last_invisible && local_prompt)
62321308Sache	    {
62421308Sache	      if (term_cr)
62521308Sache		tputs (term_cr, 1, _rl_output_character_function);
62621308Sache	      _rl_output_some_chars (local_prompt, nleft);
62721308Sache	      _rl_last_c_pos = nleft;
62821308Sache	    }
62921308Sache
63021308Sache	  /* Where on that line?  And where does that line start
63121308Sache	     in the buffer? */
63221308Sache	  pos = inv_lbreaks[cursor_linenum];
63321308Sache	  /* nleft == number of characters in the line buffer between the
63421308Sache	     start of the line and the cursor position. */
63521308Sache	  nleft = c_pos - pos;
63621308Sache
63721308Sache	  /* Since _rl_backspace() doesn't know about invisible characters in the
63821308Sache	     prompt, and there's no good way to tell it, we compensate for
63921308Sache	     those characters here and call _rl_backspace() directly. */
64021308Sache	  if (wrap_offset && cursor_linenum == 0 && nleft < _rl_last_c_pos)
64121308Sache	    {
64221308Sache	      _rl_backspace (_rl_last_c_pos - nleft);
64321308Sache	      _rl_last_c_pos = nleft;
64421308Sache	    }
64521308Sache
64621308Sache	  if (nleft != _rl_last_c_pos)
64721308Sache	    _rl_move_cursor_relative (nleft, &invisible_line[pos]);
64821308Sache	}
64921308Sache    }
65021308Sache  else				/* Do horizontal scrolling. */
65121308Sache    {
65221308Sache#define M_OFFSET(margin, offset) ((margin) == 0 ? offset : 0)
65321308Sache      int lmargin, ndisp, nleft, phys_c_pos, t;
65421308Sache
65521308Sache      /* Always at top line. */
65621308Sache      _rl_last_v_pos = 0;
65721308Sache
65821308Sache      /* Compute where in the buffer the displayed line should start.  This
65921308Sache	 will be LMARGIN. */
66021308Sache
66121308Sache      /* The number of characters that will be displayed before the cursor. */
66221308Sache      ndisp = c_pos - wrap_offset;
66321308Sache      nleft  = visible_length + wrap_offset;
66421308Sache      /* Where the new cursor position will be on the screen.  This can be
66521308Sache         longer than SCREENWIDTH; if it is, lmargin will be adjusted. */
66621308Sache      phys_c_pos = c_pos - (last_lmargin ? last_lmargin : wrap_offset);
66721308Sache      t = screenwidth / 3;
66821308Sache
66921308Sache      /* If the number of characters had already exceeded the screenwidth,
67021308Sache         last_lmargin will be > 0. */
67121308Sache
67221308Sache      /* If the number of characters to be displayed is more than the screen
67321308Sache         width, compute the starting offset so that the cursor is about
67421308Sache         two-thirds of the way across the screen. */
67521308Sache      if (phys_c_pos > screenwidth - 2)
67621308Sache	{
67721308Sache	  lmargin = c_pos - (2 * t);
67821308Sache	  if (lmargin < 0)
67921308Sache	    lmargin = 0;
68021308Sache	  /* If the left margin would be in the middle of a prompt with
68121308Sache	     invisible characters, don't display the prompt at all. */
68221308Sache	  if (wrap_offset && lmargin > 0 && lmargin < nleft)
68321308Sache	    lmargin = nleft;
68421308Sache	}
68521308Sache      else if (ndisp < screenwidth - 2)		/* XXX - was -1 */
68621308Sache        lmargin = 0;
68721308Sache      else if (phys_c_pos < 1)
68821308Sache	{
68921308Sache	  /* If we are moving back towards the beginning of the line and
69021308Sache	     the last margin is no longer correct, compute a new one. */
69121308Sache	  lmargin = ((c_pos - 1) / t) * t;	/* XXX */
69221308Sache	  if (wrap_offset && lmargin > 0 && lmargin < nleft)
69321308Sache	    lmargin = nleft;
69421308Sache	}
69521308Sache      else
69621308Sache        lmargin = last_lmargin;
69721308Sache
69821308Sache      /* If the first character on the screen isn't the first character
69921308Sache	 in the display line, indicate this with a special character. */
70021308Sache      if (lmargin > 0)
70121308Sache	line[lmargin] = '<';
70221308Sache
70321308Sache      /* If SCREENWIDTH characters starting at LMARGIN do not encompass
70421308Sache         the whole line, indicate that with a special characters at the
70521308Sache         right edge of the screen.  If LMARGIN is 0, we need to take the
70621308Sache         wrap offset into account. */
70721308Sache      t = lmargin + M_OFFSET (lmargin, wrap_offset) + screenwidth;
70821308Sache      if (t < out)
70921308Sache        line[t - 1] = '>';
71021308Sache
71121308Sache      if (!rl_display_fixed || forced_display || lmargin != last_lmargin)
71221308Sache	{
71321308Sache	  forced_display = 0;
71421308Sache	  update_line (&visible_line[last_lmargin],
71521308Sache		       &invisible_line[lmargin],
71621308Sache		       0,
71721308Sache		       screenwidth + visible_wrap_offset,
71821308Sache		       screenwidth + (lmargin ? 0 : wrap_offset),
71921308Sache		       0);
72021308Sache
72121308Sache	  /* If the visible new line is shorter than the old, but the number
72221308Sache	     of invisible characters is greater, and we are at the end of
72321308Sache	     the new line, we need to clear to eol. */
72421308Sache	  t = _rl_last_c_pos - M_OFFSET (lmargin, wrap_offset);
72521308Sache	  if ((M_OFFSET (lmargin, wrap_offset) > visible_wrap_offset) &&
72621308Sache	      (_rl_last_c_pos == out) &&
72721308Sache	      t < visible_first_line_len)
72821308Sache	    {
72921308Sache	      nleft = screenwidth - t;
73026497Sache	      _rl_clear_to_eol (nleft);
73121308Sache	    }
73221308Sache	  visible_first_line_len = out - lmargin - M_OFFSET (lmargin, wrap_offset);
73321308Sache	  if (visible_first_line_len > screenwidth)
73421308Sache	    visible_first_line_len = screenwidth;
73521308Sache
73621308Sache	  _rl_move_cursor_relative (c_pos - lmargin, &invisible_line[lmargin]);
73721308Sache	  last_lmargin = lmargin;
73821308Sache	}
73921308Sache    }
74021308Sache  fflush (rl_outstream);
74121308Sache
74221308Sache  /* Swap visible and non-visible lines. */
74321308Sache  {
74421308Sache    char *temp = visible_line;
74521308Sache    int *itemp = vis_lbreaks;
74621308Sache    visible_line = invisible_line;
74721308Sache    invisible_line = temp;
74821308Sache    vis_lbreaks = inv_lbreaks;
74921308Sache    inv_lbreaks = itemp;
75021308Sache    rl_display_fixed = 0;
75121308Sache    /* If we are displaying on a single line, and last_lmargin is > 0, we
75221308Sache       are not displaying any invisible characters, so set visible_wrap_offset
75321308Sache       to 0. */
75421308Sache    if (_rl_horizontal_scroll_mode && last_lmargin)
75521308Sache      visible_wrap_offset = 0;
75621308Sache    else
75721308Sache      visible_wrap_offset = wrap_offset;
75821308Sache  }
75921308Sache}
76021308Sache
76121308Sache/* PWP: update_line() is based on finding the middle difference of each
76221308Sache   line on the screen; vis:
76321308Sache
76421308Sache			     /old first difference
76521308Sache	/beginning of line   |	      /old last same       /old EOL
76621308Sache	v		     v	      v		    v
76721308Sacheold:	eddie> Oh, my little gruntle-buggy is to me, as lurgid as
76821308Sachenew:	eddie> Oh, my little buggy says to me, as lurgid as
76921308Sache	^		     ^	^			   ^
77021308Sache	\beginning of line   |	\new last same	   \new end of line
77121308Sache			     \new first difference
77221308Sache
77321308Sache   All are character pointers for the sake of speed.  Special cases for
77421308Sache   no differences, as well as for end of line additions must be handeled.
77521308Sache
77621308Sache   Could be made even smarter, but this works well enough */
77721308Sachestatic void
77821308Sacheupdate_line (old, new, current_line, omax, nmax, inv_botlin)
77921308Sache     register char *old, *new;
78021308Sache     int current_line, omax, nmax, inv_botlin;
78121308Sache{
78221308Sache  register char *ofd, *ols, *oe, *nfd, *nls, *ne;
78321308Sache  int temp, lendiff, wsatend, od, nd;
78421308Sache  int current_invis_chars;
78521308Sache
78621308Sache  /* If we're at the right edge of a terminal that supports xn, we're
78721308Sache     ready to wrap around, so do so.  This fixes problems with knowing
78821308Sache     the exact cursor position and cut-and-paste with certain terminal
78921308Sache     emulators.  In this calculation, TEMP is the physical screen
79021308Sache     position of the cursor. */
79121308Sache  temp = _rl_last_c_pos - W_OFFSET(_rl_last_v_pos, visible_wrap_offset);
79221308Sache  if (temp == screenwidth && _rl_term_autowrap && !_rl_horizontal_scroll_mode
79321308Sache      && _rl_last_v_pos == current_line - 1)
79421308Sache    {
79521308Sache      if (new[0])
79621308Sache	putc (new[0], rl_outstream);
79721308Sache      else
79821308Sache	putc (' ', rl_outstream);
79921308Sache      _rl_last_c_pos = 1;		/* XXX */
80021308Sache      _rl_last_v_pos++;
80121308Sache      if (old[0] && new[0])
80221308Sache        old[0] = new[0];
80321308Sache    }
80421308Sache
80521308Sache  /* Find first difference. */
80621308Sache  for (ofd = old, nfd = new;
80721308Sache       (ofd - old < omax) && *ofd && (*ofd == *nfd);
80821308Sache       ofd++, nfd++)
80921308Sache    ;
81021308Sache
81121308Sache  /* Move to the end of the screen line.  ND and OD are used to keep track
81221308Sache     of the distance between ne and new and oe and old, respectively, to
81321308Sache     move a subtraction out of each loop. */
81421308Sache  for (od = ofd - old, oe = ofd; od < omax && *oe; oe++, od++);
81521308Sache  for (nd = nfd - new, ne = nfd; nd < nmax && *ne; ne++, nd++);
81621308Sache
81721308Sache  /* If no difference, continue to next line. */
81821308Sache  if (ofd == oe && nfd == ne)
81921308Sache    return;
82021308Sache
82121308Sache  wsatend = 1;			/* flag for trailing whitespace */
82221308Sache  ols = oe - 1;			/* find last same */
82321308Sache  nls = ne - 1;
82421308Sache  while ((ols > ofd) && (nls > nfd) && (*ols == *nls))
82521308Sache    {
82621308Sache      if (*ols != ' ')
82721308Sache	wsatend = 0;
82821308Sache      ols--;
82921308Sache      nls--;
83021308Sache    }
83121308Sache
83221308Sache  if (wsatend)
83321308Sache    {
83421308Sache      ols = oe;
83521308Sache      nls = ne;
83621308Sache    }
83721308Sache  else if (*ols != *nls)
83821308Sache    {
83921308Sache      if (*ols)			/* don't step past the NUL */
84021308Sache	ols++;
84121308Sache      if (*nls)
84221308Sache	nls++;
84321308Sache    }
84421308Sache
84521308Sache  /* count of invisible characters in the current invisible line. */
84621308Sache  current_invis_chars = W_OFFSET (current_line, wrap_offset);
84721308Sache  if (_rl_last_v_pos != current_line)
84821308Sache    {
84921308Sache      _rl_move_vert (current_line);
85021308Sache      if (current_line == 0 && visible_wrap_offset)
85121308Sache	_rl_last_c_pos += visible_wrap_offset;
85221308Sache    }
85321308Sache
85421308Sache  /* If this is the first line and there are invisible characters in the
85521308Sache     prompt string, and the prompt string has not changed, and the current
85621308Sache     cursor position is before the last invisible character in the prompt,
85721308Sache     and the index of the character to move to is past the end of the prompt
85821308Sache     string, then redraw the entire prompt string.  We can only do this
85921308Sache     reliably if the terminal supports a `cr' capability.
86021308Sache
86121308Sache     This is not an efficiency hack -- there is a problem with redrawing
86221308Sache     portions of the prompt string if they contain terminal escape
86321308Sache     sequences (like drawing the `unbold' sequence without a corresponding
86421308Sache     `bold') that manifests itself on certain terminals. */
86521308Sache
86621308Sache  lendiff = local_prompt ? strlen (local_prompt) : 0;
86721308Sache  od = ofd - old;	/* index of first difference in visible line */
86821308Sache  if (current_line == 0 && !_rl_horizontal_scroll_mode &&
86921308Sache      term_cr && lendiff > visible_length && _rl_last_c_pos > 0 &&
87021308Sache      od > lendiff && _rl_last_c_pos < last_invisible)
87121308Sache    {
87221308Sache      tputs (term_cr, 1, _rl_output_character_function);
87321308Sache      _rl_output_some_chars (local_prompt, lendiff);
87421308Sache      _rl_last_c_pos = lendiff;
87521308Sache    }
87621308Sache
87721308Sache  _rl_move_cursor_relative (od, old);
87821308Sache
87921308Sache  /* if (len (new) > len (old)) */
88021308Sache  lendiff = (nls - nfd) - (ols - ofd);
88121308Sache
88221308Sache  /* If we are changing the number of invisible characters in a line, and
88321308Sache     the spot of first difference is before the end of the invisible chars,
88421308Sache     lendiff needs to be adjusted. */
88521308Sache  if (current_line == 0 && !_rl_horizontal_scroll_mode &&
88621308Sache      current_invis_chars != visible_wrap_offset)
88721308Sache    {
88821308Sache      temp = visible_wrap_offset - current_invis_chars;
88921308Sache      lendiff += temp;
89021308Sache    }
89121308Sache
89221308Sache  /* Insert (diff (len (old), len (new)) ch. */
89321308Sache  temp = ne - nfd;
89421308Sache  if (lendiff > 0)
89521308Sache    {
89621308Sache      /* Non-zero if we're increasing the number of lines. */
89721308Sache      int gl = current_line >= _rl_vis_botlin && inv_botlin > _rl_vis_botlin;
89821308Sache      /* Sometimes it is cheaper to print the characters rather than
89921308Sache	 use the terminal's capabilities.  If we're growing the number
90021308Sache	 of lines, make sure we actually cause the new line to wrap
90121308Sache	 around on auto-wrapping terminals. */
90221308Sache      if (terminal_can_insert && ((2 * temp) >= lendiff || term_IC) && (!_rl_term_autowrap || !gl))
90321308Sache	{
90421308Sache	  /* If lendiff > visible_length and _rl_last_c_pos == 0 and
90521308Sache	     _rl_horizontal_scroll_mode == 1, inserting the characters with
90621308Sache	     term_IC or term_ic will screw up the screen because of the
90721308Sache	     invisible characters.  We need to just draw them. */
90821308Sache	  if (*ols && (!_rl_horizontal_scroll_mode || _rl_last_c_pos > 0 ||
90921308Sache			lendiff <= visible_length || !current_invis_chars))
91021308Sache	    {
91121308Sache	      insert_some_chars (nfd, lendiff);
91221308Sache	      _rl_last_c_pos += lendiff;
91321308Sache	    }
91421308Sache	  else if (*ols == 0)
91521308Sache	    {
91621308Sache	      /* At the end of a line the characters do not have to
91721308Sache		 be "inserted".  They can just be placed on the screen. */
91821308Sache	      /* However, this screws up the rest of this block, which
91921308Sache	         assumes you've done the insert because you can. */
92021308Sache	      _rl_output_some_chars (nfd, lendiff);
92121308Sache	      _rl_last_c_pos += lendiff;
92221308Sache	    }
92321308Sache	  else
92421308Sache	    {
92521308Sache	      /* We have horizontal scrolling and we are not inserting at
92621308Sache		 the end.  We have invisible characters in this line.  This
92721308Sache		 is a dumb update. */
92821308Sache	      _rl_output_some_chars (nfd, temp);
92921308Sache	      _rl_last_c_pos += temp;
93021308Sache	      return;
93121308Sache	    }
93221308Sache	  /* Copy (new) chars to screen from first diff to last match. */
93321308Sache	  temp = nls - nfd;
93421308Sache	  if ((temp - lendiff) > 0)
93521308Sache	    {
93621308Sache	      _rl_output_some_chars (nfd + lendiff, temp - lendiff);
93721308Sache	      _rl_last_c_pos += temp - lendiff;
93821308Sache	    }
93921308Sache	}
94021308Sache      else
94121308Sache	{
94221308Sache	  /* cannot insert chars, write to EOL */
94321308Sache	  _rl_output_some_chars (nfd, temp);
94421308Sache	  _rl_last_c_pos += temp;
94521308Sache	}
94621308Sache    }
94721308Sache  else				/* Delete characters from line. */
94821308Sache    {
94921308Sache      /* If possible and inexpensive to use terminal deletion, then do so. */
95021308Sache      if (term_dc && (2 * temp) >= -lendiff)
95121308Sache	{
95221308Sache	  /* If all we're doing is erasing the invisible characters in the
95321308Sache	     prompt string, don't bother.  It screws up the assumptions
95421308Sache	     about what's on the screen. */
95521308Sache	  if (_rl_horizontal_scroll_mode && _rl_last_c_pos == 0 &&
95621308Sache	      -lendiff == visible_wrap_offset)
95721308Sache	    lendiff = 0;
95821308Sache
95921308Sache	  if (lendiff)
96021308Sache	    delete_chars (-lendiff); /* delete (diff) characters */
96121308Sache
96221308Sache	  /* Copy (new) chars to screen from first diff to last match */
96321308Sache	  temp = nls - nfd;
96421308Sache	  if (temp > 0)
96521308Sache	    {
96621308Sache	      _rl_output_some_chars (nfd, temp);
96721308Sache	      _rl_last_c_pos += temp;
96821308Sache	    }
96921308Sache	}
97021308Sache      /* Otherwise, print over the existing material. */
97121308Sache      else
97221308Sache	{
97321308Sache	  if (temp > 0)
97421308Sache	    {
97521308Sache	      _rl_output_some_chars (nfd, temp);
97621308Sache	      _rl_last_c_pos += temp;
97721308Sache	    }
97821308Sache	  lendiff = (oe - old) - (ne - new);
97921308Sache	  if (_rl_term_autowrap && current_line < inv_botlin)
98021308Sache	    space_to_eol (lendiff);
98121308Sache	  else
98226497Sache	    _rl_clear_to_eol (lendiff);
98321308Sache	}
98421308Sache    }
98521308Sache}
98621308Sache
98721308Sache/* Tell the update routines that we have moved onto a new (empty) line. */
98821308Sacheint
98921308Sacherl_on_new_line ()
99021308Sache{
99121308Sache  if (visible_line)
99221308Sache    visible_line[0] = '\0';
99321308Sache
99421308Sache  _rl_last_c_pos = _rl_last_v_pos = 0;
99521308Sache  _rl_vis_botlin = last_lmargin = 0;
99621308Sache  if (vis_lbreaks)
99721308Sache    vis_lbreaks[0] = vis_lbreaks[1] = 0;
99821308Sache  visible_wrap_offset = 0;
99921308Sache  return 0;
100021308Sache}
100121308Sache
100221308Sache/* Actually update the display, period. */
100321308Sacheint
100421308Sacherl_forced_update_display ()
100521308Sache{
100621308Sache  if (visible_line)
100721308Sache    {
100821308Sache      register char *temp = visible_line;
100921308Sache
101021308Sache      while (*temp)
101121308Sache        *temp++ = '\0';
101221308Sache    }
101321308Sache  rl_on_new_line ();
101421308Sache  forced_display++;
101521308Sache  (*rl_redisplay_function) ();
101621308Sache  return 0;
101721308Sache}
101821308Sache
101921308Sache/* Move the cursor from _rl_last_c_pos to NEW, which are buffer indices.
102021308Sache   DATA is the contents of the screen line of interest; i.e., where
102121308Sache   the movement is being done. */
102221308Sachevoid
102321308Sache_rl_move_cursor_relative (new, data)
102421308Sache     int new;
102521308Sache     char *data;
102621308Sache{
102721308Sache  register int i;
102821308Sache
102921308Sache  /* If we don't have to do anything, then return. */
103021308Sache  if (_rl_last_c_pos == new) return;
103121308Sache
103221308Sache  /* It may be faster to output a CR, and then move forwards instead
103321308Sache     of moving backwards. */
103421308Sache  /* i == current physical cursor position. */
103521308Sache  i = _rl_last_c_pos - W_OFFSET(_rl_last_v_pos, visible_wrap_offset);
103621308Sache  if (new == 0 || CR_FASTER (new, _rl_last_c_pos) ||
103721308Sache      (_rl_term_autowrap && i == screenwidth))
103821308Sache    {
103921308Sache#if defined (__MSDOS__)
104021308Sache      putc ('\r', rl_outstream);
104121308Sache#else
104221308Sache      tputs (term_cr, 1, _rl_output_character_function);
104321308Sache#endif /* !__MSDOS__ */
104421308Sache      _rl_last_c_pos = 0;
104521308Sache    }
104621308Sache
104721308Sache  if (_rl_last_c_pos < new)
104821308Sache    {
104921308Sache      /* Move the cursor forward.  We do it by printing the command
105021308Sache	 to move the cursor forward if there is one, else print that
105121308Sache	 portion of the output buffer again.  Which is cheaper? */
105221308Sache
105321308Sache      /* The above comment is left here for posterity.  It is faster
105421308Sache	 to print one character (non-control) than to print a control
105521308Sache	 sequence telling the terminal to move forward one character.
105621308Sache	 That kind of control is for people who don't know what the
105721308Sache	 data is underneath the cursor. */
105821308Sache#if defined (HACK_TERMCAP_MOTION)
105921308Sache      extern char *term_forward_char;
106021308Sache
106121308Sache      if (term_forward_char)
106221308Sache	for (i = _rl_last_c_pos; i < new; i++)
106321308Sache	  tputs (term_forward_char, 1, _rl_output_character_function);
106421308Sache      else
106521308Sache	for (i = _rl_last_c_pos; i < new; i++)
106621308Sache	  putc (data[i], rl_outstream);
106721308Sache#else
106821308Sache      for (i = _rl_last_c_pos; i < new; i++)
106921308Sache	putc (data[i], rl_outstream);
107021308Sache#endif /* HACK_TERMCAP_MOTION */
107121308Sache    }
107221308Sache  else if (_rl_last_c_pos != new)
107321308Sache    _rl_backspace (_rl_last_c_pos - new);
107421308Sache  _rl_last_c_pos = new;
107521308Sache}
107621308Sache
107721308Sache/* PWP: move the cursor up or down. */
107821308Sachevoid
107921308Sache_rl_move_vert (to)
108021308Sache     int to;
108121308Sache{
108221308Sache  register int delta, i;
108321308Sache
108421308Sache  if (_rl_last_v_pos == to || to > screenheight)
108521308Sache    return;
108621308Sache
108721308Sache#if defined (__GO32__)
108821308Sache  {
108921308Sache    int row, col;
109021308Sache
109121308Sache    ScreenGetCursor (&row, &col);
109221308Sache    ScreenSetCursor ((row + to - _rl_last_v_pos), col);
109321308Sache  }
109421308Sache#else /* !__GO32__ */
109521308Sache
109621308Sache  if ((delta = to - _rl_last_v_pos) > 0)
109721308Sache    {
109821308Sache      for (i = 0; i < delta; i++)
109921308Sache	putc ('\n', rl_outstream);
110021308Sache      tputs (term_cr, 1, _rl_output_character_function);
110121308Sache      _rl_last_c_pos = 0;
110221308Sache    }
110321308Sache  else
110421308Sache    {			/* delta < 0 */
110521308Sache      if (term_up && *term_up)
110621308Sache	for (i = 0; i < -delta; i++)
110721308Sache	  tputs (term_up, 1, _rl_output_character_function);
110821308Sache    }
110921308Sache#endif /* !__GO32__ */
111021308Sache  _rl_last_v_pos = to;		/* Now TO is here */
111121308Sache}
111221308Sache
111321308Sache/* Physically print C on rl_outstream.  This is for functions which know
111421308Sache   how to optimize the display.  Return the number of characters output. */
111521308Sacheint
111621308Sacherl_show_char (c)
111721308Sache     int c;
111821308Sache{
111921308Sache  int n = 1;
112021308Sache  if (META_CHAR (c) && (_rl_output_meta_chars == 0))
112121308Sache    {
112221308Sache      fprintf (rl_outstream, "M-");
112321308Sache      n += 2;
112421308Sache      c = UNMETA (c);
112521308Sache    }
112621308Sache
112721308Sache#if defined (DISPLAY_TABS)
112821308Sache  if ((CTRL_CHAR (c) && c != '\t') || c == RUBOUT)
112921308Sache#else
113021308Sache  if (CTRL_CHAR (c) || c == RUBOUT)
113121308Sache#endif /* !DISPLAY_TABS */
113221308Sache    {
113321308Sache      fprintf (rl_outstream, "C-");
113421308Sache      n += 2;
113521308Sache      c = CTRL_CHAR (c) ? UNCTRL (c) : '?';
113621308Sache    }
113721308Sache
113821308Sache  putc (c, rl_outstream);
113921308Sache  fflush (rl_outstream);
114021308Sache  return n;
114121308Sache}
114221308Sache
114321308Sacheint
114421308Sacherl_character_len (c, pos)
114521308Sache     register int c, pos;
114621308Sache{
114721308Sache  unsigned char uc;
114821308Sache
114921308Sache  uc = (unsigned char)c;
115021308Sache
115121308Sache  if (META_CHAR (uc))
115221308Sache    return ((_rl_output_meta_chars == 0) ? 4 : 1);
115321308Sache
115421308Sache  if (uc == '\t')
115521308Sache    {
115621308Sache#if defined (DISPLAY_TABS)
115721308Sache      return (((pos | 7) + 1) - pos);
115821308Sache#else
115921308Sache      return (2);
116021308Sache#endif /* !DISPLAY_TABS */
116121308Sache    }
116221308Sache
116321308Sache  if (CTRL_CHAR (c) || c == RUBOUT)
116421308Sache    return (2);
116521308Sache
116621308Sache  return ((isprint (uc)) ? 1 : 2);
116721308Sache}
116821308Sache
116921308Sache/* How to print things in the "echo-area".  The prompt is treated as a
117021308Sache   mini-modeline. */
117121308Sache
117221308Sache#if defined (USE_VARARGS)
117321308Sacheint
117421308Sache#if defined (PREFER_STDARG)
117521308Sacherl_message (const char *format, ...)
117621308Sache#else
117721308Sacherl_message (va_alist)
117821308Sache     va_dcl
117921308Sache#endif
118021308Sache{
118121308Sache  va_list args;
118221308Sache#if defined (PREFER_VARARGS)
118321308Sache  char *format;
118421308Sache#endif
118521308Sache
118621308Sache#if defined (PREFER_STDARG)
118721308Sache  va_start (args, format);
118821308Sache#else
118921308Sache  va_start (args);
119021308Sache  format = va_arg (args, char *);
119121308Sache#endif
119221308Sache
119321308Sache  vsprintf (msg_buf, format, args);
119421308Sache  va_end (args);
119521308Sache
119621308Sache  rl_display_prompt = msg_buf;
119721308Sache  (*rl_redisplay_function) ();
119821308Sache  return 0;
119921308Sache}
120021308Sache#else /* !USE_VARARGS */
120121308Sacheint
120221308Sacherl_message (format, arg1, arg2)
120321308Sache     char *format;
120421308Sache{
120521308Sache  sprintf (msg_buf, format, arg1, arg2);
120621308Sache  rl_display_prompt = msg_buf;
120721308Sache  (*rl_redisplay_function) ();
120821308Sache  return 0;
120921308Sache}
121021308Sache#endif /* !USE_VARARGS */
121121308Sache
121221308Sache/* How to clear things from the "echo-area". */
121321308Sacheint
121421308Sacherl_clear_message ()
121521308Sache{
121621308Sache  rl_display_prompt = rl_prompt;
121721308Sache  (*rl_redisplay_function) ();
121821308Sache  return 0;
121921308Sache}
122021308Sache
122121308Sacheint
122221308Sacherl_reset_line_state ()
122321308Sache{
122421308Sache  rl_on_new_line ();
122521308Sache
122621308Sache  rl_display_prompt = rl_prompt ? rl_prompt : "";
122721308Sache  forced_display = 1;
122821308Sache  return 0;
122921308Sache}
123021308Sache
123121308Sachestatic char *saved_local_prompt;
123221308Sachestatic char *saved_local_prefix;
123321308Sachestatic int saved_last_invisible;
123421308Sachestatic int saved_visible_length;
123521308Sache
123621308Sachevoid
123721308Sache_rl_save_prompt ()
123821308Sache{
123921308Sache  saved_local_prompt = local_prompt;
124021308Sache  saved_local_prefix = local_prompt_prefix;
124121308Sache  saved_last_invisible = last_invisible;
124221308Sache  saved_visible_length = visible_length;
124321308Sache
124421308Sache  local_prompt = local_prompt_prefix = (char *)0;
124521308Sache  last_invisible = visible_length = 0;
124621308Sache}
124721308Sache
124821308Sachevoid
124921308Sache_rl_restore_prompt ()
125021308Sache{
125121308Sache  if (local_prompt)
125221308Sache    free (local_prompt);
125321308Sache  if (local_prompt_prefix)
125421308Sache    free (local_prompt_prefix);
125521308Sache
125621308Sache  local_prompt = saved_local_prompt;
125721308Sache  local_prompt_prefix = saved_local_prefix;
125821308Sache  last_invisible = saved_last_invisible;
125921308Sache  visible_length = saved_visible_length;
126021308Sache}
126121308Sache
126221308Sachechar *
126321308Sache_rl_make_prompt_for_search (pchar)
126421308Sache     int pchar;
126521308Sache{
126621308Sache  int len;
126721308Sache  char *pmt;
126821308Sache
126921308Sache  _rl_save_prompt ();
127021308Sache
127121308Sache  if (saved_local_prompt == 0)
127221308Sache    {
127321308Sache      len = (rl_prompt && *rl_prompt) ? strlen (rl_prompt) : 0;
127421308Sache      pmt = xmalloc (len + 2);
127521308Sache      if (len)
127621308Sache        strcpy (pmt, rl_prompt);
127721308Sache      pmt[len] = pchar;
127821308Sache      pmt[len+1] = '\0';
127921308Sache    }
128021308Sache  else
128121308Sache    {
128221308Sache      len = *saved_local_prompt ? strlen (saved_local_prompt) : 0;
128321308Sache      pmt = xmalloc (len + 2);
128421308Sache      if (len)
128521308Sache        strcpy (pmt, saved_local_prompt);
128621308Sache      pmt[len] = pchar;
128721308Sache      pmt[len+1] = '\0';
128821308Sache      local_prompt = savestring (pmt);
128921308Sache      last_invisible = saved_last_invisible;
129021308Sache      visible_length = saved_visible_length + 1;
129121308Sache    }
129221308Sache  return pmt;
129321308Sache}
129421308Sache
129521308Sache/* Quick redisplay hack when erasing characters at the end of the line. */
129621308Sachevoid
129721308Sache_rl_erase_at_end_of_line (l)
129821308Sache     int l;
129921308Sache{
130021308Sache  register int i;
130121308Sache
130221308Sache  _rl_backspace (l);
130321308Sache  for (i = 0; i < l; i++)
130421308Sache    putc (' ', rl_outstream);
130521308Sache  _rl_backspace (l);
130621308Sache  for (i = 0; i < l; i++)
130721308Sache    visible_line[--_rl_last_c_pos] = '\0';
130821308Sache  rl_display_fixed++;
130921308Sache}
131021308Sache
131121308Sache/* Clear to the end of the line.  COUNT is the minimum
131221308Sache   number of character spaces to clear, */
131326497Sachevoid
131426497Sache_rl_clear_to_eol (count)
131521308Sache     int count;
131621308Sache{
131721308Sache#if !defined (__GO32__)
131821308Sache  if (term_clreol)
131926497Sache    tputs (term_clreol, 1, _rl_output_character_function);
132026497Sache  else if (count)
132121308Sache#endif /* !__GO32__ */
132221308Sache    space_to_eol (count);
132321308Sache}
132421308Sache
132521308Sache/* Clear to the end of the line using spaces.  COUNT is the minimum
132621308Sache   number of character spaces to clear, */
132721308Sachestatic void
132821308Sachespace_to_eol (count)
132921308Sache     int count;
133021308Sache{
133121308Sache  register int i;
133221308Sache
133321308Sache  for (i = 0; i < count; i++)
133421308Sache   putc (' ', rl_outstream);
133521308Sache
133621308Sache  _rl_last_c_pos += count;
133721308Sache}
133821308Sache
133926497Sachevoid
134026497Sache_rl_clear_screen ()
134126497Sache{
134226497Sache#if !defined (__GO32__)
134326497Sache  if (term_clrpag)
134426497Sache    tputs (term_clrpag, 1, _rl_output_character_function);
134526497Sache  else
134626497Sache#endif /* !__GO32__ */
134726497Sache    crlf ();
134826497Sache}
134926497Sache
135021308Sache/* Insert COUNT characters from STRING to the output stream. */
135121308Sachestatic void
135221308Sacheinsert_some_chars (string, count)
135321308Sache     char *string;
135421308Sache     int count;
135521308Sache{
135621308Sache#if defined (__GO32__)
135721308Sache  int row, col, width;
135821308Sache  char *row_start;
135921308Sache
136021308Sache  ScreenGetCursor (&row, &col);
136121308Sache  width = ScreenCols ();
136221308Sache  row_start = ScreenPrimary + (row * width);
136321308Sache
136421308Sache  memcpy (row_start + col + count, row_start + col, width - col - count);
136521308Sache
136621308Sache  /* Place the text on the screen. */
136721308Sache  _rl_output_some_chars (string, count);
136821308Sache#else /* !_GO32 */
136921308Sache
137021308Sache  /* If IC is defined, then we do not have to "enter" insert mode. */
137121308Sache  if (term_IC)
137221308Sache    {
137321308Sache      char *buffer;
137421308Sache      buffer = tgoto (term_IC, 0, count);
137521308Sache      tputs (buffer, 1, _rl_output_character_function);
137621308Sache      _rl_output_some_chars (string, count);
137721308Sache    }
137821308Sache  else
137921308Sache    {
138021308Sache      register int i;
138121308Sache
138221308Sache      /* If we have to turn on insert-mode, then do so. */
138321308Sache      if (term_im && *term_im)
138421308Sache	tputs (term_im, 1, _rl_output_character_function);
138521308Sache
138621308Sache      /* If there is a special command for inserting characters, then
138721308Sache	 use that first to open up the space. */
138821308Sache      if (term_ic && *term_ic)
138921308Sache	{
139021308Sache	  for (i = count; i--; )
139121308Sache	    tputs (term_ic, 1, _rl_output_character_function);
139221308Sache	}
139321308Sache
139421308Sache      /* Print the text. */
139521308Sache      _rl_output_some_chars (string, count);
139621308Sache
139721308Sache      /* If there is a string to turn off insert mode, we had best use
139821308Sache	 it now. */
139921308Sache      if (term_ei && *term_ei)
140021308Sache	tputs (term_ei, 1, _rl_output_character_function);
140121308Sache    }
140221308Sache#endif /* !__GO32__ */
140321308Sache}
140421308Sache
140521308Sache/* Delete COUNT characters from the display line. */
140621308Sachestatic void
140721308Sachedelete_chars (count)
140821308Sache     int count;
140921308Sache{
141021308Sache#if defined (__GO32__)
141121308Sache  int row, col, width;
141221308Sache  char *row_start;
141321308Sache
141421308Sache  ScreenGetCursor (&row, &col);
141521308Sache  width = ScreenCols ();
141621308Sache  row_start = ScreenPrimary + (row * width);
141721308Sache
141821308Sache  memcpy (row_start + col, row_start + col + count, width - col - count);
141921308Sache  memset (row_start + width - count, 0, count * 2);
142021308Sache#else /* !_GO32 */
142121308Sache
142221308Sache  if (count > screenwidth)	/* XXX */
142321308Sache    return;
142421308Sache
142521308Sache  if (term_DC && *term_DC)
142621308Sache    {
142721308Sache      char *buffer;
142821308Sache      buffer = tgoto (term_DC, count, count);
142921308Sache      tputs (buffer, count, _rl_output_character_function);
143021308Sache    }
143121308Sache  else
143221308Sache    {
143321308Sache      if (term_dc && *term_dc)
143421308Sache	while (count--)
143521308Sache	  tputs (term_dc, 1, _rl_output_character_function);
143621308Sache    }
143721308Sache#endif /* !__GO32__ */
143821308Sache}
143921308Sache
144021308Sachevoid
144121308Sache_rl_update_final ()
144221308Sache{
144321308Sache  int full_lines;
144421308Sache
144521308Sache  full_lines = 0;
144621308Sache  /* If the cursor is the only thing on an otherwise-blank last line,
144721308Sache     compensate so we don't print an extra CRLF. */
144821308Sache  if (_rl_vis_botlin && _rl_last_c_pos == 0 &&
144926497Sache	visible_line[vis_lbreaks[_rl_vis_botlin]] == 0)
145021308Sache    {
145121308Sache      _rl_vis_botlin--;
145221308Sache      full_lines = 1;
145321308Sache    }
145421308Sache  _rl_move_vert (_rl_vis_botlin);
145521308Sache  /* If we've wrapped lines, remove the final xterm line-wrap flag. */
145621308Sache  if (full_lines && _rl_term_autowrap && (VIS_LLEN(_rl_vis_botlin) == screenwidth))
145721308Sache    {
145821308Sache      char *last_line;
145921308Sache      last_line = &visible_line[inv_lbreaks[_rl_vis_botlin]];
146021308Sache      _rl_move_cursor_relative (screenwidth - 1, last_line);
146126497Sache      _rl_clear_to_eol (0);
146221308Sache      putc (last_line[screenwidth - 1], rl_outstream);
146321308Sache    }
146421308Sache  _rl_vis_botlin = 0;
146521308Sache  crlf ();
146621308Sache  fflush (rl_outstream);
146721308Sache  rl_display_fixed++;
146821308Sache}
146921308Sache
147021308Sache/* Move to the start of the current line. */
147121308Sachestatic void
147221308Sachecr ()
147321308Sache{
147421308Sache  if (term_cr)
147521308Sache    {
147621308Sache      tputs (term_cr, 1, _rl_output_character_function);
147721308Sache      _rl_last_c_pos = 0;
147821308Sache    }
147921308Sache}
148021308Sache
148121308Sache/* Redisplay the current line after a SIGWINCH is received. */
148221308Sachevoid
148321308Sache_rl_redisplay_after_sigwinch ()
148421308Sache{
148521308Sache  char *t, *oldp;
148621308Sache
148721308Sache  /* Clear the current line and put the cursor at column 0.  Make sure
148821308Sache     the right thing happens if we have wrapped to a new screen line. */
148921308Sache  if (term_cr)
149021308Sache    {
149121308Sache      tputs (term_cr, 1, _rl_output_character_function);
149221308Sache      _rl_last_c_pos = 0;
149321308Sache      if (term_clreol)
149421308Sache	tputs (term_clreol, 1, _rl_output_character_function);
149521308Sache      else
149621308Sache	{
149721308Sache	  space_to_eol (screenwidth);
149821308Sache	  tputs (term_cr, 1, _rl_output_character_function);
149921308Sache	}
150021308Sache      if (_rl_last_v_pos > 0)
150121308Sache	_rl_move_vert (0);
150221308Sache    }
150321308Sache  else
150421308Sache    crlf ();
150521308Sache
150621308Sache  /* Redraw only the last line of a multi-line prompt. */
150721308Sache  t = strrchr (rl_display_prompt, '\n');
150821308Sache  if (t)
150921308Sache    {
151021308Sache      oldp = rl_display_prompt;
151121308Sache      rl_display_prompt = ++t;
151221308Sache      rl_forced_update_display ();
151321308Sache      rl_display_prompt = oldp;
151421308Sache    }
151521308Sache  else
151621308Sache    rl_forced_update_display ();
151721308Sache}
151821308Sache
151921308Sachevoid
152021308Sache_rl_clean_up_for_exit ()
152121308Sache{
152221308Sache  if (readline_echoing_p)
152321308Sache    {
152421308Sache      _rl_move_vert (_rl_vis_botlin);
152521308Sache      _rl_vis_botlin = 0;
152621308Sache      fflush (rl_outstream);
152721308Sache      rl_restart_output ();
152821308Sache    }
152921308Sache}
1530