1 /*
2 * Copyright (c) 1983, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Edward Wang at The University of California, Berkeley.
7 *
8 * %sccs.include.redist.c%
9 */
10
11 #ifndef lint
12 static char sccsid[] = "@(#)wwupdate.c 8.1 (Berkeley) 06/06/93";
13 #endif /* not lint */
14
15 #include "ww.h"
16 #include "tt.h"
17
wwupdate1(top,bot)18 wwupdate1(top, bot)
19 {
20 int i;
21 register j;
22 char *touched;
23 struct ww_update *upd;
24 char check_clreos = 0;
25 int scan_top, scan_bot;
26
27 wwnupdate++;
28 {
29 register char *t1 = wwtouched + top, *t2 = wwtouched + bot;
30 register n;
31
32 while (!*t1++)
33 if (t1 == t2)
34 return;
35 while (!*--t2)
36 ;
37 scan_top = top = t1 - wwtouched - 1;
38 scan_bot = bot = t2 - wwtouched + 1;
39 if (scan_bot - scan_top > 1 &&
40 (tt.tt_clreos != 0 || tt.tt_clear != 0)) {
41 int st = tt.tt_clreos != 0 ? scan_top : 0;
42
43 /*
44 * t1 is one past the first touched row,
45 * t2 is on the last touched row.
46 */
47 for (t1--, n = 1; t1 < t2;)
48 if (*t1++)
49 n++;
50 /*
51 * If we can't clreos then we try for clearing
52 * the whole screen.
53 */
54 if (check_clreos = n * 10 > (wwnrow - st) * 9) {
55 scan_top = st;
56 scan_bot = wwnrow;
57 }
58 }
59 }
60 if (tt.tt_clreol == 0 && !check_clreos)
61 goto simple;
62 for (i = scan_top, touched = &wwtouched[i], upd = &wwupd[i];
63 i < scan_bot;
64 i++, touched++, upd++) {
65 register gain = 0;
66 register best_gain = 0;
67 register best_col;
68 register union ww_char *ns, *os;
69
70 if (wwinterrupt())
71 return;
72 if (!check_clreos && !*touched)
73 continue;
74 wwnupdscan++;
75 j = wwncol;
76 ns = &wwns[i][j];
77 os = &wwos[i][j];
78 while (--j >= 0) {
79 /*
80 * The cost of clearing is:
81 * ncol - nblank + X
82 * The cost of straight update is, more or less:
83 * ncol - nsame
84 * We clear if nblank - nsame > X
85 * X is the clreol overhead.
86 * So we make gain = nblank - nsame.
87 */
88 if ((--ns)->c_w == (--os)->c_w)
89 gain--;
90 else
91 best_gain--;
92 if (ns->c_w == ' ')
93 gain++;
94 if (gain > best_gain) {
95 best_col = j;
96 best_gain = gain;
97 }
98 }
99 upd->best_gain = best_gain;
100 upd->best_col = best_col;
101 upd->gain = gain;
102 }
103 if (check_clreos) {
104 register struct ww_update *u;
105 register gain = 0;
106 register best_gain = 0;
107 int best_row;
108 register simple_gain = 0;
109 char didit = 0;
110
111 /*
112 * gain is the advantage of clearing all the lines.
113 * best_gain is the advantage of clearing to eos
114 * at best_row and u->best_col.
115 * simple_gain is the advantage of using only clreol.
116 * We use g > best_gain because u->best_col can be
117 * undefined when u->best_gain is 0 so we can't use it.
118 */
119 for (j = scan_bot - 1, u = wwupd + j; j >= top; j--, u--) {
120 register g = gain + u->best_gain;
121
122 if (g > best_gain) {
123 best_gain = g;
124 best_row = j;
125 }
126 gain += u->gain;
127 if (tt.tt_clreol != 0 && u->best_gain > 4)
128 simple_gain += u->best_gain - 4;
129 }
130 if (tt.tt_clreos == 0) {
131 if (gain > simple_gain && gain > 4) {
132 xxclear();
133 i = top = scan_top;
134 bot = scan_bot;
135 j = 0;
136 didit = 1;
137 }
138 } else
139 if (best_gain > simple_gain && best_gain > 4) {
140 i = best_row;
141 xxclreos(i, j = wwupd[i].best_col);
142 bot = scan_bot;
143 didit = 1;
144 }
145 if (didit) {
146 wwnupdclreos++;
147 wwnupdclreosline += wwnrow - i;
148 u = wwupd + i;
149 while (i < scan_bot) {
150 register union ww_char *os = &wwos[i][j];
151
152 for (j = wwncol - j; --j >= 0;)
153 os++->c_w = ' ';
154 wwtouched[i++] |= WWU_TOUCHED;
155 u++->best_gain = 0;
156 j = 0;
157 }
158 } else
159 wwnupdclreosmiss++;
160 }
161 simple:
162 for (i = top, touched = &wwtouched[i], upd = &wwupd[i]; i < bot;
163 i++, touched++, upd++) {
164 register union ww_char *os, *ns;
165 char didit;
166
167 if (!*touched)
168 continue;
169 *touched = 0;
170 wwnupdline++;
171 didit = 0;
172 if (tt.tt_clreol != 0 && upd->best_gain > 4) {
173 wwnupdclreol++;
174 xxclreol(i, j = upd->best_col);
175 for (os = &wwos[i][j], j = wwncol - j; --j >= 0;)
176 os++->c_w = ' ';
177 didit = 1;
178 }
179 ns = wwns[i];
180 os = wwos[i];
181 for (j = 0; j < wwncol;) {
182 register char *p, *q;
183 char m;
184 int c;
185 register n;
186 char buf[512]; /* > wwncol */
187 union ww_char lastc;
188
189 for (; j++ < wwncol && ns++->c_w == os++->c_w;)
190 ;
191 if (j > wwncol)
192 break;
193 p = buf;
194 m = ns[-1].c_m;
195 c = j - 1;
196 os[-1] = ns[-1];
197 *p++ = ns[-1].c_c;
198 n = 5;
199 q = p;
200 while (j < wwncol && ns->c_m == m) {
201 *p++ = ns->c_c;
202 if (ns->c_w == os->c_w) {
203 if (--n <= 0)
204 break;
205 os++;
206 ns++;
207 } else {
208 n = 5;
209 q = p;
210 lastc = *os;
211 *os++ = *ns++;
212 }
213 j++;
214 }
215 n = q - buf;
216 if (!wwwrap || i != wwnrow - 1 || c + n != wwncol)
217 xxwrite(i, c, buf, n, m);
218 else if (tt.tt_inschar || tt.tt_insspace) {
219 if (n > 1) {
220 q[-2] = q[-1];
221 n--;
222 } else
223 c--;
224 xxwrite(i, c, buf, n, m);
225 c += n - 1;
226 if (tt.tt_inschar)
227 xxinschar(i, c, ns[-2].c_c,
228 ns[-2].c_m);
229 else {
230 xxinsspace(i, c);
231 xxwrite(i, c, &ns[-2].c_c, 1,
232 ns[-2].c_m);
233 }
234 } else {
235 if (--n)
236 xxwrite(i, c, buf, n, m);
237 os[-1] = lastc;
238 *touched = WWU_TOUCHED;
239 }
240 didit = 1;
241 }
242 if (!didit)
243 wwnupdmiss++;
244 }
245 }
246