#include "sam.h"
#include "parse.h"
Address addr;
String lastpat;
int patset;
File *menu;
File *matchfile(String*);
Address charaddr(Posn, Address, int);
Address
address(Addr *ap, Address a, int sign)
{
File *f = a.f;
Address a1, a2;
do{
switch(ap->type){
case 'l':
case '#':
a = (*(ap->type=='#'?charaddr:lineaddr))(ap->num, a, sign);
break;
case '.':
a = f->dot;
break;
case '$':
a.r.p1 = a.r.p2 = f->nc;
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.p[0];
break;
case '"':
a = matchfile(ap->are)->dot;
f = a.f;
if(f->unread)
load(f);
break;
case '*':
a.r.p1 = 0, a.r.p2 = f->nc;
return a;
case ',':
case ';':
if(ap->left)
a1 = address(ap->left, a, 0);
else
a1.f = a.f, a1.r.p1 = a1.r.p2 = 0;
if(ap->type == ';'){
f = a1.f;
a = a1;
f->dot = a1;
}
if(ap->next)
a2 = address(ap->next, a, 0);
else
a2.f = a.f, a2.r.p1 = a2.r.p2 = f->nc;
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); /* assign = */
return a;
}
void
nextmatch(File *f, String *r, Posn p, int sign)
{
compile(r);
if(sign >= 0){
if(!execute(f, p, INFINITY))
error(Esearch);
if(sel.p[0].p1==sel.p[0].p2 && sel.p[0].p1==p){
if(++p>f->nc)
p = 0;
if(!execute(f, p, INFINITY))
panic("address");
}
}else{
if(!bexecute(f, p))
error(Esearch);
if(sel.p[0].p1==sel.p[0].p2 && sel.p[0].p2==p){
if(--p<0)
p = f->nc;
if(!bexecute(f, p))
panic("address");
}
}
}
File *
matchfile(String *r)
{
File *f;
File *match = 0;
int i;
for(i = 0; i<file.nused; i++){
f = file.filepptr[i];
if(f == cmd)
continue;
if(filematch(f, r)){
if(match)
error(Emanyfiles);
match = f;
}
}
if(!match)
error(Efsearch);
return match;
}
int
filematch(File *f, String *r)
{
char *c, buf[STRSIZE+100];
String *t;
c = Strtoc(&f->name);
sprint(buf, "%c%c%c %s\n", " '"[f->mod],
"-+"[f->rasp!=0], " ."[f==curfile], c);
free(c);
t = tmpcstr(buf);
Strduplstr(&genstr, t);
freetmpstr(t);
/* A little dirty... */
if(menu == 0)
menu = fileopen();
bufreset(menu);
bufinsert(menu, 0, genstr.s, genstr.n);
compile(r);
return execute(menu, 0, menu->nc);
}
Address
charaddr(Posn l, Address addr, int sign)
{
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->nc)
error(Erange);
return addr;
}
Address
lineaddr(Posn l, Address addr, int sign)
{
int n;
int c;
File *f = addr.f;
Address a;
Posn p;
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;
p = addr.r.p2-1;
}else{
if(sign==0 || addr.r.p2==0){
p = (Posn)0;
n = 1;
}else{
p = addr.r.p2-1;
n = filereadc(f, p++)=='\n';
}
while(n < l){
if(p >= f->nc)
error(Erange);
if(filereadc(f, p++) == '\n')
n++;
}
a.r.p1 = p;
}
while(p < f->nc && filereadc(f, p++)!='\n')
;
a.r.p2 = p;
}else{
p = addr.r.p1;
if(l == 0)
a.r.p2 = addr.r.p1;
else{
for(n = 0; n<l; ){ /* always runs once */
if(p == 0){
if(++n != l)
error(Erange);
}else{
c = filereadc(f, p-1);
if(c != '\n' || ++n != l)
p--;
}
}
a.r.p2 = p;
if(p > 0)
p--;
}
while(p > 0 && filereadc(f, p-1)!='\n') /* lines start after a newline */
p--;
a.r.p1 = p;
}
return a;
}
|