[mod.sources] v09i031: A TECO text editor, Part04/04

sources-request@mirror.UUCP (03/13/87)

Submitted by: genrad!mlf
Mod.sources: Volume 9, Issue 31
Archive-name: teco/Part04

#! /bin/sh
# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
# If this archive is complete, you will see the message:
#		"End of archive 4 (of 4)."
# Contents:  te_window.c
# Wrapped by rs@mirror on Thu Mar 12 19:54:35 1987
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo shar: Extracting \"te_window.c\" \(33018 characters\)
if test -f te_window.c ; then 
  echo shar: Will not over-write existing file \"te_window.c\"
else
sed "s/^X//" >te_window.c <<'END_OF_te_window.c'
X/* TECO for Ultrix   Copyright 1986 Matt Fichtenbaum						*/
X/* This program and its components belong to GenRad Inc, Concord MA 01742	*/
X/* They may be copied if this copyright notice is included					*/
X
X/* te_window.c   window for teco   10/10/86 */
X/* This attempts to be a real window, without unecessary redraw */
X/* it is very VT-100 specific, and ought to be rewritten to be general */
X
X#include "te_defs.h"
X
X/* maximum screen height and width (horiz and vert, not height and vidth) */
X#define W_MAX_V 70
X#define W_MAX_H 150
X#define MAX 0x7fffffff			/* maximum positive integer, for "last modified" location */
X#define W_MARK 0200				/* "this loc is special" in screen image */
X
X
X/* image of current window */
X
Xstruct w_line			/* data associated with one screen line */
X	{
X	int start, end;				/* dot at beginning, at end */
X	short n, cflag, col;		/* number of char positions used, line continuation flag, starting col */
X	char ch[W_MAX_H];			/* image of line */
X	}
X	 w_image[W_MAX_V];
X
X
X/* define "this line is continued" / "this line is a continuation" flags */
X#define WF_BEG 1
X#define WF_CONT 2
X
Xstruct w_line *wlp[W_MAX_V];	/* each word points to the corresponding line's data structure */
X
Xstruct qp w_p1;					/* pointer for window access to buffer */
X
Xshort curr_x, curr_y;			/* active character position */
Xshort term_x, term_y;			/* current terminal cursor position */
Xshort curs_x, curs_y;			/* current teco dot screen coordinates */
Xshort last_y;					/* last used line in window */
Xchar curs_c;					/* code for char at cursor */
Xchar *curs_p;					/* pointer to cursor loc in window image */
Xshort curs_crflag;				/* flag that cursor is on a CR */
Xshort redraw_sw;				/* forces absolute redraw */
X
X
X/* fill characters and terminal speeds: 0th entry used when std out is not a terminal */
Xchar win_speeds[] = { 0, 0, B9600, B4800, B2400, B1800, B1200, B600, B300, B200, B150, B134, B110 };
Xchar win_dlye[] =   { 0, 90, 45, 23, 11, 9, 6, 3, 1, 1, 1, 1, 1 };	/* delay for erase-screen */
Xchar win_dlys[] =   { 0, 60, 30, 15, 7, 6, 4, 2, 1, 1, 0, 0, 0 };	/* delay for scroll ops */
Xchar win_dlyl[] =   { 0, 4, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 };		/* delay for erase line */
Xchar win_dlyc[] =   { 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };		/* delay for other control functions */
Xshort win_speed;
X/* routine to perform simple scope operations */
X/* (an attempt to concentrate VT-100 specific things in one place) */
X
Xvt(func)
X	int func;
X	{
X	short t;
X	switch (func)
X		{
X		case VT_CLEAR:			/* clear screen */
X			fputs("\033[H\033[J", stdout);
X			for (t = 0; t < win_dlye[win_speed]; t++) putchar('\0');	/* fill chars */
X			break;
X
X		case VT_EEOL:			/* erase to end of line */
X			fputs("\033[K", stdout);
X			for (t = 0; t < win_dlyl[win_speed]; t++) putchar('\0');	/* fill chars */
X			break;
X
X		case VT_EBOL:			/* erase from beginning of line */
X			fputs("\033[1K", stdout);
X			for (t = 0; t < win_dlyl[win_speed]; t++) putchar('\0');	/* fill chars */
X			break;
X
X		case VT_SETSPEC1:		/* reverse video */
X			fputs("\033[7m", stdout);
X			break;
X
X		case VT_SETSPEC2:		/* bright reverse video */
X			fputs("\033[1;7m", stdout);
X			break;
X
X		case VT_CLRSPEC:		/* normal video */
X			fputs("\033[0m", stdout);
X			break;
X
X		case VT_BS1:			/* backspace 1 spot */
X			fputs("\b \b", stdout);
X			break;
X
X		case VT_BS2:			/* backspace 2 spots */
X			fputs("\b \b\b \b", stdout);
X			break;
X
X		case VT_LINEUP:			/* up one line */
X			fputs("\033[1A", stdout);
X			break;
X		}
X	}
X/* routine to set window parameters */
X
X/* 0: scope type, 1: width, 2: height, 3: seeall, 4: mark position,		*/
X/* 5: hold mode, 6: upper left corner position, 7: scroll region size	*/
X
X/*				   0   1		2		 3  4	  5   6	   7	*/
Xint win_min[]  = { 4,  20,		4,		 0, 0,	 -1,  1,   0 } ;	/* min values for window parameters */
Xint win_max[]  = { 4,  W_MAX_H,	W_MAX_V, 1, MAX, 12, -1,  20 } ;	/* max values */
Xint win_data[] = { 4,  132,		24,		 0, 0,	  0,  0,   0 } ;	/* window parameters	*/
X
Xint window_size;								/* # of lines in a window */
X
Xdo_window(ref_flag)
X	int ref_flag;					/* nonzero forces "refresh" operation */
X	{
X	int i;
X
X	if (colonflag && !ref_flag)
X		{
X		i = get_value(0);	/* get sub-function */
X		if ((i < 0) || (i > 7)) ERROR(E_IWA);
X		if (!esp->flag2)	/* it's a "get" */
X			{
X			esp->val1 = win_data[i];
X			esp->flag1 = 1;
X			}
X		else
X			{
X			if ((esp->val2 < win_min[i]) || (esp->val2 > win_max[i]))	/* check range */
X				ERROR(E_IWA);
X			if (i == 7)
X				{
X				if (esp->val2)
X					{
X					WN_scroll = esp->val2;
X					window_size = WN_height - WN_scroll;	/* define size of window area */
X					window(WIN_INIT);			/* turn on window */
X					}
X				else window(WIN_OFF);			/* turn off window */
X				}
X			win_data[i] = esp->val2;			/* redundant for ~0,7:w, but no harm */
X			esp->flag2 = 0;
X			window(WIN_REDRAW);					/* redraw window */
X			}
X		}
X
X	else								/* no colon, or ^W command */
X		{
X		if (esp->flag1 || ref_flag)
X			{
X			if (!ref_flag && (esp->val1 == -1000)) redraw_sw = 0;	/* -1000W: "forget that output was done" */
X			else window(WIN_DISP);		/* nW or ^W refreshes window */
X			}
X		 esp->flag2 = esp->flag1 = 0;		/* no colon, consume args */
X		}
X	colonflag = 0;
X	esp->op = OP_START;
X	}
X/* routine to update screen size with numbers obtained from environment	*/
X/* (called by main program's initialization)							*/
X
Xset_term_par(lines, cols)
X	int lines, cols;
X	{
X	if ((lines >= win_min[2]) && (lines <= win_max[2])) window_size = win_data[2] = lines;
X	if ((cols >= win_min[1]) && (cols <= win_max[1])) win_data[1] = cols;
X	}
X
X
X/* window routine.  performs function as indicated by argument						*/
X/* WIN_OFF:		disables split-screen scrolling										*/
X/* WIN_SUSP:	disables split-screen scrolling temporarily							*/
X/* WIN_INIT:	sets up display support if split-screen scrolling enabled, else nop	*/
X/* WIN_RESUME:	re-enables display support											*/
X/* WIN_REDRAW:	causes window to be redrawn on next refresh call					*/
X/* WIN_REFR:	if scrolling enabled, redoes window, else if ev or es enabled, does	*/
X/*				that, else nop														*/
X/* WIN_LINE:	does WIN_REFR unless that wouldn't do anything, in which case		*/
X/*				it does effective 1EV output										*/
X
Xint last_dot = -1;				/* last dot location */
X
Xwindow(arg)
X	int arg;
X	{
X	int i;
X
X	switch (arg)
X		{
X		case WIN_OFF:				/* final window off */
X		case WIN_SUSP:				/* temp window off */
X			if (WN_scroll)			/* if reset/clean up */
X				{
X				/* full margins, cursor to last line, erase line */
X				printf("\033[r\033[%d;0H\033[K", WN_height);
X				}
X			break;
X
X		case WIN_INIT:				/* initialize window - find output speed */
X			if (out_noterm) win_speed = 0;		/* std out is not a terminal */
X			else
X				{
X				for (win_speed = 1; (win_speeds[win_speed] != ttybuf.sg_ospeed) && (win_speed < 13); win_speed++);
X				if (win_speed == 13) win_speed = 1;
X				}
X			w_init();				/* set up screen image buffer */
X			if (WN_scroll) vt(VT_CLEAR);		/* if split-screen is enabled, clear screen */
X									/* (fall through to "resume") */
X
X		case WIN_RESUME:			/* re-enable window */
X			if (WN_scroll)			/* set scroll region, cursor to bottom */
X				printf("\033[%d;%dr\033[%d;0H", WN_height - WN_scroll + 1, WN_height, WN_height);
X			break;
X		case WIN_REDRAW:		/* force redraw of window */
X			redraw_sw = 1;
X			break;
X
X		case WIN_LINE:			/* display one line unless window enabled or ev */
X			if (WN_scroll || ev_val) window(WIN_REFR);		/* if a real window is set, do it */
X			else if (w_setptr(dot, &w_p1))		/* set pointer to dot... and if there's a buffer */
X				{
X				w_lines(0, &w_p1, &w_p1);		/* get to beginning of line */
X				window0(1);						/* and type 1 line */
X				}
X			break;
X
X		case WIN_REFR:			/* if enabled, refresh window; else do ev or es */
X			if (WN_scroll) window1();		/* if scrolling enabled, refresh the window */
X			else if ((ev_val) || (es_val && search_flag))	/* else if ev or es, do that */
X				{
X				i = (ev_val) ? ev_val : es_val;
X				if (w_setptr(dot, &w_p1))		/* set a pointer at dot... and if there's a buffer */
X					window0(i - w_lines(1 - i, &w_p1, &w_p1));	/* go back (i-1) lines and ahead (i) lines */
X				}
X			break;
X
X		case WIN_DISP:					/* display buffer independent of whether scroll mode is enabled */
X			window1();
X			break;
X
X		}		/* end of switch */
X
X	fflush(stdout);			/* send output out */
X	}					/* end of window() */
X/* routine to type n lines with character at "dot" in reverse video			*/
X/* used for ev, es, and <BS> or <LF> as immediate commands					*/
X/* starting char position is in w_p1; argument is number of lines			*/
X
Xwindow0(num)
X	int num;
X	{
X	int wi;
X	char wc;			/* temp char */
X
X	for (wi = w_p1.dot; (num > 0) && (wi < z); wi++)		/* for each character */
X		{
X		wc = w_p1.p->ch[w_p1.c];		/* get character */
X
X		if ((char_count >= WN_width) && (wc != CR) && !(spec_chars[wc] & A_L))	/* if about to exceed width */
X			{
X			if (et_val & ET_TRUNC) goto w0_noprint;			/* truncate: don't print this */
X			else
X				{
X				fputs("\033[K\015\012\033(0h\033(B ", stdout);	/* <eeol> "NL space" */
X				char_count = 2;
X				--num;					/* one fewer line remaining */
X				}
X			}
X
X		if (wi == dot)					/* if this char is at the pointer */
X			{
X			vt(VT_SETSPEC2);			/* set reverse video */
X			if (wc == TAB)
X				{
X				type_char(' ');		/* illuminate the first sp of a tab */
X				vt(VT_CLRSPEC);		/* clear reverse video */
X				if (char_count & tabmask) type_char(TAB);
X				}
X			else						/* not a tab */
X				{
X				if ((wc == CR) && (char_count < WN_width))	/* CR at rh margin: don't display cursor */
X					{
X					type_char(' ');		/* cr: put a space after line */
X					vt(VT_EEOL);		/* erase to eol */
X					}
X				type_char(wc);			/* type the char, or exec CR */
X				if (wc == LF)
X					{
X					fputs("\033(0", stdout);
X					type_char('e');
X					fputs("\033(B", stdout);
X					}
X				vt(VT_CLRSPEC);		/* clear reverse video */
X				}
X			}
X		else					/* this is not char at pointer */
X			{
X			if (wc == CR && curr_x < WN_width) vt(VT_EEOL);		/* erase to EOL */
X			type_char(wc);
X			}
X		if ((wc == FF) || (wc == VT))		/* FF & VT end a line */
X			{
X			vt(VT_EEOL);			/* erase rest of this line */
X			crlf();					/* and leave a blank one */
X			if (!(ez_val & EZ_NOVTFF)) --num;		/* if FF and VT count as line sep's, count them */
X			}
X
X	  w0_noprint:
X		if (++w_p1.c > CELLSIZE-1) w_p1.p = w_p1.p->f, w_p1.c = 0;	/* next char */
X		if (wc == LF) --num;	/* if this is a line feed, count lines */
X		}
X
X	if (dot == z) fputs("\033[1;7m \033[0m\033[0K", stdout);	/* type one space and erase rest of line */
X	else fputs("\033[0K", stdout);			/* else just erase to EOL */
X	}
X/* routine to maintain the screen window										*/
X/* if scroll mode is enabled, the VT100 screen is split and only the upper part */
X/* is used by this routine; else the whole screen is used.						*/
X
Xwindow1()
X	{
X	int i, j, m, lflag;
X
X	if (!redraw_sw && (dot == last_dot) && (buff_mod == MAX)) return;		/* return if nothing has changed */
X
X	block_inter(1);							/* disable ^C interrupts */
X	if (WN_scroll) printf("\033[1;%dr", window_size);		/* scroll mode: redefine scroll region */
X	printf("\033[H");						/* home */
X	term_y = term_x = 0;					/* indicate cursor is at home */
X
X	if ((redraw_sw) || (z <= wlp[0]->start)) window1_abs();		/* forced redraw, or z before start of screen */
X
X
X/* check whether pointer is before modified buffer location */
X
X	else if (buff_mod >= dot)	/* yes */
X		{
X
X		if (dot < wlp[0]->start)			/* if dot is before screen */
X			{
X			w_setptr(wlp[0]->start, &w_p1);	/* get to beginning of screen */
X
X		/* check whether screen begins with the last part of a continued line */
X			for (j = 0; (wlp[j]->cflag & WF_CONT) && (j < window_size/2); j++);
X			if (j < window_size/2)			/* if so, does it continue less than halfway down the screen? */
X				{
X
X				if (j)						/* is there a partial line? */
X					{
X					w_lines(0, &w_p1, &w_p1);		/* 0L */
X					j -= w_lines(1, &w_p1, NULL);		/* now j is number of display lines before screen */
X					}
X		/* now look for how many lines back "dot" is: if screen starts with partial line, w_p1 has already been moved */
X		/* to beginning of the line and j equals the count of extra lines to scroll */
X
X				for (i = 0; (dot < w_p1.dot) && (i < window_size/2); ) i -= w_lines(-1, &w_p1, &w_p1);
X				if ((dot >= w_p1.dot) && (i < window_size))			/* found point within reason */
X					{
X					w_scroll(j - i);			/* scroll screen down that many lines */
X					curr_y = wlp[0]->cflag = wlp[0]->col = curr_x = 0;		/* start from top of screen */
X					wlp[0]->start = w_p1.dot;	/* save starting char position */
X					window2(0);					/* and rewrite screen */
X					}
X
X				else window1_abs();				/* farther back than that - redraw */
X				}
X
X			else window1_abs();					/* continuation was too long: give up and redraw */
X			}				/* end of "dot is before screen" */
X
X		else if (dot <= wlp[last_y]->end) window1_inc(dot);		/* on screen - redraw incrementally */
X
X		else window1_after();				/* dot is after screen: scroll or redraw */
X		}				/* end of "dot is before modified point" */
X
X
X/* the modified point in the buffer is before dot */
X
X	else
X		{
X		if (buff_mod < wlp[0]->start) window1_abs();	/* modified point before screen - redraw fully */
X
X		else if (buff_mod <= wlp[last_y]->end)			/* modified point on screen */
X			{
X			for (m = 0; buff_mod > wlp[m]->end; m++);	/* find line with buff_mod */
X			w_setptr(wlp[m]->start, &w_p1);				/* set a pointer to start of line with buff_mod */
X			j = (m < window_size/2) ? window_size - 1 - m : window_size/2;	/* maximum # of lines between buff_mod & dot */
X			for (i = 0; (dot >= w_p1.dot) && (w_p1.dot < z) && (i <= j); )
X				i += (lflag = w_lines(1, &w_p1, &w_p1) ) ? lflag : 1;	/* count lines from buff_mod to first line after dot */
X			if (i > j) window1_abs();					/* too far - redraw */
X			else
X				{
X				if (lflag && (dot == z)) i++;			/* if at end, following a LF */
X				w_setptr(wlp[m]->start, &w_p1);			/* pointer to start of area to redraw */
X				if (i >= window_size - m)				/* if there are not enough blank lines on screen */
X					w_scroll(i = i - window_size + m), curr_y = m - i, curs_y -= i;	/* scroll up the difference */
X				else curr_y = m;
X				curr_x = (wlp[curr_y]->cflag & WF_CONT) ? 2 : wlp[curr_y]->col;		/* line starts at left unless continuation */
X				if ((curr_y > curs_y) && (curs_y >= 0)) w_rmcurs();		/* remove old cursor if it won't be written over */
X				window2(0);							/* rewrite newly cleared region */
X				for (curr_x = 0; ++curr_y < window_size; )		/* clear rest of screen if needed */
X					{
X					wlp[curr_y]->cflag = 0;
X					if (wlp[curr_y]->n) wlp[curr_y]->n = 0, vtm(VT_EEOL);
X					}
X				}
X			}			/* end "modified point on screen */
X
X		else window1_after();		/* modified point after screen: scroll or redraw as appropriate */
X		}
X/* done redrawing: do cleanup work */
X
X	if (WN_scroll)
X		{
X		printf("\033[%d;%dr", window_size+1, WN_height);	/* reset margins */
X		printf("\033[%d;0H", WN_height);		/* cursor to bottom */
X		}
X	else printf("\033[H");		/* no split screen: set home */
X
X	fflush(stdout);				/* flush output */
X	WN_origin = wlp[0]->start;	/* save first char pos on screen */
X	redraw_sw = 0;				/* mark screen as updated */
X	buff_mod = MAX;
X	last_dot = dot;
X	block_inter(0);				/* reenable interrupts */
X	}
X/* routine to redraw screen absolutely */
X
Xwindow1_abs()
X	{
X	int i, j;
X
X	curr_y = wlp[0]->col = curr_x = 0;				/* indicate where refresh starts */
X	set_pointer(dot, &w_p1);						/* make a text buffer, if none, and refresh the display */
X	w_lines(0, &w_p1, &w_p1);						/* do 0L */
X	if ((i = w_lines(window_size/2, &w_p1, NULL)) == 0) i = 1;		/* check how many lines after dot */
X	if (i > window_size/2) i = window_size/2;		/* limit amount after dot */
X	for (j = 0; (j < window_size - i) && (w_p1.dot > 0); )		/* find start of display area */
X		j -= w_lines(-1, &w_p1, &w_p1);
X	if (j > window_size - i) w_lines(1, &w_p1, &w_p1);			/* if too far back, move up one line */
X
X	wlp[0]->start = w_p1.dot;		/* indicate where first window line starts */
X	window2(0);						/* refresh the whole display */
X
X	for (curr_x = 0; ++curr_y < window_size; )		/* blank out lines not written by window2 */
X		if (wlp[curr_y]->n || redraw_sw) wlp[curr_y]->n = 0, vtm(VT_EEOL);
X	}
X
X
X
X
X/* redraw screen incrementally */
X
Xwindow1_inc(wd)
X	int wd;						/* argument is earliest change */
X	{
X	short temp_y;
X
X/* find the line containing the character at wd */
X
X	for (temp_y = 0; wd > wlp[temp_y]->end; temp_y++);
X
X	if ((curs_y != temp_y) || (buff_mod == MAX) || curs_crflag)		/* if the cursor line won't be rewritten */
X		w_rmcurs();					/* remove the old cursor */
X	curr_y = temp_y;				/* and go to work on the beginning of the line with dot */
X	curr_x = (wlp[curr_y]->cflag & WF_CONT) ? 2 : wlp[curr_y]->col;		/* line starts at left unless continuation */
X
X	w_setptr(wlp[curr_y]->start, &w_p1);		/* make a pointer there */
X	window2(buff_mod == MAX);		/* if buffer not modified, redraw only the line with dot */
X
X	if (buff_mod < MAX)			/* if buffer has changed, erase display lines beyond end of buffer */
X		for (curr_x = 0; ++curr_y < window_size; )
X			if ( ((wlp[curr_y]->start >= z) || (wlp[curr_y]->start <= wlp[curr_y-1]->end)) && (wlp[curr_y]->n || redraw_sw) )
X				wlp[curr_y]->n = 0, vtm(VT_EEOL), wlp[curr_y]->cflag = 0;
X	}
X/* routine to move window downwards: scroll up or redraw as appropriate */
X
Xwindow1_after()
X	{
X	int i, lflag;
X
X	w_rmcurs();						/* remove old cursor */
X	w_setptr(wlp[window_size-1]->start, &w_p1);		/* set pointer to start of last line on screen */
X
X	for (i = 0; (dot >= w_p1.dot) && (w_p1.dot < z) && (i <= window_size/2); )
X		i += (lflag = w_lines(1, &w_p1, &w_p1)) ? lflag : 1;	/* fwd one line at a time until > dot or end of buffer */
X
X	if (i <= window_size/2)			/* found within n lines */
X		{
X		if (lflag && (dot == z)) ++i;				/* if dot is at end of buffer after a LF */
X		if (i >= window_size - last_y)				/* if there are not enough blank lines on screen */
X			w_scroll(i - window_size + last_y), curr_y = window_size - i;	/* scroll up the difference */
X		else curr_y = last_y;
X
X		while (curr_y && (wlp[curr_y]->cflag & WF_CONT)) --curr_y;		/* get to start of cont'd lines */
X		w_setptr(wlp[curr_y]->start, &w_p1);		/* pointer to start of area to redraw */
X		curr_x = wlp[curr_y]->col;					/* redraw starts at line's first column */
X		window2(0);									/* rewrite newly cleared region */
X		}
X
X	else window1_abs();						/* move down is too far: redraw fully */
X	}
X
X
X
X/* routine to remove the existing cursor */
X
Xw_rmcurs()
X	{
X	if (curs_c)			/* if there was a cursor */
X		{
X		w_move(curs_y, curs_x);		/* go remove the old cursor */
X		if (curs_c & W_MARK) fputs("\033(0", stdout);		/* if prev char was a spec char */
X		putchar(*curs_p = curs_c);	/* put back the char that was there */
X		if (curs_c & W_MARK) fputs("\033(B", stdout);
X		++term_x;					/* and keep the terminal cursor loc. happy */
X		}
X	}
X/* routine to do actual display refresh												*/
X/* called with w_p1 at starting char, curr_y, curr_x at starting coordinate			*/
X/* rewrites to end of screen if arg = 0, or only until line with cursor if arg = 1	*/
X
Xwindow2(arg)
X	int arg;
X	{
X	register int wdot;
X	register char wc;			/* temp char */
X	register short dflag;		/* nonzero if this is char at dot */
X	short cr_found;				/* indicates a cr found on this line */
X
X	cr_found = 0;				/* clear "cr" flag in first line written */
X	for (wdot = w_p1.dot; (curr_y < window_size) && (wdot < z); wdot++)		/* for each character */
X		{
X		wc = w_p1.p->ch[w_p1.c] & 0177;		/* get character */
X		if (dflag = (wdot == dot)) if (arg) arg = -1;		/* save "this is char at dot", "on line with dot" */
X
X		if (wc < ' ') switch (wc)				/* dispatch control characters */
X			{
X			case CR:
X				if (dflag)			/* if cursor on this CR */
X					{
X					if (curr_x < WN_width) w_makecurs(' ', 1), w_type(' ', 1);	/* display a space, unless at end */
X					else curs_crflag = curs_c = 0;				/* else set "no cursor displayed" */
X					}
X				/* trim remainder of line if this is first cr and old line was longer */
X				if (!cr_found && ((curr_x < wlp[curr_y]->n) || redraw_sw))
X					{
X					wlp[curr_y]->n = curr_x;
X					if (curr_x < WN_width) vtm(VT_EEOL);
X					}
X				cr_found = 1;			/* set cr flag */
X				wlp[curr_y]->cflag &= ~WF_BEG;		/* this line is not continued */
X				while (curr_y && (wlp[curr_y]->cflag & WF_CONT)) --curr_y;		/* if line is a continuation, scan up */
X				curr_x = 0;
X				break;
X
X			case TAB:
X				if (curr_x >= WN_width)
X					{
X					if (et_val & ET_TRUNC) goto noprint;
X					if (w_overflow(wdot)) goto w2_exit;				/* extend line */
X					}
X				if (dflag) w_makecurs(' ', 0);
X				w_type(' ', dflag);						/* type one space */
X				if (dflag)
X					{
X					vt(VT_CLRSPEC);		/* end reverse video */
X					dflag = 0;
X					}
X				while ((curr_x & tabmask) && (curr_x < WN_width)) w_type(' ', 0);		/* finish tab */
X				break;
X			case LF:
X				while ((curr_y < window_size) && (wlp[curr_y]->cflag & WF_BEG)) ++curr_y;	/* last screen row of this line */
X				wlp[curr_y]->end = wdot;		/* save char position that ended this line */
X				if (dflag)		/* if this LF is at dot */
X					{			/* put cursor there, save char that was there */
X					w_makecurs( (curr_x < wlp[curr_y]->n) ? wlp[curr_y]->ch[curr_x] : ' ', 0);
X					fputs("\033(0", stdout);			/* put in a "LF" char */
X					w_type('e', 1);
X					fputs("\033(B", stdout);
X					}			/* if no cr found and not in last column, erase rest of line */
X				if (!cr_found && (curr_x < wlp[curr_y]->n))
X					{
X					wlp[curr_y]->n = curr_x;
X					if (curr_x < WN_width) vtm(VT_EEOL);
X					}
X				if (dflag) --curr_x;			/* put the cursor back before the artificial LF char, if any */
X				if (curr_y >= window_size-1)	/* if at end of screen, exit, but... */
X					{
X					if (dflag) vt(VT_CLRSPEC);	/* if cursor is here, clear reverse video first */
X					goto w2_exit;
X					}
X
X				if ((wlp[curr_y]->cflag & WF_CONT) && (wlp[curr_y]->end - wlp[curr_y]->start == 1))	/* if a now-empty cont. line, */
X					{															/* flush it */
X					if (curr_y > 0) wlp[curr_y-1]->cflag &= ~WF_BEG;			/* remove "cont'd" flag from prev line */
X					arg = 0;													/* and force redraw of rest of screen */
X					if (curs_y == curr_y) curs_c = 0;							/* if cursor was on this line, it will disappear */
X					}
X				else ++curr_y;				/* down one line if not absorbing blank contin. line */
X
X				wlp[curr_y]->start = wdot + 1;				/* assume line starts with next char */
X				wlp[curr_y]->col = curr_x;					/* save starting column */
X				cr_found = wlp[curr_y]->cflag = 0;			/* clear line continuation flags */
X				if (curr_x) w_ebol();						/* if not at left margin, erase beginning of line */
X				if (arg == -1)								/* finished line with dot... quit if spec'd */
X					{
X					if (dflag)						/* but first, if at cursor, clear reverse video */
X						{
X						vt(VT_CLRSPEC);
X						dflag = 0;
X						}
X					return;
X					}
X				break;
X
X			case ESC:
X				if (curr_x >= WN_width)
X					{
X					if (et_val & ET_TRUNC) goto noprint;
X					if (w_overflow(wdot)) goto w2_exit;				/* extend line */
X					}
X				if (dflag) w_makecurs('$', 0);
X				w_type('$', dflag);
X				break;
X			default:					/* all other control chars print as ^X */
X				if (curr_x >= WN_width - 1)
X					{
X					if (et_val & ET_TRUNC) goto noprint;
X					if (w_overflow(wdot)) goto w2_exit;
X					}
X				if (dflag) w_makecurs('^', 0);
X				w_type('^', dflag);				/* ^ */
X				if (dflag)
X					{
X					vt(VT_CLRSPEC);		/* if at cursor, clear reverse video */
X					dflag = 0;
X					}
X				w_type(wc | 0100, 0);
X				break;
X			}					/* end "switch" */
X		else					/* a printing character */
X			{
X			if (curr_x >= WN_width)
X				{
X				if (et_val & ET_TRUNC) goto noprint;
X				if (w_overflow(wdot)) goto w2_exit;				/* extend line */
X				}
X			if (dflag) w_makecurs(wc, 0);
X			w_type(wc, dflag);
X			}
X
X		if (dflag)
X			{
X			vt(VT_CLRSPEC);				/* if at cursor, clear reverse video */
X			}
X
X		if ((wc == FF) || (wc == VT))			/* these chars leave a display line blank */
X			{
X			if (redraw_sw || (curr_x < wlp[curr_y]->n))
X				{
X				wlp[curr_y]->n = curr_x;
X				if (curr_x < WN_width) vtm(VT_EEOL);	/* erase rest of line */
X				}
X			wlp[curr_y]->end = wdot;
X			if (curr_y >= window_size-1) goto w2_exit;	/* quit if overflow screen */
X			wlp[++curr_y]->start = wdot + 1;
X			cr_found = wlp[curr_y]->cflag = 0;		/* init new line */
X			if (curr_x -= 2) w_ebol();		/* back up over ^X; if not at left margin, erase beginning of line */
X			wlp[curr_y]->col = curr_x;				/* save starting column */
X			}
X	  noprint:
X		if (++ w_p1.c > CELLSIZE - 1) w_p1.p = w_p1.p->f, w_p1.c = 0;	/* next char in buffer */
X		}		/* end of "for all characters" */
X
X	if (dot == z)
X		{
X		if (curr_x < WN_width) w_makecurs(' ', 1), w_type(' ', 1), vt(VT_CLRSPEC);	/* display a space, unless at end */
X		else curs_crflag = curs_c = 0;				/* else set "no cursor displayed" */
X		}
X
X	/* clear rest of line if needed */
X	if (!cr_found && (redraw_sw || (curr_x < wlp[curr_y]->n)))
X		{
X		wlp[curr_y]->n = curr_x;
X		if (curr_x < WN_width) vtm(VT_EEOL);
X		}
X	wlp[curr_y]->end = wdot;		/* save char at end of last line */
X  w2_exit:
X	last_y = curr_y;				/* record last used line on screen */
X	}
X/* routine to move cursor to current location and then call vt */
X
Xvtm(arg)
X	int arg;
X	{
X	w_move(curr_y, curr_x);
X	vt(arg);
X	}
X
X
X
X
X/* routine to set reverse video and save cursor location */
X/* first argument is char at cursor, 2nd is value for curs_crflag */
X
Xw_makecurs(wc, crflag)
X	char wc;
X	short crflag;
X	{
X	curs_y = curr_y, curs_x = curr_x, curs_c = wc;	/* save cursor coord and char */
X	curs_p = &wlp[curr_y]->ch[curr_x];				/* save location of cursor spot in window image */
X	curs_crflag = crflag;		/* save crflag */
X	vt(VT_SETSPEC2);			/* set flag and reverse video */
X	}
X
X
X
X
X/* routine to handle line overflow */
X/* returns nonzero if at end of screen, zero otherwise */
X/* arg is current character position */
X
Xint w_overflow(wd)
X	{
X	wlp[curr_y]->end = wd-1;			/* last character was end of this line */
X	if (wlp[curr_y]->n > curr_x)
X		{
X		wlp[curr_y]->n = curr_x;
X		if (curr_x < WN_width) vtm(VT_EEOL);		/* if old line was wider, erase */
X		}
X	if (curr_y >= window_size-1) return(1);
X	wlp[curr_y]->cflag |= WF_BEG;				/* mark this line as "continued" */
X	wlp[++curr_y]->cflag = WF_CONT;				/* next line is a continuation line */
X	wlp[curr_y]->start = wd;					/* char about to be printed is this line's first */
X	wlp[curr_y]->col = curr_x = 0;				/* new line starts at left margin */
X	fputs("\033(0", stdout);					/* alternate char set */
X	w_type('h', W_MARK);						/* "NL" space */
X	w_type(' ', W_MARK);
X	fputs("\033(B", stdout);
X	return(0);
X	}
X/* routine to type one character:  arguments are char and a */
X/* "mark" bit.  If mark is set, the char is always retyped  */
X
Xw_type(c, m)
X	char c;
X	int m;
X	{
X	register char *p;
X
X	p = &wlp[curr_y]->ch[curr_x];		/* pointer to char image */
X	if ((c != *p) || (m) || (redraw_sw) || (curr_x >= wlp[curr_y]->n))
X		{
X		w_move(curr_y, curr_x);
X		putchar(c);
X		*p = (m) ? c | W_MARK : c;
X		++term_x;
X		}
X	++curr_x;
X	if (wlp[curr_y]->n < curr_x) wlp[curr_y]->n = curr_x;	/* if we've lengthened the line, record that fact */
X	}
X
X
X
X
X/* initialize display image */
X
Xw_init()
X	{
X	short i, j;
X
X	for (i = 0; i < window_size; i++)		/* for each row */
X		{
X		wlp[i] = &w_image[i];				/* set pointer to this line's data */
X		w_image[i].n = w_image[i].cflag = 0;	/* no chars used, cr flag clear */
X		for (j = 0; j < W_MAX_H; w_image[i].ch[j++] = ' ');		/* clear line */
X		}
X	}
X
X
X
X
X/* put character followed by appropriate number of nulls for "other control function" */
X/* if argument is 0, output filler chars only */
X
Xputchar_d(c)
X	char c;
X	{
X	int i;
X
X	if (c) putchar(c);												/* output character */
X	for (i = 0; i < win_dlyc[win_speed]; i++) putchar('\0');		/* output filler */
X	}
X/* put out appropriate number of filler chars for display function that scrolls (LF, etc.) */
X
Xscroll_dly()
X	{
X	int i;
X
X	for (i = 0; i < win_dlys[win_speed]; i++) putchar('\0');		/* output filler */
X	}
X
X
X
X/* move terminal cursor to stated y, x position */
X/* uses incremental moves or absolute cursor position, whichever is shorter */
X
Xw_move(y, x)
X	short y, x;
X	{
X	register short i;
X
X	/* if practical, use CR to get to left margin */
X	if ((curr_x == 0) && (term_x != 0)) putchar(CR), term_x = 0;
X	if ((y == term_y) && (term_x < WN_width))		/* if term x is beyond last char, use abs positioning */
X		{
X		if (x == term_x) return;
X		if (x > term_x)
X			{
X			if (x - term_x == 1) fputs("\033[C", stdout);
X			else printf("\033[%dC", x - term_x);
X			}
X		else
X			{
X			if ((i = term_x - x) < 4) for (; i > 0; i--) putchar('\b');	/* use BS */
X			else printf("\033[%dD", term_x - x);		/* use incremental jump */
X			}
X		term_x = x;
X		}
X	else
X		{
X		if ((x == term_x) && (term_x < WN_width))
X			{
X			if (y > term_y)
X				{
X				if ((i = y - term_y) < 4) for (; i >0; i--) putchar(LF);	/* use LF */
X				else printf("\033[%dB", i);		/* use incremental jump */
X				}
X			else if ((i = term_y - y) == 1) fputs("\033[A", stdout);	/* move 1 */
X			else printf("\033[%dA", i);
X			term_y = y;
X			}
X		else printf("\033[%d;%dH", (term_y = y) + 1, (term_x = x) + 1);		/* absolute jump */
X		}
X	}
X/* scroll screen: argument is count: + up, - down */
X
Xw_scroll(count)
X	int count;
X	{
X	register int i, ic;
X	struct w_line *p[W_MAX_V];		/* temp copy of pointer array */
X
X	if (count > 0)		/* scrolling up */
X		{
X		w_move(window_size-1, 0);	/* cursor to bottom of window */
X		for (i = 0; i < count; i++)
X			{
X			putchar(LF), wlp[i]->n = 0;		/* scroll terminal, blank out image line */
X			}
X		}
X	else		/* scroll down */
X		{
X		w_move(0, 0);		/* cursor to top */
X		for (i = 0; i > count; i--)
X			{
X			fputs("\033M", stdout), wlp[window_size-1+i]->n = 0;
X			}
X		}
X	for (i = 0; i < window_size; i++) p[i] = wlp[(window_size + i + count) % window_size];	/* rearrange */
X	for (i = 0; i < window_size; i++) wlp[i] = p[i];
X	}
X
X
X
X/* clear line to left of curr_x */
X/* if some chars nonblank, does erase from start of line */
X
Xw_ebol()
X	{
X	short i, j;
X
X	for (j = i = 0; i < curr_x; i++) if (wlp[curr_y]->ch[i] != ' ') wlp[curr_y]->ch[i] = ' ', j++;
X	if (j || redraw_sw) w_move(curr_y, curr_x-1), vt(VT_EBOL);
X	}
X
X
X
X/* routine to set a pointer to a given location (like set_pointer) */
X/* returns nonzero if a text buffer exists, otherwise 0 */
X
Xint w_setptr(loc, pp)
X	register int loc;				/* location */
X	register struct qp *pp;			/* address of pointer */
X	{
X	register int i;
X
X	if (buff.f)
X		{
X		for (i = loc / CELLSIZE, pp->p = buff.f; i > 0; i--) pp->p = pp->p->f;
X		pp->c = loc % CELLSIZE;
X		pp->dot = loc;
X		}
X	return( (int) buff.f);
X	}
X/* routine to move N lines (back, forward, or 0)				*/
X/* w_lines(n, &source, &dest) where n is the line count, source	*/
X/* points to a qp at the current pointer, dest, if nonzero,		*/
X/* it points to a qp where the result is to go.					*/
X/* routine returns actual number of display lines				*/
X
Xstruct qp w_lines_p;				/* to compute # of display lines in -N lines */
X
Xint w_lines(n, ps, pd)
X	int n;							/* number of lines */
X	register struct qp *ps, *pd;	/* source, destination qp's */
X	{
X	register struct buffcell *tp;	/* local copy of the qp */
X	register int tc, tdot, tn;
X	int tcnt, tl;					/* chars/line and display line count */
X	char tch;
X
X	tdot = ps->dot;
X	tp = ps->p;
X	tc = ps->c;
X
X	if (n > 0)			/* argument is positive */
X		{
X		for (tcnt = tl = tn = 0; (tn < n) && (tdot < z); tdot++)	/* forward over N line separators */
X			{
X			if (spec_chars[ tch = tp->ch[tc] ] & A_L) ++tl, ++tn;		/* count separators */
X			else if (!(et_val & ET_TRUNC))		/* if text lines can overflow screen lines */
X				{
X				if (!(tch & 0140))				/* if character is a control char */
X					{
X					if (tch == CR)										/* CR resets count */
X						{
X						if (tcnt > WN_width) ++tl;
X						tcnt = 0;
X						}
X					else if (tch == TAB) tcnt = (tcnt | tabmask) +1;	/* tab to next tab stop */
X					else if (tch == ESC) ++tcnt;						/* ESC takes one space */
X					else tcnt += 2;										/* normal control chars take 2 spaces */
X					}
X				else ++tcnt;				/* not a control char: takes one space */
X				if (tcnt > WN_width) ++tl, tcnt = 2;		/* if overflow, one more line */
X				}
X
X			if (++tc > CELLSIZE-1) tp = tp->f, tc = 0;		/* next character position */
X			}
X		if (tl > tn) tn = tl;		/* if counting display lines and there's more of them, return that */
X		}
X	else				/* argument is zero or negative */
X		{
X		for (tn = 0; (tn >= n) && (tdot > 0); )		/* back up over (n+1) line feeds */
X			{
X			--tdot;
X			if (--tc < 0) tp = tp->b, tc = CELLSIZE -1;
X			if (spec_chars[tp->ch[tc]] & A_L) --tn;
X			}
X		if (tn < n)			/* if stopped on a line sep, fwd over it */
X			{
X			++tn;
X			++tdot;
X			if (++tc > CELLSIZE-1) tp = tp->f, tc = 0;
X			}
X
X		if (!(et_val & ET_TRUNC) && (n != 0))			/* if text line can overflow display line */
X			{
X			w_lines_p.dot = tdot, w_lines_p.p = tp, w_lines_p.c = tc;		/* then count the number of display */
X			tn = -w_lines(-n, &w_lines_p, 0);				/* lines in the N text lines we just backed up over */
X			}
X		}
X
X	if (pd) pd->dot = tdot, pd->p = tp, pd->c = tc;		/* if an "after" pointer given, update it */
X	return(tn);
X	}
X
END_OF_te_window.c
if test 33018 -ne `wc -c <te_window.c`; then
    echo shar: \"te_window.c\" unpacked with wrong size!?
fi
# end of overwriting check
fi
echo shar: End of archive 4 \(of 4\).
cp /dev/null ark4isdone
DONE=true
for I in 1 2 3 4 ; do
    if test ! -f ark${I}isdone ; then
	echo shar: You still need to run archive ${I}.
	DONE=false
    fi
done
if test "$DONE" = "true" ; then
	echo You have unpacked all 4 archives.
	echo "See the *.doc files"
	rm -f ark[1-9]isdone
fi
##  End of shell archive.
exit 0