1 #include "sam.h" 2 /* 3 * GROWDATASIZE must be big enough that all errors go out as Hgrowdata's, 4 * so they will be scrolled into visibility in the ~~sam~~ window (yuck!). 5 */ 6 #define GROWDATASIZE 50 /* if size is > this, send data with grow */ 7 8 void rcut(List*, Posn, Posn); 9 int rterm(List*, Posn); 10 void rgrow(List*, Posn, Posn); 11 12 static Posn growpos; 13 static Posn grown; 14 static Posn shrinkpos; 15 static Posn shrunk; 16 17 /* 18 * rasp routines inform the terminal of changes to the file. 19 * 20 * a rasp is a list of spans within the file, and an indication 21 * of whether the terminal knows about the span. 22 * 23 * optimize by coalescing multiple updates to the same span 24 * if it is not known by the terminal. 25 * 26 * other possible optimizations: flush terminal's rasp by cut everything, 27 * insert everything if rasp gets too large. 28 */ 29 30 /* 31 * only called for initial load of file 32 */ 33 void 34 raspload(File *f) 35 { 36 if(f->rasp == nil) 37 return; 38 grown = f->nc; 39 growpos = 0; 40 if(f->nc) 41 rgrow(f->rasp, 0, f->nc); 42 raspdone(f, 1); 43 } 44 45 void 46 raspstart(File *f) 47 { 48 if(f->rasp == nil) 49 return; 50 grown = 0; 51 shrunk = 0; 52 noflush = 1; 53 } 54 55 void 56 raspdone(File *f, int toterm) 57 { 58 if(f->dot.r.p1 > f->nc) 59 f->dot.r.p1 = f->nc; 60 if(f->dot.r.p2 > f->nc) 61 f->dot.r.p2 = f->nc; 62 if(f->mark.p1 > f->nc) 63 f->mark.p1 = f->nc; 64 if(f->mark.p2 > f->nc) 65 f->mark.p2 = f->nc; 66 if(f->rasp == nil) 67 return; 68 if(grown) 69 outTsll(Hgrow, f->tag, growpos, grown); 70 else if(shrunk) 71 outTsll(Hcut, f->tag, shrinkpos, shrunk); 72 if(toterm) 73 outTs(Hcheck0, f->tag); 74 outflush(); 75 noflush = 0; 76 if(f == cmd){ 77 cmdpt += cmdptadv; 78 cmdptadv = 0; 79 } 80 } 81 82 void 83 raspdelete(File *f, uint p1, uint p2, int toterm) 84 { 85 long n; 86 87 n = p2 - p1; 88 if(n == 0) 89 return; 90 91 if(p2 <= f->dot.r.p1){ 92 f->dot.r.p1 -= n; 93 f->dot.r.p2 -= n; 94 } 95 if(p2 <= f->mark.p1){ 96 f->mark.p1 -= n; 97 f->mark.p2 -= n; 98 } 99 100 if(f->rasp == nil) 101 return; 102 103 if(f==cmd && p1<cmdpt){ 104 if(p2 <= cmdpt) 105 cmdpt -= n; 106 else 107 cmdpt = p1; 108 } 109 if(toterm){ 110 if(grown){ 111 outTsll(Hgrow, f->tag, growpos, grown); 112 grown = 0; 113 }else if(shrunk && shrinkpos!=p1 && shrinkpos!=p2){ 114 outTsll(Hcut, f->tag, shrinkpos, shrunk); 115 shrunk = 0; 116 } 117 if(!shrunk || shrinkpos==p2) 118 shrinkpos = p1; 119 shrunk += n; 120 } 121 rcut(f->rasp, p1, p2); 122 } 123 124 void 125 raspinsert(File *f, uint p1, Rune *buf, uint n, int toterm) 126 { 127 Range r; 128 129 if(n == 0) 130 return; 131 132 if(p1 < f->dot.r.p1){ 133 f->dot.r.p1 += n; 134 f->dot.r.p2 += n; 135 } 136 if(p1 < f->mark.p1){ 137 f->mark.p1 += n; 138 f->mark.p2 += n; 139 } 140 141 142 if(f->rasp == nil) 143 return; 144 if(f==cmd && p1<cmdpt) 145 cmdpt += n; 146 if(toterm){ 147 if(shrunk){ 148 outTsll(Hcut, f->tag, shrinkpos, shrunk); 149 shrunk = 0; 150 } 151 if(n>GROWDATASIZE || !rterm(f->rasp, p1)){ 152 rgrow(f->rasp, p1, n); 153 if(grown && growpos+grown!=p1 && growpos!=p1){ 154 outTsll(Hgrow, f->tag, growpos, grown); 155 grown = 0; 156 } 157 if(!grown) 158 growpos = p1; 159 grown += n; 160 }else{ 161 if(grown){ 162 outTsll(Hgrow, f->tag, growpos, grown); 163 grown = 0; 164 } 165 rgrow(f->rasp, p1, n); 166 r = rdata(f->rasp, p1, n); 167 if(r.p1!=p1 || r.p2!=p1+n) 168 panic("rdata in toterminal"); 169 outTsllS(Hgrowdata, f->tag, p1, n, tmprstr(buf, n)); 170 } 171 }else{ 172 rgrow(f->rasp, p1, n); 173 r = rdata(f->rasp, p1, n); 174 if(r.p1!=p1 || r.p2!=p1+n) 175 panic("rdata in toterminal"); 176 } 177 } 178 179 #define M 0x80000000L 180 #define P(i) r->posnptr[i] 181 #define T(i) (P(i)&M) /* in terminal */ 182 #define L(i) (P(i)&~M) /* length of this piece */ 183 184 void 185 rcut(List *r, Posn p1, Posn p2) 186 { 187 Posn p, x; 188 int i; 189 190 if(p1 == p2) 191 panic("rcut 0"); 192 for(p=0,i=0; i<r->nused && p+L(i)<=p1; p+=L(i++)) 193 ; 194 if(i == r->nused) 195 panic("rcut 1"); 196 if(p < p1){ /* chop this piece */ 197 if(p+L(i) < p2){ 198 x = p1-p; 199 p += L(i); 200 }else{ 201 x = L(i)-(p2-p1); 202 p = p2; 203 } 204 if(T(i)) 205 P(i) = x|M; 206 else 207 P(i) = x; 208 i++; 209 } 210 while(i<r->nused && p+L(i)<=p2){ 211 p += L(i); 212 dellist(r, i); 213 } 214 if(p < p2){ 215 if(i == r->nused) 216 panic("rcut 2"); 217 x = L(i)-(p2-p); 218 if(T(i)) 219 P(i) = x|M; 220 else 221 P(i) = x; 222 } 223 /* can we merge i and i-1 ? */ 224 if(i>0 && i<r->nused && T(i-1)==T(i)){ 225 x = L(i-1)+L(i); 226 dellist(r, i--); 227 if(T(i)) 228 P(i)=x|M; 229 else 230 P(i)=x; 231 } 232 } 233 234 void 235 rgrow(List *r, Posn p1, Posn n) 236 { 237 Posn p; 238 int i; 239 240 if(n == 0) 241 panic("rgrow 0"); 242 for(p=0,i=0; i<r->nused && p+L(i)<=p1; p+=L(i++)) 243 ; 244 if(i == r->nused){ /* stick on end of file */ 245 if(p!=p1) 246 panic("rgrow 1"); 247 if(i>0 && !T(i-1)) 248 P(i-1)+=n; 249 else 250 inslist(r, i, n); 251 }else if(!T(i)) /* goes in this empty piece */ 252 P(i)+=n; 253 else if(p==p1 && i>0 && !T(i-1)) /* special case; simplifies life */ 254 P(i-1)+=n; 255 else if(p==p1) 256 inslist(r, i, n); 257 else{ /* must break piece in terminal */ 258 inslist(r, i+1, (L(i)-(p1-p))|M); 259 inslist(r, i+1, n); 260 P(i) = (p1-p)|M; 261 } 262 } 263 264 int 265 rterm(List *r, Posn p1) 266 { 267 Posn p; 268 int i; 269 270 for(p = 0,i = 0; i<r->nused && p+L(i)<=p1; p+=L(i++)) 271 ; 272 if(i==r->nused && (i==0 || !T(i-1))) 273 return 0; 274 return T(i); 275 } 276 277 Range 278 rdata(List *r, Posn p1, Posn n) 279 { 280 Posn p; 281 int i; 282 Range rg; 283 284 if(n==0) 285 panic("rdata 0"); 286 for(p = 0,i = 0; i<r->nused && p+L(i)<=p1; p+=L(i++)) 287 ; 288 if(i==r->nused) 289 panic("rdata 1"); 290 if(T(i)){ 291 n-=L(i)-(p1-p); 292 if(n<=0){ 293 rg.p1 = rg.p2 = p1; 294 return rg; 295 } 296 p+=L(i++); 297 p1 = p; 298 } 299 if(T(i) || i==r->nused) 300 panic("rdata 2"); 301 if(p+L(i)<p1+n) 302 n = L(i)-(p1-p); 303 rg.p1 = p1; 304 rg.p2 = p1+n; 305 if(p!=p1){ 306 inslist(r, i+1, L(i)-(p1-p)); 307 P(i)=p1-p; 308 i++; 309 } 310 if(L(i)!=n){ 311 inslist(r, i+1, L(i)-n); 312 P(i)=n; 313 } 314 P(i)|=M; 315 /* now i is set; can we merge? */ 316 if(i<r->nused-1 && T(i+1)){ 317 P(i)=(n+=L(i+1))|M; 318 dellist(r, i+1); 319 } 320 if(i>0 && T(i-1)){ 321 P(i)=(n+L(i-1))|M; 322 dellist(r, i-1); 323 } 324 return rg; 325 } 326