Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include "rc.h"
#include "exec.h"
#include "io.h"
#include "getflags.h"
#include "fns.h"
int getnext(void);

int
wordchr(int c)
{
        return !strchr("\n \t#;&|^$=`'{}()<>", c) && c!=EOF;
}

int
idchr(int c)
{
        /*
         * Formerly:
         * return 'a'<=c && c<='z' || 'A'<=c && c<='Z' || '0'<=c && c<='9'
         *      || c=='_' || c=='*';
         */
        return c>' ' && !strchr("!\"#$%&'()+,-./:;<=>?@[\\]^`{|}~", c);
}
int future = EOF;
int doprompt = 1;
int inquote;
int incomm;
/*
 * Look ahead in the input stream
 */

int
nextc(void)
{
        if(future==EOF)
                future = getnext();
        return future;
}
/*
 * Consume the lookahead character.
 */

int
advance(void)
{
        int c = nextc();
        lastc = future;
        future = EOF;
        return c;
}
/*
 * read a character from the input stream
 */     

int
getnext(void)
{
        int c;
        static int peekc = EOF;
        if(peekc!=EOF){
                c = peekc;
                peekc = EOF;
                return c;
        }
        if(runq->eof)
                return EOF;
        if(doprompt)
                pprompt();
        c = rchr(runq->cmdfd);
        if(!inquote && c=='\\'){
                c = rchr(runq->cmdfd);
                if(c=='\n' && !incomm){         /* don't continue a comment */
                        doprompt = 1;
                        c=' ';
                }
                else{
                        peekc = c;
                        c='\\';
                }
        }
        doprompt = doprompt || c=='\n' || c==EOF;
        if(c==EOF)
                runq->eof++;
        else if(flag['V'] || ndot>=2 && flag['v']) pchr(err, c);
        return c;
}

void
pprompt(void)
{
        var *prompt;
        if(runq->iflag){
                pstr(err, promptstr);
                flush(err);
                prompt = vlook("prompt");
                if(prompt->val && prompt->val->next)
                        promptstr = prompt->val->next->word;
                else
                        promptstr="\t";
        }
        runq->lineno++;
        doprompt = 0;
}

void
skipwhite(void)
{
        int c;
        for(;;){
                c = nextc();
                /* Why did this used to be  if(!inquote && c=='#') ?? */
                if(c=='#'){
                        incomm = 1;
                        for(;;){
                                c = nextc();
                                if(c=='\n' || c==EOF) {
                                        incomm = 0;
                                        break;
                                }
                                advance();
                        }
                }
                if(c==' ' || c=='\t')
                        advance();
                else return;
        }
}

void
skipnl(void)
{
        int c;
        for(;;){
                skipwhite();
                c = nextc();
                if(c!='\n')
                        return;
                advance();
        }
}

int
nextis(int c)
{
        if(nextc()==c){
                advance();
                return 1;
        }
        return 0;
}

char*
addtok(char *p, int val)
{
        if(p==0)
                return 0;
        if(p >= &tok[NTOK]){
                *p = 0;
                yyerror("token buffer too short");
                return 0;
        }
        *p++=val;
        return p;
}

char*
addutf(char *p, int c)
{
        uchar b, m;
        int i;

        p = addtok(p, c);       /* 1-byte UTF runes are special */
        if(c < Runeself)
                return p;

        m = 0xc0;
        b = 0x80;
        for(i=1; i < UTFmax; i++){
                if((c&m) == b)
                        break;
                p = addtok(p, advance());
                b = m;
                m = (m >> 1)|0x80;
        }
        return p;
}

int lastdol;    /* was the last token read '$' or '$#' or '"'? */
int lastword;   /* was the last token read a word or compound word terminator? */

