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