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