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