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