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