xref: /dragonfly/contrib/tcsh-6/sh.set.c (revision f2c43266)
1 /* $Header: /p/tcsh/cvsroot/tcsh/sh.set.c,v 3.86 2014/10/28 18:40:46 christos Exp $ */
2 /*
3  * sh.set.c: Setting and Clearing of variables
4  */
5 /*-
6  * Copyright (c) 1980, 1991 The Regents of the University of California.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. 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 #include "sh.h"
34 
35 RCSID("$tcsh: sh.set.c,v 3.86 2014/10/28 18:40:46 christos Exp $")
36 
37 #include "ed.h"
38 #include "tw.h"
39 
40 #ifdef HAVE_NL_LANGINFO
41 #include <langinfo.h>
42 #endif
43 
44 extern int GotTermCaps;
45 int numeof = 0;
46 
47 static	void		 update_vars	(Char *);
48 static	Char		*getinx		(Char *, int *);
49 static	void		 asx		(Char *, int, Char *);
50 static	struct varent 	*getvx		(Char *, int);
51 static	Char		*xset		(Char *, Char ***);
52 static	Char		*operate	(int, Char *, Char *);
53 static	void	 	 putn1		(tcsh_number_t);
54 static	struct varent	*madrof		(Char *, struct varent *);
55 static	void		 unsetv1	(struct varent *);
56 static	void		 balance	(struct varent *, int, int);
57 
58 /*
59  * C Shell
60  */
61 
62 static void
63 update_vars(Char *vp)
64 {
65     if (eq(vp, STRpath)) {
66 	struct varent *p = adrof(STRpath);
67 	if (p == NULL)
68 	    stderror(ERR_NAME | ERR_UNDVAR);
69 	else {
70 	    exportpath(p->vec);
71 	    dohash(NULL, NULL);
72 	}
73     }
74     else if (eq(vp, STRhistchars)) {
75 	Char *pn = varval(vp);
76 
77 	HIST = *pn++;
78 	if (HIST)
79 	    HISTSUB = *pn;
80 	else
81 	    HISTSUB = HIST;
82     }
83     else if (eq(vp, STRpromptchars)) {
84 	Char *pn = varval(vp);
85 
86 	PRCH = *pn++;
87 	if (PRCH)
88 	    PRCHROOT = *pn;
89 	else
90 	    PRCHROOT = PRCH;
91     }
92     else if (eq(vp, STRhistlit)) {
93 	HistLit = 1;
94     }
95     else if (eq(vp, STRuser)) {
96 	tsetenv(STRKUSER, varval(vp));
97 	tsetenv(STRLOGNAME, varval(vp));
98     }
99     else if (eq(vp, STRgroup)) {
100 	tsetenv(STRKGROUP, varval(vp));
101     }
102     else if (eq(vp, STRwordchars)) {
103 	word_chars = varval(vp);
104     }
105     else if (eq(vp, STRloginsh)) {
106 	loginsh = 1;
107     }
108     else if (eq(vp, STRanyerror)) {
109 	anyerror = 1;
110     }
111     else if (eq(vp, STRsymlinks)) {
112 	Char *pn = varval(vp);
113 
114 	if (eq(pn, STRignore))
115 	    symlinks = SYM_IGNORE;
116 	else if (eq(pn, STRexpand))
117 	    symlinks = SYM_EXPAND;
118 	else if (eq(pn, STRchase))
119 	    symlinks = SYM_CHASE;
120 	else
121 	    symlinks = 0;
122     }
123     else if (eq(vp, STRterm)) {
124 	Char *cp = varval(vp);
125 	tsetenv(STRKTERM, cp);
126 #ifdef DOESNT_WORK_RIGHT
127 	cp = getenv("TERMCAP");
128 	if (cp && (*cp != '/'))	/* if TERMCAP and not a path */
129 	    Unsetenv(STRTERMCAP);
130 #endif /* DOESNT_WORK_RIGHT */
131 	GotTermCaps = 0;
132 	if (noediting && Strcmp(cp, STRnetwork) != 0 &&
133 	    Strcmp(cp, STRunknown) != 0 && Strcmp(cp, STRdumb) != 0) {
134 	    editing = 1;
135 	    noediting = 0;
136 	    setNS(STRedit);
137 	}
138 	ed_Init();		/* reset the editor */
139     }
140     else if (eq(vp, STRhome)) {
141 	Char *cp, *canon;
142 
143 	cp = Strsave(varval(vp));	/* get the old value back */
144 	cleanup_push(cp, xfree);
145 
146 	/*
147 	 * convert to cononical pathname (possibly resolving symlinks)
148 	 */
149 	canon = dcanon(cp, cp);
150 	cleanup_ignore(cp);
151 	cleanup_until(cp);
152 	cleanup_push(canon, xfree);
153 
154 	setcopy(vp, canon, VAR_READWRITE);	/* have to save the new val */
155 
156 	/* and now mirror home with HOME */
157 	tsetenv(STRKHOME, canon);
158 	/* fix directory stack for new tilde home */
159 	dtilde();
160 	cleanup_until(canon);
161     }
162     else if (eq(vp, STRedit)) {
163 	editing = 1;
164 	noediting = 0;
165 	/* PWP: add more stuff in here later */
166     }
167     else if (eq(vp, STRshlvl)) {
168 	tsetenv(STRKSHLVL, varval(vp));
169     }
170     else if (eq(vp, STRignoreeof)) {
171 	Char *cp;
172 	numeof = 0;
173     	for ((cp = varval(STRignoreeof)); cp && *cp; cp++) {
174 	    if (!Isdigit(*cp)) {
175 		numeof = 0;
176 		break;
177 	    }
178 	    numeof = numeof * 10 + *cp - '0';
179 	}
180 	if (numeof <= 0) numeof = 26;	/* Sanity check */
181     }
182     else if (eq(vp, STRbackslash_quote)) {
183 	bslash_quote = 1;
184     }
185     else if (eq(vp, STRcompat_expr)) {
186 	compat_expr = 1;
187     }
188     else if (eq(vp, STRdirstack)) {
189 	dsetstack();
190     }
191     else if (eq(vp, STRrecognize_only_executables)) {
192 	tw_cmd_free();
193     }
194     else if (eq(vp, STRkillring)) {
195 	SetKillRing((int)getn(varval(vp)));
196     }
197     else if (eq(vp, STRhistory)) {
198 	sethistory((int)getn(varval(vp)));
199     }
200 #ifndef HAVENOUTMP
201     else if (eq(vp, STRwatch)) {
202 	resetwatch();
203     }
204 #endif /* HAVENOUTMP */
205     else if (eq(vp, STRimplicitcd)) {
206 	implicit_cd = ((eq(varval(vp), STRverbose)) ? 2 : 1);
207     }
208     else if (eq(vp, STRcdtohome)) {
209 	cdtohome = 1;
210     }
211 #ifdef COLOR_LS_F
212     else if (eq(vp, STRcolor)) {
213 	set_color_context();
214     }
215 #endif /* COLOR_LS_F */
216 #if defined(KANJI) && defined(SHORT_STRINGS) && defined(DSPMBYTE)
217     else if(eq(vp, CHECK_MBYTEVAR) || eq(vp, STRnokanji)) {
218 	update_dspmbyte_vars();
219     }
220 #endif
221 #ifdef NLS_CATALOGS
222     else if (eq(vp, STRcatalog)) {
223 	nlsclose();
224 	nlsinit();
225     }
226 #if defined(FILEC) && defined(TIOCSTI)
227     else if (eq(vp, STRfilec))
228 	filec = 1;
229 #endif
230 #endif /* NLS_CATALOGS */
231 }
232 
233 
234 /*ARGSUSED*/
235 void
236 doset(Char **v, struct command *c)
237 {
238     Char *p;
239     Char   *vp;
240     Char  **vecp;
241     int    hadsub;
242     int     subscr;
243     int	    flags = VAR_READWRITE;
244     int    first_match = 0;
245     int    last_match = 0;
246     int    changed = 0;
247 
248     USE(c);
249     v++;
250     do {
251 	changed = 0;
252 	/*
253 	 * Readonly addition From: Tim P. Starrin <noid@cyborg.larc.nasa.gov>
254 	 */
255 	if (*v && eq(*v, STRmr)) {
256 	    flags = VAR_READONLY;
257 	    v++;
258 	    changed = 1;
259 	}
260 	if (*v && eq(*v, STRmf) && !last_match) {
261 	    first_match = 1;
262 	    v++;
263 	    changed = 1;
264 	}
265 	if (*v && eq(*v, STRml) && !first_match) {
266 	    last_match = 1;
267 	    v++;
268 	    changed = 1;
269 	}
270     } while(changed);
271     p = *v++;
272     if (p == 0) {
273 	plist(&shvhed, flags);
274 	return;
275     }
276     do {
277 	hadsub = 0;
278 	vp = p;
279 	if (!letter(*p))
280 	    stderror(ERR_NAME | ERR_VARBEGIN);
281 	do {
282 	    p++;
283 	} while (alnum(*p));
284 	if (*p == '[') {
285 	    hadsub++;
286 	    p = getinx(p, &subscr);
287 	}
288 	if (*p != '\0' && *p != '=')
289 	    stderror(ERR_NAME | ERR_VARALNUM);
290 	if (*p == '=') {
291 	    *p++ = '\0';
292 	    if (*p == '\0' && *v != NULL && **v == '(')
293 		p = *v++;
294 	}
295 	else if (*v && eq(*v, STRequal)) {
296 	    if (*++v != NULL)
297 		p = *v++;
298 	}
299 	if (eq(p, STRLparen)) {
300 	    Char **e = v;
301 
302 	    if (hadsub)
303 		stderror(ERR_NAME | ERR_SYNTAX);
304 	    for (;;) {
305 		if (!*e)
306 		    stderror(ERR_NAME | ERR_MISSING, ')');
307 		if (**e == ')')
308 		    break;
309 		e++;
310 	    }
311 	    p = *e;
312 	    *e = 0;
313 	    vecp = saveblk(v);
314 	    if (first_match)
315 	       flags |= VAR_FIRST;
316 	    else if (last_match)
317 	       flags |= VAR_LAST;
318 
319 	    set1(vp, vecp, &shvhed, flags);
320 	    *e = p;
321 	    v = e + 1;
322 	}
323 	else if (hadsub) {
324 	    Char *copy;
325 
326 	    copy = Strsave(p);
327 	    cleanup_push(copy, xfree);
328 	    asx(vp, subscr, copy);
329 	    cleanup_ignore(copy);
330 	    cleanup_until(copy);
331 	}
332 	else
333 	    setv(vp, Strsave(p), flags);
334 	update_vars(vp);
335     } while ((p = *v++) != NULL);
336 }
337 
338 static Char *
339 getinx(Char *cp, int *ip)
340 {
341     *ip = 0;
342     *cp++ = 0;
343     while (*cp && Isdigit(*cp))
344 	*ip = *ip * 10 + *cp++ - '0';
345     if (*cp++ != ']')
346 	stderror(ERR_NAME | ERR_SUBSCRIPT);
347     return (cp);
348 }
349 
350 static void
351 asx(Char *vp, int subscr, Char *p)
352 {
353     struct varent *v = getvx(vp, subscr);
354     Char *prev;
355 
356     if (v->v_flags & VAR_READONLY)
357 	stderror(ERR_READONLY|ERR_NAME, v->v_name);
358     prev = v->vec[subscr - 1];
359     cleanup_push(prev, xfree);
360     v->vec[subscr - 1] = globone(p, G_APPEND);
361     cleanup_until(prev);
362 }
363 
364 static struct varent *
365 getvx(Char *vp, int subscr)
366 {
367     struct varent *v = adrof(vp);
368 
369     if (v == 0)
370 	udvar(vp);
371     if (subscr < 1 || subscr > blklen(v->vec))
372 	stderror(ERR_NAME | ERR_RANGE);
373     return (v);
374 }
375 
376 /*ARGSUSED*/
377 void
378 dolet(Char **v, struct command *dummy)
379 {
380     Char *p;
381     Char   *vp, c, op;
382     int    hadsub;
383     int     subscr;
384 
385     USE(dummy);
386     v++;
387     p = *v++;
388     if (p == 0) {
389 	prvars();
390 	return;
391     }
392     do {
393 	hadsub = 0;
394 	vp = p;
395 	if (letter(*p))
396 	    for (; alnum(*p); p++)
397 		continue;
398 	if (vp == p || !letter(*vp))
399 	    stderror(ERR_NAME | ERR_VARBEGIN);
400 	if (*p == '[') {
401 	    hadsub++;
402 	    p = getinx(p, &subscr);
403 	}
404 	if (*p == 0 && *v)
405 	    p = *v++;
406 	if ((op = *p) != 0)
407 	    *p++ = 0;
408 	else
409 	    stderror(ERR_NAME | ERR_ASSIGN);
410 
411 	/*
412 	 * if there is no expression after the '=' then print a "Syntax Error"
413 	 * message - strike
414 	 */
415 	if (*p == '\0' && *v == NULL)
416 	    stderror(ERR_NAME | ERR_ASSIGN);
417 
418 	vp = Strsave(vp);
419 	cleanup_push(vp, xfree);
420 	if (op == '=') {
421 	    c = '=';
422 	    p = xset(p, &v);
423 	}
424 	else {
425 	    c = *p++;
426 	    if (any("+-", c)) {
427 		if (c != op || *p)
428 		    stderror(ERR_NAME | ERR_UNKNOWNOP);
429 		p = Strsave(STR1);
430 	    }
431 	    else {
432 		if (any("<>", op)) {
433 		    if (c != op)
434 			stderror(ERR_NAME | ERR_UNKNOWNOP);
435 		    stderror(ERR_NAME | ERR_SYNTAX);
436 		}
437 		if (c != '=')
438 		    stderror(ERR_NAME | ERR_UNKNOWNOP);
439 		p = xset(p, &v);
440 	    }
441 	}
442 	cleanup_push(p, xfree);
443 	if (op == '=') {
444 	    if (hadsub)
445 		asx(vp, subscr, p);
446 	    else
447 		setv(vp, p, VAR_READWRITE);
448 	    cleanup_ignore(p);
449 	}
450 	else if (hadsub) {
451 	    struct varent *gv = getvx(vp, subscr);
452 	    Char *val;
453 
454 	    val = operate(op, gv->vec[subscr - 1], p);
455 	    cleanup_push(val, xfree);
456 	    asx(vp, subscr, val);
457 	    cleanup_ignore(val);
458 	    cleanup_until(val);
459 	}
460 	else {
461 	    Char *val;
462 
463 	    val = operate(op, varval(vp), p);
464 	    cleanup_push(val, xfree);
465 	    setv(vp, val, VAR_READWRITE);
466 	    cleanup_ignore(val);
467 	    cleanup_until(val);
468 	}
469 	update_vars(vp);
470 	cleanup_until(vp);
471     } while ((p = *v++) != NULL);
472 }
473 
474 static Char *
475 xset(Char *cp, Char ***vp)
476 {
477     Char *dp;
478 
479     if (*cp) {
480 	dp = Strsave(cp);
481 	--(*vp);
482 	xfree(** vp);
483 	**vp = dp;
484     }
485     return (putn(expr(vp)));
486 }
487 
488 static Char *
489 operate(int op, Char *vp, Char *p)
490 {
491     Char    opr[2];
492     Char   *vec[5];
493     Char **v = vec;
494     Char  **vecp = v;
495     tcsh_number_t i;
496 
497     if (op != '=') {
498 	if (*vp)
499 	    *v++ = vp;
500 	opr[0] = op;
501 	opr[1] = 0;
502 	*v++ = opr;
503 	if (op == '<' || op == '>')
504 	    *v++ = opr;
505     }
506     *v++ = p;
507     *v++ = 0;
508     i = expr(&vecp);
509     if (*vecp)
510 	stderror(ERR_NAME | ERR_EXPRESSION);
511     return (putn(i));
512 }
513 
514 static Char *putp;
515 
516 Char *
517 putn(tcsh_number_t n)
518 {
519     Char nbuf[1024]; /* Enough even for octal */
520 
521     putp = nbuf;
522     if (n < 0) {
523 	n = -n;
524 	*putp++ = '-';
525     }
526     putn1(n);
527     *putp = 0;
528     return (Strsave(nbuf));
529 }
530 
531 static void
532 putn1(tcsh_number_t n)
533 {
534     if (n > 9)
535 	putn1(n / 10);
536     *putp++ = (Char)(n % 10 + '0');
537 }
538 
539 tcsh_number_t
540 getn(const Char *cp)
541 {
542     tcsh_number_t n;
543     int     sign;
544     int base;
545 
546     if (!cp)			/* PWP: extra error checking */
547 	stderror(ERR_NAME | ERR_BADNUM);
548 
549     sign = 0;
550     if (cp[0] == '+' && cp[1])
551 	cp++;
552     if (*cp == '-') {
553 	sign++;
554 	cp++;
555 	if (!Isdigit(*cp))
556 	    stderror(ERR_NAME | ERR_BADNUM);
557     }
558 
559     if (cp[0] == '0' && cp[1] && is_set(STRparseoctal))
560 	base = 8;
561     else
562 	base = 10;
563 
564     n = 0;
565     while (Isdigit(*cp))
566     {
567 	if (base == 8 && *cp >= '8')
568 	    stderror(ERR_NAME | ERR_BADNUM);
569 	n = n * base + *cp++ - '0';
570     }
571     if (*cp)
572 	stderror(ERR_NAME | ERR_BADNUM);
573     return (sign ? -n : n);
574 }
575 
576 Char   *
577 value1(Char *var, struct varent *head)
578 {
579     struct varent *vp;
580 
581     if (!var || !head)		/* PWP: extra error checking */
582 	return (STRNULL);
583 
584     vp = adrof1(var, head);
585     return ((vp == NULL || vp->vec == NULL || vp->vec[0] == NULL) ?
586 	STRNULL : vp->vec[0]);
587 }
588 
589 static struct varent *
590 madrof(Char *pat, struct varent *vp)
591 {
592     struct varent *vp1;
593 
594     for (vp = vp->v_left; vp; vp = vp->v_right) {
595 	if (vp->v_left && (vp1 = madrof(pat, vp)) != NULL)
596 	    return vp1;
597 	if (Gmatch(vp->v_name, pat))
598 	    return vp;
599     }
600     return vp;
601 }
602 
603 struct varent *
604 adrof1(const Char *name, struct varent *v)
605 {
606     int cmp;
607 
608     v = v->v_left;
609     while (v && ((cmp = *name - *v->v_name) != 0 ||
610 		 (cmp = Strcmp(name, v->v_name)) != 0))
611 	if (cmp < 0)
612 	    v = v->v_left;
613 	else
614 	    v = v->v_right;
615     return v;
616 }
617 
618 void
619 setcopy(const Char *var, const Char *val, int flags)
620 {
621     Char *copy;
622 
623     copy = Strsave(val);
624     cleanup_push(copy, xfree);
625     setv(var, copy, flags);
626     cleanup_ignore(copy);
627     cleanup_until(copy);
628 }
629 
630 /*
631  * The caller is responsible for putting value in a safe place
632  */
633 void
634 setv(const Char *var, Char *val, int flags)
635 {
636     Char **vec = xmalloc(2 * sizeof(Char **));
637 
638     vec[0] = val;
639     vec[1] = 0;
640     set1(var, vec, &shvhed, flags);
641 }
642 
643 void
644 set1(const Char *var, Char **vec, struct varent *head, int flags)
645 {
646     Char **oldv = vec;
647 
648     if ((flags & VAR_NOGLOB) == 0) {
649 	int gflag;
650 
651 	gflag = tglob(oldv);
652 	if (gflag) {
653 	    vec = globall(oldv, gflag);
654 	    if (vec == 0) {
655 		blkfree(oldv);
656 		stderror(ERR_NAME | ERR_NOMATCH);
657 	    }
658 	    blkfree(oldv);
659 	}
660     }
661     /*
662      * Uniqueness addition from: Michael Veksler <mveksler@vnet.ibm.com>
663      */
664     if ( flags & (VAR_FIRST | VAR_LAST) ) {
665 	/*
666 	 * Code for -f (VAR_FIRST) and -l (VAR_LAST) options.
667 	 * Method:
668 	 *  Delete all duplicate words leaving "holes" in the word array (vec).
669 	 *  Then remove the "holes", keeping the order of the words unchanged.
670 	 */
671 	if (vec && vec[0] && vec[1]) { /* more than one word ? */
672 	    int i, j;
673 	    int num_items;
674 
675 	    for (num_items = 0; vec[num_items]; num_items++)
676 	        continue;
677 	    if (flags & VAR_FIRST) {
678 		/* delete duplications, keeping first occurance */
679 		for (i = 1; i < num_items; i++)
680 		    for (j = 0; j < i; j++)
681 			/* If have earlier identical item, remove i'th item */
682 			if (vec[i] && vec[j] && Strcmp(vec[j], vec[i]) == 0) {
683 			    xfree(vec[i]);
684 			    vec[i] = NULL;
685 			    break;
686 			}
687 	    } else if (flags & VAR_LAST) {
688 	      /* delete duplications, keeping last occurance */
689 		for (i = 0; i < num_items - 1; i++)
690 		    for (j = i + 1; j < num_items; j++)
691 			/* If have later identical item, remove i'th item */
692 			if (vec[i] && vec[j] && Strcmp(vec[j], vec[i]) == 0) {
693 			    /* remove identical item (the first) */
694 			    xfree(vec[i]);
695 			    vec[i] = NULL;
696 			}
697 	    }
698 	    /* Compress items - remove empty items */
699 	    for (j = i = 0; i < num_items; i++)
700 	       if (vec[i])
701 		  vec[j++] = vec[i];
702 
703 	    /* NULL-fy remaining items */
704 	    for (; j < num_items; j++)
705 		 vec[j] = NULL;
706 	}
707 	/* don't let the attribute propagate */
708 	flags &= ~(VAR_FIRST|VAR_LAST);
709     }
710     setq(var, vec, head, flags);
711 }
712 
713 
714 void
715 setq(const Char *name, Char **vec, struct varent *p, int flags)
716 {
717     struct varent *c;
718     int f;
719 
720     f = 0;			/* tree hangs off the header's left link */
721     while ((c = p->v_link[f]) != 0) {
722 	if ((f = *name - *c->v_name) == 0 &&
723 	    (f = Strcmp(name, c->v_name)) == 0) {
724 	    if (c->v_flags & VAR_READONLY)
725 		stderror(ERR_READONLY|ERR_NAME, c->v_name);
726 	    blkfree(c->vec);
727 	    c->v_flags = flags;
728 	    trim(c->vec = vec);
729 	    return;
730 	}
731 	p = c;
732 	f = f > 0;
733     }
734     p->v_link[f] = c = xmalloc(sizeof(struct varent));
735     c->v_name = Strsave(name);
736     c->v_flags = flags;
737     c->v_bal = 0;
738     c->v_left = c->v_right = 0;
739     c->v_parent = p;
740     balance(p, f, 0);
741     trim(c->vec = vec);
742 }
743 
744 /*ARGSUSED*/
745 void
746 unset(Char **v, struct command *c)
747 {
748     int did_roe, did_edit;
749 
750     USE(c);
751     did_roe = adrof(STRrecognize_only_executables) != NULL;
752     did_edit = adrof(STRedit) != NULL;
753     unset1(v, &shvhed);
754 
755 #if defined(FILEC) && defined(TIOCSTI)
756     if (adrof(STRfilec) == 0)
757 	filec = 0;
758 #endif /* FILEC && TIOCSTI */
759 
760     if (adrof(STRhistchars) == 0) {
761 	HIST = '!';
762 	HISTSUB = '^';
763     }
764     if (adrof(STRignoreeof) == 0)
765 	numeof = 0;
766     if (adrof(STRpromptchars) == 0) {
767 	PRCH = tcsh ? '>' : '%';
768 	PRCHROOT = '#';
769     }
770     if (adrof(STRhistlit) == 0)
771 	HistLit = 0;
772     if (adrof(STRloginsh) == 0)
773 	loginsh = 0;
774     if (adrof(STRanyerror) == 0)
775 	anyerror = 0;
776     if (adrof(STRwordchars) == 0)
777 	word_chars = STR_WORD_CHARS;
778     if (adrof(STRedit) == 0)
779 	editing = 0;
780     if (adrof(STRbackslash_quote) == 0)
781 	bslash_quote = 0;
782     if (adrof(STRcompat_expr) == 0)
783 	compat_expr = 0;
784     if (adrof(STRsymlinks) == 0)
785 	symlinks = 0;
786     if (adrof(STRimplicitcd) == 0)
787 	implicit_cd = 0;
788     if (adrof(STRcdtohome) == 0)
789 	cdtohome = 0;
790     if (adrof(STRkillring) == 0)
791 	SetKillRing(0);
792     if (did_edit && noediting && adrof(STRedit) == 0)
793 	noediting = 0;
794     if (did_roe && adrof(STRrecognize_only_executables) == 0)
795 	tw_cmd_free();
796     if (adrof(STRhistory) == 0)
797 	sethistory(0);
798 #ifdef COLOR_LS_F
799     if (adrof(STRcolor) == 0)
800 	set_color_context();
801 #endif /* COLOR_LS_F */
802 #if defined(KANJI) && defined(SHORT_STRINGS) && defined(DSPMBYTE)
803     update_dspmbyte_vars();
804 #endif
805 #ifdef NLS_CATALOGS
806     nlsclose();
807     nlsinit();
808 #endif /* NLS_CATALOGS */
809 }
810 
811 void
812 unset1(Char *v[], struct varent *head)
813 {
814     struct varent *vp;
815     int cnt;
816 
817     while (*++v) {
818 	cnt = 0;
819 	while ((vp = madrof(*v, head)) != NULL)
820 	    if (vp->v_flags & VAR_READONLY)
821 		stderror(ERR_READONLY|ERR_NAME, vp->v_name);
822 	    else
823 		unsetv1(vp), cnt++;
824 	if (cnt == 0)
825 	    setname(short2str(*v));
826     }
827 }
828 
829 void
830 unsetv(Char *var)
831 {
832     struct varent *vp;
833 
834     if ((vp = adrof1(var, &shvhed)) == 0)
835 	udvar(var);
836     unsetv1(vp);
837 }
838 
839 static void
840 unsetv1(struct varent *p)
841 {
842     struct varent *c, *pp;
843     int f;
844 
845     /*
846      * Free associated memory first to avoid complications.
847      */
848     blkfree(p->vec);
849     xfree(p->v_name);
850     /*
851      * If p is missing one child, then we can move the other into where p is.
852      * Otherwise, we find the predecessor of p, which is guaranteed to have no
853      * right child, copy it into p, and move it's left child into it.
854      */
855     if (p->v_right == 0)
856 	c = p->v_left;
857     else if (p->v_left == 0)
858 	c = p->v_right;
859     else {
860 	for (c = p->v_left; c->v_right; c = c->v_right)
861 	    continue;
862 	p->v_name = c->v_name;
863 	p->v_flags = c->v_flags;
864 	p->vec = c->vec;
865 	p = c;
866 	c = p->v_left;
867     }
868 
869     /*
870      * Move c into where p is.
871      */
872     pp = p->v_parent;
873     f = pp->v_right == p;
874     if ((pp->v_link[f] = c) != 0)
875 	c->v_parent = pp;
876     /*
877      * Free the deleted node, and rebalance.
878      */
879     xfree(p);
880     balance(pp, f, 1);
881 }
882 
883 /* Set variable name to NULL. */
884 void
885 setNS(const Char *varName)
886 {
887     setcopy(varName, STRNULL, VAR_READWRITE);
888 }
889 
890 /*ARGSUSED*/
891 void
892 shift(Char **v, struct command *c)
893 {
894     struct varent *argv;
895     Char *name;
896 
897     USE(c);
898     v++;
899     name = *v;
900     if (name == 0)
901 	name = STRargv;
902     else
903 	(void) strip(name);
904     argv = adrof(name);
905     if (argv == NULL || argv->vec == NULL)
906 	udvar(name);
907     if (argv->vec[0] == 0)
908 	stderror(ERR_NAME | ERR_NOMORE);
909     lshift(argv->vec, 1);
910     update_vars(name);
911 }
912 
913 void
914 exportpath(Char **val)
915 {
916     struct Strbuf buf = Strbuf_INIT;
917     Char    	*exppath;
918 
919     if (val)
920 	while (*val) {
921 	    Strbuf_append(&buf, *val++);
922 	    if (*val == 0 || eq(*val, STRRparen))
923 		break;
924 	    Strbuf_append1(&buf, PATHSEP);
925 	}
926     exppath = Strbuf_finish(&buf);
927     cleanup_push(exppath, xfree);
928     tsetenv(STRKPATH, exppath);
929     cleanup_until(exppath);
930 }
931 
932 #ifndef lint
933  /*
934   * Lint thinks these have null effect
935   */
936  /* macros to do single rotations on node p */
937 # define rright(p) (\
938 	t = (p)->v_left,\
939 	(t)->v_parent = (p)->v_parent,\
940 	(((p)->v_left = t->v_right) != NULL) ?\
941 	    (t->v_right->v_parent = (p)) : 0,\
942 	(t->v_right = (p))->v_parent = t,\
943 	(p) = t)
944 # define rleft(p) (\
945 	t = (p)->v_right,\
946 	((t)->v_parent = (p)->v_parent,\
947 	((p)->v_right = t->v_left) != NULL) ? \
948 		(t->v_left->v_parent = (p)) : 0,\
949 	(t->v_left = (p))->v_parent = t,\
950 	(p) = t)
951 #else
952 static struct varent *
953 rleft(struct varent *p)
954 {
955     return (p);
956 }
957 static struct varent *
958 rright(struct varent *p)
959 {
960     return (p);
961 }
962 
963 #endif /* ! lint */
964 
965 
966 /*
967  * Rebalance a tree, starting at p and up.
968  * F == 0 means we've come from p's left child.
969  * D == 1 means we've just done a delete, otherwise an insert.
970  */
971 static void
972 balance(struct varent *p, int f, int d)
973 {
974     struct varent *pp;
975 
976 #ifndef lint
977     struct varent *t;	/* used by the rotate macros */
978 #endif /* !lint */
979     int ff;
980 #ifdef lint
981     ff = 0;	/* Sun's lint is dumb! */
982 #endif
983 
984     /*
985      * Ok, from here on, p is the node we're operating on; pp is it's parent; f
986      * is the branch of p from which we have come; ff is the branch of pp which
987      * is p.
988      */
989     for (; (pp = p->v_parent) != 0; p = pp, f = ff) {
990 	ff = pp->v_right == p;
991 	if (f ^ d) {		/* right heavy */
992 	    switch (p->v_bal) {
993 	    case -1:		/* was left heavy */
994 		p->v_bal = 0;
995 		break;
996 	    case 0:		/* was balanced */
997 		p->v_bal = 1;
998 		break;
999 	    case 1:		/* was already right heavy */
1000 		switch (p->v_right->v_bal) {
1001 		case 1:	/* single rotate */
1002 		    pp->v_link[ff] = rleft(p);
1003 		    p->v_left->v_bal = 0;
1004 		    p->v_bal = 0;
1005 		    break;
1006 		case 0:	/* single rotate */
1007 		    pp->v_link[ff] = rleft(p);
1008 		    p->v_left->v_bal = 1;
1009 		    p->v_bal = -1;
1010 		    break;
1011 		case -1:	/* double rotate */
1012 		    (void) rright(p->v_right);
1013 		    pp->v_link[ff] = rleft(p);
1014 		    p->v_left->v_bal =
1015 			p->v_bal < 1 ? 0 : -1;
1016 		    p->v_right->v_bal =
1017 			p->v_bal > -1 ? 0 : 1;
1018 		    p->v_bal = 0;
1019 		    break;
1020 		default:
1021 		    break;
1022 		}
1023 		break;
1024 	    default:
1025 		break;
1026 	    }
1027 	}
1028 	else {			/* left heavy */
1029 	    switch (p->v_bal) {
1030 	    case 1:		/* was right heavy */
1031 		p->v_bal = 0;
1032 		break;
1033 	    case 0:		/* was balanced */
1034 		p->v_bal = -1;
1035 		break;
1036 	    case -1:		/* was already left heavy */
1037 		switch (p->v_left->v_bal) {
1038 		case -1:	/* single rotate */
1039 		    pp->v_link[ff] = rright(p);
1040 		    p->v_right->v_bal = 0;
1041 		    p->v_bal = 0;
1042 		    break;
1043 		case 0:	/* single rotate */
1044 		    pp->v_link[ff] = rright(p);
1045 		    p->v_right->v_bal = -1;
1046 		    p->v_bal = 1;
1047 		    break;
1048 		case 1:	/* double rotate */
1049 		    (void) rleft(p->v_left);
1050 		    pp->v_link[ff] = rright(p);
1051 		    p->v_left->v_bal =
1052 			p->v_bal < 1 ? 0 : -1;
1053 		    p->v_right->v_bal =
1054 			p->v_bal > -1 ? 0 : 1;
1055 		    p->v_bal = 0;
1056 		    break;
1057 		default:
1058 		    break;
1059 		}
1060 		break;
1061 	    default:
1062 		break;
1063 	    }
1064 	}
1065 	/*
1066 	 * If from insert, then we terminate when p is balanced. If from
1067 	 * delete, then we terminate when p is unbalanced.
1068 	 */
1069 	if ((p->v_bal == 0) ^ d)
1070 	    break;
1071     }
1072 }
1073 
1074 void
1075 plist(struct varent *p, int what)
1076 {
1077     struct varent *c;
1078     int len;
1079 
1080     for (;;) {
1081 	while (p->v_left)
1082 	    p = p->v_left;
1083 x:
1084 	if (p->v_parent == 0)	/* is it the header? */
1085 	    break;
1086 	if ((p->v_flags & what) != 0) {
1087 	    if (setintr) {
1088 		int old_pintr_disabled;
1089 
1090 		pintr_push_enable(&old_pintr_disabled);
1091 		cleanup_until(&old_pintr_disabled);
1092 	    }
1093 	    len = blklen(p->vec);
1094 	    xprintf("%S\t", p->v_name);
1095 	    if (len != 1)
1096 		xputchar('(');
1097 	    blkpr(p->vec);
1098 	    if (len != 1)
1099 		xputchar(')');
1100 	    xputchar('\n');
1101 	}
1102 	if (p->v_right) {
1103 	    p = p->v_right;
1104 	    continue;
1105 	}
1106 	do {
1107 	    c = p;
1108 	    p = p->v_parent;
1109 	} while (p->v_right == c);
1110 	goto x;
1111     }
1112 }
1113 
1114 #if defined(KANJI)
1115 # if defined(SHORT_STRINGS) && defined(DSPMBYTE)
1116 extern int dspmbyte_ls;
1117 
1118 void
1119 update_dspmbyte_vars(void)
1120 {
1121     int lp, iskcode;
1122     Char *dstr1;
1123     struct varent *vp;
1124 
1125     /* if variable "nokanji" is set, multi-byte display is disabled */
1126     if ((vp = adrof(CHECK_MBYTEVAR)) && !adrof(STRnokanji)) {
1127 	_enable_mbdisp = 1;
1128 	dstr1 = vp->vec[0];
1129 	if(eq (dstr1, STRsjis))
1130 	    iskcode = 1;
1131 	else if (eq(dstr1, STReuc))
1132 	    iskcode = 2;
1133 	else if (eq(dstr1, STRbig5))
1134 	    iskcode = 3;
1135 	else if (eq(dstr1, STRutf8))
1136 	    iskcode = 4;
1137 	else if ((dstr1[0] - '0') >= 0 && (dstr1[0] - '0') <= 3) {
1138 	    iskcode = 0;
1139 	}
1140 	else {
1141 	    xprintf(CGETS(18, 2,
1142 	       "Warning: unknown multibyte display; using default(euc(JP))\n"));
1143 	    iskcode = 2;
1144 	}
1145 	if (dstr1 && vp->vec[1] && eq(vp->vec[1], STRls))
1146 	  dspmbyte_ls = 1;
1147 	else
1148 	  dspmbyte_ls = 0;
1149 	for (lp = 0; lp < 256 && iskcode > 0; lp++) {
1150 	    switch (iskcode) {
1151 	    case 1:
1152 		/* Shift-JIS */
1153 		_cmap[lp] = _cmap_mbyte[lp];
1154 		_mbmap[lp] = _mbmap_sjis[lp];
1155 		break;
1156 	    case 2:
1157 		/* 2 ... euc */
1158 		_cmap[lp] = _cmap_mbyte[lp];
1159 		_mbmap[lp] = _mbmap_euc[lp];
1160 		break;
1161 	    case 3:
1162 		/* 3 ... big5 */
1163 		_cmap[lp] = _cmap_mbyte[lp];
1164 		_mbmap[lp] = _mbmap_big5[lp];
1165 		break;
1166 	    case 4:
1167 		/* 4 ... utf8 */
1168 		_cmap[lp] = _cmap_mbyte[lp];
1169 		_mbmap[lp] = _mbmap_utf8[lp];
1170 		break;
1171 	    default:
1172 		xprintf(CGETS(18, 3,
1173 		    "Warning: unknown multibyte code %d; multibyte disabled\n"),
1174 		    iskcode);
1175 		_cmap[lp] = _cmap_c[lp];
1176 		_mbmap[lp] = 0;	/* Default map all 0 */
1177 		_enable_mbdisp = 0;
1178 		break;
1179 	    }
1180 	}
1181 	if (iskcode == 0) {
1182 	    /* check original table */
1183 	    if (Strlen(dstr1) != 256) {
1184 		xprintf(CGETS(18, 4,
1185        "Warning: Invalid multibyte table length (%d); multibyte disabled\n"),
1186 		    Strlen(dstr1));
1187 		_enable_mbdisp = 0;
1188 	    }
1189 	    for (lp = 0; lp < 256 && _enable_mbdisp == 1; lp++) {
1190 		if (!((dstr1[lp] - '0') >= 0 && (dstr1[lp] - '0') <= 3)) {
1191 		    xprintf(CGETS(18, 4,
1192 	   "Warning: bad multibyte code at offset +%d; multibyte diabled\n"),
1193 			lp);
1194 		    _enable_mbdisp = 0;
1195 		    break;
1196 		}
1197 	    }
1198 	    /* set original table */
1199 	    for (lp = 0; lp < 256; lp++) {
1200 		if (_enable_mbdisp == 1) {
1201 		    _cmap[lp] = _cmap_mbyte[lp];
1202 		    _mbmap[lp] = (unsigned short) ((dstr1[lp] - '0') & 0x0f);
1203 		}
1204 		else {
1205 		    _cmap[lp] = _cmap_c[lp];
1206 		    _mbmap[lp] = 0;	/* Default map all 0 */
1207 		}
1208 	    }
1209 	}
1210     }
1211     else {
1212 	for (lp = 0; lp < 256; lp++) {
1213 	    _cmap[lp] = _cmap_c[lp];
1214 	    _mbmap[lp] = 0;	/* Default map all 0 */
1215 	}
1216 	_enable_mbdisp = 0;
1217 	dspmbyte_ls = 0;
1218     }
1219 #ifdef MBYTEDEBUG	/* Sorry, use for beta testing */
1220     {
1221 	Char mbmapstr[300];
1222 	for (lp = 0; lp < 256; lp++)
1223 	    mbmapstr[lp] = _mbmap[lp] + '0';
1224 	mbmapstr[lp] = 0;
1225 	setcopy(STRmbytemap, mbmapstr, VAR_READWRITE);
1226     }
1227 #endif /* MBYTEMAP */
1228 }
1229 
1230 /* dspkanji/dspmbyte autosetting */
1231 /* PATCH IDEA FROM Issei.Suzuki VERY THANKS */
1232 void
1233 autoset_dspmbyte(const Char *pcp)
1234 {
1235     int i;
1236     static const struct dspm_autoset_Table {
1237 	Char *n;
1238 	Char *v;
1239     } dspmt[] = {
1240 	{ STRLANGEUCJP, STReuc },
1241 	{ STRLANGEUCKR, STReuc },
1242 	{ STRLANGEUCZH, STReuc },
1243 	{ STRLANGEUCJPB, STReuc },
1244 	{ STRLANGEUCKRB, STReuc },
1245 	{ STRLANGEUCZHB, STReuc },
1246 #ifdef __linux__
1247 	{ STRLANGEUCJPC, STReuc },
1248 #endif
1249 	{ STRLANGSJIS, STRsjis },
1250 	{ STRLANGSJISB, STRsjis },
1251 	{ STRLANGBIG5, STRbig5 },
1252 	{ STRstarutfstar8, STRutf8 },
1253 	{ NULL, NULL }
1254     };
1255 #if defined(HAVE_NL_LANGINFO) && defined(CODESET)
1256     static const struct dspm_autoset_Table dspmc[] = {
1257 	{ STRstarutfstar8, STRutf8 },
1258 	{ STReuc, STReuc },
1259 	{ STRGB2312, STReuc },
1260 	{ STRLANGBIG5, STRbig5 },
1261 	{ NULL, NULL }
1262     };
1263     Char *codeset;
1264 
1265     codeset = str2short(nl_langinfo(CODESET));
1266     if (*codeset != '\0') {
1267 	for (i = 0; dspmc[i].n; i++) {
1268 	    const Char *estr;
1269 	    if (dspmc[i].n[0] && t_pmatch(pcp, dspmc[i].n, &estr, 0) > 0) {
1270 		setcopy(CHECK_MBYTEVAR, dspmc[i].v, VAR_READWRITE);
1271 		update_dspmbyte_vars();
1272 		return;
1273 	    }
1274 	}
1275     }
1276 #endif
1277 
1278     if (*pcp == '\0')
1279 	return;
1280 
1281     for (i = 0; dspmt[i].n; i++) {
1282 	const Char *estr;
1283 	if (dspmt[i].n[0] && t_pmatch(pcp, dspmt[i].n, &estr, 0) > 0) {
1284 	    setcopy(CHECK_MBYTEVAR, dspmt[i].v, VAR_READWRITE);
1285 	    update_dspmbyte_vars();
1286 	    break;
1287 	}
1288     }
1289 }
1290 # elif defined(AUTOSET_KANJI)
1291 void
1292 autoset_kanji(void)
1293 {
1294     char *codeset = nl_langinfo(CODESET);
1295 
1296     if (*codeset == '\0') {
1297 	if (adrof(STRnokanji) == NULL)
1298 	    setNS(STRnokanji);
1299 	return;
1300     }
1301 
1302     if (strcasestr(codeset, "SHIFT_JIS") == (char*)0) {
1303 	if (adrof(STRnokanji) == NULL)
1304 	    setNS(STRnokanji);
1305 	return;
1306     }
1307 
1308     if (adrof(STRnokanji) != NULL)
1309 	unsetv(STRnokanji);
1310 }
1311 #endif
1312 #endif
1313