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