1 /* $NetBSD: wwupdate.c,v 1.6 2003/08/07 11:17:46 agc Exp $ */ 2 3 /* 4 * Copyright (c) 1983, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Edward Wang at The University of California, Berkeley. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #include <sys/cdefs.h> 36 #ifndef lint 37 #if 0 38 static char sccsid[] = "@(#)wwupdate.c 8.1 (Berkeley) 6/6/93"; 39 #else 40 __RCSID("$NetBSD: wwupdate.c,v 1.6 2003/08/07 11:17:46 agc Exp $"); 41 #endif 42 #endif /* not lint */ 43 44 #include "ww.h" 45 #include "tt.h" 46 #include "xx.h" 47 48 void 49 wwupdate1(int top, int bot) 50 { 51 int i; 52 int j; 53 char *touched; 54 struct ww_update *upd; 55 char check_clreos = 0; 56 int scan_top, scan_bot; 57 58 wwnupdate++; 59 { 60 char *t1 = wwtouched + top, *t2 = wwtouched + bot; 61 int n; 62 63 while (!*t1++) 64 if (t1 == t2) 65 return; 66 while (!*--t2) 67 ; 68 scan_top = top = t1 - wwtouched - 1; 69 scan_bot = bot = t2 - wwtouched + 1; 70 if (scan_bot - scan_top > 1 && 71 (tt.tt_clreos != 0 || tt.tt_clear != 0)) { 72 int st = tt.tt_clreos != 0 ? scan_top : 0; 73 74 /* 75 * t1 is one past the first touched row, 76 * t2 is on the last touched row. 77 */ 78 for (t1--, n = 1; t1 < t2;) 79 if (*t1++) 80 n++; 81 /* 82 * If we can't clreos then we try for clearing 83 * the whole screen. 84 */ 85 if ((check_clreos = n * 10 > (wwnrow - st) * 9)) { 86 scan_top = st; 87 scan_bot = wwnrow; 88 } 89 } 90 } 91 if (tt.tt_clreol == 0 && !check_clreos) 92 goto simple; 93 for (i = scan_top, touched = &wwtouched[i], upd = &wwupd[i]; 94 i < scan_bot; 95 i++, touched++, upd++) { 96 int gain = 0; 97 int best_gain = 0; 98 int best_col = 0; 99 union ww_char *ns, *os; 100 101 if (wwinterrupt()) 102 return; 103 if (!check_clreos && !*touched) 104 continue; 105 wwnupdscan++; 106 j = wwncol; 107 ns = &wwns[i][j]; 108 os = &wwos[i][j]; 109 while (--j >= 0) { 110 /* 111 * The cost of clearing is: 112 * ncol - nblank + X 113 * The cost of straight update is, more or less: 114 * ncol - nsame 115 * We clear if nblank - nsame > X 116 * X is the clreol overhead. 117 * So we make gain = nblank - nsame. 118 */ 119 if ((--ns)->c_w == (--os)->c_w) 120 gain--; 121 else 122 best_gain--; 123 if (ns->c_w == ' ') 124 gain++; 125 if (gain > best_gain) { 126 best_col = j; 127 best_gain = gain; 128 } 129 } 130 upd->best_gain = best_gain; 131 upd->best_col = best_col; 132 upd->gain = gain; 133 } 134 if (check_clreos) { 135 struct ww_update *u; 136 int gain = 0; 137 int best_gain = 0; 138 int best_row = 0; 139 int simple_gain = 0; 140 char didit = 0; 141 142 /* 143 * gain is the advantage of clearing all the lines. 144 * best_gain is the advantage of clearing to eos 145 * at best_row and u->best_col. 146 * simple_gain is the advantage of using only clreol. 147 * We use g > best_gain because u->best_col can be 148 * undefined when u->best_gain is 0 so we can't use it. 149 */ 150 for (j = scan_bot - 1, u = wwupd + j; j >= top; j--, u--) { 151 int g = gain + u->best_gain; 152 153 if (g > best_gain) { 154 best_gain = g; 155 best_row = j; 156 } 157 gain += u->gain; 158 if (tt.tt_clreol != 0 && u->best_gain > 4) 159 simple_gain += u->best_gain - 4; 160 } 161 if (tt.tt_clreos == 0) { 162 if (gain > simple_gain && gain > 4) { 163 xxclear(); 164 i = top = scan_top; 165 bot = scan_bot; 166 j = 0; 167 didit = 1; 168 } 169 } else 170 if (best_gain > simple_gain && best_gain > 4) { 171 i = best_row; 172 xxclreos(i, j = wwupd[i].best_col); 173 bot = scan_bot; 174 didit = 1; 175 } 176 if (didit) { 177 wwnupdclreos++; 178 wwnupdclreosline += wwnrow - i; 179 u = wwupd + i; 180 while (i < scan_bot) { 181 union ww_char *os = &wwos[i][j]; 182 183 for (j = wwncol - j; --j >= 0;) 184 os++->c_w = ' '; 185 wwtouched[i++] |= WWU_TOUCHED; 186 u++->best_gain = 0; 187 j = 0; 188 } 189 } else 190 wwnupdclreosmiss++; 191 } 192 simple: 193 for (i = top, touched = &wwtouched[i], upd = &wwupd[i]; i < bot; 194 i++, touched++, upd++) { 195 union ww_char *os, *ns; 196 char didit; 197 198 if (!*touched) 199 continue; 200 *touched = 0; 201 wwnupdline++; 202 didit = 0; 203 if (tt.tt_clreol != 0 && upd->best_gain > 4) { 204 wwnupdclreol++; 205 xxclreol(i, j = upd->best_col); 206 for (os = &wwos[i][j], j = wwncol - j; --j >= 0;) 207 os++->c_w = ' '; 208 didit = 1; 209 } 210 ns = wwns[i]; 211 os = wwos[i]; 212 for (j = 0; j < wwncol;) { 213 char *p, *q; 214 char m; 215 int c; 216 int n; 217 char buf[512]; /* > wwncol */ 218 union ww_char lastc; 219 220 for (; j++ < wwncol && ns++->c_w == os++->c_w;) 221 ; 222 if (j > wwncol) 223 break; 224 p = buf; 225 m = ns[-1].c_m; 226 c = j - 1; 227 os[-1] = ns[-1]; 228 *p++ = ns[-1].c_c; 229 n = 5; 230 q = p; 231 while (j < wwncol && ns->c_m == m) { 232 *p++ = ns->c_c; 233 if (ns->c_w == os->c_w) { 234 if (--n <= 0) 235 break; 236 os++; 237 ns++; 238 } else { 239 n = 5; 240 q = p; 241 lastc = *os; 242 *os++ = *ns++; 243 } 244 j++; 245 } 246 n = q - buf; 247 if (!wwwrap || i != wwnrow - 1 || c + n != wwncol) 248 xxwrite(i, c, buf, n, m); 249 else if (tt.tt_inschar || tt.tt_insspace) { 250 if (n > 1) { 251 q[-2] = q[-1]; 252 n--; 253 } else 254 c--; 255 xxwrite(i, c, buf, n, m); 256 c += n - 1; 257 if (tt.tt_inschar) 258 xxinschar(i, c, ns[-2].c_c, 259 ns[-2].c_m); 260 else { 261 xxinsspace(i, c); 262 xxwrite(i, c, &ns[-2].c_c, 1, 263 ns[-2].c_m); 264 } 265 } else { 266 if (--n) 267 xxwrite(i, c, buf, n, m); 268 os[-1] = lastc; 269 *touched = WWU_TOUCHED; 270 } 271 didit = 1; 272 } 273 if (!didit) 274 wwnupdmiss++; 275 } 276 } 277