xref: /illumos-gate/usr/src/lib/libcurses/screen/wrefresh.c (revision 89b2a9fbeabf42fa54594df0e5927bcc50a07cc9)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1988 AT&T	*/
28 /*	  All Rights Reserved	*/
29 
30 /*
31  * University Copyright- Copyright (c) 1982, 1986, 1988
32  * The Regents of the University of California
33  * All Rights Reserved
34  *
35  * University Acknowledgment- Portions of this document are derived from
36  * software developed by the University of California, Berkeley, and its
37  * contributors.
38  */
39 
40 #pragma ident	"%Z%%M%	%I%	%E% SMI"
41 
42 /*LINTLIBRARY*/
43 
44 #include	<sys/types.h>
45 #include	<stdlib.h>
46 #include	<string.h>
47 #include	"curses_inc.h"
48 
49 /*
50  * Make the screen look like "win" over the area covered by win.
51  * This routine may use insert/delete char/line and scrolling-region.
52  * win : the window being updated
53  */
54 
55 extern int	outchcount;
56 
57 static void	_updateln(int), _turn_off_background(void),
58 		_setmark1(int, int, chtype *),
59 		_setmark2(int, int, chtype *), _rmargin(int),
60 		_useceod(int, int);
61 static int	_useidch(chtype *, chtype *, int, int, int *),
62 		_prefix(chtype *, chtype *, int, int, int *),
63 		_getceod(int, int);
64 
65 static	short	cy, cx,		/* current cursor coord */
66 		scrli,		/* actual screen lines */
67 		scrco;		/* actual screen columns */
68 static	char	**marks;	/* the mark table for cookie terminals */
69 static	char	**color_marks;	/* color mark table for cookie terminals */
70 
71 #define	_ISMARK1(y, x)	(marks[y][x / BITSPERBYTE] & (1 << (x % BITSPERBYTE)))
72 #define	_ISMARK2(y, x)	(color_marks ? (color_marks[y][x / BITSPERBYTE] & \
73 			(1 << (x % BITSPERBYTE))) : FALSE)
74 
75 #define	_VIDEO(c)	((c) & A_ATTRIBUTES & ~A_COLOR)
76 #define	_COLOR(c)	((c) & A_COLOR)
77 
78 #ifdef	_VR2_COMPAT_CODE
79 extern	char	_endwin;
80 #endif	/* _VR2_COMPAT_CODE */
81 
82 int
83 wrefresh(WINDOW *win)
84 {
85 
86 	short	*bnsch, *ensch;
87 	SLK_MAP	*slk;
88 	int	wx, wy, nc, boty, clby, idby, *hs, curwin;
89 
90 	curwin = (win == curscr);
91 
92 	/* don't allow curscr refresh if the screen was just created */
93 
94 	if (curwin && curscr->_sync)
95 		return (OK);
96 
97 	/* go thru _stdbody */
98 	if (!curwin && (win != _virtscr))
99 		(void) wnoutrefresh(win);
100 
101 	/* if there is typeahead */
102 	if ((_INPUTPENDING = _chkinput()) == TRUE) {
103 		if (curwin)
104 			curscr->_clear = TRUE;
105 		return (OK);
106 	}
107 
108 	if (curwin || curscr->_clear)
109 		_virtscr->_clear = TRUE;
110 
111 	/* save curscr cursor coordinates */
112 	cy = curscr->_cury;
113 	cx = curscr->_curx;
114 
115 	/* to simplify code in some cases */
116 	marks = _MARKS;
117 	color_marks = _COLOR_MARKS;
118 	scrli = curscr->_maxy;
119 	scrco = curscr->_maxx;
120 	slk = SP->slk;
121 
122 	outchcount = 0;
123 
124 	/* make sure we're in program mode */
125 	if (SP->fl_endwin) {
126 		/* If endwin is equal to 2 it means we just did a newscreen. */
127 		if (SP->fl_endwin == TRUE) {
128 			(void) reset_prog_mode();
129 			if (SP->kp_state)
130 				(void) tputs(keypad_xmit, 1, _outch);
131 			if (slk)
132 				(*_do_slk_tch)();
133 			if (SP->fl_meta)
134 				(void) tputs(meta_on, 1, _outch);
135 			if (cur_term->_cursorstate != 1)
136 				_PUTS(cur_term->cursor_seq[cur_term->
137 				    _cursorstate], 0);
138 		}
139 		_PUTS(enter_ca_mode, 1);
140 		(void) tputs(ena_acs, 1, _outch);
141 
142 		if (exit_attribute_mode)
143 			_PUTS(tparm_p0(exit_attribute_mode), 1);
144 		else
145 			/*
146 			 * If there is no exit_attribute mode, then vidupdate
147 			 * could only possibly turn off one of the below three
148 			 * so that's all we ask it turn off.
149 			*/
150 			vidupdate(A_NORMAL, (A_ALTCHARSET | A_STANDOUT |
151 			    A_UNDERLINE), _outch);
152 
153 		SP->fl_endwin = FALSE;
154 
155 #ifdef	_VR2_COMPAT_CODE
156 		_endwin = (char) FALSE;
157 #endif	/* _VR2_COMPAT_CODE */
158 	}
159 
160 	/* clear the screen if required */
161 	if (_virtscr->_clear) {
162 /* SS: colors */
163 		if (back_color_erase)
164 			_turn_off_background();
165 
166 		_PUTS(clear_screen, scrli);
167 		cy = cx = curscr->_curx = curscr->_cury = 0;
168 
169 		/* _sync indicates that this a new screen */
170 		if (!curscr->_sync)
171 			(void) werase(curscr);
172 		else {
173 			nc = scrco / BITSPERBYTE - (scrco %
174 			    BITSPERBYTE ? 0 : 1);
175 			wy = scrli - 1;
176 			bnsch = _BEGNS; ensch = _ENDNS;
177 			hs = _CURHASH;
178 			for (; wy >= 0; --wy) {
179 				*bnsch++ = scrco;
180 				*ensch++ = -1;
181 				*hs++ = 0;
182 				if (marks)
183 					for (wx = nc; wx >= 0; --wx)
184 						marks[wy][wx] = 0;
185 			}
186 		}
187 
188 		_virtscr->_clear = curscr->_sync = curscr->_clear = FALSE;
189 		if (slk)
190 			(*_do_slk_tch)();
191 
192 		/* pretend _virtscr has been totally changed */
193 		(void) wtouchln(_virtscr, 0, scrli, -1);
194 		_VIRTTOP = 0;
195 		_VIRTBOT = scrli - 1;
196 
197 		/* will not do clear-eod or ins/del lines */
198 		clby = idby = scrli;
199 	} else
200 		clby = idby = -1;
201 
202 	/* Software soft labels; if _changed == 2, slk's are in clear mode. */
203 	if (slk && slk->_win && (slk->_changed == TRUE))
204 		(*_do_slk_noref)();
205 
206 	/* do line updating */
207 	_virtscr->_clear = FALSE;
208 	wy = _VIRTTOP;
209 	boty = _VIRTBOT + 1;
210 	bnsch = _virtscr->_firstch + wy;
211 	ensch = _virtscr->_lastch + wy;
212 
213 	for (; wy < boty; ++wy, ++bnsch, ++ensch) {
214 		/* this line is up-to-date */
215 		if (*bnsch >= scrco)
216 			goto next;
217 
218 		/* there is type-ahead */
219 		if (!curwin && (_INPUTPENDING = _chkinput()) == TRUE) {
220 			/* LINTED */
221 			_VIRTTOP = (short) wy;
222 			goto done;
223 		}
224 
225 		if (clby < 0) {
226 			/* now we have to work, check for ceod */
227 			clby = _getceod(wy, boty);
228 
229 			/* check for insert/delete lines */
230 			if (_virtscr->_use_idl)
231 				idby = (*_setidln)();
232 		}
233 
234 		/* try clear-to-eod */
235 		if (wy == clby)
236 			_useceod(wy, boty);
237 
238 		/* try ins/del lines */
239 		if (wy == idby) {
240 			curscr->_cury = cy;
241 			curscr->_curx = cx;
242 			(*_useidln)();
243 			cy = curscr->_cury;
244 			cx = curscr->_curx;
245 		}
246 
247 		if (*bnsch < scrco)
248 			_updateln(wy);
249 
250 next:
251 		*bnsch = _INFINITY;
252 		*ensch = -1;
253 	}
254 
255 	/* do hardware soft labels; if _changed == 2, */
256 	/* slk's are in clear mode. */
257 	if (slk && (slk->_changed == TRUE) && !(slk->_win))
258 		(*_do_slk_ref)();
259 
260 	/* move cursor */
261 	wy = _virtscr->_cury;
262 	wx = _virtscr->_curx;
263 	if (wy != cy || wx != cx) {
264 		(void) mvcur(cy, cx, wy, wx);
265 		/* LINTED */
266 		cy = (short) wy;
267 		/* LINTED */
268 		cx = (short) wx;
269 	}
270 
271 	/* reset the flags */
272 	curscr->_clear = FALSE;
273 	_virtscr->_use_idl = FALSE;
274 	_virtscr->_use_idc = TRUE;
275 	_INPUTPENDING = FALSE;
276 
277 	/* virtual image is now up-to-date */
278 	_VIRTTOP = scrli;
279 	_VIRTBOT = -1;
280 
281 done :
282 	curscr->_cury = cy;
283 	curscr->_curx = cx;
284 	(void) fflush(SP->term_file);
285 	return (outchcount);
286 }
287 
288 /* Shift appropriate portions of a line to leave space for cookies. */
289 
290 static	chtype	*
291 _shove(int wy)
292 {
293 	chtype		*wcp, *cp, prev;
294 	short		curx;
295 	int		x, cury, didshift;
296 	static	chtype	*line;
297 	static	int	length;
298 
299 	/* allocate space for shifted line */
300 	if (length < scrco) {
301 		if (line)
302 			free((char *) line);
303 		line = (chtype *) malloc(scrco * sizeof (chtype));
304 		length = line ? scrco : 0;
305 	}
306 
307 	/* no space to do it */
308 	if (!line)
309 		return (_virtscr->_y[wy]);
310 
311 	prev = A_NORMAL;
312 	cp = line;
313 	wcp = _virtscr->_y[wy];
314 	curx = _virtscr->_curx;
315 	cury = _virtscr->_cury;
316 	didshift = FALSE;
317 
318 	for (x = 0; x < scrco; ++x, ++wcp, ++cp) {
319 		if (_ATTR(*wcp) != prev) {
320 			/* use existing blank */
321 			if (_CHAR(*wcp) == ' ')
322 				*cp = ' ' | _ATTR(*(wcp + 1));
323 				/* use previous blank */
324 			else
325 				if ((x > 0) && _CHAR(*(cp - 1)) == ' ') {
326 					*(cp - 1) = ' ' | _ATTR(*wcp);
327 					*cp = *wcp;
328 				} else {
329 					if ((curx >= x) && (cury == wy))
330 						++curx;
331 					*cp = ' ' | _ATTR(*wcp);
332 					--wcp;
333 					didshift = TRUE;
334 				}
335 			prev = _ATTR(*cp);
336 		} else
337 			*cp = *wcp;
338 	}
339 
340 	/* make sure that the end of the line is normal */
341 	cp = line + scrco - 1;
342 	if (didshift || (_ATTR(*cp) != A_NORMAL) ||
343 	    ((wy == scrli - 1) && (_ATTR(*(cp - 1)) != A_NORMAL))) {
344 		*cp = didshift ? ' ' : _CHAR(*cp);
345 		if (wy == scrli - 1)
346 			*(cp - 1) = didshift ? ' ' : _CHAR(*(cp - 1));
347 	}
348 
349 	if (wy == cury)
350 		_virtscr->_curx = curx >= scrco ? scrco - 1 : curx;
351 
352 	return (line);
353 }
354 
355 /*
356  * Update a line.
357  * Three schemes of coloring are allowed. The first is the usual
358  * pen-up/pen-down model. The second is the HP26*-like model.
359  * In this case, colorings are specified by intervals, the left
360  * side of the interval has the coloring mark, the right side
361  * has the end-coloring mark. We assume that clear sequences will
362  * clear ALL marks in the affected regions. The second case is
363  * signified by the boolean flag ceol_standout_glitch.
364  * The third case is for terminals that leave visible cookies on
365  * the screen. This last case is at most an approximation of what
366  * can be done right.
367  */
368 
369 static	void
370 _updateln(int wy)
371 {
372 	chtype	*wcp, *scp, *wp, *sp, wc, sc;
373 	int	wx, lastx, x, mtch, idch, blnkx, idcx, video_attrx,
374 		color_attrx, maxi, endns, begns, wx_sav, multi_col;
375 	bool	redraw, changed, didcolor, didvideo;
376 
377 	redraw = (_virtscr->_firstch[wy] == _REDRAW);
378 	endns = _ENDNS[wy];
379 	begns = _BEGNS[wy];
380 
381 	/* easy case */
382 	if (!redraw && (_virtscr->_lastch[wy] == _BLANK) && (begns >= scrco))
383 		return;
384 
385 	/* line images */
386 	wcp = magic_cookie_glitch <= 0 ? _virtscr->_y[wy] : _shove(wy);
387 	scp = curscr->_y[wy];
388 
389 	/* the interval to be updated */
390 	if (redraw || magic_cookie_glitch >= 0) {
391 		wx = 0;
392 		lastx = scrco;
393 	} else {
394 		wx = _virtscr->_firstch[wy];
395 		lastx = _virtscr->_lastch[wy] == _BLANK ? scrco :
396 		    _virtscr->_lastch[wy] + 1;
397 	}
398 
399 	/* skip equal parts */
400 	if (!redraw) {
401 		/* skip the starting equal part */
402 		wp = wcp + wx;
403 		sp = scp + wx;
404 		for (; wx < lastx; ++wx)
405 			if (*wp++ != *sp++)
406 				break;
407 		if (wx >= lastx)
408 			return;
409 
410 		/* start update at an entire character */
411 		for (sp = scp+wx, wp = wcp+wx; wp > wcp; --wp, --sp, --wx)
412 			if (!ISCBIT(*wp) && !ISCBIT(*sp))
413 				break;
414 
415 		/* skip the ending equal part */
416 		wp = wcp + lastx - 1;
417 		sp = scp + lastx - 1;
418 		for (; lastx > wx; --lastx)
419 			if (*wp-- != *sp--)
420 				break;
421 		++wp;
422 		++wp;
423 		++sp;
424 		++sp;
425 		for (; lastx < scrco; ++wp, ++sp, ++lastx)
426 			if (!ISCBIT(*wp) && !ISCBIT(*sp))
427 				break;
428 	}
429 
430 	/* place to do clear-eol */
431 	if (!clr_eol || endns >= lastx)
432 		blnkx = scrco;
433 	else
434 		if (_virtscr->_lastch[wy] == _BLANK)
435 			blnkx = -1;
436 		else {
437 			for (blnkx = lastx - 1, wp = wcp + blnkx;
438 			    blnkx >= wx; --blnkx, --wp)
439 				if (_DARKCHAR(*wp))
440 					break;
441 			for (sp = scp + blnkx + 1; blnkx < scrco - 1;
442 			    ++sp, ++blnkx)
443 				if (!ISCBIT(*sp))
444 					break;
445 			if (blnkx + _COST(Clr_eol) >= lastx)
446 				blnkx = scrco;
447 		}
448 
449 	/* on cookie terminals, we may need to do more work */
450 	if (marks) {
451 		/* video_attrx = color_attrx = scrco; */
452 		video_attrx = color_attrx = (lastx >= scrco) ? lastx - 1 :
453 		    lastx;
454 
455 		/* find the last video attribute on the line	*/
456 
457 		wp = wcp + video_attrx;
458 		for (; video_attrx >= wx; --video_attrx, --wp)
459 			if (_VIDEO(*wp) != A_NORMAL)
460 				break;
461 
462 		/* find the last color attribute on the line	*/
463 
464 		if (color_marks) {
465 			wp = wcp + color_attrx;
466 			for (; color_attrx >= wx; --color_attrx, --wp)
467 				if (_COLOR(*wp) != A_NORMAL)
468 					break;
469 			if (color_attrx < lastx)
470 				color_attrx++;
471 		}
472 		if (video_attrx < lastx)
473 			video_attrx++;
474 
475 		if (video_attrx >= scrco)
476 			--video_attrx;
477 		if (color_marks && color_attrx >= scrco)
478 			--color_attrx;
479 		if (magic_cookie_glitch > 0 && wy == scrli - 1 &&
480 		    video_attrx == scrco - 1)
481 			--video_attrx;
482 		if (color_marks && magic_cookie_glitch > 0 &&
483 		    wy == scrli - 1 && color_attrx == scrco - 1)
484 			--color_attrx;
485 		for (wp = wcp+video_attrx; wp >= wcp+wx; --wp)
486 			if (!ISCBIT(*wp))
487 				break;
488 	}
489 
490 	/* place for insert/delete chars */
491 #define	SLACK	4
492 	if (redraw || (!SP->dchok && !SP->ichok) || !(_virtscr->_use_idc) ||
493 	    endns < wx || (endns >= lastx && (scrco - lastx) > SLACK)) {
494 		idcx = scrco;
495 	} else
496 		if (!marks)
497 			idcx = -1;
498 		else {
499 			/* on cookie term, only do idch where no attrs */
500 			/* are used */
501 			for (idcx = scrco - 1, wp = wcp + idcx; idcx >= wx;
502 			    --idcx, --wp)
503 				if (_ATTR(*wp) || _ISMARK1(wy, idcx) ||
504 				    _ISMARK2(wy, idcx))
505 					break;
506 			if (idcx >= scrco - SLACK)
507 				idcx = scrco;
508 		}
509 
510 	if (idcx < lastx && endns >= lastx)
511 		lastx = scrco;
512 
513 	/* max amount of insert allow */
514 	if (idcx == scrco || !SP->ichok)
515 		maxi = 0;
516 	else
517 		if (lastx == scrco)
518 			maxi = scrco;
519 		else
520 			maxi = lastx - (endns + 1);
521 
522 	/* go */
523 	wcp += wx;
524 	scp += wx;
525 	didvideo = changed = FALSE;
526 	didcolor = (color_marks) ? FALSE : TRUE;
527 
528 	while (wx < lastx) {
529 		/* skip things that are already right */
530 		if (!redraw) {
531 			multi_col = 0;
532 			wx_sav = wx;
533 			for (; wx < lastx; ++wx, ++wcp, ++scp)
534 				if (*wcp != *scp)
535 					break;
536 			if (wx >= lastx)
537 				goto done;
538 			for (; wx > wx_sav; --wx, --wcp, --scp) {
539 				if (!ISCBIT(*wcp) && !ISCBIT(*scp))
540 					break;
541 				multi_col = 1;
542 			}
543 		}
544 
545 		/* try clear-bol, we'll assume exclusive clr_bol */
546 		if (!changed && !marks && clr_bol && blnkx > wx &&
547 		    begns >= wx) {
548 			for (x = wx, wp = wcp; x < lastx; ++x, ++wp)
549 				if (_DARKCHAR(*wp))
550 					break;
551 			/* clearing only whole screen characters */
552 			for (sp = scp+(x-wx); x >= wx; --x, --sp)
553 				if (!ISCBIT(*sp))
554 					break;
555 			x -= 1;
556 
557 			if ((x - (redraw ? 0 : begns)) > _COST(Clr_bol)) {
558 				(void) mvcur(cy, cx, wy, x);
559 				/* MORE?: colors - mvcur will shuts of */
560 				/* colors when msgr is not defined */
561 
562 /* SS: colors */
563 				if (back_color_erase)
564 					_turn_off_background();
565 
566 				_PUTS(clr_bol, 1);
567 				/* LINTED */
568 				cy = (short) wy;
569 				/* LINTED */
570 				cx = (short) x;
571 
572 				mtch = x - wx;
573 				(void) memcpy((char *) scp, (char *) wcp,
574 				    (mtch * sizeof (chtype)));
575 				wcp += mtch;
576 				scp += mtch;
577 				wx = x;
578 			}
579 		}
580 
581 		/* screen image is changing */
582 		changed = TRUE;
583 
584 		/* move to the point to start refresh */
585 		if (cy != wy || cx != wx)
586 			(void) mvcur(cy, cx, wy, wx);
587 		/* LINTED */
588 		cy = (short) wy;
589 		/* LINTED */
590 		cx = (short) wx;
591 
592 		/* update screen image */
593 		while (wx < lastx) {
594 			wc = *wcp;
595 			sc = *scp;
596 
597 			if (!redraw && !multi_col && wc == sc)
598 				break;
599 
600 			/* real video attributes */
601 			if (marks)
602 				curscr->_attrs = _ATTR(sc);
603 
604 			/* blanks only */
605 			if (wx > blnkx) {
606 /* SS: colors */
607 				if (back_color_erase)
608 					_turn_off_background();
609 
610 				_PUTS(clr_eol, 1);
611 				/* LINTED */
612 				curscr->_curx = (short) wx;
613 		 		/* LINTED */
614 				curscr->_cury = (short) wy;
615 				(void) wclrtoeol(curscr);
616 
617 				if (marks && wx > 0 && _ATTR(*(scp - 1)) !=
618 				    A_NORMAL) {
619 					_VIDS(A_NORMAL, _ATTR(*(scp - 1)));
620 					if (_VIDEO(*scp - 1))
621 						_setmark1(wy, wx, NULL);
622 					if (_COLOR(*scp - 1))
623 						_setmark2(wy, wx, NULL);
624 				}
625 				goto done;
626 			}
627 
628 			/* try insert/delete chars */
629 			if (wx > idcx && !ISCBIT(*scp) &&
630 			    (mtch = _useidch(wcp, scp, lastx - wx,
631 			    maxi, &idch))) {
632 				maxi -= idch;
633 				wx += mtch;
634 				scp += mtch;
635 				wcp += mtch;
636 				break;
637 			}
638 
639 			/* about to output chars, make sure insert */
640 			/* mode is off */
641 			if (SP->phys_irm)
642 				_OFFINSERT();
643 
644 			/* color and video attributes */
645 			if (_ATTR(wc) != curscr->_attrs) {
646 			    bool  color_change = FALSE;
647 			    bool  video_change = FALSE;
648 
649 			    if (marks)
650 				if (_VIDEO(wc) != _VIDEO(curscr->_attrs))
651 					video_change = TRUE;
652 				if (color_marks)
653 				    if (_COLOR(wc) != _COLOR(curscr->_attrs))
654 					color_change = TRUE;
655 
656 				/* the following may occurs when, for */
657 				/* example the application */
658 				/* is written for color terminal and then */
659 				/* run on a monocrome  */
660 
661 				if (marks && !video_change && !color_change)
662 					goto no_change;
663 
664 				/* prevent spilling out of line */
665 				if (marks && !(didcolor && didvideo)) {
666 				    if ((video_change && !_ISMARK1(wy,
667 					video_attrx)) || (color_change &&
668 					!_ISMARK2(wy, color_attrx))) {
669 					    int    tempx;
670 					    chtype sa = curscr->_attrs;
671 					    bool   first  = FALSE;
672 					    bool   second = FALSE;
673 
674 					    if (!didvideo && video_change &&
675 						!_ISMARK1(wy, video_attrx)) {
676 						didvideo = TRUE;
677 						(void) mvcur(wy, wx,
678 						    wy, video_attrx);
679 						_VIDS(_VIDEO(_virtscr->_y[wy]
680 						    [video_attrx]),
681 						    _VIDEO(_virtscr->_y[wy]
682 						    [video_attrx-1]));
683 						_setmark1(wy, video_attrx,
684 						    NULL);
685 						first = TRUE;
686 					    }
687 
688 				if (!didcolor && color_change &&
689 				    !_ISMARK2(wy, color_attrx)) {
690 					didcolor = TRUE;
691 					tempx = first ? video_attrx : wx;
692 					if (tempx != color_attrx)
693 						(void) mvcur(wy, tempx, wy,
694 						    color_attrx);
695 				/*
696 				 * sc = _COLOR(curscr->_y[wy][color_attrx]);
697 				 *_VIDS(sc, (~sc & A_COLOR));
698 				*/
699 					_VIDS(_COLOR(_virtscr->_y[wy]
700 					    [color_attrx]),
701 					    _COLOR(_virtscr->_y[wy]
702 					    [color_attrx-1]));
703 					_setmark2(wy, color_attrx, NULL);
704 					second = TRUE;
705 				}
706 				(void) mvcur(wy, (second ? color_attrx :
707 				    video_attrx), wy, wx);
708 				curscr->_attrs = sa;
709 			    }
710 			}
711 
712 			_VIDS(_ATTR(wc), curscr->_attrs);
713 
714 			/* on cookie terminals mark the interval */
715 			if (video_change)
716 				_setmark1(wy, wx, scp);
717 			if (color_change)
718 				_setmark2(wy, wx, scp);
719 		}
720 
721 		/* end-of-line */
722 no_change:
723 		x = 1;
724 		if (_scrmax > 1)
725 			x = _curs_scrwidth[TYPE(RBYTE(wc))];
726 		if (wx == scrco - x) {
727 			_rmargin(wx);
728 			goto done;
729 		}
730 
731 		if (transparent_underline && erase_overstrike &&
732 		    _CHAR(wc) == '_') {
733 			(void) _outch(' ');
734 			(void) mvcur(wy, wx + 1, wy, wx);
735 		}
736 
737 		/* put out the character */
738 		(void) _outwch(tilde_glitch && _CHAR(wc) == '~' ? '`' : wc);
739 
740 		*scp++ = wc;
741 		wcp++;
742 		wx++;
743 		cx++;
744 		/* output entire multi-byte chars */
745 		while (wx < lastx && ISCBIT(*wcp)) {
746 			(void) _outwch(*wcp);
747 			*scp++ = *wcp++;
748 			wx++;
749 			cx++;
750 
751 
752 
753 
754 		}
755 		}
756 	}
757 
758 done:
759 	if (changed) {
760 		/* update the blank structure */
761 		for (wx = 0, scp = curscr->_y[wy]; wx < scrco; ++wx, ++scp)
762 			if (_DARKCHAR(*scp))
763 				break;
764 		/* LINTED */
765 		_BEGNS[wy] = (short) wx;
766 		if (wx == scrco)
767 			_ENDNS[wy] = -1;
768 		else {
769 			wx = scrco - 1;
770 			scp = curscr->_y[wy] + wx;
771 			for (; wx >= 0; --wx, --scp)
772 				if (_DARKCHAR(*scp))
773 					break;
774 			/* LINTED */
775 			_ENDNS[wy] = (short) wx;
776 		}
777 
778 		/* update the hash structure */
779 		_CURHASH[wy] = _BEGNS[wy] < scrco ? _NOHASH : 0;
780 	}
781 }
782 
783 /*
784  * See if a left or right shift is apppropriate
785  * This routine is called only if !cookie_glitch or no video attributes
786  * are used in the affected part.
787  * The main idea is to find a longest common substring which is a
788  * prefix of one of 'wcp' or 'scp', then either delete or
789  * insert depending on where the prefix is.
790  *
791  * wcp : what we want the screen to look like
792  * scp : what the screen looks like now
793  * length: the length to be updated
794  * maxi: maximum possible insert amount
795  * id; *id returns the amount of insert/delete
796  *
797  * Return the number of chars matched after the shift.
798  */
799 
800 static int
801 _useidch(chtype *wcp, chtype *scp, int length, int maxi, int *id)
802 {
803 	int	x1, x2, blnk, idch, cost, cost_ich1, match;
804 	chtype	wc;
805 
806 	/* try deletion */
807 	if (SP->dchok && _CHAR(*wcp) != ' ') {
808 		if ((match = _prefix(wcp, scp, length, length / 2, &idch)) > 0)
809 			cost = _COST(dcfixed) + (parm_dch ? _COST(Parm_dch) :
810 			    _COST(Delete_character) * idch);
811 		else
812 			cost = _INFINITY;
813 
814 		if (match >= cost) {
815 /* SS: colors */
816 			if (back_color_erase)
817 				_turn_off_background();
818 
819 			if (SP->dmode) {
820 				if (SP->sid_equal) {
821 					if (!(SP->phys_irm))
822 						_ONINSERT();
823 				} else {
824 					if (SP->phys_irm)
825 						_OFFINSERT();
826 					_PUTS(enter_delete_mode, 1);
827 				}
828 			}
829 
830 			if (parm_dch)
831 				_PUTS(tparm_p1(parm_dch, idch), 1);
832 			else
833 				for (x1 = 0; x1 < idch; ++x1)
834 					_PUTS(delete_character, 1);
835 
836 			if (SP->dmode) {
837 				if (SP->eid_equal)
838 					SP->phys_irm = FALSE;
839 				_PUTS(exit_delete_mode, 1);
840 			}
841 
842 			/* update screen image */
843 			for (x1 = 0, x2 = idch; x2 < length; ++x1, ++x2)
844 				scp[x1] = scp[x2];
845 			for (; x1 < length; ++x1)
846 				scp[x1] = ' ';
847 
848 			*id = -idch;
849 			return (match);
850 		}
851 	}
852 
853 	/* no insertion wanted or possible */
854 	if (!(SP->ichok) || _CHAR(*scp) == ' ')
855 		return (0);
856 
857 	/* see if insertion is worth it */
858 	maxi = (idch = length / 2) < maxi ? idch : maxi;
859 	if ((match = _prefix(scp, wcp, length, maxi, &idch)) <= 0)
860 		return (0);
861 
862 	/* see if inserting blanks only */
863 	for (blnk = 0; blnk < idch; ++blnk)
864 		if (wcp[blnk] != ' ') {
865 			blnk = 0;
866 			break;
867 		}
868 
869 	/* see if doing insertion is worth it */
870 	cost_ich1 = idch * _COST(Insert_character);
871 	if (SP->imode) {
872 		cost = SP->phys_irm ? 0 : _COST(icfixed);
873 		if (blnk > _COST(Parm_ich) && _COST(Parm_ich) < cost_ich1)
874 			cost += _COST(Parm_ich);
875 		else
876 			if (insert_character)
877 				cost += cost_ich1;
878 	} else {
879 		if (parm_ich && _COST(Parm_ich) < cost_ich1)
880 			cost = _COST(Parm_ich);
881 		else
882 			cost = cost_ich1;
883 	}
884 	if ((cost - blnk) > match)
885 		return (0);
886 
887 	/* perform the insertions */
888 
889 	/* SS: colors */
890 	if (back_color_erase)
891 		_turn_off_background();
892 
893 	if (SP->imode) {
894 		if (!SP->phys_irm)
895 			_ONINSERT();
896 		if (blnk > _COST(Parm_ich) && _COST(Parm_ich) < cost_ich1)
897 			_PUTS(tparm_p1(parm_ich, idch), 1);
898 		else
899 			if (insert_character)
900 				goto do_insert_char;
901 			else
902 				/* so that we'll do real char insertions */
903 				blnk = 0;
904 	} else {
905 		if (parm_ich && _COST(Parm_ich) < cost_ich1)
906 			_PUTS(tparm_p1(parm_ich, idch), 1);
907 		else {
908 do_insert_char:
909 			for (x1 = 0; x1 < idch; ++x1)
910 				_PUTS(insert_character, 1);
911 		}
912 	}
913 
914 	/* inserting desired characters */
915 	if (!blnk)
916 		for (x1 = 0; x1 < idch; ++x1) {
917 			wc = wcp[x1];
918 			if (_ATTR(wc) != curscr->_attrs)
919 				_VIDS(_ATTR(wc), curscr->_attrs);
920 			(void) _outwch(_CHAR(wc) == '~' &&
921 			    tilde_glitch ? '`' : wc);
922 			++cx;
923 		}
924 
925 	/* update the screen image */
926 	for (x1 = length - 1, x2 = length - idch - 1; x2 >= 0; --x1, --x2)
927 		scp[x1] = scp[x2];
928 	(void) memcpy((char *) scp, (char *) wcp, idch * sizeof (chtype));
929 
930 	*id = idch;
931 	return (match + idch);
932 }
933 
934 /*
935  * Find a substring of s2 that match a prefix of s1.
936  * The substring is such that:
937  * 	1. it does not start with an element
938  *	   that is in perfect alignment with one in s1 and
939  * 	2: it is at least as long as the displacement.
940  *
941  * length: the length of s1, s2.
942  * maxs: only search for match in [1,maxs]  of s2.
943  * begm: *begm returns where the match begins.
944  *
945  * Return the number of matches.
946  */
947 
948 static int
949 _prefix(chtype *s1, chtype *s2, int length, int maxs, int *begm)
950 {
951 	int	m, n, k;
952 
953 	n = 0;
954 	for (m = 1; m <= maxs; ++m)
955 		/* testing for s1[m] != s2[m] is condition 1 */
956 		if (s1[0] == s2[m] && s1[m] != s2[m]) {
957 			/* see if it's long enough (condition 2) */
958 			for (k = 2 * m - 1; k > m; --k)
959 				if (s1[k - m] != s2[k])
960 					break;
961 			/* found a match with a good length */
962 			if (k == m) {
963 				*begm = m;
964 
965 				/* count the # of matches */
966 				s2 += m;
967 				length -= m;
968 				for (n = m; n < length; ++n)
969 					if (s1[n] != s2[n])
970 						break;
971 				goto done;
972 			}
973 		}
974 
975 done:
976 	return (n);
977 }
978 
979 /* Set video markers for cookie terminal. */
980 
981 static void
982 _setmark1(int y, int x, chtype *s)
983 {
984 	long	a;
985 
986 	/* set the mark map */
987 	marks[y][x / BITSPERBYTE] |= (1 << (x % BITSPERBYTE));
988 
989 	if (s) {
990 		a  = _VIDEO(curscr->_attrs);
991 
992 		/* set the video attr of the first char here */
993 		/* LINTED */
994 		*s = _CHAR(*s) | _COLOR(*s) | a;
995 
996 		/* now the video attr of the rest of the affected interval */
997 		for (x += 1, s += 1; x < scrco; ++x, ++s)
998 			if (_ISMARK1(y, x))
999 				break;
1000 			else
1001 				/* LINTED */
1002 				*s = _CHAR(*s) | _COLOR(*s) | a;
1003 	}
1004 }
1005 
1006 /* Set color markers for cookie terminal. */
1007 
1008 static void
1009 _setmark2(int y, int x, chtype *s)
1010 {
1011 	long	a;
1012 
1013 	/* set the mark map */
1014 	color_marks[y][x / BITSPERBYTE] |= (1 << (x % BITSPERBYTE));
1015 
1016 	if (s) {
1017 		a  = _COLOR(curscr->_attrs);
1018 
1019 		/* set the video attr of the first char here */
1020 		/* LINTED */
1021 		*s = _CHAR(*s) | _VIDEO(*s) | a;
1022 
1023 		/* now the video attr of the rest of the affected interval */
1024 		for (x += 1, s += 1; x < scrco; ++x, ++s)
1025 			if (_ISMARK2(y, x))
1026 				break;
1027 			else
1028 				/* LINTED */
1029 				*s = _CHAR(*s) | _VIDEO(*s) | a;
1030 	}
1031 }
1032 
1033 
1034 /* At the right margin various weird things can happen.  We treat them here. */
1035 
1036 /* At the right margin various weird things can happen.  We treat them here. */
1037 
1038 static void
1039 _rmargin(int wx)
1040 {
1041 	int	x, w, ix;
1042 	chtype	sc;
1043 	chtype	*wcp =	_virtscr->_y[cy];
1044 
1045 	/* screen may scroll */
1046 	if (cy == scrli - 1) {
1047 		/* can't do anything */
1048 		if (!SP->ichok)
1049 			return;
1050 
1051 		/* the width of the new character */
1052 		w = _curs_scrwidth[TYPE(RBYTE(wcp[wx]))];
1053 		/* the place to put it without causing scrolling */
1054 		for (x = wx - 1; x > 0; --x)
1055 			if (!ISCBIT(wcp[x]))
1056 				break;
1057 		sc = curscr->_y[cy][x];
1058 
1059 		(void) mvcur(cy, cx, cy, x);
1060 		if (_ATTR(wcp[wx]) != curscr->_attrs)
1061 			_VIDS(_ATTR(wcp[wx]), curscr->_attrs);
1062 		(void) _outwch(tilde_glitch &&
1063 		    _CHAR(wcp[wx]) == '~' ? '`' : wcp[wx]);
1064 
1065 		for (ix = wx + 1; ix < scrco; ++ix) {
1066 			(void) _outwch(wcp[ix]);
1067 		}
1068 
1069 		/* insert sc back in and push wcp[wx] right */
1070 		(void) mvcur(cy, x+w, cy, x);
1071 
1072 		/* SS: colors */
1073 		if (back_color_erase)
1074 			_turn_off_background();
1075 
1076 		if (SP->imode && !SP->phys_irm)
1077 			_ONINSERT();
1078 		/* width of the old character that was overwritten */
1079 		w = _curs_scrwidth[TYPE(RBYTE(curscr->_y[cy][x]))];
1080 
1081 		if (insert_character)
1082 			for (ix = 0; ix < w; ++ix)
1083 				_PUTS(insert_character, 1);
1084 		else
1085 			if (parm_ich && !SP->imode)
1086 				_PUTS(tparm_p1(parm_ich, w), 1);
1087 
1088 		if (_ATTR(sc) != curscr->_attrs)
1089 			_VIDS(_ATTR(sc), curscr->_attrs);
1090 		for (ix = x; w > 0; --w, ++ix)
1091 			(void) _outwch(curscr->_y[cy][ix]);
1092 
1093 		/* make sure the video attrs are ok */
1094 		if (marks && (_ATTR(sc) || _ATTR(wcp[wx])))
1095 			_VIDS(_ATTR(wcp[wx]), ~_ATTR(sc));
1096 
1097 		/* update screen image */
1098 		/* LINTED */
1099 		cx = (short) wx;
1100 		curscr->_y[cy][wx] = wcp[wx];
1101 		for (x = wx + 1; x < scrco; ++x) {
1102 			(void) _outwch(wcp[x]);
1103 			curscr->_y[cy][x] = wcp[x];
1104 		}
1105 		return;
1106 	}
1107 
1108 	/* put char out and update screen image */
1109 	(void) _outwch(tilde_glitch && _CHAR(wcp[wx]) == '~' ? '`' : wcp[wx]);
1110 
1111 
1112 
1113 
1114 
1115 
1116 
1117 
1118 	curscr->_y[cy][wx] = wcp[wx];
1119 
1120 	for (x = wx + 1; x < scrco; ++x) {
1121 		(void) _outwch(wcp[x]);
1122 		curscr->_y[cy][x] = wcp[x];
1123 	}
1124 
1125 	/* make sure that wrap-around happens */
1126 	if (!auto_right_margin || eat_newline_glitch) {
1127 		(void) _outch('\r');
1128 		(void) _outch('\n');
1129 	}
1130 	cx = 0;
1131 	++cy;
1132 }
1133 
1134 /*
1135  * Find the top-most line to do clear-to-eod.
1136  *
1137  * topy, boty: the region to consider
1138  */
1139 
1140 static int
1141 _getceod(int topy, int boty)
1142 {
1143 	chtype	*wcp, *ecp;
1144 	int	wy;
1145 	short	*begch, *endch, *begns;
1146 
1147 	/* do nothing */
1148 	if ((topy + 1) >= boty)
1149 		return (boty);
1150 
1151 	wy = boty - 1;
1152 	begch = _virtscr->_firstch + wy;
1153 	endch = _virtscr->_lastch + wy;
1154 	begns = _BEGNS + wy;
1155 
1156 	for (; wy >= topy; --wy, --begch, --endch, --begns) {
1157 		if (*endch == _BLANK || (*begch >= scrco && *begns >= scrco))
1158 			continue;
1159 
1160 		wcp = _virtscr->_y[wy];
1161 		ecp = wcp + scrco;
1162 		for (; wcp < ecp; ++wcp)
1163 			if (_DARKCHAR(*wcp))
1164 			break;
1165 		if (wcp != ecp)
1166 			break;
1167 
1168 		*endch = _BLANK;
1169 	}
1170 
1171 	return (wy + 1);
1172 }
1173 
1174 /* Use hardware clear-to-bottom. */
1175 
1176 static void
1177 _useceod(int topy, int boty)
1178 {
1179 	short	*begns, *begch;
1180 
1181 	/* skip lines already blanked */
1182 	begch = _virtscr->_firstch + topy;
1183 	begns = _BEGNS + topy;
1184 	for (; topy < boty; ++topy, ++begns, ++begch)
1185 		if (*begns < scrco || *begch == _REDRAW)
1186 			break;
1187 		else
1188 			*begch = _INFINITY;
1189 
1190 	/* nothing to do */
1191 	if (topy + 1 >= boty)
1192 		return;
1193 
1194 	/* see if bottom is clear */
1195 	for (begns = _BEGNS + boty; boty < scrli; ++boty, ++begns)
1196 		if (*begns < scrco)
1197 			return;
1198 
1199 	/* use clear-screen if appropriate */
1200 	if (topy == 0) {
1201 		/* SS: colors */
1202 		if (back_color_erase)
1203 			_turn_off_background();
1204 
1205 		_PUTS(clear_screen, scrli);
1206 		cy = 0; cx = 0;
1207 		(void) werase(curscr);
1208 	} else
1209 
1210 		/* use clear-to-end-of-display or delete lines */
1211 		if (clr_eos || (parm_delete_line && !memory_below)) {
1212 			(void) mvcur(cy, cx, topy, 0);
1213 			/* LINTED */
1214 			cy = (short) topy;
1215 			cx = 0;
1216 			/* SS: colors */
1217 			if (back_color_erase)
1218 				_turn_off_background();
1219 			_PUTS(clr_eos ? clr_eos : tparm_p1(parm_delete_line,
1220 			    scrli - topy), scrli - topy);
1221 
1222 			/* update curscr */
1223 			/* LINTED */
1224 			curscr->_cury = (short) topy;
1225 			curscr->_curx = 0;
1226 			(void) wclrtobot(curscr);
1227 		} else
1228 			/* no hardware support */
1229 			return;
1230 
1231 		/* correct the update structure */
1232 		(void) wtouchln(_virtscr, topy, scrli, FALSE);
1233 }
1234 
1235 
1236 static void
1237 _turn_off_background(void)
1238 {
1239 	/* this routine turn the background color to zero.  This need to be */
1240 	/* done only in forllowing cases:				*/
1241 	/*  1) We are using Tek type terminal (which has bce terminfo	*/
1242 	/*	variable)  */
1243 	/*  2) The current background is not already zero		*/
1244 
1245 	if (set_background && cur_term->_cur_pair.background > 0) {
1246 		_PUTS(orig_pair, 1);
1247 		cur_term->_cur_pair.foreground = -1;
1248 		cur_term->_cur_pair.background = -1;
1249 		curscr->_attrs &= ~A_COLOR;
1250 	}
1251 }
1252