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