1715 lines
		
	
	
		
			51 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			1715 lines
		
	
	
		
			51 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
/* ELLE - Copyright 1982, 1987 by Ken Harrenstien, SRI International
 | 
						||
 *	This software is quasi-public; it may be used freely with
 | 
						||
 *	like software, but may NOT be sold or made part of licensed
 | 
						||
 *	products without permission of the author.
 | 
						||
 */
 | 
						||
/* EEDISP	Redisplay and screen image routines
 | 
						||
 */
 | 
						||
 | 
						||
#if 0
 | 
						||
 | 
						||
Note that there are several different types of "efficiency" criteria
 | 
						||
involved with respect to display updating:
 | 
						||
	(1) Terminal speed: minimize # characters output.
 | 
						||
	(2) Program speed: minimize CPU time used.
 | 
						||
	(3) Program size: minimize code and memory usage.
 | 
						||
	(4) Program modularity: minimize "hooks" between edit/display rtns.
 | 
						||
The current algorithms necessarily represent a compromise among all of
 | 
						||
these objectives.
 | 
						||
 | 
						||
	The cursor is always located at CUR_DOT in the buffer CUR_BUF
 | 
						||
of the current window CUR_WIN.  This may not be true during function
 | 
						||
execution, but is always true at the top-level loop of command
 | 
						||
execution and redisplay.  In order to minimize update overhead, there
 | 
						||
are various flags or variables that the edit functions can use to
 | 
						||
communicate with "redisplay" and tell it how extensive the updates
 | 
						||
really need to be.
 | 
						||
 | 
						||
	The entire known screen is always represented by a linked list
 | 
						||
of "windows"; updating the entire screen consists of separately
 | 
						||
updating every window on the list.  Windows can only be defined
 | 
						||
horizontally (as a range of lines), and must not overlap.  Each window
 | 
						||
has a buffer associated with it; the redisplay routines are responsible
 | 
						||
for displaying the contents of this buffer.
 | 
						||
 | 
						||
	The lowest level data structure for the screen consists of an
 | 
						||
array of SCR_LINE structures, one for each possible physical screen
 | 
						||
line.  Each line structure has some flags, and pointers to three different
 | 
						||
representations of what should be on the line:
 | 
						||
	(1) SL_BOFF, SL_LEN - Defines the range of the buffer data which
 | 
						||
		this screen line should represent.
 | 
						||
		If the flag SL_EOL is set, this range ends with (and includes)
 | 
						||
		an EOL character.
 | 
						||
	(2) SL_LINE, SL_COL - Always keeps a copy of the current physical
 | 
						||
		screen line image.  Each byte is a character which occupies
 | 
						||
		only one column position on the screen.
 | 
						||
		If the flag SL_CSO is set, the line is in standout mode.
 | 
						||
	(3) SL_NLIN, SL_NCOL - The desired "new" screen line image.
 | 
						||
		This is only valid if the SL_MOD flag is set for the line,
 | 
						||
		indicating that these variables are set and point to the
 | 
						||
		new image of what the screen line should be.
 | 
						||
		If the flag SL_NSO is set, the new line should be in standout
 | 
						||
		mode.
 | 
						||
 | 
						||
	Lastly there is a variable SL_CONT, which is needed for
 | 
						||
continuation of too-long logical lines over several physical lines.  If
 | 
						||
SL_CONT is:
 | 
						||
	0 = logical line fits entirely on the screen.
 | 
						||
		Either SL_EOL is set, or this line is ended by EOF
 | 
						||
		(end of the buffer).
 | 
						||
	1 = logical line is too long, but the last buffer char fits
 | 
						||
		entirely on this physical line.  SL_EOL is never set.
 | 
						||
	>1 = logical line is too long, and the last buffer char
 | 
						||
		"overruns" the end of the physical image; that is, part of
 | 
						||
		its representation is at the end of this line, but the
 | 
						||
		rest of it is at the start of the next line.  This can
 | 
						||
		only happen with "big" characters like TAB, ^A, ~^A, etc.
 | 
						||
		that need more than one column of representation.
 | 
						||
		There are SL_CONT-1 chars of overrun stored at the
 | 
						||
		end of SL_LINE (SL_NLIN if SL_MOD is set).
 | 
						||
		SL_EOL is never set.
 | 
						||
 | 
						||
Note that if a line contains any overrun, and the next line is also
 | 
						||
part of the same window, the next line''s screen image will start with
 | 
						||
the SL_CONT-1 chars of overrun, rather than with the representation of
 | 
						||
that line''s first buffer char.
 | 
						||
 | 
						||
	The "EOL" character on Unix systems is normally the new-line
 | 
						||
character '\n' (ASCII LF).  However, on other systems EOL may be
 | 
						||
indicated by a two-character CR-LF sequence, with either CR or LF alone
 | 
						||
considered to be "stray".  For this reason, the buffer flag B_EOLCRLF
 | 
						||
exists to control handling and display of EOLs.  If the flag is off,
 | 
						||
the EOL mode is LF, and there are no problems of splitting up characters.
 | 
						||
If the flag is on, however, the EOL mode is CRLF and the following rules
 | 
						||
hold:
 | 
						||
	EOL is the sequence CR-LF only.
 | 
						||
	LF without preceding CR is a "stray" LF, displayed as ^J.
 | 
						||
	CR without following LF is a "stray" CR, displayed as ^M.
 | 
						||
	Stray LFs and CRs do not terminate a logical line.
 | 
						||
	"End of Line" as a position is the dot just before the CR of a CR-LF.
 | 
						||
	"Beg of Line" as a position is the dot just after the LF of a CR-LF.
 | 
						||
	If the current dot is between a CR and LF, it is positioned at
 | 
						||
		the beginning of the physical screen line.
 | 
						||
 | 
						||
 | 
						||
SL_LINE and SL_COL are always accurate at every stage of processing.
 | 
						||
The other variables are accurate only after fix_wind has been called
 | 
						||
to "fix up" the line structures within a window.  If either
 | 
						||
RD_WINRES or RD_TMOD is set, none of these "other variables" should
 | 
						||
be depended on.  Any functions which are screen-relative (d_ type)
 | 
						||
must be sure that fix_wind is called if necessary, and must give
 | 
						||
preference to the "new" representation in SL_NLINE and SL_NCOL if
 | 
						||
SL_MOD is set.
 | 
						||
 | 
						||
The flag RD_UPDWIN will be set by fix_wind if any lines have been
 | 
						||
modified.  Because fix_wind does not perform any actual display update,
 | 
						||
it is possible for functions to continue operating on the buffer and
 | 
						||
screen image without requiring that changes be displayed until there is
 | 
						||
nothing else left to do.  The routine upd_wind performs the actual
 | 
						||
terminal I/O necessary to update all the screen lines which have SL_MOD
 | 
						||
set.  Although the process of updating each line is currently
 | 
						||
non-interruptible, it is possible for upd_wind to interrupt itself
 | 
						||
between line updates if it detects that user input has happened, and it will
 | 
						||
return with the window only partially updated.  The screen image state
 | 
						||
will be completely consistent, however, and the RD_UPDWIN flag will
 | 
						||
remain set.
 | 
						||
 | 
						||
Communication between the editing functions and the redisplay routines
 | 
						||
is limited as much as possible to the flags in the global RD_TYPE.
 | 
						||
Each window has its own copy of these flags in W_REDP, so that if
 | 
						||
windows are changed, the update hints for that window will be
 | 
						||
preserved.  The flags that can be set are listed below.  Those marked
 | 
						||
with "*" are global in nature; all others apply only within a single
 | 
						||
window (normally the current window).
 | 
						||
 | 
						||
* RD_SCREEN - Total refresh.  Clears entire screen and redisplays all
 | 
						||
	windows.
 | 
						||
* RD_MODE - Mode line has changed, update it.
 | 
						||
* RD_CHKALL - Check ALL windows for any redisplay flags, and perform
 | 
						||
	any updates necessary.  Otherwise only the current (or specified)
 | 
						||
	window flags are checked.
 | 
						||
* RD_WINDS - Updates all windows.  Like RD_WINRES applied to all windows.
 | 
						||
  RD_WINRES - Update window (assume completely changed).
 | 
						||
  RD_TMOD - Text changed in this window.  The range of changes is
 | 
						||
	specified by W_BMOD and W_EMOD in combination with W_OLDZ.
 | 
						||
	Redisplay checking will limit itself to this range.
 | 
						||
	These vars are set by buf_tmod in the main command loop, and
 | 
						||
	reset by fix_wind when the window is fixed up.
 | 
						||
  RD_MOVE - Cursor has moved within current window; may have moved outside
 | 
						||
	the window.  W_DOT or CUR_DOT specifies where it should be.
 | 
						||
  RD_ILIN - Hint: Line insert done.  Currently no function sets this.
 | 
						||
  RD_DLIN - Hint: Line delete done.  Currently no function sets this.
 | 
						||
 | 
						||
Internal flags:
 | 
						||
  RD_UPDWIN - Window needs updating. Used by fix_wind and upd_wind only.
 | 
						||
	Set when window has been "fixed up" and at least one screen
 | 
						||
	line was modified.
 | 
						||
  RD_FIXWIN - Supposed to mean window needs fixing (via call to fix_wind).
 | 
						||
	Not really used.
 | 
						||
 | 
						||
Not implemented, may never be, but comments retained:
 | 
						||
  RD_WINCLR - Clear window (not entire screen)
 | 
						||
  RD_NEWWIN - Window has moved.  (not needed? Random stuff here)
 | 
						||
	a. to follow cursor; redisplay selects a new TOPLDOT.
 | 
						||
	b. randomly; new TOPLDOT furnished, use unless cursor out (then a).
 | 
						||
	c. find new TOPLDOT as directed (move up/down N screen lines)
 | 
						||
	For now, assume that (c) doesn''t apply (ie C-V uses (b) and sets
 | 
						||
	TOPLDOT itself).  So fix_wind selects new one only if cursor
 | 
						||
	won''t fit.  topldot takes precedence over sl_boff.
 | 
						||
 | 
						||
#endif /*COMMENT*/
 | 
						||
 | 
						||
/* Declarations and stuff */
 | 
						||
 | 
						||
#include "elle.h"
 | 
						||
 | 
						||
static int sctr();
 | 
						||
 | 
						||
int trm_mode;	/* 0 = TTY in normal, non-edit mode.
 | 
						||
		 * 1 = TTY in edit mode.
 | 
						||
		 * -1 = TTY detached (hung up).
 | 
						||
		 * This flag is only used by the 3 routines below,
 | 
						||
		 * plus hup_exit.
 | 
						||
		 */
 | 
						||
 | 
						||
/* REDP_INIT() - Called once-only at startup to initialize redisplay
 | 
						||
 *	and terminal
 | 
						||
 */
 | 
						||
redp_init ()
 | 
						||
{
 | 
						||
	trm_mode = 0;		/* Ensure flag says not in edit mode */
 | 
						||
	ts_init();		/* Get sys term info, set up stuff */
 | 
						||
	if (trm_ospeed == 0)	/* Default speed to 9600 if unknown */
 | 
						||
		trm_ospeed = 13;
 | 
						||
	t_init();		/* Identify term type, set term-dep stuff */
 | 
						||
	set_scr();		/* Set up software screen image */
 | 
						||
	set_tty();		/* Enter editing mode! */
 | 
						||
	redp(RD_SCREEN|RD_MODE); /* Force full re-display, new mode line */
 | 
						||
}
 | 
						||
 | 
						||
