1 /* $OpenBSD: exp.c,v 1.16 2015/12/26 13:48:38 mestre 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 free(p1); 187 free(p2); 188 return (i); 189 } 190 i = egetn(p1); 191 free(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 free(p1); 227 free(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 free(p1); 249 free(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 free(p1); 278 free(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 free(p1); 325 free(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 free(cp); 344 return (putn(!i)); 345 } 346 if (eq(**vp, STRtilde)) { 347 (*vp)++; 348 cp = exp6(vp, ignore); 349 i = egetn(cp); 350 free(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 (cp[1] == 'l' ? lstat(short2str(ep), &stb) : 430 stat(short2str(ep), &stb)) { 431 free(ep); 432 return (Strsave(STR0)); 433 } 434 switch (cp[1]) { 435 436 case 'f': 437 i = S_ISREG(stb.st_mode); 438 break; 439 440 case 'd': 441 i = S_ISDIR(stb.st_mode); 442 break; 443 444 case 'p': 445 i = S_ISFIFO(stb.st_mode); 446 break; 447 448 case 'l': 449 i = S_ISLNK(stb.st_mode); 450 break; 451 452 case 's': 453 i = S_ISSOCK(stb.st_mode); 454 break; 455 456 case 'z': 457 i = stb.st_size == 0; 458 break; 459 460 case 'e': 461 i = 1; 462 break; 463 464 case 'o': 465 i = stb.st_uid == uid; 466 break; 467 } 468 } 469 free(ep); 470 return (putn(i)); 471 } 472 return (ignore & NOGLOB ? Strsave(cp) : globone(cp, G_ERROR)); 473 } 474 475 static void 476 evalav(Char **v) 477 { 478 struct wordent paraml1; 479 struct wordent *hp = ¶ml1; 480 struct command *t; 481 struct wordent *wdp = hp; 482 483 set(STRstatus, Strsave(STR0)); 484 hp->prev = hp->next = hp; 485 hp->word = STRNULL; 486 while (*v) { 487 struct wordent *new = xcalloc(1, sizeof *wdp); 488 489 new->prev = wdp; 490 new->next = hp; 491 wdp->next = new; 492 wdp = new; 493 wdp->word = Strsave(*v++); 494 } 495 hp->prev = wdp; 496 alias(¶ml1); 497 t = syntax(paraml1.next, ¶ml1, 0); 498 if (seterr) 499 stderror(ERR_OLD); 500 execute(t, -1, NULL, NULL); 501 freelex(¶ml1), freesyn(t); 502 } 503 504 static int 505 isa(Char *cp, int what) 506 { 507 if (cp == 0) 508 return ((what & RESTOP) != 0); 509 if (cp[1] == 0) { 510 if (what & ADDOP && (*cp == '+' || *cp == '-')) 511 return (1); 512 if (what & MULOP && (*cp == '*' || *cp == '/' || *cp == '%')) 513 return (1); 514 if (what & RESTOP && (*cp == '(' || *cp == ')' || *cp == '!' || 515 *cp == '~' || *cp == '^' || *cp == '"')) 516 return (1); 517 } 518 else if (cp[2] == 0) { 519 if (what & RESTOP) { 520 if (cp[0] == '|' && cp[1] == '&') 521 return (1); 522 if (cp[0] == '<' && cp[1] == '<') 523 return (1); 524 if (cp[0] == '>' && cp[1] == '>') 525 return (1); 526 } 527 if (what & EQOP) { 528 if (cp[0] == '=') { 529 if (cp[1] == '=') 530 return (EQEQ); 531 if (cp[1] == '~') 532 return (EQMATCH); 533 } 534 else if (cp[0] == '!') { 535 if (cp[1] == '=') 536 return (NOTEQ); 537 if (cp[1] == '~') 538 return (NOTEQMATCH); 539 } 540 } 541 } 542 if (what & RELOP) { 543 if (*cp == '<') 544 return (LSS); 545 if (*cp == '>') 546 return (GTR); 547 } 548 return (0); 549 } 550 551 static int 552 egetn(Char *cp) 553 { 554 if (*cp && *cp != '-' && !Isdigit(*cp)) 555 stderror(ERR_NAME | ERR_EXPRESSION); 556 return (getn(cp)); 557 } 558 559 /* Phew! */ 560