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