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