/* SET_TTY() - Set up terminal modes for editing */
 | 
						||
 | 
						||
set_tty()
 | 
						||
{	if(trm_mode) return;	/* Ignore if detached or in edit mode */
 | 
						||
	trm_mode++;
 | 
						||
	ts_enter();		/* Set up system's ideas about terminal */
 | 
						||
	t_enter();		/* Set terminal up for editing */
 | 
						||
}
 | 
						||
 | 
						||
/* CLEAN_EXIT() - Restore original terminal modes.
 | 
						||
 *	Returns previous state.
 | 
						||
 */
 | 
						||
clean_exit ()
 | 
						||
{	register int prevstate = trm_mode;
 | 
						||
 | 
						||
	if(prevstate > 0)	/* Ignore unless in editing mode */
 | 
						||
	  {	trm_mode = 0;
 | 
						||
		t_curpos(scr_ht-1, 0);	/* Go to screen bottom */
 | 
						||
		t_exit();		/* Clean up the terminal */
 | 
						||
		tbufls();		/* Force out all buffered output */
 | 
						||
		ts_exit();		/* Restore system's old term state */
 | 
						||
#if ! IMAGEN
 | 
						||
		writez(1,"\n");		/* Get fresh line using OS output */
 | 
						||
#endif /*-IMAGEN*/
 | 
						||
	  }
 | 
						||
	return prevstate;
 | 
						||
}
 | 
						||
 | 
						||
/* SET_SCR() - Allocate screen image, set up screenline pointer table */
 | 
						||
 | 
						||
set_scr()
 | 
						||
{	register struct scr_line **scrp, *stp;
 | 
						||
	register scrsiz;
 | 
						||
	char *sbuf;
 | 
						||
 | 
						||
	scr_wd0 = scr_wid - 1;
 | 
						||
	scrsiz = scr_ht*(scr_wid+MAXCHAR);
 | 
						||
	if(  scr_ht  > MAXHT || scr_wid > MAXLINE)
 | 
						||
	  {	clean_exit();
 | 
						||
		printf("ELLE: %dx%d screen too big\n",scr_ht,scr_wid);
 | 
						||
		exit(1);
 | 
						||
	  }
 | 
						||
	if((stp = (struct scr_line *) calloc(scr_ht*sizeof(struct scr_line)
 | 
						||
							 + scrsiz*2,1)) == 0)
 | 
						||
	  {	clean_exit();
 | 
						||
		printf("ELLE: not enough memory\n");
 | 
						||
		exit(1);
 | 
						||
	  }
 | 
						||
	sbuf = (char *)stp + scr_ht*sizeof(struct scr_line);
 | 
						||
	for(scrp = &scr[0]; scrp < &scr[scr_ht]; sbuf += scr_wid+MAXCHAR)
 | 
						||
	  {	stp->sl_line = sbuf;
 | 
						||
		stp->sl_nlin = sbuf + scrsiz;
 | 
						||
		*scrp++ = stp++;
 | 
						||
	  }
 | 
						||
}
 | 
						||
 | 
						||
/* REDISPLAY()
 | 
						||
 *	Main function of redisplay routines.  Called every time ELLE
 | 
						||
 * forces update of the terminal screen.  "rd_type" contains hints
 | 
						||
 * as to what has changed or needs updating, to avoid wasting time
 | 
						||
 * on things which don't need attention.
 | 
						||
 */
 | 
						||
redisplay ()
 | 
						||
{	register struct window *w;
 | 
						||
	register i;
 | 
						||
	struct window *make_mode();
 | 
						||
 | 
						||
	w = cur_win;
 | 
						||
	w->w_redp |= rd_type&RDS_WINFLGS;	/* Set cur_win's flags */
 | 
						||
	rd_type &= ~RDS_WINFLGS;		/* Leave only globals */
 | 
						||
 | 
						||
	if (rd_type & RD_SCREEN)		/* Clear and refresh? */
 | 
						||
	  {
 | 
						||
		t_clear ();			/* Clear the screen */
 | 
						||
		for(i = scr_ht; --i >= 0;)	/* Clear screen image */
 | 
						||
			scr[i]->sl_col = 0;
 | 
						||
		if(w != ask_win)		/* If not in ask-window */
 | 
						||
		  {	chg_win(ask_win);
 | 
						||
			e_reset();		/* Then flush its contents */
 | 
						||
			chg_win(w);
 | 
						||
		  }
 | 
						||
		redp(RD_WINDS);		/* Update all windows */
 | 
						||
		rd_type &= ~RD_SCREEN;	/* If redisplay is interrupted, */
 | 
						||
					/* don't do it all over again */
 | 
						||
	  }
 | 
						||
	if (rd_type & RD_WINDS)		/* Update all windows? */
 | 
						||
	  {	redp(RD_CHKALL);
 | 
						||
		for (w = win_head; w; w = w -> w_next)	/* For each win */
 | 
						||
			w->w_redp |= RD_WINRES;
 | 
						||
		rd_type &= ~RD_WINDS;
 | 
						||
	  }
 | 
						||
	if (rd_type & RD_CHKALL)	/* Check all windows for changes? */
 | 
						||
	  {	for (w = win_head; w; w = w->w_next)	/* For each win */
 | 
						||
		    if(!(w->w_flags&W_MODE))		/* skip mode wins */
 | 
						||
			if(w->w_redp && upd_wind(w))
 | 
						||
				return;		/* May be interrupted */
 | 
						||
 | 
						||
	  }
 | 
						||
 | 
						||
	/* See if ask-window needs updating (to avoid RD_CHKALL in SAY) */
 | 
						||
	if((w = ask_win)->w_redp && upd_wind(w))
 | 
						||
		return;				/* May be interrupted */
 | 
						||
 | 
						||
	/* Check current window for changes */
 | 
						||
	if((w = cur_win)->w_redp && upd_wind(w))
 | 
						||
		return;				/* May be interrupted */
 | 
						||
 | 
						||
	/* Now update mode line(s) if necessary */
 | 
						||
	if(rd_type&RD_MODE)
 | 
						||
	  {
 | 
						||
		fupd_wind(w = make_mode(user_win));
 | 
						||
#if FX_2MODEWINDS
 | 
						||
		if (sep_win			/* If 2 windows */
 | 
						||
		  && (sep_win->w_flags&W_MODE)	/* and 2 mode windows */
 | 
						||
		  && (sep_win->w_redp || mode_win->w_redp))	/* Check */
 | 
						||
			fupd_wind(make_mode(oth_win));	/* Must update both */
 | 
						||
#endif
 | 
						||
	  }
 | 
						||
 | 
						||
	/* Finally, leave cursor in right place. */
 | 
						||
	if(upd_curs(cur_dot)==0)		/* If something screwed up, */
 | 
						||
		errbarf("Cursor out of window");	/* Complain, */
 | 
						||
						/* and leave cursor at bot */
 | 
						||
	rd_type = 0;
 | 
						||
	tbufls();		/* Force out all terminal output */
 | 
						||
}
 | 
						||
 | 
						||
fupd_wind(w)		/* Force window update */
 | 
						||
register struct window *w;
 | 
						||
{
 | 
						||
	w->w_redp |= RD_WINRES;
 | 
						||
	if(fix_wind(w))
 | 
						||
		upd_wind(w);
 | 
						||
}
 | 
						||
 | 
						||
/*
 | 
						||
 * UPD_CURS
 | 
						||
 *	Move screen cursor to position of specified dot within current window.
 | 
						||
 *	Returns 0 if dot was not within window (and cursor was not moved),
 | 
						||
 *	otherwise returns 1 for success.
 | 
						||
 */
 | 
						||
upd_curs(adot)
 | 
						||
chroff adot;
 | 
						||
{	register struct scr_line *s;
 | 
						||
	register int y, x;
 | 
						||
	chroff savdot;
 | 
						||
 | 
						||
	if((y = d_line(adot)) < 0)
 | 
						||
		return(0);	/* Fail, not within window */
 | 
						||
	s = scr[y];		/* Now have line that dot is on */
 | 
						||
 | 
						||
	/* Get proper offset for any continuation chars from prev line */
 | 
						||
	if(y > cur_win->w_pos)
 | 
						||
	  {	if((x = scr[y-1]->sl_cont) > 0)
 | 
						||
			x--;
 | 
						||
	  }
 | 
						||
	else x = 0;
 | 
						||
 | 
						||
	savdot = e_dot();
 | 
						||
	e_go(s->sl_boff);
 | 
						||
	if((x = d_ncols((int)(adot - s->sl_boff),x)) < 0)
 | 
						||
	  {	/* If lost, assume it's because we are just after a char
 | 
						||
		** which has its representation continued onto next line.
 | 
						||
		** Move cursor to end of that continuation.
 | 
						||
		** d_line should have ensured that this is safe, but
 | 
						||
		** we double-check just to make sure.
 | 
						||
		*/
 | 
						||
		if((x = s->sl_cont) > 0)	/* Set X to end of cont */
 | 
						||
			--x;
 | 
						||
						/* and on next line down */
 | 
						||
		if(++y >= (cur_win->w_pos + cur_win->w_ht))
 | 
						||
		  {	e_go(savdot);		/* Failed, below window */
 | 
						||
			return(0);
 | 
						||
		  }
 | 
						||
	  }
 | 
						||
	e_go(savdot);
 | 
						||
	t_move(y, x);		/* Move cursor cleverly */
 | 
						||
	return(1);		/* Return success! */
 | 
						||
}
 | 
						||
 | 
						||
/* Return line # for given dot, -1 if out of current window */
 | 
						||
d_line(cdot)
 | 
						||
chroff cdot;
 | 
						||
{	register struct scr_line *s;
 | 
						||
	register struct window *w;
 | 
						||
	register int i;
 | 
						||
	chroff savdot;
 | 
						||
	int bot;
 | 
						||
 | 
						||
	w = cur_win;
 | 
						||
	i = w->w_pos;
 | 
						||
	bot = i + w->w_ht;
 | 
						||
	for(; i < bot; i++)
 | 
						||
	  {	s = scr[i];
 | 
						||
		if(cdot <= s->sl_boff)
 | 
						||
			goto gotl;
 | 
						||
	  }
 | 
						||
	/* End of window, repeat test specially for last line */
 | 
						||
	savdot = s->sl_boff + (chroff)s->sl_len;
 | 
						||
	if(cdot > savdot)	/* If past last char of last line */
 | 
						||
		return(-1);	/* then clearly outside */
 | 
						||
	--i;			/* Make i match s (bottom line) */
 | 
						||
	if(savdot != cdot)	/* If not exactly at end */
 | 
						||
		return(i);	/* Then we're inside for sure */
 | 
						||
	goto linbet;
 | 
						||
 | 
						||
gotl:	if(s->sl_boff != cdot)	/* Are we on line boundary? */
 | 
						||
	  {	if(i <= w->w_pos)	/* No, off top of window? */
 | 
						||
			return(-1);	/* Above top, out for sure */
 | 
						||
		return(--i);
 | 
						||
	  }
 | 
						||
 | 
						||
	/* Here, dot is exactly on line boundary, have to decide which
 | 
						||
	 * line it really belongs to.
 | 
						||
	 * Get S = pointer to line which cursor is at the end of.
 | 
						||
	 */
 | 
						||
	if(i <= w->w_pos)	/* Quick chk of trivial case, empty buffer */
 | 
						||
		return(i);
 | 
						||
	s = scr[--i];
 | 
						||
linbet:
 | 
						||
	if((s->sl_flg&SL_EOL)	/* If line has LF */
 | 
						||
	  || (s->sl_cont > 1))	/* or a continued char */
 | 
						||
		if(++i >= bot)		/* Then cursor is on next line */
 | 
						||
			return(-1);
 | 
						||
	return(i);
 | 
						||
}
 | 
						||
 | 
						||
