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