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