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