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