int
yylex(void)
{
        int c, d = nextc();
        char *w = tok;
        struct tree *t;
        yylval.tree = 0;
        /*
         * Embarassing sneakiness:  if the last token read was a quoted or unquoted
         * WORD then we alter the meaning of what follows.  If the next character
         * is `(', we return SUB (a subscript paren) and consume the `('.  Otherwise,
         * if the next character is the first character of a simple or compound word,
         * we insert a `^' before it.
         */
        if(lastword){
                lastword = 0;
                if(d=='('){
                        advance();
                        strcpy(tok, "( [SUB]");
                        return SUB;
                }
                if(wordchr(d) || d=='\'' || d=='`' || d=='$' || d=='"'){
                        strcpy(tok, "^");
                        return '^';
                }
        }
        inquote = 0;
        skipwhite();
        switch(c = advance()){
        case EOF:
                lastdol = 0;
                strcpy(tok, "EOF");
                return EOF;
        case '$':
                lastdol = 1;
                if(nextis('#')){
                        strcpy(tok, "$#");
                        return COUNT;
                }
                if(nextis('"')){
                        strcpy(tok, "$\"");
                        return '"';
                }
                strcpy(tok, "$");
                return '$';
        case '&':
                lastdol = 0;
                if(nextis('&')){
                        skipnl();
                        strcpy(tok, "&&");
                        return ANDAND;
                }
                strcpy(tok, "&");
                return '&';
        case '|':
                lastdol = 0;
                if(nextis(c)){
                        skipnl();
                        strcpy(tok, "||");
                        return OROR;
                }
        case '<':
        case '>':
                lastdol = 0;
                /*
                 * funny redirection tokens:
                 *      redir:  arrow | arrow '[' fd ']'
                 *      arrow:  '<' | '<<' | '>' | '>>' | '|'
                 *      fd:     digit | digit '=' | digit '=' digit
                 *      digit:  '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'
                 * some possibilities are nonsensical and get a message.
                 */
                *w++=c;
                t = newtree();
                switch(c){
                case '|':
                        t->type = PIPE;
                        t->fd0 = 1;
                        t->fd1 = 0;
                        break;
                case '>':
                        t->type = REDIR;
                        if(nextis(c)){
                                t->rtype = APPEND;
                                *w++=c;
                        }
                        else t->rtype = WRITE;
                        t->fd0 = 1;
                        break;
                case '<':
                        t->type = REDIR;
                        if(nextis(c)){
                                t->rtype = HERE;
                                *w++=c;
                        } else if (nextis('>')){
                                t->rtype = RDWR;
                                *w++=c;
                        } else t->rtype = READ;
                        t->fd0 = 0;
                        break;
                }
                if(nextis('[')){
                        *w++='[';
                        c = advance();
                        *w++=c;
                        if(c<'0' || '9'<c){
                        RedirErr:
                                *w = 0;
                                yyerror(t->type==PIPE?"pipe syntax"
                                                :"redirection syntax");
                                return EOF;
                        }
                        t->fd0 = 0;
                        do{
                                t->fd0 = t->fd0*10+c-'0';
                                *w++=c;
                                c = advance();
                        }while('0'<=c && c<='9');
                        if(c=='='){
                                *w++='=';
                                if(t->type==REDIR)
                                        t->type = DUP;
                                c = advance();
                                if('0'<=c && c<='9'){
                                        t->rtype = DUPFD;
                                        t->fd1 = t->fd0;
                                        t->fd0 = 0;
                                        do{
                                                t->fd0 = t->fd0*10+c-'0';
                                                *w++=c;
                                                c = advance();
                                        }while('0'<=c && c<='9');
                                }
                                else{
                                        if(t->type==PIPE)
                                                goto RedirErr;
                                        t->rtype = CLOSE;
                                }
                        }
                        if(c!=']'
                        || t->type==DUP && (t->rtype==HERE || t->rtype==APPEND))
                                goto RedirErr;
                        *w++=']';
                }
                *w='\0';
                yylval.tree = t;
                if(t->type==PIPE)
                        skipnl();
                return t->type;
        case '\'':
                lastdol = 0;
                lastword = 1;
                inquote = 1;
                for(;;){
                        c = advance();
                        if(c==EOF)
                                break;
                        if(c=='\''){
                                if(nextc()!='\'')
                                        break;
                                advance();
                        }
                        w = addutf(w, c);
                }
                if(w!=0)
                        *w='\0';
                t = token(tok, WORD);
                t->quoted = 1;
                yylval.tree = t;
                return t->type;
        }
        if(!wordchr(c)){
                lastdol = 0;
                tok[0] = c;
                tok[1]='\0';
                return c;
        }
        for(;;){
                if(c=='*' || c=='[' || c=='?' || c==GLOB)
                        w = addtok(w, GLOB);
                w = addutf(w, c);
                c = nextc();
                if(lastdol?!idchr(c):!wordchr(c)) break;
                advance();
        }

        lastword = 1;
        lastdol = 0;
        if(w!=0)
                *w='\0';
        t = klook(tok);
        if(t->type!=WORD)
                lastword = 0;
        t->quoted = 0;
        yylval.tree = t;
        return t->type;
}