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