]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/tcsh/sh.set.c
This commit was generated by cvs2svn to compensate for changes in r95567,
[FreeBSD/FreeBSD.git] / contrib / tcsh / sh.set.c
1 /* $Header: /src/pub/tcsh/sh.set.c,v 3.39 2001/03/18 19:06:30 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. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *      This product includes software developed by the University of
20  *      California, Berkeley and its contributors.
21  * 4. Neither the name of the University nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  */
37 #include "sh.h"
38
39 RCSID("$Id: sh.set.c,v 3.39 2001/03/18 19:06:30 christos Exp $")
40
41 #include "ed.h"
42 #include "tw.h"
43
44 extern Char HistLit;
45 extern bool GotTermCaps;
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         register Char *pn = varval(vp);
73
74         HIST = *pn++;
75         HISTSUB = *pn;
76     }
77     else if (eq(vp, STRpromptchars)) {
78         register 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         register 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         register 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, STRbackslash_quote)) {
155         bslash_quote = 1;
156     }
157     else if (eq(vp, STRdirstack)) {
158         dsetstack();
159     }
160     else if (eq(vp, STRrecognize_only_executables)) {
161         tw_cmd_free();
162     }
163     else if (eq(vp, STRkillring)) {
164         SetKillRing(getn(varval(vp)));
165     }
166 #ifndef HAVENOUTMP
167     else if (eq(vp, STRwatch)) {
168         resetwatch();
169     }
170 #endif /* HAVENOUTMP */
171     else if (eq(vp, STRimplicitcd)) {
172         implicit_cd = ((eq(varval(vp), STRverbose)) ? 2 : 1);
173     }
174 #ifdef COLOR_LS_F
175     else if (eq(vp, STRcolor)) {
176         set_color_context();
177     }
178 #endif /* COLOR_LS_F */
179 #if defined(KANJI) && defined(SHORT_STRINGS) && defined(DSPMBYTE)
180     else if(eq(vp, CHECK_MBYTEVAR) || eq(vp, STRnokanji)) {
181         update_dspmbyte_vars();
182     }
183 #endif
184 #ifdef NLS_CATALOGS
185     else if (eq(vp, STRcatalog)) {
186         (void) catclose(catd);
187         nlsinit();
188     }
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 == 0 || vp->vec[0] == 0 ? STRNULL : vp->vec[0]);
554 }
555
556 static struct varent *
557 madrof(pat, vp)
558     Char   *pat;
559     register struct varent *vp;
560 {
561     register struct varent *vp1;
562
563     for (vp = vp->v_left; vp; vp = vp->v_right) {
564         if (vp->v_left && (vp1 = madrof(pat, vp)) != NULL)
565             return vp1;
566         if (Gmatch(vp->v_name, pat))
567             return vp;
568     }
569     return vp;
570 }
571
572 struct varent *
573 adrof1(name, v)
574     register Char *name;
575     register struct varent *v;
576 {
577     int cmp;
578
579     v = v->v_left;
580     while (v && ((cmp = *name - *v->v_name) != 0 || 
581                  (cmp = Strcmp(name, v->v_name)) != 0))
582         if (cmp < 0)
583             v = v->v_left;
584         else
585             v = v->v_right;
586     return v;
587 }
588
589 /*
590  * The caller is responsible for putting value in a safe place
591  */
592 void
593 set(var, val, flags)
594     Char   *var, *val;
595     int    flags;
596 {
597     register Char **vec = (Char **) xmalloc((size_t) (2 * sizeof(Char **)));
598
599     vec[0] = val;
600     vec[1] = 0;
601     set1(var, vec, &shvhed, flags);
602 }
603
604 void
605 set1(var, vec, head, flags)
606     Char   *var, **vec;
607     struct varent *head;
608     int flags;
609 {
610     register Char **oldv = vec;
611
612     if ((flags & VAR_NOGLOB) == 0) {
613         gflag = 0;
614         tglob(oldv);
615         if (gflag) {
616             vec = globall(oldv);
617             if (vec == 0) {
618                 blkfree(oldv);
619                 stderror(ERR_NAME | ERR_NOMATCH);
620                 return;
621             }
622             blkfree(oldv);
623             gargv = 0;
624         }
625     }
626     /*
627      * Uniqueness addition from: Michael Veksler <mveksler@vnet.ibm.com>
628      */
629     if ( flags & (VAR_FIRST | VAR_LAST) ) {
630         /*
631          * Code for -f (VAR_FIRST) and -l (VAR_LAST) options.
632          * Method:
633          *  Delete all duplicate words leaving "holes" in the word array (vec).
634          *  Then remove the "holes", keeping the order of the words unchanged.
635          */
636         if (vec && vec[0] && vec[1]) { /* more than one word ? */
637             int i, j;
638             int num_items;
639
640             for (num_items = 0; vec[num_items]; num_items++)
641                 continue;
642             if (flags & VAR_FIRST) {
643                 /* delete duplications, keeping first occurance */
644                 for (i = 1; i < num_items; i++)
645                     for (j = 0; j < i; j++)
646                         /* If have earlier identical item, remove i'th item */
647                         if (vec[i] && vec[j] && Strcmp(vec[j], vec[i]) == 0) {
648                             free(vec[i]);
649                             vec[i] = NULL;
650                             break;
651                         }
652             } else if (flags & VAR_LAST) {
653               /* delete duplications, keeping last occurance */
654                 for (i = 0; i < num_items - 1; i++)
655                     for (j = i + 1; j < num_items; j++)
656                         /* If have later identical item, remove i'th item */
657                         if (vec[i] && vec[j] && Strcmp(vec[j], vec[i]) == 0) {
658                             /* remove identical item (the first) */
659                             free(vec[i]);
660                             vec[i] = NULL;
661                         }
662             }
663             /* Compress items - remove empty items */
664             for (j = i = 0; i < num_items; i++)
665                if (vec[i]) 
666                   vec[j++] = vec[i];
667
668             /* NULL-fy remaining items */
669             for (; j < num_items; j++)
670                  vec[j] = NULL;
671         }
672         /* don't let the attribute propagate */
673         flags &= ~(VAR_FIRST|VAR_LAST);
674     } 
675     setq(var, vec, head, flags);
676 }
677
678
679 void
680 setq(name, vec, p, flags)
681     Char   *name, **vec;
682     register struct varent *p;
683     int flags;
684 {
685     register struct varent *c;
686     register int f;
687
688     f = 0;                      /* tree hangs off the header's left link */
689     while ((c = p->v_link[f]) != 0) {
690         if ((f = *name - *c->v_name) == 0 &&
691             (f = Strcmp(name, c->v_name)) == 0) {
692             if (c->v_flags & VAR_READONLY)
693                 stderror(ERR_READONLY|ERR_NAME, c->v_name);
694             blkfree(c->vec);
695             c->v_flags = flags;
696             trim(c->vec = vec);
697             return;
698         }
699         p = c;
700         f = f > 0;
701     }
702     p->v_link[f] = c = (struct varent *) xmalloc((size_t)sizeof(struct varent));
703     c->v_name = Strsave(name);
704     c->v_flags = flags;
705     c->v_bal = 0;
706     c->v_left = c->v_right = 0;
707     c->v_parent = p;
708     balance(p, f, 0);
709     trim(c->vec = vec);
710 }
711
712 /*ARGSUSED*/
713 void
714 unset(v, c)
715     Char   **v;
716     struct command *c;
717 {
718     bool did_roe, did_edit;
719
720     USE(c);
721     did_roe = adrof(STRrecognize_only_executables) != NULL;
722     did_edit = adrof(STRedit) != NULL;
723     unset1(v, &shvhed);
724     if (adrof(STRhistchars) == 0) {
725         HIST = '!';
726         HISTSUB = '^';
727     }
728     if (adrof(STRpromptchars) == 0) {
729         PRCH = '>';
730         PRCHROOT = '#';
731     }
732     if (adrof(STRhistlit) == 0)
733         HistLit = 0;
734     if (adrof(STRloginsh) == 0)
735         loginsh = 0;
736     if (adrof(STRwordchars) == 0)
737         word_chars = STR_WORD_CHARS;
738     if (adrof(STRedit) == 0)
739         editing = 0;
740     if (adrof(STRbackslash_quote) == 0)
741         bslash_quote = 0;
742     if (adrof(STRsymlinks) == 0)
743         symlinks = 0;
744     if (adrof(STRimplicitcd) == 0)
745         implicit_cd = 0;
746     if (adrof(STRkillring) == 0)
747         SetKillRing(0);
748     if (did_edit && noediting && adrof(STRedit) == 0)
749         noediting = 0;
750     if (did_roe && adrof(STRrecognize_only_executables) == 0)
751         tw_cmd_free();
752 #ifdef COLOR_LS_F
753     if (adrof(STRcolor) == 0)
754         set_color_context();
755 #endif /* COLOR_LS_F */
756 #if defined(KANJI) && defined(SHORT_STRINGS) && defined(DSPMBYTE)
757     update_dspmbyte_vars();
758 #endif
759 #ifdef NLS_CATALOGS
760     (void) catclose(catd);
761     nlsinit();
762 #endif /* NLS_CATALOGS */
763 }
764
765 void
766 unset1(v, head)
767     register Char *v[];
768     struct varent *head;
769 {
770     register struct varent *vp;
771     register int cnt;
772
773     while (*++v) {
774         cnt = 0;
775         while ((vp = madrof(*v, head)) != NULL)
776             if (vp->v_flags & VAR_READONLY)
777                 stderror(ERR_READONLY|ERR_NAME, vp->v_name);
778             else
779                 unsetv1(vp), cnt++;
780         if (cnt == 0)
781             setname(short2str(*v));
782     }
783 }
784
785 void
786 unsetv(var)
787     Char   *var;
788 {
789     register struct varent *vp;
790
791     if ((vp = adrof1(var, &shvhed)) == 0)
792         udvar(var);
793     unsetv1(vp);
794 }
795
796 static void
797 unsetv1(p)
798     register struct varent *p;
799 {
800     register struct varent *c, *pp;
801     register int f;
802
803     /*
804      * Free associated memory first to avoid complications.
805      */
806     blkfree(p->vec);
807     xfree((ptr_t) p->v_name);
808     /*
809      * If p is missing one child, then we can move the other into where p is.
810      * Otherwise, we find the predecessor of p, which is guaranteed to have no
811      * right child, copy it into p, and move it's left child into it.
812      */
813     if (p->v_right == 0)
814         c = p->v_left;
815     else if (p->v_left == 0)
816         c = p->v_right;
817     else {
818         for (c = p->v_left; c->v_right; c = c->v_right)
819             continue;
820         p->v_name = c->v_name;
821         p->v_flags = c->v_flags;
822         p->vec = c->vec;
823         p = c;
824         c = p->v_left;
825     }
826
827     /*
828      * Move c into where p is.
829      */
830     pp = p->v_parent;
831     f = pp->v_right == p;
832     if ((pp->v_link[f] = c) != 0)
833         c->v_parent = pp;
834     /*
835      * Free the deleted node, and rebalance.
836      */
837     xfree((ptr_t) p);
838     balance(pp, f, 1);
839 }
840
841 void
842 setNS(cp)
843     Char   *cp;
844 {
845     set(cp, Strsave(STRNULL), VAR_READWRITE);
846 }
847
848 /*ARGSUSED*/
849 void
850 shift(v, c)
851     register Char **v;
852     struct command *c;
853 {
854     register struct varent *argv;
855     register Char *name;
856
857     USE(c);
858     v++;
859     name = *v;
860     if (name == 0)
861         name = STRargv;
862     else
863         (void) strip(name);
864     argv = adrof(name);
865     if (argv == 0)
866         udvar(name);
867     if (argv->vec[0] == 0)
868         stderror(ERR_NAME | ERR_NOMORE);
869     lshift(argv->vec, 1);
870     update_vars(name);
871 }
872
873 static Char STRsep[2] = { PATHSEP, '\0' };
874
875 static void
876 exportpath(val)
877     Char  **val;
878 {
879   Char          *exppath;
880   size_t        exppath_size = BUFSIZE;
881   exppath = (Char *)xmalloc(sizeof(Char)*exppath_size);
882
883     exppath[0] = 0;
884     if (val)
885         while (*val) {
886           while (Strlen(*val) + Strlen(exppath) + 2 > exppath_size) {
887             if ((exppath
888                  = (Char *)xrealloc(exppath, sizeof(Char)*(exppath_size *= 2)))
889                  == NULL) {
890                 xprintf(CGETS(18, 1,
891                               "Warning: ridiculously long PATH truncated\n"));
892                 break;
893               }
894             }
895             (void) Strcat(exppath, *val++);
896             if (*val == 0 || eq(*val, STRRparen))
897               break;
898             (void) Strcat(exppath, STRsep);
899           }
900   tsetenv(STRKPATH, exppath);
901   free(exppath);
902 }
903
904 #ifndef lint
905  /*
906   * Lint thinks these have null effect
907   */
908  /* macros to do single rotations on node p */
909 # define rright(p) (\
910         t = (p)->v_left,\
911         (t)->v_parent = (p)->v_parent,\
912         (((p)->v_left = t->v_right) != NULL) ?\
913             (t->v_right->v_parent = (p)) : 0,\
914         (t->v_right = (p))->v_parent = t,\
915         (p) = t)
916 # define rleft(p) (\
917         t = (p)->v_right,\
918         ((t)->v_parent = (p)->v_parent,\
919         ((p)->v_right = t->v_left) != NULL) ? \
920                 (t->v_left->v_parent = (p)) : 0,\
921         (t->v_left = (p))->v_parent = t,\
922         (p) = t)
923 #else
924 static struct varent *
925 rleft(p)
926     struct varent *p;
927 {
928     return (p);
929 }
930 static struct varent *
931 rright(p)
932     struct varent *p;
933 {
934     return (p);
935 }
936
937 #endif /* ! lint */
938
939
940 /*
941  * Rebalance a tree, starting at p and up.
942  * F == 0 means we've come from p's left child.
943  * D == 1 means we've just done a delete, otherwise an insert.
944  */
945 static void
946 balance(p, f, d)
947     register struct varent *p;
948     register int f, d;
949 {
950     register struct varent *pp;
951
952 #ifndef lint
953     register struct varent *t;  /* used by the rotate macros */
954 #endif /* !lint */
955     register int ff;
956 #ifdef lint
957     ff = 0;     /* Sun's lint is dumb! */
958 #endif
959
960     /*
961      * Ok, from here on, p is the node we're operating on; pp is it's parent; f
962      * is the branch of p from which we have come; ff is the branch of pp which
963      * is p.
964      */
965     for (; (pp = p->v_parent) != 0; p = pp, f = ff) {
966         ff = pp->v_right == p;
967         if (f ^ d) {            /* right heavy */
968             switch (p->v_bal) {
969             case -1:            /* was left heavy */
970                 p->v_bal = 0;
971                 break;
972             case 0:             /* was balanced */
973                 p->v_bal = 1;
974                 break;
975             case 1:             /* was already right heavy */
976                 switch (p->v_right->v_bal) {
977                 case 1: /* sigle rotate */
978                     pp->v_link[ff] = rleft(p);
979                     p->v_left->v_bal = 0;
980                     p->v_bal = 0;
981                     break;
982                 case 0: /* single rotate */
983                     pp->v_link[ff] = rleft(p);
984                     p->v_left->v_bal = 1;
985                     p->v_bal = -1;
986                     break;
987                 case -1:        /* double rotate */
988                     (void) rright(p->v_right);
989                     pp->v_link[ff] = rleft(p);
990                     p->v_left->v_bal =
991                         p->v_bal < 1 ? 0 : -1;
992                     p->v_right->v_bal =
993                         p->v_bal > -1 ? 0 : 1;
994                     p->v_bal = 0;
995                     break;
996                 default:
997                     break;
998                 }
999                 break;
1000             default:
1001                 break;
1002             }
1003         }
1004         else {                  /* left heavy */
1005             switch (p->v_bal) {
1006             case 1:             /* was right heavy */
1007                 p->v_bal = 0;
1008                 break;
1009             case 0:             /* was balanced */
1010                 p->v_bal = -1;
1011                 break;
1012             case -1:            /* was already left heavy */
1013                 switch (p->v_left->v_bal) {
1014                 case -1:        /* single rotate */
1015                     pp->v_link[ff] = rright(p);
1016                     p->v_right->v_bal = 0;
1017                     p->v_bal = 0;
1018                     break;
1019                 case 0: /* signle rotate */
1020                     pp->v_link[ff] = rright(p);
1021                     p->v_right->v_bal = -1;
1022                     p->v_bal = 1;
1023                     break;
1024                 case 1: /* double rotate */
1025                     (void) rleft(p->v_left);
1026                     pp->v_link[ff] = rright(p);
1027                     p->v_left->v_bal =
1028                         p->v_bal < 1 ? 0 : -1;
1029                     p->v_right->v_bal =
1030                         p->v_bal > -1 ? 0 : 1;
1031                     p->v_bal = 0;
1032                     break;
1033                 default:
1034                     break;
1035                 }
1036                 break;
1037             default:
1038                 break;
1039             }
1040         }
1041         /*
1042          * If from insert, then we terminate when p is balanced. If from
1043          * delete, then we terminate when p is unbalanced.
1044          */
1045         if ((p->v_bal == 0) ^ d)
1046             break;
1047     }
1048 }
1049
1050 void
1051 plist(p, what)
1052     register struct varent *p;
1053     int what;
1054 {
1055     register struct varent *c;
1056     register int len;
1057
1058     if (setintr)
1059 #ifdef BSDSIGS
1060         (void) sigsetmask(sigblock((sigmask_t) 0) & ~sigmask(SIGINT));
1061 #else /* !BSDSIGS */
1062         (void) sigrelse(SIGINT);
1063 #endif /* BSDSIGS */
1064
1065     for (;;) {
1066         while (p->v_left)
1067             p = p->v_left;
1068 x:
1069         if (p->v_parent == 0)   /* is it the header? */
1070             return;
1071         if ((p->v_flags & what) != 0) {
1072             len = blklen(p->vec);
1073             xprintf("%S\t", p->v_name);
1074             if (len != 1)
1075                 xputchar('(');
1076             blkpr(p->vec);
1077             if (len != 1)
1078                 xputchar(')');
1079             xputchar('\n');
1080         }
1081         if (p->v_right) {
1082             p = p->v_right;
1083             continue;
1084         }
1085         do {
1086             c = p;
1087             p = p->v_parent;
1088         } while (p->v_right == c);
1089         goto x;
1090     }
1091 }
1092
1093 #if defined(KANJI) && defined(SHORT_STRINGS) && defined(DSPMBYTE)
1094 bool dspmbyte_ls;
1095
1096 void
1097 update_dspmbyte_vars()
1098 {
1099     int lp, iskcode;
1100     Char *dstr1;
1101     struct varent *vp;
1102     
1103     /* if variable "nokanji" is set, multi-byte display is disabled */
1104     if ((vp = adrof(CHECK_MBYTEVAR)) && !adrof(STRnokanji)) {
1105         _enable_mbdisp = 1;
1106         dstr1 = vp->vec[0];
1107         if(eq (dstr1, STRKSJIS))
1108             iskcode = 1;
1109         else if (eq(dstr1, STRKEUC))
1110             iskcode = 2;
1111         else if (eq(dstr1, STRKBIG5))
1112             iskcode = 3;
1113         else if ((dstr1[0] - '0') >= 0 && (dstr1[0] - '0') <= 3) {
1114             iskcode = 0;
1115         }
1116         else {
1117             xprintf(CGETS(18, 2,
1118                "Warning: unknown multibyte display; using default(euc(JP))\n"));
1119             iskcode = 2;
1120         }
1121         if (dstr1 && vp->vec[1] && eq(vp->vec[1], STRls))
1122           dspmbyte_ls = 1;
1123         else
1124           dspmbyte_ls = 0;
1125         for (lp = 0; lp < 256 && iskcode > 0; lp++) {
1126             switch (iskcode) {
1127             case 1:
1128                 /* Shift-JIS */
1129                 _cmap[lp] = _cmap_mbyte[lp];
1130                 _mbmap[lp] = _mbmap_sjis[lp];
1131                 break;
1132             case 2:
1133                 /* 2 ... euc */
1134                 _cmap[lp] = _cmap_mbyte[lp];
1135                 _mbmap[lp] = _mbmap_euc[lp];
1136                 break;
1137             case 3:
1138                 /* 3 ... big5 */
1139                 _cmap[lp] = _cmap_mbyte[lp];
1140                 _mbmap[lp] = _mbmap_big5[lp];
1141                 break;
1142             default:
1143                 xprintf(CGETS(18, 3,
1144                     "Warning: unknown multibyte code %d; multibyte disabled\n"),
1145                     iskcode);
1146                 _cmap[lp] = _cmap_c[lp];
1147                 _mbmap[lp] = 0; /* Default map all 0 */
1148                 _enable_mbdisp = 0;
1149                 break;
1150             }
1151         }
1152         if (iskcode == 0) {
1153             /* check original table */
1154             if (Strlen(dstr1) != 256) {
1155                 xprintf(CGETS(18, 4,
1156        "Warning: Invalid multibyte table length (%d); multibyte disabled\n"),
1157                     Strlen(dstr1));
1158                 _enable_mbdisp = 0;
1159             }
1160             for (lp = 0; lp < 256 && _enable_mbdisp == 1; lp++) {
1161                 if (!((dstr1[lp] - '0') >= 0 && (dstr1[lp] - '0') <= 3)) {
1162                     xprintf(CGETS(18, 4,
1163            "Warning: bad multibyte code at offset +%d; multibyte diabled\n"),
1164                         lp);
1165                     _enable_mbdisp = 0;
1166                     break;
1167                 }
1168             }
1169             /* set original table */
1170             for (lp = 0; lp < 256; lp++) {
1171                 if (_enable_mbdisp == 1) {
1172                     _cmap[lp] = _cmap_mbyte[lp];
1173                     _mbmap[lp] = (unsigned short) ((dstr1[lp] - '0') & 0x0f);
1174                 }
1175                 else {
1176                     _cmap[lp] = _cmap_c[lp];
1177                     _mbmap[lp] = 0;     /* Default map all 0 */
1178                 }
1179             }
1180         }
1181     }
1182     else {
1183         for (lp = 0; lp < 256; lp++) {
1184             _cmap[lp] = _cmap_c[lp];
1185             _mbmap[lp] = 0;     /* Default map all 0 */
1186         }
1187         _enable_mbdisp = 0;
1188         dspmbyte_ls = 0;
1189     }
1190 #ifdef MBYTEDEBUG       /* Sorry, use for beta testing */
1191     {
1192         Char mbmapstr[300];
1193         for (lp = 0; lp < 256; lp++) {
1194             mbmapstr[lp] = _mbmap[lp] + '0';
1195             mbmapstr[lp+1] = 0;
1196         }
1197         set(STRmbytemap, Strsave(mbmapstr), VAR_READWRITE);
1198     }
1199 #endif /* MBYTEMAP */
1200 }
1201
1202 /* dspkanji/dspmbyte autosetting */
1203 /* PATCH IDEA FROM Issei.Suzuki VERY THANKS */
1204 void
1205 autoset_dspmbyte(pcp)
1206     Char *pcp;
1207 {
1208     int i;
1209     struct dspm_autoset_Table {
1210         Char *n;
1211         Char *v;
1212     } dspmt[] = {
1213         { STRLANGEUCJP, STRKEUC },
1214         { STRLANGEUCKR, STRKEUC },
1215         { STRLANGEUCZH, STRKEUC },
1216         { STRLANGEUCJPB, STRKEUC },
1217         { STRLANGEUCKRB, STRKEUC },
1218         { STRLANGEUCZHB, STRKEUC },
1219         { STRLANGSJIS, STRKSJIS },
1220         { STRLANGSJISB, STRKSJIS },
1221         { STRLANGBIG5, STRKBIG5 },
1222         { NULL, NULL }
1223     };
1224
1225     if (*pcp == '\0')
1226         return;
1227
1228     for (i = 0; dspmt[i].n; i++) {
1229         if (eq(pcp, dspmt[i].n)) {
1230             set(CHECK_MBYTEVAR, Strsave(dspmt[i].v), VAR_READWRITE);
1231             update_dspmbyte_vars();
1232             break;
1233         }
1234     }
1235 }
1236 #endif