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