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