1 /* 2 * shell parser (C version) 3 */ 4 5 #include "sh.h" 6 #include "c_test.h" 7 8 struct nesting_state { 9 int start_token; /* token than began nesting (eg, FOR) */ 10 int start_line; /* line nesting began on */ 11 }; 12 13 static void yyparse ARGS((void)); 14 static struct op *pipeline ARGS((int cf)); 15 static struct op *andor ARGS((void)); 16 static struct op *c_list ARGS((int multi)); 17 static struct ioword *synio ARGS((int cf)); 18 static void musthave ARGS((int c, int cf)); 19 static struct op *nested ARGS((int type, int smark, int emark)); 20 static struct op *get_command ARGS((int cf)); 21 static struct op *dogroup ARGS((void)); 22 static struct op *thenpart ARGS((void)); 23 static struct op *elsepart ARGS((void)); 24 static struct op *caselist ARGS((void)); 25 static struct op *casepart ARGS((int endtok)); 26 static struct op *function_body ARGS((char *name, int ksh_func)); 27 static char ** wordlist ARGS((void)); 28 static struct op *block ARGS((int type, struct op *t1, struct op *t2, 29 char **wp)); 30 static struct op *newtp ARGS((int type)); 31 static void syntaxerr ARGS((const char *what)) 32 GCC_FUNC_ATTR(noreturn); 33 static void nesting_push ARGS((struct nesting_state *save, int tok)); 34 static void nesting_pop ARGS((struct nesting_state *saved)); 35 static int assign_command ARGS((char *s)); 36 static int inalias ARGS((struct source *s)); 37 #ifdef KSH 38 static int dbtestp_isa ARGS((Test_env *te, Test_meta meta)); 39 static const char *dbtestp_getopnd ARGS((Test_env *te, Test_op op, 40 int do_eval)); 41 static int dbtestp_eval ARGS((Test_env *te, Test_op op, const char *opnd1, 42 const char *opnd2, int do_eval)); 43 static void dbtestp_error ARGS((Test_env *te, int offset, const char *msg)); 44 #endif /* KSH */ 45 46 static struct op *outtree; /* yyparse output */ 47 48 static struct nesting_state nesting; /* \n changed to ; */ 49 50 static int reject; /* token(cf) gets symbol again */ 51 static int symbol; /* yylex value */ 52 53 #define REJECT (reject = 1) 54 #define ACCEPT (reject = 0) 55 #define token(cf) \ 56 ((reject) ? (ACCEPT, symbol) : (symbol = yylex(cf))) 57 #define tpeek(cf) \ 58 ((reject) ? (symbol) : (REJECT, symbol = yylex(cf))) 59 60 static void 61 yyparse() 62 { 63 int c; 64 65 ACCEPT; 66 67 outtree = c_list(source->type == SSTRING); 68 c = tpeek(0); 69 if (c == 0 && !outtree) 70 outtree = newtp(TEOF); 71 else if (c != '\n' && c != 0) 72 syntaxerr((char *) 0); 73 } 74 75 static struct op * 76 pipeline(cf) 77 int cf; 78 { 79 register struct op *t, *p, *tl = NULL; 80 81 t = get_command(cf); 82 if (t != NULL) { 83 while (token(0) == '|') { 84 if ((p = get_command(CONTIN)) == NULL) 85 syntaxerr((char *) 0); 86 if (tl == NULL) 87 t = tl = block(TPIPE, t, p, NOWORDS); 88 else 89 tl = tl->right = block(TPIPE, tl->right, p, NOWORDS); 90 } 91 REJECT; 92 } 93 return (t); 94 } 95 96 static struct op * 97 andor() 98 { 99 register struct op *t, *p; 100 register int c; 101 102 t = pipeline(0); 103 if (t != NULL) { 104 while ((c = token(0)) == LOGAND || c == LOGOR) { 105 if ((p = pipeline(CONTIN)) == NULL) 106 syntaxerr((char *) 0); 107 t = block(c == LOGAND? TAND: TOR, t, p, NOWORDS); 108 } 109 REJECT; 110 } 111 return (t); 112 } 113 114 static struct op * 115 c_list(multi) 116 int multi; 117 { 118 register struct op *t = NULL, *p, *tl = NULL; 119 register int c; 120 int have_sep; 121 122 while (1) { 123 p = andor(); 124 /* Token has always been read/rejected at this point, so 125 * we don't worry about what flags to pass token() 126 */ 127 c = token(0); 128 have_sep = 1; 129 if (c == '\n' && (multi || inalias(source))) { 130 if (!p) /* ignore blank lines */ 131 continue; 132 } else if (!p) 133 break; 134 else if (c == '&' || c == COPROC) 135 p = block(c == '&' ? TASYNC : TCOPROC, 136 p, NOBLOCK, NOWORDS); 137 else if (c != ';') 138 have_sep = 0; 139 if (!t) 140 t = p; 141 else if (!tl) 142 t = tl = block(TLIST, t, p, NOWORDS); 143 else 144 tl = tl->right = block(TLIST, tl->right, p, NOWORDS); 145 if (!have_sep) 146 break; 147 } 148 REJECT; 149 return t; 150 } 151 152 static struct ioword * 153 synio(cf) 154 int cf; 155 { 156 register struct ioword *iop; 157 int ishere; 158 159 if (tpeek(cf) != REDIR) 160 return NULL; 161 ACCEPT; 162 iop = yylval.iop; 163 ishere = (iop->flag&IOTYPE) == IOHERE; 164 musthave(LWORD, ishere ? HEREDELIM : 0); 165 if (ishere) { 166 iop->delim = yylval.cp; 167 if (*ident != 0) /* unquoted */ 168 iop->flag |= IOEVAL; 169 if (herep >= &heres[HERES]) 170 yyerror("too many <<'s\n"); 171 *herep++ = iop; 172 } else 173 iop->name = yylval.cp; 174 return iop; 175 } 176 177 static void 178 musthave(c, cf) 179 int c, cf; 180 { 181 if ((token(cf)) != c) 182 syntaxerr((char *) 0); 183 } 184 185 static struct op * 186 nested(type, smark, emark) 187 int type, smark, emark; 188 { 189 register struct op *t; 190 struct nesting_state old_nesting; 191 192 nesting_push(&old_nesting, smark); 193 t = c_list(TRUE); 194 musthave(emark, KEYWORD|ALIAS); 195 nesting_pop(&old_nesting); 196 return (block(type, t, NOBLOCK, NOWORDS)); 197 } 198 199 static struct op * 200 get_command(cf) 201 int cf; 202 { 203 register struct op *t; 204 register int c, iopn = 0, syniocf; 205 struct ioword *iop, **iops; 206 XPtrV args, vars; 207 struct nesting_state old_nesting; 208 209 iops = (struct ioword **) alloc(sizeofN(struct ioword *, NUFILE+1), 210 ATEMP); 211 XPinit(args, 16); 212 XPinit(vars, 16); 213 214 syniocf = KEYWORD|ALIAS; 215 switch (c = token(cf|KEYWORD|ALIAS|VARASN)) { 216 default: 217 REJECT; 218 afree((void*) iops, ATEMP); 219 XPfree(args); 220 XPfree(vars); 221 return NULL; /* empty line */ 222 223 case LWORD: 224 case REDIR: 225 REJECT; 226 syniocf &= ~(KEYWORD|ALIAS); 227 t = newtp(TCOM); 228 t->lineno = source->line; 229 while (1) { 230 cf = (t->u.evalflags ? ARRAYVAR : 0) 231 | (XPsize(args) == 0 ? ALIAS|VARASN : CMDWORD); 232 switch (tpeek(cf)) { 233 case REDIR: 234 if (iopn >= NUFILE) 235 yyerror("too many redirections\n"); 236 iops[iopn++] = synio(cf); 237 break; 238 239 case LWORD: 240 ACCEPT; 241 /* the iopn == 0 and XPsize(vars) == 0 are 242 * dubious but at&t ksh acts this way 243 */ 244 if (iopn == 0 && XPsize(vars) == 0 245 && XPsize(args) == 0 246 && assign_command(ident)) 247 t->u.evalflags = DOVACHECK; 248 if ((XPsize(args) == 0 || Flag(FKEYWORD)) 249 && is_wdvarassign(yylval.cp)) 250 XPput(vars, yylval.cp); 251 else 252 XPput(args, yylval.cp); 253 break; 254 255 case '(': 256 /* Check for "> foo (echo hi)", which at&t ksh 257 * allows (not POSIX, but not disallowed) 258 */ 259 afree(t, ATEMP); 260 if (XPsize(args) == 0 && XPsize(vars) == 0) { 261 ACCEPT; 262 goto Subshell; 263 } 264 /* Must be a function */ 265 if (iopn != 0 || XPsize(args) != 1 266 || XPsize(vars) != 0) 267 syntaxerr((char *) 0); 268 ACCEPT; 269 /*(*/ 270 musthave(')', 0); 271 t = function_body(XPptrv(args)[0], FALSE); 272 goto Leave; 273 274 default: 275 goto Leave; 276 } 277 } 278 Leave: 279 break; 280 281 Subshell: 282 case '(': 283 t = nested(TPAREN, '(', ')'); 284 break; 285 286 case '{': /*}*/ 287 t = nested(TBRACE, '{', '}'); 288 break; 289 290 #ifdef KSH 291 case MDPAREN: 292 { 293 static const char let_cmd[] = { CHAR, 'l', CHAR, 'e', 294 CHAR, 't', EOS }; 295 /* Leave KEYWORD in syniocf (allow if (( 1 )) then ...) */ 296 t = newtp(TCOM); 297 t->lineno = source->line; 298 ACCEPT; 299 XPput(args, wdcopy(let_cmd, ATEMP)); 300 musthave(LWORD,LETEXPR); 301 XPput(args, yylval.cp); 302 break; 303 } 304 #endif /* KSH */ 305 306 #ifdef KSH 307 case DBRACKET: /* [[ .. ]] */ 308 /* Leave KEYWORD in syniocf (allow if [[ -n 1 ]] then ...) */ 309 t = newtp(TDBRACKET); 310 ACCEPT; 311 { 312 Test_env te; 313 314 te.flags = TEF_DBRACKET; 315 te.pos.av = &args; 316 te.isa = dbtestp_isa; 317 te.getopnd = dbtestp_getopnd; 318 te.eval = dbtestp_eval; 319 te.error = dbtestp_error; 320 321 test_parse(&te); 322 } 323 break; 324 #endif /* KSH */ 325 326 case FOR: 327 case SELECT: 328 t = newtp((c == FOR) ? TFOR : TSELECT); 329 musthave(LWORD, ARRAYVAR); 330 if (!is_wdvarname(yylval.cp, TRUE)) 331 yyerror("%s: bad identifier\n", 332 c == FOR ? "for" : "select"); 333 t->str = str_save(ident, ATEMP); 334 nesting_push(&old_nesting, c); 335 t->vars = wordlist(); 336 t->left = dogroup(); 337 nesting_pop(&old_nesting); 338 break; 339 340 case WHILE: 341 case UNTIL: 342 nesting_push(&old_nesting, c); 343 t = newtp((c == WHILE) ? TWHILE : TUNTIL); 344 t->left = c_list(TRUE); 345 t->right = dogroup(); 346 nesting_pop(&old_nesting); 347 break; 348 349 case CASE: 350 t = newtp(TCASE); 351 musthave(LWORD, 0); 352 t->str = yylval.cp; 353 nesting_push(&old_nesting, c); 354 t->left = caselist(); 355 nesting_pop(&old_nesting); 356 break; 357 358 case IF: 359 nesting_push(&old_nesting, c); 360 t = newtp(TIF); 361 t->left = c_list(TRUE); 362 t->right = thenpart(); 363 musthave(FI, KEYWORD|ALIAS); 364 nesting_pop(&old_nesting); 365 break; 366 367 case BANG: 368 syniocf &= ~(KEYWORD|ALIAS); 369 t = pipeline(0); 370 if (t == (struct op *) 0) 371 syntaxerr((char *) 0); 372 t = block(TBANG, NOBLOCK, t, NOWORDS); 373 break; 374 375 case TIME: 376 syniocf &= ~(KEYWORD|ALIAS); 377 t = pipeline(0); 378 t = block(TTIME, t, NOBLOCK, NOWORDS); 379 break; 380 381 case FUNCTION: 382 musthave(LWORD, 0); 383 t = function_body(yylval.cp, TRUE); 384 break; 385 } 386 387 while ((iop = synio(syniocf)) != NULL) { 388 if (iopn >= NUFILE) 389 yyerror("too many redirections\n"); 390 iops[iopn++] = iop; 391 } 392 393 if (iopn == 0) { 394 afree((void*) iops, ATEMP); 395 t->ioact = NULL; 396 } else { 397 iops[iopn++] = NULL; 398 iops = (struct ioword **) aresize((void*) iops, 399 sizeofN(struct ioword *, iopn), ATEMP); 400 t->ioact = iops; 401 } 402 403 if (t->type == TCOM || t->type == TDBRACKET) { 404 XPput(args, NULL); 405 t->args = (char **) XPclose(args); 406 XPput(vars, NULL); 407 t->vars = (char **) XPclose(vars); 408 } else { 409 XPfree(args); 410 XPfree(vars); 411 } 412 413 return t; 414 } 415 416 static struct op * 417 dogroup() 418 { 419 register int c; 420 register struct op *list; 421 422 c = token(CONTIN|KEYWORD|ALIAS); 423 /* A {...} can be used instead of do...done for for/select loops 424 * but not for while/until loops - we don't need to check if it 425 * is a while loop because it would have been parsed as part of 426 * the conditional command list... 427 */ 428 if (c == DO) 429 c = DONE; 430 else if (c == '{') 431 c = '}'; 432 else 433 syntaxerr((char *) 0); 434 list = c_list(TRUE); 435 musthave(c, KEYWORD|ALIAS); 436 return list; 437 } 438 439 static struct op * 440 thenpart() 441 { 442 register struct op *t; 443 444 musthave(THEN, KEYWORD|ALIAS); 445 t = newtp(0); 446 t->left = c_list(TRUE); 447 if (t->left == NULL) 448 syntaxerr((char *) 0); 449 t->right = elsepart(); 450 return (t); 451 } 452 453 static struct op * 454 elsepart() 455 { 456 register struct op *t; 457 458 switch (token(KEYWORD|ALIAS|VARASN)) { 459 case ELSE: 460 if ((t = c_list(TRUE)) == NULL) 461 syntaxerr((char *) 0); 462 return (t); 463 464 case ELIF: 465 t = newtp(TELIF); 466 t->left = c_list(TRUE); 467 t->right = thenpart(); 468 return (t); 469 470 default: 471 REJECT; 472 } 473 return NULL; 474 } 475 476 static struct op * 477 caselist() 478 { 479 register struct op *t, *tl; 480 int c; 481 482 c = token(CONTIN|KEYWORD|ALIAS); 483 /* A {...} can be used instead of in...esac for case statements */ 484 if (c == IN) 485 c = ESAC; 486 else if (c == '{') 487 c = '}'; 488 else 489 syntaxerr((char *) 0); 490 t = tl = NULL; 491 while ((tpeek(CONTIN|KEYWORD|ESACONLY)) != c) { /* no ALIAS here */ 492 struct op *tc = casepart(c); 493 if (tl == NULL) 494 t = tl = tc, tl->right = NULL; 495 else 496 tl->right = tc, tl = tc; 497 } 498 musthave(c, KEYWORD|ALIAS); 499 return (t); 500 } 501 502 static struct op * 503 casepart(endtok) 504 int endtok; 505 { 506 register struct op *t; 507 register int c; 508 XPtrV ptns; 509 510 XPinit(ptns, 16); 511 t = newtp(TPAT); 512 c = token(CONTIN|KEYWORD); /* no ALIAS here */ 513 if (c != '(') 514 REJECT; 515 do { 516 musthave(LWORD, 0); 517 XPput(ptns, yylval.cp); 518 } while ((c = token(0)) == '|'); 519 REJECT; 520 XPput(ptns, NULL); 521 t->vars = (char **) XPclose(ptns); 522 musthave(')', 0); 523 524 t->left = c_list(TRUE); 525 /* Note: Posix requires the ;; */ 526 if ((tpeek(CONTIN|KEYWORD|ALIAS)) != endtok) 527 musthave(BREAK, CONTIN|KEYWORD|ALIAS); 528 return (t); 529 } 530 531 static struct op * 532 function_body(name, ksh_func) 533 char *name; 534 int ksh_func; /* function foo { ... } vs foo() { .. } */ 535 { 536 char *sname, *p; 537 struct op *t; 538 int old_func_parse; 539 540 sname = wdstrip(name); 541 /* Check for valid characters in name. posix and ksh93 say only 542 * allow [a-zA-Z_0-9] but this allows more as old pdksh's have 543 * allowed more (the following were never allowed: 544 * nul space nl tab $ ' " \ ` ( ) & | ; = < > 545 * C_QUOTE covers all but = and adds # [ ? *) 546 */ 547 for (p = sname; *p; p++) 548 if (ctype(*p, C_QUOTE) || *p == '=') 549 yyerror("%s: invalid function name\n", sname); 550 551 t = newtp(TFUNCT); 552 t->str = sname; 553 t->u.ksh_func = ksh_func; 554 t->lineno = source->line; 555 556 /* Note that POSIX allows only compound statements after foo(), sh and 557 * at&t ksh allow any command, go with the later since it shouldn't 558 * break anything. However, for function foo, at&t ksh only accepts 559 * an open-brace. 560 */ 561 if (ksh_func) { 562 musthave('{', CONTIN|KEYWORD|ALIAS); /* } */ 563 REJECT; 564 } 565 566 old_func_parse = e->flags & EF_FUNC_PARSE; 567 e->flags |= EF_FUNC_PARSE; 568 if ((t->left = get_command(CONTIN)) == (struct op *) 0) { 569 /* 570 * Probably something like foo() followed by eof or ;. 571 * This is accepted by sh and ksh88. 572 * To make "typset -f foo" work reliably (so its output can 573 * be used as input), we pretend there is a colon here. 574 */ 575 t->left = newtp(TCOM); 576 t->left->args = (char **) alloc(sizeof(char *) * 2, ATEMP); 577 t->left->args[0] = alloc(sizeof(char) * 3, ATEMP); 578 t->left->args[0][0] = CHAR; 579 t->left->args[0][1] = ':'; 580 t->left->args[0][2] = EOS; 581 t->left->args[1] = (char *) 0; 582 t->left->vars = (char **) alloc(sizeof(char *), ATEMP); 583 t->left->vars[0] = (char *) 0; 584 t->left->lineno = 1; 585 } 586 if (!old_func_parse) 587 e->flags &= ~EF_FUNC_PARSE; 588 589 return t; 590 } 591 592 static char ** 593 wordlist() 594 { 595 register int c; 596 XPtrV args; 597 598 XPinit(args, 16); 599 /* Posix does not do alias expansion here... */ 600 if ((c = token(CONTIN|KEYWORD|ALIAS)) != IN) { 601 if (c != ';') /* non-POSIX, but at&t ksh accepts a ; here */ 602 REJECT; 603 return NULL; 604 } 605 while ((c = token(0)) == LWORD) 606 XPput(args, yylval.cp); 607 if (c != '\n' && c != ';') 608 syntaxerr((char *) 0); 609 if (XPsize(args) == 0) { 610 XPfree(args); 611 return NULL; 612 } else { 613 XPput(args, NULL); 614 return (char **) XPclose(args); 615 } 616 } 617 618 /* 619 * supporting functions 620 */ 621 622 static struct op * 623 block(type, t1, t2, wp) 624 int type; 625 struct op *t1, *t2; 626 char **wp; 627 { 628 register struct op *t; 629 630 t = newtp(type); 631 t->left = t1; 632 t->right = t2; 633 t->vars = wp; 634 return (t); 635 } 636 637 const struct tokeninfo { 638 const char *name; 639 short val; 640 short reserved; 641 } tokentab[] = { 642 /* Reserved words */ 643 { "if", IF, TRUE }, 644 { "then", THEN, TRUE }, 645 { "else", ELSE, TRUE }, 646 { "elif", ELIF, TRUE }, 647 { "fi", FI, TRUE }, 648 { "case", CASE, TRUE }, 649 { "esac", ESAC, TRUE }, 650 { "for", FOR, TRUE }, 651 #ifdef KSH 652 { "select", SELECT, TRUE }, 653 #endif /* KSH */ 654 { "while", WHILE, TRUE }, 655 { "until", UNTIL, TRUE }, 656 { "do", DO, TRUE }, 657 { "done", DONE, TRUE }, 658 { "in", IN, TRUE }, 659 { "function", FUNCTION, TRUE }, 660 { "time", TIME, TRUE }, 661 { "{", '{', TRUE }, 662 { "}", '}', TRUE }, 663 { "!", BANG, TRUE }, 664 #ifdef KSH 665 { "[[", DBRACKET, TRUE }, 666 #endif /* KSH */ 667 /* Lexical tokens (0[EOF], LWORD and REDIR handled specially) */ 668 { "&&", LOGAND, FALSE }, 669 { "||", LOGOR, FALSE }, 670 { ";;", BREAK, FALSE }, 671 #ifdef KSH 672 { "((", MDPAREN, FALSE }, 673 { "|&", COPROC, FALSE }, 674 #endif /* KSH */ 675 /* and some special cases... */ 676 { "newline", '\n', FALSE }, 677 { 0 } 678 }; 679 680 void 681 initkeywords() 682 { 683 register struct tokeninfo const *tt; 684 register struct tbl *p; 685 686 tinit(&keywords, APERM, 32); /* must be 2^n (currently 20 keywords) */ 687 for (tt = tokentab; tt->name; tt++) { 688 if (tt->reserved) { 689 p = tenter(&keywords, tt->name, hash(tt->name)); 690 p->flag |= DEFINED|ISSET; 691 p->type = CKEYWD; 692 p->val.i = tt->val; 693 } 694 } 695 } 696 697 static void 698 syntaxerr(what) 699 const char *what; 700 { 701 char redir[6]; /* 2<<- is the longest redirection, I think */ 702 const char *s; 703 struct tokeninfo const *tt; 704 int c; 705 706 if (!what) 707 what = "unexpected"; 708 REJECT; 709 c = token(0); 710 Again: 711 switch (c) { 712 case 0: 713 if (nesting.start_token) { 714 c = nesting.start_token; 715 source->errline = nesting.start_line; 716 what = "unmatched"; 717 goto Again; 718 } 719 /* don't quote the EOF */ 720 yyerror("syntax error: unexpected EOF\n"); 721 /*NOTREACHED*/ 722 723 case LWORD: 724 s = snptreef((char *) 0, 32, "%S", yylval.cp); 725 break; 726 727 case REDIR: 728 s = snptreef(redir, sizeof(redir), "%R", yylval.iop); 729 break; 730 731 default: 732 for (tt = tokentab; tt->name; tt++) 733 if (tt->val == c) 734 break; 735 if (tt->name) 736 s = tt->name; 737 else { 738 if (c > 0 && c < 256) { 739 redir[0] = c; 740 redir[1] = '\0'; 741 } else 742 shf_snprintf(redir, sizeof(redir), 743 "?%d", c); 744 s = redir; 745 } 746 } 747 yyerror("syntax error: `%s' %s\n", s, what); 748 } 749 750 static void 751 nesting_push(save, tok) 752 struct nesting_state *save; 753 int tok; 754 { 755 *save = nesting; 756 nesting.start_token = tok; 757 nesting.start_line = source->line; 758 } 759 760 static void 761 nesting_pop(saved) 762 struct nesting_state *saved; 763 { 764 nesting = *saved; 765 } 766 767 static struct op * 768 newtp(type) 769 int type; 770 { 771 register struct op *t; 772 773 t = (struct op *) alloc(sizeof(*t), ATEMP); 774 t->type = type; 775 t->u.evalflags = 0; 776 t->args = t->vars = NULL; 777 t->ioact = NULL; 778 t->left = t->right = NULL; 779 t->str = NULL; 780 return (t); 781 } 782 783 struct op * 784 compile(s) 785 Source *s; 786 { 787 nesting.start_token = 0; 788 nesting.start_line = 0; 789 herep = heres; 790 source = s; 791 yyparse(); 792 return outtree; 793 } 794 795 /* This kludge exists to take care of sh/at&t ksh oddity in which 796 * the arguments of alias/export/readonly/typeset have no field 797 * splitting, file globbing, or (normal) tilde expansion done. 798 * at&t ksh seems to do something similar to this since 799 * $ touch a=a; typeset a=[ab]; echo "$a" 800 * a=[ab] 801 * $ x=typeset; $x a=[ab]; echo "$a" 802 * a=a 803 * $ 804 */ 805 static int 806 assign_command(s) 807 char *s; 808 { 809 char c = *s; 810 811 if (Flag(FPOSIX) || !*s) 812 return 0; 813 return (c == 'a' && strcmp(s, "alias") == 0) 814 || (c == 'e' && strcmp(s, "export") == 0) 815 || (c == 'r' && strcmp(s, "readonly") == 0) 816 || (c == 't' && strcmp(s, "typeset") == 0); 817 } 818 819 /* Check if we are in the middle of reading an alias */ 820 static int 821 inalias(s) 822 struct source *s; 823 { 824 for (; s && s->type == SALIAS; s = s->next) 825 if (!(s->flags & SF_ALIASEND)) 826 return 1; 827 return 0; 828 } 829 830 831 #ifdef KSH 832 /* Order important - indexed by Test_meta values 833 * Note that ||, &&, ( and ) can't appear in as unquoted strings 834 * in normal shell input, so these can be interpreted unambiguously 835 * in the evaluation pass. 836 */ 837 static const char dbtest_or[] = { CHAR, '|', CHAR, '|', EOS }; 838 static const char dbtest_and[] = { CHAR, '&', CHAR, '&', EOS }; 839 static const char dbtest_not[] = { CHAR, '!', EOS }; 840 static const char dbtest_oparen[] = { CHAR, '(', EOS }; 841 static const char dbtest_cparen[] = { CHAR, ')', EOS }; 842 const char *const dbtest_tokens[] = { 843 dbtest_or, dbtest_and, dbtest_not, 844 dbtest_oparen, dbtest_cparen 845 }; 846 const char db_close[] = { CHAR, ']', CHAR, ']', EOS }; 847 const char db_lthan[] = { CHAR, '<', EOS }; 848 const char db_gthan[] = { CHAR, '>', EOS }; 849 850 /* Test if the current token is a whatever. Accepts the current token if 851 * it is. Returns 0 if it is not, non-zero if it is (in the case of 852 * TM_UNOP and TM_BINOP, the returned value is a Test_op). 853 */ 854 static int 855 dbtestp_isa(te, meta) 856 Test_env *te; 857 Test_meta meta; 858 { 859 int c = tpeek(ARRAYVAR | (meta == TM_BINOP ? 0 : CONTIN)); 860 int uqword = 0; 861 char *save = (char *) 0; 862 int ret = 0; 863 864 /* unquoted word? */ 865 uqword = c == LWORD && *ident; 866 867 if (meta == TM_OR) 868 ret = c == LOGOR; 869 else if (meta == TM_AND) 870 ret = c == LOGAND; 871 else if (meta == TM_NOT) 872 ret = uqword && strcmp(yylval.cp, dbtest_tokens[(int) TM_NOT]) == 0; 873 else if (meta == TM_OPAREN) 874 ret = c == '(' /*)*/; 875 else if (meta == TM_CPAREN) 876 ret = c == /*(*/ ')'; 877 else if (meta == TM_UNOP || meta == TM_BINOP) { 878 if (meta == TM_BINOP && c == REDIR 879 && (yylval.iop->flag == IOREAD 880 || yylval.iop->flag == IOWRITE)) 881 { 882 ret = 1; 883 save = wdcopy(yylval.iop->flag == IOREAD ? 884 db_lthan : db_gthan, ATEMP); 885 } else if (uqword && (ret = (int) test_isop(te, meta, ident))) 886 save = yylval.cp; 887 } else /* meta == TM_END */ 888 ret = uqword && strcmp(yylval.cp, db_close) == 0; 889 if (ret) { 890 ACCEPT; 891 if (meta != TM_END) { 892 if (!save) 893 save = wdcopy(dbtest_tokens[(int) meta], ATEMP); 894 XPput(*te->pos.av, save); 895 } 896 } 897 return ret; 898 } 899 900 static const char * 901 dbtestp_getopnd(te, op, do_eval) 902 Test_env *te; 903 Test_op op; 904 int do_eval; 905 { 906 int c = tpeek(ARRAYVAR); 907 908 if (c != LWORD) 909 return (const char *) 0; 910 911 ACCEPT; 912 XPput(*te->pos.av, yylval.cp); 913 914 return null; 915 } 916 917 static int 918 dbtestp_eval(te, op, opnd1, opnd2, do_eval) 919 Test_env *te; 920 Test_op op; 921 const char *opnd1; 922 const char *opnd2; 923 int do_eval; 924 { 925 return 1; 926 } 927 928 static void 929 dbtestp_error(te, offset, msg) 930 Test_env *te; 931 int offset; 932 const char *msg; 933 { 934 te->flags |= TEF_ERROR; 935 936 if (offset < 0) { 937 REJECT; 938 /* Kludgy to say the least... */ 939 symbol = LWORD; 940 yylval.cp = *(XPptrv(*te->pos.av) + XPsize(*te->pos.av) 941 + offset); 942 } 943 syntaxerr(msg); 944 } 945 #endif /* KSH */ 946