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