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"
19extern int	didchdir;
20
21/*
22 * C Shell
23 */
24
25void	asx(tchar *, int, tchar *);
26void	putn1(int);
27void	set(tchar *, tchar *);
28void	set1(tchar *, tchar **, struct varent *);
29void	setq(tchar *, tchar **, struct varent *);
30void	unset1(tchar *[], struct varent *);
31void	unsetv1(struct varent *);
32void	exportpath(tchar **);
33void	balance(struct varent *, int, int);
34tchar	*operate(tchar, tchar *, tchar *);
35tchar	*getinx(tchar *, int *);
36tchar	*xset(tchar *, tchar ***);
37struct varent	*getvx(tchar *, int);
38
39void
40doset(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 != '=')
85setsyn:
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
134tchar *
135getinx(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
150void
151asx(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
162struct varent *
163getvx(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
177tchar plusplus[2] = { '1', 0 };
178
179void
180dolet(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++;
226letsyn:
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
267tchar *
268xset(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
284tchar *
285operate(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
310static tchar *putp;
311
312tchar *
313putn(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
341void
342putn1(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
352int
353getn(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);
376badnum:
377	bferr("Badly formed number");
378	return (0);
379}
380
381tchar *
382value1(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
393struct varent *
394madrof(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
410struct varent *
411adrof1(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 */
431void
432set(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
444void
445set1(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	/*
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
475void
476setq(tchar *name, tchar **vec, struct varent *p)
477{
478	struct varent *c;
479	int f;
480
481#ifdef TRACE
482	tprintf("TRACE- setq()\n");
483#endif
484	f = 0;			/* tree hangs off the header's left link */
485	while (c = p->v_link[f]) {
486		if ((f = *name - *c->v_name) == 0 &&
487		    (f = strcmp_(name, c->v_name)) == 0) {
488			blkfree(c->vec);
489			goto found;
490		}
491		p = c;
492		f = f > 0;
493	}
494	p->v_link[f] = c = (struct varent *)xalloc(sizeof (struct varent));
495	c->v_name = savestr(name);
496	c->v_bal = 0;
497	c->v_left = c->v_right = 0;
498	c->v_parent = p;
499	balance(p, f, 0);
500found:
501	trim(c->vec = vec);
502}
503
504void
505unset(tchar *v[])
506{
507
508#ifdef TRACE
509	tprintf("TRACE- unset()\n");
510#endif
511	unset1(v, &shvhed);
512	if (adrof(S_histchars /* "histchars" */) == 0) {
513		HIST = '!';
514		HISTSUB = '^';
515	}
516#ifdef FILEC
517	if (adrof(S_filec /* "filec" */) == 0)
518		filec = 0;
519#endif
520}
521
522void
523unset1(tchar *v[], struct varent *head)
524{
525	struct varent *vp;
526	int cnt;
527
528#ifdef TRACE
529	tprintf("TRACE- unset1()\n");
530#endif
531	while (*++v) {
532		cnt = 0;
533		while (vp = madrof(*v, head->v_left))
534			unsetv1(vp), cnt++;
535		if (cnt == 0)
536			setname(*v);
537	}
538}
539
540void
541unsetv(tchar *var)
542{
543	struct varent *vp;
544
545#ifdef TRACE
546	tprintf("TRACE- unsetv()\n");
547#endif
548	if ((vp = adrof1(var, &shvhed)) == 0)
549		udvar(var);
550	unsetv1(vp);
551}
552
553void
554unsetv1(struct varent *p)
555{
556	struct varent *c, *pp;
557	int f;
558
559#ifdef TRACE
560	tprintf("TRACE- unsetv1()\n");
561#endif
562	/*
563	 * Free associated memory first to avoid complications.
564	 */
565	blkfree(p->vec);
566	xfree(p->v_name);
567	/*
568	 * If p is missing one child, then we can move the other
569	 * into where p is.  Otherwise, we find the predecessor
570	 * of p, which is guaranteed to have no right child, copy
571	 * it into p, and move it's left child into it.
572	 */
573	if (p->v_right == 0)
574		c = p->v_left;
575	else if (p->v_left == 0)
576		c = p->v_right;
577	else {
578		for (c = p->v_left; c->v_right; c = c->v_right)
579			;
580		p->v_name = c->v_name;
581		p->vec = c->vec;
582		p = c;
583		c = p->v_left;
584	}
585	/*
586	 * Move c into where p is.
587	 */
588	pp = p->v_parent;
589	f = pp->v_right == p;
590	if (pp->v_link[f] = c)
591		c->v_parent = pp;
592	/*
593	 * Free the deleted node, and rebalance.
594	 */
595	xfree(p);
596	balance(pp, f, 1);
597}
598
599void
600setNS(tchar *cp)
601{
602#ifdef TRACE
603	tprintf("TRACE- setNS()\n");
604#endif
605
606	set(cp, S_ /* "" */);
607}
608
609void
610shift(tchar **v)
611{
612	struct varent *argv;
613	tchar *name;
614
615#ifdef TRACE
616	tprintf("TRACE- shift()\n");
617#endif
618	v++;
619	name = *v;
620	if (name == 0)
621		name = S_argv /* "argv" */;
622	else
623		(void) strip(name);
624	argv = adrof(name);
625	if (argv == 0)
626		udvar(name);
627	if (argv->vec[0] == 0)
628		bferr("No more words");
629	lshift(argv->vec, 1);
630}
631
632void
633exportpath(tchar **val)
634{
635	tchar exppath[PATHSIZ];
636
637#ifdef TRACE
638	tprintf("TRACE- exportpath()\n");
639#endif
640	exppath[0] = 0;
641	if (val)
642		while (*val) {
643			if (strlen_(*val) + strlen_(exppath) + 2 > PATHSIZ) {
644				printf("Warning: ridiculously long PATH truncated\n");
645				break;
646			}
647			(void) strcat_(exppath, *val++);
648			if (*val == 0 || eq(*val, S_RPAR /* ")" */))
649				break;
650			(void) strcat_(exppath, S_COLON /* ":" */);
651		}
652	local_setenv(S_PATH /* "PATH" */, exppath);
653}
654
655	/* macros to do single rotations on node p */
656#define	rright(p) (\
657	t = (p)->v_left,\
658	(t)->v_parent = (p)->v_parent,\
659	((p)->v_left = t->v_right) ? (t->v_right->v_parent = (p)) : 0,\
660	(t->v_right = (p))->v_parent = t,\
661	(p) = t)
662#define	rleft(p) (\
663	t = (p)->v_right,\
664	(t)->v_parent = (p)->v_parent,\
665	((p)->v_right = t->v_left) ? (t->v_left->v_parent = (p)) : 0,\
666	(t->v_left = (p))->v_parent = t,\
667	(p) = t)
668
669/*
670 * Rebalance a tree, starting at p and up.
671 * F == 0 means we've come from p's left child.
672 * D == 1 means we've just done a delete, otherwise an insert.
673 */
674void
675balance(struct varent *p, int f, int d)
676{
677	struct varent *pp;
678	struct varent *t;		/* used by the rotate macros */
679	int ff;
680
681#ifdef TRACE
682	tprintf("TRACE- balance()\n");
683#endif
684	/*
685	 * Ok, from here on, p is the node we're operating on;
686	 * pp is it's parent; f is the branch of p from which we have come;
687	 * ff is the branch of pp which is p.
688	 */
689	for (; pp = p->v_parent; p = pp, f = ff) {
690		ff = pp->v_right == p;
691		if (f ^ d) {		/* right heavy */
692			switch (p->v_bal) {
693			case -1:		/* was left heavy */
694				p->v_bal = 0;
695				break;
696			case 0:			/* was balanced */
697				p->v_bal = 1;
698				break;
699			case 1:			/* was already right heavy */
700				switch (p->v_right->v_bal) {
701				case 1:			/* sigle rotate */
702					pp->v_link[ff] = rleft(p);
703					p->v_left->v_bal = 0;
704					p->v_bal = 0;
705					break;
706				case 0:			/* single rotate */
707					pp->v_link[ff] = rleft(p);
708					p->v_left->v_bal = 1;
709					p->v_bal = -1;
710					break;
711				case -1:		/* double rotate */
712					rright(p->v_right);
713					pp->v_link[ff] = rleft(p);
714					p->v_left->v_bal =
715						p->v_bal < 1 ? 0 : -1;
716					p->v_right->v_bal =
717						p->v_bal > -1 ? 0 : 1;
718					p->v_bal = 0;
719					break;
720				}
721				break;
722			}
723		} else {		/* left heavy */
724			switch (p->v_bal) {
725			case 1:			/* was right heavy */
726				p->v_bal = 0;
727				break;
728			case 0:			/* was balanced */
729				p->v_bal = -1;
730				break;
731			case -1:		/* was already left heavy */
732				switch (p->v_left->v_bal) {
733				case -1:		/* single rotate */
734					pp->v_link[ff] = rright(p);
735					p->v_right->v_bal = 0;
736					p->v_bal = 0;
737					break;
738				case 0:			/* signle rotate */
739					pp->v_link[ff] = rright(p);
740					p->v_right->v_bal = -1;
741					p->v_bal = 1;
742					break;
743				case 1:			/* double rotate */
744					rleft(p->v_left);
745					pp->v_link[ff] = rright(p);
746					p->v_left->v_bal =
747						p->v_bal < 1 ? 0 : -1;
748					p->v_right->v_bal =
749						p->v_bal > -1 ? 0 : 1;
750					p->v_bal = 0;
751					break;
752				}
753				break;
754			}
755		}
756		/*
757		 * If from insert, then we terminate when p is balanced.
758		 * If from delete, then we terminate when p is unbalanced.
759		 */
760		if ((p->v_bal == 0) ^ d)
761			break;
762	}
763}
764
765void
766plist(struct varent *p)
767{
768	struct varent *c;
769	int len;
770
771#ifdef TRACE
772	tprintf("TRACE- plist()\n");
773#endif
774	if (setintr)
775		(void) sigsetmask(sigblock(0) & ~ sigmask(SIGINT));
776	for (;;) {
777		while (p->v_left)
778			p = p->v_left;
779	x:
780		if (p->v_parent == 0)		/* is it the header? */
781			return;
782		len = blklen(p->vec);
783		printf("%t", p->v_name);
784		Putchar('\t');
785		if (len != 1)
786			Putchar('(');
787		blkpr(p->vec);
788		if (len != 1)
789			Putchar(')');
790		Putchar('\n');
791		if (p->v_right) {
792			p = p->v_right;
793			continue;
794		}
795		do {
796			c = p;
797			p = p->v_parent;
798		} while (p->v_right == c);
799		goto x;
800	}
801}
802