xref: /original-bsd/usr.bin/window/wwupdate.c (revision 7323bcb8)
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.22 (Berkeley) 08/08/88";
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 didit;
32 	char check_clreos = 0;
33 	int scan_top, scan_bot;
34 
35 	wwnupdate++;
36 	{
37 		register char *t1 = wwtouched + top, *t2 = wwtouched + bot;
38 		register n;
39 
40 		while (!*t1++)
41 			if (t1 == t2)
42 				return;
43 		while (!*--t2)
44 			;
45 		scan_top = top = t1 - wwtouched - 1;
46 		scan_bot = bot = t2 - wwtouched + 1;
47 		if (scan_bot - scan_top > 1 &&
48 		    (tt.tt_clreos != 0 || tt.tt_clear != 0)) {
49 			int st = tt.tt_clreos != 0 ? scan_top : 0;
50 
51 			for (n = 1; t1 < t2;)
52 				if (*t1++)
53 					n++;
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 		for (j = scan_bot - 1, u = wwupd + j; j >= top; j--, u--) {
112 			register g = gain + u->best_gain;
113 
114 			if (g >= best_gain) {
115 				best_gain = g;
116 				best_row = j;
117 			}
118 			gain += u->gain;
119 			if (tt.tt_clreol != 0 && u->best_gain > 4)
120 				simple_gain += u->best_gain - 4;
121 		}
122 		if (tt.tt_clreos == 0) {
123 			if (gain > simple_gain && gain > 4) {
124 				(*tt.tt_clear)();
125 				i = top = scan_top;
126 				bot = scan_bot;
127 				j = 0;
128 				didit = 1;
129 			}
130 		} else
131 			if (best_gain > simple_gain && best_gain > 4) {
132 				i = best_row;
133 				(*tt.tt_move)(i, j = wwupd[i].best_col);
134 				(*tt.tt_clreos)();
135 				bot = scan_bot;
136 				didit = 1;
137 			}
138 		if (didit) {
139 			wwnupdclreos++;
140 			wwnupdclreosline += wwnrow - i;
141 			u = wwupd + i;
142 			while (i < scan_bot) {
143 				register union ww_char *os = &wwos[i][j];
144 
145 				for (j = wwncol - j; --j >= 0;)
146 					os++->c_w = ' ';
147 				wwtouched[i++] |= WWU_TOUCHED;
148 				u++->best_gain = 0;
149 				j = 0;
150 			}
151 		} else
152 			wwnupdclreosmiss++;
153 	}
154 simple:
155 	for (i = top, touched = &wwtouched[i], upd = &wwupd[i]; i < bot;
156 	     i++, touched++, upd++) {
157 		register union ww_char *os, *ns;
158 		char didit;
159 
160 		if (!*touched)
161 			continue;
162 		*touched = 0;
163 		wwnupdline++;
164 		didit = 0;
165 		if (tt.tt_clreol != 0 && upd->best_gain > 4) {
166 			wwnupdclreol++;
167 			(*tt.tt_move)(i, j = upd->best_col);
168 			(*tt.tt_clreol)();
169 			for (os = &wwos[i][j], j = wwncol - j; --j >= 0;)
170 				os++->c_w = ' ';
171 			didit = 1;
172 		}
173 		ns = wwns[i];
174 		os = wwos[i];
175 		for (j = 0; j < wwncol;) {
176 			register char *p, *q;
177 			char m;
178 			int c;
179 			register n;
180 			char buf[512];			/* > wwncol */
181 			union ww_char lastc;
182 
183 			for (; j++ < wwncol && ns++->c_w == os++->c_w;)
184 				;
185 			if (j > wwncol)
186 				break;
187 			p = buf;
188 			m = ns[-1].c_m;
189 			c = j - 1;
190 			os[-1] = ns[-1];
191 			*p++ = ns[-1].c_c;
192 			n = 5;
193 			q = p;
194 			while (j < wwncol && ns->c_m == m) {
195 				*p++ = ns->c_c;
196 				if (ns->c_w == os->c_w) {
197 					if (--n <= 0)
198 						break;
199 					os++;
200 					ns++;
201 				} else {
202 					n = 5;
203 					q = p;
204 					lastc = *os;
205 					*os++ = *ns++;
206 				}
207 				j++;
208 			}
209 			tt.tt_nmodes = m;
210 			if (wwwrap
211 			    && i == wwnrow - 1 && q - buf + c == wwncol) {
212 				if (tt.tt_hasinsert) {
213 					if (q - buf != 1) {
214 						(*tt.tt_move)(i, c);
215 						(*tt.tt_write)(buf + 1,
216 							q - buf - 1);
217 						(*tt.tt_move)(i, c);
218 						tt.tt_ninsert = 1;
219 						(*tt.tt_write)(buf, 1);
220 						tt.tt_ninsert = 0;
221 					} else {
222 						(*tt.tt_move)(i, c - 1);
223 						(*tt.tt_write)(buf, 1);
224 						tt.tt_nmodes = ns[-2].c_m;
225 						(*tt.tt_move)(i, c - 1);
226 						tt.tt_ninsert = 1;
227 						(*tt.tt_write)(&ns[-2].c_c, 1);
228 						tt.tt_ninsert = 0;
229 					}
230 				} else {
231 					if (q - buf > 1) {
232 						(*tt.tt_move)(i, c);
233 						(*tt.tt_write)(buf, q-buf-1);
234 					}
235 					os[-1] = lastc;
236 					*touched = WWU_TOUCHED;
237 				}
238 			} else {
239 				(*tt.tt_move)(i, c);
240 				(*tt.tt_write)(buf, q - buf);
241 			}
242 			didit = 1;
243 		}
244 		if (!didit)
245 			wwnupdmiss++;
246 	}
247 }
248