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