xref: /original-bsd/bin/csh/set.c (revision 5d3a6356)
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 = "@(#)set.c	5.3 (Berkeley) 05/19/88";
9 #endif
10 
11 #include "sh.h"
12 
13 /*
14  * C Shell
15  */
16 
17 doset(v)
18 	register char **v;
19 {
20 	register char *p;
21 	char *vp, op;
22 	char **vecp;
23 	bool hadsub;
24 	int subscr;
25 
26 	v++;
27 	p = *v++;
28 	if (p == 0) {
29 		prvars();
30 		return;
31 	}
32 	do {
33 		hadsub = 0;
34 		for (vp = p; alnum(*p); p++)
35 			continue;
36 		if (vp == p || !letter(*vp))
37 			goto setsyn;
38 		if (*p == '[') {
39 			hadsub++;
40 			p = getinx(p, &subscr);
41 		}
42 		if (op = *p) {
43 			*p++ = 0;
44 			if (*p == 0 && *v && **v == '(')
45 				p = *v++;
46 		} else if (*v && eq(*v, "=")) {
47 			op = '=', v++;
48 			if (*v)
49 				p = *v++;
50 		}
51 		if (op && op != '=')
52 setsyn:
53 			bferr("Syntax error");
54 		if (eq(p, "(")) {
55 			register char **e = v;
56 
57 			if (hadsub)
58 				goto setsyn;
59 			for (;;) {
60 				if (!*e)
61 					bferr("Missing )");
62 				if (**e == ')')
63 					break;
64 				e++;
65 			}
66 			p = *e;
67 			*e = 0;
68 			vecp = saveblk(v);
69 			set1(vp, vecp, &shvhed);
70 			*e = p;
71 			v = e + 1;
72 		} else if (hadsub)
73 			asx(vp, subscr, savestr(p));
74 		else
75 			set(vp, savestr(p));
76 		if (eq(vp, "path")) {
77 			exportpath(adrof("path")->vec);
78 			dohash();
79 		} else if (eq(vp, "histchars")) {
80 			register char *p = value("histchars");
81 
82 			HIST = *p++;
83 			HISTSUB = *p;
84 		} else if (eq(vp, "user"))
85 			setenv("USER", value(vp));
86 		else if (eq(vp, "term"))
87 			setenv("TERM", value(vp));
88 		else if (eq(vp, "home"))
89 			setenv("HOME", value(vp));
90 #ifdef FILEC
91 		else if (eq(vp, "filec"))
92 			filec = 1;
93 #endif
94 	} while (p = *v++);
95 }
96 
97 char *
98 getinx(cp, ip)
99 	register char *cp;
100 	register int *ip;
101 {
102 
103 	*ip = 0;
104 	*cp++ = 0;
105 	while (*cp && digit(*cp))
106 		*ip = *ip * 10 + *cp++ - '0';
107 	if (*cp++ != ']')
108 		bferr("Subscript error");
109 	return (cp);
110 }
111 
112 asx(vp, subscr, p)
113 	char *vp;
114 	int subscr;
115 	char *p;
116 {
117 	register struct varent *v = getvx(vp, subscr);
118 
119 	xfree(v->vec[subscr - 1]);
120 	v->vec[subscr - 1] = globone(p);
121 }
122 
123 struct varent *
124 getvx(vp, subscr)
125 	char *vp;
126 {
127 	register struct varent *v = adrof(vp);
128 
129 	if (v == 0)
130 		udvar(vp);
131 	if (subscr < 1 || subscr > blklen(v->vec))
132 		bferr("Subscript out of range");
133 	return (v);
134 }
135 
136 char	plusplus[2] = { '1', 0 };
137 
138 dolet(v)
139 	char **v;
140 {
141 	register char *p;
142 	char *vp, c, op;
143 	bool hadsub;
144 	int subscr;
145 
146 	v++;
147 	p = *v++;
148 	if (p == 0) {
149 		prvars();
150 		return;
151 	}
152 	do {
153 		hadsub = 0;
154 		for (vp = p; alnum(*p); p++)
155 			continue;
156 		if (vp == p || !letter(*vp))
157 			goto letsyn;
158 		if (*p == '[') {
159 			hadsub++;
160 			p = getinx(p, &subscr);
161 		}
162 		if (*p == 0 && *v)
163 			p = *v++;
164 		if (op = *p)
165 			*p++ = 0;
166 		else
167 			goto letsyn;
168 		vp = savestr(vp);
169 		if (op == '=') {
170 			c = '=';
171 			p = xset(p, &v);
172 		} else {
173 			c = *p++;
174 			if (any(c, "+-")) {
175 				if (c != op || *p)
176 					goto letsyn;
177 				p = plusplus;
178 			} else {
179 				if (any(op, "<>")) {
180 					if (c != op)
181 						goto letsyn;
182 					c = *p++;
183 letsyn:
184 					bferr("Syntax error");
185 				}
186 				if (c != '=')
187 					goto letsyn;
188 				p = xset(p, &v);
189 			}
190 		}
191 		if (op == '=')
192 			if (hadsub)
193 				asx(vp, subscr, p);
194 			else
195 				set(vp, p);
196 		else
197 			if (hadsub)
198 #ifndef V6
199 				/* avoid bug in vax CC */
200 				{
201 					struct varent *gv = getvx(vp, subscr);
202 
203 					asx(vp, subscr, operate(op, gv->vec[subscr - 1], p));
204 				}
205 #else
206 				asx(vp, subscr, operate(op, getvx(vp, subscr)->vec[subscr - 1], p));
207 #endif
208 			else
209 				set(vp, operate(op, value(vp), p));
210 		if (eq(vp, "path")) {
211 			exportpath(adrof("path")->vec);
212 			dohash();
213 		}
214 		XFREE(vp)
215 		if (c != '=')
216 			XFREE(p)
217 	} while (p = *v++);
218 }
219 
220 char *
221 xset(cp, vp)
222 	char *cp, ***vp;
223 {
224 	register char *dp;
225 
226 	if (*cp) {
227 		dp = savestr(cp);
228 		--(*vp);
229 		xfree(**vp);
230 		**vp = dp;
231 	}
232 	return (putn(exp(vp)));
233 }
234 
235 char *
236 operate(op, vp, p)
237 	char op, *vp, *p;
238 {
239 	char opr[2];
240 	char *vec[5];
241 	register char **v = vec;
242 	char **vecp = v;
243 	register int i;
244 
245 	if (op != '=') {
246 		if (*vp)
247 			*v++ = vp;
248 		opr[0] = op;
249 		opr[1] = 0;
250 		*v++ = opr;
251 		if (op == '<' || op == '>')
252 			*v++ = opr;
253 	}
254 	*v++ = p;
255 	*v++ = 0;
256 	i = exp(&vecp);
257 	if (*vecp)
258 		bferr("Expression syntax");
259 	return (putn(i));
260 }
261 
262 static	char *putp;
263 
264 char *
265 putn(n)
266 	register int n;
267 {
268 	static char number[15];
269 
270 	putp = number;
271 	if (n < 0) {
272 		n = -n;
273 		*putp++ = '-';
274 	}
275 	if (sizeof (int) == 2 && n == -32768) {
276 		*putp++ = '3';
277 		n = 2768;
278 #ifdef pdp11
279 	}
280 #else
281 	} else if (sizeof (int) == 4 && n == -2147483648) {
282 		*putp++ = '2';
283 		n = 147483648;
284 	}
285 #endif
286 	putn1(n);
287 	*putp = 0;
288 	return (savestr(number));
289 }
290 
291 putn1(n)
292 	register int n;
293 {
294 	if (n > 9)
295 		putn1(n / 10);
296 	*putp++ = n % 10 + '0';
297 }
298 
299 getn(cp)
300 	register char *cp;
301 {
302 	register int n;
303 	int sign;
304 
305 	sign = 0;
306 	if (cp[0] == '+' && cp[1])
307 		cp++;
308 	if (*cp == '-') {
309 		sign++;
310 		cp++;
311 		if (!digit(*cp))
312 			goto badnum;
313 	}
314 	n = 0;
315 	while (digit(*cp))
316 		n = n * 10 + *cp++ - '0';
317 	if (*cp)
318 		goto badnum;
319 	return (sign ? -n : n);
320 badnum:
321 	bferr("Badly formed number");
322 	return (0);
323 }
324 
325 char *
326 value1(var, head)
327 	char *var;
328 	struct varent *head;
329 {
330 	register struct varent *vp;
331 
332 	vp = adrof1(var, head);
333 	return (vp == 0 || vp->vec[0] == 0 ? "" : vp->vec[0]);
334 }
335 
336 struct varent *
337 madrof(pat, vp)
338 	char *pat;
339 	register struct varent *vp;
340 {
341 	register struct varent *vp1;
342 
343 	for (; vp; vp = vp->v_right) {
344 		if (vp->v_left && (vp1 = madrof(pat, vp->v_left)))
345 			return vp1;
346 		if (Gmatch(vp->v_name, pat))
347 			return vp;
348 	}
349 	return vp;
350 }
351 
352 struct varent *
353 adrof1(name, v)
354 	register char *name;
355 	register struct varent *v;
356 {
357 	register cmp;
358 
359 	v = v->v_left;
360 	while (v && ((cmp = *name - *v->v_name) ||
361 		     (cmp = strcmp(name, v->v_name))))
362 		if (cmp < 0)
363 			v = v->v_left;
364 		else
365 			v = v->v_right;
366 	return v;
367 }
368 
369 /*
370  * The caller is responsible for putting value in a safe place
371  */
372 set(var, val)
373 	char *var, *val;
374 {
375 	register char **vec = (char **) xalloc(2 * sizeof (char **));
376 
377 	vec[0] = onlyread(val) ? savestr(val) : val;
378 	vec[1] = 0;
379 	set1(var, vec, &shvhed);
380 }
381 
382 set1(var, vec, head)
383 	char *var, **vec;
384 	struct varent *head;
385 {
386 	register char **oldv = vec;
387 
388 	gflag = 0; tglob(oldv);
389 	if (gflag) {
390 		vec = glob(oldv);
391 		if (vec == 0) {
392 			bferr("No match");
393 			blkfree(oldv);
394 			return;
395 		}
396 		blkfree(oldv);
397 		gargv = 0;
398 	}
399 	setq(var, vec, head);
400 }
401 
402 setq(name, vec, p)
403 	char *name, **vec;
404 	register struct varent *p;
405 {
406 	register struct varent *c;
407 	register f;
408 
409 	f = 0;			/* tree hangs off the header's left link */
410 	while (c = p->v_link[f]) {
411 		if ((f = *name - *c->v_name) == 0 &&
412 		    (f = strcmp(name, c->v_name)) == 0) {
413 			blkfree(c->vec);
414 			goto found;
415 		}
416 		p = c;
417 		f = f > 0;
418 	}
419 	p->v_link[f] = c = (struct varent *)xalloc(sizeof (struct varent));
420 	c->v_name = savestr(name);
421 	c->v_bal = 0;
422 	c->v_left = c->v_right = 0;
423 	c->v_parent = p;
424 	balance(p, f, 0);
425 found:
426 	trim(c->vec = vec);
427 }
428 
429 unset(v)
430 	char *v[];
431 {
432 
433 	unset1(v, &shvhed);
434 	if (adrof("histchars") == 0) {
435 		HIST = '!';
436 		HISTSUB = '^';
437 	}
438 #ifdef FILEC
439 	if (adrof("filec") == 0)
440 		filec = 0;
441 #endif
442 }
443 
444 unset1(v, head)
445 	register char *v[];
446 	struct varent *head;
447 {
448 	register struct varent *vp;
449 	register int cnt;
450 
451 	while (*++v) {
452 		cnt = 0;
453 		while (vp = madrof(*v, head->v_left))
454 			unsetv1(vp), cnt++;
455 		if (cnt == 0)
456 			setname(*v);
457 	}
458 }
459 
460 unsetv(var)
461 	char *var;
462 {
463 	register struct varent *vp;
464 
465 	if ((vp = adrof1(var, &shvhed)) == 0)
466 		udvar(var);
467 	unsetv1(vp);
468 }
469 
470 unsetv1(p)
471 	register struct varent *p;
472 {
473 	register struct varent *c, *pp;
474 	register f;
475 
476 	/*
477 	 * Free associated memory first to avoid complications.
478 	 */
479 	blkfree(p->vec);
480 	XFREE(p->v_name);
481 	/*
482 	 * If p is missing one child, then we can move the other
483 	 * into where p is.  Otherwise, we find the predecessor
484 	 * of p, which is guaranteed to have no right child, copy
485 	 * it into p, and move it's left child into it.
486 	 */
487 	if (p->v_right == 0)
488 		c = p->v_left;
489 	else if (p->v_left == 0)
490 		c = p->v_right;
491 	else {
492 		for (c = p->v_left; c->v_right; c = c->v_right)
493 			;
494 		p->v_name = c->v_name;
495 		p->vec = c->vec;
496 		p = c;
497 		c = p->v_left;
498 	}
499 	/*
500 	 * Move c into where p is.
501 	 */
502 	pp = p->v_parent;
503 	f = pp->v_right == p;
504 	if (pp->v_link[f] = c)
505 		c->v_parent = pp;
506 	/*
507 	 * Free the deleted node, and rebalance.
508 	 */
509 	XFREE((char *)p);
510 	balance(pp, f, 1);
511 }
512 
513 setNS(cp)
514 	char *cp;
515 {
516 
517 	set(cp, "");
518 }
519 
520 shift(v)
521 	register char **v;
522 {
523 	register struct varent *argv;
524 	register char *name;
525 
526 	v++;
527 	name = *v;
528 	if (name == 0)
529 		name = "argv";
530 	else
531 		(void) strip(name);
532 	argv = adrof(name);
533 	if (argv == 0)
534 		udvar(name);
535 	if (argv->vec[0] == 0)
536 		bferr("No more words");
537 	lshift(argv->vec, 1);
538 }
539 
540 exportpath(val)
541 char **val;
542 {
543 	char exppath[BUFSIZ];
544 
545 	exppath[0] = 0;
546 	if (val)
547 		while (*val) {
548 			if (strlen(*val) + strlen(exppath) + 2 > BUFSIZ) {
549 				printf("Warning: ridiculously long PATH truncated\n");
550 				break;
551 			}
552 			(void) strcat(exppath, *val++);
553 			if (*val == 0 || eq(*val, ")"))
554 				break;
555 			(void) strcat(exppath, ":");
556 		}
557 	setenv("PATH", exppath);
558 }
559 
560 	/* macros to do single rotations on node p */
561 #define rright(p) (\
562 	t = (p)->v_left,\
563 	(t)->v_parent = (p)->v_parent,\
564 	((p)->v_left = t->v_right) ? (t->v_right->v_parent = (p)) : 0,\
565 	(t->v_right = (p))->v_parent = t,\
566 	(p) = t)
567 #define rleft(p) (\
568 	t = (p)->v_right,\
569 	(t)->v_parent = (p)->v_parent,\
570 	((p)->v_right = t->v_left) ? (t->v_left->v_parent = (p)) : 0,\
571 	(t->v_left = (p))->v_parent = t,\
572 	(p) = t)
573 
574 /*
575  * Rebalance a tree, starting at p and up.
576  * F == 0 means we've come from p's left child.
577  * D == 1 means we've just done a delete, otherwise an insert.
578  */
579 balance(p, f, d)
580 	register struct varent *p;
581 	register f;
582 {
583 	register struct varent *pp;
584 	register struct varent *t;		/* used by the rotate macros */
585 	register ff;
586 
587 	/*
588 	 * Ok, from here on, p is the node we're operating on;
589 	 * pp is it's parent; f is the branch of p from which we have come;
590 	 * ff is the branch of pp which is p.
591 	 */
592 	for (; pp = p->v_parent; p = pp, f = ff) {
593 		ff = pp->v_right == p;
594 		if (f ^ d) {		/* right heavy */
595 			switch (p->v_bal) {
596 			case -1:		/* was left heavy */
597 				p->v_bal = 0;
598 				break;
599 			case 0:			/* was balanced */
600 				p->v_bal = 1;
601 				break;
602 			case 1:			/* was already right heavy */
603 				switch (p->v_right->v_bal) {
604 				case 1:			/* sigle rotate */
605 					pp->v_link[ff] = rleft(p);
606 					p->v_left->v_bal = 0;
607 					p->v_bal = 0;
608 					break;
609 				case 0:			/* single rotate */
610 					pp->v_link[ff] = rleft(p);
611 					p->v_left->v_bal = 1;
612 					p->v_bal = -1;
613 					break;
614 				case -1:		/* double rotate */
615 					rright(p->v_right);
616 					pp->v_link[ff] = rleft(p);
617 					p->v_left->v_bal =
618 						p->v_bal < 1 ? 0 : -1;
619 					p->v_right->v_bal =
620 						p->v_bal > -1 ? 0 : 1;
621 					p->v_bal = 0;
622 					break;
623 				}
624 				break;
625 			}
626 		} else {		/* left heavy */
627 			switch (p->v_bal) {
628 			case 1:			/* was right heavy */
629 				p->v_bal = 0;
630 				break;
631 			case 0:			/* was balanced */
632 				p->v_bal = -1;
633 				break;
634 			case -1:		/* was already left heavy */
635 				switch (p->v_left->v_bal) {
636 				case -1:		/* single rotate */
637 					pp->v_link[ff] = rright(p);
638 					p->v_right->v_bal = 0;
639 					p->v_bal = 0;
640 					break;
641 				case 0:			/* signle rotate */
642 					pp->v_link[ff] = rright(p);
643 					p->v_right->v_bal = -1;
644 					p->v_bal = 1;
645 					break;
646 				case 1:			/* double rotate */
647 					rleft(p->v_left);
648 					pp->v_link[ff] = rright(p);
649 					p->v_left->v_bal =
650 						p->v_bal < 1 ? 0 : -1;
651 					p->v_right->v_bal =
652 						p->v_bal > -1 ? 0 : 1;
653 					p->v_bal = 0;
654 					break;
655 				}
656 				break;
657 			}
658 		}
659 		/*
660 		 * If from insert, then we terminate when p is balanced.
661 		 * If from delete, then we terminate when p is unbalanced.
662 		 */
663 		if ((p->v_bal == 0) ^ d)
664 			break;
665 	}
666 }
667 
668 plist(p)
669 	register struct varent *p;
670 {
671 	register struct varent *c;
672 	register len;
673 
674 	if (setintr)
675 		(void) sigsetmask(sigblock(0) & ~ sigmask(SIGINT));
676 	for (;;) {
677 		while (p->v_left)
678 			p = p->v_left;
679 	x:
680 		if (p->v_parent == 0)		/* is it the header? */
681 			return;
682 		len = blklen(p->vec);
683 		printf(p->v_name);
684 		cshputchar('\t');
685 		if (len != 1)
686 			cshputchar('(');
687 		blkpr(p->vec);
688 		if (len != 1)
689 			cshputchar(')');
690 		cshputchar('\n');
691 		if (p->v_right) {
692 			p = p->v_right;
693 			continue;
694 		}
695 		do {
696 			c = p;
697 			p = p->v_parent;
698 		} while (p->v_right == c);
699 		goto x;
700 	}
701 }
702