13e12c5d1SDavid du Colombier #include "rc.h" 23e12c5d1SDavid du Colombier #include "exec.h" 33e12c5d1SDavid du Colombier #include "io.h" 43e12c5d1SDavid du Colombier #include "getflags.h" 53e12c5d1SDavid du Colombier #include "fns.h" 63e12c5d1SDavid du Colombier int getnext(void); 73e12c5d1SDavid du Colombier int wordchr(int c) 83e12c5d1SDavid du Colombier { 93e12c5d1SDavid du Colombier return !strchr("\n \t#;&|^$=`'{}()<>", c) && c!=EOF; 103e12c5d1SDavid du Colombier } 113e12c5d1SDavid du Colombier int idchr(int c) 123e12c5d1SDavid du Colombier { 133e12c5d1SDavid du Colombier /* 143e12c5d1SDavid du Colombier * Formerly: 153e12c5d1SDavid du Colombier * return 'a'<=c && c<='z' || 'A'<=c && c<='Z' || '0'<=c && c<='9' 163e12c5d1SDavid du Colombier * || c=='_' || c=='*'; 173e12c5d1SDavid du Colombier */ 183e12c5d1SDavid du Colombier return c>' ' && !strchr("!\"#$%&'()+,-./:;<=>?@[\\]^`{|}~", c); 193e12c5d1SDavid du Colombier } 203e12c5d1SDavid du Colombier int future=EOF; 213e12c5d1SDavid du Colombier int doprompt=1; 223e12c5d1SDavid du Colombier int inquote; 233e12c5d1SDavid du Colombier /* 243e12c5d1SDavid du Colombier * Look ahead in the input stream 253e12c5d1SDavid du Colombier */ 263e12c5d1SDavid du Colombier int nextc(void){ 273e12c5d1SDavid du Colombier if(future==EOF) future=getnext(); 283e12c5d1SDavid du Colombier return future; 293e12c5d1SDavid du Colombier } 303e12c5d1SDavid du Colombier /* 313e12c5d1SDavid du Colombier * Consume the lookahead character. 323e12c5d1SDavid du Colombier */ 333e12c5d1SDavid du Colombier int advance(void){ 343e12c5d1SDavid du Colombier int c=nextc(); 353e12c5d1SDavid du Colombier lastc=future; 363e12c5d1SDavid du Colombier future=EOF; 373e12c5d1SDavid du Colombier return c; 383e12c5d1SDavid du Colombier } 393e12c5d1SDavid du Colombier /* 403e12c5d1SDavid du Colombier * read a character from the input stream 413e12c5d1SDavid du Colombier */ 423e12c5d1SDavid du Colombier int getnext(void){ 433e12c5d1SDavid du Colombier register int c; 443e12c5d1SDavid du Colombier static peekc=EOF; 453e12c5d1SDavid du Colombier if(peekc!=EOF){ 463e12c5d1SDavid du Colombier c=peekc; 473e12c5d1SDavid du Colombier peekc=EOF; 483e12c5d1SDavid du Colombier return c; 493e12c5d1SDavid du Colombier } 503e12c5d1SDavid du Colombier if(runq->eof) return EOF; 513e12c5d1SDavid du Colombier if(doprompt) pprompt(); 523e12c5d1SDavid du Colombier c=rchr(runq->cmdfd); 533e12c5d1SDavid du Colombier if(!inquote && c=='\\'){ 543e12c5d1SDavid du Colombier c=rchr(runq->cmdfd); 553e12c5d1SDavid du Colombier if(c=='\n'){ 563e12c5d1SDavid du Colombier doprompt=1; 573e12c5d1SDavid du Colombier c=' '; 583e12c5d1SDavid du Colombier } 593e12c5d1SDavid du Colombier else{ 603e12c5d1SDavid du Colombier peekc=c; 613e12c5d1SDavid du Colombier c='\\'; 623e12c5d1SDavid du Colombier } 633e12c5d1SDavid du Colombier } 643e12c5d1SDavid du Colombier doprompt=doprompt || c=='\n' || c==EOF; 653e12c5d1SDavid du Colombier if(c==EOF) runq->eof++; 663e12c5d1SDavid du Colombier else if(flag['V'] || ndot>=2 && flag['v']) pchr(err, c); 673e12c5d1SDavid du Colombier return c; 683e12c5d1SDavid du Colombier } 693e12c5d1SDavid du Colombier void pprompt(void){ 703e12c5d1SDavid du Colombier var *prompt; 713e12c5d1SDavid du Colombier if(runq->iflag){ 723e12c5d1SDavid du Colombier pstr(err, promptstr); 733e12c5d1SDavid du Colombier flush(err); 743e12c5d1SDavid du Colombier prompt=vlook("prompt"); 753e12c5d1SDavid du Colombier if(prompt->val && prompt->val->next) 763e12c5d1SDavid du Colombier promptstr=prompt->val->next->word; 773e12c5d1SDavid du Colombier else 783e12c5d1SDavid du Colombier promptstr="\t"; 793e12c5d1SDavid du Colombier } 803e12c5d1SDavid du Colombier runq->lineno++; 813e12c5d1SDavid du Colombier doprompt=0; 823e12c5d1SDavid du Colombier } 833e12c5d1SDavid du Colombier void skipwhite(void){ 843e12c5d1SDavid du Colombier int c; 853e12c5d1SDavid du Colombier for(;;){ 863e12c5d1SDavid du Colombier c=nextc(); 873e12c5d1SDavid du Colombier if(c=='#'){ /* Why did this used to be if(!inquote && c=='#') ?? */ 883e12c5d1SDavid du Colombier for(;;){ 893e12c5d1SDavid du Colombier c=nextc(); 903e12c5d1SDavid du Colombier if(c=='\n' || c==EOF) break; 913e12c5d1SDavid du Colombier advance(); 923e12c5d1SDavid du Colombier } 933e12c5d1SDavid du Colombier } 943e12c5d1SDavid du Colombier if(c==' ' || c=='\t') advance(); 953e12c5d1SDavid du Colombier else return; 963e12c5d1SDavid du Colombier } 973e12c5d1SDavid du Colombier } 983e12c5d1SDavid du Colombier void skipnl(void){ 993e12c5d1SDavid du Colombier register int c; 1003e12c5d1SDavid du Colombier for(;;){ 1013e12c5d1SDavid du Colombier skipwhite(); 1023e12c5d1SDavid du Colombier c=nextc(); 1033e12c5d1SDavid du Colombier if(c!='\n') return; 1043e12c5d1SDavid du Colombier advance(); 1053e12c5d1SDavid du Colombier } 1063e12c5d1SDavid du Colombier } 1073e12c5d1SDavid du Colombier int nextis(int c){ 1083e12c5d1SDavid du Colombier if(nextc()==c){ 1093e12c5d1SDavid du Colombier advance(); 1103e12c5d1SDavid du Colombier return 1; 1113e12c5d1SDavid du Colombier } 1123e12c5d1SDavid du Colombier return 0; 1133e12c5d1SDavid du Colombier } 1143e12c5d1SDavid du Colombier char *addtok(char *p, int val){ 1153e12c5d1SDavid du Colombier if(p==0) return 0; 1163e12c5d1SDavid du Colombier if(p==&tok[NTOK]){ 1173e12c5d1SDavid du Colombier *p=0; 1183e12c5d1SDavid du Colombier yyerror("token buffer too short"); 1193e12c5d1SDavid du Colombier return 0; 1203e12c5d1SDavid du Colombier } 1213e12c5d1SDavid du Colombier *p++=val; 1223e12c5d1SDavid du Colombier return p; 1233e12c5d1SDavid du Colombier } 1243e12c5d1SDavid du Colombier char *addutf(char *p, int c){ 1253e12c5d1SDavid du Colombier p=addtok(p, c); 1263e12c5d1SDavid du Colombier if(twobyte(c)) /* 2-byte escape */ 1273e12c5d1SDavid du Colombier return addtok(p, advance()); 1283e12c5d1SDavid du Colombier if(threebyte(c)){ /* 3-byte escape */ 1293e12c5d1SDavid du Colombier p=addtok(p, advance()); 1303e12c5d1SDavid du Colombier return addtok(p, advance()); 1313e12c5d1SDavid du Colombier } 1323e12c5d1SDavid du Colombier return p; 1333e12c5d1SDavid du Colombier } 1343e12c5d1SDavid du Colombier int lastdol; /* was the last token read '$' or '$#' or '"'? */ 1353e12c5d1SDavid du Colombier int lastword; /* was the last token read a word or compound word terminator? */ 1363e12c5d1SDavid du Colombier int yylex(void){ 1373e12c5d1SDavid du Colombier register int c, d=nextc(); 1383e12c5d1SDavid du Colombier register char *w=tok; 1393e12c5d1SDavid du Colombier register struct tree *t; 1403e12c5d1SDavid du Colombier yylval.tree=0; 1413e12c5d1SDavid du Colombier /* 1423e12c5d1SDavid du Colombier * Embarassing sneakiness: if the last token read was a quoted or unquoted 1433e12c5d1SDavid du Colombier * WORD then we alter the meaning of what follows. If the next character 1443e12c5d1SDavid du Colombier * is `(', we return SUB (a subscript paren) and consume the `('. Otherwise, 1453e12c5d1SDavid du Colombier * if the next character is the first character of a simple or compound word, 1463e12c5d1SDavid du Colombier * we insert a `^' before it. 1473e12c5d1SDavid du Colombier */ 1483e12c5d1SDavid du Colombier if(lastword){ 1493e12c5d1SDavid du Colombier lastword=0; 1503e12c5d1SDavid du Colombier if(d=='('){ 1513e12c5d1SDavid du Colombier advance(); 1523e12c5d1SDavid du Colombier strcpy(tok, "( [SUB]"); 1533e12c5d1SDavid du Colombier return SUB; 1543e12c5d1SDavid du Colombier } 1553e12c5d1SDavid du Colombier if(wordchr(d) || d=='\'' || d=='`' || d=='$' || d=='"'){ 1563e12c5d1SDavid du Colombier strcpy(tok, "^"); 1573e12c5d1SDavid du Colombier return '^'; 1583e12c5d1SDavid du Colombier } 1593e12c5d1SDavid du Colombier } 1603e12c5d1SDavid du Colombier inquote=0; 1613e12c5d1SDavid du Colombier skipwhite(); 1623e12c5d1SDavid du Colombier switch(c=advance()){ 1633e12c5d1SDavid du Colombier case EOF: 1643e12c5d1SDavid du Colombier lastdol=0; 1653e12c5d1SDavid du Colombier strcpy(tok, "EOF"); 1663e12c5d1SDavid du Colombier return EOF; 1673e12c5d1SDavid du Colombier case '$': 1683e12c5d1SDavid du Colombier lastdol=1; 1693e12c5d1SDavid du Colombier if(nextis('#')){ 1703e12c5d1SDavid du Colombier strcpy(tok, "$#"); 1713e12c5d1SDavid du Colombier return COUNT; 1723e12c5d1SDavid du Colombier } 1733e12c5d1SDavid du Colombier if(nextis('"')){ 1743e12c5d1SDavid du Colombier strcpy(tok, "$\""); 1753e12c5d1SDavid du Colombier return '"'; 1763e12c5d1SDavid du Colombier } 1773e12c5d1SDavid du Colombier strcpy(tok, "$"); 1783e12c5d1SDavid du Colombier return '$'; 1793e12c5d1SDavid du Colombier case '&': 1803e12c5d1SDavid du Colombier lastdol=0; 1813e12c5d1SDavid du Colombier if(nextis('&')){ 1823e12c5d1SDavid du Colombier skipnl(); 1833e12c5d1SDavid du Colombier strcpy(tok, "&&"); 1843e12c5d1SDavid du Colombier return ANDAND; 1853e12c5d1SDavid du Colombier } 1863e12c5d1SDavid du Colombier strcpy(tok, "&"); 1873e12c5d1SDavid du Colombier return '&'; 1883e12c5d1SDavid du Colombier case '|': 1893e12c5d1SDavid du Colombier lastdol=0; 1903e12c5d1SDavid du Colombier if(nextis(c)){ 1913e12c5d1SDavid du Colombier skipnl(); 1923e12c5d1SDavid du Colombier strcpy(tok, "||"); 1933e12c5d1SDavid du Colombier return OROR; 1943e12c5d1SDavid du Colombier } 1953e12c5d1SDavid du Colombier case '<': 1963e12c5d1SDavid du Colombier case '>': 1973e12c5d1SDavid du Colombier lastdol=0; 1983e12c5d1SDavid du Colombier /* 1993e12c5d1SDavid du Colombier * funny redirection tokens: 2003e12c5d1SDavid du Colombier * redir: arrow | arrow '[' fd ']' 2013e12c5d1SDavid du Colombier * arrow: '<' | '<<' | '>' | '>>' | '|' 2023e12c5d1SDavid du Colombier * fd: digit | digit '=' | digit '=' digit 2033e12c5d1SDavid du Colombier * digit: '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9' 2043e12c5d1SDavid du Colombier * some possibilities are nonsensical and get a message. 2053e12c5d1SDavid du Colombier */ 2063e12c5d1SDavid du Colombier *w++=c; 2073e12c5d1SDavid du Colombier t=newtree(); 2083e12c5d1SDavid du Colombier switch(c){ 2093e12c5d1SDavid du Colombier case '|': 2103e12c5d1SDavid du Colombier t->type=PIPE; 2113e12c5d1SDavid du Colombier t->fd0=1; 2123e12c5d1SDavid du Colombier t->fd1=0; 2133e12c5d1SDavid du Colombier break; 2143e12c5d1SDavid du Colombier case '>': 2153e12c5d1SDavid du Colombier t->type=REDIR; 2163e12c5d1SDavid du Colombier if(nextis(c)){ 2173e12c5d1SDavid du Colombier t->rtype=APPEND; 2183e12c5d1SDavid du Colombier *w++=c; 2193e12c5d1SDavid du Colombier } 2203e12c5d1SDavid du Colombier else t->rtype=WRITE; 2213e12c5d1SDavid du Colombier t->fd0=1; 2223e12c5d1SDavid du Colombier break; 2233e12c5d1SDavid du Colombier case '<': 2243e12c5d1SDavid du Colombier t->type=REDIR; 2253e12c5d1SDavid du Colombier if(nextis(c)){ 2263e12c5d1SDavid du Colombier t->rtype=HERE; 2273e12c5d1SDavid du Colombier *w++=c; 2283e12c5d1SDavid du Colombier } 2293e12c5d1SDavid du Colombier else t->rtype=READ; 2303e12c5d1SDavid du Colombier t->fd0=0; 2313e12c5d1SDavid du Colombier break; 2323e12c5d1SDavid du Colombier } 2333e12c5d1SDavid du Colombier if(nextis('[')){ 2343e12c5d1SDavid du Colombier *w++='['; 2353e12c5d1SDavid du Colombier c=advance(); 2363e12c5d1SDavid du Colombier *w++=c; 2373e12c5d1SDavid du Colombier if(c<'0' || '9'<c){ 2383e12c5d1SDavid du Colombier RedirErr: 2393e12c5d1SDavid du Colombier *w=0; 2403e12c5d1SDavid du Colombier yyerror(t->type==PIPE?"pipe syntax" 2413e12c5d1SDavid du Colombier :"redirection syntax"); 2423e12c5d1SDavid du Colombier return EOF; 2433e12c5d1SDavid du Colombier } 2443e12c5d1SDavid du Colombier t->fd0=0; 2453e12c5d1SDavid du Colombier do{ 2463e12c5d1SDavid du Colombier t->fd0=t->fd0*10+c-'0'; 2473e12c5d1SDavid du Colombier *w++=c; 2483e12c5d1SDavid du Colombier c=advance(); 2493e12c5d1SDavid du Colombier }while('0'<=c && c<='9'); 2503e12c5d1SDavid du Colombier if(c=='='){ 2513e12c5d1SDavid du Colombier *w++='='; 2523e12c5d1SDavid du Colombier if(t->type==REDIR) t->type=DUP; 2533e12c5d1SDavid du Colombier c=advance(); 2543e12c5d1SDavid du Colombier if('0'<=c && c<='9'){ 2553e12c5d1SDavid du Colombier t->rtype=DUPFD; 2563e12c5d1SDavid du Colombier t->fd1=t->fd0; 2573e12c5d1SDavid du Colombier t->fd0=0; 2583e12c5d1SDavid du Colombier do{ 2593e12c5d1SDavid du Colombier t->fd0=t->fd0*10+c-'0'; 2603e12c5d1SDavid du Colombier *w++=c; 2613e12c5d1SDavid du Colombier c=advance(); 2623e12c5d1SDavid du Colombier }while('0'<=c && c<='9'); 2633e12c5d1SDavid du Colombier } 2643e12c5d1SDavid du Colombier else{ 2653e12c5d1SDavid du Colombier if(t->type==PIPE) goto RedirErr; 2663e12c5d1SDavid du Colombier t->rtype=CLOSE; 2673e12c5d1SDavid du Colombier } 2683e12c5d1SDavid du Colombier } 2693e12c5d1SDavid du Colombier if(c!=']' 2703e12c5d1SDavid du Colombier || t->type==DUP && (t->rtype==HERE || t->rtype==APPEND)) 2713e12c5d1SDavid du Colombier goto RedirErr; 2723e12c5d1SDavid du Colombier *w++=']'; 2733e12c5d1SDavid du Colombier } 2743e12c5d1SDavid du Colombier *w='\0'; 2753e12c5d1SDavid du Colombier yylval.tree=t; 2763e12c5d1SDavid du Colombier if(t->type==PIPE) skipnl(); 2773e12c5d1SDavid du Colombier return t->type; 2783e12c5d1SDavid du Colombier case '\'': 2793e12c5d1SDavid du Colombier lastdol=0; 2803e12c5d1SDavid du Colombier lastword=1; 2813e12c5d1SDavid du Colombier inquote=1; 2823e12c5d1SDavid du Colombier for(;;){ 2833e12c5d1SDavid du Colombier c=advance(); 2843e12c5d1SDavid du Colombier if(c==EOF) break; 2853e12c5d1SDavid du Colombier if(c=='\''){ 2863e12c5d1SDavid du Colombier if(nextc()!='\'') 2873e12c5d1SDavid du Colombier break; 2883e12c5d1SDavid du Colombier advance(); 2893e12c5d1SDavid du Colombier } 2903e12c5d1SDavid du Colombier w=addutf(w, c); 2913e12c5d1SDavid du Colombier } 2923e12c5d1SDavid du Colombier if(w!=0) *w='\0'; 2933e12c5d1SDavid du Colombier t=token(tok, WORD); 2943e12c5d1SDavid du Colombier t->quoted=1; 2953e12c5d1SDavid du Colombier yylval.tree=t; 2963e12c5d1SDavid du Colombier return t->type; 2973e12c5d1SDavid du Colombier } 2983e12c5d1SDavid du Colombier if(!wordchr(c)){ 2993e12c5d1SDavid du Colombier lastdol=0; 3003e12c5d1SDavid du Colombier tok[0]=c; 3013e12c5d1SDavid du Colombier tok[1]='\0'; 3023e12c5d1SDavid du Colombier return c; 3033e12c5d1SDavid du Colombier } 3043e12c5d1SDavid du Colombier for(;;){ 3053e12c5d1SDavid du Colombier /* next line should have (char)c==GLOB, but ken's compiler is broken */ 3063e12c5d1SDavid du Colombier if(c=='*' || c=='[' || c=='?' || c==(unsigned char)GLOB) 3073e12c5d1SDavid du Colombier w=addtok(w, GLOB); 3083e12c5d1SDavid du Colombier w=addutf(w, c); 3093e12c5d1SDavid du Colombier c=nextc(); 3103e12c5d1SDavid du Colombier if(lastdol?!idchr(c):!wordchr(c)) break; 3113e12c5d1SDavid du Colombier advance(); 3123e12c5d1SDavid du Colombier } 313*7dd7cddfSDavid du Colombier 3143e12c5d1SDavid du Colombier lastword=1; 3153e12c5d1SDavid du Colombier lastdol=0; 3163e12c5d1SDavid du Colombier if(w!=0) *w='\0'; 3173e12c5d1SDavid du Colombier t=klook(tok); 3183e12c5d1SDavid du Colombier if(t->type!=WORD) lastword=0; 3193e12c5d1SDavid du Colombier t->quoted=0; 3203e12c5d1SDavid du Colombier yylval.tree=t; 3213e12c5d1SDavid du Colombier return t->type; 3223e12c5d1SDavid du Colombier } 323