V9/jtools/src/sam/address.c
#include "sam.h"
#include "parse.h"
Address addr;
Address charaddr();
String lastpat;
int patset;
File *matchfile();
File *menu;
Address
address(ap, a, sign)
register Addr *ap;
Address a;
{
register File *f=a.f;
Address a1, a2;
do{
switch(ap->type){
case 'l':
case '#':
a=(*(ap->type=='#'?charaddr:lineaddr))((Posn)ap->num, a, sign);
break;
case '.':
a=f->dot;
break;
case '$':
a.r.p1=a.r.p2=f->nbytes;
break;
case '\'':
a.r=f->mark;
break;
case '?':
sign= -sign;
if(sign==0)
sign= -1;
/* fall through */
case '/':
nextmatch(f, ap->are, sign>=0? a.r.p2 : a.r.p1, sign);
a.r=sel;
break;
case '"':
a=matchfile(ap->are)->dot;
f=a.f;
if(f->state==Unread)
load(f);
break;
case '*':
a.r.p1=0, a.r.p2=f->nbytes;
return a;
case ',':
case ';':
if(ap->aprev)
a1=address(ap->aprev, a, 0);
else
a1.f=a.f, a1.r.p1=a1.r.p2=0;
if(ap->type==';')
f->dot=a=a1;
if(ap->next)
a2=address(ap->next, a, 0);
else
a2.f=a.f, a2.r.p1=a2.r.p2=f->nbytes;
if(a1.f!=a2.f)
error(Eorder);
a.f=a1.f, a.r.p1=a1.r.p1, a.r.p2=a2.r.p2;
if(a.r.p2<a.r.p1)
error(Eorder);
return a;
case '+':
case '-':
sign=1;
if(ap->type=='-')
sign= -1;
if(ap->next==0 || ap->next->type=='+' || ap->next->type=='-')
a=lineaddr(1L, a, sign);
break;
default:
panic("address");
return a;
}
}while(ap=ap->next);
return a;
}
nextmatch(f, r, p, sign)
register File *f;
register Regexp *r;
register Posn p;
{
compile(r);
if(sign>=0){
if(!execute(f, p, INFINITY))
error(Esearch);
if(sel.p1==sel.p2 && sel.p1==p){
if(++p>f->nbytes)
p=0;
if(!execute(f, p, INFINITY))
panic("address");
}
}else{
if(!bexecute(f, p))
error(Esearch);
if(sel.p1==sel.p2 && sel.p2==p){
if(--p<0)
p=f->nbytes;
if(!bexecute(f, p))
panic("address");
}
}
}
File *
matchfile(r)
Regexp *r;
{
register File *f;
register File *match=0;
register i;
for(i=0; i<file.nused; i++){
f=file.ptr[i];
if(f==cmd)
continue;
if(filematch(f, r)){
if(match)
error(Emanyfiles);
match=f;
}
}
if(!match)
error(Efsearch);
return match;
}
filematch(f, r)
register File *f;
register Regexp *r;
{
sprint(genbuf, "%c%c%c %s\n", " '"[f->state==Dirty],
"-+"[f->rasp!=0], " ."[f==curfile], f->name.s);
strdup(&genstr, genbuf);
/* A little dirty... */
if(menu==0)
(menu=Fopen())->state=Clean;
Bdelete(menu->buf, (Posn)0, menu->buf->nbytes);
Binsert(menu->buf, &genstr, (Posn)0);
menu->nbytes=menu->buf->nbytes;
compile(r);
return execute(menu, (Posn)0, menu->nbytes);
}
Address
charaddr(l, addr, sign)
register Posn l;
Address addr;
{
if(sign==0)
addr.r.p1=addr.r.p2=l;
else if(sign<0)
addr.r.p2=addr.r.p1-=l;
else if(sign>0)
addr.r.p1=addr.r.p2+=l;
if(addr.r.p1<0 || addr.r.p2>addr.f->nbytes)
error(Erange);
return addr;
}
Address
lineaddr(l, addr, sign)
register Posn l;
Address addr;
{
register n;
register c;
register File *f=addr.f;
Address a;
a.f=f;
if(sign>=0){
if(l==0){
if(sign==0 || addr.r.p2==0){
a.r.p1=a.r.p2=0;
return a;
}
a.r.p1=addr.r.p2;
Fgetcset(f, addr.r.p2-1);
}else{
if(sign==0 || addr.r.p2==0){
Fgetcset(f, (Posn)0);
n=1;
}else{
Fgetcset(f, addr.r.p2-1);
n=Fgetc(f)=='\n';
}
for(; n<l; ){
c=Fgetc(f);
if(c==-1)
error(Erange);
else if(c=='\n')
n++;
}
a.r.p1=f->getcp;
}
do; while((c=Fgetc(f))!='\n' && c!=-1);
a.r.p2=f->getcp;
}else{
Fbgetcset(f, addr.r.p1);
if(l==0)
a.r.p2=addr.r.p1;
else{
for(n=0; n<l; ){ /* always runs once */
c=Fbgetc(f);
if(c=='\n')
n++;
else if(c==-1){
if(++n!=l)
error(Erange);
}
}
a.r.p2=f->getcp;
if(c=='\n')
a.r.p2++; /* lines start after a newline */
}
do; while((c=Fbgetc(f))!='\n' && c!=-1);
a.r.p1=f->getcp;
if(c=='\n')
a.r.p1++; /* lines start after a newline */
}
return a;
}