1715 lines
		
	
	
		
			51 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1715 lines
		
	
	
		
			51 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* 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 */
 | ||
| 
 | ||
| void 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.
 | ||
|  */
 | ||
| void 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, 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
 | ||
| void 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
 | ||
| 
 | ||
| void 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);
 | ||
| }
 | ||
| 
 | ||
| void 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 */
 | ||
| void fix_line(slp, olds)
 | ||
| struct scr_line *slp;
 | ||
| struct scr_line *olds;
 | ||
| {	register struct scr_line *s;
 | ||
| 	register int col, scrw;
 | ||
| 	char *cp;
 | ||
| 
 | ||
| 	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
 | ||
| 
 | ||
| 
 | ||
| void 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);
 | ||
| 		  }
 | ||
| 	  }
 | ||
| }
 | ||
| 
 | 
