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