1*3e12c5d1SDavid du Colombier #include "rc.h" 2*3e12c5d1SDavid du Colombier #include "exec.h" 3*3e12c5d1SDavid du Colombier #include "io.h" 4*3e12c5d1SDavid du Colombier #include "getflags.h" 5*3e12c5d1SDavid du Colombier #include "fns.h" 6*3e12c5d1SDavid du Colombier int getnext(void); 7*3e12c5d1SDavid du Colombier int wordchr(int c) 8*3e12c5d1SDavid du Colombier { 9*3e12c5d1SDavid du Colombier return !strchr("\n \t#;&|^$=`'{}()<>", c) && c!=EOF; 10*3e12c5d1SDavid du Colombier } 11*3e12c5d1SDavid du Colombier int idchr(int c) 12*3e12c5d1SDavid du Colombier { 13*3e12c5d1SDavid du Colombier /* 14*3e12c5d1SDavid du Colombier * Formerly: 15*3e12c5d1SDavid du Colombier * return 'a'<=c && c<='z' || 'A'<=c && c<='Z' || '0'<=c && c<='9' 16*3e12c5d1SDavid du Colombier * || c=='_' || c=='*'; 17*3e12c5d1SDavid du Colombier */ 18*3e12c5d1SDavid du Colombier return c>' ' && !strchr("!\"#$%&'()+,-./:;<=>?@[\\]^`{|}~", c); 19*3e12c5d1SDavid du Colombier } 20*3e12c5d1SDavid du Colombier int future=EOF; 21*3e12c5d1SDavid du Colombier int doprompt=1; 22*3e12c5d1SDavid du Colombier int inquote; 23*3e12c5d1SDavid du Colombier /* 24*3e12c5d1SDavid du Colombier * Look ahead in the input stream 25*3e12c5d1SDavid du Colombier */ 26*3e12c5d1SDavid du Colombier int nextc(void){ 27*3e12c5d1SDavid du Colombier if(future==EOF) future=getnext(); 28*3e12c5d1SDavid du Colombier return future; 29*3e12c5d1SDavid du Colombier } 30*3e12c5d1SDavid du Colombier /* 31*3e12c5d1SDavid du Colombier * Consume the lookahead character. 32*3e12c5d1SDavid du Colombier */ 33*3e12c5d1SDavid du Colombier int advance(void){ 34*3e12c5d1SDavid du Colombier int c=nextc(); 35*3e12c5d1SDavid du Colombier lastc=future; 36*3e12c5d1SDavid du Colombier future=EOF; 37*3e12c5d1SDavid du Colombier return c; 38*3e12c5d1SDavid du Colombier } 39*3e12c5d1SDavid du Colombier /* 40*3e12c5d1SDavid du Colombier * read a character from the input stream 41*3e12c5d1SDavid du Colombier */ 42*3e12c5d1SDavid du Colombier int getnext(void){ 43*3e12c5d1SDavid du Colombier register int c; 44*3e12c5d1SDavid du Colombier static peekc=EOF; 45*3e12c5d1SDavid du Colombier if(peekc!=EOF){ 46*3e12c5d1SDavid du Colombier c=peekc; 47*3e12c5d1SDavid du Colombier peekc=EOF; 48*3e12c5d1SDavid du Colombier return c; 49*3e12c5d1SDavid du Colombier } 50*3e12c5d1SDavid du Colombier if(runq->eof) return EOF; 51*3e12c5d1SDavid du Colombier if(doprompt) pprompt(); 52*3e12c5d1SDavid du Colombier c=rchr(runq->cmdfd); 53*3e12c5d1SDavid du Colombier if(!inquote && c=='\\'){ 54*3e12c5d1SDavid du Colombier c=rchr(runq->cmdfd); 55*3e12c5d1SDavid du Colombier if(c=='\n'){ 56*3e12c5d1SDavid du Colombier doprompt=1; 57*3e12c5d1SDavid du Colombier c=' '; 58*3e12c5d1SDavid du Colombier } 59*3e12c5d1SDavid du Colombier else{ 60*3e12c5d1SDavid du Colombier peekc=c; 61*3e12c5d1SDavid du Colombier c='\\'; 62*3e12c5d1SDavid du Colombier } 63*3e12c5d1SDavid du Colombier } 64*3e12c5d1SDavid du Colombier doprompt=doprompt || c=='\n' || c==EOF; 65*3e12c5d1SDavid du Colombier if(c==EOF) runq->eof++; 66*3e12c5d1SDavid du Colombier else if(flag['V'] || ndot>=2 && flag['v']) pchr(err, c); 67*3e12c5d1SDavid du Colombier return c; 68*3e12c5d1SDavid du Colombier } 69*3e12c5d1SDavid du Colombier void pprompt(void){ 70*3e12c5d1SDavid du Colombier var *prompt; 71*3e12c5d1SDavid du Colombier if(runq->iflag){ 72*3e12c5d1SDavid du Colombier pstr(err, promptstr); 73*3e12c5d1SDavid du Colombier flush(err); 74*3e12c5d1SDavid du Colombier prompt=vlook("prompt"); 75*3e12c5d1SDavid du Colombier if(prompt->val && prompt->val->next) 76*3e12c5d1SDavid du Colombier promptstr=prompt->val->next->word; 77*3e12c5d1SDavid du Colombier else 78*3e12c5d1SDavid du Colombier promptstr="\t"; 79*3e12c5d1SDavid du Colombier } 80*3e12c5d1SDavid du Colombier runq->lineno++; 81*3e12c5d1SDavid du Colombier doprompt=0; 82*3e12c5d1SDavid du Colombier } 83*3e12c5d1SDavid du Colombier void skipwhite(void){ 84*3e12c5d1SDavid du Colombier int c; 85*3e12c5d1SDavid du Colombier for(;;){ 86*3e12c5d1SDavid du Colombier c=nextc(); 87*3e12c5d1SDavid du Colombier if(c=='#'){ /* Why did this used to be if(!inquote && c=='#') ?? */ 88*3e12c5d1SDavid du Colombier for(;;){ 89*3e12c5d1SDavid du Colombier c=nextc(); 90*3e12c5d1SDavid du Colombier if(c=='\n' || c==EOF) break; 91*3e12c5d1SDavid du Colombier advance(); 92*3e12c5d1SDavid du Colombier } 93*3e12c5d1SDavid du Colombier } 94*3e12c5d1SDavid du Colombier if(c==' ' || c=='\t') advance(); 95*3e12c5d1SDavid du Colombier else return; 96*3e12c5d1SDavid du Colombier } 97*3e12c5d1SDavid du Colombier } 98*3e12c5d1SDavid du Colombier void skipnl(void){ 99*3e12c5d1SDavid du Colombier register int c; 100*3e12c5d1SDavid du Colombier for(;;){ 101*3e12c5d1SDavid du Colombier skipwhite(); 102*3e12c5d1SDavid du Colombier c=nextc(); 103*3e12c5d1SDavid du Colombier if(c!='\n') return; 104*3e12c5d1SDavid du Colombier advance(); 105*3e12c5d1SDavid du Colombier } 106*3e12c5d1SDavid du Colombier } 107*3e12c5d1SDavid du Colombier int nextis(int c){ 108*3e12c5d1SDavid du Colombier if(nextc()==c){ 109*3e12c5d1SDavid du Colombier advance(); 110*3e12c5d1SDavid du Colombier return 1; 111*3e12c5d1SDavid du Colombier } 112*3e12c5d1SDavid du Colombier return 0; 113*3e12c5d1SDavid du Colombier } 114*3e12c5d1SDavid du Colombier char *addtok(char *p, int val){ 115*3e12c5d1SDavid du Colombier if(p==0) return 0; 116*3e12c5d1SDavid du Colombier if(p==&tok[NTOK]){ 117*3e12c5d1SDavid du Colombier *p=0; 118*3e12c5d1SDavid du Colombier yyerror("token buffer too short"); 119*3e12c5d1SDavid du Colombier return 0; 120*3e12c5d1SDavid du Colombier } 121*3e12c5d1SDavid du Colombier *p++=val; 122*3e12c5d1SDavid du Colombier return p; 123*3e12c5d1SDavid du Colombier } 124*3e12c5d1SDavid du Colombier char *addutf(char *p, int c){ 125*3e12c5d1SDavid du Colombier p=addtok(p, c); 126*3e12c5d1SDavid du Colombier if(twobyte(c)) /* 2-byte escape */ 127*3e12c5d1SDavid du Colombier return addtok(p, advance()); 128*3e12c5d1SDavid du Colombier if(threebyte(c)){ /* 3-byte escape */ 129*3e12c5d1SDavid du Colombier p=addtok(p, advance()); 130*3e12c5d1SDavid du Colombier return addtok(p, advance()); 131*3e12c5d1SDavid du Colombier } 132*3e12c5d1SDavid du Colombier return p; 133*3e12c5d1SDavid du Colombier } 134*3e12c5d1SDavid du Colombier int lastdol; /* was the last token read '$' or '$#' or '"'? */ 135*3e12c5d1SDavid du Colombier int lastword; /* was the last token read a word or compound word terminator? */ 136*3e12c5d1SDavid du Colombier int yylex(void){ 137*3e12c5d1SDavid du Colombier register int c, d=nextc(); 138*3e12c5d1SDavid du Colombier register char *w=tok; 139*3e12c5d1SDavid du Colombier register struct tree *t; 140*3e12c5d1SDavid du Colombier yylval.tree=0; 141*3e12c5d1SDavid du Colombier /* 142*3e12c5d1SDavid du Colombier * Embarassing sneakiness: if the last token read was a quoted or unquoted 143*3e12c5d1SDavid du Colombier * WORD then we alter the meaning of what follows. If the next character 144*3e12c5d1SDavid du Colombier * is `(', we return SUB (a subscript paren) and consume the `('. Otherwise, 145*3e12c5d1SDavid du Colombier * if the next character is the first character of a simple or compound word, 146*3e12c5d1SDavid du Colombier * we insert a `^' before it. 147*3e12c5d1SDavid du Colombier */ 148*3e12c5d1SDavid du Colombier if(lastword){ 149*3e12c5d1SDavid du Colombier lastword=0; 150*3e12c5d1SDavid du Colombier if(d=='('){ 151*3e12c5d1SDavid du Colombier advance(); 152*3e12c5d1SDavid du Colombier strcpy(tok, "( [SUB]"); 153*3e12c5d1SDavid du Colombier return SUB; 154*3e12c5d1SDavid du Colombier } 155*3e12c5d1SDavid du Colombier if(wordchr(d) || d=='\'' || d=='`' || d=='$' || d=='"'){ 156*3e12c5d1SDavid du Colombier strcpy(tok, "^"); 157*3e12c5d1SDavid du Colombier return '^'; 158*3e12c5d1SDavid du Colombier } 159*3e12c5d1SDavid du Colombier } 160*3e12c5d1SDavid du Colombier inquote=0; 161*3e12c5d1SDavid du Colombier skipwhite(); 162*3e12c5d1SDavid du Colombier switch(c=advance()){ 163*3e12c5d1SDavid du Colombier case EOF: 164*3e12c5d1SDavid du Colombier lastdol=0; 165*3e12c5d1SDavid du Colombier strcpy(tok, "EOF"); 166*3e12c5d1SDavid du Colombier return EOF; 167*3e12c5d1SDavid du Colombier case '$': 168*3e12c5d1SDavid du Colombier lastdol=1; 169*3e12c5d1SDavid du Colombier if(nextis('#')){ 170*3e12c5d1SDavid du Colombier strcpy(tok, "$#"); 171*3e12c5d1SDavid du Colombier return COUNT; 172*3e12c5d1SDavid du Colombier } 173*3e12c5d1SDavid du Colombier if(nextis('"')){ 174*3e12c5d1SDavid du Colombier strcpy(tok, "$\""); 175*3e12c5d1SDavid du Colombier return '"'; 176*3e12c5d1SDavid du Colombier } 177*3e12c5d1SDavid du Colombier strcpy(tok, "$"); 178*3e12c5d1SDavid du Colombier return '$'; 179*3e12c5d1SDavid du Colombier case '&': 180*3e12c5d1SDavid du Colombier lastdol=0; 181*3e12c5d1SDavid du Colombier if(nextis('&')){ 182*3e12c5d1SDavid du Colombier skipnl(); 183*3e12c5d1SDavid du Colombier strcpy(tok, "&&"); 184*3e12c5d1SDavid du Colombier return ANDAND; 185*3e12c5d1SDavid du Colombier } 186*3e12c5d1SDavid du Colombier strcpy(tok, "&"); 187*3e12c5d1SDavid du Colombier return '&'; 188*3e12c5d1SDavid du Colombier case '|': 189*3e12c5d1SDavid du Colombier lastdol=0; 190*3e12c5d1SDavid du Colombier if(nextis(c)){ 191*3e12c5d1SDavid du Colombier skipnl(); 192*3e12c5d1SDavid du Colombier strcpy(tok, "||"); 193*3e12c5d1SDavid du Colombier return OROR; 194*3e12c5d1SDavid du Colombier } 195*3e12c5d1SDavid du Colombier case '<': 196*3e12c5d1SDavid du Colombier case '>': 197*3e12c5d1SDavid du Colombier lastdol=0; 198*3e12c5d1SDavid du Colombier /* 199*3e12c5d1SDavid du Colombier * funny redirection tokens: 200*3e12c5d1SDavid du Colombier * redir: arrow | arrow '[' fd ']' 201*3e12c5d1SDavid du Colombier * arrow: '<' | '<<' | '>' | '>>' | '|' 202*3e12c5d1SDavid du Colombier * fd: digit | digit '=' | digit '=' digit 203*3e12c5d1SDavid du Colombier * digit: '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9' 204*3e12c5d1SDavid du Colombier * some possibilities are nonsensical and get a message. 205*3e12c5d1SDavid du Colombier */ 206*3e12c5d1SDavid du Colombier *w++=c; 207*3e12c5d1SDavid du Colombier t=newtree(); 208*3e12c5d1SDavid du Colombier switch(c){ 209*3e12c5d1SDavid du Colombier case '|': 210*3e12c5d1SDavid du Colombier t->type=PIPE; 211*3e12c5d1SDavid du Colombier t->fd0=1; 212*3e12c5d1SDavid du Colombier t->fd1=0; 213*3e12c5d1SDavid du Colombier break; 214*3e12c5d1SDavid du Colombier case '>': 215*3e12c5d1SDavid du Colombier t->type=REDIR; 216*3e12c5d1SDavid du Colombier if(nextis(c)){ 217*3e12c5d1SDavid du Colombier t->rtype=APPEND; 218*3e12c5d1SDavid du Colombier *w++=c; 219*3e12c5d1SDavid du Colombier } 220*3e12c5d1SDavid du Colombier else t->rtype=WRITE; 221*3e12c5d1SDavid du Colombier t->fd0=1; 222*3e12c5d1SDavid du Colombier break; 223*3e12c5d1SDavid du Colombier case '<': 224*3e12c5d1SDavid du Colombier t->type=REDIR; 225*3e12c5d1SDavid du Colombier if(nextis(c)){ 226*3e12c5d1SDavid du Colombier t->rtype=HERE; 227*3e12c5d1SDavid du Colombier *w++=c; 228*3e12c5d1SDavid du Colombier } 229*3e12c5d1SDavid du Colombier else t->rtype=READ; 230*3e12c5d1SDavid du Colombier t->fd0=0; 231*3e12c5d1SDavid du Colombier break; 232*3e12c5d1SDavid du Colombier } 233*3e12c5d1SDavid du Colombier if(nextis('[')){ 234*3e12c5d1SDavid du Colombier *w++='['; 235*3e12c5d1SDavid du Colombier c=advance(); 236*3e12c5d1SDavid du Colombier *w++=c; 237*3e12c5d1SDavid du Colombier if(c<'0' || '9'<c){ 238*3e12c5d1SDavid du Colombier RedirErr: 239*3e12c5d1SDavid du Colombier *w=0; 240*3e12c5d1SDavid du Colombier yyerror(t->type==PIPE?"pipe syntax" 241*3e12c5d1SDavid du Colombier :"redirection syntax"); 242*3e12c5d1SDavid du Colombier return EOF; 243*3e12c5d1SDavid du Colombier } 244*3e12c5d1SDavid du Colombier t->fd0=0; 245*3e12c5d1SDavid du Colombier do{ 246*3e12c5d1SDavid du Colombier t->fd0=t->fd0*10+c-'0'; 247*3e12c5d1SDavid du Colombier *w++=c; 248*3e12c5d1SDavid du Colombier c=advance(); 249*3e12c5d1SDavid du Colombier }while('0'<=c && c<='9'); 250*3e12c5d1SDavid du Colombier if(c=='='){ 251*3e12c5d1SDavid du Colombier *w++='='; 252*3e12c5d1SDavid du Colombier if(t->type==REDIR) t->type=DUP; 253*3e12c5d1SDavid du Colombier c=advance(); 254*3e12c5d1SDavid du Colombier if('0'<=c && c<='9'){ 255*3e12c5d1SDavid du Colombier t->rtype=DUPFD; 256*3e12c5d1SDavid du Colombier t->fd1=t->fd0; 257*3e12c5d1SDavid du Colombier t->fd0=0; 258*3e12c5d1SDavid du Colombier do{ 259*3e12c5d1SDavid du Colombier t->fd0=t->fd0*10+c-'0'; 260*3e12c5d1SDavid du Colombier *w++=c; 261*3e12c5d1SDavid du Colombier c=advance(); 262*3e12c5d1SDavid du Colombier }while('0'<=c && c<='9'); 263*3e12c5d1SDavid du Colombier } 264*3e12c5d1SDavid du Colombier else{ 265*3e12c5d1SDavid du Colombier if(t->type==PIPE) goto RedirErr; 266*3e12c5d1SDavid du Colombier t->rtype=CLOSE; 267*3e12c5d1SDavid du Colombier } 268*3e12c5d1SDavid du Colombier } 269*3e12c5d1SDavid du Colombier if(c!=']' 270*3e12c5d1SDavid du Colombier || t->type==DUP && (t->rtype==HERE || t->rtype==APPEND)) 271*3e12c5d1SDavid du Colombier goto RedirErr; 272*3e12c5d1SDavid du Colombier *w++=']'; 273*3e12c5d1SDavid du Colombier } 274*3e12c5d1SDavid du Colombier *w='\0'; 275*3e12c5d1SDavid du Colombier yylval.tree=t; 276*3e12c5d1SDavid du Colombier if(t->type==PIPE) skipnl(); 277*3e12c5d1SDavid du Colombier return t->type; 278*3e12c5d1SDavid du Colombier case '\'': 279*3e12c5d1SDavid du Colombier lastdol=0; 280*3e12c5d1SDavid du Colombier lastword=1; 281*3e12c5d1SDavid du Colombier inquote=1; 282*3e12c5d1SDavid du Colombier for(;;){ 283*3e12c5d1SDavid du Colombier c=advance(); 284*3e12c5d1SDavid du Colombier if(c==EOF) break; 285*3e12c5d1SDavid du Colombier if(c=='\''){ 286*3e12c5d1SDavid du Colombier if(nextc()!='\'') 287*3e12c5d1SDavid du Colombier break; 288*3e12c5d1SDavid du Colombier advance(); 289*3e12c5d1SDavid du Colombier } 290*3e12c5d1SDavid du Colombier w=addutf(w, c); 291*3e12c5d1SDavid du Colombier } 292*3e12c5d1SDavid du Colombier if(w!=0) *w='\0'; 293*3e12c5d1SDavid du Colombier t=token(tok, WORD); 294*3e12c5d1SDavid du Colombier t->quoted=1; 295*3e12c5d1SDavid du Colombier yylval.tree=t; 296*3e12c5d1SDavid du Colombier return t->type; 297*3e12c5d1SDavid du Colombier } 298*3e12c5d1SDavid du Colombier if(!wordchr(c)){ 299*3e12c5d1SDavid du Colombier lastdol=0; 300*3e12c5d1SDavid du Colombier tok[0]=c; 301*3e12c5d1SDavid du Colombier tok[1]='\0'; 302*3e12c5d1SDavid du Colombier return c; 303*3e12c5d1SDavid du Colombier } 304*3e12c5d1SDavid du Colombier for(;;){ 305*3e12c5d1SDavid du Colombier /* next line should have (char)c==GLOB, but ken's compiler is broken */ 306*3e12c5d1SDavid du Colombier if(c=='*' || c=='[' || c=='?' || c==(unsigned char)GLOB) 307*3e12c5d1SDavid du Colombier w=addtok(w, GLOB); 308*3e12c5d1SDavid du Colombier w=addutf(w, c); 309*3e12c5d1SDavid du Colombier c=nextc(); 310*3e12c5d1SDavid du Colombier if(lastdol?!idchr(c):!wordchr(c)) break; 311*3e12c5d1SDavid du Colombier advance(); 312*3e12c5d1SDavid du Colombier } 313*3e12c5d1SDavid du Colombier Out: 314*3e12c5d1SDavid du Colombier lastword=1; 315*3e12c5d1SDavid du Colombier lastdol=0; 316*3e12c5d1SDavid du Colombier if(w!=0) *w='\0'; 317*3e12c5d1SDavid du Colombier t=klook(tok); 318*3e12c5d1SDavid du Colombier if(t->type!=WORD) lastword=0; 319*3e12c5d1SDavid du Colombier t->quoted=0; 320*3e12c5d1SDavid du Colombier yylval.tree=t; 321*3e12c5d1SDavid du Colombier return t->type; 322*3e12c5d1SDavid du Colombier } 323