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 void 13 toterminal(File *f, int toterm) 14 { 15 Buffer *t = f->transcript; 16 Posn n, p0, p1, p2, delta = 0, deltacmd = 0; 17 Range r; 18 union{ 19 union Hdr g; 20 Rune buf[8+GROWDATASIZE]; 21 }hdr; 22 Posn growpos, grown; 23 24 if(f->rasp == 0) 25 return; 26 if(f->marked) 27 p0 = f->markp+sizeof(Mark)/RUNESIZE; 28 else 29 p0 = 0; 30 grown = 0; 31 noflush = 1; 32 SET(growpos); 33 while(Bread(t, (Rune*)&hdr, sizeof(hdr)/RUNESIZE, p0) > 0){ 34 switch(hdr.g.cs.c){ 35 default: 36 fprint(2, "char %c %.2ux\n", hdr.g.cs.c, hdr.g.cs.c); 37 panic("unknown in toterminal"); 38 39 case 'd': 40 if(grown){ 41 outTsll(Hgrow, f->tag, growpos, grown); 42 grown = 0; 43 } 44 p1 = hdr.g.cll.l; 45 p2 = hdr.g.cll.l1; 46 if(p2 <= p1) 47 panic("toterminal delete 0"); 48 if(f==cmd && p1<cmdpt){ 49 if(p2 <= cmdpt) 50 deltacmd -= (p2-p1); 51 else 52 deltacmd -= cmdpt-p1; 53 } 54 p1 += delta; 55 p2 += delta; 56 p0 += sizeof(struct _cll)/RUNESIZE; 57 if(toterm) 58 outTsll(Hcut, f->tag, p1, p2-p1); 59 rcut(f->rasp, p1, p2); 60 delta -= p2-p1; 61 break; 62 63 case 'f': 64 if(grown){ 65 outTsll(Hgrow, f->tag, growpos, grown); 66 grown = 0; 67 } 68 n = hdr.g.cs.s; 69 p0 += sizeof(struct _cs)/RUNESIZE + n; 70 break; 71 72 case 'i': 73 n = hdr.g.csl.s; 74 p1 = hdr.g.csl.l; 75 p0 += sizeof(struct _csl)/RUNESIZE + n; 76 if(n <= 0) 77 panic("toterminal insert 0"); 78 if(f==cmd && p1<cmdpt) 79 deltacmd += n; 80 p1 += delta; 81 if(toterm){ 82 if(n>GROWDATASIZE || !rterm(f->rasp, p1)){ 83 rgrow(f->rasp, p1, n); 84 if(grown && growpos+grown!=p1){ 85 outTsll(Hgrow, f->tag, growpos, grown); 86 grown = 0; 87 } 88 if(grown) 89 grown += n; 90 else{ 91 growpos = p1; 92 grown = n; 93 } 94 }else{ 95 Rune *rp; 96 if(grown){ 97 outTsll(Hgrow, f->tag, growpos, grown); 98 grown = 0; 99 } 100 rp = hdr.buf+sizeof(hdr.g.csl)/RUNESIZE; 101 rgrow(f->rasp, p1, n); 102 r = rdata(f->rasp, p1, n); 103 if(r.p1!=p1 || r.p2!=p1+n) 104 panic("rdata in toterminal"); 105 outTsllS(Hgrowdata, f->tag, p1, n, tmprstr(rp, n)); 106 } 107 }else{ 108 rgrow(f->rasp, p1, n); 109 r = rdata(f->rasp, p1, n); 110 if(r.p1!=p1 || r.p2!=p1+n) 111 panic("rdata in toterminal"); 112 } 113 delta += n; 114 break; 115 } 116 } 117 if(grown) 118 outTsll(Hgrow, f->tag, growpos, grown); 119 if(toterm) 120 outTs(Hcheck0, f->tag); 121 outflush(); 122 noflush = 0; 123 if(f == cmd){ 124 cmdpt += deltacmd+cmdptadv; 125 cmdptadv = 0; 126 } 127 } 128 129 #define M 0x80000000L 130 #define P(i) r->longptr[i] 131 #define T(i) (P(i)&M) /* in terminal */ 132 #define L(i) (P(i)&~M) /* length of this piece */ 133 134 void 135 rcut(List *r, Posn p1, Posn p2) 136 { 137 Posn p, x; 138 int i; 139 140 if(p1 == p2) 141 panic("rcut 0"); 142 for(p=0,i=0; i<r->nused && p+L(i)<=p1; p+=L(i++)) 143 ; 144 if(i == r->nused) 145 panic("rcut 1"); 146 if(p<p1){ /* chop this piece */ 147 if(p+L(i) < p2){ 148 x = p1-p; 149 p += L(i); 150 }else{ 151 x = L(i)-(p2-p1); 152 p = p2; 153 } 154 if(T(i)) 155 P(i) = x|M; 156 else 157 P(i) = x; 158 i++; 159 } 160 while(i<r->nused && p+L(i)<=p2){ 161 p += L(i); 162 dellist(r, i); 163 } 164 if(p<p2){ 165 if(i == r->nused) 166 panic("rcut 2"); 167 x = L(i)-(p2-p); 168 if(T(i)) 169 P(i) = x|M; 170 else 171 P(i) = x; 172 } 173 /* can we merge i and i-1 ? */ 174 if(i>0 && i<r->nused && T(i-1)==T(i)){ 175 x = L(i-1)+L(i); 176 dellist(r, i--); 177 if(T(i)) 178 P(i)=x|M; 179 else 180 P(i)=x; 181 } 182 } 183 184 void 185 rgrow(List *r, Posn p1, Posn n) 186 { 187 Posn p; 188 int i; 189 190 if(n == 0) 191 panic("rgrow 0"); 192 for(p=0,i=0; i<r->nused && p+L(i)<=p1; p+=L(i++)) 193 ; 194 if(i == r->nused){ /* stick on end of file */ 195 if(p!=p1) 196 panic("rgrow 1"); 197 if(i>0 && !T(i-1)) 198 P(i-1)+=n; 199 else 200 inslist(r, i, n); 201 }else if(!T(i)) /* goes in this empty piece */ 202 P(i)+=n; 203 else if(p==p1 && i>0 && !T(i-1)) /* special case; simplifies life */ 204 P(i-1)+=n; 205 else if(p==p1) 206 inslist(r, i, n); 207 else{ /* must break piece in terminal */ 208 inslist(r, i+1, (L(i)-(p1-p))|M); 209 inslist(r, i+1, n); 210 P(i) = (p1-p)|M; 211 } 212 } 213 214 int 215 rterm(List *r, Posn p1) 216 { 217 Posn p; 218 int i; 219 220 for(p = 0,i = 0; i<r->nused && p+L(i)<=p1; p+=L(i++)) 221 ; 222 if(i==r->nused && (i==0 || !T(i-1))) 223 return 0; 224 return T(i); 225 } 226 227 Range 228 rdata(List *r, Posn p1, Posn n) 229 { 230 Posn p; 231 int i; 232 Range rg; 233 234 if(n==0) 235 panic("rdata 0"); 236 for(p = 0,i = 0; i<r->nused && p+L(i)<=p1; p+=L(i++)) 237 ; 238 if(i==r->nused) 239 panic("rdata 1"); 240 if(T(i)){ 241 n-=L(i)-(p1-p); 242 if(n<=0){ 243 rg.p1 = rg.p2 = p1; 244 return rg; 245 } 246 p+=L(i++); 247 p1 = p; 248 } 249 if(T(i) || i==r->nused) 250 panic("rdata 2"); 251 if(p+L(i)<p1+n) 252 n = L(i)-(p1-p); 253 rg.p1 = p1; 254 rg.p2 = p1+n; 255 if(p!=p1){ 256 inslist(r, i+1, L(i)-(p1-p)); 257 P(i)=p1-p; 258 i++; 259 } 260 if(L(i)!=n){ 261 inslist(r, i+1, L(i)-n); 262 P(i)=n; 263 } 264 P(i)|=M; 265 /* now i is set; can we merge? */ 266 if(i<r->nused-1 && T(i+1)){ 267 P(i)=(n+=L(i+1))|M; 268 dellist(r, i+1); 269 } 270 if(i>0 && T(i-1)){ 271 P(i)=(n+L(i-1))|M; 272 dellist(r, i-1); 273 } 274 return rg; 275 } 276