241 lines
3.9 KiB
C
241 lines
3.9 KiB
C
#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;
|
|
}
|