/* D_NCOLS - auxiliary for UPD_CURS.  (also called by indtion() in EEFD)
 | 
						||
**	 We are positioned at a place in the current buffer corresponding to
 | 
						||
** the beginning of the screen line, and given:
 | 
						||
**	lcnt - # of chars in buffer to move forward over
 | 
						||
**	ccol - current column position
 | 
						||
** Returns the new column position.  There are some special cases:
 | 
						||
**	Hits EOF: returns normally (new column position)
 | 
						||
**	Hits EOL: returns -1
 | 
						||
**	Position is past end of screen: returns -1
 | 
						||
** The buffer position has changed, but this is irrelevant as upd_curs
 | 
						||
** restores it just after the call.
 | 
						||
*/
 | 
						||
d_ncols(lcnt, ccol)
 | 
						||
int lcnt;
 | 
						||
int ccol;
 | 
						||
{	register int col, i;
 | 
						||
	register SBBUF *sb;
 | 
						||
	int c;
 | 
						||
	char tmp[MAXCHAR*2];	/* MAXCHAR is enough, but *2 just in case */
 | 
						||
 | 
						||
	col = ccol;
 | 
						||
	sb = (SBBUF *) cur_buf;
 | 
						||
	if((i = lcnt) > 0)
 | 
						||
		do {	if((c = sb_getc(sb)) == EOF)
 | 
						||
				break;
 | 
						||
			/* Check to see if we've run into an EOL */
 | 
						||
#if FX_EOLMODE
 | 
						||
			if(c == CR)
 | 
						||
			  {	if(eolcrlf(sb))
 | 
						||
				  {	if((c = sb_getc(sb)) == LF) /* EOL? */
 | 
						||
					/* Real EOL.  Fail unless point
 | 
						||
					** is between CR and LF, in which case
 | 
						||
					** we return 0 (left margin).
 | 
						||
					*/
 | 
						||
					    return (i==1 ? 0 : -1);
 | 
						||
					/* Stray CR, back up & fall thru */
 | 
						||
					if(c != EOF)
 | 
						||
						sb_backc(sb);
 | 
						||
					c = CR;
 | 
						||
				  }
 | 
						||
			  } else if (c == LF)
 | 
						||
			  {	if(!eolcrlf(sb))	/* Real EOL? */
 | 
						||
					return -1;	/* Yes, fail */
 | 
						||
				/* If EOL mode is CRLF then hitting a LF
 | 
						||
				** can only happen for stray LFs (the
 | 
						||
				** previous check for CR takes care of
 | 
						||
				** CRLFs, and we never start scanning
 | 
						||
				** from the middle of a CRLF.
 | 
						||
				** Drop thru to show stray LF.
 | 
						||
				*/
 | 
						||
			  }
 | 
						||
#else
 | 
						||
			if(c == LF)
 | 
						||
				return(-1);
 | 
						||
#endif /*-FX_EOLMODE*/
 | 
						||
			col += sctr(c, tmp, col);
 | 
						||
		  } while(--i);
 | 
						||
	if(col > scr_wd0)
 | 
						||
		return(-1);
 | 
						||
	return(col);
 | 
						||
}
 | 
						||
 | 
						||
/* D_LUPD - called from command level to completely redisplay a
 | 
						||
 *	specific line on the screen.
 | 
						||
 */
 | 
						||
d_lupd(w, idx)
 | 
						||
struct window *w;		/* Window this line belongs to, if known */
 | 
						||
int idx;
 | 
						||
{	t_curpos(idx, 0);
 | 
						||
	t_docleol();		/* Zap physical screen line */
 | 
						||
	scr[idx]->sl_col = 0;	/* Reflect it on phys screen image */
 | 
						||
	if(w)			/* Mark window for updating */
 | 
						||
		w->w_redp |= RD_WINRES;
 | 
						||
	else redp(RD_WINDS);	/* No window given, assume global */
 | 
						||
	redp(RD_MOVE);		/* Cursor has moved */
 | 
						||
}
 | 
						||
 | 
						||
/* Clear a window completely the "quickest possible way" */
 | 
						||
clear_wind(w)
 | 
						||
register struct window *w;
 | 
						||
{
 | 
						||
	register int i = w->w_pos;	/* Top line of window */
 | 
						||
	register int bot = i + w->w_ht;	/* Bottom line (plus 1) of window */
 | 
						||
 | 
						||
	for ( ; i < bot; ++i)
 | 
						||
		d_lupd(w, i);		/* Zap that line */
 | 
						||
}
 | 
						||
 | 
						||
/* FIX_WIND - Sets up window screen image.  Does not generate any
 | 
						||
 *	terminal output, but completely specifies what the new screen
 | 
						||
 *	image should look like.
 | 
						||
 *	Only the following 4 flags (lumped together in RDS_DOFIX)
 | 
						||
 *	provoke fix_wind to do something:
 | 
						||
 *		RD_MOVE - cursor has moved, must make sure still within
 | 
						||
 *			window, and select new one if not.
 | 
						||
 *		RD_TMOD - Text has been changed somewhere.
 | 
						||
 *		RD_FIXWIN - Something requested that fix_wind fix things.
 | 
						||
 *			Normally this is set when a new w_topldot is set.
 | 
						||
 *		RD_WINRES - Window needs to be completely regenerated.
 | 
						||
 * Results:
 | 
						||
 *	Verifies that the current dot for the window (w_dot) exists.
 | 
						||
 * If it is past the end of buffer, it is reset to EOB, and if this is
 | 
						||
 * the current window, also updates cur_dot.  Otherwise, w_dot is never
 | 
						||
 * adjusted; it is fix_wind's responsibility to make sure that the window
 | 
						||
 * displays w_dot.
 | 
						||
 *	Verifies that current w_topldot setting will result in cursor
 | 
						||
 * (specified by w_dot) appearing within window.  If not, resets w_topldot
 | 
						||
 * to an appropriate value (1/3 of way down from top, unless
 | 
						||
 * moving up in which case 1/3 of way up from bottom).
 | 
						||
 *	Makes sure that sl_boff, sl_len, sl_flg, and sl_cont
 | 
						||
 * are set properly for all lines in window.  SL_MOD is set
 | 
						||
 * for any lines requiring screen updates; these lines
 | 
						||
 * also have sl_nlin and sl_ncol properly set.
 | 
						||
 *	Note that sl_line and sl_col are NOT updated or changed, because
 | 
						||
 * the physical screen has not been altered!
 | 
						||
 *
 | 
						||
 *	Returns 0 if no physical screen updates are needed (other than
 | 
						||
 *		cursor moving and mode line updating).
 | 
						||
 *	Returns 1 if screen updates are needed; RD_UPDWIN is set in w_redp,
 | 
						||
 *		indicating that UPD_WIND should be called.
 | 
						||
 */
 | 
						||
 | 
						||
fix_wind (win)
 | 
						||
