xref: /original-bsd/bin/csh/set.c (revision 58b1b499)
1 /*-
2  * Copyright (c) 1980, 1991, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char sccsid[] = "@(#)set.c	8.2 (Berkeley) 03/22/95";
10 #endif /* not lint */
11 
12 #include <sys/types.h>
13 #include <stdlib.h>
14 #ifndef SHORT_STRINGS
15 #include <string.h>
16 #endif /* SHORT_STRINGS */
17 #if __STDC__
18 # include <stdarg.h>
19 #else
20 # include <varargs.h>
21 #endif
22 
23 #include "csh.h"
24 #include "extern.h"
25 
26 static Char	*getinx __P((Char *, int *));
27 static void	 asx __P((Char *, int, Char *));
28 static struct varent
29 		*getvx __P((Char *, int));
30 static Char	*xset __P((Char *, Char ***));
31 static Char	*operate __P((int, Char *, Char *));
32 static void	 putn1 __P((int));
33 static struct varent
34 		*madrof __P((Char *, struct varent *));
35 static void	 unsetv1 __P((struct varent *));
36 static void	 exportpath __P((Char **));
37 static void	 balance __P((struct varent *, int, int));
38 
39 
40 /*
41  * C Shell
42  */
43 
44 void
45 /*ARGSUSED*/
46 doset(v, t)
47     Char **v;
48     struct command *t;
49 {
50     register Char *p;
51     Char   *vp, op;
52     Char  **vecp;
53     bool    hadsub;
54     int     subscr;
55 
56     v++;
57     p = *v++;
58     if (p == 0) {
59 	prvars();
60 	return;
61     }
62     do {
63 	hadsub = 0;
64 	vp = p;
65 	if (letter(*p))
66 	    for (; alnum(*p); p++)
67 		continue;
68 	if (vp == p || !letter(*vp))
69 	    stderror(ERR_NAME | ERR_VARBEGIN);
70 	if ((p - vp) > MAXVARLEN) {
71 	    stderror(ERR_NAME | ERR_VARTOOLONG);
72 	    return;
73 	}
74 	if (*p == '[') {
75 	    hadsub++;
76 	    p = getinx(p, &subscr);
77 	}
78 	if ((op = *p) != '\0') {
79 	    *p++ = 0;
80 	    if (*p == 0 && *v && **v == '(')
81 		p = *v++;
82 	}
83 	else if (*v && eq(*v, STRequal)) {
84 	    op = '=', v++;
85 	    if (*v)
86 		p = *v++;
87 	}
88 	if (op && op != '=')
89 	    stderror(ERR_NAME | ERR_SYNTAX);
90 	if (eq(p, STRLparen)) {
91 	    register Char **e = v;
92 
93 	    if (hadsub)
94 		stderror(ERR_NAME | ERR_SYNTAX);
95 	    for (;;) {
96 		if (!*e)
97 		    stderror(ERR_NAME | ERR_MISSING, ')');
98 		if (**e == ')')
99 		    break;
100 		e++;
101 	    }
102 	    p = *e;
103 	    *e = 0;
104 	    vecp = saveblk(v);
105 	    set1(vp, vecp, &shvhed);
106 	    *e = p;
107 	    v = e + 1;
108 	}
109 	else if (hadsub)
110 	    asx(vp, subscr, Strsave(p));
111 	else
112 	    set(vp, Strsave(p));
113 	if (eq(vp, STRpath)) {
114 	    exportpath(adrof(STRpath)->vec);
115 	    dohash(NULL, NULL);
116 	}
117 	else if (eq(vp, STRhistchars)) {
118 	    register Char *pn = value(STRhistchars);
119 
120 	    HIST = *pn++;
121 	    HISTSUB = *pn;
122 	}
123 	else if (eq(vp, STRuser)) {
124 	    Setenv(STRUSER, value(vp));
125 	    Setenv(STRLOGNAME, value(vp));
126 	}
127 	else if (eq(vp, STRwordchars)) {
128 	    word_chars = value(vp);
129 	}
130 	else if (eq(vp, STRterm))
131 	    Setenv(STRTERM, value(vp));
132 	else if (eq(vp, STRhome)) {
133 	    register Char *cp;
134 
135 	    cp = Strsave(value(vp));	/* get the old value back */
136 
137 	    /*
138 	     * convert to cononical pathname (possibly resolving symlinks)
139 	     */
140 	    cp = dcanon(cp, cp);
141 
142 	    set(vp, Strsave(cp));	/* have to save the new val */
143 
144 	    /* and now mirror home with HOME */
145 	    Setenv(STRHOME, cp);
146 	    /* fix directory stack for new tilde home */
147 	    dtilde();
148 	    xfree((ptr_t) cp);
149 	}
150 #ifdef FILEC
151 	else if (eq(vp, STRfilec))
152 	    filec = 1;
153 #endif
154     } while ((p = *v++) != NULL);
155 }
156 
157 static Char *
158 getinx(cp, ip)
159     register Char *cp;
160     register int *ip;
161 {
162 
163     *ip = 0;
164     *cp++ = 0;
165     while (*cp && Isdigit(*cp))
166 	*ip = *ip * 10 + *cp++ - '0';
167     if (*cp++ != ']')
168 	stderror(ERR_NAME | ERR_SUBSCRIPT);
169     return (cp);
170 }
171 
172 static void
173 asx(vp, subscr, p)
174     Char   *vp;
175     int     subscr;
176     Char   *p;
177 {
178     register struct varent *v = getvx(vp, subscr);
179 
180     xfree((ptr_t) v->vec[subscr - 1]);
181     v->vec[subscr - 1] = globone(p, G_APPEND);
182 }
183 
184 static struct varent *
185 getvx(vp, subscr)
186     Char   *vp;
187     int     subscr;
188 {
189     register struct varent *v = adrof(vp);
190 
191     if (v == 0)
192 	udvar(vp);
193     if (subscr < 1 || subscr > blklen(v->vec))
194 	stderror(ERR_NAME | ERR_RANGE);
195     return (v);
196 }
197 
198 void
199 /*ARGSUSED*/
200 dolet(v, t)
201     Char **v;
202     struct command *t;
203 {
204     register Char *p;
205     Char   *vp, c, op;
206     bool    hadsub;
207     int     subscr;
208 
209     v++;
210     p = *v++;
211     if (p == 0) {
212 	prvars();
213 	return;
214     }
215     do {
216 	hadsub = 0;
217 	vp = p;
218 	if (letter(*p))
219 	    for (; alnum(*p); p++)
220 		continue;
221 	if (vp == p || !letter(*vp))
222 	    stderror(ERR_NAME | ERR_VARBEGIN);
223 	if ((p - vp) > MAXVARLEN)
224 	    stderror(ERR_NAME | ERR_VARTOOLONG);
225 	if (*p == '[') {
226 	    hadsub++;
227 	    p = getinx(p, &subscr);
228 	}
229 	if (*p == 0 && *v)
230 	    p = *v++;
231 	if ((op = *p) != '\0')
232 	    *p++ = 0;
233 	else
234 	    stderror(ERR_NAME | ERR_ASSIGN);
235 
236 	if (*p == '\0' && *v == NULL)
237 	    stderror(ERR_NAME | ERR_ASSIGN);
238 
239 	vp = Strsave(vp);
240 	if (op == '=') {
241 	    c = '=';
242 	    p = xset(p, &v);
243 	}
244 	else {
245 	    c = *p++;
246 	    if (any("+-", c)) {
247 		if (c != op || *p)
248 		    stderror(ERR_NAME | ERR_UNKNOWNOP);
249 		p = Strsave(STR1);
250 	    }
251 	    else {
252 		if (any("<>", op)) {
253 		    if (c != op)
254 			stderror(ERR_NAME | ERR_UNKNOWNOP);
255 		    c = *p++;
256 		    stderror(ERR_NAME | ERR_SYNTAX);
257 		}
258 		if (c != '=')
259 		    stderror(ERR_NAME | ERR_UNKNOWNOP);
260 		p = xset(p, &v);
261 	    }
262 	}
263 	if (op == '=')
264 	    if (hadsub)
265 		asx(vp, subscr, p);
266 	    else
267 		set(vp, p);
268 	else if (hadsub) {
269 	    struct varent *gv = getvx(vp, subscr);
270 
271 	    asx(vp, subscr, operate(op, gv->vec[subscr - 1], p));
272 	}
273 	else
274 	    set(vp, operate(op, value(vp), p));
275 	if (eq(vp, STRpath)) {
276 	    exportpath(adrof(STRpath)->vec);
277 	    dohash(NULL, NULL);
278 	}
279 	xfree((ptr_t) vp);
280 	if (c != '=')
281 	    xfree((ptr_t) p);
282     } while ((p = *v++) != NULL);
283 }
284 
285 static Char *
286 xset(cp, vp)
287     Char   *cp, ***vp;
288 {
289     register Char *dp;
290 
291     if (*cp) {
292 	dp = Strsave(cp);
293 	--(*vp);
294 	xfree((ptr_t) ** vp);
295 	**vp = dp;
296     }
297     return (putn(expr(vp)));
298 }
299 
300 static Char *
301 operate(op, vp, p)
302     int    op;
303     Char  *vp, *p;
304 {
305     Char    opr[2];
306     Char   *vec[5];
307     register Char **v = vec;
308     Char  **vecp = v;
309     register int i;
310 
311     if (op != '=') {
312 	if (*vp)
313 	    *v++ = vp;
314 	opr[0] = op;
315 	opr[1] = 0;
316 	*v++ = opr;
317 	if (op == '<' || op == '>')
318 	    *v++ = opr;
319     }
320     *v++ = p;
321     *v++ = 0;
322     i = expr(&vecp);
323     if (*vecp)
324 	stderror(ERR_NAME | ERR_EXPRESSION);
325     return (putn(i));
326 }
327 
328 static Char *putp;
329 
330 Char   *
331 putn(n)
332     register int n;
333 {
334     int     num;
335     static Char number[15];
336 
337     putp = number;
338     if (n < 0) {
339 	n = -n;
340 	*putp++ = '-';
341     }
342     num = 2;			/* confuse lint */
343     if (sizeof(int) == num && ((unsigned int) n) == 0x8000) {
344 	*putp++ = '3';
345 	n = 2768;
346 #ifdef pdp11
347     }
348 #else
349     }
350     else {
351 	num = 4;		/* confuse lint */
352 	if (sizeof(int) == num && ((unsigned int) n) == 0x80000000) {
353 	    *putp++ = '2';
354 	    n = 147483648;
355 	}
356     }
357 #endif
358     putn1(n);
359     *putp = 0;
360     return (Strsave(number));
361 }
362 
363 static void
364 putn1(n)
365     register int n;
366 {
367     if (n > 9)
368 	putn1(n / 10);
369     *putp++ = n % 10 + '0';
370 }
371 
372 int
373 getn(cp)
374     register Char *cp;
375 {
376     register int n;
377     int     sign;
378 
379     sign = 0;
380     if (cp[0] == '+' && cp[1])
381 	cp++;
382     if (*cp == '-') {
383 	sign++;
384 	cp++;
385 	if (!Isdigit(*cp))
386 	    stderror(ERR_NAME | ERR_BADNUM);
387     }
388     n = 0;
389     while (Isdigit(*cp))
390 	n = n * 10 + *cp++ - '0';
391     if (*cp)
392 	stderror(ERR_NAME | ERR_BADNUM);
393     return (sign ? -n : n);
394 }
395 
396 Char   *
397 value1(var, head)
398     Char   *var;
399     struct varent *head;
400 {
401     register struct varent *vp;
402 
403     vp = adrof1(var, head);
404     return (vp == 0 || vp->vec[0] == 0 ? STRNULL : vp->vec[0]);
405 }
406 
407 static struct varent *
408 madrof(pat, vp)
409     Char   *pat;
410     register struct varent *vp;
411 {
412     register struct varent *vp1;
413 
414     for (; vp; vp = vp->v_right) {
415 	if (vp->v_left && (vp1 = madrof(pat, vp->v_left)))
416 	    return vp1;
417 	if (Gmatch(vp->v_name, pat))
418 	    return vp;
419     }
420     return vp;
421 }
422 
423 struct varent *
424 adrof1(name, v)
425     register Char *name;
426     register struct varent *v;
427 {
428     register cmp;
429 
430     v = v->v_left;
431     while (v && ((cmp = *name - *v->v_name) ||
432 		 (cmp = Strcmp(name, v->v_name))))
433 	if (cmp < 0)
434 	    v = v->v_left;
435 	else
436 	    v = v->v_right;
437     return v;
438 }
439 
440 /*
441  * The caller is responsible for putting value in a safe place
442  */
443 void
444 set(var, val)
445     Char   *var, *val;
446 {
447     register Char **vec = (Char **) xmalloc((size_t) (2 * sizeof(Char **)));
448 
449     vec[0] = val;
450     vec[1] = 0;
451     set1(var, vec, &shvhed);
452 }
453 
454 void
455 set1(var, vec, head)
456     Char   *var, **vec;
457     struct varent *head;
458 {
459     register Char **oldv = vec;
460 
461     gflag = 0;
462     tglob(oldv);
463     if (gflag) {
464 	vec = globall(oldv);
465 	if (vec == 0) {
466 	    blkfree(oldv);
467 	    stderror(ERR_NAME | ERR_NOMATCH);
468 	    return;
469 	}
470 	blkfree(oldv);
471 	gargv = 0;
472     }
473     setq(var, vec, head);
474 }
475 
476 
477 void
478 setq(name, vec, p)
479     Char   *name, **vec;
480     register struct varent *p;
481 {
482     register struct varent *c;
483     register f;
484 
485     f = 0;			/* tree hangs off the header's left link */
486     while ((c = p->v_link[f]) != NULL) {
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 *) xmalloc((size_t) sizeof(struct varent));
496     c->v_name = Strsave(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 void
506 /*ARGSUSED*/
507 unset(v, t)
508     Char **v;
509     struct command *t;
510 {
511     unset1(v, &shvhed);
512 #ifdef FILEC
513     if (adrof(STRfilec) == 0)
514 	filec = 0;
515 #endif
516     if (adrof(STRhistchars) == 0) {
517 	HIST = '!';
518 	HISTSUB = '^';
519     }
520     if (adrof(STRwordchars) == 0)
521 	word_chars = STR_WORD_CHARS;
522 }
523 
524 void
525 unset1(v, head)
526     register Char *v[];
527     struct varent *head;
528 {
529     register struct varent *vp;
530     register int cnt;
531 
532     while (*++v) {
533 	cnt = 0;
534 	while ((vp = madrof(*v, head->v_left)) != NULL)
535 	    unsetv1(vp), cnt++;
536 	if (cnt == 0)
537 	    setname(vis_str(*v));
538     }
539 }
540 
541 void
542 unsetv(var)
543     Char   *var;
544 {
545     register struct varent *vp;
546 
547     if ((vp = adrof1(var, &shvhed)) == 0)
548 	udvar(var);
549     unsetv1(vp);
550 }
551 
552 static void
553 unsetv1(p)
554     register struct varent *p;
555 {
556     register struct varent *c, *pp;
557     register f;
558 
559     /*
560      * Free associated memory first to avoid complications.
561      */
562     blkfree(p->vec);
563     xfree((ptr_t) p->v_name);
564     /*
565      * If p is missing one child, then we can move the other into where p is.
566      * Otherwise, we find the predecessor of p, which is guaranteed to have no
567      * right child, copy it into p, and move it's left child into it.
568      */
569     if (p->v_right == 0)
570 	c = p->v_left;
571     else if (p->v_left == 0)
572 	c = p->v_right;
573     else {
574 	for (c = p->v_left; c->v_right; c = c->v_right)
575 	    continue;
576 	p->v_name = c->v_name;
577 	p->vec = c->vec;
578 	p = c;
579 	c = p->v_left;
580     }
581     /*
582      * Move c into where p is.
583      */
584     pp = p->v_parent;
585     f = pp->v_right == p;
586     if ((pp->v_link[f] = c) != NULL)
587 	c->v_parent = pp;
588     /*
589      * Free the deleted node, and rebalance.
590      */
591     xfree((ptr_t) p);
592     balance(pp, f, 1);
593 }
594 
595 void
596 setNS(cp)
597     Char   *cp;
598 {
599     set(cp, Strsave(STRNULL));
600 }
601 
602 void
603 /*ARGSUSED*/
604 shift(v, t)
605     Char **v;
606     struct command *t;
607 {
608     register struct varent *argv;
609     register Char *name;
610 
611     v++;
612     name = *v;
613     if (name == 0)
614 	name = STRargv;
615     else
616 	(void) strip(name);
617     argv = adrof(name);
618     if (argv == 0)
619 	udvar(name);
620     if (argv->vec[0] == 0)
621 	stderror(ERR_NAME | ERR_NOMORE);
622     lshift(argv->vec, 1);
623 }
624 
625 static void
626 exportpath(val)
627     Char  **val;
628 {
629     Char    exppath[BUFSIZ];
630 
631     exppath[0] = 0;
632     if (val)
633 	while (*val) {
634 	    if (Strlen(*val) + Strlen(exppath) + 2 > BUFSIZ) {
635 		(void) fprintf(csherr,
636 			       "Warning: ridiculously long PATH truncated\n");
637 		break;
638 	    }
639 	    if ((**val != '/' || **val == '\0') && (euid == 0 || uid == 0))
640 		    (void) fprintf(csherr,
641 		    "Warning: exported path contains relative components.\n");
642 	    (void) Strcat(exppath, *val++);
643 	    if (*val == 0 || eq(*val, STRRparen))
644 		break;
645 	    (void) Strcat(exppath, STRcolon);
646 	}
647     Setenv(STRPATH, exppath);
648 }
649 
650 #ifndef lint
651  /*
652   * Lint thinks these have null effect
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 #else
668 struct varent *
669 rleft(p)
670     struct varent *p;
671 {
672     return (p);
673 }
674 struct varent *
675 rright(p)
676     struct varent *p;
677 {
678     return (p);
679 }
680 
681 #endif				/* ! lint */
682 
683 
684 /*
685  * Rebalance a tree, starting at p and up.
686  * F == 0 means we've come from p's left child.
687  * D == 1 means we've just done a delete, otherwise an insert.
688  */
689 static void
690 balance(p, f, d)
691     register struct varent *p;
692     register int f, d;
693 {
694     register struct varent *pp;
695 
696 #ifndef lint
697     register struct varent *t;	/* used by the rotate macros */
698 
699 #endif
700     register ff;
701 
702     /*
703      * Ok, from here on, p is the node we're operating on; pp is it's parent; f
704      * is the branch of p from which we have come; ff is the branch of pp which
705      * is p.
706      */
707     for (; (pp = p->v_parent) != NULL; p = pp, f = ff) {
708 	ff = pp->v_right == p;
709 	if (f ^ d) {		/* right heavy */
710 	    switch (p->v_bal) {
711 	    case -1:		/* was left heavy */
712 		p->v_bal = 0;
713 		break;
714 	    case 0:		/* was balanced */
715 		p->v_bal = 1;
716 		break;
717 	    case 1:		/* was already right heavy */
718 		switch (p->v_right->v_bal) {
719 		case 1:	/* sigle rotate */
720 		    pp->v_link[ff] = rleft(p);
721 		    p->v_left->v_bal = 0;
722 		    p->v_bal = 0;
723 		    break;
724 		case 0:	/* single rotate */
725 		    pp->v_link[ff] = rleft(p);
726 		    p->v_left->v_bal = 1;
727 		    p->v_bal = -1;
728 		    break;
729 		case -1:	/* double rotate */
730 		    (void) rright(p->v_right);
731 		    pp->v_link[ff] = rleft(p);
732 		    p->v_left->v_bal =
733 			p->v_bal < 1 ? 0 : -1;
734 		    p->v_right->v_bal =
735 			p->v_bal > -1 ? 0 : 1;
736 		    p->v_bal = 0;
737 		    break;
738 		}
739 		break;
740 	    }
741 	}
742 	else {			/* left heavy */
743 	    switch (p->v_bal) {
744 	    case 1:		/* was right heavy */
745 		p->v_bal = 0;
746 		break;
747 	    case 0:		/* was balanced */
748 		p->v_bal = -1;
749 		break;
750 	    case -1:		/* was already left heavy */
751 		switch (p->v_left->v_bal) {
752 		case -1:	/* single rotate */
753 		    pp->v_link[ff] = rright(p);
754 		    p->v_right->v_bal = 0;
755 		    p->v_bal = 0;
756 		    break;
757 		case 0:	/* signle rotate */
758 		    pp->v_link[ff] = rright(p);
759 		    p->v_right->v_bal = -1;
760 		    p->v_bal = 1;
761 		    break;
762 		case 1:	/* double rotate */
763 		    (void) rleft(p->v_left);
764 		    pp->v_link[ff] = rright(p);
765 		    p->v_left->v_bal =
766 			p->v_bal < 1 ? 0 : -1;
767 		    p->v_right->v_bal =
768 			p->v_bal > -1 ? 0 : 1;
769 		    p->v_bal = 0;
770 		    break;
771 		}
772 		break;
773 	    }
774 	}
775 	/*
776 	 * If from insert, then we terminate when p is balanced. If from
777 	 * delete, then we terminate when p is unbalanced.
778 	 */
779 	if ((p->v_bal == 0) ^ d)
780 	    break;
781     }
782 }
783 
784 void
785 plist(p)
786     register struct varent *p;
787 {
788     register struct varent *c;
789     register len;
790     sigset_t sigset;
791 
792     if (setintr) {
793 	sigemptyset(&sigset);
794 	sigaddset(&sigset, SIGINT);
795 	sigprocmask(SIG_UNBLOCK, &sigset, NULL);
796     }
797 
798     for (;;) {
799 	while (p->v_left)
800 	    p = p->v_left;
801 x:
802 	if (p->v_parent == 0)	/* is it the header? */
803 	    return;
804 	len = blklen(p->vec);
805 	(void) fprintf(cshout, "%s\t", short2str(p->v_name));
806 	if (len != 1)
807 	    (void) fputc('(', cshout);
808 	blkpr(cshout, p->vec);
809 	if (len != 1)
810 	    (void) fputc(')', cshout);
811 	(void) fputc('\n', cshout);
812 	if (p->v_right) {
813 	    p = p->v_right;
814 	    continue;
815 	}
816 	do {
817 	    c = p;
818 	    p = p->v_parent;
819 	} while (p->v_right == c);
820 	goto x;
821     }
822 }
823