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