| #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->b.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->b.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->b.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->b.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->b.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->b); |
| bufinsert(&menu->b, 0, genstr.s, genstr.n); |
| compile(r); |
| return execute(menu, 0, menu->b.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->b.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->b.nc) |
| error(Erange); |
| if(filereadc(f, p++) == '\n') |
| n++; |
| } |
| a.r.p1 = p; |
| } |
| while(p < f->b.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; |
| } |