Drop main() prototype. Syncs with NetBSD-8
[minix.git] / bin / csh / exp.c
bloba4be1fc147ff3534fe273af8aa0b8c0608563604
1 /* $NetBSD: exp.c,v 1.20 2009/02/14 07:12:29 lukem Exp $ */
3 /*-
4 * Copyright (c) 1980, 1991, 1993
5 * The Regents of the University of California. All rights reserved.
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.
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.
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 */
41 #include <sys/types.h>
42 #include <sys/stat.h>
44 #include <stdarg.h>
45 #include <stdlib.h>
46 #include <unistd.h>
48 #ifndef SHORT_STRINGS
49 #include <string.h>
50 #endif /* SHORT_STRINGS */
52 #include "csh.h"
53 #include "extern.h"
55 #define IGNORE 1 /* in ignore, it means to ignore value, just parse */
56 #define NOGLOB 2 /* in ignore, it means not to globone */
58 #define ADDOP 1
59 #define MULOP 2
60 #define EQOP 4
61 #define RELOP 8
62 #define RESTOP 16
63 #define ANYOP 31
65 #define EQEQ 1
66 #define GTR 2
67 #define LSS 4
68 #define NOTEQ 6
69 #define EQMATCH 7
70 #define NOTEQMATCH 8
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 *);
86 #ifdef EDEBUG
87 static void etracc(char *, Char *, Char ***);
88 static void etraci(char *, int, Char ***);
89 #endif
91 int
92 expr(Char ***vp)
94 return (exp0(vp, 0));
97 int
98 exp0(Char ***vp, int ignore)
100 int p1;
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;
109 (*vp)++;
110 p2 = exp0(vp, (ignore & IGNORE) || p1);
111 #ifdef EDEBUG
112 etraci("exp0 p2", p2, vp);
113 #endif
114 return (p1 || p2);
116 return (p1);
119 static int
120 exp1(Char ***vp, int ignore)
122 int p1;
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;
131 (*vp)++;
132 p2 = exp1(vp, (ignore & IGNORE) || !p1);
133 #ifdef EDEBUG
134 etraci("exp1 p2", p2, vp);
135 #endif
136 return (p1 && p2);
138 return (p1);
141 static int
142 csh_exp2(Char ***vp, int ignore)
144 int p1;
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;
153 (*vp)++;
154 p2 = csh_exp2(vp, ignore);
155 #ifdef EDEBUG
156 etraci("exp3 p2", p2, vp);
157 #endif
158 return (p1 | p2);
160 return (p1);
163 static int
164 exp2a(Char ***vp, int ignore)
166 int p1;
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;
175 (*vp)++;
176 p2 = exp2a(vp, ignore);
177 #ifdef EDEBUG
178 etraci("exp2a p2", p2, vp);
179 #endif
180 return (p1 ^ p2);
182 return (p1);
185 static int
186 exp2b(Char ***vp, int ignore)
188 int p1;
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;
197 (*vp)++;
198 p2 = exp2b(vp, ignore);
199 #ifdef EDEBUG
200 etraci("exp2b p2", p2, vp);
201 #endif
202 return (p1 & p2);
204 return (p1);
207 static int
208 exp2c(Char ***vp, int ignore)
210 Char *p1, *p2;
211 int i;
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;
240 xfree((ptr_t) p1);
241 xfree((ptr_t) p2);
242 return (i);
244 i = egetn(p1);
245 xfree((ptr_t) p1);
246 return (i);
249 static Char *
250 exp3(Char ***vp, int ignore)
252 Char *p1, *p2;
253 int i;
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;
282 xfree((ptr_t) p1);
283 xfree((ptr_t) p2);
284 return (putn(i));
286 return (p1);
289 static Char *
290 exp3a(Char ***vp, int ignore)
292 Char *op, *p1, *p2;
293 int i;
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));
314 return (p1);
317 static Char *
318 exp4(Char ***vp, int ignore)
320 Char *p1, *p2;
321 int i;
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;
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;
345 xfree((ptr_t) p1);
346 xfree((ptr_t) p2);
347 return (putn(i));
349 return (p1);
352 static Char *
353 exp5(Char ***vp, int ignore)
355 Char *p1, *p2;
356 int i;
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;
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;
389 xfree((ptr_t) p1);
390 xfree((ptr_t) p2);
391 return (putn(i));
393 return (p1);
396 static Char *
397 exp6(Char ***vp, int ignore)
399 Char *cp, *dp, *ep;
400 int ccode, i;
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));
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));
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));
436 if (eq(**vp, STRLbrace)) {
437 struct command faket;
438 Char *fakecom[2];
439 Char **v;
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;
455 if (ignore & IGNORE)
456 return (Strsave(STRNULL));
457 psavejob();
458 if (pfork(&faket, -1) == 0) {
459 *--(*vp) = 0;
460 evalav(v);
461 exitstat();
463 pwait();
464 prestjob();
465 #ifdef EDEBUG
466 etraci("exp6 {} status", egetn(value(STRstatus)), vp);
467 #endif
468 return (putn(egetn(value(STRstatus)) == 0));
470 if (isa(**vp, ANYOP))
471 return (Strsave(STRNULL));
472 cp = *(*vp)++;
473 if (*cp == '-' && any("erwxfdzopls", cp[1])) {
474 struct stat stb;
476 if (cp[2] != '\0')
477 stderror(ERR_NAME | ERR_FILEINQ);
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.
485 if (isa(**vp, ANYOP) && stat(short2str(**vp), &stb))
486 stderror(ERR_NAME | ERR_FILENAME);
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));
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;
547 #ifdef EDEBUG
548 etraci("exp6 -? i", i, vp);
549 #endif
550 xfree((ptr_t) ep);
551 return (putn(i));
553 #ifdef EDEBUG
554 etracc("exp6 default", cp, vp);
555 #endif
556 return (ignore & NOGLOB ? Strsave(cp) : globone(cp, G_ERROR));
559 static void
560 evalav(Char **v)
562 struct wordent *hp, paraml1, *wdp;
563 struct command *t;
565 hp = &paraml1;
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;
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++);
580 hp->prev = wdp;
581 alias(&paraml1);
582 t = syntax(paraml1.next, &paraml1, 0);
583 if (seterr)
584 stderror(ERR_OLD);
585 execute(t, -1, NULL, NULL);
586 freelex(&paraml1), freesyn(t);
589 static int
590 isa(Char *cp, int what)
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);
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);
612 if (what & EQOP) {
613 if (cp[0] == '=') {
614 if (cp[1] == '=')
615 return (EQEQ);
616 if (cp[1] == '~')
617 return (EQMATCH);
619 else if (cp[0] == '!') {
620 if (cp[1] == '=')
621 return (NOTEQ);
622 if (cp[1] == '~')
623 return (NOTEQMATCH);
627 if (what & RELOP) {
628 if (*cp == '<')
629 return (LSS);
630 if (*cp == '>')
631 return (GTR);
633 return (0);
636 static int
637 egetn(Char *cp)
639 if (*cp && *cp != '-' && !Isdigit(*cp))
640 stderror(ERR_NAME | ERR_EXPRESSION);
641 return (getn(cp));
644 /* Phew! */
646 #ifdef EDEBUG
647 static void
648 etraci(char *str, int i, Char ***vp)
650 (void)fprintf(csherr, "%s=%d\t", str, i);
651 blkpr(csherr, *vp);
652 (void)fprintf(csherr, "\n");
654 static void
655 etracc(char *str, Char *cp, Char ***vp)
657 (void)fprintf(csherr, "%s=%s\t", str, vis_str(cp));
658 blkpr(csherr, *vp);
659 (void)fprintf(csherr, "\n");
661 #endif