1 /* $OpenBSD: exp.c,v 1.14 2015/10/26 21:57:42 naddy 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 #include <stdarg.h> 39 40 #include "csh.h" 41 #include "extern.h" 42 43 #define IGNORE 1 /* in ignore, it means to ignore value, just parse */ 44 #define 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 exp1(Char ***, bool); 61 static int exp2_(Char ***, bool); 62 static int exp2a(Char ***, bool); 63 static int exp2b(Char ***, bool); 64 static int exp2c(Char ***, bool); 65 static Char * exp3(Char ***, bool); 66 static Char * exp3a(Char ***, bool); 67 static Char * exp4(Char ***, bool); 68 static Char * exp5(Char ***, bool); 69 static Char * exp6(Char ***, bool); 70 static void evalav(Char **); 71 static int isa(Char *, int); 72 static int egetn(Char *); 73 74 int 75 expr(Char ***vp) 76 { 77 return (exp0(vp, 0)); 78 } 79 80 int 81 exp0(Char ***vp, bool ignore) 82 { 83 int p1 = exp1(vp, ignore); 84 85 if (**vp && eq(**vp, STRor2)) { 86 int p2; 87 88 (*vp)++; 89 p2 = exp0(vp, (ignore & IGNORE) || p1); 90 return (p1 || p2); 91 } 92 return (p1); 93 } 94 95 static int 96 exp1(Char ***vp, bool ignore) 97 { 98 int p1 = exp2_(vp, ignore); 99 100 if (**vp && eq(**vp, STRand2)) { 101 int p2; 102 103 (*vp)++; 104 p2 = exp1(vp, (ignore & IGNORE) || !p1); 105 return (p1 && p2); 106 } 107 return (p1); 108 } 109 110 static int 111 exp2_(Char ***vp, bool ignore) 112 { 113 int p1 = exp2a(vp, ignore); 114 115 if (**vp && eq(**vp, STRor)) { 116 int p2; 117 118 (*vp)++; 119 p2 = exp2_(vp, ignore); 120 return (p1 | p2); 121 } 122 return (p1); 123 } 124 125 static int 126 exp2a(Char ***vp, bool ignore) 127 { 128 int p1 = exp2b(vp, ignore); 129 130 if (**vp && eq(**vp, STRcaret)) { 131 int p2; 132 133 (*vp)++; 134 p2 = exp2a(vp, ignore); 135 return (p1 ^ p2); 136 } 137 return (p1); 138 } 139 140 static int 141 exp2b(Char ***vp, bool ignore) 142 { 143 int p1 = exp2c(vp, ignore); 144 145 if (**vp && eq(**vp, STRand)) { 146 int p2; 147 148 (*vp)++; 149 p2 = exp2b(vp, ignore); 150 return (p1 & p2); 151 } 152 return (p1); 153 } 154 155 static int 156 exp2c(Char ***vp, bool ignore) 157 { 158 Char *p1 = exp3(vp, ignore); 159 Char *p2; 160 int i; 161 162 if ((i = isa(**vp, EQOP)) != 0) { 163 (*vp)++; 164 if (i == EQMATCH || i == NOTEQMATCH) 165 ignore |= NOGLOB; 166 p2 = exp3(vp, ignore); 167 if (!(ignore & IGNORE)) 168 switch (i) { 169 170 case EQEQ: 171 i = eq(p1, p2); 172 break; 173 174 case NOTEQ: 175 i = !eq(p1, p2); 176 break; 177 178 case EQMATCH: 179 i = Gmatch(p1, p2); 180 break; 181 182 case NOTEQMATCH: 183 i = !Gmatch(p1, p2); 184 break; 185 } 186 xfree(p1); 187 xfree(p2); 188 return (i); 189 } 190 i = egetn(p1); 191 xfree(p1); 192 return (i); 193 } 194 195 static Char * 196 exp3(Char ***vp, bool ignore) 197 { 198 Char *p1, *p2; 199 int i; 200 201 p1 = exp3a(vp, ignore); 202 if ((i = isa(**vp, RELOP)) != 0) { 203 (*vp)++; 204 if (**vp && eq(**vp, STRequal)) 205 i |= 1, (*vp)++; 206 p2 = exp3(vp, ignore); 207 if (!(ignore & IGNORE)) 208 switch (i) { 209 210 case GTR: 211 i = egetn(p1) > egetn(p2); 212 break; 213 214 case GTR | 1: 215 i = egetn(p1) >= egetn(p2); 216 break; 217 218 case LSS: 219 i = egetn(p1) < egetn(p2); 220 break; 221 222 case LSS | 1: 223 i = egetn(p1) <= egetn(p2); 224 break; 225 } 226 xfree(p1); 227 xfree(p2); 228 return (putn(i)); 229 } 230 return (p1); 231 } 232 233 static Char * 234 exp3a(Char ***vp, bool ignore) 235 { 236 Char *p1, *p2, *op; 237 int i; 238 239 p1 = exp4(vp, ignore); 240 op = **vp; 241 if (op && any("<>", op[0]) && op[0] == op[1]) { 242 (*vp)++; 243 p2 = exp3a(vp, ignore); 244 if (op[0] == '<') 245 i = egetn(p1) << egetn(p2); 246 else 247 i = egetn(p1) >> egetn(p2); 248 xfree(p1); 249 xfree(p2); 250 return (putn(i)); 251 } 252 return (p1); 253 } 254 255 static Char * 256 exp4(Char ***vp, bool ignore) 257 { 258 Char *p1, *p2; 259 int i = 0; 260 261 p1 = exp5(vp, ignore); 262 if (isa(**vp, ADDOP)) { 263 Char *op = *(*vp)++; 264 265 p2 = exp4(vp, ignore); 266 if (!(ignore & IGNORE)) 267 switch (op[0]) { 268 269 case '+': 270 i = egetn(p1) + egetn(p2); 271 break; 272 273 case '-': 274 i = egetn(p1) - egetn(p2); 275 break; 276 } 277 xfree(p1); 278 xfree(p2); 279 return (putn(i)); 280 } 281 return (p1); 282 } 283 284 static Char * 285 exp5(Char ***vp, bool ignore) 286 { 287 Char *p1, *p2; 288 int i = 0, l; 289 290 p1 = exp6(vp, ignore); 291 if (isa(**vp, MULOP)) { 292 Char *op = *(*vp)++; 293 294 p2 = exp5(vp, ignore); 295 if (!(ignore & IGNORE)) 296 switch (op[0]) { 297 298 case '*': 299 i = egetn(p1) * egetn(p2); 300 break; 301 302 case '/': 303 i = egetn(p2); 304 if (i == 0) 305 stderror(ERR_DIV0); 306 l = egetn(p1); 307 if (l == INT_MIN && i == -1) 308 i = INT_MIN; 309 else 310 i = l / i; 311 break; 312 313 case '%': 314 i = egetn(p2); 315 if (i == 0) 316 stderror(ERR_MOD0); 317 l = egetn(p1); 318 if (l == INT_MIN && i == -1) 319 i = 0; 320 else 321 i = l % i; 322 break; 323 } 324 xfree(p1); 325 xfree(p2); 326 return (putn(i)); 327 } 328 return (p1); 329 } 330 331 static Char * 332 exp6(Char ***vp, bool ignore) 333 { 334 int ccode, i = 0; 335 Char *cp, *dp, *ep; 336 337 if (**vp == 0) 338 stderror(ERR_NAME | ERR_EXPRESSION); 339 if (eq(**vp, STRbang)) { 340 (*vp)++; 341 cp = exp6(vp, ignore); 342 i = egetn(cp); 343 xfree(cp); 344 return (putn(!i)); 345 } 346 if (eq(**vp, STRtilde)) { 347 (*vp)++; 348 cp = exp6(vp, ignore); 349 i = egetn(cp); 350 xfree(cp); 351 return (putn(~i)); 352 } 353 if (eq(**vp, STRLparen)) { 354 (*vp)++; 355 ccode = exp0(vp, ignore); 356 if (*vp == 0 || **vp == 0 || ***vp != ')') 357 stderror(ERR_NAME | ERR_EXPRESSION); 358 (*vp)++; 359 return (putn(ccode)); 360 } 361 if (eq(**vp, STRLbrace)) { 362 Char **v; 363 struct command faket; 364 Char *fakecom[2]; 365 366 faket.t_dtyp = NODE_COMMAND; 367 faket.t_dflg = 0; 368 faket.t_dcar = faket.t_dcdr = faket.t_dspr = NULL; 369 faket.t_dcom = fakecom; 370 fakecom[0] = STRfakecom; 371 fakecom[1] = NULL; 372 (*vp)++; 373 v = *vp; 374 for (;;) { 375 if (!**vp) 376 stderror(ERR_NAME | ERR_MISSING, '}'); 377 if (eq(*(*vp)++, STRRbrace)) 378 break; 379 } 380 if (ignore & IGNORE) 381 return (Strsave(STRNULL)); 382 psavejob(); 383 if (pfork(&faket, -1) == 0) { 384 *--(*vp) = 0; 385 evalav(v); 386 exitstat(); 387 } 388 pwait(); 389 prestjob(); 390 return (putn(egetn(value(STRstatus)) == 0)); 391 } 392 if (isa(**vp, ANYOP)) 393 return (Strsave(STRNULL)); 394 cp = *(*vp)++; 395 if (*cp == '-' && any("erwxfdzopls", cp[1])) { 396 struct stat stb; 397 398 if (cp[2] != '\0') 399 stderror(ERR_NAME | ERR_FILEINQ); 400 /* 401 * Detect missing file names by checking for operator in the file name 402 * position. However, if an operator name appears there, we must make 403 * sure that there's no file by that name (e.g., "/") before announcing 404 * an error. Even this check isn't quite right, since it doesn't take 405 * globbing into account. 406 */ 407 if (isa(**vp, ANYOP) && stat(short2str(**vp), &stb)) 408 stderror(ERR_NAME | ERR_FILENAME); 409 410 dp = *(*vp)++; 411 if (ignore & IGNORE) 412 return (Strsave(STRNULL)); 413 ep = globone(dp, G_ERROR); 414 switch (cp[1]) { 415 416 case 'r': 417 i = !access(short2str(ep), R_OK); 418 break; 419 420 case 'w': 421 i = !access(short2str(ep), W_OK); 422 break; 423 424 case 'x': 425 i = !access(short2str(ep), X_OK); 426 break; 427 428 default: 429 if ( 430 #ifdef S_IFLNK 431 cp[1] == 'l' ? lstat(short2str(ep), &stb) : 432 #endif 433 stat(short2str(ep), &stb)) { 434 xfree(ep); 435 return (Strsave(STR0)); 436 } 437 switch (cp[1]) { 438 439 case 'f': 440 i = S_ISREG(stb.st_mode); 441 break; 442 443 case 'd': 444 i = S_ISDIR(stb.st_mode); 445 break; 446 447 case 'p': 448 #ifdef S_ISFIFO 449 i = S_ISFIFO(stb.st_mode); 450 #else 451 i = 0; 452 #endif 453 break; 454 455 case 'l': 456 #ifdef S_ISLNK 457 i = S_ISLNK(stb.st_mode); 458 #else 459 i = 0; 460 #endif 461 break; 462 463 case 's': 464 #ifdef S_ISSOCK 465 i = S_ISSOCK(stb.st_mode); 466 #else 467 i = 0; 468 #endif 469 break; 470 471 case 'z': 472 i = stb.st_size == 0; 473 break; 474 475 case 'e': 476 i = 1; 477 break; 478 479 case 'o': 480 i = stb.st_uid == uid; 481 break; 482 } 483 } 484 xfree(ep); 485 return (putn(i)); 486 } 487 return (ignore & NOGLOB ? Strsave(cp) : globone(cp, G_ERROR)); 488 } 489 490 static void 491 evalav(Char **v) 492 { 493 struct wordent paraml1; 494 struct wordent *hp = ¶ml1; 495 struct command *t; 496 struct wordent *wdp = hp; 497 498 set(STRstatus, Strsave(STR0)); 499 hp->prev = hp->next = hp; 500 hp->word = STRNULL; 501 while (*v) { 502 struct wordent *new = xcalloc(1, sizeof *wdp); 503 504 new->prev = wdp; 505 new->next = hp; 506 wdp->next = new; 507 wdp = new; 508 wdp->word = Strsave(*v++); 509 } 510 hp->prev = wdp; 511 alias(¶ml1); 512 t = syntax(paraml1.next, ¶ml1, 0); 513 if (seterr) 514 stderror(ERR_OLD); 515 execute(t, -1, NULL, NULL); 516 freelex(¶ml1), freesyn(t); 517 } 518 519 static int 520 isa(Char *cp, int what) 521 { 522 if (cp == 0) 523 return ((what & RESTOP) != 0); 524 if (cp[1] == 0) { 525 if (what & ADDOP && (*cp == '+' || *cp == '-')) 526 return (1); 527 if (what & MULOP && (*cp == '*' || *cp == '/' || *cp == '%')) 528 return (1); 529 if (what & RESTOP && (*cp == '(' || *cp == ')' || *cp == '!' || 530 *cp == '~' || *cp == '^' || *cp == '"')) 531 return (1); 532 } 533 else if (cp[2] == 0) { 534 if (what & RESTOP) { 535 if (cp[0] == '|' && cp[1] == '&') 536 return (1); 537 if (cp[0] == '<' && cp[1] == '<') 538 return (1); 539 if (cp[0] == '>' && cp[1] == '>') 540 return (1); 541 } 542 if (what & EQOP) { 543 if (cp[0] == '=') { 544 if (cp[1] == '=') 545 return (EQEQ); 546 if (cp[1] == '~') 547 return (EQMATCH); 548 } 549 else if (cp[0] == '!') { 550 if (cp[1] == '=') 551 return (NOTEQ); 552 if (cp[1] == '~') 553 return (NOTEQMATCH); 554 } 555 } 556 } 557 if (what & RELOP) { 558 if (*cp == '<') 559 return (LSS); 560 if (*cp == '>') 561 return (GTR); 562 } 563 return (0); 564 } 565 566 static int 567 egetn(Char *cp) 568 { 569 if (*cp && *cp != '-' && !Isdigit(*cp)) 570 stderror(ERR_NAME | ERR_EXPRESSION); 571 return (getn(cp)); 572 } 573 574 /* Phew! */ 575