1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1995-1999 by Sun Microsystems, Inc.
24*7c478bd9Sstevel@tonic-gate  * All rights reserved.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate /* LINTLIBRARY */
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate /*
30*7c478bd9Sstevel@tonic-gate  * doupdate.c
31*7c478bd9Sstevel@tonic-gate  *
32*7c478bd9Sstevel@tonic-gate  * XCurses Library
33*7c478bd9Sstevel@tonic-gate  *
34*7c478bd9Sstevel@tonic-gate  * Copyright 1990, 1995 by Mortice Kern Systems Inc.  All rights reserved.
35*7c478bd9Sstevel@tonic-gate  *
36*7c478bd9Sstevel@tonic-gate  */
37*7c478bd9Sstevel@tonic-gate 
38*7c478bd9Sstevel@tonic-gate #ifdef M_RCSID
39*7c478bd9Sstevel@tonic-gate #ifndef lint
40*7c478bd9Sstevel@tonic-gate static char const rcsID[] =
41*7c478bd9Sstevel@tonic-gate "$Header: /team/ps/sun_xcurses/archive/local_changes/xcurses/src/lib/"
42*7c478bd9Sstevel@tonic-gate "libxcurses/src/libc/xcurses/rcs/doupdate.c 1.22 1998/06/04 12:13:38 "
43*7c478bd9Sstevel@tonic-gate "cbates Exp $";
44*7c478bd9Sstevel@tonic-gate #endif
45*7c478bd9Sstevel@tonic-gate #endif
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate #include <sys/isa_defs.h>
48*7c478bd9Sstevel@tonic-gate #include <private.h>
49*7c478bd9Sstevel@tonic-gate #include <string.h>
50*7c478bd9Sstevel@tonic-gate #include <signal.h>
51*7c478bd9Sstevel@tonic-gate 
52*7c478bd9Sstevel@tonic-gate #undef SIGTSTP
53*7c478bd9Sstevel@tonic-gate 
54*7c478bd9Sstevel@tonic-gate /*
55*7c478bd9Sstevel@tonic-gate  * This value is the ideal length for the cursor addressing sequence
56*7c478bd9Sstevel@tonic-gate  * being four bytes long, ie. "<escape><cursor addressing code><row><col>".
57*7c478bd9Sstevel@tonic-gate  * eg. VT52 - "\EYrc" or ADM3A - "\E=rc"
58*7c478bd9Sstevel@tonic-gate  */
59*7c478bd9Sstevel@tonic-gate #define	JUMP_SIZE	4
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate /*
62*7c478bd9Sstevel@tonic-gate  * This value is the ideal length for the clear-to-eol sequence
63*7c478bd9Sstevel@tonic-gate  * being two bytes long, ie "<escape><clear eol code>".
64*7c478bd9Sstevel@tonic-gate  */
65*7c478bd9Sstevel@tonic-gate #define	CEOL_SIZE	2
66*7c478bd9Sstevel@tonic-gate 
67*7c478bd9Sstevel@tonic-gate #define	GOTO(r, c)	((void) __m_mvcur(curscr->_cury, curscr->_curx,\
68*7c478bd9Sstevel@tonic-gate 	r, c, __m_outc), curscr->_cury = r, curscr->_curx = c)
69*7c478bd9Sstevel@tonic-gate 
70*7c478bd9Sstevel@tonic-gate typedef struct cost_op {
71*7c478bd9Sstevel@tonic-gate 	short	cost;
72*7c478bd9Sstevel@tonic-gate 	short	op;
73*7c478bd9Sstevel@tonic-gate } lcost;
74*7c478bd9Sstevel@tonic-gate 
75*7c478bd9Sstevel@tonic-gate typedef void (*t_action)(int, int);
76*7c478bd9Sstevel@tonic-gate 
77*7c478bd9Sstevel@tonic-gate 
78*7c478bd9Sstevel@tonic-gate #define	LC(i, j) 	(lc[(i) * (LINES + 1) + (j)])
79*7c478bd9Sstevel@tonic-gate 
80*7c478bd9Sstevel@tonic-gate static lcost *lc = NULL;
81*7c478bd9Sstevel@tonic-gate #if defined(_LP64)
82*7c478bd9Sstevel@tonic-gate static unsigned int	*nhash = NULL;
83*7c478bd9Sstevel@tonic-gate #else
84*7c478bd9Sstevel@tonic-gate static unsigned long	*nhash = NULL;
85*7c478bd9Sstevel@tonic-gate #endif
86*7c478bd9Sstevel@tonic-gate static t_action *del = NULL;
87*7c478bd9Sstevel@tonic-gate static t_action *ins_rep = NULL;
88*7c478bd9Sstevel@tonic-gate 
89*7c478bd9Sstevel@tonic-gate static WINDOW	*newscr;
90*7c478bd9Sstevel@tonic-gate 
91*7c478bd9Sstevel@tonic-gate static void erase_bottom(int, int);
92*7c478bd9Sstevel@tonic-gate static void clear_bottom(int);
93*7c478bd9Sstevel@tonic-gate static void complex(void);
94*7c478bd9Sstevel@tonic-gate static int cost(int, int);
95*7c478bd9Sstevel@tonic-gate static void lines_delete(int, int);
96*7c478bd9Sstevel@tonic-gate static void lines_insert(int, int);
97*7c478bd9Sstevel@tonic-gate static void lines_replace(int, int);
98*7c478bd9Sstevel@tonic-gate static void script(int, int);
99*7c478bd9Sstevel@tonic-gate static int scroll_up(int);
100*7c478bd9Sstevel@tonic-gate static void simple(void);
101*7c478bd9Sstevel@tonic-gate static void text_replace(int);
102*7c478bd9Sstevel@tonic-gate #if 0
103*7c478bd9Sstevel@tonic-gate static int scroll_dn(int);
104*7c478bd9Sstevel@tonic-gate #endif
105*7c478bd9Sstevel@tonic-gate 
106*7c478bd9Sstevel@tonic-gate 
107*7c478bd9Sstevel@tonic-gate /*
108*7c478bd9Sstevel@tonic-gate  * Wrapper that streams Curses output.
109*7c478bd9Sstevel@tonic-gate  *
110*7c478bd9Sstevel@tonic-gate  * All escape sequences going to the screen come through here.
111*7c478bd9Sstevel@tonic-gate  * All ordinary characters go to the screen via the putc in doupdate.c
112*7c478bd9Sstevel@tonic-gate  */
113*7c478bd9Sstevel@tonic-gate int
__m_outc(int ch)114*7c478bd9Sstevel@tonic-gate __m_outc(int ch)
115*7c478bd9Sstevel@tonic-gate {
116*7c478bd9Sstevel@tonic-gate 	return (putc(ch, __m_screen->_of));
117*7c478bd9Sstevel@tonic-gate }
118*7c478bd9Sstevel@tonic-gate 
119*7c478bd9Sstevel@tonic-gate /*
120*7c478bd9Sstevel@tonic-gate  * Allocate or grow doupdate() structures.
121*7c478bd9Sstevel@tonic-gate  */
122*7c478bd9Sstevel@tonic-gate int
__m_doupdate_init(void)123*7c478bd9Sstevel@tonic-gate __m_doupdate_init(void)
124*7c478bd9Sstevel@tonic-gate {
125*7c478bd9Sstevel@tonic-gate 	void	*new;
126*7c478bd9Sstevel@tonic-gate 	static short	nlines = 0;
127*7c478bd9Sstevel@tonic-gate 
128*7c478bd9Sstevel@tonic-gate 	if (lines <= 0)
129*7c478bd9Sstevel@tonic-gate 		return (-1);
130*7c478bd9Sstevel@tonic-gate 
131*7c478bd9Sstevel@tonic-gate 	if (lines <= nlines)
132*7c478bd9Sstevel@tonic-gate 		return (0);
133*7c478bd9Sstevel@tonic-gate 
134*7c478bd9Sstevel@tonic-gate 	new = malloc((lines + 1) * (lines + 1) * sizeof (*lc));
135*7c478bd9Sstevel@tonic-gate 	if (new == NULL)
136*7c478bd9Sstevel@tonic-gate 		return (-1);
137*7c478bd9Sstevel@tonic-gate 	if (lc != NULL)
138*7c478bd9Sstevel@tonic-gate 		free(lc);
139*7c478bd9Sstevel@tonic-gate 	lc = (lcost *) new;
140*7c478bd9Sstevel@tonic-gate 
141*7c478bd9Sstevel@tonic-gate 	new = malloc((lines + lines) * sizeof (*del));
142*7c478bd9Sstevel@tonic-gate 	if (new == NULL)
143*7c478bd9Sstevel@tonic-gate 		return (-1);
144*7c478bd9Sstevel@tonic-gate 	if (del != NULL)
145*7c478bd9Sstevel@tonic-gate 		free(del);
146*7c478bd9Sstevel@tonic-gate 	del = (t_action *) new;
147*7c478bd9Sstevel@tonic-gate 	ins_rep = del + lines;
148*7c478bd9Sstevel@tonic-gate 
149*7c478bd9Sstevel@tonic-gate 	new = malloc(lines * sizeof (*nhash));
150*7c478bd9Sstevel@tonic-gate 	if (new == NULL)
151*7c478bd9Sstevel@tonic-gate 		return (-1);
152*7c478bd9Sstevel@tonic-gate 	if (nhash != NULL)
153*7c478bd9Sstevel@tonic-gate 		free(nhash);
154*7c478bd9Sstevel@tonic-gate #if defined(_LP64)
155*7c478bd9Sstevel@tonic-gate 	nhash = (unsigned int *) new;
156*7c478bd9Sstevel@tonic-gate #else
157*7c478bd9Sstevel@tonic-gate 	nhash = (unsigned long *) new;
158*7c478bd9Sstevel@tonic-gate #endif
159*7c478bd9Sstevel@tonic-gate 
160*7c478bd9Sstevel@tonic-gate 	nlines = lines;
161*7c478bd9Sstevel@tonic-gate 
162*7c478bd9Sstevel@tonic-gate 	return (0);
163*7c478bd9Sstevel@tonic-gate }
164*7c478bd9Sstevel@tonic-gate 
165*7c478bd9Sstevel@tonic-gate static void
erase_bottom(int start,int end)166*7c478bd9Sstevel@tonic-gate erase_bottom(int start, int end)
167*7c478bd9Sstevel@tonic-gate {
168*7c478bd9Sstevel@tonic-gate 	int i;
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate 	for (i = start; i < end; ++i) {
171*7c478bd9Sstevel@tonic-gate 		(void) __m_cc_erase(curscr, i, 0, i, curscr->_maxx - 1);
172*7c478bd9Sstevel@tonic-gate 		__m_cc_hash(curscr, __m_screen->_hash, i);
173*7c478bd9Sstevel@tonic-gate 	}
174*7c478bd9Sstevel@tonic-gate }
175*7c478bd9Sstevel@tonic-gate 
176*7c478bd9Sstevel@tonic-gate /*
177*7c478bd9Sstevel@tonic-gate  *  Clear from the start of the current row to bottom of screen.
178*7c478bd9Sstevel@tonic-gate  */
179*7c478bd9Sstevel@tonic-gate static void
clear_bottom(int y)180*7c478bd9Sstevel@tonic-gate clear_bottom(int y)
181*7c478bd9Sstevel@tonic-gate {
182*7c478bd9Sstevel@tonic-gate 	/* Restore default color pair before doing area clears. */
183*7c478bd9Sstevel@tonic-gate 	if (back_color_erase)
184*7c478bd9Sstevel@tonic-gate 		(void) vid_puts(WA_NORMAL, 0, (void *) 0, __m_outc);
185*7c478bd9Sstevel@tonic-gate 
186*7c478bd9Sstevel@tonic-gate 	if (y == 0 && clear_screen != NULL) {
187*7c478bd9Sstevel@tonic-gate 		(void) TPUTS(clear_screen, 1, __m_outc);
188*7c478bd9Sstevel@tonic-gate 	} else {
189*7c478bd9Sstevel@tonic-gate 		(void) __m_mvcur(-1, -1, y, 0, __m_outc);
190*7c478bd9Sstevel@tonic-gate 		if (clr_eos != NULL) {
191*7c478bd9Sstevel@tonic-gate 			(void) TPUTS(clr_eos, 1, __m_outc);
192*7c478bd9Sstevel@tonic-gate 		} else if (clr_eol != NULL) {
193*7c478bd9Sstevel@tonic-gate 			for (;;) {
194*7c478bd9Sstevel@tonic-gate 				(void) TPUTS(clr_eol, 1, __m_outc);
195*7c478bd9Sstevel@tonic-gate 				if (LINES <= y)
196*7c478bd9Sstevel@tonic-gate 					break;
197*7c478bd9Sstevel@tonic-gate 				(void) __m_mvcur(y, 0, y + 1, 0, __m_outc);
198*7c478bd9Sstevel@tonic-gate 				++y;
199*7c478bd9Sstevel@tonic-gate 			}
200*7c478bd9Sstevel@tonic-gate 		}
201*7c478bd9Sstevel@tonic-gate 	}
202*7c478bd9Sstevel@tonic-gate 
203*7c478bd9Sstevel@tonic-gate 	curscr->_cury = y;
204*7c478bd9Sstevel@tonic-gate 	curscr->_curx = 0;
205*7c478bd9Sstevel@tonic-gate }
206*7c478bd9Sstevel@tonic-gate 
207*7c478bd9Sstevel@tonic-gate 
208*7c478bd9Sstevel@tonic-gate 
209*7c478bd9Sstevel@tonic-gate /*
210*7c478bd9Sstevel@tonic-gate  * Rewrite of text_replace() implementation by C. Bates of MKS
211*7c478bd9Sstevel@tonic-gate  *
212*7c478bd9Sstevel@tonic-gate  * This code creates a list of 'regions' for each test line which
213*7c478bd9Sstevel@tonic-gate  * is to be replaced. Each region describes a portion of the line.
214*7c478bd9Sstevel@tonic-gate  * Logic is performed on the list of regions, then the regions
215*7c478bd9Sstevel@tonic-gate  * are used to generate output.
216*7c478bd9Sstevel@tonic-gate  */
217*7c478bd9Sstevel@tonic-gate typedef	struct LineRegion {
218*7c478bd9Sstevel@tonic-gate 	int	col;	/* Starting column of region */
219*7c478bd9Sstevel@tonic-gate 	int	size;	/* Size of region */
220*7c478bd9Sstevel@tonic-gate 	/* 0: Difference Region, 1: Common Region, 2: Delete Region */
221*7c478bd9Sstevel@tonic-gate 	int	type;
222*7c478bd9Sstevel@tonic-gate } LineRegion;
223*7c478bd9Sstevel@tonic-gate #define	REGION_DIFFERENT	0
224*7c478bd9Sstevel@tonic-gate #define	REGION_COMMON		1
225*7c478bd9Sstevel@tonic-gate #define	REGION_DELETE		2
226*7c478bd9Sstevel@tonic-gate 
227*7c478bd9Sstevel@tonic-gate #define	DELETE_SEARCH_LIMIT	4
228*7c478bd9Sstevel@tonic-gate #define	DELETE_THRESHOLD	10
229*7c478bd9Sstevel@tonic-gate 
230*7c478bd9Sstevel@tonic-gate static LineRegion	regions[1024];
231*7c478bd9Sstevel@tonic-gate int	nRegions = 0;
232*7c478bd9Sstevel@tonic-gate 
233*7c478bd9Sstevel@tonic-gate /*
234*7c478bd9Sstevel@tonic-gate  * Return the first column of the completely blank End-of-line
235*7c478bd9Sstevel@tonic-gate  */
236*7c478bd9Sstevel@tonic-gate static int
_find_blank_tail(int row)237*7c478bd9Sstevel@tonic-gate _find_blank_tail(int row)
238*7c478bd9Sstevel@tonic-gate {
239*7c478bd9Sstevel@tonic-gate 	cchar_t	*nptr;
240*7c478bd9Sstevel@tonic-gate 	int	tail = COLS;
241*7c478bd9Sstevel@tonic-gate 
242*7c478bd9Sstevel@tonic-gate 	if (!clr_eol)
243*7c478bd9Sstevel@tonic-gate 		return (COLS);
244*7c478bd9Sstevel@tonic-gate 	/*
245*7c478bd9Sstevel@tonic-gate 	 * Find start of blank tail region.
246*7c478bd9Sstevel@tonic-gate 	 */
247*7c478bd9Sstevel@tonic-gate 	nptr = &newscr->_line[row][COLS];
248*7c478bd9Sstevel@tonic-gate 	for (; 0 < tail; --tail) {
249*7c478bd9Sstevel@tonic-gate 		if (!__m_cc_compare(--nptr, &newscr->_bg, 1))
250*7c478bd9Sstevel@tonic-gate 			break;
251*7c478bd9Sstevel@tonic-gate 	}
252*7c478bd9Sstevel@tonic-gate 	return (tail);
253*7c478bd9Sstevel@tonic-gate }
254*7c478bd9Sstevel@tonic-gate 
255*7c478bd9Sstevel@tonic-gate /*
256*7c478bd9Sstevel@tonic-gate  * Send all the characters in the region to the terminal
257*7c478bd9Sstevel@tonic-gate  */
258*7c478bd9Sstevel@tonic-gate static void
_writeRegion(int row,LineRegion region)259*7c478bd9Sstevel@tonic-gate _writeRegion(int row, LineRegion region)
260*7c478bd9Sstevel@tonic-gate {
261*7c478bd9Sstevel@tonic-gate 	short	npair;
262*7c478bd9Sstevel@tonic-gate 	attr_t	nattr;
263*7c478bd9Sstevel@tonic-gate 	int	i;
264*7c478bd9Sstevel@tonic-gate 	cchar_t	*optr = &curscr->_line[row][region.col];
265*7c478bd9Sstevel@tonic-gate 	cchar_t	*nptr = &newscr->_line[row][region.col];
266*7c478bd9Sstevel@tonic-gate 
267*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < region.size; i++, nptr++, optr++) {
268*7c478bd9Sstevel@tonic-gate 		nattr = nptr->_at;
269*7c478bd9Sstevel@tonic-gate 		npair = nptr->_co;
270*7c478bd9Sstevel@tonic-gate 
271*7c478bd9Sstevel@tonic-gate 		/*
272*7c478bd9Sstevel@tonic-gate 		 * Change attribute state.
273*7c478bd9Sstevel@tonic-gate 		 */
274*7c478bd9Sstevel@tonic-gate 		if ((ATTR_STATE != nattr) || (optr->_at != nattr) ||
275*7c478bd9Sstevel@tonic-gate 			(cur_term->_co != npair)) {
276*7c478bd9Sstevel@tonic-gate 			(void) vid_puts(nattr, npair, NULL, __m_outc);
277*7c478bd9Sstevel@tonic-gate 		}
278*7c478bd9Sstevel@tonic-gate 		/*
279*7c478bd9Sstevel@tonic-gate 		 * Don't display internal characters.
280*7c478bd9Sstevel@tonic-gate 		 */
281*7c478bd9Sstevel@tonic-gate 		if (nptr->_f)
282*7c478bd9Sstevel@tonic-gate 			(void) __m_cc_write(nptr);
283*7c478bd9Sstevel@tonic-gate 
284*7c478bd9Sstevel@tonic-gate 		/*
285*7c478bd9Sstevel@tonic-gate 		 * Update copy of screen image.
286*7c478bd9Sstevel@tonic-gate 		 */
287*7c478bd9Sstevel@tonic-gate 		*optr = *nptr;
288*7c478bd9Sstevel@tonic-gate 		curscr->_curx = region.col + i + 1;
289*7c478bd9Sstevel@tonic-gate 	}
290*7c478bd9Sstevel@tonic-gate }
291*7c478bd9Sstevel@tonic-gate 
292*7c478bd9Sstevel@tonic-gate /*
293*7c478bd9Sstevel@tonic-gate  * Delete some characters from the terminal for this region
294*7c478bd9Sstevel@tonic-gate  */
295*7c478bd9Sstevel@tonic-gate static void
_deleteRegion(int row,LineRegion region)296*7c478bd9Sstevel@tonic-gate _deleteRegion(int row, LineRegion region)
297*7c478bd9Sstevel@tonic-gate {
298*7c478bd9Sstevel@tonic-gate 	int	i;
299*7c478bd9Sstevel@tonic-gate 	cchar_t	*optr = &curscr->_line[row][region.col];
300*7c478bd9Sstevel@tonic-gate 
301*7c478bd9Sstevel@tonic-gate 	if ((region.size <= 1) || !parm_dch) {
302*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < region.size; i++)
303*7c478bd9Sstevel@tonic-gate 			(void) TPUTS(delete_character, 1, __m_outc);
304*7c478bd9Sstevel@tonic-gate 	} else {
305*7c478bd9Sstevel@tonic-gate 		(void) TPUTS(tparm(parm_dch, (long)region.size,
306*7c478bd9Sstevel@tonic-gate 			0, 0, 0, 0, 0, 0, 0, 0), region.size, __m_outc);
307*7c478bd9Sstevel@tonic-gate 	}
308*7c478bd9Sstevel@tonic-gate 	for (i = region.col; i < COLS - region.size; i++) {
309*7c478bd9Sstevel@tonic-gate 		/*
310*7c478bd9Sstevel@tonic-gate 		 * Delete the chars in the image of the real screen
311*7c478bd9Sstevel@tonic-gate 		 */
312*7c478bd9Sstevel@tonic-gate 		*optr = *(optr + region.size);
313*7c478bd9Sstevel@tonic-gate 		optr++;
314*7c478bd9Sstevel@tonic-gate 	}
315*7c478bd9Sstevel@tonic-gate }
316*7c478bd9Sstevel@tonic-gate 
317*7c478bd9Sstevel@tonic-gate /*
318*7c478bd9Sstevel@tonic-gate  * Use clr_eol control if possible
319*7c478bd9Sstevel@tonic-gate  */
320*7c478bd9Sstevel@tonic-gate static void
_clearToEOL(int row,int tail)321*7c478bd9Sstevel@tonic-gate _clearToEOL(int row, int tail)
322*7c478bd9Sstevel@tonic-gate {
323*7c478bd9Sstevel@tonic-gate 	if (tail < COLS) {
324*7c478bd9Sstevel@tonic-gate 		GOTO(row, tail);
325*7c478bd9Sstevel@tonic-gate 		/*
326*7c478bd9Sstevel@tonic-gate 		 * Restore default color pair before area clear.
327*7c478bd9Sstevel@tonic-gate 		 */
328*7c478bd9Sstevel@tonic-gate 		if (back_color_erase)
329*7c478bd9Sstevel@tonic-gate 			(void) vid_puts(WA_NORMAL, 0, NULL, __m_outc);
330*7c478bd9Sstevel@tonic-gate 
331*7c478bd9Sstevel@tonic-gate 		(void) TPUTS(clr_eol, 1, __m_outc);
332*7c478bd9Sstevel@tonic-gate 		(void) __m_cc_erase(curscr, row, tail, row, COLS - 1);
333*7c478bd9Sstevel@tonic-gate 	}
334*7c478bd9Sstevel@tonic-gate }
335*7c478bd9Sstevel@tonic-gate 
336*7c478bd9Sstevel@tonic-gate /*
337*7c478bd9Sstevel@tonic-gate  * Delete leading common region
338*7c478bd9Sstevel@tonic-gate  */
339*7c478bd9Sstevel@tonic-gate static void
_normalizeRegions1(void)340*7c478bd9Sstevel@tonic-gate _normalizeRegions1(void)
341*7c478bd9Sstevel@tonic-gate {
342*7c478bd9Sstevel@tonic-gate 	int	iRegion;
343*7c478bd9Sstevel@tonic-gate 
344*7c478bd9Sstevel@tonic-gate 	/*
345*7c478bd9Sstevel@tonic-gate 	 * Delete leading common region
346*7c478bd9Sstevel@tonic-gate 	 */
347*7c478bd9Sstevel@tonic-gate 	if (regions[0].type == REGION_COMMON) {
348*7c478bd9Sstevel@tonic-gate 		nRegions--;
349*7c478bd9Sstevel@tonic-gate 		for (iRegion = 0; iRegion < nRegions; iRegion++) {
350*7c478bd9Sstevel@tonic-gate 			regions[iRegion] = regions[iRegion + 1];
351*7c478bd9Sstevel@tonic-gate 		}
352*7c478bd9Sstevel@tonic-gate 	}
353*7c478bd9Sstevel@tonic-gate }
354*7c478bd9Sstevel@tonic-gate 
355*7c478bd9Sstevel@tonic-gate /*
356*7c478bd9Sstevel@tonic-gate  * Give each region a size, then delete all trailing common regions
357*7c478bd9Sstevel@tonic-gate  */
358*7c478bd9Sstevel@tonic-gate static void
_normalizeRegions2(void)359*7c478bd9Sstevel@tonic-gate _normalizeRegions2(void)
360*7c478bd9Sstevel@tonic-gate {
361*7c478bd9Sstevel@tonic-gate 	int	iRegion;
362*7c478bd9Sstevel@tonic-gate 
363*7c478bd9Sstevel@tonic-gate 	for (iRegion = 0; iRegion < nRegions - 1; iRegion++) {
364*7c478bd9Sstevel@tonic-gate 		regions[iRegion].size = regions[iRegion + 1].col -
365*7c478bd9Sstevel@tonic-gate 			regions[iRegion].col;
366*7c478bd9Sstevel@tonic-gate 	}
367*7c478bd9Sstevel@tonic-gate 	regions[nRegions - 1].size = COLS - regions[nRegions - 1].col;
368*7c478bd9Sstevel@tonic-gate 
369*7c478bd9Sstevel@tonic-gate 	/*
370*7c478bd9Sstevel@tonic-gate 	 * Delete trailing common regions
371*7c478bd9Sstevel@tonic-gate 	 */
372*7c478bd9Sstevel@tonic-gate 	while (regions[nRegions - 1].type == REGION_COMMON)
373*7c478bd9Sstevel@tonic-gate 		nRegions--;
374*7c478bd9Sstevel@tonic-gate }
375*7c478bd9Sstevel@tonic-gate 
376*7c478bd9Sstevel@tonic-gate /*
377*7c478bd9Sstevel@tonic-gate  * Tiny common regions are merged into adjacent difference regions
378*7c478bd9Sstevel@tonic-gate  */
379*7c478bd9Sstevel@tonic-gate static void
_mergeTinyRegions(void)380*7c478bd9Sstevel@tonic-gate _mergeTinyRegions(void)
381*7c478bd9Sstevel@tonic-gate {
382*7c478bd9Sstevel@tonic-gate 	int	from;
383*7c478bd9Sstevel@tonic-gate 	int	to;
384*7c478bd9Sstevel@tonic-gate 	for (from = 1, to = 1; from < nRegions; ) {
385*7c478bd9Sstevel@tonic-gate 		if ((regions[from].type == REGION_COMMON) &&
386*7c478bd9Sstevel@tonic-gate 			(regions[from].size < JUMP_SIZE)) {
387*7c478bd9Sstevel@tonic-gate 			/*
388*7c478bd9Sstevel@tonic-gate 			 * Merge out tiny common regions
389*7c478bd9Sstevel@tonic-gate 			 */
390*7c478bd9Sstevel@tonic-gate 			regions[to - 1].size += regions[from].size;
391*7c478bd9Sstevel@tonic-gate 			/*
392*7c478bd9Sstevel@tonic-gate 			 * Now join adjacent non-common regions
393*7c478bd9Sstevel@tonic-gate 			 */
394*7c478bd9Sstevel@tonic-gate 			if (++from < nRegions)
395*7c478bd9Sstevel@tonic-gate 				regions[to - 1].size += regions[from++].size;
396*7c478bd9Sstevel@tonic-gate 		} else {
397*7c478bd9Sstevel@tonic-gate 			regions[to++] = regions[from++];
398*7c478bd9Sstevel@tonic-gate 		}
399*7c478bd9Sstevel@tonic-gate 	}
400*7c478bd9Sstevel@tonic-gate 	nRegions = to;
401*7c478bd9Sstevel@tonic-gate }
402*7c478bd9Sstevel@tonic-gate 
403*7c478bd9Sstevel@tonic-gate /*
404*7c478bd9Sstevel@tonic-gate  * Create the initial list of regions for this row
405*7c478bd9Sstevel@tonic-gate  */
406*7c478bd9Sstevel@tonic-gate static int
_findRegions(int row)407*7c478bd9Sstevel@tonic-gate _findRegions(int row)
408*7c478bd9Sstevel@tonic-gate {
409*7c478bd9Sstevel@tonic-gate 	int	cmp;
410*7c478bd9Sstevel@tonic-gate 	int	old_cmp;
411*7c478bd9Sstevel@tonic-gate 	int	col;
412*7c478bd9Sstevel@tonic-gate 	int	bestDeleteCount;
413*7c478bd9Sstevel@tonic-gate 	cchar_t	*nptr = &newscr->_line[row][0];
414*7c478bd9Sstevel@tonic-gate 	cchar_t	*optr = &curscr->_line[row][0];
415*7c478bd9Sstevel@tonic-gate 
416*7c478bd9Sstevel@tonic-gate 	col = 0;
417*7c478bd9Sstevel@tonic-gate 	nRegions = 0;
418*7c478bd9Sstevel@tonic-gate 	bestDeleteCount = 0;
419*7c478bd9Sstevel@tonic-gate 	if ((__m_screen->_flags & S_INS_DEL_CHAR) &&
420*7c478bd9Sstevel@tonic-gate 		(parm_dch || delete_character)) {
421*7c478bd9Sstevel@tonic-gate 		int	bestFit = 0;
422*7c478bd9Sstevel@tonic-gate 		int	deletePoint;
423*7c478bd9Sstevel@tonic-gate 		int	deleteCount;
424*7c478bd9Sstevel@tonic-gate 		int	matches;
425*7c478bd9Sstevel@tonic-gate 
426*7c478bd9Sstevel@tonic-gate 		/*
427*7c478bd9Sstevel@tonic-gate 		 * Skip to first difference
428*7c478bd9Sstevel@tonic-gate 		 */
429*7c478bd9Sstevel@tonic-gate 		for (col = 0; col < COLS; col++) {
430*7c478bd9Sstevel@tonic-gate 			if (!__m_cc_compare(&optr[col], &nptr[col], 1))
431*7c478bd9Sstevel@tonic-gate 				break;
432*7c478bd9Sstevel@tonic-gate 		}
433*7c478bd9Sstevel@tonic-gate 		deletePoint = col;
434*7c478bd9Sstevel@tonic-gate 		for (deleteCount = 1; deleteCount < DELETE_SEARCH_LIMIT;
435*7c478bd9Sstevel@tonic-gate 			deleteCount++) {
436*7c478bd9Sstevel@tonic-gate 			matches = 0;
437*7c478bd9Sstevel@tonic-gate 			for (col = deletePoint; col < COLS - deleteCount;
438*7c478bd9Sstevel@tonic-gate 				col++) {
439*7c478bd9Sstevel@tonic-gate 				if (__m_cc_compare(&optr[col + deleteCount],
440*7c478bd9Sstevel@tonic-gate 					&nptr[col], 1))
441*7c478bd9Sstevel@tonic-gate 					matches++;
442*7c478bd9Sstevel@tonic-gate 				else
443*7c478bd9Sstevel@tonic-gate 					break;
444*7c478bd9Sstevel@tonic-gate 			}
445*7c478bd9Sstevel@tonic-gate 			if (matches > bestFit) {
446*7c478bd9Sstevel@tonic-gate 				bestFit = matches;
447*7c478bd9Sstevel@tonic-gate 				bestDeleteCount = deleteCount;
448*7c478bd9Sstevel@tonic-gate 			}
449*7c478bd9Sstevel@tonic-gate 		}
450*7c478bd9Sstevel@tonic-gate 		if (bestFit > DELETE_THRESHOLD) {
451*7c478bd9Sstevel@tonic-gate 			regions[nRegions].type = REGION_DELETE;
452*7c478bd9Sstevel@tonic-gate 			regions[nRegions].col = deletePoint;
453*7c478bd9Sstevel@tonic-gate 			regions[nRegions].size = bestDeleteCount;
454*7c478bd9Sstevel@tonic-gate 			nRegions++;
455*7c478bd9Sstevel@tonic-gate 			col = deletePoint + bestDeleteCount;
456*7c478bd9Sstevel@tonic-gate 		} else {
457*7c478bd9Sstevel@tonic-gate 			col = 0;
458*7c478bd9Sstevel@tonic-gate 			nRegions = 0;
459*7c478bd9Sstevel@tonic-gate 			/* Forget trying to use character delete */
460*7c478bd9Sstevel@tonic-gate 			bestDeleteCount = 0;
461*7c478bd9Sstevel@tonic-gate 		}
462*7c478bd9Sstevel@tonic-gate 	}
463*7c478bd9Sstevel@tonic-gate 	for (old_cmp = -1; col + bestDeleteCount < COLS; col++) {
464*7c478bd9Sstevel@tonic-gate 		cmp = __m_cc_compare(&optr[col + bestDeleteCount],
465*7c478bd9Sstevel@tonic-gate 			&nptr[col], 1);
466*7c478bd9Sstevel@tonic-gate 		if (cmp != old_cmp) {
467*7c478bd9Sstevel@tonic-gate 			regions[nRegions].type = cmp ? REGION_COMMON :
468*7c478bd9Sstevel@tonic-gate 				REGION_DIFFERENT;
469*7c478bd9Sstevel@tonic-gate 			regions[nRegions].col = col;
470*7c478bd9Sstevel@tonic-gate 			regions[nRegions].size = 0;	/* Determine later */
471*7c478bd9Sstevel@tonic-gate 			nRegions++;
472*7c478bd9Sstevel@tonic-gate 			old_cmp = cmp;
473*7c478bd9Sstevel@tonic-gate 		}
474*7c478bd9Sstevel@tonic-gate 	}
475*7c478bd9Sstevel@tonic-gate 	if (bestDeleteCount) {
476*7c478bd9Sstevel@tonic-gate 		/*
477*7c478bd9Sstevel@tonic-gate 		 * Force update of end-of-line if delete is to be used
478*7c478bd9Sstevel@tonic-gate 		 */
479*7c478bd9Sstevel@tonic-gate 		regions[nRegions].type = REGION_DIFFERENT;
480*7c478bd9Sstevel@tonic-gate 		regions[nRegions].col = col;
481*7c478bd9Sstevel@tonic-gate 		regions[nRegions].size = 0;	/* Determine later */
482*7c478bd9Sstevel@tonic-gate 		nRegions++;
483*7c478bd9Sstevel@tonic-gate 	}
484*7c478bd9Sstevel@tonic-gate 	_normalizeRegions1();
485*7c478bd9Sstevel@tonic-gate 	if (nRegions == 0)
486*7c478bd9Sstevel@tonic-gate 		return (0);		/* No difference regions */
487*7c478bd9Sstevel@tonic-gate 
488*7c478bd9Sstevel@tonic-gate 	_normalizeRegions2();
489*7c478bd9Sstevel@tonic-gate 	return (1);
490*7c478bd9Sstevel@tonic-gate }
491*7c478bd9Sstevel@tonic-gate 
492*7c478bd9Sstevel@tonic-gate /*
493*7c478bd9Sstevel@tonic-gate  * Determine if Clr-EOL optimization can be used, and
494*7c478bd9Sstevel@tonic-gate  * adjust regions accordingly
495*7c478bd9Sstevel@tonic-gate  */
496*7c478bd9Sstevel@tonic-gate static int
_ceolAdjustRegions(int row)497*7c478bd9Sstevel@tonic-gate _ceolAdjustRegions(int row)
498*7c478bd9Sstevel@tonic-gate {
499*7c478bd9Sstevel@tonic-gate 	int	iRegion;
500*7c478bd9Sstevel@tonic-gate 	int	blankEolStart = _find_blank_tail(row);
501*7c478bd9Sstevel@tonic-gate 
502*7c478bd9Sstevel@tonic-gate 	for (iRegion = 0; iRegion < nRegions; iRegion++) {
503*7c478bd9Sstevel@tonic-gate 		switch (regions[iRegion].type) {
504*7c478bd9Sstevel@tonic-gate 		case REGION_DIFFERENT:
505*7c478bd9Sstevel@tonic-gate 			if (regions[iRegion].col >= blankEolStart) {
506*7c478bd9Sstevel@tonic-gate 				/*
507*7c478bd9Sstevel@tonic-gate 				 * Delete this and all following regions
508*7c478bd9Sstevel@tonic-gate 				 */
509*7c478bd9Sstevel@tonic-gate 				nRegions = iRegion;
510*7c478bd9Sstevel@tonic-gate 				return (blankEolStart);
511*7c478bd9Sstevel@tonic-gate 			}
512*7c478bd9Sstevel@tonic-gate 			if (regions[iRegion].col + regions[iRegion].size >
513*7c478bd9Sstevel@tonic-gate 				blankEolStart) {
514*7c478bd9Sstevel@tonic-gate 				/*
515*7c478bd9Sstevel@tonic-gate 				 * Truncate this region to end
516*7c478bd9Sstevel@tonic-gate 				 * where blank EOL starts
517*7c478bd9Sstevel@tonic-gate 				 */
518*7c478bd9Sstevel@tonic-gate 				regions[iRegion].size = blankEolStart -
519*7c478bd9Sstevel@tonic-gate 					regions[iRegion].col;
520*7c478bd9Sstevel@tonic-gate 				/*
521*7c478bd9Sstevel@tonic-gate 				 * Delete all following regions
522*7c478bd9Sstevel@tonic-gate 				 */
523*7c478bd9Sstevel@tonic-gate 				nRegions = iRegion + 1;
524*7c478bd9Sstevel@tonic-gate 				return (blankEolStart);
525*7c478bd9Sstevel@tonic-gate 			}
526*7c478bd9Sstevel@tonic-gate 			break;
527*7c478bd9Sstevel@tonic-gate 		case REGION_COMMON:
528*7c478bd9Sstevel@tonic-gate 			break;
529*7c478bd9Sstevel@tonic-gate 		case REGION_DELETE:		/* Scrap the whole thing */
530*7c478bd9Sstevel@tonic-gate 			return (COLS);
531*7c478bd9Sstevel@tonic-gate 		}
532*7c478bd9Sstevel@tonic-gate 	}
533*7c478bd9Sstevel@tonic-gate 	return (COLS);	/* Couldn't use Clear EOL optimization */
534*7c478bd9Sstevel@tonic-gate }
535*7c478bd9Sstevel@tonic-gate 
536*7c478bd9Sstevel@tonic-gate /*
537*7c478bd9Sstevel@tonic-gate  * Generate output, based on region list
538*7c478bd9Sstevel@tonic-gate  */
539*7c478bd9Sstevel@tonic-gate static void
_updateRegions(int row)540*7c478bd9Sstevel@tonic-gate _updateRegions(int row)
541*7c478bd9Sstevel@tonic-gate {
542*7c478bd9Sstevel@tonic-gate 	int	ceolStart;
543*7c478bd9Sstevel@tonic-gate 	int	iRegion;
544*7c478bd9Sstevel@tonic-gate 
545*7c478bd9Sstevel@tonic-gate 	ceolStart = _ceolAdjustRegions(row);
546*7c478bd9Sstevel@tonic-gate 
547*7c478bd9Sstevel@tonic-gate 	/*
548*7c478bd9Sstevel@tonic-gate 	 * regions are guaranteed to start with a non-common region.
549*7c478bd9Sstevel@tonic-gate 	 * tiny common regions have also been merged into
550*7c478bd9Sstevel@tonic-gate 	 * bracketting common-regions.
551*7c478bd9Sstevel@tonic-gate 	 */
552*7c478bd9Sstevel@tonic-gate 	if (nRegions) {
553*7c478bd9Sstevel@tonic-gate 		for (iRegion = 0; iRegion < nRegions; iRegion++) {
554*7c478bd9Sstevel@tonic-gate 			switch (regions[iRegion].type) {
555*7c478bd9Sstevel@tonic-gate 			case REGION_COMMON:
556*7c478bd9Sstevel@tonic-gate 				break;
557*7c478bd9Sstevel@tonic-gate 			case REGION_DELETE:
558*7c478bd9Sstevel@tonic-gate 				/*
559*7c478bd9Sstevel@tonic-gate 				 * Start of non-common region
560*7c478bd9Sstevel@tonic-gate 				 */
561*7c478bd9Sstevel@tonic-gate 				GOTO(row, regions[iRegion].col);
562*7c478bd9Sstevel@tonic-gate 				_deleteRegion(row, regions[iRegion]);
563*7c478bd9Sstevel@tonic-gate 				break;
564*7c478bd9Sstevel@tonic-gate 			case REGION_DIFFERENT:
565*7c478bd9Sstevel@tonic-gate 				/*
566*7c478bd9Sstevel@tonic-gate 				 * Star of non-common region
567*7c478bd9Sstevel@tonic-gate 				 */
568*7c478bd9Sstevel@tonic-gate 				GOTO(row, regions[iRegion].col);
569*7c478bd9Sstevel@tonic-gate 				_writeRegion(row, regions[iRegion]);
570*7c478bd9Sstevel@tonic-gate 				break;
571*7c478bd9Sstevel@tonic-gate 			}
572*7c478bd9Sstevel@tonic-gate 		}
573*7c478bd9Sstevel@tonic-gate 	}
574*7c478bd9Sstevel@tonic-gate 	if (ceolStart != COLS) {
575*7c478bd9Sstevel@tonic-gate 		_clearToEOL(row, ceolStart);
576*7c478bd9Sstevel@tonic-gate 	}
577*7c478bd9Sstevel@tonic-gate }
578*7c478bd9Sstevel@tonic-gate 
579*7c478bd9Sstevel@tonic-gate /*
580*7c478bd9Sstevel@tonic-gate  * The new text_replace algorithm, which uses regions
581*7c478bd9Sstevel@tonic-gate  */
582*7c478bd9Sstevel@tonic-gate static void
text_replace(int row)583*7c478bd9Sstevel@tonic-gate text_replace(int row)
584*7c478bd9Sstevel@tonic-gate {
585*7c478bd9Sstevel@tonic-gate 	if (!_findRegions(row))
586*7c478bd9Sstevel@tonic-gate 		return;
587*7c478bd9Sstevel@tonic-gate 	_mergeTinyRegions();
588*7c478bd9Sstevel@tonic-gate 	_updateRegions(row);
589*7c478bd9Sstevel@tonic-gate 
590*7c478bd9Sstevel@tonic-gate 	/*
591*7c478bd9Sstevel@tonic-gate 	 * Line wrapping checks.
592*7c478bd9Sstevel@tonic-gate 	 */
593*7c478bd9Sstevel@tonic-gate 	if (COLS <= curscr->_curx) {
594*7c478bd9Sstevel@tonic-gate 		--curscr->_curx;
595*7c478bd9Sstevel@tonic-gate 		if (auto_right_margin && (row < LINES - 1)) {
596*7c478bd9Sstevel@tonic-gate 			if (eat_newline_glitch) {
597*7c478bd9Sstevel@tonic-gate 				(void) __m_outc('\r');
598*7c478bd9Sstevel@tonic-gate 				(void) __m_outc('\n');
599*7c478bd9Sstevel@tonic-gate 			}
600*7c478bd9Sstevel@tonic-gate 			++curscr->_cury;
601*7c478bd9Sstevel@tonic-gate 			curscr->_curx = 0;
602*7c478bd9Sstevel@tonic-gate 		}
603*7c478bd9Sstevel@tonic-gate 	}
604*7c478bd9Sstevel@tonic-gate }
605*7c478bd9Sstevel@tonic-gate 
606*7c478bd9Sstevel@tonic-gate /*
607*7c478bd9Sstevel@tonic-gate  * Replace a block of lines.
608*7c478bd9Sstevel@tonic-gate  * Only ever used for complex().
609*7c478bd9Sstevel@tonic-gate  */
610*7c478bd9Sstevel@tonic-gate static void
lines_replace(int from,int to_1)611*7c478bd9Sstevel@tonic-gate lines_replace(int from, int to_1)
612*7c478bd9Sstevel@tonic-gate {
613*7c478bd9Sstevel@tonic-gate 	for (; from < to_1; ++from)
614*7c478bd9Sstevel@tonic-gate 		text_replace(from);
615*7c478bd9Sstevel@tonic-gate }
616*7c478bd9Sstevel@tonic-gate 
617*7c478bd9Sstevel@tonic-gate /*
618*7c478bd9Sstevel@tonic-gate  * Delete a block of lines.
619*7c478bd9Sstevel@tonic-gate  * Only ever used for complex().
620*7c478bd9Sstevel@tonic-gate  */
621*7c478bd9Sstevel@tonic-gate static void
lines_delete(int from,int to_1)622*7c478bd9Sstevel@tonic-gate lines_delete(int from, int to_1)
623*7c478bd9Sstevel@tonic-gate {
624*7c478bd9Sstevel@tonic-gate 	int count = to_1 - from;
625*7c478bd9Sstevel@tonic-gate 
626*7c478bd9Sstevel@tonic-gate 	if (LINES <= to_1) {
627*7c478bd9Sstevel@tonic-gate 		erase_bottom(from, LINES);
628*7c478bd9Sstevel@tonic-gate 		clear_bottom(from);
629*7c478bd9Sstevel@tonic-gate 	} else {
630*7c478bd9Sstevel@tonic-gate 		GOTO(from, 0);
631*7c478bd9Sstevel@tonic-gate 		(void) winsdelln(curscr, -count);
632*7c478bd9Sstevel@tonic-gate 
633*7c478bd9Sstevel@tonic-gate 		if (parm_delete_line != NULL) {
634*7c478bd9Sstevel@tonic-gate 			/*
635*7c478bd9Sstevel@tonic-gate 			 * Assume that the sequence to delete more than one
636*7c478bd9Sstevel@tonic-gate 			 * line is faster than repeated single delete_lines.
637*7c478bd9Sstevel@tonic-gate 			 */
638*7c478bd9Sstevel@tonic-gate 			(void) TPUTS(tparm(parm_delete_line, (long)count,
639*7c478bd9Sstevel@tonic-gate 				0, 0, 0, 0, 0, 0, 0, 0), count, __m_outc);
640*7c478bd9Sstevel@tonic-gate 		} else if (delete_line != NULL) {
641*7c478bd9Sstevel@tonic-gate 			while (from++ < to_1)
642*7c478bd9Sstevel@tonic-gate 				(void) TPUTS(delete_line, 1, __m_outc);
643*7c478bd9Sstevel@tonic-gate 		} else  {
644*7c478bd9Sstevel@tonic-gate 			/* Error -- what to do. */
645*7c478bd9Sstevel@tonic-gate 			return;
646*7c478bd9Sstevel@tonic-gate 		}
647*7c478bd9Sstevel@tonic-gate 	}
648*7c478bd9Sstevel@tonic-gate }
649*7c478bd9Sstevel@tonic-gate 
650*7c478bd9Sstevel@tonic-gate /*
651*7c478bd9Sstevel@tonic-gate  * Insert a block of lines.
652*7c478bd9Sstevel@tonic-gate  * Only ever used for complex().
653*7c478bd9Sstevel@tonic-gate  *
654*7c478bd9Sstevel@tonic-gate  * We must assume that insert_line and parm_insert_line reset the
655*7c478bd9Sstevel@tonic-gate  * cursor column to zero.  Therefore it is text_replace() responsiblity
656*7c478bd9Sstevel@tonic-gate  * to move the cursor to the correct column to begin the update.
657*7c478bd9Sstevel@tonic-gate  */
658*7c478bd9Sstevel@tonic-gate static void
lines_insert(int from,int to_1)659*7c478bd9Sstevel@tonic-gate lines_insert(int from, int to_1)
660*7c478bd9Sstevel@tonic-gate {
661*7c478bd9Sstevel@tonic-gate 	int	row;
662*7c478bd9Sstevel@tonic-gate 	int	count = to_1 - from;
663*7c478bd9Sstevel@tonic-gate 
664*7c478bd9Sstevel@tonic-gate 	/*
665*7c478bd9Sstevel@tonic-gate 	 * Position the cursor and insert a block of lines into the screen
666*7c478bd9Sstevel@tonic-gate 	 * image now, insert lines into the physical screen, then draw the
667*7c478bd9Sstevel@tonic-gate 	 * new screen lines.
668*7c478bd9Sstevel@tonic-gate 	 */
669*7c478bd9Sstevel@tonic-gate 	GOTO(from, 0);
670*7c478bd9Sstevel@tonic-gate 	(void) winsdelln(curscr, count);
671*7c478bd9Sstevel@tonic-gate 
672*7c478bd9Sstevel@tonic-gate 	if (parm_insert_line != NULL) {
673*7c478bd9Sstevel@tonic-gate 		/*
674*7c478bd9Sstevel@tonic-gate 		 * Assume that the sequence to insert more than one line is
675*7c478bd9Sstevel@tonic-gate 		 * faster than repeated single insert_lines.
676*7c478bd9Sstevel@tonic-gate 		 */
677*7c478bd9Sstevel@tonic-gate 		(void) TPUTS(tparm(parm_insert_line, (long)count,
678*7c478bd9Sstevel@tonic-gate 			0, 0, 0, 0, 0, 0, 0, 0), count, __m_outc);
679*7c478bd9Sstevel@tonic-gate 	} else if (insert_line != NULL) {
680*7c478bd9Sstevel@tonic-gate 		/*
681*7c478bd9Sstevel@tonic-gate 		 * For the single line insert we use to iterate moving
682*7c478bd9Sstevel@tonic-gate 		 * the cursor, inserting, and then drawing a line.  That
683*7c478bd9Sstevel@tonic-gate 		 * would appear to be slow but visually appealing.  However,
684*7c478bd9Sstevel@tonic-gate 		 * people on slow terminals want speed and those on fast
685*7c478bd9Sstevel@tonic-gate 		 * terminal won't see it.
686*7c478bd9Sstevel@tonic-gate 		 */
687*7c478bd9Sstevel@tonic-gate 		for (row = from; row < to_1; ++row)
688*7c478bd9Sstevel@tonic-gate 			(void) TPUTS(insert_line, 1, __m_outc);
689*7c478bd9Sstevel@tonic-gate 	} else {
690*7c478bd9Sstevel@tonic-gate 		/* Error -- what to do. */
691*7c478bd9Sstevel@tonic-gate 		return;
692*7c478bd9Sstevel@tonic-gate 	}
693*7c478bd9Sstevel@tonic-gate 
694*7c478bd9Sstevel@tonic-gate 	for (row = from; row < to_1; ++row)
695*7c478bd9Sstevel@tonic-gate 		text_replace(row);
696*7c478bd9Sstevel@tonic-gate }
697*7c478bd9Sstevel@tonic-gate 
698*7c478bd9Sstevel@tonic-gate static int
scroll_up(int n)699*7c478bd9Sstevel@tonic-gate scroll_up(int n)
700*7c478bd9Sstevel@tonic-gate {
701*7c478bd9Sstevel@tonic-gate 	int	count = n;
702*7c478bd9Sstevel@tonic-gate 	int	start, finish, to;
703*7c478bd9Sstevel@tonic-gate 
704*7c478bd9Sstevel@tonic-gate 	if (scroll_forward != NULL) {
705*7c478bd9Sstevel@tonic-gate 		GOTO(LINES-1, 0);
706*7c478bd9Sstevel@tonic-gate 		while (0 < n--)
707*7c478bd9Sstevel@tonic-gate 			(void) TPUTS(scroll_forward, 1, __m_outc);
708*7c478bd9Sstevel@tonic-gate 	} else if (parm_delete_line != NULL && 1 < n) {
709*7c478bd9Sstevel@tonic-gate 		GOTO(0, 0);
710*7c478bd9Sstevel@tonic-gate 		(void) TPUTS(tparm(parm_delete_line, (long)n,
711*7c478bd9Sstevel@tonic-gate 			0, 0, 0, 0, 0, 0, 0, 0), n, __m_outc);
712*7c478bd9Sstevel@tonic-gate 	} else if (delete_line != NULL) {
713*7c478bd9Sstevel@tonic-gate 		GOTO(0, 0);
714*7c478bd9Sstevel@tonic-gate 		while (0 < n--)
715*7c478bd9Sstevel@tonic-gate 			(void) TPUTS(delete_line, 1, __m_outc);
716*7c478bd9Sstevel@tonic-gate 	} else {
717*7c478bd9Sstevel@tonic-gate 		return (0);
718*7c478bd9Sstevel@tonic-gate 	}
719*7c478bd9Sstevel@tonic-gate 
720*7c478bd9Sstevel@tonic-gate 	/* Scroll recorded image. */
721*7c478bd9Sstevel@tonic-gate 	start = 0;
722*7c478bd9Sstevel@tonic-gate 	finish = count-1;
723*7c478bd9Sstevel@tonic-gate 	to = lines;
724*7c478bd9Sstevel@tonic-gate 
725*7c478bd9Sstevel@tonic-gate 	(void) __m_cc_erase(curscr, start, 0, finish, curscr->_maxx-1);
726*7c478bd9Sstevel@tonic-gate 	(void) __m_ptr_move((void **) curscr->_line,
727*7c478bd9Sstevel@tonic-gate 		curscr->_maxy, start, finish, to);
728*7c478bd9Sstevel@tonic-gate 
729*7c478bd9Sstevel@tonic-gate 	simple();
730*7c478bd9Sstevel@tonic-gate 
731*7c478bd9Sstevel@tonic-gate 	return (1);
732*7c478bd9Sstevel@tonic-gate }
733*7c478bd9Sstevel@tonic-gate 
734*7c478bd9Sstevel@tonic-gate #if 0
735*7c478bd9Sstevel@tonic-gate static int
736*7c478bd9Sstevel@tonic-gate scroll_dn(int n)
737*7c478bd9Sstevel@tonic-gate {
738*7c478bd9Sstevel@tonic-gate 	int	count = n;
739*7c478bd9Sstevel@tonic-gate 	int	start, finish, to;
740*7c478bd9Sstevel@tonic-gate 
741*7c478bd9Sstevel@tonic-gate 	if (LINES < n)
742*7c478bd9Sstevel@tonic-gate 		return (0);
743*7c478bd9Sstevel@tonic-gate 
744*7c478bd9Sstevel@tonic-gate 	if (scroll_reverse != NULL) {
745*7c478bd9Sstevel@tonic-gate 		GOTO(0, 0);
746*7c478bd9Sstevel@tonic-gate 		while (0 < n--)
747*7c478bd9Sstevel@tonic-gate 			(void) TPUTS(scroll_reverse, 1, __m_outc);
748*7c478bd9Sstevel@tonic-gate 	} else if (parm_insert_line != NULL && 1 < n) {
749*7c478bd9Sstevel@tonic-gate 		GOTO(0, 0);
750*7c478bd9Sstevel@tonic-gate 		(void) TPUTS(tparm(parm_insert_line, (long)n,
751*7c478bd9Sstevel@tonic-gate 			0, 0, 0, 0, 0, 0, 0, 0), n, __m_outc);
752*7c478bd9Sstevel@tonic-gate 	} else if (insert_line != NULL) {
753*7c478bd9Sstevel@tonic-gate 		GOTO(0, 0);
754*7c478bd9Sstevel@tonic-gate 		while (0 < n--)
755*7c478bd9Sstevel@tonic-gate 			(void) TPUTS(insert_line, 1, __m_outc);
756*7c478bd9Sstevel@tonic-gate 	} else {
757*7c478bd9Sstevel@tonic-gate 		return (0);
758*7c478bd9Sstevel@tonic-gate 	}
759*7c478bd9Sstevel@tonic-gate 
760*7c478bd9Sstevel@tonic-gate 	/* Scroll recorded image. */
761*7c478bd9Sstevel@tonic-gate 	start = lines - count;
762*7c478bd9Sstevel@tonic-gate 	finish = lines - 1;
763*7c478bd9Sstevel@tonic-gate 	to = 0;
764*7c478bd9Sstevel@tonic-gate 
765*7c478bd9Sstevel@tonic-gate 	(void) __m_cc_erase(curscr, start, 0, finish, curscr->_maxx-1);
766*7c478bd9Sstevel@tonic-gate 	(void) __m_ptr_move((void **) curscr->_line,
767*7c478bd9Sstevel@tonic-gate 		curscr->_maxy, start, finish, to);
768*7c478bd9Sstevel@tonic-gate 
769*7c478bd9Sstevel@tonic-gate 	simple();
770*7c478bd9Sstevel@tonic-gate 
771*7c478bd9Sstevel@tonic-gate 	return (1);
772*7c478bd9Sstevel@tonic-gate }
773*7c478bd9Sstevel@tonic-gate #endif
774*7c478bd9Sstevel@tonic-gate 
775*7c478bd9Sstevel@tonic-gate /*
776*7c478bd9Sstevel@tonic-gate  * Dynamic programming algorithm for the string edit problem.
777*7c478bd9Sstevel@tonic-gate  *
778*7c478bd9Sstevel@tonic-gate  * This is a modified Gosling cost algorithm that takes into account
779*7c478bd9Sstevel@tonic-gate  * null/move operations.
780*7c478bd9Sstevel@tonic-gate  *
781*7c478bd9Sstevel@tonic-gate  * Costs for move, delete, replace, and insert are 0, 1, 2, and 3
782*7c478bd9Sstevel@tonic-gate  * repectively.
783*7c478bd9Sstevel@tonic-gate  */
784*7c478bd9Sstevel@tonic-gate #define	MOVE_COST	0
785*7c478bd9Sstevel@tonic-gate #define	REPLACE_COST	10
786*7c478bd9Sstevel@tonic-gate #define	INSERT_COST	12
787*7c478bd9Sstevel@tonic-gate #define	DELETE_COST	1
788*7c478bd9Sstevel@tonic-gate 
789*7c478bd9Sstevel@tonic-gate static int
cost(int fr,int lr)790*7c478bd9Sstevel@tonic-gate cost(int fr, int lr)
791*7c478bd9Sstevel@tonic-gate {
792*7c478bd9Sstevel@tonic-gate 	lcost	*lcp;
793*7c478bd9Sstevel@tonic-gate 	int	or, nr, cc;
794*7c478bd9Sstevel@tonic-gate #if defined(_LP64)
795*7c478bd9Sstevel@tonic-gate 	unsigned int	*ohash = __m_screen->_hash;
796*7c478bd9Sstevel@tonic-gate #else
797*7c478bd9Sstevel@tonic-gate 	unsigned long	*ohash = __m_screen->_hash;
798*7c478bd9Sstevel@tonic-gate #endif
799*7c478bd9Sstevel@tonic-gate 
800*7c478bd9Sstevel@tonic-gate 	/*
801*7c478bd9Sstevel@tonic-gate 	 * Prepare initial row and column of cost matrix.
802*7c478bd9Sstevel@tonic-gate 	 *
803*7c478bd9Sstevel@tonic-gate 	 *	0 3 6 9 ...
804*7c478bd9Sstevel@tonic-gate 	 *	1
805*7c478bd9Sstevel@tonic-gate 	 *	2
806*7c478bd9Sstevel@tonic-gate 	 *	3
807*7c478bd9Sstevel@tonic-gate 	 *	:
808*7c478bd9Sstevel@tonic-gate 	 */
809*7c478bd9Sstevel@tonic-gate 	LC(fr, fr).cost = MOVE_COST;
810*7c478bd9Sstevel@tonic-gate 	for (cc = 1, ++lr, nr = fr+1; nr <= lr; ++nr, ++cc) {
811*7c478bd9Sstevel@tonic-gate 		/* Top row is 3, 6, 9, ... */
812*7c478bd9Sstevel@tonic-gate 		LC(fr, nr).cost = cc * INSERT_COST;
813*7c478bd9Sstevel@tonic-gate 		LC(fr, nr).op = 'i';
814*7c478bd9Sstevel@tonic-gate 
815*7c478bd9Sstevel@tonic-gate 		/* Left column is 1, 2, 3, ... */
816*7c478bd9Sstevel@tonic-gate 		LC(nr, fr).cost = cc * DELETE_COST;
817*7c478bd9Sstevel@tonic-gate 		LC(nr, fr).op = 'd';
818*7c478bd9Sstevel@tonic-gate 	}
819*7c478bd9Sstevel@tonic-gate 
820*7c478bd9Sstevel@tonic-gate 	for (--lr, or = fr; or <= lr; ++or) {
821*7c478bd9Sstevel@tonic-gate 		for (nr = fr; nr <= lr; ++nr) {
822*7c478bd9Sstevel@tonic-gate 			lcp = &LC(or + 1, nr + 1);
823*7c478bd9Sstevel@tonic-gate 
824*7c478bd9Sstevel@tonic-gate 			/* Assume move op. */
825*7c478bd9Sstevel@tonic-gate 			lcp->cost = LC(or, nr).cost;
826*7c478bd9Sstevel@tonic-gate 			lcp->op = 'm';
827*7c478bd9Sstevel@tonic-gate 
828*7c478bd9Sstevel@tonic-gate 			if (ohash[or] != nhash[nr]) {
829*7c478bd9Sstevel@tonic-gate 				/* Lines are different, assume replace op. */
830*7c478bd9Sstevel@tonic-gate 				lcp->cost += REPLACE_COST;
831*7c478bd9Sstevel@tonic-gate 				lcp->op = 'r';
832*7c478bd9Sstevel@tonic-gate 			}
833*7c478bd9Sstevel@tonic-gate 
834*7c478bd9Sstevel@tonic-gate 			/* Compare insert op. */
835*7c478bd9Sstevel@tonic-gate 			if ((cc = LC(or + 1, nr).cost + INSERT_COST) <
836*7c478bd9Sstevel@tonic-gate 				lcp->cost) {
837*7c478bd9Sstevel@tonic-gate 				lcp->cost = cc;
838*7c478bd9Sstevel@tonic-gate 				lcp->op = 'i';
839*7c478bd9Sstevel@tonic-gate 			}
840*7c478bd9Sstevel@tonic-gate 
841*7c478bd9Sstevel@tonic-gate 			/* Compare delete op. */
842*7c478bd9Sstevel@tonic-gate 			if ((cc = LC(or, nr + 1).cost + DELETE_COST) <
843*7c478bd9Sstevel@tonic-gate 				lcp->cost) {
844*7c478bd9Sstevel@tonic-gate 				lcp->cost = cc;
845*7c478bd9Sstevel@tonic-gate 				lcp->op = 'd';
846*7c478bd9Sstevel@tonic-gate 			}
847*7c478bd9Sstevel@tonic-gate 		}
848*7c478bd9Sstevel@tonic-gate 	}
849*7c478bd9Sstevel@tonic-gate 
850*7c478bd9Sstevel@tonic-gate 	return (LC(lr + 1, lr + 1).cost);
851*7c478bd9Sstevel@tonic-gate }
852*7c478bd9Sstevel@tonic-gate 
853*7c478bd9Sstevel@tonic-gate /*
854*7c478bd9Sstevel@tonic-gate  * Build edit script.
855*7c478bd9Sstevel@tonic-gate  *
856*7c478bd9Sstevel@tonic-gate  * Normally this would be a recursve routine doing the deletes, inserts,
857*7c478bd9Sstevel@tonic-gate  * and replaces on individual lines. Instead we build the script so that
858*7c478bd9Sstevel@tonic-gate  * we can later do the operations on a block basis.  For terminals with
859*7c478bd9Sstevel@tonic-gate  * parm_delete or parm_insert strings this will be better in terms of the
860*7c478bd9Sstevel@tonic-gate  * number of characters sent to delete and insert a block of lines.
861*7c478bd9Sstevel@tonic-gate  *
862*7c478bd9Sstevel@tonic-gate  * Also we can optimize the script so that tail inserts become replaces.
863*7c478bd9Sstevel@tonic-gate  * This saves unnecessary inserts operations when the tail can just be
864*7c478bd9Sstevel@tonic-gate  * overwritten.
865*7c478bd9Sstevel@tonic-gate  */
866*7c478bd9Sstevel@tonic-gate static void
script(int fr,int lr)867*7c478bd9Sstevel@tonic-gate script(int fr, int lr)
868*7c478bd9Sstevel@tonic-gate {
869*7c478bd9Sstevel@tonic-gate 	int	i, j;
870*7c478bd9Sstevel@tonic-gate 	cchar_t	*cp;
871*7c478bd9Sstevel@tonic-gate 
872*7c478bd9Sstevel@tonic-gate 	i = j = lr + 1;
873*7c478bd9Sstevel@tonic-gate 
874*7c478bd9Sstevel@tonic-gate 	(void) memset(del, 0, sizeof (*del) * LINES);
875*7c478bd9Sstevel@tonic-gate 	(void) memset(ins_rep, 0, sizeof (*ins_rep) * LINES);
876*7c478bd9Sstevel@tonic-gate 
877*7c478bd9Sstevel@tonic-gate 	do {
878*7c478bd9Sstevel@tonic-gate 		/*
879*7c478bd9Sstevel@tonic-gate 		 * We don't have to bounds check i or j becuase row fr and
880*7c478bd9Sstevel@tonic-gate 		 * column fr of lc have been preset in order to guarantee the
881*7c478bd9Sstevel@tonic-gate 		 * correct motion.
882*7c478bd9Sstevel@tonic-gate 		 */
883*7c478bd9Sstevel@tonic-gate 		switch (LC(i, j).op) {
884*7c478bd9Sstevel@tonic-gate 		case 'i':
885*7c478bd9Sstevel@tonic-gate 			--j;
886*7c478bd9Sstevel@tonic-gate 			ins_rep[j] = lines_insert;
887*7c478bd9Sstevel@tonic-gate 			break;
888*7c478bd9Sstevel@tonic-gate 		case 'd':
889*7c478bd9Sstevel@tonic-gate 			--i;
890*7c478bd9Sstevel@tonic-gate 			del[i] = lines_delete;
891*7c478bd9Sstevel@tonic-gate 			break;
892*7c478bd9Sstevel@tonic-gate 		case 'm':
893*7c478bd9Sstevel@tonic-gate 			--i;
894*7c478bd9Sstevel@tonic-gate 			--j;
895*7c478bd9Sstevel@tonic-gate 			break;
896*7c478bd9Sstevel@tonic-gate 		case 'r':
897*7c478bd9Sstevel@tonic-gate 			--i;
898*7c478bd9Sstevel@tonic-gate 			--j;
899*7c478bd9Sstevel@tonic-gate 			ins_rep[j] = lines_replace;
900*7c478bd9Sstevel@tonic-gate 			break;
901*7c478bd9Sstevel@tonic-gate 		}
902*7c478bd9Sstevel@tonic-gate 	} while (fr < i || fr < j);
903*7c478bd9Sstevel@tonic-gate 
904*7c478bd9Sstevel@tonic-gate 	/* Optimize Tail Inserts */
905*7c478bd9Sstevel@tonic-gate 	for (i = LINES-1; 0 <= i && ins_rep[i] == lines_insert; --i) {
906*7c478bd9Sstevel@tonic-gate 		/* Make each character in the screen line image invalid. */
907*7c478bd9Sstevel@tonic-gate 		for (cp = curscr->_line[i], j = 0; j < COLS; ++j, ++cp)
908*7c478bd9Sstevel@tonic-gate 			cp->_n = -1;
909*7c478bd9Sstevel@tonic-gate 		ins_rep[i] = lines_replace;
910*7c478bd9Sstevel@tonic-gate 	}
911*7c478bd9Sstevel@tonic-gate }
912*7c478bd9Sstevel@tonic-gate 
913*7c478bd9Sstevel@tonic-gate /*
914*7c478bd9Sstevel@tonic-gate  * Complex update algorithm using insert/delete line operations.
915*7c478bd9Sstevel@tonic-gate  *
916*7c478bd9Sstevel@tonic-gate  * References:
917*7c478bd9Sstevel@tonic-gate  * [MyM86]	E.W. Myers & W. Miller, Row Replacement Algorithms for
918*7c478bd9Sstevel@tonic-gate  *		Screen Editors, TR 86-19, Dept. Computer Science, U. of Arizona
919*7c478bd9Sstevel@tonic-gate  * [MyM87]	E.W. Myers & W. Miller, A Simple Row Replacement Method,
920*7c478bd9Sstevel@tonic-gate  *		TR 86-28, Dept. Computer Science, U. of Arizona
921*7c478bd9Sstevel@tonic-gate  * [Mil87]	W. Miller, A Software Tools Sampler, Prentice-Hall, 1987
922*7c478bd9Sstevel@tonic-gate  * [Gos81]	James Gosling, A redisplay algorithm, Proceedings of the
923*7c478bd9Sstevel@tonic-gate  *		ACM Symposium on Text Manipulation, SIGPLAN Notices,
924*7c478bd9Sstevel@tonic-gate  *		16(6) June 1981, pg 123-129
925*7c478bd9Sstevel@tonic-gate  *
926*7c478bd9Sstevel@tonic-gate  * All the above were reviewed and experimented with.  Due to the nature of
927*7c478bd9Sstevel@tonic-gate  * Curses' having to handling overlapping WINDOWs, the only suitable
928*7c478bd9Sstevel@tonic-gate  * algorithum is [Gos81].  The others are better suited to editor type
929*7c478bd9Sstevel@tonic-gate  * applications that have one window being the entire terminal screen.
930*7c478bd9Sstevel@tonic-gate  *
931*7c478bd9Sstevel@tonic-gate  */
932*7c478bd9Sstevel@tonic-gate static void
complex(void)933*7c478bd9Sstevel@tonic-gate complex(void)
934*7c478bd9Sstevel@tonic-gate {
935*7c478bd9Sstevel@tonic-gate 	int	fr = -1;
936*7c478bd9Sstevel@tonic-gate 	int	i, j, lr;
937*7c478bd9Sstevel@tonic-gate 	t_action	func;
938*7c478bd9Sstevel@tonic-gate 
939*7c478bd9Sstevel@tonic-gate 	/* Find block of lines to change */
940*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < LINES; ++i) {
941*7c478bd9Sstevel@tonic-gate 		if (newscr->_first[i] < newscr->_last[i]) {
942*7c478bd9Sstevel@tonic-gate 			/* Compute new hash. */
943*7c478bd9Sstevel@tonic-gate 			__m_cc_hash(newscr, nhash, i);
944*7c478bd9Sstevel@tonic-gate 			if (fr == -1)
945*7c478bd9Sstevel@tonic-gate 				fr = i;
946*7c478bd9Sstevel@tonic-gate 			lr = i;
947*7c478bd9Sstevel@tonic-gate 		} else {
948*7c478bd9Sstevel@tonic-gate 			/* Line not dirty so hash same as before. */
949*7c478bd9Sstevel@tonic-gate 			nhash[i] = __m_screen->_hash[i];
950*7c478bd9Sstevel@tonic-gate 		}
951*7c478bd9Sstevel@tonic-gate 	}
952*7c478bd9Sstevel@tonic-gate 
953*7c478bd9Sstevel@tonic-gate 	if (fr != -1) {
954*7c478bd9Sstevel@tonic-gate 		/* Gosling */
955*7c478bd9Sstevel@tonic-gate 		(void) cost(fr, lr);
956*7c478bd9Sstevel@tonic-gate 		script(fr, lr);
957*7c478bd9Sstevel@tonic-gate 
958*7c478bd9Sstevel@tonic-gate 		/* Do deletes first in reverse order. */
959*7c478bd9Sstevel@tonic-gate 		for (j = lr; fr <= j; --j) {
960*7c478bd9Sstevel@tonic-gate 			if (del[j] != (t_action) 0) {
961*7c478bd9Sstevel@tonic-gate 				for (i = j-1; fr <= i; --i)
962*7c478bd9Sstevel@tonic-gate 					if (del[i] == (t_action) 0)
963*7c478bd9Sstevel@tonic-gate 						break;
964*7c478bd9Sstevel@tonic-gate 
965*7c478bd9Sstevel@tonic-gate 				lines_delete(i+1, j+1);
966*7c478bd9Sstevel@tonic-gate 				j = i;
967*7c478bd9Sstevel@tonic-gate 			}
968*7c478bd9Sstevel@tonic-gate 		}
969*7c478bd9Sstevel@tonic-gate 
970*7c478bd9Sstevel@tonic-gate 		/* Do insert/replace in forward order. */
971*7c478bd9Sstevel@tonic-gate 		for (i = fr; i <= lr; ++i) {
972*7c478bd9Sstevel@tonic-gate 			if ((func = ins_rep[i]) != (t_action) 0) {
973*7c478bd9Sstevel@tonic-gate 				/* Find size of block */
974*7c478bd9Sstevel@tonic-gate 				for (j = i; j <= lr && ins_rep[j] == func; ++j)
975*7c478bd9Sstevel@tonic-gate 					;
976*7c478bd9Sstevel@tonic-gate 				(*func)(i, j);
977*7c478bd9Sstevel@tonic-gate 				i = j - 1;
978*7c478bd9Sstevel@tonic-gate 			}
979*7c478bd9Sstevel@tonic-gate 		}
980*7c478bd9Sstevel@tonic-gate 		/*
981*7c478bd9Sstevel@tonic-gate 		 * _line[], which contains pointers to screen lines,
982*7c478bd9Sstevel@tonic-gate 		 * may be shuffled.
983*7c478bd9Sstevel@tonic-gate 		 */
984*7c478bd9Sstevel@tonic-gate 		for (i = fr; i <= lr; ++i) {
985*7c478bd9Sstevel@tonic-gate 			/* Save new hash for next update. */
986*7c478bd9Sstevel@tonic-gate 			__m_screen->_hash[i] = nhash[i];
987*7c478bd9Sstevel@tonic-gate 
988*7c478bd9Sstevel@tonic-gate 			/* Mark line as untouched. */
989*7c478bd9Sstevel@tonic-gate 			newscr->_first[i] = newscr->_maxx;
990*7c478bd9Sstevel@tonic-gate 			newscr->_last[i] = -1;
991*7c478bd9Sstevel@tonic-gate 		}
992*7c478bd9Sstevel@tonic-gate 	}
993*7c478bd9Sstevel@tonic-gate }
994*7c478bd9Sstevel@tonic-gate 
995*7c478bd9Sstevel@tonic-gate /*
996*7c478bd9Sstevel@tonic-gate  * Simple screen update algorithm
997*7c478bd9Sstevel@tonic-gate  *
998*7c478bd9Sstevel@tonic-gate  * We perform a simple incremental update of the terminal screen.
999*7c478bd9Sstevel@tonic-gate  * Only the segment of a line that was touched is replaced on the
1000*7c478bd9Sstevel@tonic-gate  * line.
1001*7c478bd9Sstevel@tonic-gate  */
1002*7c478bd9Sstevel@tonic-gate static void
simple(void)1003*7c478bd9Sstevel@tonic-gate simple(void)
1004*7c478bd9Sstevel@tonic-gate {
1005*7c478bd9Sstevel@tonic-gate 	int row;
1006*7c478bd9Sstevel@tonic-gate 
1007*7c478bd9Sstevel@tonic-gate 	for (row = 0; row < newscr->_maxy; ++row) {
1008*7c478bd9Sstevel@tonic-gate 		if (newscr->_first[row] < newscr->_last[row]) {
1009*7c478bd9Sstevel@tonic-gate 			text_replace(row);
1010*7c478bd9Sstevel@tonic-gate 
1011*7c478bd9Sstevel@tonic-gate 			/* Mark line as untouched. */
1012*7c478bd9Sstevel@tonic-gate 			newscr->_first[row] = newscr->_maxx;
1013*7c478bd9Sstevel@tonic-gate 			newscr->_last[row] = -1;
1014*7c478bd9Sstevel@tonic-gate 			__m_cc_hash(curscr, __m_screen->_hash, row);
1015*7c478bd9Sstevel@tonic-gate 		}
1016*7c478bd9Sstevel@tonic-gate 	}
1017*7c478bd9Sstevel@tonic-gate 
1018*7c478bd9Sstevel@tonic-gate 	newscr->_flags &= ~W_REDRAW_WINDOW;
1019*7c478bd9Sstevel@tonic-gate }
1020*7c478bd9Sstevel@tonic-gate 
1021*7c478bd9Sstevel@tonic-gate void
wtouchln_hard(WINDOW * w,int y,int n)1022*7c478bd9Sstevel@tonic-gate wtouchln_hard(WINDOW *w, int y, int n)
1023*7c478bd9Sstevel@tonic-gate {
1024*7c478bd9Sstevel@tonic-gate 	int	last;
1025*7c478bd9Sstevel@tonic-gate 
1026*7c478bd9Sstevel@tonic-gate 	last = w->_maxx;
1027*7c478bd9Sstevel@tonic-gate 
1028*7c478bd9Sstevel@tonic-gate 	for (; (y < w->_maxy) && (0 < n); ++y, --n) {
1029*7c478bd9Sstevel@tonic-gate 		/*
1030*7c478bd9Sstevel@tonic-gate 		 * Force compare in doupdate to fail.
1031*7c478bd9Sstevel@tonic-gate 		 * Touch should be unconditional
1032*7c478bd9Sstevel@tonic-gate 		 */
1033*7c478bd9Sstevel@tonic-gate (void) memset(&__m_screen->_curscr->_line[w->_begy + y][w->_begx],
1034*7c478bd9Sstevel@tonic-gate 	0xff, last * sizeof (cchar_t));
1035*7c478bd9Sstevel@tonic-gate 	}
1036*7c478bd9Sstevel@tonic-gate }
1037*7c478bd9Sstevel@tonic-gate /*
1038*7c478bd9Sstevel@tonic-gate  * Send all changes made to _newscr to the physical terminal.
1039*7c478bd9Sstevel@tonic-gate  *
1040*7c478bd9Sstevel@tonic-gate  * If idlok() is set TRUE then doupdate will try and use hardware insert
1041*7c478bd9Sstevel@tonic-gate  * and delete line sequences in an effort to optimize output.  idlok()
1042*7c478bd9Sstevel@tonic-gate  * should really only be used in applications that want a proper scrolling
1043*7c478bd9Sstevel@tonic-gate  * effect.
1044*7c478bd9Sstevel@tonic-gate  *
1045*7c478bd9Sstevel@tonic-gate  * Added scroll heuristic to handle special case where a full size window
1046*7c478bd9Sstevel@tonic-gate  * with full size scroll region, will scroll the window and replace dirty
1047*7c478bd9Sstevel@tonic-gate  * lines instead of performing usual cost/script operations.
1048*7c478bd9Sstevel@tonic-gate  */
1049*7c478bd9Sstevel@tonic-gate int
doupdate(void)1050*7c478bd9Sstevel@tonic-gate doupdate(void)
1051*7c478bd9Sstevel@tonic-gate {
1052*7c478bd9Sstevel@tonic-gate #ifdef SIGTSTP
1053*7c478bd9Sstevel@tonic-gate 	int (*oldsig)(int) = signal(SIGTSTP, SIG_IGN);
1054*7c478bd9Sstevel@tonic-gate #endif
1055*7c478bd9Sstevel@tonic-gate 
1056*7c478bd9Sstevel@tonic-gate 	if (pollTypeahead()) {
1057*7c478bd9Sstevel@tonic-gate 		return (OK);
1058*7c478bd9Sstevel@tonic-gate 	}
1059*7c478bd9Sstevel@tonic-gate 	newscr = __m_screen->_newscr;
1060*7c478bd9Sstevel@tonic-gate 
1061*7c478bd9Sstevel@tonic-gate 	if (__m_screen->_flags & S_ENDWIN) {
1062*7c478bd9Sstevel@tonic-gate 		/* Return from temporary escape done with endwin(). */
1063*7c478bd9Sstevel@tonic-gate 		__m_screen->_flags &= ~S_ENDWIN;
1064*7c478bd9Sstevel@tonic-gate 
1065*7c478bd9Sstevel@tonic-gate 		(void) reset_prog_mode();
1066*7c478bd9Sstevel@tonic-gate 		if (enter_ca_mode != NULL)
1067*7c478bd9Sstevel@tonic-gate 			(void) TPUTS(enter_ca_mode, 1, __m_outc);
1068*7c478bd9Sstevel@tonic-gate 		if (keypad_xmit != NULL)
1069*7c478bd9Sstevel@tonic-gate 			(void) TPUTS(keypad_xmit, 1, __m_outc);
1070*7c478bd9Sstevel@tonic-gate 		if (ena_acs != NULL)
1071*7c478bd9Sstevel@tonic-gate 			(void) TPUTS(ena_acs, 1, __m_outc);
1072*7c478bd9Sstevel@tonic-gate 
1073*7c478bd9Sstevel@tonic-gate 		/* Force redraw of screen. */
1074*7c478bd9Sstevel@tonic-gate 		newscr->_flags |= W_CLEAR_WINDOW;
1075*7c478bd9Sstevel@tonic-gate 	}
1076*7c478bd9Sstevel@tonic-gate 	/*
1077*7c478bd9Sstevel@tonic-gate 	 * When redrawwing a window, we not only assume that line
1078*7c478bd9Sstevel@tonic-gate 	 * noise may have lost characters, but line noise may have
1079*7c478bd9Sstevel@tonic-gate 	 * generated bogus characters on the screen outside the
1080*7c478bd9Sstevel@tonic-gate 	 * the window in question, in which case redraw the entire
1081*7c478bd9Sstevel@tonic-gate 	 * screen to be sure.
1082*7c478bd9Sstevel@tonic-gate 	 */
1083*7c478bd9Sstevel@tonic-gate 	if ((newscr->_flags & (W_CLEAR_WINDOW | W_REDRAW_WINDOW)) ||
1084*7c478bd9Sstevel@tonic-gate 		(curscr->_flags & W_CLEAR_WINDOW)) {
1085*7c478bd9Sstevel@tonic-gate 		erase_bottom(0, newscr->_maxy);
1086*7c478bd9Sstevel@tonic-gate 		clear_bottom(0);
1087*7c478bd9Sstevel@tonic-gate 		(void) wtouchln(newscr, 0, newscr->_maxy, 1);
1088*7c478bd9Sstevel@tonic-gate 		newscr->_flags &= ~W_CLEAR_WINDOW;
1089*7c478bd9Sstevel@tonic-gate 		curscr->_flags &= ~W_CLEAR_WINDOW;
1090*7c478bd9Sstevel@tonic-gate 	}
1091*7c478bd9Sstevel@tonic-gate 
1092*7c478bd9Sstevel@tonic-gate 	/*
1093*7c478bd9Sstevel@tonic-gate 	 * Scrolling heuristic should only be used if lines being
1094*7c478bd9Sstevel@tonic-gate 	 * scrolled are clean because scrolling overrides updates
1095*7c478bd9Sstevel@tonic-gate 	 *
1096*7c478bd9Sstevel@tonic-gate 	 * Right now, the following code should always turn off
1097*7c478bd9Sstevel@tonic-gate 	 * scrolling, because the internal scroll touches the
1098*7c478bd9Sstevel@tonic-gate 	 * scrolled lines. This thing requires a lot more care
1099*7c478bd9Sstevel@tonic-gate 	 * than I have right now...
1100*7c478bd9Sstevel@tonic-gate 	 */
1101*7c478bd9Sstevel@tonic-gate 	if (newscr->_scroll) {
1102*7c478bd9Sstevel@tonic-gate 		int	y;
1103*7c478bd9Sstevel@tonic-gate 		for (y = 0; y < newscr->_maxy; ++y) {
1104*7c478bd9Sstevel@tonic-gate 			if (0 <= newscr->_last[y]) {
1105*7c478bd9Sstevel@tonic-gate 				newscr->_scroll = 0;
1106*7c478bd9Sstevel@tonic-gate 			}
1107*7c478bd9Sstevel@tonic-gate 		}
1108*7c478bd9Sstevel@tonic-gate 		newscr->_scroll = 0;	/* Just fudge it for now ... */
1109*7c478bd9Sstevel@tonic-gate 	}
1110*7c478bd9Sstevel@tonic-gate 	if (newscr->_flags & W_REDRAW_WINDOW) {
1111*7c478bd9Sstevel@tonic-gate 		simple();
1112*7c478bd9Sstevel@tonic-gate 	} else {
1113*7c478bd9Sstevel@tonic-gate 		if (newscr->_scroll == 0) {
1114*7c478bd9Sstevel@tonic-gate 			if (__m_screen->_flags & S_INS_DEL_LINE) {
1115*7c478bd9Sstevel@tonic-gate 				complex();
1116*7c478bd9Sstevel@tonic-gate 			} else {
1117*7c478bd9Sstevel@tonic-gate 				simple();
1118*7c478bd9Sstevel@tonic-gate 			}
1119*7c478bd9Sstevel@tonic-gate 		} else {
1120*7c478bd9Sstevel@tonic-gate 			if (!scroll_up(newscr->_scroll)) {
1121*7c478bd9Sstevel@tonic-gate 				if (__m_screen->_flags & S_INS_DEL_LINE) {
1122*7c478bd9Sstevel@tonic-gate 					complex();
1123*7c478bd9Sstevel@tonic-gate 				} else {
1124*7c478bd9Sstevel@tonic-gate 					simple();
1125*7c478bd9Sstevel@tonic-gate 				}
1126*7c478bd9Sstevel@tonic-gate 			}
1127*7c478bd9Sstevel@tonic-gate 		}
1128*7c478bd9Sstevel@tonic-gate 	}
1129*7c478bd9Sstevel@tonic-gate 
1130*7c478bd9Sstevel@tonic-gate 	if (!(newscr->_flags & W_LEAVE_CURSOR))	{
1131*7c478bd9Sstevel@tonic-gate 		GOTO(newscr->_cury, newscr->_curx);
1132*7c478bd9Sstevel@tonic-gate 	}
1133*7c478bd9Sstevel@tonic-gate 
1134*7c478bd9Sstevel@tonic-gate 	if (!(curscr->_flags & W_FLUSH)) {
1135*7c478bd9Sstevel@tonic-gate 		(void) fflush(__m_screen->_of);
1136*7c478bd9Sstevel@tonic-gate 	}
1137*7c478bd9Sstevel@tonic-gate 
1138*7c478bd9Sstevel@tonic-gate 	newscr->_scroll = curscr->_scroll = 0;
1139*7c478bd9Sstevel@tonic-gate 
1140*7c478bd9Sstevel@tonic-gate 	/* Send labels to terminal that supports them. */
1141*7c478bd9Sstevel@tonic-gate 	__m_slk_doupdate();
1142*7c478bd9Sstevel@tonic-gate #ifdef SIGTSTP
1143*7c478bd9Sstevel@tonic-gate 	signal(SIGTSTP, oldsig);
1144*7c478bd9Sstevel@tonic-gate #endif
1145*7c478bd9Sstevel@tonic-gate 
1146*7c478bd9Sstevel@tonic-gate 	return (OK);
1147*7c478bd9Sstevel@tonic-gate }
1148*7c478bd9Sstevel@tonic-gate 
1149*7c478bd9Sstevel@tonic-gate /*
1150*7c478bd9Sstevel@tonic-gate  * If true, the implementation may use hardware insert and delete,
1151*7c478bd9Sstevel@tonic-gate  * character features of the terminal.  The window parameter
1152*7c478bd9Sstevel@tonic-gate  * is ignored.
1153*7c478bd9Sstevel@tonic-gate  */
1154*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1155*7c478bd9Sstevel@tonic-gate void
idcok(WINDOW * w,bool bf)1156*7c478bd9Sstevel@tonic-gate idcok(WINDOW *w, bool bf)
1157*7c478bd9Sstevel@tonic-gate {
1158*7c478bd9Sstevel@tonic-gate 	__m_screen->_flags &= ~S_INS_DEL_CHAR;
1159*7c478bd9Sstevel@tonic-gate 	if (bf)
1160*7c478bd9Sstevel@tonic-gate 		__m_screen->_flags |= S_INS_DEL_CHAR;
1161*7c478bd9Sstevel@tonic-gate }
1162*7c478bd9Sstevel@tonic-gate 
1163*7c478bd9Sstevel@tonic-gate /*
1164*7c478bd9Sstevel@tonic-gate  * If true, the implementation may use hardware insert, delete,
1165*7c478bd9Sstevel@tonic-gate  * and scroll line features of the terminal.  The window parameter
1166*7c478bd9Sstevel@tonic-gate  * is ignored.
1167*7c478bd9Sstevel@tonic-gate  */
1168*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1169*7c478bd9Sstevel@tonic-gate int
idlok(WINDOW * w,bool bf)1170*7c478bd9Sstevel@tonic-gate idlok(WINDOW *w, bool bf)
1171*7c478bd9Sstevel@tonic-gate {
1172*7c478bd9Sstevel@tonic-gate 	__m_screen->_flags &= ~S_INS_DEL_LINE;
1173*7c478bd9Sstevel@tonic-gate 	if (bf && has_il())
1174*7c478bd9Sstevel@tonic-gate 		__m_screen->_flags |= S_INS_DEL_LINE;
1175*7c478bd9Sstevel@tonic-gate 
1176*7c478bd9Sstevel@tonic-gate 	return (OK);
1177*7c478bd9Sstevel@tonic-gate }
1178*7c478bd9Sstevel@tonic-gate 
1179*7c478bd9Sstevel@tonic-gate /*
1180*7c478bd9Sstevel@tonic-gate  * Use the POSIX 32-bit CRC function to compute a hash value
1181*7c478bd9Sstevel@tonic-gate  * for the window line.
1182*7c478bd9Sstevel@tonic-gate  */
1183*7c478bd9Sstevel@tonic-gate void
1184*7c478bd9Sstevel@tonic-gate #if defined(_LP64)
__m_cc_hash(WINDOW * w,unsigned int * array,int y)1185*7c478bd9Sstevel@tonic-gate __m_cc_hash(WINDOW *w, unsigned int *array, int y)
1186*7c478bd9Sstevel@tonic-gate #else
1187*7c478bd9Sstevel@tonic-gate __m_cc_hash(WINDOW *w, unsigned long *array, int y)
1188*7c478bd9Sstevel@tonic-gate #endif
1189*7c478bd9Sstevel@tonic-gate {
1190*7c478bd9Sstevel@tonic-gate 	array[y] = 0;
1191*7c478bd9Sstevel@tonic-gate 	m_crcposix(&array[y], (unsigned char *) w->_line[y],
1192*7c478bd9Sstevel@tonic-gate 		(size_t)(w->_maxx * sizeof (**w->_line)));
1193*7c478bd9Sstevel@tonic-gate }
1194