123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616 |
- /*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
- #include "sam.h"
- #include "parse.h"
- static char linex[]="\n";
- static char wordx[]=" \t\n";
- 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 = { 'p' };
- List addrlist = { 'p' };
- List relist = { 'p' };
- List stringlist = { 'p' };
- int eof;
- void
- resetcmd(void)
- {
- linep = line;
- *linep = 0;
- terminp = termoutp = termline;
- freecmd();
- }
- int
- inputc(void)
- {
- int n, nbuf;
- char buf[UTFmax];
- 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, start;
- /*
- * Could set linep = line and i = 0 here and just
- * error(Etoolong) below, but this way we keep
- * old input buffer history around for a while.
- * This is useful only for debugging.
- */
- i = linep - line;
- do{
- if((c = inputc())<=0)
- return -1;
- if(i == nelem(line)-1){
- if(linep == line)
- error(Etoolong);
- start = linep - line;
- runemove(line, linep, i-start);
- i -= start;
- linep = line;
- }
- }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'<c) /* no number defaults to 1 */
- return sign;
- while('0'<=(c=getch()) && c<='9')
- n = n*10 + (c-'0');
- ungetch();
- return sign*n;
- }
- int
- skipbl(void)
- {
- int c;
- do
- c = getch();
- while(c==' ' || c=='\t');
- if(c >= 0)
- ungetch();
- return c;
- }
- void
- termcommand(void)
- {
- Posn p;
- for(p=cmdpt; p<cmd->nc; p++){
- if(terminp >= termline+nelem(termline)){
- 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, p);
- return p;
- }
- Addr*
- newaddr(void)
- {
- Addr *p;
- p = emalloc(sizeof(Addr));
- inslist(&addrlist, addrlist.nused, p);
- return p;
- }
- String*
- newre(void)
- {
- String *p;
- p = emalloc(sizeof(String));
- inslist(&relist, relist.nused, p);
- Strinit(p);
- return p;
- }
- String*
- newstring(void)
- {
- String *p;
- p = emalloc(sizeof(String));
- inslist(&stringlist, stringlist.nused, p);
- Strinit(p);
- return p;
- }
- void
- freecmd(void)
- {
- int i;
- while(cmdlist.nused > 0)
- free(cmdlist.voidpptr[--cmdlist.nused]);
- while(addrlist.nused > 0)
- free(addrlist.voidpptr[--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;
- 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;
- }
|