From 76193d7cb0457807b2f0b95f909ab5de19480cd7 Mon Sep 17 00:00:00 2001 From: rsc Date: Tue, 30 Sep 2003 17:47:42 +0000 Subject: Initial revision --- src/cmd/sam/cmd.c | 594 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 594 insertions(+) create mode 100644 src/cmd/sam/cmd.c (limited to 'src/cmd/sam/cmd.c') diff --git a/src/cmd/sam/cmd.c b/src/cmd/sam/cmd.c new file mode 100644 index 00000000..8c152f94 --- /dev/null +++ b/src/cmd/sam/cmd.c @@ -0,0 +1,594 @@ +#include "sam.h" +#include "parse.h" + +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, 2, 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, plan9_cmd, + '>', 0, 0, 0, 0, aDot, 0, linex, plan9_cmd, + '<', 0, 0, 0, 0, aDot, 0, linex, plan9_cmd, + '|', 0, 0, 0, 0, aDot, 0, linex, plan9_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(int); +Addr *compoundaddr(void); +Addr *simpleaddr(void); +void freecmd(void); +void okdelim(int); + +Rune line[BLOCKSIZE]; +Rune termline[BLOCKSIZE]; +Rune *linep = line; +Rune *terminp = termline; +Rune *termoutp = termline; +List cmdlist; +List addrlist; +List relist; +List stringlist; +int eof; + +void +resetcmd(void) +{ + linep = line; + *linep = 0; + terminp = termoutp = termline; + freecmd(); +} + +int +inputc(void) +{ + int n, nbuf; + char buf[3]; + Rune r; + + Again: + nbuf = 0; + if(downloaded){ + while(termoutp == terminp){ + cmdupdate(); + if(patset) + tellpat(); + while(termlocked > 0){ + outT0(Hunlock); + termlocked--; + } + if(rcv() == 0) + return -1; + } + r = *termoutp++; + if(termoutp == terminp) + terminp = termoutp = termline; + }else{ + do{ + n = read(0, buf+nbuf, 1); + if(n <= 0) + return -1; + nbuf += n; + }while(!fullrune(buf, nbuf)); + chartorune(&r, buf); + } + if(r == 0){ + warn(Wnulls); + goto Again; + } + return r; +} + +int +inputline(void) +{ + int i, c; + + linep = line; + i = 0; + do{ + if((c = inputc())<=0) + return -1; + if(i == (sizeof line)/RUNESIZE-1) + error(Etoolong); + }while((line[i++]=c) != '\n'); + line[i] = 0; + return 1; +} + +int +getch(void) +{ + if(eof) + return -1; + if(*linep==0 && inputline()<0){ + eof = TRUE; + return -1; + } + return *linep++; +} + +int +nextc(void) +{ + if(*linep == 0) + return -1; + return *linep; +} + +void +ungetch(void) +{ + if(--linep < line) + panic("ungetch"); +} + +Posn +getnum(int signok) +{ + Posn n=0; + int c, sign; + + sign = 1; + if(signok>1 && nextc()=='-'){ + sign = -1; + getch(); + } + if((c=nextc())<'0' || '9'= 0) + ungetch(); + return c; +} + +void +termcommand(void) +{ + Posn p; + + for(p=cmdpt; p_.nc; p++){ + if(terminp >= &termline[BLOCKSIZE]){ + cmdpt = cmd->_.nc; + error(Etoolong); + } + *terminp++ = filereadc(cmd, p); + } + cmdpt = cmd->_.nc; +} + +void +cmdloop(void) +{ + Cmd *cmdp; + File *ocurfile; + int loaded; + + for(;;){ + if(!downloaded && curfile && curfile->unread) + load(curfile); + if((cmdp = parsecmd(0))==0){ + if(downloaded){ + rescue(); + exits("eof"); + } + break; + } + ocurfile = curfile; + loaded = curfile && !curfile->unread; + if(cmdexec(curfile, cmdp) == 0) + break; + freecmd(); + cmdupdate(); + update(); + if(downloaded && curfile && + (ocurfile!=curfile || (!loaded && !curfile->unread))) + outTs(Hcurrent, curfile->tag); + /* don't allow type ahead on files that aren't bound */ + if(downloaded && curfile && curfile->rasp == 0) + terminp = termoutp; + } +} + +Cmd * +newcmd(void){ + Cmd *p; + + p = emalloc(sizeof(Cmd)); + inslist(&cmdlist, cmdlist.nused, (long)p); + return p; +} + +Addr* +newaddr(void) +{ + Addr *p; + + p = emalloc(sizeof(Addr)); + inslist(&addrlist, addrlist.nused, (long)p); + return p; +} + +String* +newre(void) +{ + String *p; + + p = emalloc(sizeof(String)); + inslist(&relist, relist.nused, (long)p); + Strinit(p); + return p; +} + +String* +newstring(void) +{ + String *p; + + p = emalloc(sizeof(String)); + inslist(&stringlist, stringlist.nused, (long)p); + Strinit(p); + return p; +} + +void +freecmd(void) +{ + int i; + + while(cmdlist.nused > 0) + free(cmdlist.ucharpptr[--cmdlist.nused]); + while(addrlist.nused > 0) + free(addrlist.ucharpptr[--addrlist.nused]); + while(relist.nused > 0){ + i = --relist.nused; + Strclose(relist.stringpptr[i]); + free(relist.stringpptr[i]); + } + while(stringlist.nused>0){ + i = --stringlist.nused; + Strclose(stringlist.stringpptr[i]); + free(stringlist.stringpptr[i]); + } +} + +int +lookup(int c) +{ + int i; + + for(i=0; cmdtab[i].cmdc; i++) + if(cmdtab[i].cmdc == c) + return i; + return -1; +} + +void +okdelim(int c) +{ + if(c=='\\' || ('a'<=c && c<='z') + || ('A'<=c && c<='Z') || ('0'<=c && c<='9')) + error_c(Edelim, c); +} + +void +atnl(void) +{ + skipbl(); + if(getch() != '\n') + error(Enewline); +} + +void +getrhs(String *s, int delim, int cmd) +{ + int c; + + while((c = getch())>0 && c!=delim && c!='\n'){ + if(c == '\\'){ + if((c=getch()) <= 0) + error(Ebadrhs); + if(c == '\n'){ + ungetch(); + c='\\'; + }else if(c == 'n') + c='\n'; + else if(c!=delim && (cmd=='s' || c!='\\')) /* s does its own */ + Straddc(s, '\\'); + } + Straddc(s, c); + } + ungetch(); /* let client read whether delimeter, '\n' or whatever */ +} + +String * +collecttoken(char *end) +{ + String *s = newstring(); + int c; + + while((c=nextc())==' ' || c=='\t') + Straddc(s, getch()); /* blanks significant for getname() */ + while((c=getch())>0 && utfrune(end, c)==0) + Straddc(s, c); + Straddc(s, 0); + if(c != '\n') + atnl(); + return s; +} + +String * +collecttext(void) +{ + String *s = newstring(); + int begline, i, c, delim; + + if(skipbl()=='\n'){ + getch(); + i = 0; + do{ + begline = i; + while((c = getch())>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, s->n-2, s->n); + }else{ + okdelim(delim = getch()); + getrhs(s, delim, 'a'); + if(nextc()==delim) + getch(); + atnl(); + } + Return: + Straddc(s, 0); /* JUST FOR CMDPRINT() */ + return s; +} + +Cmd * +parsecmd(int nest) +{ + int i, c; + struct cmdtab *ct; + 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=getch())==-1) + return 0; + cmd.cmdc = c; + if(cmd.cmdc=='c' && nextc()=='d'){ /* sleazy two-character case */ + getch(); /* 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(ct->count); + 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 = getch())=='\n' || c<0) + error(Enopattern); + okdelim(c); + cmd.re = getregexp(c); + if(ct->cmdc == 's'){ + cmd.ctext = newstring(); + getrhs(cmd.ctext, c, 's'); + if(nextc() == c){ + getch(); + if(nextc() == 'g') + cmd.flag = getch(); + } + + } + } + } + if(ct->addr && (cmd.caddr=simpleaddr())==0) + error(Eaddress); + if(ct->defcmd){ + if(skipbl() == '\n'){ + getch(); + 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') + getch(); + 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; +} + +String* /* BUGGERED */ +getregexp(int delim) +{ + String *r = newre(); + int c; + + for(Strzero(&genstr); ; Straddc(&genstr, c)) + if((c = getch())=='\\'){ + if(nextc()==delim) + c = getch(); + else if(nextc()=='\\'){ + Straddc(&genstr, c); + c = getch(); + } + }else if(c==delim || c=='\n') + break; + if(c!=delim && c) + ungetch(); + if(genstr.n > 0){ + patset = TRUE; + Strduplstr(&lastpat, &genstr); + Straddc(&lastpat, '\0'); + } + if(lastpat.n <= 1) + error(Epattern); + Strduplstr(r, &lastpat); + return r; +} + +Addr * +simpleaddr(void) +{ + Addr addr; + Addr *ap, *nap; + + addr.next = 0; + addr.left = 0; + switch(skipbl()){ + case '#': + addr.type = getch(); + addr.num = getnum(1); + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + addr.num = getnum(1); + addr.type='l'; + break; + case '/': case '?': case '"': + addr.are = getregexp(addr.type = getch()); + break; + case '.': + case '$': + case '+': + case '-': + case '\'': + addr.type = getch(); + 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; +} + +Addr * +compoundaddr(void) +{ + Addr addr; + Addr *ap, *next; + + addr.left = simpleaddr(); + if((addr.type = skipbl())!=',' && addr.type!=';') + return addr.left; + getch(); + next = addr.next = compoundaddr(); + if(next && (next->type==',' || next->type==';') && next->left==0) + error(Eaddress); + ap = newaddr(); + *ap = addr; + return ap; +} -- cgit v1.2.3