Home | History | Annotate | Line # | Download | only in csh
exp.c revision 1.13
      1 /* $NetBSD: exp.c,v 1.13 2002/05/25 23:29:16 wiz 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. All advertising materials mentioning features or use of this software
     16  *    must display the following acknowledgement:
     17  *	This product includes software developed by the University of
     18  *	California, Berkeley and its contributors.
     19  * 4. Neither the name of the University nor the names of its contributors
     20  *    may be used to endorse or promote products derived from this software
     21  *    without specific prior written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33  * SUCH DAMAGE.
     34  */
     35 
     36 #include <sys/cdefs.h>
     37 #ifndef lint
     38 #if 0
     39 static char sccsid[] = "@(#)exp.c	8.1 (Berkeley) 5/31/93";
     40 #else
     41 __RCSID("$NetBSD: exp.c,v 1.13 2002/05/25 23:29:16 wiz Exp $");
     42 #endif
     43 #endif /* not lint */
     44 
     45 #include <sys/types.h>
     46 #include <sys/stat.h>
     47 
     48 #include <stdarg.h>
     49 #include <stdlib.h>
     50 #include <unistd.h>
     51 
     52 #ifndef SHORT_STRINGS
     53 #include <string.h>
     54 #endif /* SHORT_STRINGS */
     55 
     56 #include "csh.h"
     57 #include "extern.h"
     58 
     59 #define IGNORE	1	/* in ignore, it means to ignore value, just parse */
     60 #define NOGLOB	2	/* in ignore, it means not to globone */
     61 
     62 #define	ADDOP	1
     63 #define	MULOP	2
     64 #define	EQOP	4
     65 #define	RELOP	8
     66 #define	RESTOP	16
     67 #define	ANYOP	31
     68 
     69 #define	EQEQ	1
     70 #define	GTR	2
     71 #define	LSS	4
     72 #define	NOTEQ	6
     73 #define EQMATCH 7
     74 #define NOTEQMATCH 8
     75 
     76 static int exp1(Char ***, bool);
     77 static int exp2(Char ***, bool);
     78 static int exp2a(Char ***, bool);
     79 static int exp2b(Char ***, bool);
     80 static int exp2c(Char ***, bool);
     81 static Char *exp3(Char ***, bool);
     82 static Char *exp3a(Char ***, bool);
     83 static Char *exp4(Char ***, bool);
     84 static Char *exp5(Char ***, bool);
     85 static Char *exp6(Char ***, bool);
     86 static void evalav(Char **);
     87 static int isa(Char *, int);
     88 static int egetn(Char *);
     89 
     90 #ifdef EDEBUG
     91 static void etracc(char *, Char *, Char ***);
     92 static void etraci(char *, int, Char ***);
     93 #endif
     94 
     95 int
     96 expr(Char ***vp)
     97 {
     98     return (exp0(vp, 0));
     99 }
    100 
    101 int
    102 exp0(Char ***vp, bool ignore)
    103 {
    104     int p1;
    105 
    106     p1 = exp1(vp, ignore);
    107 #ifdef EDEBUG
    108     etraci("exp0 p1", p1, vp);
    109 #endif
    110     if (**vp && eq(**vp, STRor2)) {
    111 	int p2;
    112 
    113 	(*vp)++;
    114 	p2 = exp0(vp, (ignore & IGNORE) || p1);
    115 #ifdef EDEBUG
    116 	etraci("exp0 p2", p2, vp);
    117 #endif
    118 	return (p1 || p2);
    119     }
    120     return (p1);
    121 }
    122 
    123 static int
    124 exp1(Char ***vp, bool ignore)
    125 {
    126     int p1;
    127 
    128     p1 = exp2(vp, ignore);
    129 #ifdef EDEBUG
    130     etraci("exp1 p1", p1, vp);
    131 #endif
    132     if (**vp && eq(**vp, STRand2)) {
    133 	int p2;
    134 
    135 	(*vp)++;
    136 	p2 = exp1(vp, (ignore & IGNORE) || !p1);
    137 #ifdef EDEBUG
    138 	etraci("exp1 p2", p2, vp);
    139 #endif
    140 	return (p1 && p2);
    141     }
    142     return (p1);
    143 }
    144 
    145 static int
    146 exp2(Char ***vp, bool ignore)
    147 {
    148     int p1;
    149 
    150     p1 = exp2a(vp, ignore);
    151 #ifdef EDEBUG
    152     etraci("exp3 p1", p1, vp);
    153 #endif
    154     if (**vp && eq(**vp, STRor)) {
    155 	int p2;
    156 
    157 	(*vp)++;
    158 	p2 = exp2(vp, ignore);
    159 #ifdef EDEBUG
    160 	etraci("exp3 p2", p2, vp);
    161 #endif
    162 	return (p1 | p2);
    163     }
    164     return (p1);
    165 }
    166 
    167 static int
    168 exp2a(Char ***vp, bool ignore)
    169 {
    170     int p1;
    171 
    172     p1 = exp2b(vp, ignore);
    173 #ifdef EDEBUG
    174     etraci("exp2a p1", p1, vp);
    175 #endif
    176     if (**vp && eq(**vp, STRcaret)) {
    177 	int p2;
    178 
    179 	(*vp)++;
    180 	p2 = exp2a(vp, ignore);
    181 #ifdef EDEBUG
    182 	etraci("exp2a p2", p2, vp);
    183 #endif
    184 	return (p1 ^ p2);
    185     }
    186     return (p1);
    187 }
    188 
    189 static int
    190 exp2b(Char ***vp, bool ignore)
    191 {
    192     int p1;
    193 
    194     p1 = exp2c(vp, ignore);
    195 #ifdef EDEBUG
    196     etraci("exp2b p1", p1, vp);
    197 #endif
    198     if (**vp && eq(**vp, STRand)) {
    199 	int p2;
    200 
    201 	(*vp)++;
    202 	p2 = exp2b(vp, ignore);
    203 #ifdef EDEBUG
    204 	etraci("exp2b p2", p2, vp);
    205 #endif
    206 	return (p1 & p2);
    207     }
    208     return (p1);
    209 }
    210 
    211 static int
    212 exp2c(Char ***vp, bool ignore)
    213 {
    214     Char *p1, *p2;
    215     int i;
    216 
    217     p1 = exp3(vp, ignore);
    218 #ifdef EDEBUG
    219     etracc("exp2c p1", p1, vp);
    220 #endif
    221     if ((i = isa(**vp, EQOP)) != 0) {
    222 	(*vp)++;
    223 	if (i == EQMATCH || i == NOTEQMATCH)
    224 	    ignore |= NOGLOB;
    225 	p2 = exp3(vp, ignore);
    226 #ifdef EDEBUG
    227 	etracc("exp2c p2", p2, vp);
    228 #endif
    229 	if (!(ignore & IGNORE))
    230 	    switch (i) {
    231 	    case EQEQ:
    232 		i = eq(p1, p2);
    233 		break;
    234 	    case EQMATCH:
    235 		i = Gmatch(p1, p2);
    236 		break;
    237 	    case NOTEQ:
    238 		i = !eq(p1, p2);
    239 		break;
    240 	    case NOTEQMATCH:
    241 		i = !Gmatch(p1, p2);
    242 		break;
    243 	    }
    244 	xfree((ptr_t) p1);
    245 	xfree((ptr_t) p2);
    246 	return (i);
    247     }
    248     i = egetn(p1);
    249     xfree((ptr_t) p1);
    250     return (i);
    251 }
    252 
    253 static Char *
    254 exp3(Char ***vp, bool ignore)
    255 {
    256     Char *p1, *p2;
    257     int i;
    258 
    259     p1 = exp3a(vp, ignore);
    260 #ifdef EDEBUG
    261     etracc("exp3 p1", p1, vp);
    262 #endif
    263     if ((i = isa(**vp, RELOP)) != 0) {
    264 	(*vp)++;
    265 	if (**vp && eq(**vp, STRequal))
    266 	    i |= 1, (*vp)++;
    267 	p2 = exp3(vp, ignore);
    268 #ifdef EDEBUG
    269 	etracc("exp3 p2", p2, vp);
    270 #endif
    271 	if (!(ignore & IGNORE))
    272 	    switch (i) {
    273 	    case GTR:
    274 		i = egetn(p1) > egetn(p2);
    275 		break;
    276 	    case GTR | 1:
    277 		i = egetn(p1) >= egetn(p2);
    278 		break;
    279 	    case LSS:
    280 		i = egetn(p1) < egetn(p2);
    281 		break;
    282 	    case LSS | 1:
    283 		i = egetn(p1) <= egetn(p2);
    284 		break;
    285 	    }
    286 	xfree((ptr_t) p1);
    287 	xfree((ptr_t) p2);
    288 	return (putn(i));
    289     }
    290     return (p1);
    291 }
    292 
    293 static Char *
    294 exp3a(Char ***vp, bool ignore)
    295 {
    296     Char *op, *p1, *p2;
    297     int i;
    298 
    299     p1 = exp4(vp, ignore);
    300 #ifdef EDEBUG
    301     etracc("exp3a p1", p1, vp);
    302 #endif
    303     op = **vp;
    304     if (op && any("<>", op[0]) && op[0] == op[1]) {
    305 	(*vp)++;
    306 	p2 = exp3a(vp, ignore);
    307 #ifdef EDEBUG
    308 	etracc("exp3a p2", p2, vp);
    309 #endif
    310 	if (op[0] == '<')
    311 	    i = egetn(p1) << egetn(p2);
    312 	else
    313 	    i = egetn(p1) >> egetn(p2);
    314 	xfree((ptr_t) p1);
    315 	xfree((ptr_t) p2);
    316 	return (putn(i));
    317     }
    318     return (p1);
    319 }
    320 
    321 static Char *
    322 exp4(Char ***vp, bool ignore)
    323 {
    324     Char *p1, *p2;
    325     int i;
    326 
    327     i = 0;
    328     p1 = exp5(vp, ignore);
    329 #ifdef EDEBUG
    330     etracc("exp4 p1", p1, vp);
    331 #endif
    332     if (isa(**vp, ADDOP)) {
    333 	Char *op;
    334 
    335 	op = *(*vp)++;
    336 	p2 = exp4(vp, ignore);
    337 #ifdef EDEBUG
    338 	etracc("exp4 p2", p2, vp);
    339 #endif
    340 	if (!(ignore & IGNORE))
    341 	    switch (op[0]) {
    342 	    case '+':
    343 		i = egetn(p1) + egetn(p2);
    344 		break;
    345 	    case '-':
    346 		i = egetn(p1) - egetn(p2);
    347 		break;
    348 	    }
    349 	xfree((ptr_t) p1);
    350 	xfree((ptr_t) p2);
    351 	return (putn(i));
    352     }
    353     return (p1);
    354 }
    355 
    356 static Char *
    357 exp5(Char ***vp, bool ignore)
    358 {
    359     Char *p1, *p2;
    360     int i;
    361 
    362     i = 0;
    363     p1 = exp6(vp, ignore);
    364 #ifdef EDEBUG
    365     etracc("exp5 p1", p1, vp);
    366 #endif
    367     if (isa(**vp, MULOP)) {
    368 	Char *op;
    369 
    370 	op = *(*vp)++;
    371 	p2 = exp5(vp, ignore);
    372 #ifdef EDEBUG
    373 	etracc("exp5 p2", p2, vp);
    374 #endif
    375 	if (!(ignore & IGNORE))
    376 	    switch (op[0]) {
    377 	    case '*':
    378 		i = egetn(p1) * egetn(p2);
    379 		break;
    380 	    case '/':
    381 		i = egetn(p2);
    382 		if (i == 0)
    383 		    stderror(ERR_DIV0);
    384 		i = egetn(p1) / i;
    385 		break;
    386 	    case '%':
    387 		i = egetn(p2);
    388 		if (i == 0)
    389 		    stderror(ERR_MOD0);
    390 		i = egetn(p1) % i;
    391 		break;
    392 	    }
    393 	xfree((ptr_t) p1);
    394 	xfree((ptr_t) p2);
    395 	return (putn(i));
    396     }
    397     return (p1);
    398 }
    399 
    400 static Char *
    401 exp6(Char ***vp, bool ignore)
    402 {
    403     Char *cp, *dp, *ep;
    404     int ccode, i;
    405 
    406     i = 0;
    407     if (**vp == 0)
    408 	stderror(ERR_NAME | ERR_EXPRESSION);
    409     if (eq(**vp, STRbang)) {
    410 	(*vp)++;
    411 	cp = exp6(vp, ignore);
    412 #ifdef EDEBUG
    413 	etracc("exp6 ! cp", cp, vp);
    414 #endif
    415 	i = egetn(cp);
    416 	xfree((ptr_t) cp);
    417 	return (putn(!i));
    418     }
    419     if (eq(**vp, STRtilde)) {
    420 	(*vp)++;
    421 	cp = exp6(vp, ignore);
    422 #ifdef EDEBUG
    423 	etracc("exp6 ~ cp", cp, vp);
    424 #endif
    425 	i = egetn(cp);
    426 	xfree((ptr_t) cp);
    427 	return (putn(~i));
    428     }
    429     if (eq(**vp, STRLparen)) {
    430 	(*vp)++;
    431 	ccode = exp0(vp, ignore);
    432 #ifdef EDEBUG
    433 	etraci("exp6 () ccode", ccode, vp);
    434 #endif
    435 	if (*vp == 0 || **vp == 0 || ***vp != ')')
    436 	    stderror(ERR_NAME | ERR_EXPRESSION);
    437 	(*vp)++;
    438 	return (putn(ccode));
    439     }
    440     if (eq(**vp, STRLbrace)) {
    441 	struct command faket;
    442 	Char *fakecom[2];
    443 	Char **v;
    444 
    445 	faket.t_dtyp = NODE_COMMAND;
    446 	faket.t_dflg = 0;
    447 	faket.t_dcar = faket.t_dcdr = faket.t_dspr = NULL;
    448 	faket.t_dcom = fakecom;
    449 	fakecom[0] = STRfakecom;
    450 	fakecom[1] = NULL;
    451 	(*vp)++;
    452 	v = *vp;
    453 	for (;;) {
    454 	    if (!**vp)
    455 		stderror(ERR_NAME | ERR_MISSING, '}');
    456 	    if (eq(*(*vp)++, STRRbrace))
    457 		break;
    458 	}
    459 	if (ignore & IGNORE)
    460 	    return (Strsave(STRNULL));
    461 	psavejob();
    462 	if (pfork(&faket, -1) == 0) {
    463 	    *--(*vp) = 0;
    464 	    evalav(v);
    465 	    exitstat();
    466 	}
    467 	pwait();
    468 	prestjob();
    469 #ifdef EDEBUG
    470 	etraci("exp6 {} status", egetn(value(STRstatus)), vp);
    471 #endif
    472 	return (putn(egetn(value(STRstatus)) == 0));
    473     }
    474     if (isa(**vp, ANYOP))
    475 	return (Strsave(STRNULL));
    476     cp = *(*vp)++;
    477     if (*cp == '-' && any("erwxfdzopls", cp[1])) {
    478 	struct stat stb;
    479 
    480 	if (cp[2] != '\0')
    481 	    stderror(ERR_NAME | ERR_FILEINQ);
    482 	/*
    483 	 * Detect missing file names by checking for operator in the file name
    484 	 * position.  However, if an operator name appears there, we must make
    485 	 * sure that there's no file by that name (e.g., "/") before announcing
    486 	 * an error.  Even this check isn't quite right, since it doesn't take
    487 	 * globbing into account.
    488 	 */
    489 	if (isa(**vp, ANYOP) && stat(short2str(**vp), &stb))
    490 	    stderror(ERR_NAME | ERR_FILENAME);
    491 
    492 	dp = *(*vp)++;
    493 	if (ignore & IGNORE)
    494 	    return (Strsave(STRNULL));
    495 	ep = globone(dp, G_ERROR);
    496 	switch (cp[1]) {
    497 	case 'r':
    498 	    i = !access(short2str(ep), R_OK);
    499 	    break;
    500 	case 'w':
    501 	    i = !access(short2str(ep), W_OK);
    502 	    break;
    503 	case 'x':
    504 	    i = !access(short2str(ep), X_OK);
    505 	    break;
    506 	default:
    507 	    if (cp[1] == 'l' ?
    508 		lstat(short2str(ep), &stb) : stat(short2str(ep), &stb)) {
    509 		xfree((ptr_t) ep);
    510 		return (Strsave(STR0));
    511 	    }
    512 	    switch (cp[1]) {
    513 	    case 'd':
    514 		i = S_ISDIR(stb.st_mode);
    515 		break;
    516 	    case 'e':
    517 		i = 1;
    518 		break;
    519 	    case 'f':
    520 		i = S_ISREG(stb.st_mode);
    521 		break;
    522 	    case 'l':
    523 #ifdef S_ISLNK
    524 		i = S_ISLNK(stb.st_mode);
    525 #else
    526 		i = 0;
    527 #endif
    528 		break;
    529 	    case 'o':
    530 		i = stb.st_uid == uid;
    531 		break;
    532 	    case 'p':
    533 #ifdef S_ISFIFO
    534 		i = S_ISFIFO(stb.st_mode);
    535 #else
    536 		i = 0;
    537 #endif
    538 		break;
    539 	    case 's':
    540 #ifdef S_ISSOCK
    541 		i = S_ISSOCK(stb.st_mode);
    542 #else
    543 		i = 0;
    544 #endif
    545 		break;
    546 	    case 'z':
    547 		i = stb.st_size == 0;
    548 		break;
    549 	    }
    550 	}
    551 #ifdef EDEBUG
    552 	etraci("exp6 -? i", i, vp);
    553 #endif
    554 	xfree((ptr_t) ep);
    555 	return (putn(i));
    556     }
    557 #ifdef EDEBUG
    558     etracc("exp6 default", cp, vp);
    559 #endif
    560     return (ignore & NOGLOB ? Strsave(cp) : globone(cp, G_ERROR));
    561 }
    562 
    563 static void
    564 evalav(Char **v)
    565 {
    566     struct wordent *hp, paraml1, *wdp;
    567     struct command *t;
    568 
    569     hp = &paraml1;
    570     wdp = hp;
    571     set(STRstatus, Strsave(STR0));
    572     hp->prev = hp->next = hp;
    573     hp->word = STRNULL;
    574     while (*v) {
    575 	struct wordent *new;
    576 
    577 	new = (struct wordent *)xcalloc(1, sizeof *wdp);
    578 	new->prev = wdp;
    579 	new->next = hp;
    580 	wdp->next = new;
    581 	wdp = new;
    582 	wdp->word = Strsave(*v++);
    583     }
    584     hp->prev = wdp;
    585     alias(&paraml1);
    586     t = syntax(paraml1.next, &paraml1, 0);
    587     if (seterr)
    588 	stderror(ERR_OLD);
    589     execute(t, -1, NULL, NULL);
    590     freelex(&paraml1), freesyn(t);
    591 }
    592 
    593 static int
    594 isa(Char *cp, int what)
    595 {
    596     if (cp == 0)
    597 	return ((what & RESTOP) != 0);
    598     if (cp[1] == 0) {
    599 	if (what & ADDOP && (*cp == '+' || *cp == '-'))
    600 	    return (1);
    601 	if (what & MULOP && (*cp == '*' || *cp == '/' || *cp == '%'))
    602 	    return (1);
    603 	if (what & RESTOP && (*cp == '(' || *cp == ')' || *cp == '!' ||
    604 			      *cp == '~' || *cp == '^' || *cp == '"'))
    605 	    return (1);
    606     }
    607     else if (cp[2] == 0) {
    608 	if (what & RESTOP) {
    609 	    if (cp[0] == '|' && cp[1] == '&')
    610 		return (1);
    611 	    if (cp[0] == '<' && cp[1] == '<')
    612 		return (1);
    613 	    if (cp[0] == '>' && cp[1] == '>')
    614 		return (1);
    615 	}
    616 	if (what & EQOP) {
    617 	    if (cp[0] == '=') {
    618 		if (cp[1] == '=')
    619 		    return (EQEQ);
    620 		if (cp[1] == '~')
    621 		    return (EQMATCH);
    622 	    }
    623 	    else if (cp[0] == '!') {
    624 		if (cp[1] == '=')
    625 		    return (NOTEQ);
    626 		if (cp[1] == '~')
    627 		    return (NOTEQMATCH);
    628 	    }
    629 	}
    630     }
    631     if (what & RELOP) {
    632 	if (*cp == '<')
    633 	    return (LSS);
    634 	if (*cp == '>')
    635 	    return (GTR);
    636     }
    637     return (0);
    638 }
    639 
    640 static int
    641 egetn(Char *cp)
    642 {
    643     if (*cp && *cp != '-' && !Isdigit(*cp))
    644 	stderror(ERR_NAME | ERR_EXPRESSION);
    645     return (getn(cp));
    646 }
    647 
    648 /* Phew! */
    649 
    650 #ifdef EDEBUG
    651 static void
    652 etraci(char *str, int i, Char ***vp)
    653 {
    654     (void)fprintf(csherr, "%s=%d\t", str, i);
    655     blkpr(csherr, *vp);
    656     (void)fprintf(csherr, "\n");
    657 }
    658 static void
    659 etracc(char *str, Char *cp, Char ***vp)
    660 {
    661     (void)fprintf(csherr, "%s=%s\t", str, vis_str(cp));
    662     blkpr(csherr, *vp);
    663     (void)fprintf(csherr, "\n");
    664 }
    665 #endif
    666