1 /* $NetBSD: exp.c,v 1.20 2009/02/14 07:12:29 lukem Exp $ */ 2 3 /*- 4 * Copyright (c) 1980, 1991, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 #if 0 35 static char sccsid[] = "@(#)exp.c 8.1 (Berkeley) 5/31/93"; 36 #else 37 __RCSID("$NetBSD: exp.c,v 1.20 2009/02/14 07:12:29 lukem Exp $"); 38 #endif 39 #endif /* not lint */ 40 41 #include <sys/types.h> 42 #include <sys/stat.h> 43 44 #include <stdarg.h> 45 #include <stdlib.h> 46 #include <unistd.h> 47 48 #ifndef SHORT_STRINGS 49 #include <string.h> 50 #endif /* SHORT_STRINGS */ 51 52 #include "csh.h" 53 #include "extern.h" 54 55 #define IGNORE 1 /* in ignore, it means to ignore value, just parse */ 56 #define NOGLOB 2 /* in ignore, it means not to globone */ 57 58 #define ADDOP 1 59 #define MULOP 2 60 #define EQOP 4 61 #define RELOP 8 62 #define RESTOP 16 63 #define ANYOP 31 64 65 #define EQEQ 1 66 #define GTR 2 67 #define LSS 4 68 #define NOTEQ 6 69 #define EQMATCH 7 70 #define NOTEQMATCH 8 71 72 static int exp1(Char ***, int); 73 static int csh_exp2(Char ***, int); 74 static int exp2a(Char ***, int); 75 static int exp2b(Char ***, int); 76 static int exp2c(Char ***, int); 77 static Char *exp3(Char ***, int); 78 static Char *exp3a(Char ***, int); 79 static Char *exp4(Char ***, int); 80 static Char *exp5(Char ***, int); 81 static Char *exp6(Char ***, int); 82 static void evalav(Char **); 83 static int isa(Char *, int); 84 static int egetn(Char *); 85 86 #ifdef EDEBUG 87 static void etracc(char *, Char *, Char ***); 88 static void etraci(char *, int, Char ***); 89 #endif 90 91 int 92 expr(Char ***vp) 93 { 94 return (exp0(vp, 0)); 95 } 96 97 int 98 exp0(Char ***vp, int ignore) 99 { 100 int p1; 101 102 p1 = exp1(vp, ignore); 103 #ifdef EDEBUG 104 etraci("exp0 p1", p1, vp); 105 #endif 106 if (**vp && eq(**vp, STRor2)) { 107 int p2; 108 109 (*vp)++; 110 p2 = exp0(vp, (ignore & IGNORE) || p1); 111 #ifdef EDEBUG 112 etraci("exp0 p2", p2, vp); 113 #endif 114 return (p1 || p2); 115 } 116 return (p1); 117 } 118 119 static int 120 exp1(Char ***vp, int ignore) 121 { 122 int p1; 123 124 p1 = csh_exp2(vp, ignore); 125 #ifdef EDEBUG 126 etraci("exp1 p1", p1, vp); 127 #endif 128 if (**vp && eq(**vp, STRand2)) { 129 int p2; 130 131 (*vp)++; 132 p2 = exp1(vp, (ignore & IGNORE) || !p1); 133 #ifdef EDEBUG 134 etraci("exp1 p2", p2, vp); 135 #endif 136 return (p1 && p2); 137 } 138 return (p1); 139 } 140 141 static int 142 csh_exp2(Char ***vp, int ignore) 143 { 144 int p1; 145 146 p1 = exp2a(vp, ignore); 147 #ifdef EDEBUG 148 etraci("exp3 p1", p1, vp); 149 #endif 150 if (**vp && eq(**vp, STRor)) { 151 int p2; 152 153 (*vp)++; 154 p2 = csh_exp2(vp, ignore); 155 #ifdef EDEBUG 156 etraci("exp3 p2", p2, vp); 157 #endif 158 return (p1 | p2); 159 } 160 return (p1); 161 } 162 163 static int 164 exp2a(Char ***vp, int ignore) 165 { 166 int p1; 167 168 p1 = exp2b(vp, ignore); 169 #ifdef EDEBUG 170 etraci("exp2a p1", p1, vp); 171 #endif 172 if (**vp && eq(**vp, STRcaret)) { 173 int p2; 174 175 (*vp)++; 176 p2 = exp2a(vp, ignore); 177 #ifdef EDEBUG 178 etraci("exp2a p2", p2, vp); 179 #endif 180 return (p1 ^ p2); 181 } 182 return (p1); 183 } 184 185 static int 186 exp2b(Char ***vp, int ignore) 187 { 188 int p1; 189 190 p1 = exp2c(vp, ignore); 191 #ifdef EDEBUG 192 etraci("exp2b p1", p1, vp); 193 #endif 194 if (**vp && eq(**vp, STRand)) { 195 int p2; 196 197 (*vp)++; 198 p2 = exp2b(vp, ignore); 199 #ifdef EDEBUG 200 etraci("exp2b p2", p2, vp); 201 #endif 202 return (p1 & p2); 203 } 204 return (p1); 205 } 206 207 static int 208 exp2c(Char ***vp, int ignore) 209 { 210 Char *p1, *p2; 211 int i; 212 213 p1 = exp3(vp, ignore); 214 #ifdef EDEBUG 215 etracc("exp2c p1", p1, vp); 216 #endif 217 if ((i = isa(**vp, EQOP)) != 0) { 218 (*vp)++; 219 if (i == EQMATCH || i == NOTEQMATCH) 220 ignore |= NOGLOB; 221 p2 = exp3(vp, ignore); 222 #ifdef EDEBUG 223 etracc("exp2c p2", p2, vp); 224 #endif 225 if (!(ignore & IGNORE)) 226 switch (i) { 227 case EQEQ: 228 i = eq(p1, p2); 229 break; 230 case EQMATCH: 231 i = Gmatch(p1, p2); 232 break; 233 case NOTEQ: 234 i = !eq(p1, p2); 235 break; 236 case NOTEQMATCH: 237 i = !Gmatch(p1, p2); 238 break; 239 } 240 xfree((ptr_t) p1); 241 xfree((ptr_t) p2); 242 return (i); 243 } 244 i = egetn(p1); 245 xfree((ptr_t) p1); 246 return (i); 247 } 248 249 static Char * 250 exp3(Char ***vp, int ignore) 251 { 252 Char *p1, *p2; 253 int i; 254 255 p1 = exp3a(vp, ignore); 256 #ifdef EDEBUG 257 etracc("exp3 p1", p1, vp); 258 #endif 259 if ((i = isa(**vp, RELOP)) != 0) { 260 (*vp)++; 261 if (**vp && eq(**vp, STRequal)) 262 i |= 1, (*vp)++; 263 p2 = exp3(vp, ignore); 264 #ifdef EDEBUG 265 etracc("exp3 p2", p2, vp); 266 #endif 267 if (!(ignore & IGNORE)) 268 switch (i) { 269 case GTR: 270 i = egetn(p1) > egetn(p2); 271 break; 272 case GTR | 1: 273 i = egetn(p1) >= egetn(p2); 274 break; 275 case LSS: 276 i = egetn(p1) < egetn(p2); 277 break; 278 case LSS | 1: 279 i = egetn(p1) <= egetn(p2); 280 break; 281 } 282 xfree((ptr_t) p1); 283 xfree((ptr_t) p2); 284 return (putn(i)); 285 } 286 return (p1); 287 } 288 289 static Char * 290 exp3a(Char ***vp, int ignore) 291 { 292 Char *op, *p1, *p2; 293 int i; 294 295 p1 = exp4(vp, ignore); 296 #ifdef EDEBUG 297 etracc("exp3a p1", p1, vp); 298 #endif 299 op = **vp; 300 if (op && any("<>", op[0]) && op[0] == op[1]) { 301 (*vp)++; 302 p2 = exp3a(vp, ignore); 303 #ifdef EDEBUG 304 etracc("exp3a p2", p2, vp); 305 #endif 306 if (op[0] == '<') 307 i = egetn(p1) << egetn(p2); 308 else 309 i = egetn(p1) >> egetn(p2); 310 xfree((ptr_t) p1); 311 xfree((ptr_t) p2); 312 return (putn(i)); 313 } 314 return (p1); 315 } 316 317 static Char * 318 exp4(Char ***vp, int ignore) 319 { 320 Char *p1, *p2; 321 int i; 322 323 i = 0; 324 p1 = exp5(vp, ignore); 325 #ifdef EDEBUG 326 etracc("exp4 p1", p1, vp); 327 #endif 328 if (isa(**vp, ADDOP)) { 329 Char *op; 330 331 op = *(*vp)++; 332 p2 = exp4(vp, ignore); 333 #ifdef EDEBUG 334 etracc("exp4 p2", p2, vp); 335 #endif 336 if (!(ignore & IGNORE)) 337 switch (op[0]) { 338 case '+': 339 i = egetn(p1) + egetn(p2); 340 break; 341 case '-': 342 i = egetn(p1) - egetn(p2); 343 break; 344 } 345 xfree((ptr_t) p1); 346 xfree((ptr_t) p2); 347 return (putn(i)); 348 } 349 return (p1); 350 } 351 352 static Char * 353 exp5(Char ***vp, int ignore) 354 { 355 Char *p1, *p2; 356 int i; 357 358 i = 0; 359 p1 = exp6(vp, ignore); 360 #ifdef EDEBUG 361 etracc("exp5 p1", p1, vp); 362 #endif 363 if (isa(**vp, MULOP)) { 364 Char *op; 365 366 op = *(*vp)++; 367 p2 = exp5(vp, ignore); 368 #ifdef EDEBUG 369 etracc("exp5 p2", p2, vp); 370 #endif 371 if (!(ignore & IGNORE)) 372 switch (op[0]) { 373 case '*': 374 i = egetn(p1) * egetn(p2); 375 break; 376 case '/': 377 i = egetn(p2); 378 if (i == 0) 379 stderror(ERR_DIV0); 380 i = egetn(p1) / i; 381 break; 382 case '%': 383 i = egetn(p2); 384 if (i == 0) 385 stderror(ERR_MOD0); 386 i = egetn(p1) % i; 387 break; 388 } 389 xfree((ptr_t) p1); 390 xfree((ptr_t) p2); 391 return (putn(i)); 392 } 393 return (p1); 394 } 395 396 static Char * 397 exp6(Char ***vp, int ignore) 398 { 399 Char *cp, *dp, *ep; 400 int ccode, i; 401 402 i = 0; 403 if (**vp == 0) 404 stderror(ERR_NAME | ERR_EXPRESSION); 405 if (eq(**vp, STRbang)) { 406 (*vp)++; 407 cp = exp6(vp, ignore); 408 #ifdef EDEBUG 409 etracc("exp6 ! cp", cp, vp); 410 #endif 411 i = egetn(cp); 412 xfree((ptr_t) cp); 413 return (putn(!i)); 414 } 415 if (eq(**vp, STRtilde)) { 416 (*vp)++; 417 cp = exp6(vp, ignore); 418 #ifdef EDEBUG 419 etracc("exp6 ~ cp", cp, vp); 420 #endif 421 i = egetn(cp); 422 xfree((ptr_t) cp); 423 return (putn(~i)); 424 } 425 if (eq(**vp, STRLparen)) { 426 (*vp)++; 427 ccode = exp0(vp, ignore); 428 #ifdef EDEBUG 429 etraci("exp6 () ccode", ccode, vp); 430 #endif 431 if (**vp == 0 || ***vp != ')') 432 stderror(ERR_NAME | ERR_EXPRESSION); 433 (*vp)++; 434 return (putn(ccode)); 435 } 436 if (eq(**vp, STRLbrace)) { 437 struct command faket; 438 Char *fakecom[2]; 439 Char **v; 440 441 faket.t_dtyp = NODE_COMMAND; 442 faket.t_dflg = 0; 443 faket.t_dcar = faket.t_dcdr = faket.t_dspr = NULL; 444 faket.t_dcom = fakecom; 445 fakecom[0] = STRfakecom; 446 fakecom[1] = NULL; 447 (*vp)++; 448 v = *vp; 449 for (;;) { 450 if (!**vp) 451 stderror(ERR_NAME | ERR_MISSING, '}'); 452 if (eq(*(*vp)++, STRRbrace)) 453 break; 454 } 455 if (ignore & IGNORE) 456 return (Strsave(STRNULL)); 457 psavejob(); 458 if (pfork(&faket, -1) == 0) { 459 *--(*vp) = 0; 460 evalav(v); 461 exitstat(); 462 } 463 pwait(); 464 prestjob(); 465 #ifdef EDEBUG 466 etraci("exp6 {} status", egetn(value(STRstatus)), vp); 467 #endif 468 return (putn(egetn(value(STRstatus)) == 0)); 469 } 470 if (isa(**vp, ANYOP)) 471 return (Strsave(STRNULL)); 472 cp = *(*vp)++; 473 if (*cp == '-' && any("erwxfdzopls", cp[1])) { 474 struct stat stb; 475 476 if (cp[2] != '\0') 477 stderror(ERR_NAME | ERR_FILEINQ); 478 /* 479 * Detect missing file names by checking for operator in the file name 480 * position. However, if an operator name appears there, we must make 481 * sure that there's no file by that name (e.g., "/") before announcing 482 * an error. Even this check isn't quite right, since it doesn't take 483 * globbing into account. 484 */ 485 if (isa(**vp, ANYOP) && stat(short2str(**vp), &stb)) 486 stderror(ERR_NAME | ERR_FILENAME); 487 488 dp = *(*vp)++; 489 if (ignore & IGNORE) 490 return (Strsave(STRNULL)); 491 ep = globone(dp, G_ERROR); 492 switch (cp[1]) { 493 case 'r': 494 i = !access(short2str(ep), R_OK); 495 break; 496 case 'w': 497 i = !access(short2str(ep), W_OK); 498 break; 499 case 'x': 500 i = !access(short2str(ep), X_OK); 501 break; 502 default: 503 if (cp[1] == 'l' ? 504 lstat(short2str(ep), &stb) : stat(short2str(ep), &stb)) { 505 xfree((ptr_t) ep); 506 return (Strsave(STR0)); 507 } 508 switch (cp[1]) { 509 case 'd': 510 i = S_ISDIR(stb.st_mode); 511 break; 512 case 'e': 513 i = 1; 514 break; 515 case 'f': 516 i = S_ISREG(stb.st_mode); 517 break; 518 case 'l': 519 #ifdef S_ISLNK 520 i = S_ISLNK(stb.st_mode); 521 #else 522 i = 0; 523 #endif 524 break; 525 case 'o': 526 i = stb.st_uid == (uid_t)uid; 527 break; 528 case 'p': 529 #ifdef S_ISFIFO 530 i = S_ISFIFO(stb.st_mode); 531 #else 532 i = 0; 533 #endif 534 break; 535 case 's': 536 #ifdef S_ISSOCK 537 i = S_ISSOCK(stb.st_mode); 538 #else 539 i = 0; 540 #endif 541 break; 542 case 'z': 543 i = stb.st_size == 0; 544 break; 545 } 546 } 547 #ifdef EDEBUG 548 etraci("exp6 -? i", i, vp); 549 #endif 550 xfree((ptr_t) ep); 551 return (putn(i)); 552 } 553 #ifdef EDEBUG 554 etracc("exp6 default", cp, vp); 555 #endif 556 return (ignore & NOGLOB ? Strsave(cp) : globone(cp, G_ERROR)); 557 } 558 559 static void 560 evalav(Char **v) 561 { 562 struct wordent *hp, paraml1, *wdp; 563 struct command *t; 564 565 hp = ¶ml1; 566 wdp = hp; 567 set(STRstatus, Strsave(STR0)); 568 hp->prev = hp->next = hp; 569 hp->word = STRNULL; 570 while (*v) { 571 struct wordent *new; 572 573 new = (struct wordent *)xcalloc(1, sizeof *wdp); 574 new->prev = wdp; 575 new->next = hp; 576 wdp->next = new; 577 wdp = new; 578 wdp->word = Strsave(*v++); 579 } 580 hp->prev = wdp; 581 alias(¶ml1); 582 t = syntax(paraml1.next, ¶ml1, 0); 583 if (seterr) 584 stderror(ERR_OLD); 585 execute(t, -1, NULL, NULL); 586 freelex(¶ml1), freesyn(t); 587 } 588 589 static int 590 isa(Char *cp, int what) 591 { 592 if (cp == 0) 593 return ((what & RESTOP) != 0); 594 if (cp[1] == 0) { 595 if (what & ADDOP && (*cp == '+' || *cp == '-')) 596 return (1); 597 if (what & MULOP && (*cp == '*' || *cp == '/' || *cp == '%')) 598 return (1); 599 if (what & RESTOP && (*cp == '(' || *cp == ')' || *cp == '!' || 600 *cp == '~' || *cp == '^' || *cp == '"')) 601 return (1); 602 } 603 else if (cp[2] == 0) { 604 if (what & RESTOP) { 605 if (cp[0] == '|' && cp[1] == '&') 606 return (1); 607 if (cp[0] == '<' && cp[1] == '<') 608 return (1); 609 if (cp[0] == '>' && cp[1] == '>') 610 return (1); 611 } 612 if (what & EQOP) { 613 if (cp[0] == '=') { 614 if (cp[1] == '=') 615 return (EQEQ); 616 if (cp[1] == '~') 617 return (EQMATCH); 618 } 619 else if (cp[0] == '!') { 620 if (cp[1] == '=') 621 return (NOTEQ); 622 if (cp[1] == '~') 623 return (NOTEQMATCH); 624 } 625 } 626 } 627 if (what & RELOP) { 628 if (*cp == '<') 629 return (LSS); 630 if (*cp == '>') 631 return (GTR); 632 } 633 return (0); 634 } 635 636 static int 637 egetn(Char *cp) 638 { 639 if (*cp && *cp != '-' && !Isdigit(*cp)) 640 stderror(ERR_NAME | ERR_EXPRESSION); 641 return (getn(cp)); 642 } 643 644 /* Phew! */ 645 646 #ifdef EDEBUG 647 static void 648 etraci(char *str, int i, Char ***vp) 649 { 650 (void)fprintf(csherr, "%s=%d\t", str, i); 651 blkpr(csherr, *vp); 652 (void)fprintf(csherr, "\n"); 653 } 654 static void 655 etracc(char *str, Char *cp, Char ***vp) 656 { 657 (void)fprintf(csherr, "%s=%s\t", str, vis_str(cp)); 658 blkpr(csherr, *vp); 659 (void)fprintf(csherr, "\n"); 660 } 661 #endif 662