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