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