mirror of
https://github.com/9fans/plan9port.git
synced 2025-01-15 11:20:03 +00:00
508 lines
8.3 KiB
C
508 lines
8.3 KiB
C
#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; i<file.nused; i++){
|
|
if(file.filepptr[i] == cmd)
|
|
continue;
|
|
f = file.filepptr[i];
|
|
Strduplstr(&genstr, &f->name);
|
|
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; i<cp->ctext->n; i++)
|
|
if((c = cp->ctext->s[i])=='\\' && i<cp->ctext->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->b, 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->b, 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->b.nc){
|
|
fprint(2, "bad display addr p1=%ld p2=%ld f->b.nc=%d\n", p1, p2, f->b.nc); /*ZZZ should never happen, can remove */
|
|
p2 = f->b.nc;
|
|
}
|
|
while(p1 < p2){
|
|
np = p2-p1;
|
|
if(np>BLOCKSIZE-1)
|
|
np = BLOCKSIZE-1;
|
|
bufread(&f->b, 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; p = a3.r.p2){
|
|
a3.r.p1 = a3.r.p2;
|
|
/*pjw if(p!=r.p1 || (linesel = lineaddr((Posn)0, a3, 1)).r.p2==p)*/
|
|
if(p!=r.p1 || (a = lineaddr((Posn)0, a3, 1), linesel = a.r, linesel.p2==p)){
|
|
a = lineaddr((Posn)1, a3, 1);
|
|
linesel = a.r;
|
|
}
|
|
if(linesel.p1 >= 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; i<tempfile.nused; i++){
|
|
f = tempfile.filepptr[i];
|
|
if(f==cmd)
|
|
continue;
|
|
if(cp->re==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;
|
|
}
|