#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; }