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