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