set.c revision 1.6 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.6 1995/01/15 09:47:38 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 (void) Strcat(exppath, *val++);
667 if (*val == 0 || eq(*val, STRRparen))
668 break;
669 (void) Strcat(exppath, STRcolon);
670 }
671 Setenv(STRPATH, exppath);
672 }
673
674 #ifndef lint
675 /*
676 * Lint thinks these have null effect
677 */
678 /* macros to do single rotations on node p */
679 #define rright(p) (\
680 t = (p)->v_left,\
681 (t)->v_parent = (p)->v_parent,\
682 ((p)->v_left = t->v_right) ? (t->v_right->v_parent = (p)) : 0,\
683 (t->v_right = (p))->v_parent = t,\
684 (p) = t)
685 #define rleft(p) (\
686 t = (p)->v_right,\
687 (t)->v_parent = (p)->v_parent,\
688 ((p)->v_right = t->v_left) ? (t->v_left->v_parent = (p)) : 0,\
689 (t->v_left = (p))->v_parent = t,\
690 (p) = t)
691 #else
692 struct varent *
693 rleft(p)
694 struct varent *p;
695 {
696 return (p);
697 }
698 struct varent *
699 rright(p)
700 struct varent *p;
701 {
702 return (p);
703 }
704
705 #endif /* ! lint */
706
707
708 /*
709 * Rebalance a tree, starting at p and up.
710 * F == 0 means we've come from p's left child.
711 * D == 1 means we've just done a delete, otherwise an insert.
712 */
713 static void
714 balance(p, f, d)
715 register struct varent *p;
716 register int f, d;
717 {
718 register struct varent *pp;
719
720 #ifndef lint
721 register struct varent *t; /* used by the rotate macros */
722
723 #endif
724 register ff;
725
726 /*
727 * Ok, from here on, p is the node we're operating on; pp is it's parent; f
728 * is the branch of p from which we have come; ff is the branch of pp which
729 * is p.
730 */
731 for (; (pp = p->v_parent) != NULL; p = pp, f = ff) {
732 ff = pp->v_right == p;
733 if (f ^ d) { /* right heavy */
734 switch (p->v_bal) {
735 case -1: /* was left heavy */
736 p->v_bal = 0;
737 break;
738 case 0: /* was balanced */
739 p->v_bal = 1;
740 break;
741 case 1: /* was already right heavy */
742 switch (p->v_right->v_bal) {
743 case 1: /* sigle rotate */
744 pp->v_link[ff] = rleft(p);
745 p->v_left->v_bal = 0;
746 p->v_bal = 0;
747 break;
748 case 0: /* single rotate */
749 pp->v_link[ff] = rleft(p);
750 p->v_left->v_bal = 1;
751 p->v_bal = -1;
752 break;
753 case -1: /* double rotate */
754 (void) rright(p->v_right);
755 pp->v_link[ff] = rleft(p);
756 p->v_left->v_bal =
757 p->v_bal < 1 ? 0 : -1;
758 p->v_right->v_bal =
759 p->v_bal > -1 ? 0 : 1;
760 p->v_bal = 0;
761 break;
762 }
763 break;
764 }
765 }
766 else { /* left heavy */
767 switch (p->v_bal) {
768 case 1: /* was right heavy */
769 p->v_bal = 0;
770 break;
771 case 0: /* was balanced */
772 p->v_bal = -1;
773 break;
774 case -1: /* was already left heavy */
775 switch (p->v_left->v_bal) {
776 case -1: /* single rotate */
777 pp->v_link[ff] = rright(p);
778 p->v_right->v_bal = 0;
779 p->v_bal = 0;
780 break;
781 case 0: /* signle rotate */
782 pp->v_link[ff] = rright(p);
783 p->v_right->v_bal = -1;
784 p->v_bal = 1;
785 break;
786 case 1: /* double rotate */
787 (void) rleft(p->v_left);
788 pp->v_link[ff] = rright(p);
789 p->v_left->v_bal =
790 p->v_bal < 1 ? 0 : -1;
791 p->v_right->v_bal =
792 p->v_bal > -1 ? 0 : 1;
793 p->v_bal = 0;
794 break;
795 }
796 break;
797 }
798 }
799 /*
800 * If from insert, then we terminate when p is balanced. If from
801 * delete, then we terminate when p is unbalanced.
802 */
803 if ((p->v_bal == 0) ^ d)
804 break;
805 }
806 }
807
808 void
809 plist(p)
810 register struct varent *p;
811 {
812 register struct varent *c;
813 register len;
814
815 if (setintr)
816 (void) sigsetmask(sigblock((sigset_t) 0) & ~sigmask(SIGINT));
817
818 for (;;) {
819 while (p->v_left)
820 p = p->v_left;
821 x:
822 if (p->v_parent == 0) /* is it the header? */
823 return;
824 len = blklen(p->vec);
825 (void) fprintf(cshout, "%s\t", short2str(p->v_name));
826 if (len != 1)
827 (void) fputc('(', cshout);
828 blkpr(cshout, p->vec);
829 if (len != 1)
830 (void) fputc(')', cshout);
831 (void) fputc('\n', cshout);
832 if (p->v_right) {
833 p = p->v_right;
834 continue;
835 }
836 do {
837 c = p;
838 p = p->v_parent;
839 } while (p->v_right == c);
840 goto x;
841 }
842 }
843