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