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