1 /*
2 * Copyright (c) 1981, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 */
7
8 #ifndef lint
9 static char sccsid[] = "@(#)refresh.c 8.7 (Berkeley) 08/13/94";
10 #endif /* not lint */
11
12 #include <string.h>
13
14 #include "curses.h"
15
16 static int curwin;
17 static short ly, lx;
18
19 static void domvcur __P((int, int, int, int));
20 static int makech __P((WINDOW *, int));
21 static void quickch __P((WINDOW *));
22 static void scrolln __P((WINDOW *, int, int, int, int, int));
23
24 /*
25 * wrefresh --
26 * Make the current screen look like "win" over the area coverd by
27 * win.
28 */
29 int
wrefresh(win)30 wrefresh(win)
31 register WINDOW *win;
32 {
33 register __LINE *wlp;
34 register int retval;
35 register short wy;
36 int dnum;
37
38 /* Initialize loop parameters. */
39 ly = curscr->cury;
40 lx = curscr->curx;
41 wy = 0;
42 curwin = (win == curscr);
43
44 if (!curwin)
45 for (wy = 0; wy < win->maxy; wy++) {
46 wlp = win->lines[wy];
47 if (wlp->flags & __ISDIRTY)
48 wlp->hash = __hash((char *)wlp->line,
49 win->maxx * __LDATASIZE);
50 }
51
52 if (win->flags & __CLEAROK || curscr->flags & __CLEAROK || curwin) {
53 if ((win->flags & __FULLWIN) || curscr->flags & __CLEAROK) {
54 tputs(CL, 0, __cputchar);
55 ly = 0;
56 lx = 0;
57 if (!curwin) {
58 curscr->flags &= ~__CLEAROK;
59 curscr->cury = 0;
60 curscr->curx = 0;
61 werase(curscr);
62 }
63 __touchwin(win);
64 }
65 win->flags &= ~__CLEAROK;
66 }
67 if (!CA) {
68 if (win->curx != 0)
69 putchar('\n');
70 if (!curwin)
71 werase(curscr);
72 }
73 #ifdef DEBUG
74 __CTRACE("wrefresh: (%0.2o): curwin = %d\n", win, curwin);
75 __CTRACE("wrefresh: \tfirstch\tlastch\n");
76 #endif
77
78 #ifndef NOQCH
79 if ((win->flags & __FULLWIN) && !curwin) {
80 /*
81 * Invoke quickch() only if more than a quarter of the lines
82 * in the window are dirty.
83 */
84 for (wy = 0, dnum = 0; wy < win->maxy; wy++)
85 if (win->lines[wy]->flags & (__ISDIRTY | __FORCEPAINT))
86 dnum++;
87 if (!__noqch && dnum > (int) win->maxy / 4)
88 quickch(win);
89 }
90 #endif
91
92 #ifdef DEBUG
93 { int i, j;
94 __CTRACE("#####################################\n");
95 for (i = 0; i < curscr->maxy; i++) {
96 __CTRACE("C: %d:", i);
97 __CTRACE(" 0x%x \n", curscr->lines[i]->hash);
98 for (j = 0; j < curscr->maxx; j++)
99 __CTRACE("%c",
100 curscr->lines[i]->line[j].ch);
101 __CTRACE("\n");
102 for (j = 0; j < curscr->maxx; j++)
103 __CTRACE("%x",
104 curscr->lines[i]->line[j].attr);
105 __CTRACE("\n");
106 __CTRACE("W: %d:", i);
107 __CTRACE(" 0x%x \n", win->lines[i]->hash);
108 __CTRACE(" 0x%x ", win->lines[i]->flags);
109 for (j = 0; j < win->maxx; j++)
110 __CTRACE("%c",
111 win->lines[i]->line[j].ch);
112 __CTRACE("\n");
113 for (j = 0; j < win->maxx; j++)
114 __CTRACE("%x",
115 win->lines[i]->line[j].attr);
116 __CTRACE("\n");
117 }
118 }
119 #endif /* DEBUG */
120
121 for (wy = 0; wy < win->maxy; wy++) {
122 #ifdef DEBUG
123 __CTRACE("%d\t%d\t%d\n",
124 wy, *win->lines[wy]->firstchp, *win->lines[wy]->lastchp);
125 #endif
126 if (!curwin)
127 curscr->lines[wy]->hash = win->lines[wy]->hash;
128 if (win->lines[wy]->flags & (__ISDIRTY | __FORCEPAINT)) {
129 if (makech(win, wy) == ERR)
130 return (ERR);
131 else {
132 if (*win->lines[wy]->firstchp >= win->ch_off)
133 *win->lines[wy]->firstchp = win->maxx +
134 win->ch_off;
135 if (*win->lines[wy]->lastchp < win->maxx +
136 win->ch_off)
137 *win->lines[wy]->lastchp = win->ch_off;
138 if (*win->lines[wy]->lastchp <
139 *win->lines[wy]->firstchp) {
140 #ifdef DEBUG
141 __CTRACE("wrefresh: line %d notdirty \n", wy);
142 #endif
143 win->lines[wy]->flags &= ~__ISDIRTY;
144 }
145 }
146
147 }
148 #ifdef DEBUG
149 __CTRACE("\t%d\t%d\n", *win->lines[wy]->firstchp,
150 *win->lines[wy]->lastchp);
151 #endif
152 }
153
154 #ifdef DEBUG
155 __CTRACE("refresh: ly=%d, lx=%d\n", ly, lx);
156 #endif
157
158 if (win == curscr)
159 domvcur(ly, lx, win->cury, win->curx);
160 else {
161 if (win->flags & __LEAVEOK) {
162 curscr->cury = ly;
163 curscr->curx = lx;
164 ly -= win->begy;
165 lx -= win->begx;
166 if (ly >= 0 && ly < win->maxy && lx >= 0 &&
167 lx < win->maxx) {
168 win->cury = ly;
169 win->curx = lx;
170 } else
171 win->cury = win->curx = 0;
172 } else {
173 domvcur(ly, lx, win->cury + win->begy,
174 win->curx + win->begx);
175 curscr->cury = win->cury + win->begy;
176 curscr->curx = win->curx + win->begx;
177 }
178 }
179 retval = OK;
180
181 (void)fflush(stdout);
182 return (retval);
183 }
184
185 /*
186 * makech --
187 * Make a change on the screen.
188 */
189 static int
makech(win,wy)190 makech(win, wy)
191 register WINDOW *win;
192 int wy;
193 {
194 static __LDATA blank = {' ', 0};
195 __LDATA *nsp, *csp, *cp, *cep;
196 u_int force;
197 int clsp, nlsp; /* Last space in lines. */
198 int lch, wx, y;
199 char *ce;
200
201 /* Is the cursor still on the end of the last line? */
202 if (wy > 0 && win->lines[wy - 1]->flags & __ISPASTEOL) {
203 domvcur(ly, lx, ly + 1, 0);
204 ly++;
205 lx = 0;
206 }
207 wx = *win->lines[wy]->firstchp - win->ch_off;
208 if (wx < 0)
209 wx = 0;
210 else if (wx >= win->maxx)
211 return (OK);
212 lch = *win->lines[wy]->lastchp - win->ch_off;
213 if (lch < 0)
214 return (OK);
215 else if (lch >= (int) win->maxx)
216 lch = win->maxx - 1;
217 y = wy + win->begy;
218
219 if (curwin)
220 csp = ␣
221 else
222 csp = &curscr->lines[wy + win->begy]->line[wx + win->begx];
223
224 nsp = &win->lines[wy]->line[wx];
225 force = win->lines[wy]->flags & __FORCEPAINT;
226 win->lines[wy]->flags &= ~__FORCEPAINT;
227 if (CE && !curwin) {
228 for (cp = &win->lines[wy]->line[win->maxx - 1];
229 cp->ch == ' ' && cp->attr == 0; cp--)
230 if (cp <= win->lines[wy]->line)
231 break;
232 nlsp = cp - win->lines[wy]->line;
233 }
234 if (!curwin)
235 ce = CE;
236 else
237 ce = NULL;
238
239 if (force) {
240 if (CM)
241 tputs(tgoto(CM, lx, ly), 0, __cputchar);
242 else {
243 tputs(HO, 0, __cputchar);
244 __mvcur(0, 0, ly, lx, 1);
245 }
246 }
247
248 while (wx <= lch) {
249 if (!force && memcmp(nsp, csp, sizeof(__LDATA)) == 0) {
250 if (wx <= lch) {
251 while (wx <= lch &&
252 memcmp(nsp, csp, sizeof(__LDATA)) == 0) {
253 nsp++;
254 if (!curwin)
255 ++csp;
256 ++wx;
257 }
258 continue;
259 }
260 break;
261 }
262 domvcur(ly, lx, y, wx + win->begx);
263
264 #ifdef DEBUG
265 __CTRACE("makech: 1: wx = %d, ly= %d, lx = %d, newy = %d, newx = %d, force =%d\n",
266 wx, ly, lx, y, wx + win->begx, force);
267 #endif
268 ly = y;
269 lx = wx + win->begx;
270 while ((force || memcmp(nsp, csp, sizeof(__LDATA)) != 0)
271 && wx <= lch) {
272
273 if (ce != NULL &&
274 win->maxx + win->begx == curscr->maxx &&
275 wx >= nlsp && nsp->ch == ' ' && nsp->attr == 0) {
276 /* Check for clear to end-of-line. */
277 cep = &curscr->lines[wy]->line[win->maxx - 1];
278 while (cep->ch == ' ' && cep->attr == 0)
279 if (cep-- <= csp)
280 break;
281 clsp = cep - curscr->lines[wy]->line -
282 win->begx * __LDATASIZE;
283 #ifdef DEBUG
284 __CTRACE("makech: clsp = %d, nlsp = %d\n", clsp, nlsp);
285 #endif
286 if ((clsp - nlsp >= strlen(CE)
287 && clsp < win->maxx * __LDATASIZE) ||
288 wy == win->maxy - 1) {
289 if (curscr->flags & __WSTANDOUT) {
290 tputs(SE, 0, __cputchar);
291 curscr->flags &= ~__WSTANDOUT;
292 }
293 tputs(CE, 0, __cputchar);
294 lx = wx + win->begx;
295 while (wx++ <= clsp) {
296 csp->ch = ' ';
297 csp->attr = 0;
298 csp++;
299 }
300 return (OK);
301 }
302 ce = NULL;
303 }
304
305 /*
306 * Enter/exit standout mode as appropriate.
307 * XXX
308 * Should use UC if SO/SE not available.
309 */
310 if (nsp->attr & __STANDOUT) {
311 if (!(curscr->flags & __WSTANDOUT) &&
312 SO != NULL && SE != NULL) {
313 tputs(SO, 0, __cputchar);
314 curscr->flags |= __WSTANDOUT;
315 }
316 } else
317 if (curscr->flags & __WSTANDOUT &&
318 SE != NULL) {
319 tputs(SE, 0, __cputchar);
320 curscr->flags &= ~__WSTANDOUT;
321 }
322
323 wx++;
324 if (wx >= win->maxx && wy == win->maxy - 1 && !curwin)
325 if (win->flags & __SCROLLOK) {
326 if (curscr->flags & __WSTANDOUT
327 && win->flags & __ENDLINE)
328 if (!MS) {
329 tputs(SE, 0,
330 __cputchar);
331 curscr->flags &=
332 ~__WSTANDOUT;
333 }
334 if (!(win->flags & __SCROLLWIN)) {
335 if (!curwin) {
336 csp->attr = nsp->attr;
337 putchar(csp->ch = nsp->ch);
338 } else
339 putchar(nsp->ch);
340 }
341 if (wx + win->begx < curscr->maxx) {
342 domvcur(ly, wx + win->begx,
343 win->begy + win->maxy - 1,
344 win->begx + win->maxx - 1);
345 }
346 ly = win->begy + win->maxy - 1;
347 lx = win->begx + win->maxx - 1;
348 return (OK);
349 }
350 if (wx < win->maxx || wy < win->maxy - 1 ||
351 !(win->flags & __SCROLLWIN)) {
352 if (!curwin) {
353 csp->attr = nsp->attr;
354 putchar(csp->ch = nsp->ch);
355 csp++;
356 } else
357 putchar(nsp->ch);
358 }
359 #ifdef DEBUG
360 __CTRACE("makech: putchar(%c)\n", nsp->ch & 0177);
361 #endif
362 if (UC && (nsp->attr & __STANDOUT)) {
363 putchar('\b');
364 tputs(UC, 0, __cputchar);
365 }
366 nsp++;
367 #ifdef DEBUG
368 __CTRACE("makech: 2: wx = %d, lx = %d\n", wx, lx);
369 #endif
370 }
371 if (lx == wx + win->begx) /* If no change. */
372 break;
373 lx = wx + win->begx;
374 if (lx >= COLS && AM)
375 lx = COLS - 1;
376 else if (wx >= win->maxx) {
377 domvcur(ly, lx, ly, win->maxx + win->begx - 1);
378 lx = win->maxx + win->begx - 1;
379 }
380
381 #ifdef DEBUG
382 __CTRACE("makech: 3: wx = %d, lx = %d\n", wx, lx);
383 #endif
384 }
385
386 /* Don't leave the screen in standout mode. */
387 if (curscr->flags & __WSTANDOUT) {
388 tputs(SE, 0, __cputchar);
389 curscr->flags &= ~__WSTANDOUT;
390 }
391 return (OK);
392 }
393
394 /*
395 * domvcur --
396 * Do a mvcur, leaving standout mode if necessary.
397 */
398 static void
domvcur(oy,ox,ny,nx)399 domvcur(oy, ox, ny, nx)
400 int oy, ox, ny, nx;
401 {
402 if (curscr->flags & __WSTANDOUT && !MS) {
403 tputs(SE, 0, __cputchar);
404 curscr->flags &= ~__WSTANDOUT;
405 }
406
407 __mvcur(oy, ox, ny, nx, 1);
408 }
409
410 /*
411 * Quickch() attempts to detect a pattern in the change of the window
412 * in order to optimize the change, e.g., scroll n lines as opposed to
413 * repainting the screen line by line.
414 */
415
416 static void
quickch(win)417 quickch(win)
418 WINDOW *win;
419 {
420 #define THRESH (int) win->maxy / 4
421
422 register __LINE *clp, *tmp1, *tmp2;
423 register int bsize, curs, curw, starts, startw, i, j;
424 int n, target, cur_period, bot, top, sc_region;
425 __LDATA buf[1024];
426 u_int blank_hash;
427
428 /*
429 * Find how many lines from the top of the screen are unchanged.
430 */
431 for (top = 0; top < win->maxy; top++)
432 if (win->lines[top]->flags & __FORCEPAINT ||
433 win->lines[top]->hash != curscr->lines[top]->hash
434 || memcmp(win->lines[top]->line,
435 curscr->lines[top]->line,
436 win->maxx * __LDATASIZE) != 0)
437 break;
438 else
439 win->lines[top]->flags &= ~__ISDIRTY;
440 /*
441 * Find how many lines from bottom of screen are unchanged.
442 */
443 for (bot = win->maxy - 1; bot >= 0; bot--)
444 if (win->lines[bot]->flags & __FORCEPAINT ||
445 win->lines[bot]->hash != curscr->lines[bot]->hash
446 || memcmp(win->lines[bot]->line,
447 curscr->lines[bot]->line,
448 win->maxx * __LDATASIZE) != 0)
449 break;
450 else
451 win->lines[bot]->flags &= ~__ISDIRTY;
452
453 #ifdef NO_JERKINESS
454 /*
455 * If we have a bottom unchanged region return. Scrolling the
456 * bottom region up and then back down causes a screen jitter.
457 * This will increase the number of characters sent to the screen
458 * but it looks better.
459 */
460 if (bot < win->maxy - 1)
461 return;
462 #endif /* NO_JERKINESS */
463
464 /*
465 * Search for the largest block of text not changed.
466 * Invariants of the loop:
467 * - Startw is the index of the beginning of the examined block in win.
468 * - Starts is the index of the beginning of the examined block in
469 * curscr.
470 * - Curs is the index of one past the end of the exmined block in win.
471 * - Curw is the index of one past the end of the exmined block in
472 * curscr.
473 * - bsize is the current size of the examined block.
474 */
475 for (bsize = bot - top; bsize >= THRESH; bsize--) {
476 for (startw = top; startw <= bot - bsize; startw++)
477 for (starts = top; starts <= bot - bsize;
478 starts++) {
479 for (curw = startw, curs = starts;
480 curs < starts + bsize; curw++, curs++)
481 if (win->lines[curw]->flags &
482 __FORCEPAINT ||
483 (win->lines[curw]->hash !=
484 curscr->lines[curs]->hash ||
485 memcmp(win->lines[curw]->line,
486 curscr->lines[curs]->line,
487 win->maxx * __LDATASIZE) != 0))
488 break;
489 if (curs == starts + bsize)
490 goto done;
491 }
492 }
493 done:
494 /* Did not find anything */
495 if (bsize < THRESH)
496 return;
497
498 #ifdef DEBUG
499 __CTRACE("quickch:bsize=%d,starts=%d,startw=%d,curw=%d,curs=%d,top=%d,bot=%d\n",
500 bsize, starts, startw, curw, curs, top, bot);
501 #endif
502
503 /*
504 * Make sure that there is no overlap between the bottom and top
505 * regions and the middle scrolled block.
506 */
507 if (bot < curs)
508 bot = curs - 1;
509 if (top > starts)
510 top = starts;
511
512 n = startw - starts;
513
514 #ifdef DEBUG
515 __CTRACE("#####################################\n");
516 for (i = 0; i < curscr->maxy; i++) {
517 __CTRACE("C: %d:", i);
518 __CTRACE(" 0x%x \n", curscr->lines[i]->hash);
519 for (j = 0; j < curscr->maxx; j++)
520 __CTRACE("%c",
521 curscr->lines[i]->line[j].ch);
522 __CTRACE("\n");
523 for (j = 0; j < curscr->maxx; j++)
524 __CTRACE("%x",
525 curscr->lines[i]->line[j].attr);
526 __CTRACE("\n");
527 __CTRACE("W: %d:", i);
528 __CTRACE(" 0x%x \n", win->lines[i]->hash);
529 __CTRACE(" 0x%x ", win->lines[i]->flags);
530 for (j = 0; j < win->maxx; j++)
531 __CTRACE("%c",
532 win->lines[i]->line[j].ch);
533 __CTRACE("\n");
534 for (j = 0; j < win->maxx; j++)
535 __CTRACE("%x",
536 win->lines[i]->line[j].attr);
537 __CTRACE("\n");
538 }
539 #endif
540
541 /* So we don't have to call __hash() each time */
542 for (i = 0; i < win->maxx; i++) {
543 buf[i].ch = ' ';
544 buf[i].attr = 0;
545 }
546 blank_hash = __hash((char *) buf, win->maxx * __LDATASIZE);
547
548 /*
549 * Perform the rotation to maintain the consistency of curscr.
550 * This is hairy since we are doing an *in place* rotation.
551 * Invariants of the loop:
552 * - I is the index of the current line.
553 * - Target is the index of the target of line i.
554 * - Tmp1 points to current line (i).
555 * - Tmp2 and points to target line (target);
556 * - Cur_period is the index of the end of the current period.
557 * (see below).
558 *
559 * There are 2 major issues here that make this rotation non-trivial:
560 * 1. Scrolling in a scrolling region bounded by the top
561 * and bottom regions determined (whose size is sc_region).
562 * 2. As a result of the use of the mod function, there may be a
563 * period introduced, i.e., 2 maps to 4, 4 to 6, n-2 to 0, and
564 * 0 to 2, which then causes all odd lines not to be rotated.
565 * To remedy this, an index of the end ( = beginning) of the
566 * current 'period' is kept, cur_period, and when it is reached,
567 * the next period is started from cur_period + 1 which is
568 * guaranteed not to have been reached since that would mean that
569 * all records would have been reached. (think about it...).
570 *
571 * Lines in the rotation can have 3 attributes which are marked on the
572 * line so that curscr is consistent with the visual screen.
573 * 1. Not dirty -- lines inside the scrolled block, top region or
574 * bottom region.
575 * 2. Blank lines -- lines in the differential of the scrolling
576 * region adjacent to top and bot regions
577 * depending on scrolling direction.
578 * 3. Dirty line -- all other lines are marked dirty.
579 */
580 sc_region = bot - top + 1;
581 i = top;
582 tmp1 = curscr->lines[top];
583 cur_period = top;
584 for (j = top; j <= bot; j++) {
585 target = (i - top + n + sc_region) % sc_region + top;
586 tmp2 = curscr->lines[target];
587 curscr->lines[target] = tmp1;
588 /* Mark block as clean and blank out scrolled lines. */
589 clp = curscr->lines[target];
590 #ifdef DEBUG
591 __CTRACE("quickch: n=%d startw=%d curw=%d i = %d target=%d ",
592 n, startw, curw, i, target);
593 #endif
594 if ((target >= startw && target < curw) || target < top
595 || target > bot) {
596 #ifdef DEBUG
597 __CTRACE("-- notdirty");
598 #endif
599 win->lines[target]->flags &= ~__ISDIRTY;
600 } else if ((n > 0 && target >= top && target < top + n) ||
601 (n < 0 && target <= bot && target > bot + n)) {
602 if (clp->hash != blank_hash || memcmp(clp->line,
603 buf, win->maxx * __LDATASIZE) !=0) {
604 (void)memcpy(clp->line, buf,
605 win->maxx * __LDATASIZE);
606 #ifdef DEBUG
607 __CTRACE("-- blanked out: dirty");
608 #endif
609 clp->hash = blank_hash;
610 __touchline(win, target, 0, win->maxx - 1, 0);
611 } else {
612 __touchline(win, target, 0, win->maxx - 1, 0);
613 #ifdef DEBUG
614 __CTRACE(" -- blank line already: dirty");
615 #endif
616 }
617 } else {
618 #ifdef DEBUG
619 __CTRACE(" -- dirty");
620 #endif
621 __touchline(win, target, 0, win->maxx - 1, 0);
622 }
623 #ifdef DEBUG
624 __CTRACE("\n");
625 #endif
626 if (target == cur_period) {
627 i = target + 1;
628 tmp1 = curscr->lines[i];
629 cur_period = i;
630 } else {
631 tmp1 = tmp2;
632 i = target;
633 }
634 }
635 #ifdef DEBUG
636 __CTRACE("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n");
637 for (i = 0; i < curscr->maxy; i++) {
638 __CTRACE("C: %d:", i);
639 for (j = 0; j < curscr->maxx; j++)
640 __CTRACE("%c",
641 curscr->lines[i]->line[j].ch);
642 __CTRACE("\n");
643 __CTRACE("W: %d:", i);
644 for (j = 0; j < win->maxx; j++)
645 __CTRACE("%c", win->lines[i]->line[j].ch);
646 __CTRACE("\n");
647 }
648 #endif
649 if (n != 0) {
650 WINDOW *wp;
651 scrolln(win, starts, startw, curs, bot, top);
652 /*
653 * Need to repoint any subwindow lines to the rotated
654 * line structured.
655 */
656 for (wp = win->nextp; wp != win; wp = wp->nextp)
657 __set_subwin(win, wp);
658 }
659 }
660
661 /*
662 * scrolln --
663 * Scroll n lines, where n is starts - startw.
664 */
665 static void
scrolln(win,starts,startw,curs,bot,top)666 scrolln(win, starts, startw, curs, bot, top)
667 WINDOW *win;
668 int starts, startw, curs, bot, top;
669 {
670 int i, oy, ox, n;
671
672 oy = curscr->cury;
673 ox = curscr->curx;
674 n = starts - startw;
675
676 /*
677 * XXX
678 * The initial tests that set __noqch don't let us reach here unless
679 * we have either CS + HO + SF/sf/SR/sr, or AL + DL. SF/sf and SR/sr
680 * scrolling can only shift the entire scrolling region, not just a
681 * part of it, which means that the quickch() routine is going to be
682 * sadly disappointed in us if we don't have CS as well.
683 *
684 * If CS, HO and SF/sf are set, can use the scrolling region. Because
685 * the cursor position after CS is undefined, we need HO which gives us
686 * the ability to move to somewhere without knowledge of the current
687 * location of the cursor. Still call __mvcur() anyway, to update its
688 * idea of where the cursor is.
689 *
690 * When the scrolling region has been set, the cursor has to be at the
691 * last line of the region to make the scroll happen.
692 *
693 * Doing SF/SR or AL/DL appears faster on the screen than either sf/sr
694 * or al/dl, and, some terminals have AL/DL, sf/sr, and CS, but not
695 * SF/SR. So, if we're scrolling almost all of the screen, try and use
696 * AL/DL, otherwise use the scrolling region. The "almost all" is a
697 * shameless hack for vi.
698 */
699 if (n > 0) {
700 if (CS != NULL && HO != NULL && (SF != NULL ||
701 (AL == NULL || DL == NULL ||
702 top > 3 || bot + 3 < win->maxy) && sf != NULL)) {
703 tputs(__tscroll(CS, top, bot + 1), 0, __cputchar);
704 __mvcur(oy, ox, 0, 0, 1);
705 tputs(HO, 0, __cputchar);
706 __mvcur(0, 0, bot, 0, 1);
707 if (SF != NULL)
708 tputs(__tscroll(SF, n, 0), 0, __cputchar);
709 else
710 for (i = 0; i < n; i++)
711 tputs(sf, 0, __cputchar);
712 tputs(__tscroll(CS, 0, win->maxy), 0, __cputchar);
713 __mvcur(bot, 0, 0, 0, 1);
714 tputs(HO, 0, __cputchar);
715 __mvcur(0, 0, oy, ox, 1);
716 return;
717 }
718
719 /* Scroll up the block. */
720 if (SF != NULL && top == 0) {
721 __mvcur(oy, ox, bot, 0, 1);
722 tputs(__tscroll(SF, n, 0), 0, __cputchar);
723 } else if (DL != NULL) {
724 __mvcur(oy, ox, top, 0, 1);
725 tputs(__tscroll(DL, n, 0), 0, __cputchar);
726 } else if (dl != NULL) {
727 __mvcur(oy, ox, top, 0, 1);
728 for (i = 0; i < n; i++)
729 tputs(dl, 0, __cputchar);
730 } else if (sf != NULL && top == 0) {
731 __mvcur(oy, ox, bot, 0, 1);
732 for (i = 0; i < n; i++)
733 tputs(sf, 0, __cputchar);
734 } else
735 abort();
736
737 /* Push down the bottom region. */
738 __mvcur(top, 0, bot - n + 1, 0, 1);
739 if (AL != NULL)
740 tputs(__tscroll(AL, n, 0), 0, __cputchar);
741 else if (al != NULL)
742 for (i = 0; i < n; i++)
743 tputs(al, 0, __cputchar);
744 else
745 abort();
746 __mvcur(bot - n + 1, 0, oy, ox, 1);
747 } else {
748 /*
749 * !!!
750 * n < 0
751 *
752 * If CS, HO and SR/sr are set, can use the scrolling region.
753 * See the above comments for details.
754 */
755 if (CS != NULL && HO != NULL && (SR != NULL ||
756 (AL == NULL || DL == NULL ||
757 top > 3 || bot + 3 < win->maxy) && sr != NULL)) {
758 tputs(__tscroll(CS, top, bot + 1), 0, __cputchar);
759 __mvcur(oy, ox, 0, 0, 1);
760 tputs(HO, 0, __cputchar);
761 __mvcur(0, 0, top, 0, 1);
762
763 if (SR != NULL)
764 tputs(__tscroll(SR, -n, 0), 0, __cputchar);
765 else
766 for (i = n; i < 0; i++)
767 tputs(sr, 0, __cputchar);
768 tputs(__tscroll(CS, 0, win->maxy), 0, __cputchar);
769 __mvcur(top, 0, 0, 0, 1);
770 tputs(HO, 0, __cputchar);
771 __mvcur(0, 0, oy, ox, 1);
772 return;
773 }
774
775 /* Preserve the bottom lines. */
776 __mvcur(oy, ox, bot + n + 1, 0, 1);
777 if (SR != NULL && bot == win->maxy)
778 tputs(__tscroll(SR, -n, 0), 0, __cputchar);
779 else if (DL != NULL)
780 tputs(__tscroll(DL, -n, 0), 0, __cputchar);
781 else if (dl != NULL)
782 for (i = n; i < 0; i++)
783 tputs(dl, 0, __cputchar);
784 else if (sr != NULL && bot == win->maxy)
785 for (i = n; i < 0; i++)
786 tputs(sr, 0, __cputchar);
787 else
788 abort();
789
790 /* Scroll the block down. */
791 __mvcur(bot + n + 1, 0, top, 0, 1);
792 if (AL != NULL)
793 tputs(__tscroll(AL, -n, 0), 0, __cputchar);
794 else if (al != NULL)
795 for (i = n; i < 0; i++)
796 tputs(al, 0, __cputchar);
797 else
798 abort();
799 __mvcur(top, 0, oy, ox, 1);
800 }
801 }
802