struct window *win;
 | 
						||
{
 | 
						||
	register struct window *w;
 | 
						||
	register int i;
 | 
						||
	register struct scr_line *s;
 | 
						||
	chroff cdot, bdelta, updot, sdot, newz;
 | 
						||
	chroff savdot;
 | 
						||
	struct buffer *savbuf;
 | 
						||
	int bot, nlmod, savi, contf, ocontf, randomflg;
 | 
						||
	int newpct;
 | 
						||
 | 
						||
	if(!(w = win))
 | 
						||
		return(0);
 | 
						||
	if(!(w->w_redp&RDS_DOFIX))	/* Anything we need to do? */
 | 
						||
		return(0);		/* Nope, just ignore */
 | 
						||
 | 
						||
	/* Find current dot for this window, and set up other stuff */
 | 
						||
	cdot = (w == cur_win) ? cur_dot : w->w_dot;
 | 
						||
	bot = w->w_pos + w->w_ht;
 | 
						||
	savbuf = cur_buf;
 | 
						||
	cur_buf = w->w_buf;
 | 
						||
	savdot = e_dot();
 | 
						||
	nlmod = 0;			/* No screen image changes so far */
 | 
						||
 | 
						||
	/* Dot (ie cursor) is before current top?  If so, must move
 | 
						||
	 * backwards to find a new topldot.  Note also that buffer may have
 | 
						||
	 * changed so that either cdot or topldot points past EOF.
 | 
						||
	 */
 | 
						||
	if(w->w_topldot > cdot)
 | 
						||
	  {	/* Yes, must search backwards scrht/3 screen lines */
 | 
						||
		/* from cdot in order to find topldot. */
 | 
						||
		/* Don't bother updating scr stuff beforehand since we'll
 | 
						||
		 * have to revise everything anyway and can do it on the fly.
 | 
						||
		 */
 | 
						||
		i = (ev_mvpct * w->w_ht) / 100;
 | 
						||
		goto skipdn;
 | 
						||
 | 
						||
	finddn:	i = ((100 - ev_mvpct) * w->w_ht) / 100;
 | 
						||
	skipdn:	if(i <= 0) i = 1;	/* Ensure # is reasonable */
 | 
						||
		else if(i >= w->w_ht) i = w->w_ht-1;
 | 
						||
		e_go(cdot);		/* Start here (may normalize to EOF)*/
 | 
						||
		d_backup(i ? i : 1);	/* Try to back up cleverly */
 | 
						||
		w->w_topldot = e_dot();
 | 
						||
		randomflg = 0;		/* We have some idea where we are */
 | 
						||
	fixall:		/* Entry point for later recheck, with randomflg==1 */
 | 
						||
		newz = e_blen();
 | 
						||
		if(newz < cdot)		/* Part of buf may have gone away */
 | 
						||
		  {			/* So normalize dot to EOF */
 | 
						||
			w->w_dot = cdot = newz;
 | 
						||
			if(w == cur_win)	/* Special check for fixing */
 | 
						||
				cur_dot = newz;	/* up cur_dot too! */
 | 
						||
			goto finddn;	/* and get a new top-of-window loc */
 | 
						||
		  }
 | 
						||
	retry:	i = w->w_pos;
 | 
						||
		contf = 0;
 | 
						||
		s = 0;
 | 
						||
		for(; i < bot; i++)
 | 
						||
		  {	nlmod++;
 | 
						||
			fix_line(scr[i], s);	/* s = 0 the first time */
 | 
						||
			s = scr[i];
 | 
						||
#if FX_SOWIND
 | 
						||
			if(w->w_flags & W_STANDOUT)
 | 
						||
				s->sl_flg |= SL_NSO;
 | 
						||
			else s->sl_flg &= ~SL_NSO;
 | 
						||
#endif
 | 
						||
		  }
 | 
						||
		if(inwinp(w,cdot))	/* Ensure in window */
 | 
						||
			goto mdone;
 | 
						||
		if(randomflg)		/* If jumped randomly, */
 | 
						||
		  {	i = (ev_nwpct * w->w_ht) / 100;
 | 
						||
			goto skipdn;	/* Try to select new window */
 | 
						||
		  }
 | 
						||
 | 
						||
		/* We tried to back up and went too far. */
 | 
						||
		if(cdot < w->w_topldot)	/* Verify place is ahead */
 | 
						||
		  {	errbarf("fix_wind failed");	/* Didn't back up?? */
 | 
						||
			goto finddn;
 | 
						||
		  }
 | 
						||
		/* Move down one line and try again */
 | 
						||
		if(w->w_ht > 1)
 | 
						||
			w->w_topldot = scr[w->w_pos+1]->sl_boff;
 | 
						||
		else
 | 
						||
		  {	s = scr[w->w_pos];
 | 
						||
			w->w_topldot = s->sl_boff + s->sl_len;
 | 
						||
		  }
 | 
						||
		e_go(w->w_topldot);
 | 
						||
		goto retry;
 | 
						||
	  }
 | 
						||
 | 
						||
	/* At some future point, could separate out processing for
 | 
						||
	 * RD_WINRES and RD_FIXWIN.  Latter flag implies only w_topldot
 | 
						||
	 * has changed (new window selected).  Former implies whole
 | 
						||
	 * buffer has been munged, and everything is completely redone.
 | 
						||
	 */
 | 
						||
	if(w->w_redp&(RD_WINRES|RD_FIXWIN))	/* If re-figuring whole window */
 | 
						||
	  {	e_go(w->w_topldot);	/* Start here, and */
 | 
						||
		randomflg = 1;		/* set up flag saying random jump */
 | 
						||
		goto fixall;		/* and go crunch all lines. */
 | 
						||
	  }
 | 
						||
	if((w->w_redp&RD_TMOD)==0)	/* If claims no text mods, */
 | 
						||
	  {	if(inwinp(w,cdot)==0)	/* Just verify cursor loc. */
 | 
						||
			goto finddn;	/* Sigh.... */
 | 
						||
		newz = w->w_oldz;	/* Win, set up for exit. */
 | 
						||
		goto done;
 | 
						||
	  }
 | 
						||
	/* Here only when RD_TMOD is set, indicating changes are
 | 
						||
	 * between range variables.
 | 
						||
	 */
 | 
						||
	/* Find upper bound of any mods.  This is a little gross in the
 | 
						||
	 * speed dept and some faster way should perhaps be devised.
 | 
						||
	 * In particular the main loop should incrementally keep track of
 | 
						||
	 * buffer size, and should set a flag RD_TEXT if anything has
 | 
						||
	 * actually been changed.  Edit routines should have lots of
 | 
						||
	 * flags available to tell main loop more precisely what they did,
 | 
						||
	 * so main loop can take care of updating b/emod and stuff.
 | 
						||
	 */
 | 
						||
	if((newz = e_blen()) == 0)
 | 
						||
		goto finddn;		/* Ensure blank window is cleared */
 | 
						||
	bdelta = newz - w->w_oldz;
 | 
						||
	if((updot = newz) > w->w_emod)
 | 
						||
		updot -= w->w_emod;
 | 
						||
	if(bdelta == 0 && (updot == w->w_bmod))
 | 
						||
		goto inwinq;
 | 
						||
 | 
						||
	/* Could also check for updot < w_topldot (changes above win)
 | 
						||
	 * or sl_boff+sl_len < w_bmod  (changes below win) but those
 | 
						||
	 * cases are probably pretty rare.
 | 
						||
	 */
 | 
						||
	/* First find line where changes start */
 | 
						||
	for(i = w->w_pos; i < bot; i++)
 | 
						||
	  {	s = scr[i];
 | 
						||
		if(w->w_bmod <= s->sl_boff)	/* Changes prior to this? */
 | 
						||
			break;
 | 
						||
	  }
 | 
						||
	if(i >= bot)			/* Test last line specially */
 | 
						||
	  {	if(w->w_bmod > (s->sl_boff + (chroff)s->sl_len))
 | 
						||
			goto inwinq;	/* Outside window */
 | 
						||
					/* Last line changed, hack it */
 | 
						||
	  }
 | 
						||
	if(i > w->w_pos			/* If we have a prev line */
 | 
						||
	  && (s->sl_len == 0		/* and we're at EOF, */
 | 
						||
	    || w->w_bmod != s->sl_boff	/* or not at start of line */
 | 
						||
	    || scr[i-1]->sl_cont))	/* or prev line is continuation */
 | 
						||
		s = scr[--i];		/* then it's prev line we want */
 | 
						||
 | 
						||
	/* I has index for screen line changes begin on; S has ptr.
 | 
						||
	 * This piece of code handles case where buffer has been modified
 | 
						||
	 * starting at BMOD, and BDELTA chars have been inserted/deleted;
 | 
						||
	 * range of changes ends at UPDOT.
 | 
						||
	 */
 | 
						||
	savi = i;
 | 
						||
	while(++i < bot)
 | 
						||
		scr[i]->sl_boff += bdelta;
 | 
						||
	i = savi;
 | 
						||
 | 
						||
	/* Now start with 1st changed line and start figuring new line
 | 
						||
	 * lengths.  Stop when hit end, or past updot and boff is correct
 | 
						||
	 * for start of line.
 | 
						||
	 */
 | 
						||
	/* can improve this by jumping out when past emod, and testing for
 | 
						||
	 * an EOL - then know stuff has to match someplace, so look for that.
 | 
						||
	 * could then simply update lengths or something?
 | 
						||
	 */
 | 
						||
	if(i > w->w_pos)	/* Find # cols already there from prev line*/
 | 
						||
		contf = scr[i-1]->sl_cont;
 | 
						||
	else contf = 0;
 | 
						||
	ocontf = 1;			/* Fake it so always update 1st line*/
 | 
						||
	e_go(sdot = s->sl_boff);
 | 
						||
	for(; i < bot; i++)
 | 
						||
	  {	s = scr[i];
 | 
						||
		if(updot <= sdot	/* If past changed stuff */
 | 
						||
		  && sdot == s->sl_boff	/* and locs are lined up */
 | 
						||
		  && contf == 0		/* and previous line clean */
 | 
						||
		  && ocontf == 0)	/* (both old and new images) */
 | 
						||
			break;		/* Then done. */
 | 
						||
		nlmod++;
 | 
						||
		ocontf = s->sl_cont;	/* Save old-image contf value */
 | 
						||
		fix_line(s, (i > w->w_pos) ? scr[i-1] : 0);
 | 
						||
#if FX_SOWIND
 | 
						||
		if(w->w_flags & W_STANDOUT)
 | 
						||
			s->sl_flg |= SL_NSO;
 | 
						||
		else s->sl_flg &= ~SL_NSO;
 | 
						||
#endif
 | 
						||
		sdot = e_dot();
 | 
						||
		contf = s->sl_cont;	/* Get new-image contf value */
 | 
						||
	  }
 | 
						||
	if(inwinp(w,cdot))	/* OK, screen fixed, see if cursor inside */
 | 
						||
		goto mdone;
 | 
						||
	goto finddn;
 | 
						||
 | 
						||
	/* Test if still in window and dispatch appropriately */
 | 
						||
inwinq:	if(inwinp(w,cdot))
 | 
						||
		goto done;
 | 
						||
	else goto finddn;
 | 
						||
 | 
						||
	/* Come here when done, after mods made to window.
 | 
						||
	 * Calculate new %-of-buffer position for window's view, and
 | 
						||
	 * see if it's changed from current %.
 | 
						||
	 */
 | 
						||
mdone:	if(w != cur_win) goto done;	/* If not current window, ignore */
 | 
						||
	s = scr[bot-1];
 | 
						||
	if((s->sl_boff + (chroff)s->sl_len) >= newz)
 | 
						||
		if(w->w_topldot) newpct = 150;	/* BOT */
 | 
						||
		else newpct = 200;		/* ALL */
 | 
						||
	else if(w->w_topldot == 0)
 | 
						||
		newpct = -1;			/* TOP */
 | 
						||
	else		/* NOTE: This won't work if topldot is huge */
 | 
						||
		newpct = (w->w_topldot*100)/newz;	/* nn% */
 | 
						||
	if(newpct != w->w_pct)		/* OK, now compare with old % */
 | 
						||
	  {	w->w_pct = newpct;	/* Different, must set and */
 | 
						||
		redp(RD_MODE);		/* invoke redisplay of mode line! */
 | 
						||
	  }
 | 
						||
 | 
						||
done:	w->w_bmod = -1;		/* To indicate vars not set */
 | 
						||
	w->w_oldz = newz;
 | 
						||
	w->w_redp &= ~RDS_DOFIX;	/* Clear flags that invoked us */
 | 
						||
	if(nlmod)
 | 
						||
		w->w_redp |= RD_UPDWIN;	/* Say stuff to be updated */
 | 
						||
	e_go(savdot);
 | 
						||
	cur_buf = savbuf;
 | 
						||
	return(nlmod);
 | 
						||
}
 | 
						||
 | 
						||
/* INWINP - Returns true if given dot is inside given window.
 | 
						||
 */
 | 
						||
inwinp(win,cdot)
 | 
						||
struct window *win;
 | 
						||
chroff cdot;
 | 
						||
{	register struct scr_line *s;
 | 
						||
	register struct window *w;
 | 
						||
	chroff sdot;
 | 
						||
 | 
						||
	w = win;
 | 
						||
	if(cdot < w->w_topldot)
 | 
						||
		return(0);
 | 
						||
	s = scr[(w->w_pos + w->w_ht) - 1];
 | 
						||
	sdot = s->sl_boff + (chroff)s->sl_len;
 | 
						||
	if(cdot < sdot)
 | 
						||
		return(1);		/* Yup, inside window. */
 | 
						||
	if(cdot > sdot)
 | 
						||
		return(0);
 | 
						||
 | 
						||
	/* Dot is exactly at end of window, must check further. */
 | 
						||
	if(s->sl_len		/* If line exists, */
 | 
						||
	 && ((s->sl_flg&SL_EOL)	/* and ends in LF, */
 | 
						||
	    || s->sl_cont > 1))	/* or sl_cont > 1, lose. */
 | 
						||
		return(0);
 | 
						||
	return(1);		/* Else inside, win. */
 | 
						||
}
 | 
						||
 | 
						||
/*
 | 
						||
 * UPD_WIND
 | 
						||
 *	If argument 0, assumes cur_win and DOESN'T interrupt if input
 | 
						||
 *	detected.
 | 
						||
 */
 | 
						||
 | 
						||
upd_wind(win)
 | 
						||
