1 /* $Header: /src/pub/tcsh/sh.exp.c,v 3.45 2005/01/18 20:24:50 christos Exp $ */ 2 /* 3 * sh.exp.c: Expression evaluations 4 */ 5 /*- 6 * Copyright (c) 1980, 1991 The Regents of the University of California. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 #include "sh.h" 34 35 RCSID("$Id: sh.exp.c,v 3.45 2005/01/18 20:24:50 christos Exp $") 36 37 #include "tw.h" 38 39 /* 40 * C shell 41 */ 42 43 #define TEXP_IGNORE 1 /* in ignore, it means to ignore value, just parse */ 44 #define TEXP_NOGLOB 2 /* in ignore, it means not to globone */ 45 46 #define ADDOP 1 47 #define MULOP 2 48 #define EQOP 4 49 #define RELOP 8 50 #define RESTOP 16 51 #define ANYOP 31 52 53 #define EQEQ 1 54 #define GTR 2 55 #define LSS 4 56 #define NOTEQ 6 57 #define EQMATCH 7 58 #define NOTEQMATCH 8 59 60 static int sh_access __P((Char *, int)); 61 static int exp1 __P((Char ***, int)); 62 static int exp2x __P((Char ***, int)); 63 static int exp2a __P((Char ***, int)); 64 static int exp2b __P((Char ***, int)); 65 static int exp2c __P((Char ***, int)); 66 static Char *exp3 __P((Char ***, int)); 67 static Char *exp3a __P((Char ***, int)); 68 static Char *exp4 __P((Char ***, int)); 69 static Char *exp5 __P((Char ***, int)); 70 static Char *exp6 __P((Char ***, int)); 71 static void evalav __P((Char **)); 72 static int isa __P((Char *, int)); 73 static int egetn __P((Char *)); 74 75 76 #ifdef EDEBUG 77 static void etracc __P((char *, Char *, Char ***)); 78 static void etraci __P((char *, int, Char ***)); 79 #endif /* EDEBUG */ 80 81 82 /* 83 * shell access function according to POSIX and non POSIX 84 * From Beto Appleton (beto@aixwiz.aix.ibm.com) 85 */ 86 static int 87 sh_access(fname, mode) 88 Char *fname; 89 int mode; 90 { 91 #if defined(POSIX) && !defined(USE_ACCESS) 92 struct stat statb; 93 #endif /* POSIX */ 94 char *name = short2str(fname); 95 96 if (*name == '\0') 97 return 1; 98 99 #if !defined(POSIX) || defined(USE_ACCESS) 100 return access(name, mode); 101 #else /* POSIX */ 102 103 /* 104 * POSIX 1003.2-d11.2 105 * -r file True if file exists and is readable. 106 * -w file True if file exists and is writable. 107 * True shall indicate only that the write flag is on. 108 * The file shall not be writable on a read-only file 109 * system even if this test indicates true. 110 * -x file True if file exists and is executable. 111 * True shall indicate only that the execute flag is on. 112 * If file is a directory, true indicates that the file 113 * can be searched. 114 */ 115 if (mode != W_OK && mode != X_OK) 116 return access(name, mode); 117 118 if (stat(name, &statb) == -1) 119 return 1; 120 121 if (access(name, mode) == 0) { 122 #ifdef S_ISDIR 123 if (S_ISDIR(statb.st_mode) && mode == X_OK) 124 return 0; 125 #endif /* S_ISDIR */ 126 127 /* root needs permission for someone */ 128 switch (mode) { 129 case W_OK: 130 mode = S_IWUSR | S_IWGRP | S_IWOTH; 131 break; 132 case X_OK: 133 mode = S_IXUSR | S_IXGRP | S_IXOTH; 134 break; 135 default: 136 abort(); 137 break; 138 } 139 140 } 141 142 else if (euid == statb.st_uid) 143 mode <<= 6; 144 145 else if (egid == statb.st_gid) 146 mode <<= 3; 147 148 # ifdef NGROUPS_MAX 149 else { 150 /* you can be in several groups */ 151 long n; 152 GETGROUPS_T *groups; 153 154 /* 155 * Try these things to find a positive maximum groups value: 156 * 1) sysconf(_SC_NGROUPS_MAX) 157 * 2) NGROUPS_MAX 158 * 3) getgroups(0, unused) 159 * Then allocate and scan the groups array if one of these worked. 160 */ 161 # if defined (HAVE_SYSCONF) && defined (_SC_NGROUPS_MAX) 162 if ((n = sysconf(_SC_NGROUPS_MAX)) == -1) 163 # endif /* _SC_NGROUPS_MAX */ 164 n = NGROUPS_MAX; 165 if (n <= 0) 166 n = getgroups(0, (GETGROUPS_T *) NULL); 167 168 if (n > 0) { 169 groups = xmalloc((size_t) (n * sizeof(*groups))); 170 n = getgroups((int) n, groups); 171 while (--n >= 0) 172 if (groups[n] == statb.st_gid) { 173 mode <<= 3; 174 break; 175 } 176 } 177 } 178 # endif /* NGROUPS_MAX */ 179 180 if (statb.st_mode & mode) 181 return 0; 182 else 183 return 1; 184 #endif /* !POSIX */ 185 } 186 187 int 188 expr(vp) 189 Char ***vp; 190 { 191 return (exp0(vp, 0)); 192 } 193 194 int 195 exp0(vp, ignore) 196 Char ***vp; 197 int ignore; 198 { 199 int p1 = exp1(vp, ignore); 200 201 #ifdef EDEBUG 202 etraci("exp0 p1", p1, vp); 203 #endif /* EDEBUG */ 204 if (**vp && eq(**vp, STRor2)) { 205 int p2; 206 207 (*vp)++; 208 p2 = exp0(vp, (ignore & TEXP_IGNORE) || p1); 209 #ifdef EDEBUG 210 etraci("exp0 p2", p2, vp); 211 #endif /* EDEBUG */ 212 return (p1 || p2); 213 } 214 return (p1); 215 } 216 217 static int 218 exp1(vp, ignore) 219 Char ***vp; 220 int ignore; 221 { 222 int p1 = exp2x(vp, ignore); 223 224 #ifdef EDEBUG 225 etraci("exp1 p1", p1, vp); 226 #endif /* EDEBUG */ 227 if (**vp && eq(**vp, STRand2)) { 228 int p2; 229 230 (*vp)++; 231 p2 = exp1(vp, (ignore & TEXP_IGNORE) || !p1); 232 #ifdef EDEBUG 233 etraci("exp1 p2", p2, vp); 234 #endif /* EDEBUG */ 235 return (p1 && p2); 236 } 237 return (p1); 238 } 239 240 static int 241 exp2x(vp, ignore) 242 Char ***vp; 243 int ignore; 244 { 245 int p1 = exp2a(vp, ignore); 246 247 #ifdef EDEBUG 248 etraci("exp3 p1", p1, vp); 249 #endif /* EDEBUG */ 250 if (**vp && eq(**vp, STRor)) { 251 int p2; 252 253 (*vp)++; 254 p2 = exp2x(vp, ignore); 255 #ifdef EDEBUG 256 etraci("exp3 p2", p2, vp); 257 #endif /* EDEBUG */ 258 return (p1 | p2); 259 } 260 return (p1); 261 } 262 263 static int 264 exp2a(vp, ignore) 265 Char ***vp; 266 int ignore; 267 { 268 int p1 = exp2b(vp, ignore); 269 270 #ifdef EDEBUG 271 etraci("exp2a p1", p1, vp); 272 #endif /* EDEBUG */ 273 if (**vp && eq(**vp, STRcaret)) { 274 int p2; 275 276 (*vp)++; 277 p2 = exp2a(vp, ignore); 278 #ifdef EDEBUG 279 etraci("exp2a p2", p2, vp); 280 #endif /* EDEBUG */ 281 return (p1 ^ p2); 282 } 283 return (p1); 284 } 285 286 static int 287 exp2b(vp, ignore) 288 Char ***vp; 289 int ignore; 290 { 291 int p1 = exp2c(vp, ignore); 292 293 #ifdef EDEBUG 294 etraci("exp2b p1", p1, vp); 295 #endif /* EDEBUG */ 296 if (**vp && eq(**vp, STRand)) { 297 int p2; 298 299 (*vp)++; 300 p2 = exp2b(vp, ignore); 301 #ifdef EDEBUG 302 etraci("exp2b p2", p2, vp); 303 #endif /* EDEBUG */ 304 return (p1 & p2); 305 } 306 return (p1); 307 } 308 309 static int 310 exp2c(vp, ignore) 311 Char ***vp; 312 int ignore; 313 { 314 Char *p1 = exp3(vp, ignore); 315 Char *p2; 316 int i; 317 318 #ifdef EDEBUG 319 etracc("exp2c p1", p1, vp); 320 #endif /* EDEBUG */ 321 if ((i = isa(**vp, EQOP)) != 0) { 322 (*vp)++; 323 if (i == EQMATCH || i == NOTEQMATCH) 324 ignore |= TEXP_NOGLOB; 325 p2 = exp3(vp, ignore); 326 #ifdef EDEBUG 327 etracc("exp2c p2", p2, vp); 328 #endif /* EDEBUG */ 329 if (!(ignore & TEXP_IGNORE)) 330 switch (i) { 331 332 case EQEQ: 333 i = eq(p1, p2); 334 break; 335 336 case NOTEQ: 337 i = !eq(p1, p2); 338 break; 339 340 case EQMATCH: 341 i = Gmatch(p1, p2); 342 break; 343 344 case NOTEQMATCH: 345 i = !Gmatch(p1, p2); 346 break; 347 } 348 xfree((ptr_t) p1); 349 xfree((ptr_t) p2); 350 return (i); 351 } 352 i = egetn(p1); 353 xfree((ptr_t) p1); 354 return (i); 355 } 356 357 static Char * 358 exp3(vp, ignore) 359 Char ***vp; 360 int ignore; 361 { 362 Char *p1, *p2; 363 int i; 364 365 p1 = exp3a(vp, ignore); 366 #ifdef EDEBUG 367 etracc("exp3 p1", p1, vp); 368 #endif /* EDEBUG */ 369 if ((i = isa(**vp, RELOP)) != 0) { 370 (*vp)++; 371 if (**vp && eq(**vp, STRequal)) 372 i |= 1, (*vp)++; 373 p2 = exp3(vp, ignore); 374 #ifdef EDEBUG 375 etracc("exp3 p2", p2, vp); 376 #endif /* EDEBUG */ 377 if (!(ignore & TEXP_IGNORE)) 378 switch (i) { 379 380 case GTR: 381 i = egetn(p1) > egetn(p2); 382 break; 383 384 case GTR | 1: 385 i = egetn(p1) >= egetn(p2); 386 break; 387 388 case LSS: 389 i = egetn(p1) < egetn(p2); 390 break; 391 392 case LSS | 1: 393 i = egetn(p1) <= egetn(p2); 394 break; 395 } 396 xfree((ptr_t) p1); 397 xfree((ptr_t) p2); 398 return (putn(i)); 399 } 400 return (p1); 401 } 402 403 static Char * 404 exp3a(vp, ignore) 405 Char ***vp; 406 int ignore; 407 { 408 Char *p1, *p2, *op; 409 int i; 410 411 p1 = exp4(vp, ignore); 412 #ifdef EDEBUG 413 etracc("exp3a p1", p1, vp); 414 #endif /* EDEBUG */ 415 op = **vp; 416 if (op && any("<>", op[0]) && op[0] == op[1]) { 417 (*vp)++; 418 p2 = exp3a(vp, ignore); 419 #ifdef EDEBUG 420 etracc("exp3a p2", p2, vp); 421 #endif /* EDEBUG */ 422 if (op[0] == '<') 423 i = egetn(p1) << egetn(p2); 424 else 425 i = egetn(p1) >> egetn(p2); 426 xfree((ptr_t) p1); 427 xfree((ptr_t) p2); 428 return (putn(i)); 429 } 430 return (p1); 431 } 432 433 static Char * 434 exp4(vp, ignore) 435 Char ***vp; 436 int ignore; 437 { 438 Char *p1, *p2; 439 int i = 0; 440 441 p1 = exp5(vp, ignore); 442 #ifdef EDEBUG 443 etracc("exp4 p1", p1, vp); 444 #endif /* EDEBUG */ 445 if (isa(**vp, ADDOP)) { 446 Char *op = *(*vp)++; 447 448 p2 = exp4(vp, ignore); 449 #ifdef EDEBUG 450 etracc("exp4 p2", p2, vp); 451 #endif /* EDEBUG */ 452 if (!(ignore & TEXP_IGNORE)) 453 switch (op[0]) { 454 455 case '+': 456 i = egetn(p1) + egetn(p2); 457 break; 458 459 case '-': 460 i = egetn(p1) - egetn(p2); 461 break; 462 } 463 xfree((ptr_t) p1); 464 xfree((ptr_t) p2); 465 return (putn(i)); 466 } 467 return (p1); 468 } 469 470 static Char * 471 exp5(vp, ignore) 472 Char ***vp; 473 int ignore; 474 { 475 Char *p1, *p2; 476 int i = 0; 477 478 p1 = exp6(vp, ignore); 479 #ifdef EDEBUG 480 etracc("exp5 p1", p1, vp); 481 #endif /* EDEBUG */ 482 483 if (isa(**vp, MULOP)) { 484 Char *op = *(*vp)++; 485 if ((ignore & TEXP_NOGLOB) != 0) 486 /* 487 * We are just trying to get the right side of 488 * a =~ or !~ operator 489 */ 490 return Strsave(op); 491 492 p2 = exp5(vp, ignore); 493 #ifdef EDEBUG 494 etracc("exp5 p2", p2, vp); 495 #endif /* EDEBUG */ 496 if (!(ignore & TEXP_IGNORE)) 497 switch (op[0]) { 498 499 case '*': 500 i = egetn(p1) * egetn(p2); 501 break; 502 503 case '/': 504 i = egetn(p2); 505 if (i == 0) 506 stderror(ERR_DIV0); 507 i = egetn(p1) / i; 508 break; 509 510 case '%': 511 i = egetn(p2); 512 if (i == 0) 513 stderror(ERR_MOD0); 514 i = egetn(p1) % i; 515 break; 516 } 517 xfree((ptr_t) p1); 518 xfree((ptr_t) p2); 519 return (putn(i)); 520 } 521 return (p1); 522 } 523 524 static Char * 525 exp6(vp, ignore) 526 Char ***vp; 527 int ignore; 528 { 529 int ccode, i = 0; 530 Char *cp; 531 532 if (**vp == 0) 533 stderror(ERR_NAME | ERR_EXPRESSION); 534 if (eq(**vp, STRbang)) { 535 (*vp)++; 536 cp = exp6(vp, ignore); 537 #ifdef EDEBUG 538 etracc("exp6 ! cp", cp, vp); 539 #endif /* EDEBUG */ 540 i = egetn(cp); 541 xfree((ptr_t) cp); 542 return (putn(!i)); 543 } 544 if (eq(**vp, STRtilde)) { 545 (*vp)++; 546 cp = exp6(vp, ignore); 547 #ifdef EDEBUG 548 etracc("exp6 ~ cp", cp, vp); 549 #endif /* EDEBUG */ 550 i = egetn(cp); 551 xfree((ptr_t) cp); 552 return (putn(~i)); 553 } 554 if (eq(**vp, STRLparen)) { 555 (*vp)++; 556 ccode = exp0(vp, ignore); 557 #ifdef EDEBUG 558 etraci("exp6 () ccode", ccode, vp); 559 #endif /* EDEBUG */ 560 if (*vp == 0 || **vp == 0 || ***vp != ')') 561 stderror(ERR_NAME | ERR_EXPRESSION); 562 (*vp)++; 563 return (putn(ccode)); 564 } 565 if (eq(**vp, STRLbrace)) { 566 Char **v; 567 struct command faket; 568 Char *fakecom[2]; 569 570 faket.t_dtyp = NODE_COMMAND; 571 faket.t_dflg = F_BACKQ; 572 faket.t_dcar = faket.t_dcdr = faket.t_dspr = NULL; 573 faket.t_dcom = fakecom; 574 fakecom[0] = STRfakecom; 575 fakecom[1] = NULL; 576 (*vp)++; 577 v = *vp; 578 for (;;) { 579 if (!**vp) 580 stderror(ERR_NAME | ERR_MISSING, '}'); 581 if (eq(*(*vp)++, STRRbrace)) 582 break; 583 } 584 if (ignore & TEXP_IGNORE) 585 return (Strsave(STRNULL)); 586 psavejob(); 587 if (pfork(&faket, -1) == 0) { 588 *--(*vp) = 0; 589 evalav(v); 590 exitstat(); 591 } 592 pwait(); 593 prestjob(); 594 #ifdef EDEBUG 595 etraci("exp6 {} status", egetn(varval(STRstatus)), vp); 596 #endif /* EDEBUG */ 597 return (putn(egetn(varval(STRstatus)) == 0)); 598 } 599 if (isa(**vp, ANYOP)) 600 return (Strsave(STRNULL)); 601 cp = *(*vp)++; 602 #ifdef convex 603 # define FILETESTS "erwxfdzoplstSXLbcugkmKR" 604 #else 605 # define FILETESTS "erwxfdzoplstSXLbcugkmK" 606 #endif /* convex */ 607 #define FILEVALS "ZAMCDIUGNFPL" 608 if (*cp == '-' && (any(FILETESTS, cp[1]) || any(FILEVALS, cp[1]))) 609 return(filetest(cp, vp, ignore)); 610 #ifdef EDEBUG 611 etracc("exp6 default", cp, vp); 612 #endif /* EDEBUG */ 613 return (ignore & TEXP_NOGLOB ? Strsave(cp) : globone(cp, G_APPEND)); 614 } 615 616 617 /* 618 * Extended file tests 619 * From: John Rowe <rowe@excc.exeter.ac.uk> 620 */ 621 Char * 622 filetest(cp, vp, ignore) 623 Char *cp, ***vp; 624 int ignore; 625 { 626 #ifdef convex 627 struct cvxstat stb, *st = NULL; 628 # define TCSH_STAT stat64 629 #else 630 # define TCSH_STAT stat 631 struct stat stb, *st = NULL; 632 #endif /* convex */ 633 634 #ifdef S_IFLNK 635 # ifdef convex 636 struct cvxstat lstb, *lst = NULL; 637 # define TCSH_LSTAT lstat64 638 # else 639 # define TCSH_LSTAT lstat 640 struct stat lstb, *lst = NULL; 641 # endif /* convex */ 642 char *filnam; 643 #endif /* S_IFLNK */ 644 645 int i = 0; 646 unsigned pmask = 0xffff; 647 int altout = 0; 648 Char *ft = cp, *dp, *ep, *strdev, *strino, *strF, *str, valtest = '\0', 649 *errval = STR0; 650 char *string, string0[8]; 651 time_t footime; 652 struct passwd *pw; 653 struct group *gr; 654 655 while(any(FILETESTS, *++ft)) 656 continue; 657 658 if (!*ft && *(ft - 1) == 'L') 659 --ft; 660 661 if (any(FILEVALS, *ft)) { 662 valtest = *ft++; 663 /* 664 * Value tests return '-1' on failure as 0 is 665 * a legitimate value for many of them. 666 * 'F' returns ':' for compatibility. 667 */ 668 errval = valtest == 'F' ? STRcolon : STRminus1; 669 670 if (valtest == 'P' && *ft >= '0' && *ft <= '7') { 671 pmask = (char) *ft - '0'; 672 while ( *++ft >= '0' && *ft <= '7' ) 673 pmask = 8 * pmask + ((char) *ft - '0'); 674 } 675 if (Strcmp(ft, STRcolon) == 0 && any("AMCUGP", valtest)) { 676 altout = 1; 677 ++ft; 678 } 679 } 680 681 if (*ft || ft == cp + 1) 682 stderror(ERR_NAME | ERR_FILEINQ); 683 684 /* 685 * Detect missing file names by checking for operator in the file name 686 * position. However, if an operator name appears there, we must make 687 * sure that there's no file by that name (e.g., "/") before announcing 688 * an error. Even this check isn't quite right, since it doesn't take 689 * globbing into account. 690 */ 691 692 if (isa(**vp, ANYOP) && TCSH_STAT(short2str(**vp), &stb)) 693 stderror(ERR_NAME | ERR_FILENAME); 694 695 dp = *(*vp)++; 696 if (ignore & TEXP_IGNORE) 697 return (Strsave(STRNULL)); 698 ep = globone(dp, G_APPEND); 699 ft = &cp[1]; 700 do 701 switch (*ft) { 702 703 case 'r': 704 i = !sh_access(ep, R_OK); 705 break; 706 707 case 'w': 708 i = !sh_access(ep, W_OK); 709 break; 710 711 case 'x': 712 i = !sh_access(ep, X_OK); 713 break; 714 715 case 'X': /* tcsh extension, name is an executable in the path 716 * or a tcsh builtin command 717 */ 718 i = find_cmd(ep, 0); 719 break; 720 721 case 't': /* SGI extension, true when file is a tty */ 722 i = isatty(atoi(short2str(ep))); 723 break; 724 725 default: 726 727 #ifdef S_IFLNK 728 if (tolower(*ft) == 'l') { 729 /* 730 * avoid convex compiler bug. 731 */ 732 if (!lst) { 733 lst = &lstb; 734 if (TCSH_LSTAT(short2str(ep), lst) == -1) { 735 xfree((ptr_t) ep); 736 return (Strsave(errval)); 737 } 738 } 739 if (*ft == 'L') 740 st = lst; 741 } 742 else 743 #endif /* S_IFLNK */ 744 /* 745 * avoid convex compiler bug. 746 */ 747 if (!st) { 748 st = &stb; 749 if (TCSH_STAT(short2str(ep), st) == -1) { 750 xfree((ptr_t) ep); 751 return (Strsave(errval)); 752 } 753 } 754 755 switch (*ft) { 756 757 case 'f': 758 #ifdef S_ISREG 759 i = S_ISREG(st->st_mode); 760 #else /* !S_ISREG */ 761 i = 0; 762 #endif /* S_ISREG */ 763 break; 764 765 case 'd': 766 #ifdef S_ISDIR 767 i = S_ISDIR(st->st_mode); 768 #else /* !S_ISDIR */ 769 i = 0; 770 #endif /* S_ISDIR */ 771 break; 772 773 case 'p': 774 #ifdef S_ISFIFO 775 i = S_ISFIFO(st->st_mode); 776 #else /* !S_ISFIFO */ 777 i = 0; 778 #endif /* S_ISFIFO */ 779 break; 780 781 case 'm' : 782 #ifdef S_ISOFL 783 i = S_ISOFL(st->st_dm_mode); 784 #else /* !S_ISOFL */ 785 i = 0; 786 #endif /* S_ISOFL */ 787 break ; 788 789 case 'K' : 790 #ifdef S_ISOFL 791 i = stb.st_dm_key; 792 #else /* !S_ISOFL */ 793 i = 0; 794 #endif /* S_ISOFL */ 795 break ; 796 797 798 case 'l': 799 #ifdef S_ISLNK 800 i = S_ISLNK(lst->st_mode); 801 #else /* !S_ISLNK */ 802 i = 0; 803 #endif /* S_ISLNK */ 804 break; 805 806 case 'S': 807 # ifdef S_ISSOCK 808 i = S_ISSOCK(st->st_mode); 809 # else /* !S_ISSOCK */ 810 i = 0; 811 # endif /* S_ISSOCK */ 812 break; 813 814 case 'b': 815 #ifdef S_ISBLK 816 i = S_ISBLK(st->st_mode); 817 #else /* !S_ISBLK */ 818 i = 0; 819 #endif /* S_ISBLK */ 820 break; 821 822 case 'c': 823 #ifdef S_ISCHR 824 i = S_ISCHR(st->st_mode); 825 #else /* !S_ISCHR */ 826 i = 0; 827 #endif /* S_ISCHR */ 828 break; 829 830 case 'u': 831 i = (S_ISUID & st->st_mode) != 0; 832 break; 833 834 case 'g': 835 i = (S_ISGID & st->st_mode) != 0; 836 break; 837 838 case 'k': 839 i = (S_ISVTX & st->st_mode) != 0; 840 break; 841 842 case 'z': 843 i = st->st_size == 0; 844 break; 845 846 #ifdef convex 847 case 'R': 848 i = (stb.st_dmonflags & IMIGRATED) == IMIGRATED; 849 break; 850 #endif /* convex */ 851 852 case 's': 853 i = stb.st_size != 0; 854 break; 855 856 case 'e': 857 i = 1; 858 break; 859 860 case 'o': 861 i = st->st_uid == uid; 862 break; 863 864 /* 865 * Value operators are a tcsh extension. 866 */ 867 868 case 'D': 869 i = (int) st->st_dev; 870 break; 871 872 case 'I': 873 i = (int) st->st_ino; 874 break; 875 876 case 'F': 877 strdev = putn( (int) st->st_dev); 878 strino = putn( (int) st->st_ino); 879 strF = (Char *) xmalloc((size_t) (2 + Strlen(strdev) + 880 Strlen(strino)) * sizeof(Char)); 881 (void) Strcat(Strcat(Strcpy(strF, strdev), STRcolon), strino); 882 xfree((ptr_t) strdev); 883 xfree((ptr_t) strino); 884 xfree((ptr_t) ep); 885 return(strF); 886 887 case 'L': 888 if ( *(ft + 1) ) { 889 i = 1; 890 break; 891 } 892 #ifdef S_ISLNK 893 filnam = short2str(ep); 894 #ifdef PATH_MAX 895 # define MY_PATH_MAX PATH_MAX 896 #else /* !PATH_MAX */ 897 /* 898 * I can't think of any more sensible alterative; readlink doesn't give 899 * us an errno if the buffer isn't large enough :-( 900 */ 901 # define MY_PATH_MAX 2048 902 #endif /* PATH_MAX */ 903 i = readlink(filnam, string = (char *) 904 xmalloc((size_t) (1 + MY_PATH_MAX) * sizeof(char)), 905 MY_PATH_MAX); 906 if (i >= 0 && i <= MY_PATH_MAX) 907 string[i] = '\0'; /* readlink does not null terminate */ 908 strF = (i < 0) ? errval : str2short(string); 909 xfree((ptr_t) string); 910 xfree((ptr_t) ep); 911 return(Strsave(strF)); 912 913 #else /* !S_ISLNK */ 914 i = 0; 915 break; 916 #endif /* S_ISLNK */ 917 918 919 case 'N': 920 i = (int) st->st_nlink; 921 break; 922 923 case 'P': 924 string = string0 + 1; 925 (void) xsnprintf(string, sizeof(string0) - 1, "%o", 926 pmask & (unsigned int) 927 ((S_IRWXU|S_IRWXG|S_IRWXO|S_ISUID|S_ISGID) & st->st_mode)); 928 if (altout && *string != '0') 929 *--string = '0'; 930 xfree((ptr_t) ep); 931 return(Strsave(str2short(string))); 932 933 case 'U': 934 if (altout && (pw = getpwuid(st->st_uid))) { 935 xfree((ptr_t) ep); 936 return(Strsave(str2short(pw->pw_name))); 937 } 938 i = (int) st->st_uid; 939 break; 940 941 case 'G': 942 if ( altout && (gr = getgrgid(st->st_gid))) { 943 xfree((ptr_t) ep); 944 return(Strsave(str2short(gr->gr_name))); 945 } 946 i = (int) st->st_gid; 947 break; 948 949 case 'Z': 950 i = (int) st->st_size; 951 break; 952 953 case 'A': case 'M': case 'C': 954 footime = *ft == 'A' ? st->st_atime : 955 *ft == 'M' ? st->st_mtime : st->st_ctime; 956 if (altout) { 957 strF = str2short(ctime(&footime)); 958 if ((str = Strchr(strF, '\n')) != NULL) 959 *str = (Char) '\0'; 960 xfree((ptr_t) ep); 961 return(Strsave(strF)); 962 } 963 i = (int) footime; 964 break; 965 966 } 967 } 968 while (*++ft && i); 969 #ifdef EDEBUG 970 etraci("exp6 -? i", i, vp); 971 #endif /* EDEBUG */ 972 xfree((ptr_t) ep); 973 return (putn(i)); 974 } 975 976 977 static void 978 evalav(v) 979 Char **v; 980 { 981 struct wordent paraml1; 982 struct wordent *hp = ¶ml1; 983 struct command *t; 984 struct wordent *wdp = hp; 985 986 set(STRstatus, Strsave(STR0), VAR_READWRITE); 987 hp->prev = hp->next = hp; 988 hp->word = STRNULL; 989 while (*v) { 990 struct wordent *new = 991 (struct wordent *) xcalloc(1, sizeof *wdp); 992 993 new->prev = wdp; 994 new->next = hp; 995 wdp->next = new; 996 wdp = new; 997 wdp->word = Strsave(*v++); 998 } 999 hp->prev = wdp; 1000 alias(¶ml1); 1001 t = syntax(paraml1.next, ¶ml1, 0); 1002 if (seterr) 1003 stderror(ERR_OLD); 1004 execute(t, -1, NULL, NULL, TRUE); 1005 freelex(¶ml1), freesyn(t); 1006 } 1007 1008 static int 1009 isa(cp, what) 1010 Char *cp; 1011 int what; 1012 { 1013 if (cp == 0) 1014 return ((what & RESTOP) != 0); 1015 if (*cp == '\0') 1016 return 0; 1017 if (cp[1] == 0) { 1018 if (what & ADDOP && (*cp == '+' || *cp == '-')) 1019 return (1); 1020 if (what & MULOP && (*cp == '*' || *cp == '/' || *cp == '%')) 1021 return (1); 1022 if (what & RESTOP && (*cp == '(' || *cp == ')' || *cp == '!' || 1023 *cp == '~' || *cp == '^' || *cp == '"')) 1024 return (1); 1025 } 1026 else if (cp[2] == 0) { 1027 if (what & RESTOP) { 1028 if (cp[0] == '|' && cp[1] == '&') 1029 return (1); 1030 if (cp[0] == '<' && cp[1] == '<') 1031 return (1); 1032 if (cp[0] == '>' && cp[1] == '>') 1033 return (1); 1034 } 1035 if (what & EQOP) { 1036 if (cp[0] == '=') { 1037 if (cp[1] == '=') 1038 return (EQEQ); 1039 if (cp[1] == '~') 1040 return (EQMATCH); 1041 } 1042 else if (cp[0] == '!') { 1043 if (cp[1] == '=') 1044 return (NOTEQ); 1045 if (cp[1] == '~') 1046 return (NOTEQMATCH); 1047 } 1048 } 1049 } 1050 if (what & RELOP) { 1051 if (*cp == '<') 1052 return (LSS); 1053 if (*cp == '>') 1054 return (GTR); 1055 } 1056 return (0); 1057 } 1058 1059 static int 1060 egetn(cp) 1061 Char *cp; 1062 { 1063 if (*cp && *cp != '-' && !Isdigit(*cp)) 1064 stderror(ERR_NAME | ERR_EXPRESSION); 1065 return (getn(cp)); 1066 } 1067 1068 /* Phew! */ 1069 1070 #ifdef EDEBUG 1071 static void 1072 etraci(str, i, vp) 1073 char *str; 1074 int i; 1075 Char ***vp; 1076 { 1077 xprintf("%s=%d\t", str, i); 1078 blkpr(*vp); 1079 xputchar('\n'); 1080 } 1081 static void 1082 etracc(str, cp, vp) 1083 char *str; 1084 Char *cp; 1085 Char ***vp; 1086 { 1087 xprintf("%s=%s\t", str, cp); 1088 blkpr(*vp); 1089 xputchar('\n'); 1090 } 1091 #endif /* EDEBUG */ 1092