2 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
6 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
7 /* All Rights Reserved */
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.
15 #pragma ident "%Z%%M% %I% %E% SMI"
18 #include "sh.tconst.h"
25 void asx(tchar
*, int, tchar
*);
27 void set(tchar
*, tchar
*);
28 void set1(tchar
*, tchar
**, struct varent
*);
29 void setq(tchar
*, tchar
**, struct varent
*);
30 void unset1(tchar
*[], struct varent
*);
31 void unsetv1(struct varent
*);
32 void exportpath(tchar
**);
33 void balance(struct varent
*, int, int);
34 tchar
*operate(tchar
, tchar
*, tchar
*);
35 tchar
*getinx(tchar
*, int *);
36 tchar
*xset(tchar
*, tchar
***);
37 struct varent
*getvx(tchar
*, int);
50 tprintf("TRACE- doset()\n");
61 * check for proper variable syntax
62 * must be alphanumeric, start with a letter and
63 * be at most 20 characters
65 for (vp
= p
; alnum(*p
); p
++)
67 if (vp
== p
|| !letter(*vp
))
69 if ((p
- vp
) > MAX_VAR_LEN
)
70 bferr("Variable name too long");
73 p
= getinx(p
, &subscr
);
77 if (*p
== 0 && *v
&& **v
== '(')
79 } else if (*v
&& eq(*v
, S_EQ
/* "=" */)) {
86 bferr("Syntax error");
87 if (eq(p
, S_LPAR
/* "(" */)) {
102 set1(vp
, vecp
, &shvhed
);
107 asx(vp
, subscr
, retp
);
112 if (eq(vp
, S_path
/* "path" */)) {
113 exportpath(adrof(S_path
/* "path" */)->vec
);
115 } else if (eq(vp
, S_histchars
/* "histchars" */)) {
116 tchar
*p
= value(S_histchars
/* "histchars" */);
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
));
126 else if (eq(vp
, S_filec
/* "filec" */))
128 else if (eq(vp
, S_cdpath
/* "cdpath" */))
135 getinx(tchar
*cp
, int *ip
)
139 tprintf("TRACE- getinx()\n");
143 while (*cp
&& digit(*cp
))
144 *ip
= *ip
* 10 + *cp
++ - '0';
146 bferr("Subscript error");
151 asx(tchar
*vp
, int subscr
, tchar
*p
)
153 struct varent
*v
= getvx(vp
, subscr
);
156 tprintf("TRACE- asx()\n");
158 xfree(v
->vec
[subscr
- 1]);
159 v
->vec
[subscr
- 1] = globone(p
);
163 getvx(tchar
*vp
, int subscr
)
165 struct varent
*v
= adrof(vp
);
168 tprintf("TRACE- getvx()\n");
172 if (subscr
< 1 || subscr
> blklen(v
->vec
))
173 bferr("Subscript out of range");
177 tchar plusplus
[2] = { '1', 0 };
195 for (vp
= p
; alnum(*p
); p
++)
197 if (vp
== p
|| !letter(*vp
))
201 p
= getinx(p
, &subscr
);
215 /* if (any(c, "+-")) { */
216 if (c
== '+' || c
== '-') {
221 /* if (any(op, "<>")) { */
222 if (op
== '<' || op
== '>') {
227 bferr("Syntax error");
242 /* avoid bug in vax CC */
244 struct varent
*gv
= getvx(vp
, subscr
);
246 asx(vp
, subscr
, operate(op
, gv
->vec
[subscr
- 1], p
));
249 asx(vp
, subscr
, operate(op
, getvx(vp
, subscr
)->vec
[subscr
- 1], p
));
252 set(vp
, operate(op
, value(vp
), p
));
253 if (eq(vp
, S_path
/* "path" */)) {
254 exportpath(adrof(S_path
/* "path" */)->vec
);
258 if (eq(vp
, S_cdpath
/* "cdpath" */))
268 xset(tchar
*cp
, tchar
***vp
)
273 tprintf("TRACE- xset()\n");
281 return (putn(exp(vp
)));
285 operate(tchar op
, tchar
*vp
, tchar
*p
)
299 if (op
== '<' || op
== '>')
306 bferr("Expression syntax");
315 static tchar number
[15];
318 tprintf("TRACE- putn()\n");
325 if (sizeof (int) == 2 && n
== -32768) {
331 } else if (sizeof (int) == 4 && n
== 0x80000000) {
338 return (savestr(number
));
345 tprintf("TRACE- putn1()\n");
349 *putp
++ = n
% 10 + '0';
359 tprintf("TRACE- getn()\n");
362 if (cp
[0] == '+' && cp
[1])
372 n
= n
* 10 + *cp
++ - '0';
375 return (sign
? -n
: n
);
377 bferr("Badly formed number");
382 value1(tchar
*var
, struct varent
*head
)
387 tprintf("TRACE- value1()\n");
389 vp
= adrof1(var
, head
);
390 return (vp
== 0 || vp
->vec
[0] == 0 ? S_
/* "" */ : vp
->vec
[0]);
394 madrof(tchar
*pat
, struct varent
*vp
)
399 tprintf("TRACE- madrof()\n");
401 for (; vp
; vp
= vp
->v_right
) {
402 if (vp
->v_left
&& (vp1
= madrof(pat
, vp
->v_left
)))
404 if (Gmatch(vp
->v_name
, pat
))
411 adrof1(tchar
*name
, struct varent
*v
)
416 tprintf("TRACE- adrof1()\n");
419 while (v
&& ((cmp
= *name
- *v
->v_name
) ||
420 (cmp
= strcmp_(name
, v
->v_name
))))
429 * The caller is responsible for putting value in a safe place
432 set(tchar
*var
, tchar
*val
)
434 tchar
**vec
= (tchar
**)xalloc(2 * sizeof (tchar
**));
437 tprintf("TRACE- set()\n");
439 vec
[0] = onlyread(val
) ? savestr(val
) : val
;
441 set1(var
, vec
, &shvhed
);
445 set1(tchar
*var
, tchar
**vec
, struct varent
*head
)
450 tprintf("TRACE- set1()\n");
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.
458 if ((!(eq(var
, S_cwd
))) || (eq(var
, S_cwd
) && (didchdir
== 0)))
472 setq(var
, vec
, head
);
476 setq(tchar
*name
, tchar
**vec
, struct varent
*p
)
482 tprintf("TRACE- setq()\n");
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) {
494 p
->v_link
[f
] = c
= (struct varent
*)xalloc(sizeof (struct varent
));
495 c
->v_name
= savestr(name
);
497 c
->v_left
= c
->v_right
= 0;
509 tprintf("TRACE- unset()\n");
512 if (adrof(S_histchars
/* "histchars" */) == 0) {
517 if (adrof(S_filec
/* "filec" */) == 0)
523 unset1(tchar
*v
[], struct varent
*head
)
529 tprintf("TRACE- unset1()\n");
533 while (vp
= madrof(*v
, head
->v_left
))
546 tprintf("TRACE- unsetv()\n");
548 if ((vp
= adrof1(var
, &shvhed
)) == 0)
554 unsetv1(struct varent
*p
)
556 struct varent
*c
, *pp
;
560 tprintf("TRACE- unsetv1()\n");
563 * Free associated memory first to avoid complications.
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.
575 else if (p
->v_left
== 0)
578 for (c
= p
->v_left
; c
->v_right
; c
= c
->v_right
)
580 p
->v_name
= c
->v_name
;
586 * Move c into where p is.
589 f
= pp
->v_right
== p
;
590 if (pp
->v_link
[f
] = c
)
593 * Free the deleted node, and rebalance.
603 tprintf("TRACE- setNS()\n");
606 set(cp
, S_
/* "" */);
616 tprintf("TRACE- shift()\n");
621 name
= S_argv
/* "argv" */;
627 if (argv
->vec
[0] == 0)
628 bferr("No more words");
629 lshift(argv
->vec
, 1);
633 exportpath(tchar
**val
)
635 tchar exppath
[PATHSIZ
];
638 tprintf("TRACE- exportpath()\n");
643 if (strlen_(*val
) + strlen_(exppath
) + 2 > PATHSIZ
) {
644 printf("Warning: ridiculously long PATH truncated\n");
647 (void) strcat_(exppath
, *val
++);
648 if (*val
== 0 || eq(*val
, S_RPAR
/* ")" */))
650 (void) strcat_(exppath
, S_COLON
/* ":" */);
652 local_setenv(S_PATH
/* "PATH" */, exppath
);
655 /* macros to do single rotations on node p */
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,\
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,\
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.
675 balance(struct varent
*p
, int f
, int d
)
678 struct varent
*t
; /* used by the rotate macros */
682 tprintf("TRACE- balance()\n");
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.
689 for (; pp
= p
->v_parent
; p
= pp
, f
= ff
) {
690 ff
= pp
->v_right
== p
;
691 if (f
^ d
) { /* right heavy */
693 case -1: /* was left heavy */
696 case 0: /* was balanced */
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;
706 case 0: /* single rotate */
707 pp
->v_link
[ff
] = rleft(p
);
708 p
->v_left
->v_bal
= 1;
711 case -1: /* double rotate */
713 pp
->v_link
[ff
] = rleft(p
);
715 p
->v_bal
< 1 ? 0 : -1;
717 p
->v_bal
> -1 ? 0 : 1;
723 } else { /* left heavy */
725 case 1: /* was right heavy */
728 case 0: /* was balanced */
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;
738 case 0: /* signle rotate */
739 pp
->v_link
[ff
] = rright(p
);
740 p
->v_right
->v_bal
= -1;
743 case 1: /* double rotate */
745 pp
->v_link
[ff
] = rright(p
);
747 p
->v_bal
< 1 ? 0 : -1;
749 p
->v_bal
> -1 ? 0 : 1;
757 * If from insert, then we terminate when p is balanced.
758 * If from delete, then we terminate when p is unbalanced.
760 if ((p
->v_bal
== 0) ^ d
)
766 plist(struct varent
*p
)
772 tprintf("TRACE- plist()\n");
775 (void) sigsetmask(sigblock(0) & ~ sigmask(SIGINT
));
780 if (p
->v_parent
== 0) /* is it the header? */
782 len
= blklen(p
->vec
);
783 printf("%t", p
->v_name
);
798 } while (p
->v_right
== c
);