xref: /original-bsd/bin/csh/exp.c (revision 262b24ac)
1 /*
2  * Copyright (c) 1980 Regents of the University of California.
3  * All rights reserved.  The Berkeley Software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 static char *sccsid = "@(#)exp.c	5.3 (Berkeley) 06/23/85";
9 #endif
10 
11 #include "sh.h"
12 
13 /*
14  * C shell
15  */
16 
17 #define IGNORE	1	/* in ignore, it means to ignore value, just parse */
18 #define NOGLOB	2	/* in ignore, it means not to globone */
19 
20 #define	ADDOP	1
21 #define	MULOP	2
22 #define	EQOP	4
23 #define	RELOP	8
24 #define	RESTOP	16
25 #define	ANYOP	31
26 
27 #define	EQEQ	1
28 #define	GTR	2
29 #define	LSS	4
30 #define	NOTEQ	6
31 #define EQMATCH 7
32 #define NOTEQMATCH 8
33 
34 exp(vp)
35 	register char ***vp;
36 {
37 
38 	return (exp0(vp, 0));
39 }
40 
41 exp0(vp, ignore)
42 	register char ***vp;
43 	bool ignore;
44 {
45 	register int p1 = exp1(vp, ignore);
46 
47 #ifdef EDEBUG
48 	etraci("exp0 p1", p1, vp);
49 #endif
50 	if (**vp && eq(**vp, "||")) {
51 		register int p2;
52 
53 		(*vp)++;
54 		p2 = exp0(vp, (ignore&IGNORE) || p1);
55 #ifdef EDEBUG
56 		etraci("exp0 p2", p2, vp);
57 #endif
58 		return (p1 || p2);
59 	}
60 	return (p1);
61 }
62 
63 exp1(vp, ignore)
64 	register char ***vp;
65 {
66 	register int p1 = exp2(vp, ignore);
67 
68 #ifdef EDEBUG
69 	etraci("exp1 p1", p1, vp);
70 #endif
71 	if (**vp && eq(**vp, "&&")) {
72 		register int p2;
73 
74 		(*vp)++;
75 		p2 = exp1(vp, (ignore&IGNORE) || !p1);
76 #ifdef EDEBUG
77 		etraci("exp1 p2", p2, vp);
78 #endif
79 		return (p1 && p2);
80 	}
81 	return (p1);
82 }
83 
84 exp2(vp, ignore)
85 	register char ***vp;
86 	bool ignore;
87 {
88 	register int p1 = exp2a(vp, ignore);
89 
90 #ifdef EDEBUG
91 	etraci("exp3 p1", p1, vp);
92 #endif
93 	if (**vp && eq(**vp, "|")) {
94 		register int p2;
95 
96 		(*vp)++;
97 		p2 = exp2(vp, ignore);
98 #ifdef EDEBUG
99 		etraci("exp3 p2", p2, vp);
100 #endif
101 		return (p1 | p2);
102 	}
103 	return (p1);
104 }
105 
106 exp2a(vp, ignore)
107 	register char ***vp;
108 	bool ignore;
109 {
110 	register int p1 = exp2b(vp, ignore);
111 
112 #ifdef EDEBUG
113 	etraci("exp2a p1", p1, vp);
114 #endif
115 	if (**vp && eq(**vp, "^")) {
116 		register int p2;
117 
118 		(*vp)++;
119 		p2 = exp2a(vp, ignore);
120 #ifdef EDEBUG
121 		etraci("exp2a p2", p2, vp);
122 #endif
123 		return (p1 ^ p2);
124 	}
125 	return (p1);
126 }
127 
128 exp2b(vp, ignore)
129 	register char ***vp;
130 	bool ignore;
131 {
132 	register int p1 = exp2c(vp, ignore);
133 
134 #ifdef EDEBUG
135 	etraci("exp2b p1", p1, vp);
136 #endif
137 	if (**vp && eq(**vp, "&")) {
138 		register int p2;
139 
140 		(*vp)++;
141 		p2 = exp2b(vp, ignore);
142 #ifdef EDEBUG
143 		etraci("exp2b p2", p2, vp);
144 #endif
145 		return (p1 & p2);
146 	}
147 	return (p1);
148 }
149 
150 exp2c(vp, ignore)
151 	register char ***vp;
152 	bool ignore;
153 {
154 	register char *p1 = exp3(vp, ignore);
155 	register char *p2;
156 	register int i;
157 
158 #ifdef EDEBUG
159 	etracc("exp2c p1", p1, vp);
160 #endif
161 	if (i = isa(**vp, EQOP)) {
162 		(*vp)++;
163 		if (i == EQMATCH || i == NOTEQMATCH)
164 			ignore |= NOGLOB;
165 		p2 = exp3(vp, ignore);
166 #ifdef EDEBUG
167 		etracc("exp2c p2", p2, vp);
168 #endif
169 		if (!(ignore&IGNORE)) switch (i) {
170 
171 		case EQEQ:
172 			i = eq(p1, p2);
173 			break;
174 
175 		case NOTEQ:
176 			i = !eq(p1, p2);
177 			break;
178 
179 		case EQMATCH:
180 			i = Gmatch(p1, p2);
181 			break;
182 
183 		case NOTEQMATCH:
184 			i = !Gmatch(p1, p2);
185 			break;
186 		}
187 		xfree(p1), xfree(p2);
188 		return (i);
189 	}
190 	i = egetn(p1);
191 	xfree(p1);
192 	return (i);
193 }
194 
195 char *
196 exp3(vp, ignore)
197 	register char ***vp;
198 	bool ignore;
199 {
200 	register char *p1, *p2;
201 	register int i;
202 
203 	p1 = exp3a(vp, ignore);
204 #ifdef EDEBUG
205 	etracc("exp3 p1", p1, vp);
206 #endif
207 	if (i = isa(**vp, RELOP)) {
208 		(*vp)++;
209 		if (**vp && eq(**vp, "="))
210 			i |= 1, (*vp)++;
211 		p2 = exp3(vp, ignore);
212 #ifdef EDEBUG
213 		etracc("exp3 p2", p2, vp);
214 #endif
215 		if (!(ignore&IGNORE)) switch (i) {
216 
217 		case GTR:
218 			i = egetn(p1) > egetn(p2);
219 			break;
220 
221 		case GTR|1:
222 			i = egetn(p1) >= egetn(p2);
223 			break;
224 
225 		case LSS:
226 			i = egetn(p1) < egetn(p2);
227 			break;
228 
229 		case LSS|1:
230 			i = egetn(p1) <= egetn(p2);
231 			break;
232 		}
233 		xfree(p1), xfree(p2);
234 		return (putn(i));
235 	}
236 	return (p1);
237 }
238 
239 char *
240 exp3a(vp, ignore)
241 	register char ***vp;
242 	bool ignore;
243 {
244 	register char *p1, *p2, *op;
245 	register int i;
246 
247 	p1 = exp4(vp, ignore);
248 #ifdef EDEBUG
249 	etracc("exp3a p1", p1, vp);
250 #endif
251 	op = **vp;
252 	if (op && any(op[0], "<>") && op[0] == op[1]) {
253 		(*vp)++;
254 		p2 = exp3a(vp, ignore);
255 #ifdef EDEBUG
256 		etracc("exp3a p2", p2, vp);
257 #endif
258 		if (op[0] == '<')
259 			i = egetn(p1) << egetn(p2);
260 		else
261 			i = egetn(p1) >> egetn(p2);
262 		xfree(p1), xfree(p2);
263 		return (putn(i));
264 	}
265 	return (p1);
266 }
267 
268 char *
269 exp4(vp, ignore)
270 	register char ***vp;
271 	bool ignore;
272 {
273 	register char *p1, *p2;
274 	register int i = 0;
275 
276 	p1 = exp5(vp, ignore);
277 #ifdef EDEBUG
278 	etracc("exp4 p1", p1, vp);
279 #endif
280 	if (isa(**vp, ADDOP)) {
281 		register char *op = *(*vp)++;
282 
283 		p2 = exp4(vp, ignore);
284 #ifdef EDEBUG
285 		etracc("exp4 p2", p2, vp);
286 #endif
287 		if (!(ignore&IGNORE)) switch (op[0]) {
288 
289 		case '+':
290 			i = egetn(p1) + egetn(p2);
291 			break;
292 
293 		case '-':
294 			i = egetn(p1) - egetn(p2);
295 			break;
296 		}
297 		xfree(p1), xfree(p2);
298 		return (putn(i));
299 	}
300 	return (p1);
301 }
302 
303 char *
304 exp5(vp, ignore)
305 	register char ***vp;
306 	bool ignore;
307 {
308 	register char *p1, *p2;
309 	register int i = 0;
310 
311 	p1 = exp6(vp, ignore);
312 #ifdef EDEBUG
313 	etracc("exp5 p1", p1, vp);
314 #endif
315 	if (isa(**vp, MULOP)) {
316 		register char *op = *(*vp)++;
317 
318 		p2 = exp5(vp, ignore);
319 #ifdef EDEBUG
320 		etracc("exp5 p2", p2, vp);
321 #endif
322 		if (!(ignore&IGNORE)) switch (op[0]) {
323 
324 		case '*':
325 			i = egetn(p1) * egetn(p2);
326 			break;
327 
328 		case '/':
329 			i = egetn(p2);
330 			if (i == 0)
331 				error("Divide by 0");
332 			i = egetn(p1) / i;
333 			break;
334 
335 		case '%':
336 			i = egetn(p2);
337 			if (i == 0)
338 				error("Mod by 0");
339 			i = egetn(p1) % i;
340 			break;
341 		}
342 		xfree(p1), xfree(p2);
343 		return (putn(i));
344 	}
345 	return (p1);
346 }
347 
348 char *
349 exp6(vp, ignore)
350 	register char ***vp;
351 {
352 	int ccode, i;
353 	register char *cp, *dp, *ep;
354 
355 	if (**vp == 0)
356 		bferr("Expression syntax");
357 	if (eq(**vp, "!")) {
358 		(*vp)++;
359 		cp = exp6(vp, ignore);
360 #ifdef EDEBUG
361 		etracc("exp6 ! cp", cp, vp);
362 #endif
363 		i = egetn(cp);
364 		xfree(cp);
365 		return (putn(!i));
366 	}
367 	if (eq(**vp, "~")) {
368 		(*vp)++;
369 		cp = exp6(vp, ignore);
370 #ifdef EDEBUG
371 		etracc("exp6 ~ cp", cp, vp);
372 #endif
373 		i = egetn(cp);
374 		xfree(cp);
375 		return (putn(~i));
376 	}
377 	if (eq(**vp, "(")) {
378 		(*vp)++;
379 		ccode = exp0(vp, ignore);
380 #ifdef EDEBUG
381 		etraci("exp6 () ccode", ccode, vp);
382 #endif
383 		if (*vp == 0 || **vp == 0 || ***vp != ')')
384 			bferr("Expression syntax");
385 		(*vp)++;
386 		return (putn(ccode));
387 	}
388 	if (eq(**vp, "{")) {
389 		register char **v;
390 		struct command faket;
391 		char *fakecom[2];
392 
393 		faket.t_dtyp = TCOM;
394 		faket.t_dflg = 0;
395 		faket.t_dcar = faket.t_dcdr = faket.t_dspr = (struct command *)0;
396 		faket.t_dcom = fakecom;
397 		fakecom[0] = "{ ... }";
398 		fakecom[1] = NOSTR;
399 		(*vp)++;
400 		v = *vp;
401 		for (;;) {
402 			if (!**vp)
403 				bferr("Missing }");
404 			if (eq(*(*vp)++, "}"))
405 				break;
406 		}
407 		if (ignore&IGNORE)
408 			return ("");
409 		psavejob();
410 		if (pfork(&faket, -1) == 0) {
411 			*--(*vp) = 0;
412 			evalav(v);
413 			exitstat();
414 		}
415 		pwait();
416 		prestjob();
417 #ifdef EDEBUG
418 		etraci("exp6 {} status", egetn(value("status")), vp);
419 #endif
420 		return (putn(egetn(value("status")) == 0));
421 	}
422 	if (isa(**vp, ANYOP))
423 		return ("");
424 	cp = *(*vp)++;
425 	if (*cp == '-' && any(cp[1], "erwxfdzo")) {
426 		struct stat stb;
427 
428 		if (isa(**vp, ANYOP))
429 			bferr("Missing file name");
430 		dp = *(*vp)++;
431 		if (ignore&IGNORE)
432 			return ("");
433 		ep = globone(dp);
434 		switch (cp[1]) {
435 
436 		case 'r':
437 			i = !access(ep, 4);
438 			break;
439 
440 		case 'w':
441 			i = !access(ep, 2);
442 			break;
443 
444 		case 'x':
445 			i = !access(ep, 1);
446 			break;
447 
448 		default:
449 			if (stat(ep, &stb)) {
450 				xfree(ep);
451 				return ("0");
452 			}
453 			switch (cp[1]) {
454 
455 			case 'f':
456 				i = (stb.st_mode & S_IFMT) == S_IFREG;
457 				break;
458 
459 			case 'd':
460 				i = (stb.st_mode & S_IFMT) == S_IFDIR;
461 				break;
462 
463 			case 'z':
464 				i = stb.st_size == 0;
465 				break;
466 
467 			case 'e':
468 				i = 1;
469 				break;
470 
471 			case 'o':
472 				i = stb.st_uid == uid;
473 				break;
474 			}
475 		}
476 #ifdef EDEBUG
477 		etraci("exp6 -? i", i, vp);
478 #endif
479 		xfree(ep);
480 		return (putn(i));
481 	}
482 #ifdef EDEBUG
483 	etracc("exp6 default", cp, vp);
484 #endif
485 	return (ignore&NOGLOB ? savestr(cp) : globone(cp));
486 }
487 
488 evalav(v)
489 	register char **v;
490 {
491 	struct wordent paraml;
492 	register struct wordent *hp = &paraml;
493 	struct command *t;
494 	register struct wordent *wdp = hp;
495 
496 	set("status", "0");
497 	hp->prev = hp->next = hp;
498 	hp->word = "";
499 	while (*v) {
500 		register struct wordent *new = (struct wordent *) calloc(1, sizeof *wdp);
501 
502 		new->prev = wdp;
503 		new->next = hp;
504 		wdp->next = new;
505 		wdp = new;
506 		wdp->word = savestr(*v++);
507 	}
508 	hp->prev = wdp;
509 	alias(&paraml);
510 	t = syntax(paraml.next, &paraml, 0);
511 	if (err)
512 		error(err);
513 	execute(t, -1);
514 	freelex(&paraml), freesyn(t);
515 }
516 
517 isa(cp, what)
518 	register char *cp;
519 	register int what;
520 {
521 
522 	if (cp == 0)
523 		return ((what & RESTOP) != 0);
524 	if (cp[1] == 0) {
525 		if (what & ADDOP && (*cp == '+' || *cp == '-'))
526 			return (1);
527 		if (what & MULOP && (*cp == '*' || *cp == '/' || *cp == '%'))
528 			return (1);
529 		if (what & RESTOP && (*cp == '(' || *cp == ')' || *cp == '!' ||
530 				      *cp == '~' || *cp == '^' || *cp == '"'))
531 			return (1);
532 	} else if (cp[2] == 0) {
533 		if (what & RESTOP) {
534 			if (cp[0] == '|' && cp[1] == '&')
535 				return (1);
536 			if (cp[0] == '<' && cp[1] == '<')
537 				return (1);
538 			if (cp[0] == '>' && cp[1] == '>')
539 				return (1);
540 		}
541 		if (what & EQOP) {
542 			if (cp[0] == '=') {
543 				if (cp[1] == '=')
544 					return (EQEQ);
545 				if (cp[1] == '~')
546 					return (EQMATCH);
547 			} else if (cp[0] == '!') {
548 				if (cp[1] == '=')
549 					return (NOTEQ);
550 				if (cp[1] == '~')
551 					return (NOTEQMATCH);
552 			}
553 		}
554 	}
555 	if (what & RELOP) {
556 		if (*cp == '<')
557 			return (LSS);
558 		if (*cp == '>')
559 			return (GTR);
560 	}
561 	return (0);
562 }
563 
564 egetn(cp)
565 	register char *cp;
566 {
567 
568 	if (*cp && *cp != '-' && !digit(*cp))
569 		bferr("Expression syntax");
570 	return (getn(cp));
571 }
572 
573 /* Phew! */
574 
575 #ifdef EDEBUG
576 etraci(str, i, vp)
577 	char *str;
578 	int i;
579 	char ***vp;
580 {
581 
582 	printf("%s=%d\t", str, i);
583 	blkpr(*vp);
584 	printf("\n");
585 }
586 
587 etracc(str, cp, vp)
588 	char *str, *cp;
589 	char ***vp;
590 {
591 
592 	printf("%s=%s\t", str, cp);
593 	blkpr(*vp);
594 	printf("\n");
595 }
596 #endif
597