1 /* $NetBSD: set.c,v 1.33 2013/07/16 17:47:43 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.33 2013/07/16 17:47:43 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);
71 if (eq(vp
, STRpath
)) {
72 struct varent
*pt
= adrof(STRpath
);
74 stderror(ERR_NAME
| ERR_UNDVAR
);
80 else if (eq(vp
, STRhistchars
)) {
81 Char
*pn
= value(STRhistchars
);
86 else if (eq(vp
, STRuser
)) {
87 Setenv(STRUSER
, value(vp
));
88 Setenv(STRLOGNAME
, value(vp
));
90 else if (eq(vp
, STRwordchars
)) {
91 word_chars
= value(vp
);
93 else if (eq(vp
, STRterm
))
94 Setenv(STRTERM
, value(vp
));
95 else if (eq(vp
, STRhome
)) {
98 cp
= Strsave(value(vp
)); /* get the old value back */
101 * convert to canonical pathname (possibly resolving symlinks)
105 set(vp
, Strsave(cp
)); /* have to save the new val */
107 /* and now mirror home with HOME */
109 /* fix directory stack for new tilde home */
114 else if (eq(vp
, STRfilec
))
118 else if (eq(vp
, STRedit
)) {
121 el
= el_init_fd(getprogname(), cshin
, cshout
, csherr
,
123 el_set(el
, EL_EDITOR
, "emacs");
124 el_set(el
, EL_PROMPT
, printpromptstr
);
126 history(hi
, &ev
, H_SETSIZE
, getn(value(STRhistory
)));
127 loadhist(Histlist
.Hnext
);
128 el_set(el
, EL_HIST
, history
, hi
);
135 doset(Char
**v
, struct command
*t
)
137 Char op
, *p
, **vecp
, *vp
;
138 int subscr
= 0; /* XXX: GCC */
151 for (; alnum(*p
); p
++)
153 if (vp
== p
|| !letter(*vp
))
154 stderror(ERR_NAME
| ERR_VARBEGIN
);
155 if ((p
- vp
) > MAXVARLEN
)
156 stderror(ERR_NAME
| ERR_VARTOOLONG
);
159 p
= getinx(p
, &subscr
);
161 if ((op
= *p
) != '\0') {
163 if (*p
== 0 && *v
&& **v
== '(')
166 else if (*v
&& eq(*v
, STRequal
)) {
172 stderror(ERR_NAME
| ERR_SYNTAX
);
173 if (eq(p
, STRLparen
)) {
177 stderror(ERR_NAME
| ERR_SYNTAX
);
180 stderror(ERR_NAME
| ERR_MISSING
, ')');
188 set1(vp
, vecp
, &shvhed
);
193 asx(vp
, subscr
, Strsave(p
));
197 } while ((p
= *v
++) != NULL
);
201 getinx(Char
*cp
, int *ip
)
205 while (*cp
&& Isdigit(*cp
))
206 *ip
= *ip
* 10 + *cp
++ - '0';
208 stderror(ERR_NAME
| ERR_SUBSCRIPT
);
213 asx(Char
*vp
, int subscr
, Char
*p
)
217 v
= getvx(vp
, subscr
);
218 xfree((ptr_t
) v
->vec
[subscr
- 1]);
219 v
->vec
[subscr
- 1] = globone(p
, G_APPEND
);
222 static struct varent
*
223 getvx(Char
*vp
, int subscr
)
230 if (subscr
< 1 || subscr
> blklen(v
->vec
))
231 stderror(ERR_NAME
| ERR_RANGE
);
237 dolet(Char
**v
, struct command
*t
)
240 int subscr
= 0; /* XXX: GCC */
253 for (; alnum(*p
); p
++)
255 if (vp
== p
|| !letter(*vp
))
256 stderror(ERR_NAME
| ERR_VARBEGIN
);
257 if ((p
- vp
) > MAXVARLEN
)
258 stderror(ERR_NAME
| ERR_VARTOOLONG
);
261 p
= getinx(p
, &subscr
);
265 if ((op
= *p
) != '\0')
268 stderror(ERR_NAME
| ERR_ASSIGN
);
270 if (*p
== '\0' && *v
== NULL
)
271 stderror(ERR_NAME
| ERR_ASSIGN
);
282 stderror(ERR_NAME
| ERR_UNKNOWNOP
);
288 stderror(ERR_NAME
| ERR_UNKNOWNOP
);
290 stderror(ERR_NAME
| ERR_SYNTAX
);
293 stderror(ERR_NAME
| ERR_UNKNOWNOP
);
303 struct varent
*gv
= getvx(vp
, subscr
);
305 asx(vp
, subscr
, operate(op
, gv
->vec
[subscr
- 1], p
));
308 set(vp
, operate(op
, value(vp
), p
));
309 if (eq(vp
, STRpath
)) {
310 struct varent
*pt
= adrof(STRpath
);
312 stderror(ERR_NAME
| ERR_UNDVAR
);
321 } while ((p
= *v
++) != NULL
);
325 xset(Char
*cp
, Char
***vp
)
332 xfree((ptr_t
) ** vp
);
335 return (putn(expr(vp
)));
339 operate(int op
, Char
*vp
, Char
*p
)
341 Char opr
[2], **v
, *vec
[5], **vecp
;
352 if (op
== '<' || op
== '>')
359 stderror(ERR_NAME
| ERR_EXPRESSION
);
368 static Char numbers
[15];
375 if ((unsigned int)n
== 0x80000000U
) {
381 return (Strsave(numbers
));
389 *putp
++ = (Char
)(n
% 10 + '0');
398 if (cp
[0] == '+' && cp
[1])
404 stderror(ERR_NAME
| ERR_BADNUM
);
408 n
= n
* 10 + *cp
++ - '0';
410 stderror(ERR_NAME
| ERR_BADNUM
);
411 return (sign
? -n
: n
);
415 value1(Char
*var
, struct varent
*head
)
419 vp
= adrof1(var
, head
);
420 return (vp
== 0 || vp
->vec
[0] == 0 ? STRNULL
: vp
->vec
[0]);
423 static struct varent
*
424 madrof(Char
*pat
, struct varent
*vp
)
428 for (; vp
; vp
= vp
->v_right
) {
429 if (vp
->v_left
&& (vp1
= madrof(pat
, vp
->v_left
)))
431 if (Gmatch(vp
->v_name
, pat
))
438 adrof1(Char
*name
, struct varent
*v
)
443 while (v
&& ((cmp
= *name
- *v
->v_name
) ||
444 (cmp
= Strcmp(name
, v
->v_name
))))
453 * The caller is responsible for putting value in a safe place
456 set(Char
*var
, Char
*val
)
460 vec
= xmalloc(2 * sizeof(*vec
));
463 set1(var
, vec
, &shvhed
);
467 set1(Char
*var
, Char
**vec
, struct varent
*head
)
478 stderror(ERR_NAME
| ERR_NOMATCH
);
483 setq(var
, vec
, head
);
487 setq(Char
*name
, Char
**vec
, struct varent
*p
)
492 f
= 0; /* tree hangs off the header's left link */
493 while ((c
= p
->v_link
[f
]) != NULL
) {
494 if ((f
= *name
- *c
->v_name
) == 0 &&
495 (f
= Strcmp(name
, c
->v_name
)) == 0) {
502 p
->v_link
[f
] = c
= xmalloc(sizeof(*c
));
503 c
->v_name
= Strsave(name
);
505 c
->v_left
= c
->v_right
= 0;
514 unset(Char
**v
, struct command
*t
)
517 if (adrof(STRhistchars
) == 0) {
521 else if (adrof(STRwordchars
) == 0)
522 word_chars
= STR_WORD_CHARS
;
524 else if (adrof(STRfilec
) == 0)
528 else if (adrof(STRedit
) == 0) {
539 unset1(Char
*v
[], struct varent
*head
)
546 while ((vp
= madrof(*v
, head
->v_left
)) != NULL
)
549 setname(vis_str(*v
));
558 if ((vp
= adrof1(var
, &shvhed
)) == 0)
564 unsetv1(struct varent
*p
)
566 struct varent
*c
, *pp
;
570 * Free associated memory first to avoid complications.
573 xfree((ptr_t
) p
->v_name
);
575 * If p is missing one child, then we can move the other into where p is.
576 * Otherwise, we find the predecessor of p, which is guaranteed to have no
577 * right child, copy it into p, and move its left child into it.
581 else if (p
->v_left
== 0)
584 for (c
= p
->v_left
; c
->v_right
; c
= c
->v_right
)
586 p
->v_name
= c
->v_name
;
592 * Move c into where p is.
595 f
= pp
->v_right
== p
;
596 if ((pp
->v_link
[f
] = c
) != NULL
)
599 * Free the deleted node, and rebalance.
608 set(cp
, Strsave(STRNULL
));
613 shift(Char
**v
, struct command
*t
)
627 if (argv
->vec
[0] == 0)
628 stderror(ERR_NAME
| ERR_NOMORE
);
629 lshift(argv
->vec
, 1);
634 exportpath(Char
**val
)
636 Char exppath
[BUFSIZE
];
641 if (Strlen(*val
) + Strlen(exppath
) + 2 > BUFSIZE
) {
642 (void)fprintf(csherr
,
643 "Warning: ridiculously long PATH truncated\n");
646 (void)Strcat(exppath
, *val
++);
647 if (*val
== 0 || eq(*val
, STRRparen
))
649 (void)Strcat(exppath
, STRcolon
);
651 Setenv(STRPATH
, exppath
);
656 * Lint thinks these have null effect
658 /* macros to do single rotations on node p */
661 (t)->v_parent = (p)->v_parent,\
662 ((p)->v_left = t->v_right) ? (t->v_right->v_parent = (p)) : 0,\
663 (t->v_right = (p))->v_parent = t,\
667 (t)->v_parent = (p)->v_parent,\
668 ((p)->v_right = t->v_left) ? (t->v_left->v_parent = (p)) : 0,\
669 (t->v_left = (p))->v_parent = t,\
673 rleft(struct varent
*p
)
678 rright(struct varent
*p
)
686 * Rebalance a tree, starting at p and up.
687 * F == 0 means we've come from p's left child.
688 * D == 1 means we've just done a delete, otherwise an insert.
691 balance(struct varent
*p
, int f
, int d
)
696 struct varent
*t
; /* used by the rotate macros */
702 * Ok, from here on, p is the node we're operating on; pp is its parent; f
703 * is the branch of p from which we have come; ff is the branch of pp which
706 for (; (pp
= p
->v_parent
) != NULL
; p
= pp
, f
= ff
) {
707 ff
= pp
->v_right
== p
;
708 if (f
^ d
) { /* right heavy */
710 case -1: /* was left heavy */
713 case 0: /* was balanced */
716 case 1: /* was already right heavy */
717 switch (p
->v_right
->v_bal
) {
718 case 1: /* single rotate */
719 pp
->v_link
[ff
] = rleft(p
);
720 p
->v_left
->v_bal
= 0;
723 case 0: /* single rotate */
724 pp
->v_link
[ff
] = rleft(p
);
725 p
->v_left
->v_bal
= 1;
728 case -1: /* double rotate */
729 (void) rright(p
->v_right
);
730 pp
->v_link
[ff
] = rleft(p
);
732 p
->v_bal
< 1 ? 0 : -1;
734 p
->v_bal
> -1 ? 0 : 1;
741 else { /* left heavy */
743 case 1: /* was right heavy */
746 case 0: /* was balanced */
749 case -1: /* was already left heavy */
750 switch (p
->v_left
->v_bal
) {
751 case -1: /* single rotate */
752 pp
->v_link
[ff
] = rright(p
);
753 p
->v_right
->v_bal
= 0;
756 case 0: /* single rotate */
757 pp
->v_link
[ff
] = rright(p
);
758 p
->v_right
->v_bal
= -1;
761 case 1: /* double rotate */
762 (void) rleft(p
->v_left
);
763 pp
->v_link
[ff
] = rright(p
);
765 p
->v_bal
< 1 ? 0 : -1;
767 p
->v_bal
> -1 ? 0 : 1;
775 * If from insert, then we terminate when p is balanced. If from
776 * delete, then we terminate when p is unbalanced.
778 if ((p
->v_bal
== 0) ^ d
)
784 plist(struct varent
*p
)
791 sigemptyset(&nsigset
);
792 (void)sigaddset(&nsigset
, SIGINT
);
793 (void)sigprocmask(SIG_UNBLOCK
, &nsigset
, NULL
);
800 if (p
->v_parent
== 0) /* is it the header? */
802 len
= blklen(p
->vec
);
803 (void)fprintf(cshout
, "%s\t", short2str(p
->v_name
));
805 (void)fputc('(', cshout
);
806 blkpr(cshout
, p
->vec
);
808 (void)fputc(')', cshout
);
809 (void)fputc('\n', cshout
);
817 } while (p
->v_right
== c
);