1 /* $Header: /src/pub/tcsh/sh.exp.c,v 3.40 2002/03/08 17:36:46 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.40 2002/03/08 17:36:46 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 ***, bool)); 62 static int exp2 __P((Char ***, bool)); 63 static int exp2a __P((Char ***, bool)); 64 static int exp2b __P((Char ***, bool)); 65 static int exp2c __P((Char ***, bool)); 66 static Char *exp3 __P((Char ***, bool)); 67 static Char *exp3a __P((Char ***, bool)); 68 static Char *exp4 __P((Char ***, bool)); 69 static Char *exp5 __P((Char ***, bool)); 70 static Char *exp6 __P((Char ***, bool)); 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 # if defined(__386BSD__) || defined(BSD4_4) 151 /* 152 * These two decided that setgroup() should take an array of int's 153 * and they define _SC_NGROUPS_MAX without having sysconf 154 */ 155 # undef _SC_NGROUPS_MAX 156 # if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__bsdi__) 157 # define GID_T gid_t 158 # else 159 # define GID_T int 160 # endif 161 # else 162 # define GID_T gid_t 163 # endif /* __386BSD__ || BSD4_4 */ 164 /* you can be in several groups */ 165 long n; 166 GID_T *groups; 167 168 /* 169 * Try these things to find a positive maximum groups value: 170 * 1) sysconf(_SC_NGROUPS_MAX) 171 * 2) NGROUPS_MAX 172 * 3) getgroups(0, unused) 173 * Then allocate and scan the groups array if one of these worked. 174 */ 175 # ifdef _SC_NGROUPS_MAX 176 if ((n = sysconf(_SC_NGROUPS_MAX)) == -1) 177 # endif /* _SC_NGROUPS_MAX */ 178 n = NGROUPS_MAX; 179 if (n <= 0) 180 n = getgroups(0, (GID_T *) NULL); 181 182 if (n > 0) { 183 groups = (GID_T *) xmalloc((size_t) (n * sizeof(GID_T))); 184 n = getgroups((int) n, groups); 185 while (--n >= 0) 186 if (groups[n] == statb.st_gid) { 187 mode <<= 3; 188 break; 189 } 190 } 191 } 192 # endif /* NGROUPS_MAX */ 193 194 if (statb.st_mode & mode) 195 return 0; 196 else 197 return 1; 198 #endif /* !POSIX */ 199 } 200 201 int 202 expr(vp) 203 register Char ***vp; 204 { 205 return (exp0(vp, 0)); 206 } 207 208 int 209 exp0(vp, ignore) 210 register Char ***vp; 211 bool ignore; 212 { 213 register int p1 = exp1(vp, ignore); 214 215 #ifdef EDEBUG 216 etraci("exp0 p1", p1, vp); 217 #endif /* EDEBUG */ 218 if (**vp && eq(**vp, STRor2)) { 219 register int p2; 220 221 (*vp)++; 222 p2 = exp0(vp, (ignore & TEXP_IGNORE) || p1); 223 #ifdef EDEBUG 224 etraci("exp0 p2", p2, vp); 225 #endif /* EDEBUG */ 226 return (p1 || p2); 227 } 228 return (p1); 229 } 230 231 static int 232 exp1(vp, ignore) 233 register Char ***vp; 234 bool ignore; 235 { 236 register int p1 = exp2(vp, ignore); 237 238 #ifdef EDEBUG 239 etraci("exp1 p1", p1, vp); 240 #endif /* EDEBUG */ 241 if (**vp && eq(**vp, STRand2)) { 242 register int p2; 243 244 (*vp)++; 245 p2 = exp1(vp, (ignore & TEXP_IGNORE) || !p1); 246 #ifdef EDEBUG 247 etraci("exp1 p2", p2, vp); 248 #endif /* EDEBUG */ 249 return (p1 && p2); 250 } 251 return (p1); 252 } 253 254 static int 255 exp2(vp, ignore) 256 register Char ***vp; 257 bool ignore; 258 { 259 register int p1 = exp2a(vp, ignore); 260 261 #ifdef EDEBUG 262 etraci("exp3 p1", p1, vp); 263 #endif /* EDEBUG */ 264 if (**vp && eq(**vp, STRor)) { 265 register int p2; 266 267 (*vp)++; 268 p2 = exp2(vp, ignore); 269 #ifdef EDEBUG 270 etraci("exp3 p2", p2, vp); 271 #endif /* EDEBUG */ 272 return (p1 | p2); 273 } 274 return (p1); 275 } 276 277 static int 278 exp2a(vp, ignore) 279 register Char ***vp; 280 bool ignore; 281 { 282 register int p1 = exp2b(vp, ignore); 283 284 #ifdef EDEBUG 285 etraci("exp2a p1", p1, vp); 286 #endif /* EDEBUG */ 287 if (**vp && eq(**vp, STRcaret)) { 288 register int p2; 289 290 (*vp)++; 291 p2 = exp2a(vp, ignore); 292 #ifdef EDEBUG 293 etraci("exp2a p2", p2, vp); 294 #endif /* EDEBUG */ 295 return (p1 ^ p2); 296 } 297 return (p1); 298 } 299 300 static int 301 exp2b(vp, ignore) 302 register Char ***vp; 303 bool ignore; 304 { 305 register int p1 = exp2c(vp, ignore); 306 307 #ifdef EDEBUG 308 etraci("exp2b p1", p1, vp); 309 #endif /* EDEBUG */ 310 if (**vp && eq(**vp, STRand)) { 311 register int p2; 312 313 (*vp)++; 314 p2 = exp2b(vp, ignore); 315 #ifdef EDEBUG 316 etraci("exp2b p2", p2, vp); 317 #endif /* EDEBUG */ 318 return (p1 & p2); 319 } 320 return (p1); 321 } 322 323 static int 324 exp2c(vp, ignore) 325 register Char ***vp; 326 bool ignore; 327 { 328 register Char *p1 = exp3(vp, ignore); 329 register Char *p2; 330 register int i; 331 332 #ifdef EDEBUG 333 etracc("exp2c p1", p1, vp); 334 #endif /* EDEBUG */ 335 if ((i = isa(**vp, EQOP)) != 0) { 336 (*vp)++; 337 if (i == EQMATCH || i == NOTEQMATCH) 338 ignore |= TEXP_NOGLOB; 339 p2 = exp3(vp, ignore); 340 #ifdef EDEBUG 341 etracc("exp2c p2", p2, vp); 342 #endif /* EDEBUG */ 343 if (!(ignore & TEXP_IGNORE)) 344 switch (i) { 345 346 case EQEQ: 347 i = eq(p1, p2); 348 break; 349 350 case NOTEQ: 351 i = !eq(p1, p2); 352 break; 353 354 case EQMATCH: 355 i = Gmatch(p1, p2); 356 break; 357 358 case NOTEQMATCH: 359 i = !Gmatch(p1, p2); 360 break; 361 } 362 xfree((ptr_t) p1); 363 xfree((ptr_t) p2); 364 return (i); 365 } 366 i = egetn(p1); 367 xfree((ptr_t) p1); 368 return (i); 369 } 370 371 static Char * 372 exp3(vp, ignore) 373 register Char ***vp; 374 bool ignore; 375 { 376 register Char *p1, *p2; 377 register int i; 378 379 p1 = exp3a(vp, ignore); 380 #ifdef EDEBUG 381 etracc("exp3 p1", p1, vp); 382 #endif /* EDEBUG */ 383 if ((i = isa(**vp, RELOP)) != 0) { 384 (*vp)++; 385 if (**vp && eq(**vp, STRequal)) 386 i |= 1, (*vp)++; 387 p2 = exp3(vp, ignore); 388 #ifdef EDEBUG 389 etracc("exp3 p2", p2, vp); 390 #endif /* EDEBUG */ 391 if (!(ignore & TEXP_IGNORE)) 392 switch (i) { 393 394 case GTR: 395 i = egetn(p1) > egetn(p2); 396 break; 397 398 case GTR | 1: 399 i = egetn(p1) >= egetn(p2); 400 break; 401 402 case LSS: 403 i = egetn(p1) < egetn(p2); 404 break; 405 406 case LSS | 1: 407 i = egetn(p1) <= egetn(p2); 408 break; 409 } 410 xfree((ptr_t) p1); 411 xfree((ptr_t) p2); 412 return (putn(i)); 413 } 414 return (p1); 415 } 416 417 static Char * 418 exp3a(vp, ignore) 419 register Char ***vp; 420 bool ignore; 421 { 422 register Char *p1, *p2, *op; 423 register int i; 424 425 p1 = exp4(vp, ignore); 426 #ifdef EDEBUG 427 etracc("exp3a p1", p1, vp); 428 #endif /* EDEBUG */ 429 op = **vp; 430 if (op && any("<>", op[0]) && op[0] == op[1]) { 431 (*vp)++; 432 p2 = exp3a(vp, ignore); 433 #ifdef EDEBUG 434 etracc("exp3a p2", p2, vp); 435 #endif /* EDEBUG */ 436 if (op[0] == '<') 437 i = egetn(p1) << egetn(p2); 438 else 439 i = egetn(p1) >> egetn(p2); 440 xfree((ptr_t) p1); 441 xfree((ptr_t) p2); 442 return (putn(i)); 443 } 444 return (p1); 445 } 446 447 static Char * 448 exp4(vp, ignore) 449 register Char ***vp; 450 bool ignore; 451 { 452 register Char *p1, *p2; 453 register int i = 0; 454 455 p1 = exp5(vp, ignore); 456 #ifdef EDEBUG 457 etracc("exp4 p1", p1, vp); 458 #endif /* EDEBUG */ 459 if (isa(**vp, ADDOP)) { 460 register Char *op = *(*vp)++; 461 462 p2 = exp4(vp, ignore); 463 #ifdef EDEBUG 464 etracc("exp4 p2", p2, vp); 465 #endif /* EDEBUG */ 466 if (!(ignore & TEXP_IGNORE)) 467 switch (op[0]) { 468 469 case '+': 470 i = egetn(p1) + egetn(p2); 471 break; 472 473 case '-': 474 i = egetn(p1) - egetn(p2); 475 break; 476 } 477 xfree((ptr_t) p1); 478 xfree((ptr_t) p2); 479 return (putn(i)); 480 } 481 return (p1); 482 } 483 484 static Char * 485 exp5(vp, ignore) 486 register Char ***vp; 487 bool ignore; 488 { 489 register Char *p1, *p2; 490 register int i = 0; 491 492 p1 = exp6(vp, ignore); 493 #ifdef EDEBUG 494 etracc("exp5 p1", p1, vp); 495 #endif /* EDEBUG */ 496 497 if (isa(**vp, MULOP)) { 498 register Char *op = *(*vp)++; 499 if ((ignore & TEXP_NOGLOB) != 0) 500 /* 501 * We are just trying to get the right side of 502 * a =~ or !~ operator 503 */ 504 return Strsave(op); 505 506 p2 = exp5(vp, ignore); 507 #ifdef EDEBUG 508 etracc("exp5 p2", p2, vp); 509 #endif /* EDEBUG */ 510 if (!(ignore & TEXP_IGNORE)) 511 switch (op[0]) { 512 513 case '*': 514 i = egetn(p1) * egetn(p2); 515 break; 516 517 case '/': 518 i = egetn(p2); 519 if (i == 0) 520 stderror(ERR_DIV0); 521 i = egetn(p1) / i; 522 break; 523 524 case '%': 525 i = egetn(p2); 526 if (i == 0) 527 stderror(ERR_MOD0); 528 i = egetn(p1) % i; 529 break; 530 } 531 xfree((ptr_t) p1); 532 xfree((ptr_t) p2); 533 return (putn(i)); 534 } 535 return (p1); 536 } 537 538 static Char * 539 exp6(vp, ignore) 540 register Char ***vp; 541 bool ignore; 542 { 543 int ccode, i = 0; 544 register Char *cp; 545 546 if (**vp == 0) 547 stderror(ERR_NAME | ERR_EXPRESSION); 548 if (eq(**vp, STRbang)) { 549 (*vp)++; 550 cp = exp6(vp, ignore); 551 #ifdef EDEBUG 552 etracc("exp6 ! cp", cp, vp); 553 #endif /* EDEBUG */ 554 i = egetn(cp); 555 xfree((ptr_t) cp); 556 return (putn(!i)); 557 } 558 if (eq(**vp, STRtilde)) { 559 (*vp)++; 560 cp = exp6(vp, ignore); 561 #ifdef EDEBUG 562 etracc("exp6 ~ cp", cp, vp); 563 #endif /* EDEBUG */ 564 i = egetn(cp); 565 xfree((ptr_t) cp); 566 return (putn(~i)); 567 } 568 if (eq(**vp, STRLparen)) { 569 (*vp)++; 570 ccode = exp0(vp, ignore); 571 #ifdef EDEBUG 572 etraci("exp6 () ccode", ccode, vp); 573 #endif /* EDEBUG */ 574 if (*vp == 0 || **vp == 0 || ***vp != ')') 575 stderror(ERR_NAME | ERR_EXPRESSION); 576 (*vp)++; 577 return (putn(ccode)); 578 } 579 if (eq(**vp, STRLbrace)) { 580 register Char **v; 581 struct command faket; 582 Char *fakecom[2]; 583 584 faket.t_dtyp = NODE_COMMAND; 585 faket.t_dflg = F_BACKQ; 586 faket.t_dcar = faket.t_dcdr = faket.t_dspr = NULL; 587 faket.t_dcom = fakecom; 588 fakecom[0] = STRfakecom; 589 fakecom[1] = NULL; 590 (*vp)++; 591 v = *vp; 592 for (;;) { 593 if (!**vp) 594 stderror(ERR_NAME | ERR_MISSING, '}'); 595 if (eq(*(*vp)++, STRRbrace)) 596 break; 597 } 598 if (ignore & TEXP_IGNORE) 599 return (Strsave(STRNULL)); 600 psavejob(); 601 if (pfork(&faket, -1) == 0) { 602 *--(*vp) = 0; 603 evalav(v); 604 exitstat(); 605 } 606 pwait(); 607 prestjob(); 608 #ifdef EDEBUG 609 etraci("exp6 {} status", egetn(varval(STRstatus)), vp); 610 #endif /* EDEBUG */ 611 return (putn(egetn(varval(STRstatus)) == 0)); 612 } 613 if (isa(**vp, ANYOP)) 614 return (Strsave(STRNULL)); 615 cp = *(*vp)++; 616 #ifdef convex 617 # define FILETESTS "erwxfdzoplstSXLbcugkmKR" 618 #else 619 # define FILETESTS "erwxfdzoplstSXLbcugkmK" 620 #endif /* convex */ 621 #define FILEVALS "ZAMCDIUGNFPL" 622 if (*cp == '-' && (any(FILETESTS, cp[1]) || any(FILEVALS, cp[1]))) 623 return(filetest(cp, vp, ignore)); 624 #ifdef EDEBUG 625 etracc("exp6 default", cp, vp); 626 #endif /* EDEBUG */ 627 return (ignore & TEXP_NOGLOB ? Strsave(cp) : globone(cp, G_APPEND)); 628 } 629 630 631 /* 632 * Extended file tests 633 * From: John Rowe <rowe@excc.exeter.ac.uk> 634 */ 635 Char * 636 filetest(cp, vp, ignore) 637 Char *cp, ***vp; 638 bool ignore; 639 { 640 #ifdef convex 641 struct cvxstat stb, *st = NULL; 642 # define TCSH_STAT stat64 643 #else 644 # define TCSH_STAT stat 645 struct stat stb, *st = NULL; 646 #endif /* convex */ 647 648 #ifdef S_IFLNK 649 # ifdef convex 650 struct cvxstat lstb, *lst = NULL; 651 # define TCSH_LSTAT lstat64 652 # else 653 # define TCSH_LSTAT lstat 654 struct stat lstb, *lst = NULL; 655 # endif /* convex */ 656 char *filnam; 657 #endif /* S_IFLNK */ 658 659 int i = 0; 660 unsigned pmask = 0xffff; 661 bool altout = 0; 662 Char *ft = cp, *dp, *ep, *strdev, *strino, *strF, *str, valtest = '\0', 663 *errval = STR0; 664 char *string, string0[8]; 665 time_t footime; 666 struct passwd *pw; 667 struct group *gr; 668 669 while(any(FILETESTS, *++ft)) 670 continue; 671 672 if (!*ft && *(ft - 1) == 'L') 673 --ft; 674 675 if (any(FILEVALS, *ft)) { 676 valtest = *ft++; 677 /* 678 * Value tests return '-1' on failure as 0 is 679 * a legitimate value for many of them. 680 * 'F' returns ':' for compatibility. 681 */ 682 errval = valtest == 'F' ? STRcolon : STRminus1; 683 684 if (valtest == 'P' && *ft >= '0' && *ft <= '7') { 685 pmask = (char) *ft - '0'; 686 while ( *++ft >= '0' && *ft <= '7' ) 687 pmask = 8 * pmask + ((char) *ft - '0'); 688 } 689 if (Strcmp(ft, STRcolon) == 0 && any("AMCUGP", valtest)) { 690 altout = 1; 691 ++ft; 692 } 693 } 694 695 if (*ft || ft == cp + 1) 696 stderror(ERR_NAME | ERR_FILEINQ); 697 698 /* 699 * Detect missing file names by checking for operator in the file name 700 * position. However, if an operator name appears there, we must make 701 * sure that there's no file by that name (e.g., "/") before announcing 702 * an error. Even this check isn't quite right, since it doesn't take 703 * globbing into account. 704 */ 705 706 if (isa(**vp, ANYOP) && TCSH_STAT(short2str(**vp), &stb)) 707 stderror(ERR_NAME | ERR_FILENAME); 708 709 dp = *(*vp)++; 710 if (ignore & TEXP_IGNORE) 711 return (Strsave(STRNULL)); 712 ep = globone(dp, G_APPEND); 713 ft = &cp[1]; 714 do 715 switch (*ft) { 716 717 case 'r': 718 i = !sh_access(ep, R_OK); 719 break; 720 721 case 'w': 722 i = !sh_access(ep, W_OK); 723 break; 724 725 case 'x': 726 i = !sh_access(ep, X_OK); 727 break; 728 729 case 'X': /* tcsh extension, name is an executable in the path 730 * or a tcsh builtin command 731 */ 732 i = find_cmd(ep, 0); 733 break; 734 735 case 't': /* SGI extension, true when file is a tty */ 736 i = isatty(atoi(short2str(ep))); 737 break; 738 739 default: 740 741 #ifdef S_IFLNK 742 if (tolower(*ft) == 'l') { 743 /* 744 * avoid convex compiler bug. 745 */ 746 if (!lst) { 747 lst = &lstb; 748 if (TCSH_LSTAT(short2str(ep), lst) == -1) { 749 xfree((ptr_t) ep); 750 return (Strsave(errval)); 751 } 752 } 753 if (*ft == 'L') 754 st = lst; 755 } 756 else 757 #endif /* S_IFLNK */ 758 /* 759 * avoid convex compiler bug. 760 */ 761 if (!st) { 762 st = &stb; 763 if (TCSH_STAT(short2str(ep), st) == -1) { 764 xfree((ptr_t) ep); 765 return (Strsave(errval)); 766 } 767 } 768 769 switch (*ft) { 770 771 case 'f': 772 #ifdef S_ISREG 773 i = S_ISREG(st->st_mode); 774 #else /* !S_ISREG */ 775 i = 0; 776 #endif /* S_ISREG */ 777 break; 778 779 case 'd': 780 #ifdef S_ISDIR 781 i = S_ISDIR(st->st_mode); 782 #else /* !S_ISDIR */ 783 i = 0; 784 #endif /* S_ISDIR */ 785 break; 786 787 case 'p': 788 #ifdef S_ISFIFO 789 i = S_ISFIFO(st->st_mode); 790 #else /* !S_ISFIFO */ 791 i = 0; 792 #endif /* S_ISFIFO */ 793 break; 794 795 case 'm' : 796 #ifdef S_ISOFL 797 i = S_ISOFL(st->st_dm_mode); 798 #else /* !S_ISOFL */ 799 i = 0; 800 #endif /* S_ISOFL */ 801 break ; 802 803 case 'K' : 804 #ifdef S_ISOFL 805 i = stb.st_dm_key; 806 #else /* !S_ISOFL */ 807 i = 0; 808 #endif /* S_ISOFL */ 809 break ; 810 811 812 case 'l': 813 #ifdef S_ISLNK 814 i = S_ISLNK(lst->st_mode); 815 #else /* !S_ISLNK */ 816 i = 0; 817 #endif /* S_ISLNK */ 818 break; 819 820 case 'S': 821 # ifdef S_ISSOCK 822 i = S_ISSOCK(st->st_mode); 823 # else /* !S_ISSOCK */ 824 i = 0; 825 # endif /* S_ISSOCK */ 826 break; 827 828 case 'b': 829 #ifdef S_ISBLK 830 i = S_ISBLK(st->st_mode); 831 #else /* !S_ISBLK */ 832 i = 0; 833 #endif /* S_ISBLK */ 834 break; 835 836 case 'c': 837 #ifdef S_ISCHR 838 i = S_ISCHR(st->st_mode); 839 #else /* !S_ISCHR */ 840 i = 0; 841 #endif /* S_ISCHR */ 842 break; 843 844 case 'u': 845 i = (S_ISUID & st->st_mode) != 0; 846 break; 847 848 case 'g': 849 i = (S_ISGID & st->st_mode) != 0; 850 break; 851 852 case 'k': 853 i = (S_ISVTX & st->st_mode) != 0; 854 break; 855 856 case 'z': 857 i = st->st_size == 0; 858 break; 859 860 #ifdef convex 861 case 'R': 862 i = (stb.st_dmonflags & IMIGRATED) == IMIGRATED; 863 break; 864 #endif /* convex */ 865 866 case 's': 867 i = stb.st_size != 0; 868 break; 869 870 case 'e': 871 i = 1; 872 break; 873 874 case 'o': 875 i = st->st_uid == uid; 876 break; 877 878 /* 879 * Value operators are a tcsh extension. 880 */ 881 882 case 'D': 883 i = (int) st->st_dev; 884 break; 885 886 case 'I': 887 i = (int) st->st_ino; 888 break; 889 890 case 'F': 891 strdev = putn( (int) st->st_dev); 892 strino = putn( (int) st->st_ino); 893 strF = (Char *) xmalloc((size_t) (2 + Strlen(strdev) + 894 Strlen(strino)) * sizeof(Char)); 895 (void) Strcat(Strcat(Strcpy(strF, strdev), STRcolon), strino); 896 xfree((ptr_t) strdev); 897 xfree((ptr_t) strino); 898 xfree((ptr_t) ep); 899 return(strF); 900 901 case 'L': 902 if ( *(ft + 1) ) { 903 i = 1; 904 break; 905 } 906 #ifdef S_ISLNK 907 filnam = short2str(ep); 908 #ifdef PATH_MAX 909 # define MY_PATH_MAX PATH_MAX 910 #else /* !PATH_MAX */ 911 /* 912 * I can't think of any more sensible alterative; readlink doesn't give 913 * us an errno if the buffer isn't large enough :-( 914 */ 915 # define MY_PATH_MAX 2048 916 #endif /* PATH_MAX */ 917 i = readlink(filnam, string = (char *) 918 xmalloc((size_t) (1 + MY_PATH_MAX) * sizeof(char)), 919 MY_PATH_MAX); 920 if (i >= 0 && i <= MY_PATH_MAX) 921 string[i] = '\0'; /* readlink does not null terminate */ 922 strF = (i < 0) ? errval : str2short(string); 923 xfree((ptr_t) string); 924 xfree((ptr_t) ep); 925 return(Strsave(strF)); 926 927 #else /* !S_ISLNK */ 928 i = 0; 929 break; 930 #endif /* S_ISLNK */ 931 932 933 case 'N': 934 i = (int) st->st_nlink; 935 break; 936 937 case 'P': 938 string = string0 + 1; 939 (void) xsnprintf(string, sizeof(string0) - 1, "%o", 940 pmask & (unsigned int) 941 ((S_IRWXU|S_IRWXG|S_IRWXO|S_ISUID|S_ISGID) & st->st_mode)); 942 if (altout && *string != '0') 943 *--string = '0'; 944 xfree((ptr_t) ep); 945 return(Strsave(str2short(string))); 946 947 case 'U': 948 if (altout && (pw = getpwuid(st->st_uid))) { 949 xfree((ptr_t) ep); 950 return(Strsave(str2short(pw->pw_name))); 951 } 952 i = (int) st->st_uid; 953 break; 954 955 case 'G': 956 if ( altout && (gr = getgrgid(st->st_gid))) { 957 xfree((ptr_t) ep); 958 return(Strsave(str2short(gr->gr_name))); 959 } 960 i = (int) st->st_gid; 961 break; 962 963 case 'Z': 964 i = (int) st->st_size; 965 break; 966 967 case 'A': case 'M': case 'C': 968 footime = *ft == 'A' ? st->st_atime : 969 *ft == 'M' ? st->st_mtime : st->st_ctime; 970 if (altout) { 971 strF = str2short(ctime(&footime)); 972 if ((str = Strchr(strF, '\n')) != NULL) 973 *str = (Char) '\0'; 974 xfree((ptr_t) ep); 975 return(Strsave(strF)); 976 } 977 i = (int) footime; 978 break; 979 980 } 981 } 982 while (*++ft && i); 983 #ifdef EDEBUG 984 etraci("exp6 -? i", i, vp); 985 #endif /* EDEBUG */ 986 xfree((ptr_t) ep); 987 return (putn(i)); 988 } 989 990 991 static void 992 evalav(v) 993 register Char **v; 994 { 995 struct wordent paraml1; 996 register struct wordent *hp = ¶ml1; 997 struct command *t; 998 register struct wordent *wdp = hp; 999 1000 set(STRstatus, Strsave(STR0), VAR_READWRITE); 1001 hp->prev = hp->next = hp; 1002 hp->word = STRNULL; 1003 while (*v) { 1004 register struct wordent *new = 1005 (struct wordent *) xcalloc(1, sizeof *wdp); 1006 1007 new->prev = wdp; 1008 new->next = hp; 1009 wdp->next = new; 1010 wdp = new; 1011 wdp->word = Strsave(*v++); 1012 } 1013 hp->prev = wdp; 1014 alias(¶ml1); 1015 t = syntax(paraml1.next, ¶ml1, 0); 1016 if (seterr) 1017 stderror(ERR_OLD); 1018 execute(t, -1, NULL, NULL, TRUE); 1019 freelex(¶ml1), freesyn(t); 1020 } 1021 1022 static int 1023 isa(cp, what) 1024 register Char *cp; 1025 register int what; 1026 { 1027 if (cp == 0) 1028 return ((what & RESTOP) != 0); 1029 if (*cp == '\0') 1030 return 0; 1031 if (cp[1] == 0) { 1032 if (what & ADDOP && (*cp == '+' || *cp == '-')) 1033 return (1); 1034 if (what & MULOP && (*cp == '*' || *cp == '/' || *cp == '%')) 1035 return (1); 1036 if (what & RESTOP && (*cp == '(' || *cp == ')' || *cp == '!' || 1037 *cp == '~' || *cp == '^' || *cp == '"')) 1038 return (1); 1039 } 1040 else if (cp[2] == 0) { 1041 if (what & RESTOP) { 1042 if (cp[0] == '|' && cp[1] == '&') 1043 return (1); 1044 if (cp[0] == '<' && cp[1] == '<') 1045 return (1); 1046 if (cp[0] == '>' && cp[1] == '>') 1047 return (1); 1048 } 1049 if (what & EQOP) { 1050 if (cp[0] == '=') { 1051 if (cp[1] == '=') 1052 return (EQEQ); 1053 if (cp[1] == '~') 1054 return (EQMATCH); 1055 } 1056 else if (cp[0] == '!') { 1057 if (cp[1] == '=') 1058 return (NOTEQ); 1059 if (cp[1] == '~') 1060 return (NOTEQMATCH); 1061 } 1062 } 1063 } 1064 if (what & RELOP) { 1065 if (*cp == '<') 1066 return (LSS); 1067 if (*cp == '>') 1068 return (GTR); 1069 } 1070 return (0); 1071 } 1072 1073 static int 1074 egetn(cp) 1075 register Char *cp; 1076 { 1077 if (*cp && *cp != '-' && !Isdigit(*cp)) 1078 stderror(ERR_NAME | ERR_EXPRESSION); 1079 return (getn(cp)); 1080 } 1081 1082 /* Phew! */ 1083 1084 #ifdef EDEBUG 1085 static void 1086 etraci(str, i, vp) 1087 char *str; 1088 int i; 1089 Char ***vp; 1090 { 1091 xprintf("%s=%d\t", str, i); 1092 blkpr(*vp); 1093 xputchar('\n'); 1094 } 1095 static void 1096 etracc(str, cp, vp) 1097 char *str; 1098 Char *cp; 1099 Char ***vp; 1100 { 1101 xprintf("%s=%s\t", str, cp); 1102 blkpr(*vp); 1103 xputchar('\n'); 1104 } 1105 #endif /* EDEBUG */ 1106