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