xref: /csrg-svn/lib/libcurses/refresh.c (revision 56715)
12261Sarnold /*
234677Sbostic  * Copyright (c) 1981 Regents of the University of California.
334677Sbostic  * All rights reserved.
434677Sbostic  *
542657Sbostic  * %sccs.include.redist.c%
622791Smckusick  */
722791Smckusick 
822791Smckusick #ifndef lint
9*56715Selan static char sccsid[] = "@(#)refresh.c	5.23 (Berkeley) 11/11/92";
1034677Sbostic #endif /* not lint */
1122791Smckusick 
1255976Sbostic #include <curses.h>
1355986Sbostic #include <string.h>
142261Sarnold 
1555976Sbostic static int curwin;
1655976Sbostic static short ly, lx;
172261Sarnold 
1855976Sbostic WINDOW *_win;
192261Sarnold 
2055976Sbostic static void	domvcur __P((int, int, int, int));
2155976Sbostic static int	makech __P((WINDOW *, int));
2256302Selan static void	quickch __P((WINDOW *));
2356559Selan static void	scrolln __P((WINDOW *, int, int, int, int, int));
2456648Selan 
2555976Sbostic /*
2655976Sbostic  * wrefresh --
2755976Sbostic  *	Make the current screen look like "win" over the area coverd by
2855976Sbostic  *	win.
2955976Sbostic  */
3055976Sbostic int
312261Sarnold wrefresh(win)
3255976Sbostic 	register WINDOW *win;
332261Sarnold {
3456648Selan 	register __LINE *wlp;
3555976Sbostic 	register int retval;
3655976Sbostic 	register short wy;
372261Sarnold 
3855976Sbostic 	/* Make sure were in visual state. */
3955976Sbostic 	if (__endwin) {
4055976Sbostic 		tputs(VS, 0, __cputchar);
4155976Sbostic 		tputs(TI, 0, __cputchar);
4255976Sbostic 		__endwin = 0;
432261Sarnold 	}
442287Sarnold 
4555976Sbostic 	/* Initialize loop parameters. */
462287Sarnold 
4756238Selan 	ly = curscr->cury;
4856238Selan 	lx = curscr->curx;
492287Sarnold 	wy = 0;
502287Sarnold 	_win = win;
512287Sarnold 	curwin = (win == curscr);
522287Sarnold 
5356378Selan 	if (!curwin)
5456378Selan 		for (wy = 0; wy < win->maxy; wy++) {
5556378Selan 			wlp = win->lines[wy];
5656378Selan 			if (wlp->flags & __ISDIRTY)
5756648Selan 				wlp->hash =
5856648Selan 				   __hash(wlp->line, win->maxx * __LDATASIZE);
5956378Selan 		}
6056378Selan 
6156238Selan 	if (win->flags & __CLEAROK || curscr->flags & __CLEAROK || curwin) {
6256238Selan 		if ((win->flags & __FULLWIN) || curscr->flags & __CLEAROK) {
6355976Sbostic 			tputs(CL, 0, __cputchar);
6412358Sarnold 			ly = 0;
6512358Sarnold 			lx = 0;
6612358Sarnold 			if (!curwin) {
6756238Selan 				curscr->flags &= ~__CLEAROK;
6856238Selan 				curscr->cury = 0;
6956238Selan 				curscr->curx = 0;
702287Sarnold 				werase(curscr);
7112358Sarnold 			}
7256651Selan 			__touchwin(win);
732261Sarnold 		}
7456238Selan 		win->flags &= ~__CLEAROK;
752261Sarnold 	}
762261Sarnold 	if (!CA) {
7756238Selan 		if (win->curx != 0)
7855976Sbostic 			putchar('\n');
792287Sarnold 		if (!curwin)
802287Sarnold 			werase(curscr);
812261Sarnold 	}
8255976Sbostic #ifdef DEBUG
8355976Sbostic 	__TRACE("wrefresh: (%0.2o): curwin = %d\n", win, curwin);
8455976Sbostic 	__TRACE("wrefresh: \tfirstch\tlastch\n");
8555976Sbostic #endif
8656302Selan 
8756302Selan #ifndef NOQCH
8856378Selan 	if (!__noqch && (win->flags & __FULLWIN) && !curwin)
8956302Selan     		quickch(win);
9056302Selan #endif
9156238Selan 	for (wy = 0; wy < win->maxy; wy++) {
9255976Sbostic #ifdef DEBUG
9355976Sbostic 		__TRACE("%d\t%d\t%d\n",
94*56715Selan 		    wy, *win->lines[wy]->firstchp, *win->lines[wy]->lastchp);
9555976Sbostic #endif
9656378Selan 		if (!curwin)
9756378Selan 			curscr->lines[wy]->hash = win->lines[wy]->hash;
9856651Selan 		if (win->lines[wy]->flags & __ISDIRTY ||
9956651Selan 		    win->lines[wy]->flags & __FORCEPAINT)
1002261Sarnold 			if (makech(win, wy) == ERR)
10155976Sbostic 				return (ERR);
10219893Sbloom 			else {
103*56715Selan 				if (*win->lines[wy]->firstchp >= win->ch_off)
104*56715Selan 					*win->lines[wy]->firstchp = win->maxx +
10556238Selan 					    win->ch_off;
106*56715Selan 				if (*win->lines[wy]->lastchp < win->maxx +
10756238Selan 				    win->ch_off)
108*56715Selan 					*win->lines[wy]->lastchp = win->ch_off;
109*56715Selan 				if (*win->lines[wy]->lastchp <
110*56715Selan 				    *win->lines[wy]->firstchp)
11156238Selan 					win->lines[wy]->flags &= ~__ISDIRTY;
11219893Sbloom 			}
11355976Sbostic #ifdef DEBUG
114*56715Selan 		__TRACE("\t%d\t%d\n", *win->lines[wy]->firstchp,
115*56715Selan 			*win->lines[wy]->lastchp);
11655976Sbostic #endif
1172261Sarnold 	}
11856238Selan 
11956302Selan #ifdef DEBUG
12056238Selan 	__TRACE("refresh: ly=%d, lx=%d\n", ly, lx);
12156302Selan #endif
12256472Selan 
12312358Sarnold 	if (win == curscr)
12456238Selan 		domvcur(ly, lx, win->cury, win->curx);
12519893Sbloom 	else {
12656238Selan 		if (win->flags & __LEAVEOK) {
12756238Selan 			curscr->cury = ly;
12856238Selan 			curscr->curx = lx;
12956238Selan 			ly -= win->begy;
13056238Selan 			lx -= win->begx;
13156238Selan 			if (ly >= 0 && ly < win->maxy && lx >= 0 &&
13256238Selan 			    lx < win->maxx) {
13356238Selan 				win->cury = ly;
13456238Selan 				win->curx = lx;
13555976Sbostic 			} else
13656238Selan 				win->cury = win->curx = 0;
13755976Sbostic 		} else {
13856238Selan 			domvcur(ly, lx, win->cury + win->begy,
13956238Selan 			    win->curx + win->begx);
14056238Selan 			curscr->cury = win->cury + win->begy;
14156238Selan 			curscr->curx = win->curx + win->begx;
14219893Sbloom 		}
1432261Sarnold 	}
1442287Sarnold 	retval = OK;
14555986Sbostic 
1462261Sarnold 	_win = NULL;
14755976Sbostic 	(void)fflush(stdout);
14855976Sbostic 	return (retval);
1492261Sarnold }
1502261Sarnold 
1512261Sarnold /*
15255976Sbostic  * makech --
15355976Sbostic  *	Make a change on the screen.
1542261Sarnold  */
15555976Sbostic static int
1562261Sarnold makech(win, wy)
15755976Sbostic 	register WINDOW *win;
15855976Sbostic 	int wy;
1592261Sarnold {
16055976Sbostic 	register int nlsp, clsp;		/* Last space in lines. */
16155976Sbostic 	register short wx, lch, y;
16256648Selan 	register __LDATA *nsp, *csp, *cp;
16356651Selan 	u_int force;
16456648Selan 	char *ce;
16556648Selan 	__LDATA blank = {' ', 0};
16656648Selan 
16756472Selan 	/* Is the cursor still on the end of the last line? */
16856472Selan 	if (wy > 0 && win->lines[wy - 1]->flags & __ISPASTEOL) {
16956551Selan 		win->lines[wy - 1]->flags &= ~__ISPASTEOL;
17056551Selan 		domvcur(ly, lx, ly + 1, 0);
17156551Selan 		ly++;
17256551Selan 		lx = 0;
17356551Selan 	}
17456238Selan 	if (!(win->lines[wy]->flags & __ISDIRTY))
17555976Sbostic 		return (OK);
176*56715Selan 	wx = *win->lines[wy]->firstchp - win->ch_off;
17756238Selan 	if (wx >= win->maxx)
17856238Selan 		return (OK);
17919893Sbloom 	else if (wx < 0)
18019893Sbloom 		wx = 0;
181*56715Selan 	lch = *win->lines[wy]->lastchp - win->ch_off;
18219893Sbloom 	if (lch < 0)
18355976Sbostic 		return (OK);
18456238Selan 	else if (lch >= win->maxx)
18556238Selan 		lch = win->maxx - 1;
18656238Selan 	y = wy + win->begy;
18719893Sbloom 
1882287Sarnold 	if (curwin)
18956648Selan 		csp = &blank;
1902287Sarnold 	else
19156238Selan 		csp = &curscr->lines[wy + win->begy]->line[wx + win->begx];
19219893Sbloom 
19356238Selan 	nsp = &win->lines[wy]->line[wx];
19456651Selan 	force = win->lines[wy]->flags & __FORCEPAINT;
19556651Selan 	win->lines[wy]->flags &= ~__FORCEPAINT;
1962287Sarnold 	if (CE && !curwin) {
19756648Selan 		for (cp = &win->lines[wy]->line[win->maxx - 1];
19856648Selan 		     cp->ch == ' ' && cp->attr == 0; cp--)
19956648Selan 			if (cp <= win->lines[wy]->line)
2002261Sarnold 				break;
20156648Selan 		nlsp = cp - win->lines[wy]->line;
2022261Sarnold 	}
2032287Sarnold 	if (!curwin)
2042287Sarnold 		ce = CE;
2052287Sarnold 	else
2062287Sarnold 		ce = NULL;
20719893Sbloom 
20856651Selan 	if (force) {
20956651Selan 		if (CM)
21056651Selan 			tputs(tgoto(CM, lx, ly), 0, __cputchar);
21156651Selan 		else {
21256651Selan 			tputs(HO, 0, __cputchar);
21356651Selan 			mvcur(0, 0, ly, lx);
21456651Selan 		}
21556651Selan 	}
2162261Sarnold 	while (wx <= lch) {
21756651Selan 		if (!force && bcmp(nsp, csp, sizeof(__LDATA)) == 0) {
21855986Sbostic 			if (wx <= lch) {
21956648Selan 				while (bcmp(nsp, csp, sizeof(__LDATA)) == 0 &&
22056648Selan 			            wx <= lch) {
22156596Selan 					    nsp++;
22256648Selan 					    if (!curwin)
22356648Selan 						    csp++;
22456648Selan 					    ++wx;
22556648Selan 				    }
22655986Sbostic 				continue;
22755986Sbostic 			}
22855986Sbostic 			break;
22955986Sbostic 		}
23056238Selan 		domvcur(ly, lx, y, wx + win->begx);
23156378Selan 
23255976Sbostic #ifdef DEBUG
23356651Selan 		__TRACE("makech: 1: wx = %d, ly= %d, lx = %d, newy = %d, newx = %d, force =%d\n",
23456651Selan 		    wx, ly, lx, y, wx + win->begx, force);
23555976Sbostic #endif
23655986Sbostic 		ly = y;
23756238Selan 		lx = wx + win->begx;
23856651Selan 		while ((force || bcmp(nsp, csp, sizeof(__LDATA)) != 0)
23956651Selan 		    && wx <= lch) {
24056378Selan #ifdef notdef
24156378Selan 			/* XXX
24256378Selan 			 * The problem with this code is that we can't count on
24356378Selan 			 * terminals wrapping around after the
24456378Selan 			 * last character on the previous line has been output
24556378Selan 			 * In effect, what then could happen is that the CE
24656378Selan 			 * clear the previous line and do nothing to the
24756378Selan 			 * next line.
24856378Selan 			 */
24956648Selan 			if (ce != NULL && wx >= nlsp &&
25056648Selan 			    nsp->ch == ' ') {
25155986Sbostic 				/* Check for clear to end-of-line. */
25256596Selan 				ce = &curscr->lines[wy]->line[COLS - 1];
25356648Selan 				while (ce->ch == ' ' && ce->attr = 0)
25455986Sbostic 					if (ce-- <= csp)
25555986Sbostic 						break;
25656596Selan 				clsp = ce - curscr->lines[wy]->line -
25756648Selan 				       win->begx * __LDATASIZE;
25855976Sbostic #ifdef DEBUG
25955986Sbostic 			__TRACE("makech: clsp = %d, nlsp = %d\n", clsp, nlsp);
26055976Sbostic #endif
26156648Selan 				if (clsp - nlsp >= strlen(CE)
26256648Selan 				    && clsp < win->maxx * __LDATASIZE) {
26355976Sbostic #ifdef DEBUG
26455986Sbostic 					__TRACE("makech: using CE\n");
26555976Sbostic #endif
26655986Sbostic 					tputs(CE, 0, __cputchar);
26756238Selan 					lx = wx + win->begx;
26856596Selan 					while (wx++ <= clsp) {
26956648Selan 						csp->ch = ' ';
27056648Selan 						csp->attr = 0;
27156648Selan 						csp++;
27256596Selan 					}
27355986Sbostic 					return (OK);
2742261Sarnold 				}
27555986Sbostic 				ce = NULL;
27655986Sbostic 			}
27756378Selan #endif
27855986Sbostic 
27955986Sbostic 			/* Enter/exit standout mode as appropriate. */
28056648Selan 			if (SO && (nsp->attr & __STANDOUT) !=
28156378Selan 			    (curscr->flags & __WSTANDOUT)) {
28256648Selan 				if (nsp->attr & __STANDOUT) {
28355986Sbostic 					tputs(SO, 0, __cputchar);
28456238Selan 					curscr->flags |= __WSTANDOUT;
28555986Sbostic 				} else {
28655986Sbostic 					tputs(SE, 0, __cputchar);
28756238Selan 					curscr->flags &= ~__WSTANDOUT;
2882261Sarnold 				}
28955986Sbostic 			}
29055986Sbostic 
29155986Sbostic 			wx++;
29256472Selan 			if (wx >= win->maxx && wy == win->maxy - 1 && !curwin)
29356238Selan 				if (win->flags & __SCROLLOK) {
29456238Selan 					if (curscr->flags & __WSTANDOUT
29556238Selan 					    && win->flags & __ENDLINE)
29655986Sbostic 						if (!MS) {
29755986Sbostic 							tputs(SE, 0,
29855986Sbostic 							    __cputchar);
29956238Selan 							curscr->flags &=
30056238Selan 							    ~__WSTANDOUT;
30155976Sbostic 						}
30256596Selan 					if (!curwin) {
30356648Selan 						csp->attr = nsp->attr;
30456648Selan 						putchar(csp->ch = nsp->ch);
30556596Selan 					} else
30656648Selan 						putchar(nsp->ch);
30756648Selan #ifdef notdef /* XXX why is this here? */
30856472Selan 					if (win->flags & __FULLWIN && !curwin)
30955986Sbostic 						scroll(curscr);
31056378Selan #endif
31156599Selan 					if (wx + win->begx < curscr->maxx) {
31256599Selan 						domvcur(ly, wx + win->begx,
31356599Selan 						    win->begy + win->maxy - 1,
31456599Selan 						    win->begx + win->maxx - 1);
31556599Selan 					}
31656378Selan 					ly = win->begy + win->maxy - 1;
31756378Selan 					lx = win->begx + win->maxx - 1;
31855986Sbostic 					return (OK);
31955986Sbostic 				} else
32056238Selan 					if (win->flags & __SCROLLWIN) {
32155986Sbostic 						lx = --wx;
32255986Sbostic 						return (ERR);
32355986Sbostic 					}
32456596Selan 			if (!curwin) {
32556648Selan 				csp->attr = nsp->attr;
32656648Selan 				putchar(csp->ch = nsp->ch);
32756648Selan 				csp++;
32856648Selan 		       	} else
32956648Selan 				putchar(nsp->ch);
33056472Selan 
33155976Sbostic #ifdef DEBUG
33256648Selan 			__TRACE("makech: putchar(%c)\n", nsp->ch & 0177);
33355976Sbostic #endif
33456648Selan 			if (UC && (nsp->attr & __STANDOUT)) {
33555986Sbostic 				putchar('\b');
33655986Sbostic 				tputs(UC, 0, __cputchar);
3372261Sarnold 			}
33855986Sbostic 			nsp++;
33955986Sbostic 		}
34055976Sbostic #ifdef DEBUG
34155986Sbostic 		__TRACE("makech: 2: wx = %d, lx = %d\n", wx, lx);
34255976Sbostic #endif
34356238Selan 		if (lx == wx + win->begx)	/* If no change. */
34455986Sbostic 			break;
34556238Selan 		lx = wx + win->begx;
34655986Sbostic 		if (lx >= COLS && AM) {
34755986Sbostic 			/*
34855986Sbostic 			 * xn glitch: chomps a newline after auto-wrap.
34955986Sbostic 			 * we just feed it now and forget about it.
35055986Sbostic 			 */
35155986Sbostic 			if (XN) {
35256472Selan 				lx = 0;
35356472Selan 				ly++;
35455986Sbostic 				putchar('\n');
35555986Sbostic 				putchar('\r');
35656472Selan 			} else {
35756472Selan 				if (wy != LINES)
35856472Selan 					win->lines[wy]->flags |= __ISPASTEOL;
35956472Selan 				lx = COLS - 1;
36022789Smckusick 			}
36156596Selan 		} else if (wx >= win->maxx) {
36256596Selan 			if (wy != win->maxy)
36356596Selan 				win->lines[wy]->flags |= __ISPASTEOL;
36456596Selan 			domvcur(ly, lx, ly, win->maxx + win->begx - 1);
36556596Selan 			lx = win->maxx + win->begx - 1;
36655986Sbostic 		}
36756596Selan 
36855976Sbostic #ifdef DEBUG
36955976Sbostic 		__TRACE("makech: 3: wx = %d, lx = %d\n", wx, lx);
37055976Sbostic #endif
3712261Sarnold 	}
37255976Sbostic 	return (OK);
37311736Sarnold }
37411736Sarnold 
37511736Sarnold /*
37655976Sbostic  * domvcur --
37755976Sbostic  *	Do a mvcur, leaving standout mode if necessary.
37811736Sarnold  */
37955976Sbostic static void
38011736Sarnold domvcur(oy, ox, ny, nx)
38155976Sbostic 	int oy, ox, ny, nx;
38255976Sbostic {
38356238Selan 	if (curscr->flags & __WSTANDOUT && !MS) {
38455976Sbostic 		tputs(SE, 0, __cputchar);
38556238Selan 		curscr->flags &= ~__WSTANDOUT;
3862261Sarnold 	}
38756596Selan 
38811736Sarnold 	mvcur(oy, ox, ny, nx);
3892261Sarnold }
39056302Selan 
39156302Selan /*
39256302Selan  * Quickch() attempts to detect a pattern in the change of the window
39356552Selan  * in order to optimize the change, e.g., scroll n lines as opposed to
39456302Selan  * repainting the screen line by line.
39556302Selan  */
39656302Selan 
397*56715Selan 
39856302Selan static void
39956302Selan quickch(win)
40056302Selan 	WINDOW *win;
40156302Selan {
40256378Selan #define THRESH		win->maxy / 4
40356302Selan 
40456648Selan 	register __LINE *clp, *tmp1, *tmp2;
40556378Selan 	register int bsize, curs, curw, starts, startw, i, j;
40656652Selan 	int n, target, cur_period, bot, top, sc_region;
40756648Selan 	__LDATA buf[1024];
40856378Selan 	u_int blank_hash;
40956302Selan 
41056552Selan 	/*
41156552Selan 	 * Search for the largest block of text not changed.
41256652Selan 	 * Invariants of the loop:
41356652Selan 	 * - Startw is the index of the beginning of the examined block in win.
41456652Selan          * - Starts is the index of the beginning of the examined block in
41556652Selan 	 *    curscr.
41656652Selan 	 * - Curs is the index of one past the end of the exmined block in win.
41756652Selan 	 * - Curw is the index of one past the end of the exmined block in
41856652Selan 	 *   curscr.
41956652Selan 	 * - bsize is the current size of the examined block.
42056552Selan          */
42156302Selan 	for (bsize = win->maxy; bsize >= THRESH; bsize--)
42256302Selan 		for (startw = 0; startw <= win->maxy - bsize; startw++)
42356302Selan 			for (starts = 0; starts <= win->maxy - bsize;
42456302Selan 			     starts++) {
42556302Selan 				for (curw = startw, curs = starts;
42656302Selan 				     curs < starts + bsize; curw++, curs++)
42756651Selan 					if (win->lines[curw]->flags &
42856651Selan 					    __FORCEPAINT ||
42956651Selan 					    (win->lines[curw]->hash !=
43056552Selan 					    curscr->lines[curs]->hash ||
43156648Selan 				            bcmp(win->lines[curw]->line,
43256648Selan 					    curscr->lines[curs]->line,
43356651Selan 					    win->maxx * __LDATASIZE) != 0))
43456302Selan 						break;
43556302Selan 				if (curs == starts + bsize)
43656302Selan 					goto done;
43756302Selan 			}
43856302Selan  done:
43956651Selan 	/* Did not find anything */
44056651Selan 	if (bsize < THRESH)
44156302Selan 		return;
44256302Selan 
44356559Selan 	/*
44456559Selan 	 * Find how many lines from the top of the screen are unchanged.
44556559Selan 	 */
44656559Selan 	if (starts != 0) {
44756559Selan 		for (top = 0; top < win->maxy; top++)
44856651Selan 			if (win->lines[top]->flags & __FORCEPAINT ||
44956651Selan 			    win->lines[top]->hash != curscr->lines[top]->hash
45056648Selan 			    || bcmp(win->lines[top]->line,
45156648Selan 			    curscr->lines[top]->line,
45256648Selan 			    win->maxx * __LDATASIZE) != 0)
45356559Selan 				break;
45456559Selan 	} else
45556559Selan 		top = 0;
45656559Selan 
45756559Selan        /*
45856559Selan 	* Find how many lines from bottom of screen are unchanged.
45956559Selan 	*/
46056559Selan 	if (curs != win->maxy) {
46156559Selan 		for (bot = win->maxy - 1; bot >= 0; bot--)
46256651Selan 			if (win->lines[bot]->flags & __FORCEPAINT ||
46356651Selan 			    win->lines[bot]->hash != curscr->lines[bot]->hash
46456648Selan 			    || bcmp(win->lines[bot]->line,
46556648Selan 			    curscr->lines[bot]->line,
46656648Selan 			    win->maxx * __LDATASIZE) != 0)
46756559Selan 				break;
46856559Selan 	} else
46956559Selan 		bot = win->maxy - 1;
47056559Selan 
47156302Selan #ifdef DEBUG
47256559Selan 	__TRACE("quickch:bsize=%d,starts=%d,startw=%d,curw=%d,curs=%d,top=%d,bot=%d\n",
47356559Selan 		bsize, starts, startw, curw, curs, top, bot);
47456302Selan #endif
47556378Selan 
47656559Selan 	/*
47756559Selan 	 * Make sure that there is no overlap between the bottom and top
47856559Selan 	 * regions and the middle scrolled block.
47956559Selan 	 */
48056691Selan 	if (bot < curs)
48156691Selan 		bot = curs - 1;
48256691Selan 	if (top > starts)
48356691Selan 		top = starts;
48456559Selan 
48556378Selan 	n = startw - starts;
48656378Selan 
48756691Selan #ifdef DEBUG
48856691Selan 		__TRACE("#####################################\n");
48956691Selan 		for (i = 0; i < curscr->maxy; i++) {
49056691Selan 			__TRACE("C: %d:", i);
49156691Selan 			for (j = 0; j < curscr->maxx; j++)
49256691Selan 				__TRACE("%c",
49356691Selan 			           curscr->lines[i]->line[j].ch);
49456691Selan 			__TRACE("\n");
49556691Selan 			__TRACE("W: %d:", i);
49656691Selan 			for (j = 0; j < win->maxx; j++)
49756691Selan 				__TRACE("%c",
49856691Selan 			           win->lines[i]->line[j].ch);
49956691Selan 			__TRACE("\n");
50056691Selan 		}
50156691Selan #endif
50256651Selan 	if (n != 0)
50356705Selan 		scrolln(win, starts, startw, curs, bot, top);
50456651Selan 
50556651Selan 
50656378Selan 	/* So we don't have to call __hash() each time */
50756648Selan 	for (i = 0; i < win->maxx; i++) {
50856648Selan 		buf[i].ch = ' ';
50956648Selan 		buf[i].attr = 0;
51056648Selan 	}
51156648Selan 	blank_hash = __hash(buf, win->maxx * __LDATASIZE);
51256378Selan 
51356378Selan 	/*
51456378Selan 	 * Perform the rotation to maintain the consistency of curscr.
51556691Selan 	 * This is hairy since we are doing an *in place* rotation.
51656652Selan 	 * Invariants of the loop:
51756652Selan 	 * - I is the index of the current line.
51856652Selan 	 * - Target is the index of the target of line i.
51956652Selan 	 * - Tmp1 points to current line (i).
52056652Selan 	 * - Tmp2 and points to target line (target);
52156652Selan 	 * - Cur_period is the index of the end of the current period.
52256652Selan 	 *   (see below).
52356652Selan 	 *
52456652Selan 	 * There are 2 major issues here that make this rotation non-trivial:
52556652Selan 	 * 1.  Scrolling in a scrolling region bounded by the top
52656652Selan 	 *     and bottom regions determined (whose size is sc_region).
52756652Selan 	 * 2.  As a result of the use of the mod function, there may be a
52856652Selan 	 *     period introduced, i.e., 2 maps to 4, 4 to 6, n-2 to 0, and
52956652Selan 	 *     0 to 2, which then causes all odd lines not to be rotated.
53056652Selan 	 *     To remedy this, an index of the end ( = beginning) of the
53156652Selan 	 *     current 'period' is kept, cur_period, and when it is reached,
53256652Selan 	 *     the next period is started from cur_period + 1 which is
53356652Selan 	 *     guaranteed not to have been reached since that would mean that
53456652Selan 	 *     all records would have been reached. (think about it...).
53556652Selan 	 *
53656652Selan 	 * Lines in the rotation can have 3 attributes which are marked on the
53756652Selan 	 * line so that curscr is consistent with the visual screen.
53856705Selan 	 * 1.  Not dirty -- lines inside the scrolled block, top region or
53956652Selan 	 *                  bottom region.
54056705Selan 	 * 2.  Blank lines -- lines in the differential of the scrolling
54156705Selan 	 *		      region adjacent to top and bot regions
54256705Selan 	 *                    depending on scrolling direction.
54356652Selan 	 * 3.  Dirty line -- all other lines are marked dirty.
54456378Selan 	 */
54556648Selan 	sc_region = bot - top + 1;
54656648Selan 	i = top;
54756648Selan 	tmp1 = curscr->lines[top];
54856652Selan 	cur_period = top;
54956648Selan 	for (j = top; j <= bot; j++) {
55056648Selan 		target = (i - top + n + sc_region) % sc_region + top;
55156378Selan 		tmp2 = curscr->lines[target];
55256378Selan 		curscr->lines[target] = tmp1;
55356378Selan 		/* Mark block as clean and blank out scrolled lines. */
55456378Selan 		clp = curscr->lines[target];
55556472Selan #ifdef DEBUG
55656378Selan 		__TRACE("quickch: n=%d startw=%d curw=%d i = %d target=%d ",
55756378Selan 			n, startw, curw, i, target);
55856472Selan #endif
55956691Selan 		if ((target >= startw && target < curw) || target < top
56056691Selan 		    || target > bot) {
56156472Selan #ifdef DEBUG
56256378Selan 			__TRACE("-- notdirty");
56356472Selan #endif
56456378Selan 			win->lines[target]->flags &= ~__ISDIRTY;
56556705Selan 		} else if ((n > 0 && target >= top && target < top + n) ||
56656705Selan 		           (n < 0 && target <= bot && target > bot + n)) {
56756648Selan 			if (clp->hash != blank_hash ||  bcmp(clp->line,
56856648Selan 			    buf, win->maxx * __LDATASIZE) !=0) {
56956648Selan 				(void)bcopy(buf, clp->line,
57056648Selan 				    win->maxx * __LDATASIZE);
57156472Selan #ifdef DEBUG
57256648Selan 				__TRACE("-- blanked out: dirty");
57356472Selan #endif
57456378Selan 				clp->hash = blank_hash;
57556652Selan 				__touchline(win, target, 0, win->maxx - 1, 0);
57656705Selan 			} else {
57756652Selan 				__touchline(win, target, 0, win->maxx - 1, 0);
57856472Selan #ifdef DEBUG
57956648Selan 				__TRACE(" -- blank line already: dirty");
58056472Selan #endif
58156705Selan 			}
58256378Selan 		} else {
58356472Selan #ifdef DEBUG
58456648Selan 			__TRACE(" -- dirty");
58556472Selan #endif
58656651Selan 			__touchline(win, target, 0, win->maxx - 1, 0);
58756378Selan 		}
58856472Selan #ifdef DEBUG
58956378Selan 		__TRACE("\n");
59056472Selan #endif
59156652Selan 		if (target == cur_period) {
59256378Selan 			i = target + 1;
59356378Selan 			tmp1 = curscr->lines[i];
59456652Selan 			cur_period = i;
59556378Selan 		} else {
59656378Selan 			tmp1 = tmp2;
59756378Selan 			i = target;
59856378Selan 		}
59956302Selan 	}
60056472Selan #ifdef DEBUG
60156648Selan 		__TRACE("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n");
60256648Selan 		for (i = 0; i < curscr->maxy; i++) {
60356691Selan 			__TRACE("C: %d:", i);
60456648Selan 			for (j = 0; j < curscr->maxx; j++)
60556648Selan 				__TRACE("%c",
60656648Selan 			           curscr->lines[i]->line[j].ch);
60756648Selan 			__TRACE("\n");
60856691Selan 			__TRACE("W: %d:", i);
60956691Selan 			for (j = 0; j < win->maxx; j++)
61056691Selan 				__TRACE("%c",
61156691Selan 			           win->lines[i]->line[j].ch);
61256691Selan 			__TRACE("\n");
61356648Selan 		}
61456472Selan #endif
61556302Selan }
61656302Selan 
61756652Selan /*
61856652Selan  * Scrolln performs the scroll by n lines, where n is starts - startw.
61956652Selan  */
62056302Selan static void
62156705Selan scrolln(win, starts, startw, curs, bot, top)
62256302Selan 	WINDOW *win;
62356705Selan 	int starts, startw, curs, bot, top;
62456302Selan {
62556302Selan 	int i, oy, ox, n;
62656302Selan 
62756302Selan 	oy = curscr->cury;
62856302Selan 	ox = curscr->curx;
62956302Selan 	n = starts - startw;
63056302Selan 
63156302Selan 	if (n > 0) {
63256559Selan 		mvcur(oy, ox, top, 0);
63356559Selan 		/* Scroll up the block */
63456302Selan 		if (DL)
63556302Selan 			tputs(tscroll(DL, n), 0, __cputchar);
63656302Selan 		else
63756302Selan 			for(i = 0; i < n; i++)
63856302Selan 				tputs(dl, 0, __cputchar);
63956652Selan 
64056651Selan 		/*
64156652Selan 		 * Push down the bottom region.
64256651Selan 		 */
64356705Selan 		mvcur(top, 0, bot - n + 1, 0);
64456652Selan 		if (AL)
64556652Selan 			tputs(tscroll(AL, n), 0, __cputchar);
64656652Selan 		else
64756652Selan 			for(i = 0; i < n; i++)
64856652Selan 				tputs(al, 0, __cputchar);
64956705Selan 		mvcur(bot - n + 1, 0, oy, ox);
65056302Selan 	} else {
65156651Selan 		/* Preserve the bottom lines */
65256705Selan 		mvcur(oy, ox, bot + n + 1, 0);	/* n < 0 */
65356652Selan 		if (DL)
65456652Selan 			tputs(tscroll(DL, -n), 0, __cputchar);
65556652Selan 		else
65656652Selan 		       	for(i = n; i < 0; i++)
65756652Selan 				tputs(dl, 0, __cputchar);
65856705Selan 		mvcur(bot + n + 1, 0, top, 0);
65956302Selan 
66056302Selan 		/* Scroll the block down */
66156302Selan 		if (AL)
66256302Selan 			tputs(tscroll(AL, -n), 0, __cputchar);
66356302Selan 		else
66456302Selan 			for(i = n; i < 0; i++)
66556302Selan 				tputs(al, 0, __cputchar);
66656705Selan 		mvcur(top, 0, oy, ox);
66756378Selan 	}
66856302Selan }
66956378Selan 
67056378Selan 
671