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