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