struct window *win;
 | 
						||
{	register int i, n;
 | 
						||
	register struct scr_line *s;
 | 
						||
	struct window *w;
 | 
						||
	int top, bot, dspf, num, isave, noicost, nodcost, iline, dline;
 | 
						||
#if FX_SOWIND
 | 
						||
	int oldso;
 | 
						||
#endif
 | 
						||
#if IMAGEN
 | 
						||
	int origdspf;
 | 
						||
	char redpmsg[128];
 | 
						||
#endif /*IMAGEN*/
 | 
						||
 | 
						||
	if((w=win)==0)
 | 
						||
		w = cur_win;
 | 
						||
	dspf = w->w_redp;		/* Get update flags for window */
 | 
						||
#if IMAGEN
 | 
						||
	origdspf = dspf;
 | 
						||
#endif /*IMAGEN*/
 | 
						||
	if(w == cur_win)		/* If updating current window, */
 | 
						||
		dspf |= rd_type;	/* merge in global flags */
 | 
						||
	if((dspf &= RDS_WINFLGS) == 0)	/* Well, it might happen sometimes */
 | 
						||
		goto zdone;
 | 
						||
	w->w_redp = dspf;
 | 
						||
	if(dspf&(RD_WINRES|RD_TMOD|RD_MOVE|RD_FIXWIN))
 | 
						||
	  {	fix_wind(w);		/* May set some flags, so */
 | 
						||
		dspf = w->w_redp;	/* get them back... */
 | 
						||
	  }
 | 
						||
	if((dspf&RD_UPDWIN)==0)		/* Must ask for update! */
 | 
						||
		goto zdone;
 | 
						||
#if IMAGEN
 | 
						||
	if (dbg_redp)
 | 
						||
	  {	sprintf(redpmsg,
 | 
						||
			"buffer: %14s, rd_type: %06o, w_redp: %06o, dspf: %06o",
 | 
						||
			w->w_buf->b_name, rd_type, origdspf, dspf);
 | 
						||
		barf2(redpmsg);
 | 
						||
	  }
 | 
						||
#endif /*IMAGEN*/
 | 
						||
 | 
						||
	/* Assume screen structure set up by FIX_WIND, just go
 | 
						||
	 * effect change for every line modified.
 | 
						||
	 */
 | 
						||
#if FX_SOWIND
 | 
						||
	oldso = t_dostandout((w->w_flags&W_STANDOUT)? 1:0);
 | 
						||
#endif
 | 
						||
	top = w->w_pos;
 | 
						||
	bot = top + w->w_ht;
 | 
						||
	for(i = top; i < bot; ++i)
 | 
						||
	  if((s = scr[i])->sl_flg&SL_MOD)
 | 
						||
	  {	if(win && tinwait())	/* If OK, stop if any chars typed */
 | 
						||
		  {	tbufls();
 | 
						||
			w->w_redp = dspf;
 | 
						||
#if FX_SOWIND
 | 
						||
			t_dostandout(oldso);
 | 
						||
#endif
 | 
						||
			return(1);	/* Return immediately, say int'd */
 | 
						||
		  }
 | 
						||
		if(slineq(s,s))		/* Compare old with new */
 | 
						||
			goto ldone;	/* Lines equal, no update needed */
 | 
						||
	
 | 
						||
#if IMAGEN
 | 
						||
		/* If hint says redo entirely */
 | 
						||
		if (dspf & RD_REDO)
 | 
						||
		  {	s->sl_flg |= SL_REDO;	 /* Do "fast update" */
 | 
						||
			goto nodel;		/* Just go update line */
 | 
						||
		  }
 | 
						||
#endif /*IMAGEN*/
 | 
						||
		if((trm_flags&TF_IDLIN)==0)
 | 
						||
			goto nodel;		/* Just go update line */
 | 
						||
 | 
						||
 | 
						||
		/* Check for I/D line.  If no hints exist, check for both
 | 
						||
		 * insert and delete.
 | 
						||
		 */
 | 
						||
		if((dspf&(RD_ILIN|RD_DLIN))==0)
 | 
						||
			dspf |= RD_ILIN|RD_DLIN;
 | 
						||
		noicost = 0;
 | 
						||
		nodcost = 0;
 | 
						||
 | 
						||
		/* Check for insert line.  See if the current old screen
 | 
						||
		 * line is duplicated among any of the new lines which
 | 
						||
		 * follow it.  If a match is found, keep looking and add
 | 
						||
		 * up the number of characters in the matching lines.
 | 
						||
		 */
 | 
						||
		if(dspf&RD_ILIN)
 | 
						||
		  {
 | 
						||
			/* See if this old screen line is needed elsewhere */
 | 
						||
			if(s->sl_col == 0)	/* Ignore if blank */
 | 
						||
				goto noins;
 | 
						||
			
 | 
						||
			for(n = i+1; n < bot; n++)
 | 
						||
			  {	if((scr[n]->sl_flg&SL_MOD)==0)
 | 
						||
					break;
 | 
						||
				if(slineq(s, scr[n]))	/* Old, new */
 | 
						||
				  {	if(!noicost) iline = n;	/* 1st time */
 | 
						||
					noicost += s->sl_col;
 | 
						||
					s++;
 | 
						||
				  }
 | 
						||
				else if(noicost) break;
 | 
						||
			  }
 | 
						||
			if(!noicost)		/* If no match, forget it */
 | 
						||
				goto noins;	/* S will not have changed. */
 | 
						||
			s = scr[i];		/* Restore S */
 | 
						||
			n = iline;		/* Have matches, get index
 | 
						||
						 * of first matching line */
 | 
						||
 | 
						||
			/* Heuristic to decide whether to perform
 | 
						||
			 * insert-line operation.  Kind of stupid, but
 | 
						||
			 * good enough for now.
 | 
						||
			 */
 | 
						||
			num = (n-i)*(tvc_ldn+tvc_lin) + (tvc_li + tvc_ld);
 | 
						||
			if((n-i) >= (scr_ht-(ECHOLINES+3))
 | 
						||
						/* Don't move lines all the
 | 
						||
						 * way down full screen! */
 | 
						||
			  || num >= noicost)	/* Compare cost with estimated
 | 
						||
						 * cost of not doing insert.*/
 | 
						||
				goto noins;
 | 
						||
 | 
						||
			/* Insert lines! */
 | 
						||
			dspf &= ~RD_ILIN;
 | 
						||
			inslin(i, n - i, w);
 | 
						||
			for(; i < n; i++)	/* Update intervening lines */
 | 
						||
				upd_line (i);
 | 
						||
			goto ldone;
 | 
						||
		  }
 | 
						||
noins:
 | 
						||
 | 
						||
		/* Check for delete line.  See if the new screen line
 | 
						||
		 * is duplicated among any of the old lines already on
 | 
						||
		 * the screen.  If a match is found, keep looking and add
 | 
						||
		 * up the number of characters in the matching lines.
 | 
						||
		 */
 | 
						||
		if(dspf&RD_DLIN)
 | 
						||
		  {
 | 
						||
			/* See if the new line already exists elsewhere */
 | 
						||
			if(s->sl_ncol == 0)	/* Ignore blank lines */
 | 
						||
				goto nodel;
 | 
						||
			for (n = i + 1; n < bot; n++)
 | 
						||
			  {	if((scr[n]->sl_flg&SL_MOD)==0)
 | 
						||
					break;
 | 
						||
				if(slineq(scr[n],s))	/* Old, new */
 | 
						||
				  {	if(!nodcost) dline = n;	/* 1st time */
 | 
						||
 					nodcost += s->sl_ncol;
 | 
						||
					s++;
 | 
						||
				  }
 | 
						||
				else if(nodcost) break;
 | 
						||
			  }
 | 
						||
			if(!nodcost)		/* If no match, forget it */
 | 
						||
				goto nodel;	/* S will not have changed. */
 | 
						||
			s = scr[i];		/* Restore S */
 | 
						||
			n = dline;		/* Index of 1st match */
 | 
						||
 | 
						||
			/* Heuristic to decide whether to perform
 | 
						||
			 * delete-line operation.  Same hack as for
 | 
						||
			 * insert-line.
 | 
						||
			 */
 | 
						||
			num = (n-i)*(tvc_ldn+tvc_lin) + (tvc_li + tvc_ld);
 | 
						||
			if((n-i) >= (scr_ht-(ECHOLINES+3))
 | 
						||
			  || num >= nodcost)
 | 
						||
				goto nodel;
 | 
						||
 | 
						||
			/* Delete lines! */
 | 
						||
			dspf &= ~RD_DLIN;
 | 
						||
			dellin(i, n - i, w);
 | 
						||
			goto ldone;
 | 
						||
		  }
 | 
						||
nodel:
 | 
						||
		/* All failed, so just update line */
 | 
						||
		upd_line(i);
 | 
						||
ldone:		s->sl_flg &= ~SL_MOD;	/* Clear mod flag */
 | 
						||
	  }
 | 
						||
done:
 | 
						||
#if FX_SOWIND
 | 
						||
	t_dostandout(oldso);	/* Back to previous mode */
 | 
						||
#endif
 | 
						||
zdone:	w->w_redp = 0;
 | 
						||
	return(0);		/* Say completed */
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
/*
 | 
						||
 * SLINEQ - Compare old, new screen image lines.  If new line doesn't
 | 
						||
 *	have the modified flag set, use its old image.
 | 
						||
 *	If the standout mode differs, always fails.
 | 
						||
 */
 | 
						||
 | 
						||
slineq(olds, news)
 | 
						||
struct scr_line *olds;
 | 
						||
struct scr_line *news;
 | 
						||
{	register char *cpo, *cpn;
 | 
						||
	register int cnt;
 | 
						||
 | 
						||
	cpo = (char *)news;
 | 
						||
	if(((struct scr_line *)cpo)->sl_flg&SL_MOD)
 | 
						||
	  {	cnt = ((struct scr_line *)cpo)->sl_ncol;
 | 
						||
		cpn = ((struct scr_line *)cpo)->sl_nlin;
 | 
						||
#if FX_SOWIND		/* Mode of old must match mode of new */
 | 
						||
		if(((olds->sl_flg & SL_CSO)==0) !=
 | 
						||
			((((struct scr_line *)cpo)->sl_flg & SL_NSO)==0))
 | 
						||
			return 0;
 | 
						||
#endif
 | 
						||
	  }
 | 
						||
	else
 | 
						||
	  {	cnt = ((struct scr_line *)cpo)->sl_col;
 | 
						||
		cpn = ((struct scr_line *)cpo)->sl_line;
 | 
						||
#if FX_SOWIND		/* Modes of current lines must match */
 | 
						||
		if((olds->sl_flg & SL_CSO) !=
 | 
						||
			(((struct scr_line *)cpo)->sl_flg & SL_CSO))
 | 
						||
			return 0;
 | 
						||
#endif
 | 
						||
	  }
 | 
						||
 | 
						||
	/* Crufty match stuff */
 | 
						||
	if(cnt != olds->sl_col)
 | 
						||
		return(0);
 | 
						||
	if(cnt)
 | 
						||
	  {	cpo = olds->sl_line;
 | 
						||
		do { if(*cpo++ != *cpn++)
 | 
						||
			return(0);
 | 
						||
		  } while(--cnt);
 | 
						||
	  }
 | 
						||
	return(1);
 | 
						||
}
 | 
						||
 | 
						||
/* UPD_LINE(lineno) - Effects the update of a physical screen line,
 | 
						||
 *	assuming that the screen line structure for that line has been
 | 
						||
 *	properly set up by fix_wind.  It cannot be interrupted by typein.
 | 
						||
 *	Does a lot of work to check out optimization for char I/D.
 | 
						||
 *	Someday it could also check out the possibility of doing a CLEOL at
 | 
						||
 *	some point to reduce the number of spaces that need to be output.
 | 
						||
 */
 | 
						||
 | 
						||
upd_line(y)
 | 
						||
int y;
 | 
						||
{	register i;
 | 
						||
	register char *sci, *cp;
 | 
						||
	struct scr_line *s;
 | 
						||
 | 
						||
	int xpos;			/* actual screen position */
 | 
						||
	int c, c2, p2, cmpcost, delcost;
 | 
						||
	int savc, ocol, ncol;
 | 
						||
	char *savcp, *savsci;
 | 
						||
#if FX_SOWIND
 | 
						||
	int oldso, newso;
 | 
						||
	int writall = 0;
 | 
						||
#endif
 | 
						||
 | 
						||
	s = scr[y];
 | 
						||
	savsci = sci = s->sl_line;	/* What is currently on the screen */
 | 
						||
#if IMAGEN
 | 
						||
	if (s->sl_flg & SL_REDO)
 | 
						||
	  {	/* Check for line-redo flag */
 | 
						||
		s->sl_flg &= ~SL_REDO;	/* Clear it: we are handling it */
 | 
						||
		writall = 1;	/* Re-do this line completely */
 | 
						||
		t_move(y, 0);
 | 
						||
		t_docleol();
 | 
						||
		s->sl_col = 0;
 | 
						||
	  }
 | 
						||
#endif /*IMAGEN*/
 | 
						||
 | 
						||
#if FX_SOWIND
 | 
						||
	/* See whether modes of the lines are the same or not. */
 | 
						||
	newso = (s->sl_flg & SL_NSO)!=0;	/* Get new mode (true if SO)*/
 | 
						||
	if(((s->sl_flg & SL_CSO)!=0) !=	newso)
 | 
						||
	  {	t_move(y, 0);		/* Not same, must zap existing line */
 | 
						||
		t_docleol();
 | 
						||
		s->sl_col = 0;
 | 
						||
		writall = newso;	/* Output all if SO is new mode */
 | 
						||
	  }
 | 
						||
	oldso = t_dostandout(newso);	/* Get in right mode */
 | 
						||
#endif
 | 
						||
 | 
						||
	ocol = s->sl_col;
 | 
						||
	savcp = cp = s->sl_nlin;
 | 
						||
	ncol = s->sl_ncol;
 | 
						||
 | 
						||
	/* Find leading equalness */
 | 
						||
	i = ocol;
 | 
						||
	if(i > ncol) i = ncol;		/* Use minimum count */
 | 
						||
	if(i)
 | 
						||
	  {	do { if(*cp++ != *sci++)
 | 
						||
			  {	--cp;
 | 
						||
				break;
 | 
						||
			  }
 | 
						||
		  } while(--i);
 | 
						||
		i = cp - savcp;
 | 
						||
		sci = savsci;		/* Restore ptr to beg of cur line */
 | 
						||
	  }
 | 
						||
 | 
						||
	/* From here on, "i" is now the x-coordinate (column addr)
 | 
						||
	 * of the first position that doesn't match.  "cp" points to
 | 
						||
	 * the first nonmatching char in the new line image.
 | 
						||
	 */
 | 
						||
#if COHERENT		/* Has direct video interface capability */
 | 
						||
	if(trm_flags&TF_DIRVID)
 | 
						||
	  {	if(ncol < ocol)
 | 
						||
		  {	/* Flesh out new line to completely replace old */
 | 
						||
			fillsp(&s->sl_nlin[ncol], ocol-ncol);
 | 
						||
			ncol = ocol;
 | 
						||
		  }
 | 
						||
		/* Spit out changed stuff.  t_direct will handle the
 | 
						||
		 * case where i == ncol (ie no changes needed).
 | 
						||
		 */
 | 
						||
		t_direct(y,i,cp,ncol-i);
 | 
						||
		goto done;
 | 
						||
	  }
 | 
						||
#endif /*COHERENT*/
 | 
						||
 | 
						||
	if(i == ncol)			/* Matched up to end of new line? */
 | 
						||
		goto idone;		/* Yes, can skip big loop! */
 | 
						||
 | 
						||
#if FX_SOWIND
 | 
						||
	if(writall)			/* If simply writing everything...*/
 | 
						||
	  {	t_move(y, 0);
 | 
						||
		tputn(cp, ncol);	/* Output them all */
 | 
						||
		curs_col = ncol;	/* Update cursor position */
 | 
						||
		goto idone;		/* then wrap up! */
 | 
						||
	  }
 | 
						||
#endif
 | 
						||
 | 
						||
	/* Now must fill out remainder of old line with blanks. */
 | 
						||
	if(ocol < scr_wid)
 | 
						||
	  {
 | 
						||
#if FX_SOWIND
 | 
						||
		if(newso) fillset(&sci[ocol], scr_wid-ocol, 0);
 | 
						||
		else
 | 
						||
#endif
 | 
						||
		fillsp(&sci[ocol],scr_wid-ocol);	/* Fill out */
 | 
						||
	  }
 | 
						||
 | 
						||
	/******  Main update loop. ******/
 | 
						||
	for (; i < ncol; i++)
 | 
						||
	  {	c = *cp++;		/* Note *CP will point to next */
 | 
						||
		if(c == sci[i])
 | 
						||
			continue;
 | 
						||
		if(i >= ocol)		/* Past EOL of old line? */
 | 
						||
		  {
 | 
						||
putin:			sci[i] = c;
 | 
						||
			if(y != curs_lin || i != curs_col)
 | 
						||
				t_move(y, i);
 | 
						||
			tput(c);
 | 
						||
			curs_col++;
 | 
						||
			continue;
 | 
						||
		  }
 | 
						||
 | 
						||
		if((trm_flags&TF_IDCHR)==0)	/* Replace */
 | 
						||
			goto putin;
 | 
						||
 | 
						||
		/* Do checking to see whether char I/D operations should
 | 
						||
		 * be invoked.  This code is quite CPU intensive and
 | 
						||
		 * can cause noticeable pauses if run on a slow CPU with
 | 
						||
		 * a fast (9600) terminal line.  The optimization tradeoff
 | 
						||
		 * seems worthwhile most of the time, however.
 | 
						||
		 */
 | 
						||
		cmpcost = 0;		/* Default is don't compare */
 | 
						||
		if(ncol == ocol)	/* If line lengths same, must chk */
 | 
						||
		  {
 | 
						||
/*			if(ncol >= scr_wid) */	/* If line overrun, compare */
 | 
						||
				cmpcost++;
 | 
						||
		  }
 | 
						||
#if 0
 | 
						||
If ncol == ocol, have problem with tabs:
 | 
						||
	If don''t use I/D char, but tabs exist, lots of wasteful update.
 | 
						||
	If DO use I/D char, and no tabs exist, potential for mistakenly
 | 
						||
		using I/D when didn''t have to.  Not too bad, though?
 | 
						||
	If DO use I/D char, then mild screw when inserting/deleting
 | 
						||
		just before a tab, since could have just overwritten,
 | 
						||
		but I/D insists on jerking things around.
 | 
						||
	Insert test:
 | 
						||
		If old char was space, replace? Problem: will cause cursor
 | 
						||
		jump if really should have shifted a long run of spaces.
 | 
						||
		But that is probably okay.
 | 
						||
	Delete test:
 | 
						||
		If new char is space, replace? again, will cause cursor jump
 | 
						||
		with long run of spaces.
 | 
						||
#endif /*COMMENT*/
 | 
						||
 | 
						||
		if(ncol < ocol || cmpcost)	/* Try delete-char */
 | 
						||
		  {
 | 
						||
			/* Search old for match of c and nextc */
 | 
						||
dodel:			savc = c;
 | 
						||
			if(i >= ncol-1)
 | 
						||
				goto putin;
 | 
						||
			c2 = *cp;
 | 
						||
			if(c == SP && ncol == ocol)
 | 
						||
				goto tryins;
 | 
						||
			p2 = i;
 | 
						||
			for(;;)
 | 
						||
			  {	if(c == sci[i] && c2 == sci[i+1])
 | 
						||
					break;
 | 
						||
				if(++i < ocol)
 | 
						||
					continue;
 | 
						||
				i = p2;
 | 
						||
				if(cmpcost) {cmpcost = 0; goto tryins;}
 | 
						||
				goto putin;
 | 
						||
			  }
 | 
						||
			/* Find # chars that match (i.e. will be saved) */
 | 
						||
			for(c=1; (i+c < ncol) && (sci[i+c] == cp[c-1]); c++);
 | 
						||
			delcost = tvc_cd + tvc_cdn*(i - p2);
 | 
						||
			if(delcost >= c)
 | 
						||
			  {	c = savc;
 | 
						||
				i = p2;
 | 
						||
				if(cmpcost) { cmpcost = 0; goto tryins;}
 | 
						||
				goto putin;	/* Punt */
 | 
						||
			  }
 | 
						||
			if(cmpcost)
 | 
						||
			  {	c = savc; i = p2;
 | 
						||
				goto tryins;
 | 
						||
			  }
 | 
						||
			t_move(y, p2);
 | 
						||
			c = i - p2;	/* Find # chars to flush */
 | 
						||
			strncpy(&sci[p2],&sci[i], ocol-i);
 | 
						||
			ocol -= c;
 | 
						||
			fillsp(&sci[ocol], c);
 | 
						||
			i = p2;			/* Restore i */
 | 
						||
			t_delchr(c);		/* Flush this many cols */
 | 
						||
			continue;
 | 
						||
		  }
 | 
						||
 | 
						||
		/* Try ins-char */
 | 
						||
		/* Search new for match of i and i+1 */
 | 
						||
		/* Note this cannot be used while in standout mode, since
 | 
						||
		** the new spaces created will probably be in the wrong mode.
 | 
						||
		*/
 | 
						||
tryins:
 | 
						||
#if FX_SOWIND
 | 
						||
		if(newso) goto putin;
 | 
						||
#endif
 | 
						||
		if(i+1 >= ocol)
 | 
						||
			goto putin;
 | 
						||
 | 
						||
		savc = c;
 | 
						||
		savcp = cp;
 | 
						||
		c2 = sci[i+1];
 | 
						||
		if(sci[i] == SP && ncol == ocol)
 | 
						||
			goto putin;
 | 
						||
		xpos = i;		/* save current col */
 | 
						||
		i++;
 | 
						||
		for(;;)
 | 
						||
		  {	if(i >= ncol) goto puntx;
 | 
						||
			c = *cp++;
 | 
						||
inlp2:			if(c != sci[xpos])
 | 
						||
			  {	if(i > scr_wid) goto puntx;
 | 
						||
				i++;
 | 
						||
				continue;
 | 
						||
			  }
 | 
						||
			if(i >= ncol) goto puntx;
 | 
						||
			c = *cp++;
 | 
						||
			if(c != c2)
 | 
						||
			  {	i++;		/* Allow for previous c */
 | 
						||
				goto inlp2;	/* which is always 1 */
 | 
						||
			  }
 | 
						||
			break;
 | 
						||
		  }
 | 
						||
		if(i >= scr_wid) goto puntx;
 | 
						||
 | 
						||
		/* Find how many chars match (i.e. will be saved) */
 | 
						||
		for(c = 2; xpos+c < ncol && sci[xpos+c] == *cp++; c++);
 | 
						||
		if((p2 = tvc_ci + tvc_cin*(i - xpos)) >= c)
 | 
						||
			goto puntx;	/* Not worth it... */
 | 
						||
		if(cmpcost && p2 >= delcost)
 | 
						||
			goto puntx;	/* Do delchr instead */
 | 
						||
 | 
						||
		/* We've decided to insert some chars! */
 | 
						||
		i -= xpos;		/* Get # char positions to insert */
 | 
						||
		cp = savcp;		/* Get ptr to newline string */
 | 
						||
		--cp;			/* Point at 1st char to insert */
 | 
						||
					/* Make room in scr array */
 | 
						||
		inspc(&sci[xpos],
 | 
						||
			&sci[(ocol+i >= scr_wid) ? scr_wid-i : ocol], i);
 | 
						||
		ocol += i;		/* Update size of old line */
 | 
						||
		strncpy(&sci[xpos], cp, i);	/* Copy all inserted chars */
 | 
						||
 | 
						||
		t_move(y, xpos);	/* Now ensure in right place */
 | 
						||
		t_inschr(i, cp);	/* and insert string onto screen! */
 | 
						||
 | 
						||
		cp += i;		/* Update source ptr */
 | 
						||
		cp++;			/* Point to next char */
 | 
						||
		i += xpos;
 | 
						||
		continue;		/* Now continue loop! */
 | 
						||
 | 
						||
	puntx:	i = xpos;
 | 
						||
		c = savc;
 | 
						||
		cp = savcp;
 | 
						||
		if(cmpcost) { cmpcost = 0; goto dodel;}
 | 
						||
		goto putin;
 | 
						||
	  }
 | 
						||
 | 
						||
	/* All done putting up new stuff.  Now see if any remaining old
 | 
						||
	** stuff needs to be cleared from end of line.
 | 
						||
	*/
 | 
						||
idone:	if(i < ocol)		/* if still have text to right, */
 | 
						||
	  {	t_move(y,i);	/* move there */
 | 
						||
		t_docleol();	/* and clear old stuff. */
 | 
						||
	  }
 | 
						||
 | 
						||
done:	s->sl_line = s->sl_nlin;	/* Replace old image by new */
 | 
						||
	s->sl_col = s->sl_ncol;
 | 
						||
	s->sl_nlin = sci;
 | 
						||
	s->sl_flg &= ~SL_MOD;
 | 
						||
#if FX_SOWIND			/* Copy standout mode to current */
 | 
						||
	if(newso) s->sl_flg |= SL_CSO;
 | 
						||
	else s->sl_flg &= ~SL_CSO;
 | 
						||
#endif
 | 
						||
}
 | 
						||
 | 
						||
#if FX_SOWIND
 | 
						||
fillset(str,cnt,c)
 | 
						||
char *str;
 | 
						||
int cnt;
 | 
						||
int c;
 | 
						||
{	register int n;
 | 
						||
	register char *cp;
 | 
						||
	if((n = cnt) <= 0) return;
 | 
						||
	cp = str;
 | 
						||
	do{ *cp++ = c;
 | 
						||
	  } while(--n);
 | 
						||
}
 | 
						||
#endif
 | 
						||
 | 
						||
fillsp(str,cnt)
 | 
						||
char *str;
 | 
						||
int cnt;
 | 
						||
{	register int n;
 | 
						||
	register char *cp;
 | 
						||
	if((n = cnt) <= 0) return;
 | 
						||
	cp = str;
 | 
						||
	do{ *cp++ = SP;
 | 
						||
	  } while(--n);
 | 
						||
}
 | 
						||
inspc(cp0, cpl, cnt)
 | 
						||
char *cp0, *cpl;
 | 
						||
int cnt;
 | 
						||
{	register char *cp, *cp2;
 | 
						||
	register n;
 | 
						||
	if((n = cnt) <= 0) return;
 | 
						||
	cp = cpl;		/* ptr to last+1 char in string */
 | 
						||
	cp2 = cp+n;		/* ptr to loc+1 to move to */
 | 
						||
	n = cp - cp0;		/* # chars to move */
 | 
						||
	do *--cp2 = *--cp;
 | 
						||
	while(--n);
 | 
						||
	n = cnt;		/* Now fill gap with spaces */
 | 
						||
	do *cp++ = SP;
 | 
						||
	while(--n);
 | 
						||
}
 | 
						||
 | 
						||
/* FIX_LINE - Fixes up new screen image for a single line.  Does not
 | 
						||
 *	do any actual terminal I/O, and does not change the old screen
 | 
						||
 *	image.  Assumes that previous line (if any is furnished) has
 | 
						||
 *	already been properly set up.
 | 
						||
 */
 | 
						||
 | 
						||
int sctreol = 0;	/* Ugly crock for talking to sctrin() */
 | 
						||
			/* 0 = no EOL seen, 1 = EOL seen, -1 = EOF seen */
 | 
						||
fix_line(slp, olds)
 | 
						||
struct scr_line *slp;
 | 
						||
struct scr_line *olds;
 | 
						||
{	register struct scr_line *s;
 | 
						||
	register int col, scrw;
 | 
						||
	char *cp;
 | 
						||
	int ch;
 | 
						||
 | 
						||
	col = 0;
 | 
						||
	scrw = scr_wid;
 | 
						||
	cp = slp->sl_nlin;
 | 
						||
	if((s = olds) && (col = s->sl_cont))
 | 
						||
	  {	if(--col)
 | 
						||
			strncpy(cp, (s->sl_flg&SL_MOD) ?
 | 
						||
					&s->sl_nlin[scrw]
 | 
						||
					 : &s->sl_line[scrw], col);
 | 
						||
		cp += col;
 | 
						||
	  }
 | 
						||
	scrw--;			/* Note now using scr_wd0 !! */
 | 
						||
	s = slp;
 | 
						||
	s->sl_boff = e_dot();
 | 
						||
	col = sctrin(cp, scrw, col);
 | 
						||
	if (col < scrw || sctreol)	/* Does line need continuation mark? */
 | 
						||
		s->sl_cont = 0;		/* No, say no cont chars */
 | 
						||
	else {
 | 
						||
		/* Yes, find # cols of overflow.  If not 0, must be > 0 */
 | 
						||
		/* and char is a biggie.  Make room for continuation chars */
 | 
						||
		if(col -= scrw)
 | 
						||
			inspc(&s->sl_nlin[scrw],&s->sl_nlin[scrw+col], 1);
 | 
						||
		s->sl_cont = col+1;		/* # cont chars, plus 1 */
 | 
						||
		s->sl_nlin[scrw] = CI_CLINE;	/* Display "contin" mark */
 | 
						||
		col = scrw+1;
 | 
						||
	  }
 | 
						||
 | 
						||
	s->sl_ncol = col;
 | 
						||
	s->sl_len = e_dot() - s->sl_boff;
 | 
						||
	s->sl_flg |= (SL_MOD|SL_EOL);	/* Say new, and assume line has EOL */
 | 
						||
	if(sctreol <= 0)		/* unless it doesn't really */
 | 
						||
		s->sl_flg &= ~SL_EOL;	/* in which case turn off flag */
 | 
						||
	return;
 | 
						||
}
 | 
						||
 | 
						||
/* SCTRIN - auxiliary for FIX_LINE.
 | 
						||
 *	lim - # cols chars are allowed to use
 | 
						||
 *	ccol - current column (0 = bol)
 | 
						||
 * Returns when see EOL or EOF, or
 | 
						||
 *	when all columns have been filled up.  Retval-ccol = # overflow.
 | 
						||
 *	Note that any overflow is indivisible (i.e. a char with a
 | 
						||
 *	multi-col representation is responsible for the overflow).
 | 
						||
 *	So, overflow = 0 means next char would be in 1st non-ex column
 | 
						||
 *	and overflow > 0 means last char read has extra columns, but
 | 
						||
 *	it did start within bounds.
 | 
						||
 */
 | 
						||
sctrin(to, lim, ccol)
 | 
						||
char *to;
 | 
						||
int lim;
 | 
						||
int ccol;
 | 
						||
{	register SBBUF *sb;
 | 
						||
	register col, cnt;
 | 
						||
 | 
						||
	sb = (SBBUF *) cur_buf;
 | 
						||
	col = ccol;
 | 
						||
	sctreol = 0;		/* No EOL or EOF seen */
 | 
						||
	do
 | 
						||
	  {	cnt = sb_getc(sb);
 | 
						||
		if(cnt == EOF)
 | 
						||
		  {	--sctreol;	/* Say EOF seen! */
 | 
						||
			return(col);
 | 
						||
		  }
 | 
						||
#if FX_EOLMODE
 | 
						||
		if(cnt == CR)		/* Possible EOL? */
 | 
						||
		  {	if(eolcrlf(sb))
 | 
						||
			  {	if((cnt = sb_getc(sb)) == LF)	/* Real EOL? */
 | 
						||
				  {	sctreol++;
 | 
						||
					return col;	/* Yes, return */
 | 
						||
				  }
 | 
						||
				/* Stray CR, back up & fall thru */
 | 
						||
				if(cnt != EOF)
 | 
						||
					sb_backc(sb);
 | 
						||
				cnt = CR;	/* Show stray CR */
 | 
						||
			  }
 | 
						||
		  } else if (cnt == LF)
 | 
						||
		  {	if(!eolcrlf(sb))	/* Real EOL? */
 | 
						||
			  {	sctreol++;
 | 
						||
				return col;	/* Yes, return */
 | 
						||
			  }
 | 
						||
			/* If EOL mode is CRLF then hitting a LF
 | 
						||
			** can only happen for stray LFs (the
 | 
						||
			** previous check for CR takes care of
 | 
						||
			** CRLFs, and we never start scanning
 | 
						||
			** from the middle of a CRLF.
 | 
						||
			** Drop thru to show stray LF.
 | 
						||
			*/
 | 
						||
		  }
 | 
						||
#else
 | 
						||
		if(cnt == LF)
 | 
						||
		  {	sctreol++;	/* Say EOL seen */
 | 
						||
			return col;
 | 
						||
		  }
 | 
						||
#endif /*_FX_EOLMODE*/
 | 
						||
		cnt = sctr(cnt, to, col);
 | 
						||
		to += cnt;
 | 
						||
		col += cnt;
 | 
						||
	  } while(col < lim);
 | 
						||
 | 
						||
	/* If we're stopping because last char put us precisely at the
 | 
						||
	** end of the line, make a further check to see whether an EOL
 | 
						||
	** is next.  If so, we can include that in the line since it
 | 
						||
	** doesn't need any more columns for representation!
 | 
						||
	*/
 | 
						||
	if (col == lim)		/* If stopping exactly at edge of screen */
 | 
						||
	    switch (sb_getc(sb))	/* Check out next char */
 | 
						||
	      {	case EOF:
 | 
						||
			--sctreol;		/* Yes, note EOF seen */
 | 
						||
			break;			/* and can return immed */
 | 
						||
#if FX_EOLMODE
 | 
						||
		case CR:		/* Possible EOL? */
 | 
						||
			if(eolcrlf(sb))
 | 
						||
			  {	if((cnt = sb_getc(sb)) == LF)	/* Real EOL? */
 | 
						||
				  {	sctreol++;	/* Yes, set flag */
 | 
						||
					break;		/* and return */
 | 
						||
				  }
 | 
						||
				/* Stray CR, back up & fall thru */
 | 
						||
				if(cnt != EOF)		/* Back up char that */
 | 
						||
					sb_backc(sb);	/* came after the CR */
 | 
						||
				sb_rgetc(sb);		/* Then back over CR */
 | 
						||
				break;
 | 
						||
			  }
 | 
						||
			sb_backc(sb);
 | 
						||
			break;
 | 
						||
		case LF:
 | 
						||
			if(!eolcrlf(sb))	/* Real EOL? */
 | 
						||
			  {	sctreol++;	/* Yes, set flag */
 | 
						||
				break;		/* and return */
 | 
						||
			  }
 | 
						||
			/* If EOL mode is CRLF then hitting a LF
 | 
						||
			** can only happen for stray LFs (the
 | 
						||
			** previous check for CR takes care of
 | 
						||
			** CRLFs, and we never start scanning
 | 
						||
			** from the middle of a CRLF.
 | 
						||
			** Drop thru into default to back up over LF.
 | 
						||
			*/
 | 
						||
#else
 | 
						||
		case LF:
 | 
						||
			sctreol++;	/* Say EOL seen */
 | 
						||
			break;		/* and return */
 | 
						||
#endif /*-FX_EOLMODE*/
 | 
						||
		default:
 | 
						||
			sb_backc(sb);		/* Back up over random char */
 | 
						||
			break;
 | 
						||
	    }
 | 
						||
	return(col);
 | 
						||
}
 | 
						||
 | 
						||
/* SCTR - Screen Char TRanslation routine.
 | 
						||
**	This routine is completely responsible for the way a buffer char is
 | 
						||
** displayed on the screen.  Given a char and the current column position,
 | 
						||
** it stores the representation using the given pointer and returns
 | 
						||
** the number of chars (columns) used by the representation.
 | 
						||
**	Normal printing chars (plus space) are simply themselves.
 | 
						||
**	TAB is a variable number of spaces depending on the column pos.
 | 
						||
**		(we use standard tabstops of 8)
 | 
						||
**	All control chars are uparrow followed by a printing char.
 | 
						||
**		e.g. ctrl-A = ^A
 | 
						||
**		This includes ESC which is ^[.
 | 
						||
**		DEL is shown as ^?.
 | 
						||
**	Chars with the 8th bit set have the prefix CI_META (currently ~) and
 | 
						||
**		the rest of the representation is as above (except for TAB).
 | 
						||
**	Chars with the 9th bit set have the prefix CI_TOP (currently |) and
 | 
						||
**		the rest of the representation is as above (except for TAB).
 | 
						||
**		This only exists for systems with 9-bit chars such as TOPS-20.
 | 
						||
*/
 | 
						||
 | 
						||
static int
 | 
						||
sctr(ch, to, ccol)
 | 
						||
int ch;			/* Buffer char to translate */
 | 
						||
char *to;		/* Place to deposit translation in */
 | 
						||
int ccol;		/* Current column position */
 | 
						||
{	register char *cp;
 | 
						||
	register c, n;
 | 
						||
 | 
						||
	c = ch;
 | 
						||
	if(037 < c && c < 0177)	/* Most common case */
 | 
						||
	  {	*to = c;
 | 
						||
		return(1);
 | 
						||
	  }
 | 
						||
	cp = to;
 | 
						||
	if(c == TAB)			/* Next most common case */
 | 
						||
	  {	n = 010 - (ccol&07);	/* Tab stops are every 8 cols */
 | 
						||
		ccol = n;		/* Save value */
 | 
						||
		do *cp++ = SP;
 | 
						||
		while (--n);
 | 
						||
		return(ccol);
 | 
						||
	  }
 | 
						||
	ccol = 1;			/* Re-use var */
 | 
						||
#if TOPS20
 | 
						||
	if(c&0400)			/* 9th bit set? */
 | 
						||
	  {	*cp++ = CI_TOP;
 | 
						||
		ccol++;
 | 
						||
	  }
 | 
						||
#endif /*TOPS20*/
 | 
						||
	if(c&0200)
 | 
						||
	  {	*cp++ = CI_META;
 | 
						||
		ccol++;
 | 
						||
	  }
 | 
						||
	if((c &= 0177) <= 037 || c == 0177)
 | 
						||
	  {	*cp++ = CI_CNTRL;
 | 
						||
		c ^= 0100;		/* Transform cntrl char */
 | 
						||
		ccol++;
 | 
						||
	  }
 | 
						||
	*cp = c;
 | 
						||
	return(ccol);
 | 
						||
}
 | 
						||
 | 
						||
/* INSLIN(line, N, wind) - Insert lines
 | 
						||
 * DELLIN(line, N, wind) - Delete lines
 | 
						||
 *	Both routines insert/delete N lines at "line" in window "wind"
 | 
						||
 *	and update the screen image accordingly.
 | 
						||
 */
 | 
						||
 | 
						||
inslin (line, n, win)
 | 
						||
int   line;			       /* line number to insert BEFORE */
 | 
						||
int   n;			       /* number of lines to insert */
 | 
						||
struct window *win;		       /* window we are in */
 | 
						||
{	register int  i;
 | 
						||
	register int bot;
 | 
						||
	register char **savp;
 | 
						||
	char *savscr[MAXHT];
 | 
						||
 | 
						||
	bot = win -> w_ht + win -> w_pos;
 | 
						||
	t_curpos (line, 0);
 | 
						||
	t_inslin (n, bot);		/* do the insertion on the screen */
 | 
						||
	savp = &savscr[0];
 | 
						||
	for (i = 1; i <= n; i++)	/* free lines that fall off-screen */
 | 
						||
		*savp++ = scr[bot - i]->sl_line;
 | 
						||
 | 
						||
	for (i = bot - 1; i >= line + n; i--)		/* move down lines */
 | 
						||
	  {	scr[i]->sl_line = scr[i - n]->sl_line;	/* below the insertion */
 | 
						||
		scr[i]->sl_col = scr[i - n]->sl_col;
 | 
						||
	  }
 | 
						||
	savp = &savscr[0];
 | 
						||
	for (i = line + n - 1; i >= line; i--)
 | 
						||
				       /* blank lines where inserted */
 | 
						||
	  {	scr[i]->sl_line = *savp++;
 | 
						||
		scr[i]->sl_col = 0;
 | 
						||
	  }
 | 
						||
	for(i = line; i < bot; ++i)
 | 
						||
		scr[i]->sl_flg |= SL_MOD;
 | 
						||
}
 | 
						||
 | 
						||
dellin (line, n, win)
 | 
						||
int   line;			       /* first line to be deleted */
 | 
						||
int   n;			       /* number of lines to be deleted */
 | 
						||
struct window *win;		       /* window we are in */
 | 
						||
{	register int  i;
 | 
						||
	register int bot;
 | 
						||
	register char **savp;
 | 
						||
	char *savscr[MAXHT];
 | 
						||
 | 
						||
	bot = win -> w_ht + win -> w_pos;
 | 
						||
 | 
						||
	t_curpos (line, 0);
 | 
						||
	t_dellin (n, bot);	       /* do the deletion on the screen */
 | 
						||
	savp = &savscr[0];
 | 
						||
	for (i = line; i < line + n; i++)    /* free the deleted lines */
 | 
						||
		*savp++ = scr[i]->sl_line;
 | 
						||
	for (i = line; i < bot - n; i++)	/* move lines up to fill */
 | 
						||
	  {	scr[i]->sl_line = scr[i + n]->sl_line;	/* deleted spaces */
 | 
						||
		scr[i]->sl_col = scr[i + n]->sl_col;
 | 
						||
	  }
 | 
						||
 | 
						||
	savp = &savscr[0];
 | 
						||
	for (i = bot - n; i < bot; i++)      /* blank lines at bottom */
 | 
						||
	  {	scr[i]->sl_line = *savp++;
 | 
						||
		scr[i]->sl_col = 0;
 | 
						||
	  }
 | 
						||
	for(i = line; i < bot; ++i)
 | 
						||
		scr[i]->sl_flg |= SL_MOD;
 | 
						||
}
 | 
						||
 | 
						||
/* T_ Terminal functions - these are similar to the terminal-dependent
 | 
						||
 *	routines in EETERM (which they call) but rely on some knowledge of
 | 
						||
 *	the screen image in order to do their job cleverly.
 | 
						||
 */
 | 
						||
 | 
						||
#if FX_SOWIND
 | 
						||
 | 
						||
/* T_DOSTANDOUT(on) - Turn standout mode on or off, cleverly.
 | 
						||
**	Returns previous state.
 | 
						||
*/
 | 
						||
static int curso = 0;		/* Current state (initially off) */
 | 
						||
int
 | 
						||
t_dostandout(on)
 | 
						||
int on;
 | 
						||
{
 | 
						||
	int oldso;
 | 
						||
 | 
						||
	if ((oldso = curso) != on)	/* If desired state doesn't match, */
 | 
						||
	  {	t_standout(on);		/* invoke new state. */
 | 
						||
		curso = on;
 | 
						||
	  }
 | 
						||
	return oldso;
 | 
						||
}
 | 
						||
#endif
 | 
						||
 | 
						||
 | 
						||
t_move(y,x)
 | 
						||
register int y,x;
 | 
						||
{	register int d;
 | 
						||
 | 
						||
	if(y != curs_lin)		/* No vertical smarts yet */
 | 
						||
	  {	t_curpos(y, x);
 | 
						||
		return;
 | 
						||
	  }
 | 
						||
	if((d = (x - curs_col)) >= 0)	/* Find diff in column position */
 | 
						||
	  {	if(d == 0) return;	/* If none, nothing to do! */
 | 
						||
 | 
						||
		/* Moving right.  If distance is less than abs-move cost,
 | 
						||
		 * do clever right-move by copying screen image */
 | 
						||
		if(d < tvc_pos)
 | 
						||
#if FX_SOWIND	/* Ensure not in standout mode */
 | 
						||
			if((scr[y]->sl_flg&(SL_CSO|SL_NSO))==0)
 | 
						||
#endif
 | 
						||
		  {
 | 
						||
			tputn(&scr[y]->sl_line[curs_col], d);
 | 
						||
			curs_col = x;
 | 
						||
			return;
 | 
						||
		  }
 | 
						||
	  }
 | 
						||
	/* Moving to left, try to do clever left-move by backspacing
 | 
						||
	 * instead of using abs move.
 | 
						||
	 */
 | 
						||
	else if((d = -d)*tvc_bs < tvc_pos)
 | 
						||
	  {	do { t_backspace();
 | 
						||
		  } while(--d);
 | 
						||
		return;
 | 
						||
	  }
 | 
						||
	/* No luck with cleverness, just move. */
 | 
						||
	t_curpos(y, x);
 | 
						||
}
 | 
						||
 | 
						||
t_docleol()
 | 
						||
{	register struct scr_line *s;
 | 
						||
	register int cnt, ocol;
 | 
						||
 | 
						||
	if(trm_flags&TF_CLEOL) t_cleol();	/* Winning */
 | 
						||
	else		/* Losing */
 | 
						||
	  {	s = scr[curs_lin];
 | 
						||
		if((cnt = s->sl_col - curs_col) > 0)
 | 
						||
		  {
 | 
						||
#if FX_SOWIND
 | 
						||
			int oldso = t_dostandout(0);
 | 
						||
#endif
 | 
						||
			ocol = curs_col;
 | 
						||
			do { tput(SP); curs_col++;
 | 
						||
			  } while(--cnt);
 | 
						||
#if FX_SOWIND
 | 
						||
			t_dostandout(oldso);
 | 
						||
#endif
 | 
						||
			t_move(curs_lin, ocol);
 | 
						||
		  }
 | 
						||
	  }
 | 
						||
}
 | 
						||
 |