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