1 /*        $NetBSD: refresh.c,v 1.129 2024/12/23 02:58:04 blymn Exp $  */
2 
3 /*
4  * Copyright (c) 1981, 1993, 1994
5  *        The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)refresh.c   8.7 (Berkeley) 8/13/94";
36 #else
37 __RCSID("$NetBSD: refresh.c,v 1.129 2024/12/23 02:58:04 blymn Exp $");
38 #endif
39 #endif                                  /* not lint */
40 
41 #include <poll.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <assert.h>
45 
46 #include "curses.h"
47 #include "curses_private.h"
48 
49 static void         domvcur(WINDOW *, int, int, int, int);
50 static void         putattr(__LDATA *);
51 static void         putattr_out(__LDATA *);
52 static int          putch(__LDATA *, __LDATA *, int, int);
53 static int          putchbr(__LDATA *, __LDATA *, __LDATA *, int, int);
54 static int          makech(int);
55 static void         quickch(void);
56 static void         scrolln(int, int, int, int, int);
57 
58 static int          _wnoutrefresh(WINDOW *, int, int, int, int, int, int);
59 
60 static int lineeq(__LDATA *, __LDATA *, size_t);
61 
62 #define   CHECK_INTERVAL                5 /* Change N lines before checking typeahead */
63 
64 #ifndef _CURSES_USE_MACROS
65 
66 /*
67  * refresh --
68  *        Make the current screen look like "stdscr" over the area covered by
69  *        stdscr.
70  */
71 int
refresh(void)72 refresh(void)
73 {
74 
75           return wrefresh(stdscr);
76 }
77 
78 #endif
79 
80 /*
81  * wnoutrefresh --
82  *        Add the contents of "win" to the virtual window.
83  */
84 int
wnoutrefresh(WINDOW * win)85 wnoutrefresh(WINDOW *win)
86 {
87 
88           __CTRACE(__CTRACE_REFRESH,
89               "wnoutrefresh: win %p, begy %d, begx %d, maxy %d, maxx %d\n",
90               win, win->begy, win->begx, win->maxy, win->maxx);
91 
92           return _wnoutrefresh(win, 0, 0, win->begy, win->begx,
93               win->maxy, win->maxx);
94 }
95 
96 /*
97  * pnoutrefresh --
98  *        Add the contents of "pad" to the virtual window.
99  */
100 int
pnoutrefresh(WINDOW * pad,int pbegy,int pbegx,int sbegy,int sbegx,int smaxy,int smaxx)101 pnoutrefresh(WINDOW *pad, int pbegy, int pbegx, int sbegy, int sbegx,
102                int smaxy, int smaxx)
103 {
104           int pmaxy, pmaxx;
105 
106           __CTRACE(__CTRACE_REFRESH, "pnoutrefresh: pad %p, flags 0x%08x\n",
107               pad, pad->flags);
108           __CTRACE(__CTRACE_REFRESH,
109               "pnoutrefresh: (%d, %d), (%d, %d), (%d, %d)\n",
110               pbegy, pbegx, sbegy, sbegx, smaxy, smaxx);
111 
112           if (__predict_false(pad == NULL))
113                     return ERR;
114 
115           /* SUS says if these are negative, they should be treated as zero */
116           if (pbegy < 0)
117                     pbegy = 0;
118           if (pbegx < 0)
119                     pbegx = 0;
120           if (sbegy < 0)
121                     sbegy = 0;
122           if (sbegx < 0)
123                     sbegx = 0;
124 
125           /* Calculate rectangle on pad - used by _wnoutrefresh */
126           pmaxy = pbegy + smaxy - sbegy + 1;
127           pmaxx = pbegx + smaxx - sbegx + 1;
128 
129           /* Check rectangle fits in pad */
130           if (pmaxy > pad->maxy - pad->begy)
131                     pmaxy = pad->maxy - pad->begy;
132           if (pmaxx > pad->maxx - pad->begx)
133                     pmaxx = pad->maxx - pad->begx;
134 
135           if (smaxy - sbegy < 0 || smaxx - sbegx < 0 )
136                     return ERR;
137 
138           return _wnoutrefresh(pad,
139               pad->begy + pbegy, pad->begx + pbegx, pad->begy + sbegy,
140               pad->begx + sbegx, pmaxy, pmaxx);
141 }
142 
143 /*
144  * _wnoutrefresh --
145  *        Does the grunt work for wnoutrefresh to the given screen.
146  *        Copies the part of the window given by the rectangle
147  *        (begy, begx) to (maxy, maxx) at screen position (wbegy, wbegx).
148  */
149 static int
_wnoutrefresh(WINDOW * win,int begy,int begx,int wbegy,int wbegx,int maxy,int maxx)150 _wnoutrefresh(WINDOW *win, int begy, int begx, int wbegy, int wbegx,
151               int maxy, int maxx)
152 {
153           SCREEN *screen = win->screen;
154           short     sy, wy, wx, y_off, x_off, mx, dy_off, dx_off, endy;
155           int newy, newx;
156 #ifdef HAVE_WCHAR
157           int i, tx;
158           wchar_t ch;
159 #endif
160           __LINE    *wlp, *vlp, *dwlp;
161           WINDOW    *sub_win, *orig, *swin, *dwin;
162 
163           __CTRACE(__CTRACE_REFRESH, "_wnoutrefresh: win %p, flags 0x%08x\n",
164               win, win->flags);
165           __CTRACE(__CTRACE_REFRESH,
166               "_wnoutrefresh: (%d, %d), (%d, %d), (%d, %d)\n",
167               begy, begx, wbegy, wbegx, maxy, maxx);
168 
169           if (__predict_false(win == NULL))
170                     return ERR;
171 
172           if (screen->curwin)
173                     return OK;
174 
175           swin = dwin = win;
176           if (win->flags & __ISDERWIN)
177                     swin = win->orig;
178 
179           /*
180            * Recurse through any sub-windows, mark as dirty lines on the parent
181            * window that are dirty on the sub-window and clear the dirty flag on
182            * the sub-window.
183            */
184           if (dwin->orig == 0) {
185                     orig = dwin;
186                     for (sub_win = dwin->nextp; sub_win != orig;
187                         sub_win = sub_win->nextp) {
188                               if (sub_win->flags & __ISDERWIN)
189                                         continue;
190                               __CTRACE(__CTRACE_REFRESH,
191                                   "wnout_refresh: win %p, sub_win %p\n",
192                                   orig, sub_win);
193                               for (sy = 0; sy < sub_win->maxy; sy++) {
194                                         if (sub_win->alines[sy]->flags & __ISDIRTY) {
195                                                   orig->alines[sy + sub_win->begy - orig->begy]->flags
196                                                       |= __ISDIRTY;
197                                                   sub_win->alines[sy]->flags
198                                                       &= ~__ISDIRTY;
199                                         }
200                                         if (sub_win->alines[sy]->flags & __ISFORCED) {
201                                                   orig->alines[sy + sub_win->begy - orig->begy]->flags
202                                                       |= __ISFORCED;
203                                                   sub_win->alines[sy]->flags
204                                                       &= ~__ISFORCED;
205                                         }
206                               }
207                     }
208           }
209 
210           /* Check that cursor position on "win" is valid for "__virtscr" */
211           newy = wbegy + dwin->cury - begy;
212           newx = wbegx + dwin->curx - begx;
213           if (begy <= dwin->cury && dwin->cury < maxy
214               && 0 <= newy && newy < screen->__virtscr->maxy)
215                     screen->__virtscr->cury = newy;
216           if (begx <= dwin->curx && dwin->curx < maxx
217               && 0 <= newx && newx < screen->__virtscr->maxx)
218                     screen->__virtscr->curx = newx;
219 
220           /* Copy the window flags from "win" to "__virtscr" */
221           if (dwin->flags & __CLEAROK) {
222                     if (dwin->flags & __FULLWIN)
223                               screen->__virtscr->flags |= __CLEAROK;
224                     dwin->flags &= ~__CLEAROK;
225           }
226           screen->__virtscr->flags &= ~__LEAVEOK;
227           screen->__virtscr->flags |= dwin->flags;
228 
229           if ((dwin->flags & __ISDERWIN) != 0)
230                     endy = begy + maxy;
231           else
232                     endy = maxy;
233 
234           for (wy = begy, y_off = wbegy, dy_off = 0; wy < endy &&
235               y_off < screen->__virtscr->maxy; wy++, y_off++, dy_off++)
236           {
237                     wlp = swin->alines[wy];
238                     dwlp = dwin->alines[dy_off];
239 #ifdef DEBUG
240                     __CTRACE(__CTRACE_REFRESH,
241                         "_wnoutrefresh: wy %d\tf %d\tl %d\tflags %x\n",
242                         wy, *wlp->firstchp, *wlp->lastchp, wlp->flags);
243 
244                     char *_wintype;
245 
246                     if ((dwin->flags & __ISDERWIN) != 0)
247                               _wintype = "derwin";
248                     else
249                               _wintype = "dwin";
250 
251                     __CTRACE(__CTRACE_REFRESH,
252                         "_wnoutrefresh: %s wy %d\tf %d\tl %d\tflags %x\n",
253                         _wintype, dy_off, *dwlp->firstchp, *dwlp->lastchp,
254                         dwlp->flags);
255                     __CTRACE(__CTRACE_REFRESH,
256                         "_wnoutrefresh: %s maxx %d\tch_off %d wlp %p\n",
257                         _wintype, dwin->maxx, dwin->ch_off, wlp);
258 #endif
259                     if (((wlp->flags & (__ISDIRTY | __ISFORCED)) == 0) &&
260                         ((dwlp->flags & (__ISDIRTY | __ISFORCED)) == 0))
261                               continue;
262                     __CTRACE(__CTRACE_REFRESH,
263                         "_wnoutrefresh: line y_off %d (dy_off %d) is dirty\n",
264                         y_off, dy_off);
265 
266                     wlp = swin->alines[wy];
267                     vlp = screen->__virtscr->alines[y_off];
268 
269                     if ((*wlp->firstchp < maxx + swin->ch_off &&
270                         *wlp->lastchp >= swin->ch_off) ||
271                         ((((dwin->flags & __ISDERWIN) != 0) &&
272                          (*dwlp->firstchp < dwin->maxx + dwin->ch_off &&
273                           *dwlp->lastchp >= dwin->ch_off))))
274                     {
275                               /* Set start column */
276                               wx = begx;
277                               x_off = wbegx;
278                               dx_off = 0;
279                               /*
280                                * if a derwin then source change pointers aren't
281                                * relevant.
282                                */
283                               if ((dwin->flags & __ISDERWIN) != 0)
284                                         mx = wx + maxx;
285                               else {
286                                         if (*wlp->firstchp - swin->ch_off > 0) {
287                                                   wx += *wlp->firstchp - swin->ch_off;
288                                                   x_off += *wlp->firstchp - swin->ch_off;
289                                         }
290                                         mx = maxx;
291                                         if (mx > *wlp->lastchp - swin->ch_off + 1)
292                                                   mx = *dwlp->lastchp - dwin->ch_off + 1;
293                                         if (x_off + (mx - wx) > screen->__virtscr->maxx)
294                                                   mx -= (x_off + maxx) -
295                                                       screen->__virtscr->maxx;
296                               }
297 
298                               /* Copy line from "win" to "__virtscr". */
299                               while (wx < mx) {
300                                         __CTRACE(__CTRACE_REFRESH,
301                                             "_wnoutrefresh: copy from %d, "
302                                             "%d to %d, %d: '%s', 0x%x, 0x%x",
303                                             wy, wx, y_off, x_off,
304                                             unctrl(wlp->line[wx].ch),
305                                             wlp->line[wx].attr, wlp->line[wx].cflags);
306                                         __CTRACE(__CTRACE_REFRESH,
307                                             " (curdest %s, 0x%x, 0x%x)",
308                                             unctrl(vlp->line[x_off].ch),
309                                             vlp->line[x_off].attr,
310                                             vlp->line[x_off].cflags);
311                                         /* Copy character */
312                                         vlp->line[x_off].ch = wlp->line[wx].ch;
313                                         /* Copy attributes  */
314                                         vlp->line[x_off].attr = wlp->line[wx].attr;
315                                         /* Copy character flags  */
316                                         vlp->line[x_off].cflags = wlp->line[wx].cflags;
317 #ifdef HAVE_WCHAR
318                                         vlp->line[x_off].wcols = wlp->line[wx].wcols;
319 
320                                         ch = wlp->line[wx].ch;
321                                         for (tx = x_off + 1, i = wlp->line[wx].wcols - 1;
322                                             i > 0; i--, tx++) {
323                                                   vlp->line[tx].ch = ch;
324                                                   vlp->line[tx].wcols = i;
325                                                   vlp->line[tx].cflags =
326                                                       CA_CONTINUATION;
327                                         }
328 #endif /* HAVE_WCHAR */
329                                         if (win->flags & __ISDERWIN) {
330                                                   dwlp->line[dx_off].ch =
331                                                             wlp->line[wx].ch;
332                                                   dwlp->line[dx_off].attr =
333                                                             wlp->line[wx].attr;
334                                                   dwlp->line[dx_off].cflags =
335                                                             wlp->line[wx].cflags;
336 #ifdef HAVE_WCHAR
337                                                   dwlp->line[dx_off].wcols =
338                                                             wlp->line[wx].wcols;
339 
340                                                   for (tx = dx_off + 1, i = wlp->line[wx].wcols - 1;
341                                                       i > 0; i--, tx++) {
342                                                             dwlp->line[tx].ch = ch;
343                                                             dwlp->line[tx].wcols = i;
344                                                             dwlp->line[tx].cflags =
345                                                                 CA_CONTINUATION;
346                                                   }
347 #endif /* HAVE_WCHAR */
348                                         }
349 
350 #ifdef HAVE_WCHAR
351                                         if (wlp->line[wx].ch == win->bch) {
352                                                   vlp->line[x_off].ch = win->bch;
353                                                   vlp->line[x_off].wcols = win->wcols;
354                                                   vlp->line[x_off].cflags = CA_BACKGROUND;
355                                                   if (_cursesi_copy_nsp(win->bnsp,
356                                                                             &vlp->line[x_off])
357                                                       == ERR)
358                                                             return ERR;
359                                                   if (win->flags & __ISDERWIN) {
360                                                             dwlp->line[dx_off].ch =
361                                                                       win->bch;
362                                                             dwlp->line[dx_off].wcols =
363                                                                 win->wcols;
364                                                             dwlp->line[dx_off].cflags =
365                                                                       wlp->line[wx].cflags;
366                                                             if (_cursesi_copy_nsp(win->bnsp,
367                                                                  &dwlp->line[dx_off])
368                                                                 == ERR)
369                                                                       return ERR;
370                                                   }
371                                         }
372 #endif /* HAVE_WCHAR */
373                                         __CTRACE(__CTRACE_REFRESH, " = '%s', 0x%x\n",
374                                             unctrl(vlp->line[x_off].ch),
375                                             vlp->line[x_off].attr);
376 #ifdef HAVE_WCHAR
377                                         x_off += wlp->line[wx].wcols;
378                                         dx_off += wlp->line[wx].wcols;
379                                         wx += wlp->line[wx].wcols;
380 #else
381                                         wx++;
382                                         x_off++;
383                                         dx_off++;
384 #endif /* HAVE_WCHAR */
385                               }
386 
387                               /* Set flags on "__virtscr" and unset on "win". */
388                               if (wlp->flags & __ISPASTEOL)
389                                         vlp->flags |= __ISPASTEOL;
390                               else
391                                         vlp->flags &= ~__ISPASTEOL;
392                               if (wlp->flags & __ISDIRTY)
393                                         vlp->flags |= __ISDIRTY;
394                               if (wlp->flags & __ISFORCED)
395                                         vlp->flags |= __ISFORCED;
396 
397 #ifdef DEBUG
398                               __CTRACE(__CTRACE_REFRESH,
399                                   "win: firstch = %d, lastch = %d\n",
400                                   *wlp->firstchp, *wlp->lastchp);
401                               if (win->flags & __ISDERWIN) {
402                                         __CTRACE(__CTRACE_REFRESH,
403                                             "derwin: fistch = %d, lastch = %d\n",
404                                             *dwlp->firstchp, *dwlp->lastchp);
405                               }
406 #endif
407                               /* Set change pointers on "__virtscr". */
408                               if (*vlp->firstchp >
409                                         *wlp->firstchp + wbegx - win->ch_off)
410                                                   *vlp->firstchp =
411                                                       *wlp->firstchp + wbegx - win->ch_off;
412                               if (*vlp->lastchp <
413                                         *wlp->lastchp + wbegx - win->ch_off)
414                                                   *vlp->lastchp =
415                                                       *wlp->lastchp + wbegx - win->ch_off;
416 
417                               if (win->flags & __ISDERWIN) {
418                                         if (*vlp->firstchp >
419                                             *dwlp->firstchp + wbegx - dwin->ch_off)
420                                         {
421                                                   *vlp->firstchp =
422                                                       *dwlp->firstchp + wbegx
423                                                             - dwin->ch_off;
424                                                   vlp->flags |= __ISDIRTY;
425                                         }
426 
427                                         if (*vlp->lastchp <
428                                             *dwlp->lastchp + wbegx - dwin->ch_off)
429                                         {
430                                                   *vlp->lastchp = *dwlp->lastchp
431                                                       + wbegx - dwin->ch_off;
432                                                   vlp->flags |= __ISDIRTY;
433                                         }
434                               }
435 
436                               __CTRACE(__CTRACE_REFRESH,
437                                   "__virtscr: firstch = %d, lastch = %d\n",
438                                   *vlp->firstchp, *vlp->lastchp);
439                               /*
440                                * Unset change pointers only if a window and we
441                                * are not forcing a redraw. A pad can be displayed
442                                * again without any of the contents changing.
443                                */
444                               if (!((win->flags & __ISPAD)) ||
445                                   ((wlp->flags & __ISFORCED) == __ISFORCED))
446                               {
447                                         /* Set change pointers on "win". */
448                                         if (*wlp->firstchp >= win->ch_off)
449                                                   *wlp->firstchp = maxx + win->ch_off;
450                                         if (*wlp->lastchp < maxx + win->ch_off)
451                                                   *wlp->lastchp = win->ch_off;
452                                         if ((*wlp->lastchp < *wlp->firstchp) ||
453                                             (*wlp->firstchp >= maxx + win->ch_off) ||
454                                             (*wlp->lastchp <= win->ch_off)) {
455                                                   __CTRACE(__CTRACE_REFRESH,
456                                                       "_wnoutrefresh: "
457                                                       "line %d notdirty\n", wy);
458                                                   wlp->flags &= ~(__ISDIRTY | __ISFORCED);
459                                         }
460                               }
461                     }
462           }
463           return OK;
464 }
465 
466 /*
467  * wrefresh --
468  *        Make the current screen look like "win" over the area covered by
469  *        win.
470  */
471 int
wrefresh(WINDOW * win)472 wrefresh(WINDOW *win)
473 {
474           int retval;
475           int pbegx, pbegy;
476 
477           __CTRACE(__CTRACE_REFRESH, "wrefresh: win %p\n", win);
478 
479           if (__predict_false(win == NULL))
480                     return ERR;
481 
482           _cursesi_screen->curwin = (win == _cursesi_screen->curscr);
483           if (!_cursesi_screen->curwin) {
484                     pbegx = pbegy = 0;
485                     if ((win->flags & __ISDERWIN) == __ISDERWIN) {
486                               pbegx = win->derx;
487                               pbegy = win->dery;
488           __CTRACE(__CTRACE_REFRESH, "wrefresh: derwin, begy = %d, begx = %x\n",
489                     pbegy, pbegx);
490                     }
491                     retval = _wnoutrefresh(win, pbegy, pbegx, win->begy, win->begx,
492                         win->maxy, win->maxx);
493           } else
494                     retval = OK;
495           if (retval == OK) {
496                     retval = doupdate();
497                     if (!(win->flags & __LEAVEOK)) {
498                               win->cury = max(0, curscr->cury - win->begy);
499                               win->curx = max(0, curscr->curx - win->begx);
500                     }
501           }
502           _cursesi_screen->curwin = 0;
503           return retval;
504 }
505 
506  /*
507  * prefresh --
508  *        Make the current screen look like "pad" over the area coverd by
509  *        the specified area of pad.
510  */
511 int
prefresh(WINDOW * pad,int pbegy,int pbegx,int sbegy,int sbegx,int smaxy,int smaxx)512 prefresh(WINDOW *pad, int pbegy, int pbegx, int sbegy, int sbegx,
513           int smaxy, int smaxx)
514 {
515           int retval;
516 
517           __CTRACE(__CTRACE_REFRESH, "prefresh: pad %p, flags 0x%08x\n",
518               pad, pad->flags);
519 
520           if (__predict_false(pad == NULL))
521                     return ERR;
522 
523           /* Retain values in case pechochar() is called. */
524           pad->pbegy = pbegy;
525           pad->pbegx = pbegx;
526           pad->sbegy = sbegy;
527           pad->sbegx = sbegx;
528           pad->smaxy = smaxy;
529           pad->smaxx = smaxx;
530 
531           /* Use pnoutrefresh() to avoid duplicating code here */
532           retval = pnoutrefresh(pad, pbegy, pbegx, sbegy, sbegx, smaxy, smaxx);
533           if (retval == OK) {
534                     retval = doupdate();
535                     if (!(pad->flags & __LEAVEOK)) {
536                               pad->cury = max(0, pbegy + (curscr->cury - sbegy));
537                               pad->curx = max(0, pbegx + (curscr->curx - sbegx));
538                     }
539           }
540           return retval;
541 }
542 
543 /*
544  * doupdate --
545  *        Make the current screen look like the virtual window "__virtscr".
546  */
547 int
doupdate(void)548 doupdate(void)
549 {
550           WINDOW    *win;
551           __LINE    *wlp, *vlp;
552           short      wy;
553           int        dnum, was_cleared, changed;
554 
555           /* Check if we need to restart ... */
556           if (_cursesi_screen->endwin)
557                     __restartwin();
558 
559           if (_cursesi_screen->curwin)
560                     win = curscr;
561           else
562                     win = _cursesi_screen->__virtscr;
563 
564           /* Initialize loop parameters. */
565           _cursesi_screen->ly = curscr->cury;
566           _cursesi_screen->lx = curscr->curx;
567           wy = 0;
568 
569           if (!_cursesi_screen->curwin) {
570                     for (wy = 0; wy < win->maxy; wy++) {
571                               wlp = win->alines[wy];
572                               if (wlp->flags & __ISDIRTY)
573                                         wlp->hash = __hash_line(wlp->line, win->maxx);
574                     }
575           }
576 
577           was_cleared = 0;
578           if ((win->flags & __CLEAROK) || (curscr->flags & __CLEAROK) ||
579               _cursesi_screen->curwin)
580           {
581                     if (curscr->wattr & __COLOR)
582                               __unsetattr(0);
583                     tputs(clear_screen, 0, __cputchar);
584                     _cursesi_screen->ly = 0;
585                     _cursesi_screen->lx = 0;
586                     if (!_cursesi_screen->curwin) {
587                               curscr->flags &= ~__CLEAROK;
588                               curscr->cury = 0;
589                               curscr->curx = 0;
590                               werase(curscr);
591                     }
592                     __touchwin(win, 0);
593                     win->flags &= ~__CLEAROK;
594                     /* note we cleared for later */
595                     was_cleared = 1;
596           }
597           if (!cursor_address) {
598                     if (win->curx != 0)
599                               __cputchar('\n');
600                     if (!_cursesi_screen->curwin)
601                               werase(curscr);
602           }
603           __CTRACE(__CTRACE_REFRESH, "doupdate: (%p): curwin = %d\n", win,
604               _cursesi_screen->curwin);
605           __CTRACE(__CTRACE_REFRESH, "doupdate: \tfirstch\tlastch\n");
606 
607           if (!_cursesi_screen->curwin) {
608                     /*
609                      * Invoke quickch() only if more than a quarter of the lines
610                      * in the window are dirty.
611                      */
612                     for (wy = 0, dnum = 0; wy < win->maxy; wy++)
613                               if (win->alines[wy]->flags & __ISDIRTY)
614                                         dnum++;
615                     if (!__noqch && dnum > (int) win->maxy / 4)
616                               quickch();
617           }
618 
619 #ifdef DEBUG
620           {
621                     int       i, j;
622 
623                     __CTRACE(__CTRACE_REFRESH,
624                         "#####################################\n");
625                     __CTRACE(__CTRACE_REFRESH,
626                         "stdscr(%p)-curscr(%p)-__virtscr(%p)\n",
627                         stdscr, curscr, _cursesi_screen->__virtscr);
628                     for (i = 0; i < curscr->maxy; i++) {
629                               __CTRACE(__CTRACE_REFRESH, "curscr: %d:", i);
630                               __CTRACE(__CTRACE_REFRESH, " 0x%x \n",
631                                   curscr->alines[i]->hash);
632                               for (j = 0; j < curscr->maxx; j++)
633                                         __CTRACE(__CTRACE_REFRESH, "%c",
634                                             curscr->alines[i]->line[j].ch);
635                               __CTRACE(__CTRACE_REFRESH, "\n");
636                               __CTRACE(__CTRACE_REFRESH, " attr:");
637                               for (j = 0; j < curscr->maxx; j++)
638                                         __CTRACE(__CTRACE_REFRESH, " %x",
639                                             curscr->alines[i]->line[j].attr);
640                               __CTRACE(__CTRACE_REFRESH, "\n");
641 #ifdef HAVE_WCHAR
642                               __CTRACE(__CTRACE_REFRESH, " wcols:");
643                               for (j = 0; j < curscr->maxx; j++)
644                                         __CTRACE(__CTRACE_REFRESH, " %d",
645                                             curscr->alines[i]->line[j].wcols);
646                               __CTRACE(__CTRACE_REFRESH, "\n");
647 
648                               __CTRACE(__CTRACE_REFRESH, " cflags:");
649                               for (j = 0; j < curscr->maxx; j++)
650                                         __CTRACE(__CTRACE_REFRESH, " 0x%x",
651                                             curscr->alines[i]->line[j].cflags);
652                               __CTRACE(__CTRACE_REFRESH, "\n");
653 #endif /* HAVE_WCHAR */
654                               __CTRACE(__CTRACE_REFRESH, "win %p: %d:", win, i);
655                               __CTRACE(__CTRACE_REFRESH, " 0x%x \n",
656                                   win->alines[i]->hash);
657                               __CTRACE(__CTRACE_REFRESH, " 0x%x ",
658                                   win->alines[i]->flags);
659                               for (j = 0; j < win->maxx; j++)
660                                         __CTRACE(__CTRACE_REFRESH, "%c",
661                                             win->alines[i]->line[j].ch);
662                               __CTRACE(__CTRACE_REFRESH, "\n");
663                               __CTRACE(__CTRACE_REFRESH, " attr:");
664                               for (j = 0; j < win->maxx; j++)
665                                         __CTRACE(__CTRACE_REFRESH, " %x",
666                                             win->alines[i]->line[j].attr);
667                               __CTRACE(__CTRACE_REFRESH, "\n");
668 #ifdef HAVE_WCHAR
669                               __CTRACE(__CTRACE_REFRESH, " wcols:");
670                               for (j = 0; j < win->maxx; j++)
671                                         __CTRACE(__CTRACE_REFRESH, " %d",
672                                             win->alines[i]->line[j].wcols);
673                               __CTRACE(__CTRACE_REFRESH, "\n");
674                               __CTRACE(__CTRACE_REFRESH, " cflags:");
675                               for (j = 0; j < win->maxx; j++)
676                                         __CTRACE(__CTRACE_REFRESH, " 0x%x",
677                                             win->alines[i]->line[j].cflags);
678                               __CTRACE(__CTRACE_REFRESH, "\n");
679                               __CTRACE(__CTRACE_REFRESH, " nsp:");
680                               for (j = 0; j < curscr->maxx; j++)
681                                         __CTRACE(__CTRACE_REFRESH, " %p",
682                                             win->alines[i]->line[j].nsp);
683                               __CTRACE(__CTRACE_REFRESH, "\n");
684                               __CTRACE(__CTRACE_REFRESH, " bnsp:");
685                               for (j = 0; j < curscr->maxx; j++)
686                                         __CTRACE(__CTRACE_REFRESH, " %p",
687                                             win->bnsp);
688                               __CTRACE(__CTRACE_REFRESH, "\n");
689 #endif /* HAVE_WCHAR */
690                     }
691           }
692 #endif /* DEBUG */
693 
694           changed = 0;
695           for (wy = 0; wy < win->maxy; wy++) {
696                     wlp = win->alines[wy];
697                     vlp = _cursesi_screen->__virtscr->alines[win->begy + wy];
698 /* XXX: remove this */
699                     __CTRACE(__CTRACE_REFRESH,
700                         "doupdate: wy %d\tf: %d\tl:%d\tflags %x\n",
701                         wy, *wlp->firstchp, *wlp->lastchp, wlp->flags);
702                     if (!_cursesi_screen->curwin)
703                               curscr->alines[wy]->hash = wlp->hash;
704                     if (wlp->flags & __ISDIRTY || wlp->flags & __ISFORCED) {
705                               __CTRACE(__CTRACE_REFRESH,
706                                   "doupdate: [ISDIRTY]wy:%d\tf:%d\tl:%d\n", wy,
707                                   *wlp->firstchp, *wlp->lastchp);
708                               /*
709                                * We have just cleared so don't force an update
710                                * otherwise we spray needless blanks to a cleared
711                                * screen.  That is, unless, we are using color,
712                                * in this case we need to force the background
713                                * color to default.
714                                */
715                               if ((was_cleared == 1) && (__using_color == 0))
716                                         win->alines[wy]->flags &= ~ 0L;
717                               /*if ((was_cleared == 1) && (__using_color == 0))
718                                         win->alines[wy]->flags &= ~__ISFORCED;*/
719 
720                               if (makech(wy) == ERR)
721                                         return ERR;
722                               else {
723                                         if (*wlp->firstchp >= 0)
724                                                   *wlp->firstchp = win->maxx;
725                                         if (*wlp->lastchp < win->maxx)
726                                                   *wlp->lastchp = win->ch_off;
727                                         if (*wlp->lastchp < *wlp->firstchp) {
728                                                   __CTRACE(__CTRACE_REFRESH,
729                                                       "doupdate: line %d notdirty\n", wy);
730                                                   wlp->flags &= ~(__ISDIRTY | __ISFORCED);
731                                         }
732 
733                                         /* Check if we have input after
734                                          * changing N lines. */
735                                         if (_cursesi_screen->checkfd != -1 &&
736                                             ++changed == CHECK_INTERVAL)
737                                         {
738                                                   struct pollfd fds[1];
739 
740                                                   /* If we have input, abort. */
741                                                   fds[0].fd = _cursesi_screen->checkfd;
742                                                   fds[0].events = POLLIN;
743                                                   if (poll(fds, 1, 0) > 0)
744                                                             goto cleanup;
745                                                   changed = 0;
746                                         }
747                               }
748                     }
749 
750                     /*
751                      * virtscr is now synced for the line, unset the change
752                      * pointers.
753                      */
754                     if (*vlp->firstchp >= 0)
755                               *vlp->firstchp = _cursesi_screen->__virtscr->maxx;
756                     if (*vlp->lastchp <= _cursesi_screen->__virtscr->maxx)
757                               *vlp->lastchp = 0;
758 
759                     __CTRACE(__CTRACE_REFRESH, "\t%d\t%d\n",
760                         *wlp->firstchp, *wlp->lastchp);
761           }
762 
763           __CTRACE(__CTRACE_REFRESH, "doupdate: ly=%d, lx=%d\n",
764               _cursesi_screen->ly, _cursesi_screen->lx);
765 
766           if (_cursesi_screen->curwin)
767                     domvcur(win, _cursesi_screen->ly, _cursesi_screen->lx,
768                               win->cury, win->curx);
769           else {
770                     if (win->flags & __LEAVEOK) {
771                               curscr->cury = _cursesi_screen->ly;
772                               curscr->curx = _cursesi_screen->lx;
773                     } else {
774                               domvcur(win, _cursesi_screen->ly, _cursesi_screen->lx,
775                                         win->cury, win->curx);
776                               curscr->cury = win->cury;
777                               curscr->curx = win->curx;
778                     }
779           }
780 
781 cleanup:
782           /* Don't leave the screen with attributes set. */
783           __unsetattr(0);
784           __do_color_init = 0;
785 #ifdef DEBUG
786 #ifdef HAVE_WCHAR
787           {
788                     int       i, j;
789 
790                     __CTRACE(__CTRACE_REFRESH,
791                         "***********after*****************\n");
792                     __CTRACE(__CTRACE_REFRESH,
793                         "stdscr(%p)-curscr(%p)-__virtscr(%p)\n",
794                         stdscr, curscr, _cursesi_screen->__virtscr);
795                     for (i = 0; i < curscr->maxy; i++) {
796                               for (j = 0; j < curscr->maxx; j++)
797                                         __CTRACE(__CTRACE_REFRESH,
798                                             "[%d,%d](%x,%x,%d,%x,%p)-(%x,%x,%d,%x,%p)\n",
799                                             i, j,
800                                             curscr->alines[i]->line[j].ch,
801                                             curscr->alines[i]->line[j].attr,
802                                             curscr->alines[i]->line[j].wcols,
803                                             curscr->alines[i]->line[j].cflags,
804                                             curscr->alines[i]->line[j].nsp,
805                                             _cursesi_screen->__virtscr->alines[i]->line[j].ch,
806                                             _cursesi_screen->__virtscr->alines[i]->line[j].attr,
807                                             _cursesi_screen->__virtscr->alines[i]->line[j].wcols,
808                                             _cursesi_screen->__virtscr->alines[i]->line[j].cflags,
809                                             _cursesi_screen->__virtscr->alines[i]->line[j].nsp);
810                     }
811           }
812 #endif /* HAVE_WCHAR */
813 #endif /* DEBUG */
814           return fflush(_cursesi_screen->outfd) == EOF ? ERR : OK;
815 }
816 
817 static void
putattr(__LDATA * nsp)818 putattr(__LDATA *nsp)
819 {
820           attr_t    off, on;
821 
822           __CTRACE(__CTRACE_REFRESH,
823               "putattr: have attr %08x, need attr %08x\n",
824               curscr->wattr
825 #ifndef HAVE_WCHAR
826               & __ATTRIBUTES
827 #else
828               & WA_ATTRIBUTES
829 #endif
830               ,  nsp->attr
831 #ifndef HAVE_WCHAR
832               & __ATTRIBUTES
833 #else
834               & WA_ATTRIBUTES
835 #endif
836               );
837 
838           off = (~nsp->attr & curscr->wattr)
839 #ifndef HAVE_WCHAR
840               & __ATTRIBUTES
841 #else
842               & WA_ATTRIBUTES
843 #endif
844               ;
845 
846           /*
847            * Unset attributes as appropriate.  Unset first
848            * so that the relevant attributes can be reset
849            * (because 'me' unsets 'mb', 'md', 'mh', 'mk',
850            * 'mp' and 'mr').  Check to see if we also turn off
851            * standout, attributes and colour.
852            */
853           if (off & __TERMATTR && exit_attribute_mode != NULL) {
854                     tputs(exit_attribute_mode, 0, __cputchar);
855                     curscr->wattr &= __mask_me;
856                     off &= __mask_me;
857           }
858 
859           /*
860            * Exit underscore mode if appropriate.
861            * Check to see if we also turn off standout,
862            * attributes and colour.
863            */
864           if (off & __UNDERSCORE && exit_underline_mode != NULL) {
865                     tputs(exit_underline_mode, 0, __cputchar);
866                     curscr->wattr &= __mask_ue;
867                     off &= __mask_ue;
868           }
869 
870           /*
871            * Exit standout mode as appropriate.
872            * Check to see if we also turn off underscore,
873            * attributes and colour.
874            * XXX
875            * Should use uc if so/se not available.
876            */
877           if (off & __STANDOUT && exit_standout_mode != NULL) {
878                     tputs(exit_standout_mode, 0, __cputchar);
879                     curscr->wattr &= __mask_se;
880                     off &= __mask_se;
881           }
882 
883           if (off & __ALTCHARSET && exit_alt_charset_mode != NULL) {
884                     tputs(exit_alt_charset_mode, 0, __cputchar);
885                     curscr->wattr &= ~__ALTCHARSET;
886           }
887 
888           /* Set/change colour as appropriate. */
889           if (__using_color)
890                     __set_color(curscr, nsp->attr & __COLOR);
891 
892           on = (nsp->attr & ~curscr->wattr)
893 #ifndef HAVE_WCHAR
894               & __ATTRIBUTES
895 #else
896               & WA_ATTRIBUTES
897 #endif
898               ;
899 
900           /*
901            * Enter standout mode if appropriate.
902            */
903           if (on & __STANDOUT &&
904               enter_standout_mode != NULL &&
905               exit_standout_mode != NULL)
906           {
907                     tputs(enter_standout_mode, 0, __cputchar);
908                     curscr->wattr |= __STANDOUT;
909           }
910 
911           /*
912            * Enter underscore mode if appropriate.
913            * XXX
914            * Should use uc if us/ue not available.
915            */
916           if (on & __UNDERSCORE &&
917               enter_underline_mode != NULL &&
918               exit_underline_mode != NULL)
919           {
920                     tputs(enter_underline_mode, 0, __cputchar);
921                     curscr->wattr |= __UNDERSCORE;
922           }
923 
924           /*
925            * Set other attributes as appropriate.
926            */
927           if (exit_attribute_mode != NULL) {
928                     if (on & __BLINK && enter_blink_mode != NULL)
929                     {
930                               tputs(enter_blink_mode, 0, __cputchar);
931                               curscr->wattr |= __BLINK;
932                     }
933                     if (on & __BOLD && enter_bold_mode != NULL)
934                     {
935                               tputs(enter_bold_mode, 0, __cputchar);
936                               curscr->wattr |= __BOLD;
937                     }
938                     if (on & __DIM && enter_dim_mode != NULL)
939                     {
940                               tputs(enter_dim_mode, 0, __cputchar);
941                               curscr->wattr |= __DIM;
942                     }
943                     if (on & __BLANK && enter_secure_mode != NULL)
944                     {
945                               tputs(enter_secure_mode, 0, __cputchar);
946                               curscr->wattr |= __BLANK;
947                     }
948                     if (on & __PROTECT && enter_protected_mode != NULL)
949                     {
950                               tputs(enter_protected_mode, 0, __cputchar);
951                               curscr->wattr |= __PROTECT;
952                     }
953                     if (on & __REVERSE && enter_reverse_mode != NULL)
954                     {
955                               tputs(enter_reverse_mode, 0, __cputchar);
956                               curscr->wattr |= __REVERSE;
957                     }
958 #ifdef HAVE_WCHAR
959                     if (on & WA_TOP && enter_top_hl_mode != NULL)
960                     {
961                               tputs(enter_top_hl_mode, 0, __cputchar);
962                               curscr->wattr |= WA_TOP;
963                     }
964                     if (on & WA_LOW && enter_low_hl_mode != NULL)
965                     {
966                               tputs(enter_low_hl_mode, 0, __cputchar);
967                               curscr->wattr |= WA_LOW;
968                     }
969                     if (on & WA_LEFT && enter_left_hl_mode != NULL)
970                     {
971                               tputs(enter_left_hl_mode, 0, __cputchar);
972                               curscr->wattr |= WA_LEFT;
973                     }
974                     if (on & WA_RIGHT && enter_right_hl_mode != NULL)
975                     {
976                               tputs(enter_right_hl_mode, 0, __cputchar);
977                               curscr->wattr |= WA_RIGHT;
978                     }
979                     if (on & WA_HORIZONTAL && enter_horizontal_hl_mode != NULL)
980                     {
981                               tputs(enter_horizontal_hl_mode, 0, __cputchar);
982                               curscr->wattr |= WA_HORIZONTAL;
983                     }
984                     if (on & WA_VERTICAL && enter_vertical_hl_mode != NULL)
985                     {
986                               tputs(enter_vertical_hl_mode, 0, __cputchar);
987                               curscr->wattr |= WA_VERTICAL;
988                     }
989 #endif /* HAVE_WCHAR */
990           }
991 
992           /* Enter/exit altcharset mode as appropriate. */
993           if (on & __ALTCHARSET && enter_alt_charset_mode != NULL &&
994               exit_alt_charset_mode != NULL) {
995                     tputs(enter_alt_charset_mode, 0, __cputchar);
996                     curscr->wattr |= __ALTCHARSET;
997           }
998 }
999 
1000 static void
putattr_out(__LDATA * nsp)1001 putattr_out(__LDATA *nsp)
1002 {
1003 
1004           if (underline_char &&
1005               ((nsp->attr & __STANDOUT) || (nsp->attr & __UNDERSCORE)))
1006           {
1007                     __cputchar('\b');
1008                     tputs(underline_char, 0, __cputchar);
1009           }
1010 }
1011 
1012 static int
putch(__LDATA * nsp,__LDATA * csp,int wy,int wx)1013 putch(__LDATA *nsp, __LDATA *csp, int wy, int wx)
1014 {
1015 #ifdef HAVE_WCHAR
1016           int i;
1017           __LDATA *tcsp;
1018 #endif /* HAVE_WCHAR */
1019 
1020           if (csp != NULL)
1021                     putattr(nsp);
1022 
1023           if (!_cursesi_screen->curwin && csp) {
1024                     csp->attr = nsp->attr;
1025                     csp->ch = nsp->ch;
1026                     csp->cflags = nsp->cflags;
1027 #ifdef HAVE_WCHAR
1028                     if (_cursesi_copy_nsp(nsp->nsp, csp) == ERR)
1029                               return ERR;
1030                     csp->wcols = nsp->wcols;
1031 
1032                     if (nsp->wcols > 1) {
1033                               tcsp = csp;
1034                               tcsp++;
1035                               for (i = nsp->wcols - 1; i > 0; i--) {
1036                                         tcsp->ch = csp->ch;
1037                                         tcsp->attr = csp->attr;
1038                                         tcsp->wcols = i;
1039                                         tcsp->cflags = CA_CONTINUATION;
1040                                         tcsp++;
1041                               }
1042                     }
1043 #endif /* HAVE_WCHAR */
1044           }
1045 
1046 #ifndef HAVE_WCHAR
1047           __cputchar((int)nsp->ch);
1048 #else
1049           if ((nsp->wcols <= 0) || (nsp->cflags & CA_CONTINUATION))
1050                     goto out;
1051 
1052           if (((_cursesi_screen->nca & nsp->attr) == 0) && (__using_color == 1) &&
1053               csp == NULL)
1054                     __set_color(curscr, nsp->attr & __COLOR);
1055           __cputwchar((int)nsp->ch);
1056           __CTRACE(__CTRACE_REFRESH,
1057               "putch: (%d,%d)putwchar(0x%x)\n", wy, wx, nsp->ch);
1058 
1059           /* Output non-spacing characters for the cell. */
1060           __cursesi_putnsp(nsp->nsp, wy, wx);
1061 out:
1062 #endif /* HAVE_WCHAR */
1063 
1064           if (csp != NULL)
1065                     putattr_out(nsp);
1066           return OK;
1067 }
1068 
1069 static int
putchbr(__LDATA * nsp,__LDATA * csp,__LDATA * psp,int wy,int wx)1070 putchbr(__LDATA *nsp, __LDATA *csp, __LDATA *psp, int wy, int wx)
1071 {
1072           int error, cw, pcw;
1073 
1074           /* Can safely print to bottom right corner. */
1075           if (!auto_right_margin)
1076                     return putch(nsp, csp, wy, wx);
1077 
1078           /* Disable auto margins temporarily. */
1079           if (enter_am_mode && exit_am_mode) {
1080                     tputs(exit_am_mode, 0, __cputchar);
1081                     error = putch(nsp, csp, wy, wx);
1082                     tputs(enter_am_mode, 0, __cputchar);
1083                     return error;
1084           }
1085 
1086           /* We need to insert characters. */
1087 #ifdef HAVE_WCHAR
1088           cw = nsp->wcols;
1089           pcw = psp->wcols;
1090           if (cw < 1 || pcw < 1)
1091                     return ERR; /* Nothing to insert */
1092 
1093           /* When inserting a wide character, we need something other than
1094            * insert_character. */
1095           if (pcw > 1 &&
1096               !(parm_ich != NULL ||
1097               (enter_insert_mode != NULL && exit_insert_mode != NULL)))
1098                     return ERR;
1099 #else
1100           cw = pcw = 1;
1101 #endif /* HAVE_WCHAR */
1102 
1103           /* Write the corner character at wx - pcw. */
1104           __mvcur(wy, wx, wy, wx - pcw, 1);
1105           if (putch(nsp, csp, wy, wx) == ERR)
1106                     return ERR;
1107 
1108           /* Move cursor back. */
1109           __mvcur(wy, wx - pcw + cw, wy, wx - cw, 1);
1110 
1111           putattr(psp);
1112 
1113           /* Enter insert mode. */
1114           if (pcw == 1 && insert_character != NULL)
1115                     tputs(insert_character, 0, __cputchar);
1116           else if (parm_ich != NULL)
1117                     tputs(tiparm(parm_ich, (long)pcw), 0, __cputchar);
1118           else if (enter_insert_mode != NULL && exit_insert_mode != NULL)
1119                     tputs(enter_insert_mode, 0, __cputchar);
1120           else
1121                     return ERR;
1122 
1123           /* Insert the old character back. */
1124           error = putch(psp, NULL, wy, wx - pcw);
1125 
1126           /* Exit insert mode. */
1127           if (insert_character != NULL || parm_ich != NULL)
1128                     ;
1129           else if (enter_insert_mode != NULL && exit_insert_mode != NULL)
1130                     tputs(exit_insert_mode, 0, __cputchar);
1131 
1132           putattr_out(psp);
1133 
1134           return error;
1135 }
1136 
1137 /*
1138  * makech --
1139  *        Make a change on the screen.
1140  */
1141 static int
makech(int wy)1142 makech(int wy)
1143 {
1144           WINDOW    *win;
1145           static __LDATA blank;
1146           __LDATA *nsp, *csp, *cp, *cep, *fsp;
1147           __LINE *wlp;
1148           int       nlsp;     /* offset to first space at eol. */
1149           size_t    mlsp;
1150           int       lch, wx, owx, chw;
1151           const char          *ce;
1152           attr_t    lspc;               /* Last space colour */
1153           attr_t    battr;              /* background attribute bits */
1154           attr_t    attr_mask;          /* attributes mask */
1155 
1156 #ifdef __GNUC__
1157           nlsp = lspc = 0;    /* XXX gcc -Wuninitialized */
1158 #endif
1159           if (_cursesi_screen->curwin)
1160                     win = curscr;
1161           else
1162                     win = __virtscr;
1163 
1164           blank.ch = win->bch;
1165           blank.attr = win->battr;
1166           blank.cflags = CA_BACKGROUND;
1167 #ifdef HAVE_WCHAR
1168           if (_cursesi_copy_nsp(win->bnsp, &blank) == ERR)
1169                     return ERR;
1170           blank.wcols = win->wcols;
1171           attr_mask = WA_ATTRIBUTES;
1172 #else
1173           attr_mask = A_ATTRIBUTES;
1174 #endif /* HAVE_WCHAR */
1175           battr = win->battr & attr_mask;
1176 
1177 #ifdef DEBUG
1178 #if HAVE_WCHAR
1179           {
1180                     int x;
1181                     __LDATA *lp, *vlp;
1182 
1183                     __CTRACE(__CTRACE_REFRESH,
1184                         "[makech-before]wy=%d,curscr(%p)-__virtscr(%p)\n",
1185                         wy, curscr, __virtscr);
1186                     for (x = 0; x < curscr->maxx; x++) {
1187                               lp = &curscr->alines[wy]->line[x];
1188                               vlp = &__virtscr->alines[wy]->line[x];
1189                               __CTRACE(__CTRACE_REFRESH,
1190                                   "[%d,%d](%x,%x,%d,%x,%x,%d,%p)-"
1191                                   "(%x,%x,%d,%x,%x,%d,%p)\n",
1192                                   wy, x, lp->ch, lp->attr, lp->wcols,
1193                                   win->bch, win->battr, win->wcols, lp->nsp,
1194                                   vlp->ch, vlp->attr, vlp->wcols,
1195                                   win->bch, win->battr, win->wcols, vlp->nsp);
1196                     }
1197           }
1198 #endif /* HAVE_WCHAR */
1199 #endif /* DEBUG */
1200 
1201           /* Is the cursor still on the end of the last line? */
1202           if (wy > 0 && curscr->alines[wy - 1]->flags & __ISPASTEOL) {
1203                     domvcur(win, _cursesi_screen->ly, _cursesi_screen->lx,
1204                               _cursesi_screen->ly + 1, 0);
1205                     _cursesi_screen->ly++;
1206                     _cursesi_screen->lx = 0;
1207           }
1208           wlp = win->alines[wy];
1209           wx = *win->alines[wy]->firstchp;
1210           if (wx < 0)
1211                     wx = 0;
1212           else
1213                     if (wx >= win->maxx)
1214                               return (OK);
1215           lch = *win->alines[wy]->lastchp;
1216           if (lch < 0)
1217                     return OK;
1218           else
1219                     if (lch >= (int) win->maxx)
1220                               lch = win->maxx - 1;
1221 
1222           if (_cursesi_screen->curwin) {
1223                     csp = &blank;
1224                     __CTRACE(__CTRACE_REFRESH, "makech: csp is blank\n");
1225           } else {
1226                     csp = &curscr->alines[wy]->line[wx];
1227                     __CTRACE(__CTRACE_REFRESH,
1228                         "makech: csp is on curscr:(%d,%d)\n", wy, wx);
1229           }
1230 
1231 
1232           while (win->alines[wy]->line[wx].cflags & CA_CONTINUATION) {
1233                     wx--;
1234                     if (wx <= 0) {
1235                               wx = 0;
1236                               break;
1237                     }
1238           }
1239 
1240           nsp = fsp = &win->alines[wy]->line[wx];
1241 
1242 #ifdef DEBUG
1243           if (_cursesi_screen->curwin)
1244                     __CTRACE(__CTRACE_REFRESH,
1245                         "makech: nsp is at curscr:(%d,%d)\n", wy, wx);
1246           else
1247                     __CTRACE(__CTRACE_REFRESH,
1248                         "makech: nsp is at __virtscr:(%d,%d)\n", wy, wx);
1249 #endif /* DEBUG */
1250 
1251           /*
1252            * Work out if we can use a clear to end of line.  If we are
1253            * using color then we can only erase the line if the terminal
1254            * can erase to the background color.
1255            */
1256           if (clr_eol && !_cursesi_screen->curwin && (!(__using_color)
1257               || (__using_color && back_color_erase))) {
1258                     nlsp = win->maxx - 1;
1259                     cp = &win->alines[wy]->line[win->maxx - 1];
1260 #ifdef HAVE_WCHAR
1261                     while ((_cursesi_celleq(cp, &blank) == 1) &&
1262 #else
1263                     while (cp->ch == blank.ch &&
1264 #endif /* HAVE_WCHAR */
1265                         ((cp->attr & attr_mask) == battr)) {
1266 #ifdef HAVE_WCHAR
1267                               nlsp -= cp->wcols;
1268                               cp -= cp->wcols;
1269 #else
1270                               nlsp--;
1271                               cp--;
1272 #endif /* HAVE_WCHAR */
1273 
1274                               if (nlsp <= 0)
1275                                         break;
1276                     }
1277 
1278 
1279                     if (nlsp < 0)
1280                               nlsp = 0;
1281           }
1282 
1283           ce = clr_eol;
1284 
1285           while (wx <= lch) {
1286                     __CTRACE(__CTRACE_REFRESH, "makech: wx=%d,lch=%d, nlsp=%d\n", wx, lch, nlsp);
1287 #ifdef HAVE_WCHAR
1288                     __CTRACE(__CTRACE_REFRESH, "makech: farnarkle: flags 0x%x, cflags 0x%x, color_init %d, celleq %d\n",
1289                               wlp->flags, nsp->cflags, __do_color_init, _cursesi_celleq(nsp, csp));
1290                     __CTRACE(__CTRACE_REFRESH, "makech: nsp=(%x,%x,%d,%x,%x,%d,%p)\n",
1291                               nsp->ch, nsp->attr, nsp->wcols, win->bch, win->battr,
1292                               win->wcols, nsp->nsp);
1293                     __CTRACE(__CTRACE_REFRESH, "makech: csp=(%x,%x,%d,%x,%x,%d,%p)\n",
1294                               csp->ch, csp->attr, csp->wcols, win->bch, win->battr,
1295                               win->wcols, csp->nsp);
1296 #endif
1297                     if (!(wlp->flags & __ISFORCED) &&
1298 #ifdef HAVE_WCHAR
1299                         ((nsp->cflags & CA_CONTINUATION) != CA_CONTINUATION) &&
1300 #endif
1301                         _cursesi_celleq(nsp, csp))
1302                     {
1303                               if (wx <= lch) {
1304                                         while (wx <= lch && _cursesi_celleq(nsp, csp)) {
1305 #ifdef HAVE_WCHAR
1306                                                   wx += nsp->wcols;
1307                                                   if (!_cursesi_screen->curwin)
1308                                                             csp += nsp->wcols;
1309                                                   nsp += nsp->wcols;
1310 #else
1311                                                   wx++;
1312                                                   nsp++;
1313                                                   if (!_cursesi_screen->curwin)
1314                                                             ++csp;
1315 #endif
1316                                         }
1317                                         continue;
1318                               }
1319                               break;
1320                     }
1321 
1322                     domvcur(win, _cursesi_screen->ly, _cursesi_screen->lx, wy, wx);
1323 
1324                     __CTRACE(__CTRACE_REFRESH, "makech: 1: wx = %d, ly= %d, "
1325                         "lx = %d, newy = %d, newx = %d, lch = %d\n",
1326                         wx, _cursesi_screen->ly, _cursesi_screen->lx, wy, wx, lch);
1327                     _cursesi_screen->ly = wy;
1328                     _cursesi_screen->lx = wx;
1329                     owx = wx;
1330                     while (wx <= lch &&
1331                            ((wlp->flags & __ISFORCED) || !_cursesi_celleq(nsp, csp)))
1332                     {
1333                               if ((ce != NULL) && (wx >= nlsp) &&
1334                                   (nsp->ch == blank.ch) &&
1335                                   (__do_color_init == 1 || nsp->attr == blank.attr))
1336                               {
1337                                         /* Check for clear to end-of-line. */
1338                                         cep = &win->alines[wy]->line[win->maxx - 1];
1339                                         while (cep->ch == blank.ch && cep->attr == battr)
1340                                                   if (cep-- <= csp)
1341                                                             break;
1342 
1343                                         mlsp = &win->alines[wy]->line[win->maxx - 1]
1344                                             - win->alines[wy]->line
1345                                             - win->begx * __LDATASIZE;
1346 
1347                                         __CTRACE(__CTRACE_REFRESH,
1348                                             "makech: nlsp = %d, max = %zu, strlen(ce) = %zu\n",
1349                                             nlsp, mlsp, strlen(ce));
1350                                         __CTRACE(__CTRACE_REFRESH,
1351                                             "makech: line = %p, cep = %p, begx = %u\n",
1352                                             win->alines[wy]->line, cep, win->begx);
1353 
1354                                         /*
1355                                          * work out how to clear the line.  If:
1356                                          *  - clear len is greater than clear_to_eol len
1357                                          *  - background char == ' '
1358                                          *  - we are not at EOL
1359                                          *  - using color and term can erase to
1360                                          *    background color
1361                                          *  - if we are at the bottom of the window
1362                                          *    (to prevent a scroll)
1363                                          * then emit the ce string.
1364                                          */
1365                                         if (((wy == win->maxy - 1) ||
1366                                             ((mlsp - wx) > strlen(ce))) &&
1367                                              ((__using_color && back_color_erase) ||
1368                                               (! __using_color))) {
1369                                                   if (wlp->line[wx].attr & win->screen->nca) {
1370                                                             __unsetattr(0);
1371                                                   } else if (__using_color &&
1372                                                       ((__do_color_init == 1) ||
1373                                                       ((lspc & __COLOR) !=
1374                                                       (curscr->wattr & __COLOR)))) {
1375                                                             __set_color(curscr, lspc &
1376                                                                 __COLOR);
1377                                                   }
1378                                                   tputs(ce, 0, __cputchar);
1379                                                   _cursesi_screen->lx = wx + win->begx;
1380                                                   csp = &curscr->alines[wy]->line[wx + win->begx];
1381                                                   wx = wx + win->begx;
1382                                                   while (wx++ <= (curscr->maxx - 1)) {
1383                                                             csp->attr = blank.attr;
1384                                                             csp->ch = blank.ch;
1385                                                             csp->cflags = CA_BACKGROUND;
1386 #ifdef HAVE_WCHAR
1387                                                             if (_cursesi_copy_nsp(blank.nsp, csp) == ERR)
1388                                                                       return ERR;
1389                                                             csp->wcols = blank.wcols;
1390                                                             csp += blank.wcols;
1391 #else
1392                                                             csp++;
1393 #endif /* HAVE_WCHAR */
1394                                                             assert(csp != &blank);
1395                                                   }
1396                                                   return OK;
1397                                         }
1398                               }
1399 
1400 #ifdef HAVE_WCHAR
1401                               chw = nsp->wcols;
1402                               if (chw < 0)
1403                                         chw = 0; /* match putch() */
1404 #else
1405                               chw = 1;
1406 #endif /* HAVE_WCHAR */
1407                               owx = wx;
1408                               if (wx + chw >= (win->maxx) &&
1409                                   wy == win->maxy - 1 && !_cursesi_screen->curwin)
1410                               {
1411                                         if (win->flags & __ENDLINE)
1412                                                   __unsetattr(1);
1413                                         if (!(win->flags & __SCROLLWIN)) {
1414                                                   int e;
1415 
1416                                                   if (win->flags & __SCROLLOK)
1417                                                             e = putch(nsp, csp, wy, wx);
1418                                                   else {
1419                                                             e = putchbr(nsp, csp,
1420                                                                 nsp == fsp ? NULL : nsp - 1,
1421                                                                 wy, wx);
1422                                                   }
1423                                                   if (e == ERR)
1424                                                             return ERR;
1425                                         }
1426                                         if (wx + chw < curscr->maxx) {
1427                                                   domvcur(win,
1428                                                       _cursesi_screen->ly, wx,
1429                                                       (int)(win->maxy - 1),
1430                                                       (int)(win->maxx - 1));
1431                                         }
1432                                         _cursesi_screen->ly = win->maxy - 1;
1433                                         _cursesi_screen->lx = win->maxx - 1;
1434                                         return OK;
1435                               }
1436                               if (wx + chw < win->maxx || wy < win->maxy - 1 ||
1437                                   !(win->flags & __SCROLLWIN))
1438                               {
1439                                         if (putch(nsp, csp, wy, wx) == ERR)
1440                                                   return ERR;
1441                               } else {
1442                                         putattr(nsp);
1443                                         putattr_out(nsp);
1444                               }
1445                               wx += chw;
1446                               nsp += chw;
1447                               if (!_cursesi_screen->curwin)
1448                                         csp += chw;
1449 
1450                               __CTRACE(__CTRACE_REFRESH,
1451                                   "makech: 2: wx = %d, lx = %d\n",
1452                                   wx, _cursesi_screen->lx);
1453                     }
1454                     if (_cursesi_screen->lx == wx)          /* If no change. */
1455                               break;
1456 
1457                     /*
1458                      * We need to work out if the cursor has been put in the
1459                      * middle of a wide character so check if curx is between
1460                      * where we were and where we are and we are on the right
1461                      * line.  If so, move the cursor now.
1462                      */
1463                     if ((wy == win->cury) && (wx > win->curx) &&
1464                         (owx < win->curx)) {
1465                               _cursesi_screen->lx = win->curx;
1466                               domvcur(win, _cursesi_screen->ly, wx,
1467                                   _cursesi_screen->ly, _cursesi_screen->lx);
1468                     } else
1469                               _cursesi_screen->lx = wx;
1470 
1471                     if (_cursesi_screen->lx >= COLS && auto_right_margin)
1472                               _cursesi_screen->lx = COLS - 1;
1473                     else
1474                               if (wx >= win->maxx) {
1475                                         domvcur(win,
1476                                                   _cursesi_screen->ly,
1477                                                   _cursesi_screen->lx,
1478                                                   _cursesi_screen->ly,
1479                                                   (int)(win->maxx - 1));
1480                                         _cursesi_screen->lx = win->maxx - 1;
1481                               }
1482                     __CTRACE(__CTRACE_REFRESH, "makech: 3: wx = %d, lx = %d\n",
1483                         wx, _cursesi_screen->lx);
1484           }
1485 #ifdef DEBUG
1486 #if HAVE_WCHAR
1487           {
1488                     int x;
1489                     __LDATA *lp, *vlp;
1490 
1491                     __CTRACE(__CTRACE_REFRESH,
1492                         "makech-after: curscr(%p)-__virtscr(%p)\n",
1493                         curscr, __virtscr );
1494                     for (x = 0; x < curscr->maxx; x++) {
1495                               lp = &curscr->alines[wy]->line[x];
1496                               vlp = &__virtscr->alines[wy]->line[x];
1497                               __CTRACE(__CTRACE_REFRESH,
1498                                   "[%d,%d](%x,%x,%d,%x,%x,%d,%p)-"
1499                                   "(%x,%x,%d,%x,%x,%d,%p)\n",
1500                                   wy, x, lp->ch, lp->attr, lp->wcols,
1501                                   win->bch, win->battr, win->wcols, lp->nsp,
1502                                   vlp->ch, vlp->attr, vlp->wcols,
1503                                   win->bch, win->battr, win->wcols, vlp->nsp);
1504                     }
1505           }
1506 #endif /* HAVE_WCHAR */
1507 #endif /* DEBUG */
1508 
1509           return OK;
1510 }
1511 
1512 /*
1513  * domvcur --
1514  *        Do a mvcur, leaving attributes if necessary.
1515  */
1516 static void
domvcur(WINDOW * win,int oy,int ox,int ny,int nx)1517 domvcur(WINDOW *win, int oy, int ox, int ny, int nx)
1518 {
1519 
1520           __CTRACE(__CTRACE_REFRESH, "domvcur: (%d,%d)=>(%d,%d) win %p\n",
1521               oy, ox, ny, nx, win );
1522 
1523           __unsetattr(1);
1524 
1525           /* Don't move the cursor unless we need to. */
1526           if (oy == ny && ox == nx) {
1527                     /* Check EOL. */
1528                     if (!(win->alines[oy]->flags & __ISPASTEOL))
1529                               return;
1530           }
1531 
1532           /* Clear EOL flags. */
1533           win->alines[oy]->flags &= ~__ISPASTEOL;
1534           win->alines[ny]->flags &= ~__ISPASTEOL;
1535 
1536           __mvcur(oy, ox, ny, nx, 1);
1537 }
1538 
1539 /*
1540  * Quickch() attempts to detect a pattern in the change of the window
1541  * in order to optimize the change, e.g., scroll n lines as opposed to
1542  * repainting the screen line by line.
1543  */
1544 
1545 static __LDATA buf[128];
1546 static  unsigned int last_hash;
1547 static  size_t last_hash_len;
1548 #define BLANKSIZE (sizeof(buf) / sizeof(buf[0]))
1549 
1550 static void
quickch(void)1551 quickch(void)
1552 {
1553 #define THRESH                (int) __virtscr->maxy / 4
1554 
1555           __LINE *clp, *tmp1, *tmp2;
1556           int       bsize, curs, curw, starts, startw, i, j;
1557           int       n, target, cur_period, bot, top, sc_region;
1558           unsigned int        blank_hash, found;
1559           attr_t    bcolor;
1560 
1561 #ifdef __GNUC__
1562           curs = curw = starts = startw = 0;      /* XXX gcc -Wuninitialized */
1563 #endif
1564           /*
1565            * Find how many lines from the top of the screen are unchanged.
1566            */
1567           for (top = 0; top < __virtscr->maxy; top++) {
1568                     if (__virtscr->alines[top]->flags & __ISDIRTY &&
1569                         (__virtscr->alines[top]->hash != curscr->alines[top]->hash ||
1570                          !lineeq(__virtscr->alines[top]->line,
1571                                    curscr->alines[top]->line,
1572                                    (size_t) __virtscr->maxx))) {
1573                               break;
1574                     } else
1575                               __virtscr->alines[top]->flags &= ~__ISDIRTY;
1576           }
1577           /*
1578            * Find how many lines from bottom of screen are unchanged.
1579            */
1580           for (bot = __virtscr->maxy - 1; bot >= 0; bot--) {
1581                     if (__virtscr->alines[bot]->flags & __ISDIRTY &&
1582                         (__virtscr->alines[bot]->hash != curscr->alines[bot]->hash ||
1583                          !lineeq(__virtscr->alines[bot]->line,
1584                                    curscr->alines[bot]->line,
1585                                    (size_t) __virtscr->maxx))) {
1586                               break;
1587                     } else
1588                               __virtscr->alines[bot]->flags &= ~__ISDIRTY;
1589           }
1590 
1591           /*
1592            * Work round an xterm bug where inserting lines causes all the
1593            * inserted lines to be covered with the background colour we
1594            * set on the first line (even if we unset it for subsequent
1595            * lines).
1596            */
1597           bcolor = __virtscr->alines[min(top,
1598               __virtscr->maxy - 1)]->line[0].attr & __COLOR;
1599           for (i = top + 1, j = 0; i < bot; i++) {
1600                     if ((__virtscr->alines[i]->line[0].attr & __COLOR) != bcolor) {
1601                               bcolor = __virtscr->alines[i]->line[__virtscr->maxx].
1602                                   attr & __COLOR;
1603                               j = i - top;
1604                     } else
1605                               break;
1606           }
1607           top += j;
1608 
1609 #ifdef NO_JERKINESS
1610           /*
1611            * If we have a bottom unchanged region return.  Scrolling the
1612            * bottom region up and then back down causes a screen jitter.
1613            * This will increase the number of characters sent to the screen
1614            * but it looks better.
1615            */
1616           if (bot < __virtscr->maxy - 1)
1617                     return;
1618 #endif                                  /* NO_JERKINESS */
1619 
1620           /*
1621            * Search for the largest block of text not changed.
1622            * Invariants of the loop:
1623            * - Startw is the index of the beginning of the examined block in
1624            *   __virtscr.
1625            * - Starts is the index of the beginning of the examined block in
1626            *   curscr.
1627            * - Curw is the index of one past the end of the exmined block in
1628            *   __virtscr.
1629            * - Curs is the index of one past the end of the exmined block in
1630            *   curscr.
1631            * - bsize is the current size of the examined block.
1632           */
1633 
1634           found = 0;
1635           for (bsize = bot - top; bsize >= THRESH; bsize--) {
1636                     for (startw = top; startw <= bot - bsize; startw++)
1637                               for (starts = top; starts <= bot - bsize; starts++) {
1638 /*                                      for (curw = startw, curs = starts;
1639                                             curs < starts + bsize; curw++, curs++)
1640                                                   if (__virtscr->alines[curw]->hash !=
1641                                                       curscr->alines[curs]->hash)
1642                                                             break;
1643                                         if (curs != starts + bsize)
1644                                                   continue;*/
1645                                         for (curw = startw, curs = starts;
1646                                                   curs < starts + bsize; curw++, curs++)
1647                                                   if (!lineeq(__virtscr->alines[curw]->line,
1648                                                                 curscr->alines[curs]->line,
1649                                                                 (size_t) __virtscr->maxx)) {
1650                                                             found = 1;
1651                                                             break;
1652                                         }
1653                                         if ((curs == starts + bsize) && (found == 1)) {
1654                                                   goto done;
1655                                         }
1656                               }
1657           }
1658 done:
1659 
1660           __CTRACE(__CTRACE_REFRESH, "quickch:bsize=%d, THRESH=%d, starts=%d, "
1661               "startw=%d, curw=%d, curs=%d, top=%d, bot=%d\n",
1662               bsize, THRESH, starts, startw, curw, curs, top, bot);
1663 
1664           /* Did not find anything */
1665           if (bsize < THRESH)
1666                     return;
1667 
1668           /*
1669            * Make sure that there is no overlap between the bottom and top
1670            * regions and the middle scrolled block.
1671            */
1672           if (bot < curs)
1673                     bot = curs - 1;
1674           if (top > starts)
1675                     top = starts;
1676 
1677           n = startw - starts;
1678 
1679 #ifdef DEBUG
1680           __CTRACE(__CTRACE_REFRESH, "#####################################\n");
1681           __CTRACE(__CTRACE_REFRESH, "quickch: n = %d\n", n);
1682           for (i = 0; i < curscr->maxy; i++) {
1683                     __CTRACE(__CTRACE_REFRESH, "C: %d:", i);
1684                     __CTRACE(__CTRACE_REFRESH, " 0x%x \n", curscr->alines[i]->hash);
1685                     for (j = 0; j < curscr->maxx; j++)
1686                               __CTRACE(__CTRACE_REFRESH, "%c",
1687                                   curscr->alines[i]->line[j].ch);
1688                     __CTRACE(__CTRACE_REFRESH, "\n");
1689                     __CTRACE(__CTRACE_REFRESH, " attr:");
1690                     for (j = 0; j < curscr->maxx; j++)
1691                               __CTRACE(__CTRACE_REFRESH, " %x",
1692                                   curscr->alines[i]->line[j].attr);
1693                     __CTRACE(__CTRACE_REFRESH, "\n");
1694                     __CTRACE(__CTRACE_REFRESH, "W: %d:", i);
1695                     __CTRACE(__CTRACE_REFRESH, " 0x%x \n",
1696                         __virtscr->alines[i]->hash);
1697                     __CTRACE(__CTRACE_REFRESH, " 0x%x ",
1698                         __virtscr->alines[i]->flags);
1699                     for (j = 0; j < __virtscr->maxx; j++)
1700                               __CTRACE(__CTRACE_REFRESH, "%c",
1701                                   __virtscr->alines[i]->line[j].ch);
1702                     __CTRACE(__CTRACE_REFRESH, "\n");
1703                     __CTRACE(__CTRACE_REFRESH, " attr:");
1704                     for (j = 0; j < __virtscr->maxx; j++)
1705                               __CTRACE(__CTRACE_REFRESH, " %x",
1706                                   __virtscr->alines[i]->line[j].attr);
1707                     __CTRACE(__CTRACE_REFRESH, "\n");
1708           }
1709 #endif
1710 
1711 #ifndef HAVE_WCHAR
1712           if (buf[0].ch != curscr->bch) {
1713                     for (i = 0; i < BLANKSIZE; i++) {
1714                               buf[i].ch = curscr->bch;
1715                               buf[i].attr = 0;
1716                               buf[i].cflags = CA_BACKGROUND;
1717                     }
1718           }
1719 #else
1720           if (buf[0].ch != curscr->bch) {
1721                     for (i = 0; i < BLANKSIZE; i++) { /* XXXX: BLANKSIZE may not be valid if wcols > 1 */
1722                               buf[i].ch = curscr->bch;
1723                               if (_cursesi_copy_nsp(curscr->bnsp, &buf[i]) == ERR)
1724                                         return;
1725                               buf[i].attr = 0;
1726                               buf[i].cflags = CA_BACKGROUND;
1727                               buf[i].wcols = curscr->wcols;
1728                     }
1729           }
1730 #endif /* HAVE_WCHAR */
1731 
1732           if (__virtscr->maxx != last_hash_len) {
1733                     blank_hash = 0;
1734                     for (i = __virtscr->maxx; i > BLANKSIZE; i -= BLANKSIZE) {
1735                               blank_hash = __hash_more(buf, sizeof(buf), blank_hash);
1736                     }
1737                     blank_hash = __hash_more((char *)(void *)buf,
1738                         i * sizeof(buf[0]), blank_hash);
1739                     /* cache result in static data - screen width doesn't change often */
1740                     last_hash_len = __virtscr->maxx;
1741                     last_hash = blank_hash;
1742           } else
1743                     blank_hash = last_hash;
1744 
1745           /*
1746            * Perform the rotation to maintain the consistency of curscr.
1747            * This is hairy since we are doing an *in place* rotation.
1748            * Invariants of the loop:
1749            * - I is the index of the current line.
1750            * - Target is the index of the target of line i.
1751            * - Tmp1 points to current line (i).
1752            * - Tmp2 and points to target line (target);
1753            * - Cur_period is the index of the end of the current period.
1754            *   (see below).
1755            *
1756            * There are 2 major issues here that make this rotation non-trivial:
1757            * 1.  Scrolling in a scrolling region bounded by the top
1758            *     and bottom regions determined (whose size is sc_region).
1759            * 2.  As a result of the use of the mod function, there may be a
1760            *     period introduced, i.e., 2 maps to 4, 4 to 6, n-2 to 0, and
1761            *     0 to 2, which then causes all odd lines not to be rotated.
1762            *     To remedy this, an index of the end ( = beginning) of the
1763            *     current 'period' is kept, cur_period, and when it is reached,
1764            *     the next period is started from cur_period + 1 which is
1765            *     guaranteed not to have been reached since that would mean that
1766            *     all records would have been reached. (think about it...).
1767            *
1768            * Lines in the rotation can have 3 attributes which are marked on the
1769            * line so that curscr is consistent with the visual screen.
1770            * 1.  Not dirty -- lines inside the scrolled block, top region or
1771            *                  bottom region.
1772            * 2.  Blank lines -- lines in the differential of the scrolling
1773            *                        region adjacent to top and bot regions
1774            *                    depending on scrolling direction.
1775            * 3.  Dirty line -- all other lines are marked dirty.
1776            */
1777           sc_region = bot - top + 1;
1778           i = top;
1779           tmp1 = curscr->alines[top];
1780           cur_period = top;
1781           for (j = top; j <= bot; j++) {
1782                     target = (i - top + n + sc_region) % sc_region + top;
1783                     tmp2 = curscr->alines[target];
1784                     curscr->alines[target] = tmp1;
1785                     /* Mark block as clean and blank out scrolled lines. */
1786                     clp = curscr->alines[target];
1787                     __CTRACE(__CTRACE_REFRESH,
1788                         "quickch: n=%d startw=%d curw=%d i = %d target=%d ",
1789                         n, startw, curw, i, target);
1790                     if ((target >= startw && target < curw) || target < top
1791                         || target > bot)
1792                     {
1793                               __CTRACE(__CTRACE_REFRESH, " notdirty\n");
1794                               __virtscr->alines[target]->flags &= ~__ISDIRTY;
1795                     } else
1796                               if ((n > 0 && target >= top && target < top + n) ||
1797                                   (n < 0 && target <= bot && target > bot + n))
1798                               {
1799                                         if (clp->hash != blank_hash ||
1800                                             !lineeq(clp->line, clp->line + 1,
1801                                                       (__virtscr->maxx - 1)) ||
1802                                             !_cursesi_celleq(clp->line, buf))
1803                                         {
1804                                                   for (i = __virtscr->maxx;
1805                                                       i > BLANKSIZE;
1806                                                       i -= BLANKSIZE) {
1807                                                             (void) memcpy(clp->line + i -
1808                                                                 BLANKSIZE, buf, sizeof(buf));
1809                                                   }
1810                                                   (void)memcpy(clp->line, buf,
1811                                                       i * sizeof(buf[0]));
1812                                                   __CTRACE(__CTRACE_REFRESH,
1813                                                       " blanked out: dirty\n");
1814                                                   clp->hash = blank_hash;
1815                                                   __touchline(__virtscr, target, 0, (int) __virtscr->maxx - 1);
1816                                         } else {
1817                                                   __CTRACE(__CTRACE_REFRESH,
1818                                                       " -- blank line already: dirty\n");
1819                                                   __touchline(__virtscr, target, 0, (int) __virtscr->maxx - 1);
1820                                         }
1821                               } else {
1822                                         __CTRACE(__CTRACE_REFRESH, " -- dirty\n");
1823                                         __touchline(__virtscr, target, 0,
1824                                             (int)__virtscr->maxx - 1);
1825                               }
1826                     if (target == cur_period) {
1827                               i = target + 1;
1828                               tmp1 = curscr->alines[i];
1829                               cur_period = i;
1830                     } else {
1831                               tmp1 = tmp2;
1832                               i = target;
1833                     }
1834           }
1835 #ifdef DEBUG
1836           __CTRACE(__CTRACE_REFRESH, "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n");
1837           for (i = 0; i < curscr->maxy; i++) {
1838                     __CTRACE(__CTRACE_REFRESH, "C: %d:", i);
1839                     for (j = 0; j < curscr->maxx; j++)
1840                               __CTRACE(__CTRACE_REFRESH, "%c",
1841                                   curscr->alines[i]->line[j].ch);
1842                     __CTRACE(__CTRACE_REFRESH, "\n");
1843                     __CTRACE(__CTRACE_REFRESH, "W: %d:", i);
1844                     for (j = 0; j < __virtscr->maxx; j++)
1845                               __CTRACE(__CTRACE_REFRESH, "%c",
1846                                   __virtscr->alines[i]->line[j].ch);
1847                     __CTRACE(__CTRACE_REFRESH, "\n");
1848           }
1849 #endif
1850           if (n != 0)
1851                     scrolln(starts, startw, curs, bot, top);
1852 }
1853 
1854 /*
1855  * scrolln --
1856  *        Scroll n lines, where n is starts - startw.
1857  */
1858 static void /* ARGSUSED */
scrolln(int starts,int startw,int curs,int bot,int top)1859 scrolln(int starts, int startw, int curs, int bot, int top)
1860 {
1861           int       i, oy, ox, n;
1862 
1863           oy = curscr->cury;
1864           ox = curscr->curx;
1865           n = starts - startw;
1866 
1867           /*
1868            * XXX
1869            * The initial tests that set __noqch don't let us reach here unless
1870            * we have either cs + ho + SF/sf/SR/sr, or AL + DL.  SF/sf and SR/sr
1871            * scrolling can only shift the entire scrolling region, not just a
1872            * part of it, which means that the quickch() routine is going to be
1873            * sadly disappointed in us if we don't have cs as well.
1874            *
1875            * If cs, ho and SF/sf are set, can use the scrolling region.  Because
1876            * the cursor position after cs is undefined, we need ho which gives us
1877            * the ability to move to somewhere without knowledge of the current
1878            * location of the cursor.  Still call __mvcur() anyway, to update its
1879            * idea of where the cursor is.
1880            *
1881            * When the scrolling region has been set, the cursor has to be at the
1882            * last line of the region to make the scroll happen.
1883            *
1884            * Doing SF/SR or AL/DL appears faster on the screen than either sf/sr
1885            * or AL/DL, and, some terminals have AL/DL, sf/sr, and cs, but not
1886            * SF/SR.  So, if we're scrolling almost all of the screen, try and use
1887            * AL/DL, otherwise use the scrolling region.  The "almost all" is a
1888            * shameless hack for vi.
1889            */
1890           if (n > 0) {
1891                     if (change_scroll_region != NULL && cursor_home != NULL &&
1892                         (parm_index != NULL ||
1893                         ((parm_insert_line == NULL || parm_delete_line == NULL ||
1894                         top > 3 || bot + 3 < __virtscr->maxy) &&
1895                         scroll_forward != NULL)))
1896                     {
1897                               tputs(tiparm(change_scroll_region, top, bot),
1898                                   0, __cputchar);
1899                               __mvcur(oy, ox, 0, 0, 1);
1900                               tputs(cursor_home, 0, __cputchar);
1901                               __mvcur(0, 0, bot, 0, 1);
1902                               if (parm_index != NULL)
1903                                         tputs(tiparm(parm_index, n),
1904                                             0, __cputchar);
1905                               else
1906                                         for (i = 0; i < n; i++)
1907                                                   tputs(scroll_forward, 0, __cputchar);
1908                               tputs(tiparm(change_scroll_region,
1909                                   0, (int)__virtscr->maxy - 1), 0, __cputchar);
1910                               __mvcur(bot, 0, 0, 0, 1);
1911                               tputs(cursor_home, 0, __cputchar);
1912                               __mvcur(0, 0, oy, ox, 1);
1913                               return;
1914                     }
1915 
1916                     /* Scroll up the block. */
1917                     if (parm_index != NULL && top == 0) {
1918                               __mvcur(oy, ox, bot, 0, 1);
1919                               tputs(tiparm(parm_index, n), 0, __cputchar);
1920                     } else
1921                               if (parm_delete_line != NULL) {
1922                                         __mvcur(oy, ox, top, 0, 1);
1923                                         tputs(tiparm(parm_delete_line, n),
1924                                             0, __cputchar);
1925                               } else
1926                                         if (delete_line != NULL) {
1927                                                   __mvcur(oy, ox, top, 0, 1);
1928                                                   for (i = 0; i < n; i++)
1929                                                             tputs(delete_line, 0,
1930                                                                 __cputchar);
1931                                         } else
1932                                                   if (scroll_forward != NULL && top == 0) {
1933                                                             __mvcur(oy, ox, bot, 0, 1);
1934                                                             for (i = 0; i < n; i++)
1935                                                                       tputs(scroll_forward, 0,
1936                                                                           __cputchar);
1937                                                   } else
1938                                                             abort();
1939 
1940                     /* Push down the bottom region. */
1941                     __mvcur(top, 0, bot - n + 1, 0, 1);
1942                     if (parm_insert_line != NULL)
1943                               tputs(tiparm(parm_insert_line, n), 0, __cputchar);
1944                     else {
1945                               if (insert_line != NULL) {
1946                                         for (i = 0; i < n; i++)
1947                                                   tputs(insert_line, 0, __cputchar);
1948                               } else
1949                                         abort();
1950                     }
1951                     __mvcur(bot - n + 1, 0, oy, ox, 1);
1952           } else {
1953                     /*
1954                      * !!!
1955                      * n < 0
1956                      *
1957                      * If cs, ho and SR/sr are set, can use the scrolling region.
1958                      * See the above comments for details.
1959                      */
1960                     if (change_scroll_region != NULL && cursor_home != NULL &&
1961                         (parm_rindex != NULL ||
1962                         ((parm_insert_line == NULL || parm_delete_line == NULL ||
1963                         top > 3 ||
1964                         bot + 3 < __virtscr->maxy) && scroll_reverse != NULL)))
1965                     {
1966                               tputs(tiparm(change_scroll_region, top, bot),
1967                                   0, __cputchar);
1968                               __mvcur(oy, ox, 0, 0, 1);
1969                               tputs(cursor_home, 0, __cputchar);
1970                               __mvcur(0, 0, top, 0, 1);
1971 
1972                               if (parm_rindex != NULL)
1973                                         tputs(tiparm(parm_rindex, -n),
1974                                             0, __cputchar);
1975                               else
1976                                         for (i = n; i < 0; i++)
1977                                                   tputs(scroll_reverse, 0, __cputchar);
1978                               tputs(tiparm(change_scroll_region,
1979                                   0, (int) __virtscr->maxy - 1), 0, __cputchar);
1980                               __mvcur(top, 0, 0, 0, 1);
1981                               tputs(cursor_home, 0, __cputchar);
1982                               __mvcur(0, 0, oy, ox, 1);
1983                               return;
1984                     }
1985 
1986                     /* Preserve the bottom lines. */
1987                     __mvcur(oy, ox, bot + n + 1, 0, 1);
1988                     if (parm_rindex != NULL && bot == __virtscr->maxy)
1989                               tputs(tiparm(parm_rindex, -n), 0, __cputchar);
1990                     else {
1991                               if (parm_delete_line != NULL)
1992                                         tputs(tiparm(parm_delete_line, -n),
1993                                             0, __cputchar);
1994                               else {
1995                                         if (delete_line != NULL)
1996                                                   for (i = n; i < 0; i++)
1997                                                             tputs(delete_line,
1998                                                                 0, __cputchar);
1999                                         else {
2000                                                   if (scroll_reverse != NULL &&
2001                                                       bot == __virtscr->maxy)
2002                                                             for (i = n; i < 0; i++)
2003                                                                       tputs(scroll_reverse, 0,
2004                                                                           __cputchar);
2005                                                   else
2006                                                             abort();
2007                                         }
2008                               }
2009                     }
2010                     /* Scroll the block down. */
2011                     __mvcur(bot + n + 1, 0, top, 0, 1);
2012                     if (parm_insert_line != NULL)
2013                               tputs(tiparm(parm_insert_line, -n), 0, __cputchar);
2014                     else
2015                               if (insert_line != NULL)
2016                                         for (i = n; i < 0; i++)
2017                                                   tputs(insert_line, 0, __cputchar);
2018                               else
2019                                         abort();
2020                     __mvcur(top, 0, oy, ox, 1);
2021           }
2022 }
2023 
2024 /*
2025  * __unsetattr --
2026  *        Unset attributes on curscr.  Leave standout, attribute and colour
2027  *        modes if necessary (!ms).  Always leave altcharset (xterm at least
2028  *        ignores a cursor move if we don't).
2029  */
2030 void /* ARGSUSED */
__unsetattr(int checkms)2031 __unsetattr(int checkms)
2032 {
2033           int       isms;
2034 
2035           if (checkms) {
2036                     if (!move_standout_mode)
2037                               isms = 1;
2038                     else
2039                               isms = 0;
2040           } else
2041                     isms = 1;
2042           __CTRACE(__CTRACE_REFRESH,
2043               "__unsetattr: checkms = %d, ms = %s, wattr = %08x\n",
2044               checkms, move_standout_mode ? "TRUE" : "FALSE", curscr->wattr);
2045 
2046           /*
2047            * Don't leave the screen in standout mode (check against ms).  Check
2048            * to see if we also turn off underscore, attributes and colour.
2049            */
2050           if (curscr->wattr & __STANDOUT && isms) {
2051                     tputs(exit_standout_mode, 0, __cputchar);
2052                     curscr->wattr &= __mask_se;
2053           }
2054           /*
2055            * Don't leave the screen in underscore mode (check against ms).
2056            * Check to see if we also turn off attributes.  Assume that we
2057            * also turn off colour.
2058            */
2059           if (curscr->wattr & __UNDERSCORE && isms) {
2060                     tputs(exit_underline_mode, 0, __cputchar);
2061                     curscr->wattr &= __mask_ue;
2062           }
2063           /*
2064            * Don't leave the screen with attributes set (check against ms).
2065            * Assume that also turn off colour.
2066            */
2067           if (curscr->wattr & __TERMATTR && isms) {
2068                     tputs(exit_attribute_mode, 0, __cputchar);
2069                     curscr->wattr &= __mask_me;
2070           }
2071           /* Don't leave the screen with altcharset set (don't check ms). */
2072           if (curscr->wattr & __ALTCHARSET) {
2073                     tputs(exit_alt_charset_mode, 0, __cputchar);
2074                     curscr->wattr &= ~__ALTCHARSET;
2075           }
2076           /* Don't leave the screen with colour set (check against ms). */
2077           if (__using_color && isms)
2078                     __unset_color(curscr);
2079 }
2080 
2081 /* compare two line segments */
2082 static int
lineeq(__LDATA * xl,__LDATA * yl,size_t len)2083 lineeq(__LDATA *xl, __LDATA *yl, size_t len)
2084 {
2085           int i = 0;
2086           __LDATA *xp = xl, *yp = yl;
2087 
2088           for (i = 0; i < len; i++, xp++, yp++) {
2089                     if (!_cursesi_celleq(xp, yp))
2090                               return 0;
2091           }
2092           return 1;
2093 }
2094 
2095 #ifdef HAVE_WCHAR
2096 /*
2097  * Output the non-spacing characters associated with the given character
2098  * cell to the screen.
2099  */
2100 
2101 void
__cursesi_putnsp(nschar_t * nsp,const int wy,const int wx)2102 __cursesi_putnsp(nschar_t *nsp, const int wy, const int wx)
2103 {
2104           nschar_t *p;
2105 
2106           /* this shuts up gcc warnings about wx and wy not being used */
2107           if (wx > wy) {
2108           }
2109 
2110           p = nsp;
2111           while (p != NULL) {
2112                     __cputwchar((int)p->ch);
2113                     __CTRACE(__CTRACE_REFRESH,
2114                         "_cursesi_putnsp: (%d,%d) non-spacing putwchar(0x%x)\n",
2115                         wy, wx - 1, p->ch);
2116                     p = p->next;
2117           }
2118 }
2119 
2120 #endif /* HAVE_WCHAR */
2121