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