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