2 * Copyright (c) 1980, 1991, 1993
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 static char sccsid[] = "@(#)set.c 8.1 (Berkeley) 5/31/93";
38 static const char rcsid[] =
43 #include <sys/types.h>
54 static Char *getinx __P((Char *, int *));
55 static void asx __P((Char *, int, Char *));
57 *getvx __P((Char *, int));
58 static Char *xset __P((Char *, Char ***));
59 static Char *operate __P((int, Char *, Char *));
60 static void putn1 __P((int));
62 *madrof __P((Char *, struct varent *));
63 static void unsetv1 __P((struct varent *));
64 static void exportpath __P((Char **));
65 static void balance __P((struct varent *, int, int));
94 for (; alnum(*p); p++)
96 if (vp == p || !letter(*vp))
97 stderror(ERR_NAME | ERR_VARBEGIN);
98 if ((p - vp) > MAXVARLEN) {
99 stderror(ERR_NAME | ERR_VARTOOLONG);
104 p = getinx(p, &subscr);
106 if ((op = *p) != '\0') {
108 if (*p == 0 && *v && **v == '(')
111 else if (*v && eq(*v, STRequal)) {
117 stderror(ERR_NAME | ERR_SYNTAX);
118 if (eq(p, STRLparen)) {
122 stderror(ERR_NAME | ERR_SYNTAX);
125 stderror(ERR_NAME | ERR_MISSING, ')');
133 set1(vp, vecp, &shvhed);
138 asx(vp, subscr, Strsave(p));
141 if (eq(vp, STRpath)) {
142 exportpath(adrof(STRpath)->vec);
145 else if (eq(vp, STRhistchars)) {
146 Char *pn = value(STRhistchars);
151 else if (eq(vp, STRuser)) {
152 Setenv(STRUSER, value(vp));
153 Setenv(STRLOGNAME, value(vp));
155 else if (eq(vp, STRwordchars)) {
156 word_chars = value(vp);
158 else if (eq(vp, STRterm))
159 Setenv(STRTERM, value(vp));
160 else if (eq(vp, STRhome)) {
163 cp = Strsave(value(vp)); /* get the old value back */
166 * convert to canonical pathname (possibly resolving symlinks)
170 set(vp, Strsave(cp)); /* have to save the new val */
172 /* and now mirror home with HOME */
174 /* fix directory stack for new tilde home */
179 else if (eq(vp, STRfilec))
182 } while ((p = *v++) != NULL);
193 while (*cp && Isdigit(*cp))
194 *ip = *ip * 10 + *cp++ - '0';
196 stderror(ERR_NAME | ERR_SUBSCRIPT);
206 struct varent *v = getvx(vp, subscr);
208 xfree((ptr_t) v->vec[subscr - 1]);
209 v->vec[subscr - 1] = globone(p, G_APPEND);
212 static struct varent *
217 struct varent *v = adrof(vp);
221 if (subscr < 1 || subscr > blklen(v->vec))
222 stderror(ERR_NAME | ERR_RANGE);
247 for (; alnum(*p); p++)
249 if (vp == p || !letter(*vp))
250 stderror(ERR_NAME | ERR_VARBEGIN);
251 if ((p - vp) > MAXVARLEN)
252 stderror(ERR_NAME | ERR_VARTOOLONG);
255 p = getinx(p, &subscr);
259 if ((op = *p) != '\0')
262 stderror(ERR_NAME | ERR_ASSIGN);
264 if (*p == '\0' && *v == NULL)
265 stderror(ERR_NAME | ERR_ASSIGN);
276 stderror(ERR_NAME | ERR_UNKNOWNOP);
282 stderror(ERR_NAME | ERR_UNKNOWNOP);
284 stderror(ERR_NAME | ERR_SYNTAX);
287 stderror(ERR_NAME | ERR_UNKNOWNOP);
297 struct varent *gv = getvx(vp, subscr);
299 asx(vp, subscr, operate(op, gv->vec[subscr - 1], p));
302 set(vp, operate(op, value(vp), p));
303 if (eq(vp, STRpath)) {
304 exportpath(adrof(STRpath)->vec);
310 } while ((p = *v++) != NULL);
322 xfree((ptr_t) ** vp);
325 return (putn(expr(vp)));
345 if (op == '<' || op == '>')
352 stderror(ERR_NAME | ERR_EXPRESSION);
363 static Char number[15];
370 num = 2; /* confuse lint */
371 if (sizeof(int) == num && ((unsigned int) n) == 0x8000) {
379 num = 4; /* confuse lint */
380 if (sizeof(int) == num && ((unsigned int) n) == 0x80000000) {
388 return (Strsave(number));
397 *putp++ = n % 10 + '0';
408 if (cp[0] == '+' && cp[1])
414 stderror(ERR_NAME | ERR_BADNUM);
418 n = n * 10 + *cp++ - '0';
420 stderror(ERR_NAME | ERR_BADNUM);
421 return (sign ? -n : n);
431 vp = adrof1(var, head);
432 return (vp == 0 || vp->vec[0] == 0 ? STRNULL : vp->vec[0]);
435 static struct varent *
442 for (; vp; vp = vp->v_right) {
443 if (vp->v_left && (vp1 = madrof(pat, vp->v_left)))
445 if (Gmatch(vp->v_name, pat))
459 while (v && ((cmp = *name - *v->v_name) ||
460 (cmp = Strcmp(name, v->v_name))))
469 * The caller is responsible for putting value in a safe place
475 Char **vec = (Char **) xmalloc((size_t) (2 * sizeof(Char **)));
479 set1(var, vec, &shvhed);
495 stderror(ERR_NAME | ERR_NOMATCH);
501 setq(var, vec, head);
513 f = 0; /* tree hangs off the header's left link */
514 while ((c = p->v_link[f]) != NULL) {
515 if ((f = *name - *c->v_name) == 0 &&
516 (f = Strcmp(name, c->v_name)) == 0) {
523 p->v_link[f] = c = (struct varent *) xmalloc((size_t) sizeof(struct varent));
524 c->v_name = Strsave(name);
526 c->v_left = c->v_right = 0;
541 if (adrof(STRfilec) == 0)
544 if (adrof(STRhistchars) == 0) {
548 if (adrof(STRwordchars) == 0)
549 word_chars = STR_WORD_CHARS;
562 while ((vp = madrof(*v, head->v_left)) != NULL)
565 setname(vis_str(*v));
575 if ((vp = adrof1(var, &shvhed)) == 0)
584 struct varent *c, *pp;
588 * Free associated memory first to avoid complications.
591 xfree((ptr_t) p->v_name);
593 * If p is missing one child, then we can move the other into where p is.
594 * Otherwise, we find the predecessor of p, which is guaranteed to have no
595 * right child, copy it into p, and move it's left child into it.
599 else if (p->v_left == 0)
602 for (c = p->v_left; c->v_right; c = c->v_right)
604 p->v_name = c->v_name;
610 * Move c into where p is.
613 f = pp->v_right == p;
614 if ((pp->v_link[f] = c) != NULL)
617 * Free the deleted node, and rebalance.
627 set(cp, Strsave(STRNULL));
648 if (argv->vec[0] == 0)
649 stderror(ERR_NAME | ERR_NOMORE);
650 lshift(argv->vec, 1);
657 Char exppath[BUFSIZ];
662 if (Strlen(*val) + Strlen(exppath) + 2 > BUFSIZ) {
663 (void) fprintf(csherr,
664 "Warning: ridiculously long PATH truncated\n");
667 if (**val != '/' && (euid == 0 || uid == 0) &&
668 (intact || (intty && isatty(SHOUT))))
669 (void) fprintf(csherr,
670 "Warning: exported path contains relative components.\n");
671 (void) Strcat(exppath, *val++);
672 if (*val == 0 || eq(*val, STRRparen))
674 (void) Strcat(exppath, STRcolon);
676 Setenv(STRPATH, exppath);
681 * Lint thinks these have null effect
683 /* macros to do single rotations on node p */
686 (t)->v_parent = (p)->v_parent,\
687 ((p)->v_left = t->v_right) ? (t->v_right->v_parent = (p)) : 0,\
688 (t->v_right = (p))->v_parent = t,\
692 (t)->v_parent = (p)->v_parent,\
693 ((p)->v_right = t->v_left) ? (t->v_left->v_parent = (p)) : 0,\
694 (t->v_left = (p))->v_parent = t,\
714 * Rebalance a tree, starting at p and up.
715 * F == 0 means we've come from p's left child.
716 * D == 1 means we've just done a delete, otherwise an insert.
726 struct varent *t; /* used by the rotate macros */
732 * Ok, from here on, p is the node we're operating on; pp is it's parent; f
733 * is the branch of p from which we have come; ff is the branch of pp which
736 for (; (pp = p->v_parent) != NULL; p = pp, f = ff) {
737 ff = pp->v_right == p;
738 if (f ^ d) { /* right heavy */
740 case -1: /* was left heavy */
743 case 0: /* was balanced */
746 case 1: /* was already right heavy */
747 switch (p->v_right->v_bal) {
748 case 1: /* single rotate */
749 pp->v_link[ff] = rleft(p);
750 p->v_left->v_bal = 0;
753 case 0: /* single rotate */
754 pp->v_link[ff] = rleft(p);
755 p->v_left->v_bal = 1;
758 case -1: /* double rotate */
759 (void) rright(p->v_right);
760 pp->v_link[ff] = rleft(p);
762 p->v_bal < 1 ? 0 : -1;
764 p->v_bal > -1 ? 0 : 1;
771 else { /* left heavy */
773 case 1: /* was right heavy */
776 case 0: /* was balanced */
779 case -1: /* was already left heavy */
780 switch (p->v_left->v_bal) {
781 case -1: /* single rotate */
782 pp->v_link[ff] = rright(p);
783 p->v_right->v_bal = 0;
786 case 0: /* single rotate */
787 pp->v_link[ff] = rright(p);
788 p->v_right->v_bal = -1;
791 case 1: /* double rotate */
792 (void) rleft(p->v_left);
793 pp->v_link[ff] = rright(p);
795 p->v_bal < 1 ? 0 : -1;
797 p->v_bal > -1 ? 0 : 1;
805 * If from insert, then we terminate when p is balanced. If from
806 * delete, then we terminate when p is unbalanced.
808 if ((p->v_bal == 0) ^ d)
821 (void) sigsetmask(sigblock(0) & ~sigmask(SIGINT));
827 if (p->v_parent == 0) /* is it the header? */
829 len = blklen(p->vec);
830 (void) fprintf(cshout, "%s\t", short2str(p->v_name));
832 (void) fputc('(', cshout);
833 blkpr(cshout, p->vec);
835 (void) fputc(')', cshout);
836 (void) fputc('\n', cshout);
844 } while (p->v_right == c);