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