V9/jtools/src/sam/rasp.c
#include "sam.h"
/*
* GROWDATASIZE must be big enough that all errors go out as Hgrowdata's,
* so they will be scrolled into visibility in the ~~sam~~ window (yuck!).
*/
#define GROWDATASIZE 50 /* if size is < this, send data with grow */
toterminal(f, toterm)
register File *f;
{
register Buffer *t=f->transcript;
register Posn n, p0, p1, p2, nbytes, delta=0, deltacmd=0;
Range r;
uchar buf[16+GROWDATASIZE];
if(f->rasp==0)
return;
nbytes=f->nbytes;
if(f->marked)
p0=f->markp+sizeof(Mark);
else
p0=0;
while(Bread(t, buf, sizeof buf, p0)>0){
switch(buf[0]){
default:
panic("unknown in toterminal");
case 'd':
GETPOSN(p1, buf+1);
GETPOSN(p2, buf+1+sizeof(Posn));
p1+=delta, p2+=delta;
if(p2<=p1)
panic("toterminal delete 0");
if(f==cmd && p1<cmdpt){
if(p2<=cmdpt)
deltacmd-=(p2-p1);
else
deltacmd-=cmdpt-p1;
}
p0+=1+2*sizeof(Posn);
if(toterm)
outTsll(Hcut, f->tag, p1, p2-p1);
rcut(f->rasp, p1, p2);
delta-=p2-p1;
nbytes-=p2-p1;
break;
case 'f':
n=buf[1]&0xFF;
n|=buf[2]<<8;
p0+=1+SS+n;
break;
case 'i':
n=buf[1]&0xFF;
n|=buf[2]<<8;
if(n<=0)
panic("toterminal insert 0");
GETPOSN(p1, (buf+1+SS));
p1+=delta;
p0+=1+SS+sizeof(Posn)+n;
if(f==cmd && p1<cmdpt)
deltacmd+=n;
if(toterm){
if(n>GROWDATASIZE || !rterm(f->rasp, p1)){
rgrow(f->rasp, p1, n);
outTsll(Hgrow, f->tag, p1, n);
}else{
uchar *s=buf+1+SS+sizeof(Posn);
rgrow(f->rasp, p1, n);
r=rdata(f->rasp, p1, n);
if(r.p1!=p1 || r.p2!=p1+n)
panic("rdata in toterminal");
s[n]=0;
outTsllS(Hgrowdata, f->tag, p1, n, s);
}
}else{
rgrow(f->rasp, p1, n);
r=rdata(f->rasp, p1, n);
if(r.p1!=p1 || r.p2!=p1+n)
panic("rdata in toterminal");
}
delta+=n;
nbytes+=n;
break;
}
}
if(toterm)
outTs(Hcheck0, f->tag);
if(f==cmd){
cmdpt+=deltacmd+cmdptadv;
cmdptadv=0;
}
}
#define M 0x80000000L
#define P(i) r->ptr[i]
#define T(i) (P(i)&M) /* in terminal */
#define L(i) (P(i)&~M) /* length of this piece */
rcut(r, p1, p2)
register List *r;
register Posn p1, p2;
{
register Posn p, x;
register i;
if(p1==p2)
panic("rcut 0");
for(p=0,i=0; i<r->nused && p+L(i)<=p1; p+=L(i++))
;
if(i==r->nused)
panic("rcut 1");
if(p<p1){ /* chop this piece */
if(p+L(i)<p2){
x=p1-p;
p+=L(i);
}else{
x=L(i)-(p2-p1);
p=p2;
}
if(T(i))
P(i)=x|M;
else
P(i)=x;
i++;
}
while(i<r->nused && p+L(i)<=p2){
p+=L(i);
dellist(r, i);
}
if(p<p2){
if(i==r->nused)
panic("rcut 2");
x=L(i)-(p2-p);
if(T(i))
P(i)=x|M;
else
P(i)=x;
}
/* can we merge i and i-1 ? */
if(i>0 && i<r->nused && T(i-1)==T(i)){
x=L(i-1)+L(i);
dellist(r, i--);
if(T(i))
P(i)=x|M;
else
P(i)=x;
}
}
rgrow(r, p1, n)
register List *r;
register Posn p1, n;
{
register Posn p;
register i;
if(n==0)
panic("rgrow 0");
for(p=0,i=0; i<r->nused && p+L(i)<=p1; p+=L(i++))
;
if(i==r->nused){ /* stick on end of file */
if(p!=p1)
panic("rgrow 1");
if(i>0 && !T(i-1))
P(i-1)+=n;
else
inslist(r, i, n);
}else if(!T(i)) /* goes in this empty piece */
P(i)+=n;
else if(p==p1 && i>0 && !T(i-1)) /* special case; simplifies life */
P(i-1)+=n;
else if(p==p1)
inslist(r, i, n);
else{ /* must break piece in terminal */
inslist(r, i+1, (L(i)-(p1-p))|M);
inslist(r, i+1, n);
P(i)=(p1-p)|M;
}
}
rterm(r, p1)
register List *r;
register Posn p1;
{
register Posn p;
register i;
for(p=0,i=0; i<r->nused && p+L(i)<=p1; p+=L(i++))
;
if(i==r->nused && (i==0 || !T(i-1)))
return 0;
return T(i);
}
Range
rdata(r, p1, n)
register List *r;
register Posn p1, n;
{
register Posn p;
register i;
Range rg;
if(n==0)
panic("rdata 0");
for(p=0,i=0; i<r->nused && p+L(i)<=p1; p+=L(i++))
;
if(i==r->nused)
panic("rdata 1");
if(T(i)){
n-=L(i)-(p1-p);
if(n<=0){
rg.p1=rg.p2=p1;
return rg;
}
p+=L(i++);
p1=p;
}
if(T(i) || i==r->nused)
panic("rdata 2");
if(p+L(i)<p1+n)
n=L(i)-(p1-p);
rg.p1=p1;
rg.p2=p1+n;
if(p!=p1){
inslist(r, i+1, L(i)-(p1-p));
P(i)=p1-p;
i++;
}
if(L(i)!=n){
inslist(r, i+1, L(i)-n);
P(i)=n;
}
P(i)|=M;
/* now i is set; can we merge? */
if(i<r->nused-1 && T(i+1)){
P(i)=(n+=L(i+1))|M;
dellist(r, i+1);
}
if(i>0 && T(i-1)){
P(i)=(n+L(i-1))|M;
dellist(r, i-1);
}
return rg;
}