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