1/* $NetBSD: exp.c,v 1.19 2007/07/16 18:26:10 christos 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 35static char sccsid[] = "@(#)exp.c 8.1 (Berkeley) 5/31/93"; 36#else 37__RCSID("$NetBSD: exp.c,v 1.19 2007/07/16 18:26:10 christos 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 72static int exp1(Char ***, int); 73static int csh_exp2(Char ***, int); 74static int exp2a(Char ***, int); 75static int exp2b(Char ***, int); 76static int exp2c(Char ***, int); 77static Char *exp3(Char ***, int); 78static Char *exp3a(Char ***, int); 79static Char *exp4(Char ***, int); 80static Char *exp5(Char ***, int); 81static Char *exp6(Char ***, int); 82static void evalav(Char **); 83static int isa(Char *, int); 84static int egetn(Char *); 85 86#ifdef EDEBUG 87static void etracc(char *, Char *, Char ***); 88static void etraci(char *, int, Char ***); 89#endif 90 91int 92expr(Char ***vp) 93{ 94 return (exp0(vp, 0)); 95} 96 97int 98exp0(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 119static int 120exp1(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 141static int 142csh_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 163static int 164exp2a(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 185static int 186exp2b(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 207static int 208exp2c(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 249static Char * 250exp3(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 289static Char * 290exp3a(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 317static Char * 318exp4(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 352static Char * 353exp5(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 396static Char * 397exp6(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 559static void 560evalav(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 589static int 590isa(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 636static int 637egetn(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 647static void 648etraci(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} 654static void 655etracc(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