#include "sam.h" #include "parse.h" int Glooping; int nest; int append(File*, Cmd*, Posn); int display(File*); void looper(File*, Cmd*, int); void filelooper(Cmd*, int); void linelooper(File*, Cmd*); void resetxec(void) { Glooping = nest = 0; } int cmdexec(File *f, Cmd *cp) { int i; Addr *ap; Address a; if(f && f->unread) load(f); if(f==0 && (cp->addr==0 || cp->addr->type!='"') && !utfrune("bBnqUXY!", cp->cmdc) && cp->cmdc!=('c'|0x100) && !(cp->cmdc=='D' && cp->ctext)) error(Enofile); i = lookup(cp->cmdc); if(i >= 0 && cmdtab[i].defaddr != aNo){ if((ap=cp->addr)==0 && cp->cmdc!='\n'){ cp->addr = ap = newaddr(); ap->type = '.'; if(cmdtab[i].defaddr == aAll) ap->type = '*'; }else if(ap && ap->type=='"' && ap->next==0 && cp->cmdc!='\n'){ ap->next = newaddr(); ap->next->type = '.'; if(cmdtab[i].defaddr == aAll) ap->next->type = '*'; } if(cp->addr){ /* may be false for '\n' (only) */ static Address none = {0,0,0}; if(f) addr = address(ap, f->dot, 0); else /* a " */ addr = address(ap, none, 0); f = addr.f; } } current(f); switch(cp->cmdc){ case '{': a = cp->addr? address(cp->addr, f->dot, 0): f->dot; for(cp = cp->ccmd; cp; cp = cp->next){ a.f->dot = a; cmdexec(a.f, cp); } break; default: i=(*cmdtab[i].fn)(f, cp); return i; } return 1; } int a_cmd(File *f, Cmd *cp) { return append(f, cp, addr.r.p2); } int b_cmd(File *f, Cmd *cp) { USED(f); f = cp->cmdc=='b'? tofile(cp->ctext) : getfile(cp->ctext); if(f->unread) load(f); else if(nest == 0) filename(f); return TRUE; } int c_cmd(File *f, Cmd *cp) { logdelete(f, addr.r.p1, addr.r.p2); f->ndot.r.p1 = f->ndot.r.p2 = addr.r.p2; return append(f, cp, addr.r.p2); } int d_cmd(File *f, Cmd *cp) { USED(cp); logdelete(f, addr.r.p1, addr.r.p2); f->ndot.r.p1 = f->ndot.r.p2 = addr.r.p1; return TRUE; } int D_cmd(File *f, Cmd *cp) { closefiles(f, cp->ctext); return TRUE; } int e_cmd(File *f, Cmd *cp) { if(getname(f, cp->ctext, cp->cmdc=='e')==0) error(Enoname); edit(f, cp->cmdc); return TRUE; } int f_cmd(File *f, Cmd *cp) { getname(f, cp->ctext, TRUE); filename(f); return TRUE; } int g_cmd(File *f, Cmd *cp) { if(f!=addr.f)panic("g_cmd f!=addr.f"); compile(cp->re); if(execute(f, addr.r.p1, addr.r.p2) ^ cp->cmdc=='v'){ f->dot = addr; return cmdexec(f, cp->ccmd); } return TRUE; } int i_cmd(File *f, Cmd *cp) { return append(f, cp, addr.r.p1); } int k_cmd(File *f, Cmd *cp) { USED(cp); f->mark = addr.r; return TRUE; } int m_cmd(File *f, Cmd *cp) { Address addr2; addr2 = address(cp->caddr, f->dot, 0); if(cp->cmdc=='m') move(f, addr2); else copy(f, addr2); return TRUE; } int n_cmd(File *f, Cmd *cp) { int i; USED(f); USED(cp); for(i = 0; iname); filename(f); } return TRUE; } int p_cmd(File *f, Cmd *cp) { USED(cp); return display(f); } int q_cmd(File *f, Cmd *cp) { USED(cp); USED(f); trytoquit(); if(downloaded){ outT0(Hexit); return TRUE; } return FALSE; } int s_cmd(File *f, Cmd *cp) { int i, j, c, n; Posn p1, op, didsub = 0, delta = 0; n = cp->num; op= -1; compile(cp->re); for(p1 = addr.r.p1; p1<=addr.r.p2 && execute(f, p1, addr.r.p2); ){ if(sel.p[0].p1==sel.p[0].p2){ /* empty match? */ if(sel.p[0].p1==op){ p1++; continue; } p1 = sel.p[0].p2+1; }else p1 = sel.p[0].p2; op = sel.p[0].p2; if(--n>0) continue; Strzero(&genstr); for(i = 0; ictext->n; i++) if((c = cp->ctext->s[i])=='\\' && ictext->n-1){ c = cp->ctext->s[++i]; if('1'<=c && c<='9') { j = c-'0'; if(sel.p[j].p2-sel.p[j].p1>BLOCKSIZE) error(Elongtag); bufread(f, sel.p[j].p1, genbuf, sel.p[j].p2-sel.p[j].p1); Strinsert(&genstr, tmprstr(genbuf, (sel.p[j].p2-sel.p[j].p1)), genstr.n); }else Straddc(&genstr, c); }else if(c!='&') Straddc(&genstr, c); else{ if(sel.p[0].p2-sel.p[0].p1>BLOCKSIZE) error(Elongrhs); bufread(f, sel.p[0].p1, genbuf, sel.p[0].p2-sel.p[0].p1); Strinsert(&genstr, tmprstr(genbuf, (int)(sel.p[0].p2-sel.p[0].p1)), genstr.n); } if(sel.p[0].p1!=sel.p[0].p2){ logdelete(f, sel.p[0].p1, sel.p[0].p2); delta-=sel.p[0].p2-sel.p[0].p1; } if(genstr.n){ loginsert(f, sel.p[0].p2, genstr.s, genstr.n); delta+=genstr.n; } didsub = 1; if(!cp->flag) break; } if(!didsub && nest==0) error(Enosub); f->ndot.r.p1 = addr.r.p1, f->ndot.r.p2 = addr.r.p2+delta; return TRUE; } int u_cmd(File *f, Cmd *cp) { int n; USED(f); USED(cp); n = cp->num; if(n >= 0) while(n-- && undo(TRUE)) ; else while(n++ && undo(FALSE)) ; return TRUE; } int w_cmd(File *f, Cmd *cp) { int fseq; fseq = f->seq; if(getname(f, cp->ctext, FALSE)==0) error(Enoname); if(fseq == seq) error_s(Ewseq, genc); writef(f); return TRUE; } int x_cmd(File *f, Cmd *cp) { if(cp->re) looper(f, cp, cp->cmdc=='x'); else linelooper(f, cp); return TRUE; } int X_cmd(File *f, Cmd *cp) { USED(f); filelooper(cp, cp->cmdc=='X'); return TRUE; } int plan9_cmd(File *f, Cmd *cp) { plan9(f, cp->cmdc, cp->ctext, nest); return TRUE; } int eq_cmd(File *f, Cmd *cp) { int charsonly; switch(cp->ctext->n){ case 1: charsonly = FALSE; break; case 2: if(cp->ctext->s[0]=='#'){ charsonly = TRUE; break; } default: SET(charsonly); error(Enewline); } printposn(f, charsonly); return TRUE; } int nl_cmd(File *f, Cmd *cp) { Address a; if(cp->addr == 0){ /* First put it on newline boundaries */ addr = lineaddr((Posn)0, f->dot, -1); a = lineaddr((Posn)0, f->dot, 1); addr.r.p2 = a.r.p2; if(addr.r.p1==f->dot.r.p1 && addr.r.p2==f->dot.r.p2) addr = lineaddr((Posn)1, f->dot, 1); display(f); }else if(downloaded) moveto(f, addr.r); else display(f); return TRUE; } int cd_cmd(File *f, Cmd *cp) { USED(f); cd(cp->ctext); return TRUE; } int append(File *f, Cmd *cp, Posn p) { if(cp->ctext->n>0 && cp->ctext->s[cp->ctext->n-1]==0) --cp->ctext->n; if(cp->ctext->n>0) loginsert(f, p, cp->ctext->s, cp->ctext->n); f->ndot.r.p1 = p; f->ndot.r.p2 = p+cp->ctext->n; return TRUE; } int display(File *f) { Posn p1, p2; int np; char *c; p1 = addr.r.p1; p2 = addr.r.p2; if(p2 > f->nc){ fprint(2, "bad display addr p1=%ld p2=%ld f->nc=%d\n", p1, p2, f->nc); /*ZZZ should never happen, can remove */ p2 = f->nc; } while(p1 < p2){ np = p2-p1; if(np>BLOCKSIZE-1) np = BLOCKSIZE-1; bufread(f, p1, genbuf, np); genbuf[np] = 0; c = Strtoc(tmprstr(genbuf, np+1)); if(downloaded) termwrite(c); else Write(1, c, strlen(c)); free(c); p1 += np; } f->dot = addr; return TRUE; } void looper(File *f, Cmd *cp, int xy) { Posn p, op; Range r; r = addr.r; op= xy? -1 : r.p1; nest++; compile(cp->re); for(p = r.p1; p<=r.p2; ){ if(!execute(f, p, r.p2)){ /* no match, but y should still run */ if(xy || op>r.p2) break; f->dot.r.p1 = op, f->dot.r.p2 = r.p2; p = r.p2+1; /* exit next loop */ }else{ if(sel.p[0].p1==sel.p[0].p2){ /* empty match? */ if(sel.p[0].p1==op){ p++; continue; } p = sel.p[0].p2+1; }else p = sel.p[0].p2; if(xy) f->dot.r = sel.p[0]; else f->dot.r.p1 = op, f->dot.r.p2 = sel.p[0].p1; } op = sel.p[0].p2; cmdexec(f, cp->ccmd); compile(cp->re); } --nest; } void linelooper(File *f, Cmd *cp) { Posn p; Range r, linesel; Address a, a3; nest++; r = addr.r; a3.f = f; a3.r.p1 = a3.r.p2 = r.p1; for(p = r.p1; p= r.p2) break; if(linesel.p2 >= r.p2) linesel.p2 = r.p2; if(linesel.p2 > linesel.p1) if(linesel.p1>=a3.r.p2 && linesel.p2>a3.r.p2){ f->dot.r = linesel; cmdexec(f, cp->ccmd); a3.r = linesel; continue; } break; } --nest; } void filelooper(Cmd *cp, int XY) { File *f, *cur; int i; if(Glooping++) error(EnestXY); nest++; settempfile(); cur = curfile; for(i = 0; ire==0 || filematch(f, cp->re)==XY) cmdexec(f, cp->ccmd); } if(cur && whichmenu(cur)>=0) /* check that cur is still a file */ current(cur); --Glooping; --nest; }