1 /* $NetBSD: set.c,v 1.28 2007/07/16 14:07:01 christos Exp $ */
4 * Copyright (c) 1980, 1991, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
35 static char sccsid
[] = "@(#)set.c 8.1 (Berkeley) 5/31/93";
37 __RCSID("$NetBSD: set.c,v 1.28 2007/07/16 14:07:01 christos Exp $");
41 #include <sys/types.h>
48 #endif /* SHORT_STRINGS */
53 static Char
*getinx(Char
*, int *);
54 static void asx(Char
*, int, Char
*);
55 static struct varent
*getvx(Char
*, int);
56 static Char
*xset(Char
*, Char
***);
57 static Char
*operate(int, Char
*, Char
*);
58 static void putn1(int);
59 static struct varent
*madrof(Char
*, struct varent
*);
60 static void unsetv1(struct varent
*);
61 static void exportpath(Char
**);
62 static void balance(struct varent
*, int, int);
70 doset(Char
**v
, struct command
*t
)
72 Char op
, *p
, **vecp
, *vp
;
73 int subscr
= 0; /* XXX: GCC */
86 for (; alnum(*p
); p
++)
88 if (vp
== p
|| !letter(*vp
))
89 stderror(ERR_NAME
| ERR_VARBEGIN
);
90 if ((p
- vp
) > MAXVARLEN
)
91 stderror(ERR_NAME
| ERR_VARTOOLONG
);
94 p
= getinx(p
, &subscr
);
96 if ((op
= *p
) != '\0') {
98 if (*p
== 0 && *v
&& **v
== '(')
101 else if (*v
&& eq(*v
, STRequal
)) {
107 stderror(ERR_NAME
| ERR_SYNTAX
);
108 if (eq(p
, STRLparen
)) {
112 stderror(ERR_NAME
| ERR_SYNTAX
);
115 stderror(ERR_NAME
| ERR_MISSING
, ')');
123 set1(vp
, vecp
, &shvhed
);
128 asx(vp
, subscr
, Strsave(p
));
131 if (eq(vp
, STRpath
)) {
132 struct varent
*pt
= adrof(STRpath
);
134 stderror(ERR_NAME
| ERR_UNDVAR
);
140 else if (eq(vp
, STRhistchars
)) {
141 Char
*pn
= value(STRhistchars
);
146 else if (eq(vp
, STRuser
)) {
147 Setenv(STRUSER
, value(vp
));
148 Setenv(STRLOGNAME
, value(vp
));
150 else if (eq(vp
, STRwordchars
)) {
151 word_chars
= value(vp
);
153 else if (eq(vp
, STRterm
))
154 Setenv(STRTERM
, value(vp
));
155 else if (eq(vp
, STRhome
)) {
158 cp
= Strsave(value(vp
)); /* get the old value back */
161 * convert to canonical pathname (possibly resolving symlinks)
165 set(vp
, Strsave(cp
)); /* have to save the new val */
167 /* and now mirror home with HOME */
169 /* fix directory stack for new tilde home */
174 else if (eq(vp
, STRfilec
))
177 } while ((p
= *v
++) != NULL
);
181 getinx(Char
*cp
, int *ip
)
185 while (*cp
&& Isdigit(*cp
))
186 *ip
= *ip
* 10 + *cp
++ - '0';
188 stderror(ERR_NAME
| ERR_SUBSCRIPT
);
193 asx(Char
*vp
, int subscr
, Char
*p
)
197 v
= getvx(vp
, subscr
);
198 xfree((ptr_t
) v
->vec
[subscr
- 1]);
199 v
->vec
[subscr
- 1] = globone(p
, G_APPEND
);
202 static struct varent
*
203 getvx(Char
*vp
, int subscr
)
210 if (subscr
< 1 || subscr
> blklen(v
->vec
))
211 stderror(ERR_NAME
| ERR_RANGE
);
217 dolet(Char
**v
, struct command
*t
)
220 int subscr
= 0; /* XXX: GCC */
233 for (; alnum(*p
); p
++)
235 if (vp
== p
|| !letter(*vp
))
236 stderror(ERR_NAME
| ERR_VARBEGIN
);
237 if ((p
- vp
) > MAXVARLEN
)
238 stderror(ERR_NAME
| ERR_VARTOOLONG
);
241 p
= getinx(p
, &subscr
);
245 if ((op
= *p
) != '\0')
248 stderror(ERR_NAME
| ERR_ASSIGN
);
250 if (*p
== '\0' && *v
== NULL
)
251 stderror(ERR_NAME
| ERR_ASSIGN
);
262 stderror(ERR_NAME
| ERR_UNKNOWNOP
);
268 stderror(ERR_NAME
| ERR_UNKNOWNOP
);
270 stderror(ERR_NAME
| ERR_SYNTAX
);
273 stderror(ERR_NAME
| ERR_UNKNOWNOP
);
283 struct varent
*gv
= getvx(vp
, subscr
);
285 asx(vp
, subscr
, operate(op
, gv
->vec
[subscr
- 1], p
));
288 set(vp
, operate(op
, value(vp
), p
));
289 if (eq(vp
, STRpath
)) {
290 struct varent
*pt
= adrof(STRpath
);
292 stderror(ERR_NAME
| ERR_UNDVAR
);
301 } while ((p
= *v
++) != NULL
);
305 xset(Char
*cp
, Char
***vp
)
312 xfree((ptr_t
) ** vp
);
315 return (putn(expr(vp
)));
319 operate(int op
, Char
*vp
, Char
*p
)
321 Char opr
[2], **v
, *vec
[5], **vecp
;
332 if (op
== '<' || op
== '>')
339 stderror(ERR_NAME
| ERR_EXPRESSION
);
348 static Char numbers
[15];
355 if ((unsigned int)n
== 0x80000000U
) {
361 return (Strsave(numbers
));
369 *putp
++ = n
% 10 + '0';
378 if (cp
[0] == '+' && cp
[1])
384 stderror(ERR_NAME
| ERR_BADNUM
);
388 n
= n
* 10 + *cp
++ - '0';
390 stderror(ERR_NAME
| ERR_BADNUM
);
391 return (sign
? -n
: n
);
395 value1(Char
*var
, struct varent
*head
)
399 vp
= adrof1(var
, head
);
400 return (vp
== 0 || vp
->vec
[0] == 0 ? STRNULL
: vp
->vec
[0]);
403 static struct varent
*
404 madrof(Char
*pat
, struct varent
*vp
)
408 for (; vp
; vp
= vp
->v_right
) {
409 if (vp
->v_left
&& (vp1
= madrof(pat
, vp
->v_left
)))
411 if (Gmatch(vp
->v_name
, pat
))
418 adrof1(Char
*name
, struct varent
*v
)
423 while (v
&& ((cmp
= *name
- *v
->v_name
) ||
424 (cmp
= Strcmp(name
, v
->v_name
))))
433 * The caller is responsible for putting value in a safe place
436 set(Char
*var
, Char
*val
)
440 vec
= (Char
**)xmalloc((size_t)(2 * sizeof(Char
**)));
443 set1(var
, vec
, &shvhed
);
447 set1(Char
*var
, Char
**vec
, struct varent
*head
)
458 stderror(ERR_NAME
| ERR_NOMATCH
);
463 setq(var
, vec
, head
);
467 setq(Char
*name
, Char
**vec
, struct varent
*p
)
472 f
= 0; /* tree hangs off the header's left link */
473 while ((c
= p
->v_link
[f
]) != NULL
) {
474 if ((f
= *name
- *c
->v_name
) == 0 &&
475 (f
= Strcmp(name
, c
->v_name
)) == 0) {
482 p
->v_link
[f
] = c
= (struct varent
*)xmalloc((size_t)sizeof(struct varent
));
483 c
->v_name
= Strsave(name
);
485 c
->v_left
= c
->v_right
= 0;
494 unset(Char
**v
, struct command
*t
)
498 if (adrof(STRfilec
) == 0)
501 if (adrof(STRhistchars
) == 0) {
505 if (adrof(STRwordchars
) == 0)
506 word_chars
= STR_WORD_CHARS
;
510 unset1(Char
*v
[], struct varent
*head
)
517 while ((vp
= madrof(*v
, head
->v_left
)) != NULL
)
520 setname(vis_str(*v
));
529 if ((vp
= adrof1(var
, &shvhed
)) == 0)
535 unsetv1(struct varent
*p
)
537 struct varent
*c
, *pp
;
541 * Free associated memory first to avoid complications.
544 xfree((ptr_t
) p
->v_name
);
546 * If p is missing one child, then we can move the other into where p is.
547 * Otherwise, we find the predecessor of p, which is guaranteed to have no
548 * right child, copy it into p, and move its left child into it.
552 else if (p
->v_left
== 0)
555 for (c
= p
->v_left
; c
->v_right
; c
= c
->v_right
)
557 p
->v_name
= c
->v_name
;
563 * Move c into where p is.
566 f
= pp
->v_right
== p
;
567 if ((pp
->v_link
[f
] = c
) != NULL
)
570 * Free the deleted node, and rebalance.
579 set(cp
, Strsave(STRNULL
));
584 shift(Char
**v
, struct command
*t
)
598 if (argv
->vec
[0] == 0)
599 stderror(ERR_NAME
| ERR_NOMORE
);
600 lshift(argv
->vec
, 1);
604 exportpath(Char
**val
)
606 Char exppath
[BUFSIZE
];
611 if (Strlen(*val
) + Strlen(exppath
) + 2 > BUFSIZE
) {
612 (void)fprintf(csherr
,
613 "Warning: ridiculously long PATH truncated\n");
616 (void)Strcat(exppath
, *val
++);
617 if (*val
== 0 || eq(*val
, STRRparen
))
619 (void)Strcat(exppath
, STRcolon
);
621 Setenv(STRPATH
, exppath
);
626 * Lint thinks these have null effect
628 /* macros to do single rotations on node p */
631 (t)->v_parent = (p)->v_parent,\
632 ((p)->v_left = t->v_right) ? (t->v_right->v_parent = (p)) : 0,\
633 (t->v_right = (p))->v_parent = t,\
637 (t)->v_parent = (p)->v_parent,\
638 ((p)->v_right = t->v_left) ? (t->v_left->v_parent = (p)) : 0,\
639 (t->v_left = (p))->v_parent = t,\
643 rleft(struct varent
*p
)
648 rright(struct varent
*p
)
656 * Rebalance a tree, starting at p and up.
657 * F == 0 means we've come from p's left child.
658 * D == 1 means we've just done a delete, otherwise an insert.
661 balance(struct varent
*p
, int f
, int d
)
666 struct varent
*t
; /* used by the rotate macros */
672 * Ok, from here on, p is the node we're operating on; pp is its parent; f
673 * is the branch of p from which we have come; ff is the branch of pp which
676 for (; (pp
= p
->v_parent
) != NULL
; p
= pp
, f
= ff
) {
677 ff
= pp
->v_right
== p
;
678 if (f
^ d
) { /* right heavy */
680 case -1: /* was left heavy */
683 case 0: /* was balanced */
686 case 1: /* was already right heavy */
687 switch (p
->v_right
->v_bal
) {
688 case 1: /* single rotate */
689 pp
->v_link
[ff
] = rleft(p
);
690 p
->v_left
->v_bal
= 0;
693 case 0: /* single rotate */
694 pp
->v_link
[ff
] = rleft(p
);
695 p
->v_left
->v_bal
= 1;
698 case -1: /* double rotate */
699 (void) rright(p
->v_right
);
700 pp
->v_link
[ff
] = rleft(p
);
702 p
->v_bal
< 1 ? 0 : -1;
704 p
->v_bal
> -1 ? 0 : 1;
711 else { /* left heavy */
713 case 1: /* was right heavy */
716 case 0: /* was balanced */
719 case -1: /* was already left heavy */
720 switch (p
->v_left
->v_bal
) {
721 case -1: /* single rotate */
722 pp
->v_link
[ff
] = rright(p
);
723 p
->v_right
->v_bal
= 0;
726 case 0: /* single rotate */
727 pp
->v_link
[ff
] = rright(p
);
728 p
->v_right
->v_bal
= -1;
731 case 1: /* double rotate */
732 (void) rleft(p
->v_left
);
733 pp
->v_link
[ff
] = rright(p
);
735 p
->v_bal
< 1 ? 0 : -1;
737 p
->v_bal
> -1 ? 0 : 1;
745 * If from insert, then we terminate when p is balanced. If from
746 * delete, then we terminate when p is unbalanced.
748 if ((p
->v_bal
== 0) ^ d
)
754 plist(struct varent
*p
)
761 sigemptyset(&nsigset
);
762 (void)sigaddset(&nsigset
, SIGINT
);
763 (void)sigprocmask(SIG_UNBLOCK
, &nsigset
, NULL
);
770 if (p
->v_parent
== 0) /* is it the header? */
772 len
= blklen(p
->vec
);
773 (void)fprintf(cshout
, "%s\t", short2str(p
->v_name
));
775 (void)fputc('(', cshout
);
776 blkpr(cshout
, p
->vec
);
778 (void)fputc(')', cshout
);
779 (void)fputc('\n', cshout
);
787 } while (p
->v_right
== c
);