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