#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; iname); 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 0) p--; } while(p > 0 && filereadc(f, p-1)!='\n') /* lines start after a newline */ p--; a.r.p1 = p; } return a; }