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