V9/jtools/src/sam/cmd.c
#include "sam.h"
#include "parse.h"
int nl_cmd(), a_cmd(), b_cmd(), c_cmd(), cd_cmd(), d_cmd(), D_cmd(), e_cmd();
int f_cmd(), g_cmd(), i_cmd(), k_cmd(), m_cmd(), n_cmd(), p_cmd(), q_cmd();
int s_cmd(), u_cmd(), w_cmd(), x_cmd(), X_cmd(), unix_cmd(), eq_cmd();
static char linex[]="\n";
static char wordx[]=" \t\n";
struct cmdtab cmdtab[]={
/* cmdc text regexp addr defcmd defaddr count token fn */
'\n', 0, 0, 0, 0, aDot, 0, 0, nl_cmd,
'a', 1, 0, 0, 0, aDot, 0, 0, a_cmd,
'b', 0, 0, 0, 0, aNo, 0, linex, b_cmd,
'B', 0, 0, 0, 0, aNo, 0, linex, b_cmd,
'c', 1, 0, 0, 0, aDot, 0, 0, c_cmd,
'd', 0, 0, 0, 0, aDot, 0, 0, d_cmd,
'D', 0, 0, 0, 0, aNo, 0, linex, D_cmd,
'e', 0, 0, 0, 0, aNo, 0, wordx, e_cmd,
'f', 0, 0, 0, 0, aNo, 0, wordx, f_cmd,
'g', 0, 1, 0, 'p', aDot, 0, 0, g_cmd,
'i', 1, 0, 0, 0, aDot, 0, 0, i_cmd,
'k', 0, 0, 0, 0, aDot, 0, 0, k_cmd,
'm', 0, 0, 1, 0, aDot, 0, 0, m_cmd,
'n', 0, 0, 0, 0, aNo, 0, 0, n_cmd,
'p', 0, 0, 0, 0, aDot, 0, 0, p_cmd,
'q', 0, 0, 0, 0, aNo, 0, 0, q_cmd,
'r', 0, 0, 0, 0, aDot, 0, wordx, e_cmd,
's', 0, 1, 0, 0, aDot, 1, 0, s_cmd,
't', 0, 0, 1, 0, aDot, 0, 0, m_cmd,
'u', 0, 0, 0, 0, aNo, 1, 0, u_cmd,
'v', 0, 1, 0, 'p', aDot, 0, 0, g_cmd,
'w', 0, 0, 0, 0, aAll, 0, wordx, w_cmd,
'x', 0, 1, 0, 'p', aDot, 0, 0, x_cmd,
'y', 0, 1, 0, 'p', aDot, 0, 0, x_cmd,
'X', 0, 1, 0, 'f', aNo, 0, 0, X_cmd,
'Y', 0, 1, 0, 'f', aNo, 0, 0, X_cmd,
'!', 0, 0, 0, 0, aNo, 0, linex, unix_cmd,
'>', 0, 0, 0, 0, aDot, 0, linex, unix_cmd,
'<', 0, 0, 0, 0, aDot, 0, linex, unix_cmd,
'|', 0, 0, 0, 0, aDot, 0, linex, unix_cmd,
'=', 0, 0, 0, 0, aDot, 0, linex, eq_cmd,
'c'|0x100,0, 0, 0, 0, aNo, 0, wordx, cd_cmd,
0, 0, 0, 0, 0, 0, 0, 0,
};
Cmd *parsecmd();
Addr *compoundaddr();
Addr *simpleaddr();
uchar line[BLOCKSIZE];
uchar termline[BLOCKSIZE];
uchar *linep=line;
uchar *terminp=termline;
uchar *termoutp=termline;
List cmdlist;
List addrlist;
List relist;
List stringlist;
int eof;
resetcmd(){
linep=line;
*linep=0;
terminp=termoutp=termline;
freecmd();
}
getc(){
if(eof)
return -1;
if(*linep==0 && inputline()<0){
eof=TRUE;
return -1;
}
return *linep++;
}
nextc(){
if(*linep==0)
return -1;
return *linep;
}
ungetc(){
if(--linep<line)
panic("ungetc");
}
inputline(){
register i, c;
linep=line;
i=0;
do{
if((c=inputc())<=0)
return -1;
if(i==(sizeof line)-1)
error(Etoolong);
}while((line[i++]=c)!='\n');
line[i]=0;
return 1;
}
termcommand()
{
register Posn p;
dounlock=TRUE;
Fgetcset(cmd, cmdpt);
for(p=cmdpt; p<cmd->nbytes; p++)
*terminp++=Fgetc(cmd);
cmdpt=cmd->nbytes;
}
inputc()
{
register c, n;
uchar cc;
Again:
if(downloaded){
while(termoutp==terminp){
if(cmd && cmd->mod!=0){
Fupdate(cmd, FALSE, downloaded);
cmd->dot.r.p1=cmd->dot.r.p2=cmd->nbytes;
telldot(cmd);
}
if(dounlock){
outT0(Hunlock);
dounlock=FALSE;
}
if(patset)
tellpat();
if(rcv()==0)
return -1;
}
c= *termoutp++;
if(termoutp==terminp)
terminp=termoutp=termline;
n=1;
}else{
n=read(0, (char *)&cc, 1);
c=cc;
}
if(n<=0)
return -1;
if(c==0 || (c&HIGHBIT)){
warn(Wnonascii);
goto Again;
}
return c;
}
cmdloop(){
Cmd *cmdp;
File *ocurfile;
int loaded;
for(;;){
if(!downloaded && curfile && curfile->state==Unread)
load(curfile);
if((cmdp=parsecmd(0))==0)
break;
ocurfile=curfile;
loaded=curfile && curfile->state!=Unread;
if(cmdexec(curfile, cmdp)==0)
break;
freecmd();
update();
if(downloaded && curfile &&
(ocurfile!=curfile || (!loaded && curfile->state!=Unread)))
outTs(Hcurrent, curfile->tag);
}
}
Cmd *
newcmd(){
register Cmd *p;
p=new(Cmd, 1);
inslist(&cmdlist, cmdlist.nused, (long)p);
return p;
}
Addr *
newaddr(){
register Addr *p;
p=new(Addr, 1);
inslist(&addrlist, addrlist.nused, (long)p);
return p;
}
Regexp *
newre(){
register Regexp *p;
p=new(Regexp, 1);
inslist(&relist, relist.nused, (long)p);
strinit(&p->text);
return p;
}
String *
newstring(){
register String *p;
p=new(String, 1);
inslist(&stringlist, stringlist.nused, (long)p);
strinit(p);
return p;
}
freecmd()
{
register i;
while(cmdlist.nused>0)
free((uchar *)cmdlist.ptr[--cmdlist.nused]);
while(addrlist.nused>0)
free((uchar *)addrlist.ptr[--addrlist.nused]);
while(relist.nused>0){
i= --relist.nused;
strclose(&((Regexp *)relist.ptr[i])->text);
free((uchar *)relist.ptr[i]); /* WARNING!! */
}
while(stringlist.nused>0){
i= --stringlist.nused;
strclose((String *)stringlist.ptr[i]);
free((uchar *)stringlist.ptr[i]);
}
}
lookup(c)
register c;
{
register i;
for(i=0; cmdtab[i].cmdc; i++)
if(cmdtab[i].cmdc==c)
return i;
return -1;
}
okdelim(c){
if(c=='\\' || ('a'<=c && c<='z') || ('A'<=c && c<='Z') || ('0'<=c && c<='9'))
error_c(Edelim, c);
}
atnl(){
skipbl();
if(getc()!='\n')
error(Enewline);
}
getrhs(s, delim, cmd)
register String *s;
register delim;
{
register c;
while((c=getc())>0 && c!=delim && c!='\n'){
if(c=='\\'){
if((c=getc())<=0)
error(Ebadrhs);
if(c=='\n'){
ungetc();
c='\\';
}else if(c=='n')
c='\n';
else if(c!=delim && (cmd=='s' || c!='\\')) /* s does its own */
straddc(s, '\\');
}
straddc(s, c);
}
ungetc(); /* let client read whether delimeter, '\n' or whatever */
}
String *
collecttoken(end)
register char *end;
{
register String *s=newstring();
register c, i;
i=0;
while((c=nextc())==' ' || c=='\t')
i++, straddc(s, getc()); /* blanks significant for getname() */
while((c=getc())>0 && strchr(end, c)==0)
i++, straddc(s, c);
straddc(s, 0);
if(c!='\n')
atnl();
return s;
}
String *
collecttext(){
register String *s=newstring();
register begline, i;
register c, delim;
if(skipbl()=='\n'){
getc();
i=0;
do{
begline=i;
while((c=getc())>0 && c!='\n')
i++, straddc(s, c);
i++, straddc(s, '\n');
if(c<0)
goto Return;
}while(s->s[begline]!='.' || s->s[begline+1]!='\n');
strdelete(s, (long)s->n-2, (long)s->n);
}else{
okdelim(delim=getc());
getrhs(s, delim, 'a');
if(nextc()==delim)
getc();
atnl();
}
Return:
straddc(s, 0); /* JUST FOR CMDPRINT() */
return s;
}
Cmd *
parsecmd(nest)
{
register i, c;
register struct cmdtab *ct;
register Cmd *cp, *ncp;
Cmd cmd;
cmd.next=cmd.ccmd=0;
cmd.re=0;
cmd.flag=cmd.num=0;
cmd.addr=compoundaddr();
if(skipbl()==-1)
return 0;
if((c=getc())==-1)
return 0;
cmd.cmdc=c;
if(cmd.cmdc=='c' && nextc()=='d'){ /* sleazy two-character case */
getc(); /* the 'd' */
cmd.cmdc='c'|0x100;
}
i=lookup(cmd.cmdc);
if(i>=0){
if(cmd.cmdc=='\n')
goto Return; /* let nl_cmd work it all out */
ct= &cmdtab[i];
if(ct->defaddr==aNo && cmd.addr)
error(Enoaddr);
if(ct->count)
cmd.num=getnum();
if(ct->regexp){
/* x without pattern -> .*\n, indicated by cmd.re==0 */
/* X without pattern is all files */
if((ct->cmdc!='x' && ct->cmdc!='X') ||
((c=nextc())!=' ' && c!='\t' && c!='\n')){
skipbl();
if((c=getc())=='\n' || c<0)
error(Enopattern);
cmd.re=getregexp(c);
if(ct->cmdc=='s'){
cmd.ctext=newstring();
getrhs(cmd.ctext, c, 's');
if(nextc()==c){
getc();
if(nextc()=='g')
cmd.flag=getc();
}
}
}
}
if(ct->addr && (cmd.caddr=simpleaddr())==0)
error(Eaddress);
if(ct->defcmd){
if(skipbl()=='\n'){
getc();
cmd.ccmd=newcmd();
cmd.ccmd->cmdc=ct->defcmd;
}else if((cmd.ccmd=parsecmd(nest))==0)
panic("defcmd");
}else if(ct->text)
cmd.ctext=collecttext();
else if(ct->token)
cmd.ctext=collecttoken(ct->token);
else
atnl();
}else
switch(cmd.cmdc){
case '{':
cp=0;
do{
if(skipbl()=='\n')
getc();
ncp=parsecmd(nest+1);
if(cp)
cp->next=ncp;
else
cmd.ccmd=ncp;
}while(cp=ncp);
break;
case '}':
atnl();
if(nest==0)
error(Enolbrace);
return 0;
default:
error_c(Eunk, cmd.cmdc);
}
Return:
cp=newcmd();
*cp=cmd;
return cp;
}
Regexp * /* BUGGERED */
getregexp(delim)
register delim;
{
register Regexp *r=newre();
register c;
for(strzero(&genstr); ; straddc(&genstr, c))
if((c=getc())=='\\'){
if(nextc()==delim)
c=getc();
else if(nextc()=='\\'){
straddc(&genstr, c);
c=getc();
}
}else if(c==delim || c=='\n')
break;
if(c!=delim && c)
ungetc();
if(genstr.n>0){
patset=TRUE;
strdupstr(&lastpat, &genstr);
straddc(&lastpat, '\0');
}
if(lastpat.n<=1)
error(Epattern);
strdupstr(&r->text, &lastpat);
return r;
}
Addr *
compoundaddr(){
Addr addr;
register Addr *ap;
addr.aprev=simpleaddr();
if((addr.type=skipbl())!=',' && addr.type!=';')
return addr.aprev;
getc();
addr.next=compoundaddr();
if(addr.next && addr.next->aprev==0)
error(Eaddress);
ap=newaddr();
*ap=addr;
return ap;
}
Addr *
simpleaddr()
{
Addr addr;
register Addr *ap, *nap;
addr.next=0;
switch(skipbl()){
case '#':
addr.type=getc();
addr.num=getnum();
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
addr.num=getnum();
addr.type='l';
break;
case '/': case '?': case '"':
addr.are=getregexp(addr.type=getc());
break;
case '.':
case '$':
case '+':
case '-':
case '\'':
addr.type=getc();
break;
default:
return 0;
}
if(addr.next=simpleaddr())
switch(addr.next->type){
case '.':
case '$':
case '\'':
if(addr.type!='"')
case '"':
error(Eaddress);
break;
case 'l':
case '#':
if(addr.type=='"')
break;
/* fall through */
case '/':
case '?':
if(addr.type!='+' && addr.type!='-'){
/* insert the missing '+' */
nap=newaddr();
nap->type='+';
nap->next=addr.next;
addr.next=nap;
}
break;
case '+':
case '-':
break;
default:
panic("simpleaddr");
}
ap=newaddr();
*ap=addr;
return ap;
}