xref: /original-bsd/usr.bin/window/wwupdate.c (revision c3e32dec)
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 
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