sh.set.c revision 131962
1235783Skib/* $Header: /src/pub/tcsh/sh.set.c,v 3.48 2004/03/21 16:48:14 christos Exp $ */
2235783Skib/*
3235783Skib * sh.set.c: Setting and Clearing of variables
4235783Skib */
5235783Skib/*-
6235783Skib * Copyright (c) 1980, 1991 The Regents of the University of California.
7235783Skib * All rights reserved.
8235783Skib *
9235783Skib * Redistribution and use in source and binary forms, with or without
10235783Skib * modification, are permitted provided that the following conditions
11235783Skib * are met:
12235783Skib * 1. Redistributions of source code must retain the above copyright
13235783Skib *    notice, this list of conditions and the following disclaimer.
14235783Skib * 2. Redistributions in binary form must reproduce the above copyright
15235783Skib *    notice, this list of conditions and the following disclaimer in the
16235783Skib *    documentation and/or other materials provided with the distribution.
17235783Skib * 3. Neither the name of the University nor the names of its contributors
18235783Skib *    may be used to endorse or promote products derived from this software
19235783Skib *    without specific prior written permission.
20235783Skib *
21235783Skib * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22235783Skib * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23235783Skib * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24235783Skib * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25235783Skib * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26298951Sjhb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27235783Skib * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28235783Skib * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29268564Srpaulo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30235783Skib * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31235783Skib * SUCH DAMAGE.
32235783Skib */
33235783Skib#include "sh.h"
34235783Skib
35235783SkibRCSID("$Id: sh.set.c,v 3.48 2004/03/21 16:48:14 christos Exp $")
36235783Skib
37235783Skib#include "ed.h"
38235783Skib#include "tw.h"
39235783Skib
40235783Skibextern Char HistLit;
41235783Skibextern bool GotTermCaps;
42235783Skibint numeof = 0;
43235783Skib
44280183Sdumbbellstatic	void		 update_vars	__P((Char *));
45280183Sdumbbellstatic	Char		*getinx		__P((Char *, int *));
46280183Sdumbbellstatic	void		 asx		__P((Char *, int, Char *));
47235783Skibstatic	struct varent 	*getvx		__P((Char *, int));
48235783Skibstatic	Char		*xset		__P((Char *, Char ***));
49235783Skibstatic	Char		*operate	__P((int, Char *, Char *));
50235783Skibstatic	void	 	 putn1		__P((int));
51235783Skibstatic	struct varent	*madrof		__P((Char *, struct varent *));
52235783Skibstatic	void		 unsetv1	__P((struct varent *));
53235783Skibstatic	void		 exportpath	__P((Char **));
54235783Skibstatic	void		 balance	__P((struct varent *, int, int));
55235783Skib
56235783Skib/*
57235783Skib * C Shell
58235783Skib */
59235783Skib
60235783Skibstatic void
61235783Skibupdate_vars(vp)
62235783Skib    Char *vp;
63235783Skib{
64235783Skib    if (eq(vp, STRpath)) {
65235783Skib	exportpath(adrof(STRpath)->vec);
66235783Skib	dohash(NULL, NULL);
67235783Skib    }
68235783Skib    else if (eq(vp, STRhistchars)) {
69235783Skib	register Char *pn = varval(vp);
70235783Skib
71235783Skib	HIST = *pn++;
72235783Skib	HISTSUB = *pn;
73235783Skib    }
74235783Skib    else if (eq(vp, STRpromptchars)) {
75235783Skib	register Char *pn = varval(vp);
76235783Skib
77235783Skib	PRCH = *pn++;
78235783Skib	PRCHROOT = *pn;
79235783Skib    }
80235783Skib    else if (eq(vp, STRhistlit)) {
81235783Skib	HistLit = 1;
82235783Skib    }
83235783Skib    else if (eq(vp, STRuser)) {
84235783Skib	tsetenv(STRKUSER, varval(vp));
85235783Skib	tsetenv(STRLOGNAME, varval(vp));
86235783Skib    }
87235783Skib    else if (eq(vp, STRgroup)) {
88235783Skib	tsetenv(STRKGROUP, varval(vp));
89235783Skib    }
90235783Skib    else if (eq(vp, STRwordchars)) {
91235783Skib	word_chars = varval(vp);
92235783Skib    }
93235783Skib    else if (eq(vp, STRloginsh)) {
94235783Skib	loginsh = 1;
95235783Skib    }
96235783Skib    else if (eq(vp, STRsymlinks)) {
97235783Skib	register Char *pn = varval(vp);
98235783Skib
99235783Skib	if (eq(pn, STRignore))
100235783Skib	    symlinks = SYM_IGNORE;
101235783Skib	else if (eq(pn, STRexpand))
102235783Skib	    symlinks = SYM_EXPAND;
103235783Skib	else if (eq(pn, STRchase))
104235783Skib	    symlinks = SYM_CHASE;
105235783Skib	else
106235783Skib	    symlinks = 0;
107235783Skib    }
108235783Skib    else if (eq(vp, STRterm)) {
109235783Skib	Char *cp = varval(vp);
110235783Skib	tsetenv(STRKTERM, cp);
111280183Sdumbbell#ifdef DOESNT_WORK_RIGHT
112235783Skib	cp = getenv("TERMCAP");
113235783Skib	if (cp && (*cp != '/'))	/* if TERMCAP and not a path */
114235783Skib	    Unsetenv(STRTERMCAP);
115235783Skib#endif /* DOESNT_WORK_RIGHT */
116235783Skib	GotTermCaps = 0;
117235783Skib	if (noediting && Strcmp(cp, STRnetwork) != 0 &&
118235783Skib	    Strcmp(cp, STRunknown) != 0 && Strcmp(cp, STRdumb) != 0) {
119235783Skib	    editing = 1;
120235783Skib	    noediting = 0;
121235783Skib	    set(STRedit, Strsave(STRNULL), VAR_READWRITE);
122235783Skib	}
123235783Skib	ed_Init();		/* reset the editor */
124235783Skib    }
125235783Skib    else if (eq(vp, STRhome)) {
126235783Skib	Char *cp;
127235783Skib
128235783Skib	cp = Strsave(varval(vp));	/* get the old value back */
129235783Skib
130280183Sdumbbell	/*
131235783Skib	 * convert to cononical pathname (possibly resolving symlinks)
132235783Skib	 */
133235783Skib	cp = dcanon(cp, cp);
134235783Skib
135235783Skib	set(vp, Strsave(cp), VAR_READWRITE);	/* have to save the new val */
136235783Skib
137235783Skib	/* and now mirror home with HOME */
138235783Skib	tsetenv(STRKHOME, cp);
139235783Skib	/* fix directory stack for new tilde home */
140235783Skib	dtilde();
141235783Skib	xfree((ptr_t) cp);
142235783Skib    }
143235783Skib    else if (eq(vp, STRedit)) {
144235783Skib	editing = 1;
145235783Skib	noediting = 0;
146235783Skib	/* PWP: add more stuff in here later */
147235783Skib    }
148235783Skib    else if (eq(vp, STRshlvl)) {
149235783Skib	tsetenv(STRKSHLVL, varval(vp));
150235783Skib    }
151249249Sdumbbell    else if (eq(vp, STRignoreeof)) {
152296548Sdumbbell	Char *cp;
153235783Skib	numeof = 0;
154235783Skib    	for ((cp = varval(STRignoreeof)); cp && *cp; cp++) {
155235783Skib	    if (!Isdigit(*cp)) {
156235783Skib		numeof = 0;
157235783Skib		break;
158235783Skib	    }
159235783Skib	    numeof = numeof * 10 + *cp - '0';
160235783Skib	}
161235783Skib	if (numeof <= 0) numeof = 26;	/* Sanity check */
162235783Skib    }
163296548Sdumbbell    else if (eq(vp, STRbackslash_quote)) {
164235783Skib	bslash_quote = 1;
165235783Skib    }
166235783Skib    else if (eq(vp, STRdirstack)) {
167235783Skib	dsetstack();
168235783Skib    }
169235783Skib    else if (eq(vp, STRrecognize_only_executables)) {
170235783Skib	tw_cmd_free();
171235783Skib    }
172280183Sdumbbell    else if (eq(vp, STRkillring)) {
173235783Skib	SetKillRing(getn(varval(vp)));
174235783Skib    }
175235783Skib#ifndef HAVENOUTMP
176235783Skib    else if (eq(vp, STRwatch)) {
177235783Skib	resetwatch();
178235783Skib    }
179235783Skib#endif /* HAVENOUTMP */
180235783Skib    else if (eq(vp, STRimplicitcd)) {
181235783Skib	implicit_cd = ((eq(varval(vp), STRverbose)) ? 2 : 1);
182235783Skib    }
183235783Skib#ifdef COLOR_LS_F
184235783Skib    else if (eq(vp, STRcolor)) {
185235783Skib	set_color_context();
186235783Skib    }
187235783Skib#endif /* COLOR_LS_F */
188280183Sdumbbell#if defined(KANJI) && defined(SHORT_STRINGS) && defined(DSPMBYTE)
189235783Skib    else if(eq(vp, CHECK_MBYTEVAR) || eq(vp, STRnokanji)) {
190235783Skib	update_dspmbyte_vars();
191235783Skib    }
192235783Skib#endif
193235783Skib#ifdef NLS_CATALOGS
194235783Skib    else if (eq(vp, STRcatalog)) {
195235783Skib	(void) catclose(catd);
196235783Skib	nlsinit();
197235783Skib    }
198235783Skib#if defined(FILEC) && defined(TIOCSTI)
199235783Skib    else if (eq(vp, STRfilec))
200235783Skib	filec = 1;
201235783Skib#endif
202235783Skib#endif /* NLS_CATALOGS */
203235783Skib}
204235783Skib
205235783Skib
206235783Skib/*ARGSUSED*/
207235783Skibvoid
208235783Skibdoset(v, c)
209235783Skib    register Char **v;
210235783Skib    struct command *c;
211235783Skib{
212235783Skib    register Char *p;
213235783Skib    Char   *vp, op;
214235783Skib    Char  **vecp;
215235783Skib    bool    hadsub;
216235783Skib    int     subscr;
217235783Skib    int	    flags = VAR_READWRITE;
218235783Skib    bool    first_match = 0;
219235783Skib    bool    last_match = 0;
220235783Skib    bool    changed = 0;
221235783Skib
222235783Skib    USE(c);
223235783Skib    v++;
224235783Skib    do {
225235783Skib	changed = 0;
226235783Skib	/*
227235783Skib	 * Readonly addition From: Tim P. Starrin <noid@cyborg.larc.nasa.gov>
228235783Skib	 */
229235783Skib	if (*v && eq(*v, STRmr)) {
230235783Skib	    flags = VAR_READONLY;
231235783Skib	    v++;
232235783Skib	    changed = 1;
233235783Skib	}
234235783Skib	if (*v && eq(*v, STRmf) && !last_match) {
235235783Skib	    first_match = 1;
236235783Skib	    v++;
237235783Skib	    changed = 1;
238235783Skib	}
239235783Skib	if (*v && eq(*v, STRml) && !first_match) {
240235783Skib	    last_match = 1;
241235783Skib	    v++;
242235783Skib	    changed = 1;
243235783Skib	}
244235783Skib    } while(changed);
245235783Skib    p = *v++;
246235783Skib    if (p == 0) {
247235783Skib	plist(&shvhed, flags);
248235783Skib	return;
249235783Skib    }
250235783Skib    do {
251235783Skib	hadsub = 0;
252235783Skib	vp = p;
253235783Skib	if (letter(*p))
254235783Skib	    for (; alnum(*p); p++)
255235783Skib		continue;
256235783Skib	if (vp == p || !letter(*vp))
257235783Skib	    stderror(ERR_NAME | ERR_VARBEGIN);
258235783Skib	if ((p - vp) > MAXVARLEN) {
259235783Skib	    stderror(ERR_NAME | ERR_VARTOOLONG);
260280183Sdumbbell	    return;
261235783Skib	}
262235783Skib	if (*p == '[') {
263235783Skib	    hadsub++;
264235783Skib	    p = getinx(p, &subscr);
265235783Skib	}
266254819Sdumbbell	if ((op = *p) != 0) {
267235783Skib	    *p++ = 0;
268235783Skib	    if (*p == 0 && *v && **v == '(')
269235783Skib		p = *v++;
270235783Skib	}
271235783Skib	else if (*v && eq(*v, STRequal)) {
272235783Skib	    op = '=', v++;
273235783Skib	    if (*v)
274235783Skib		p = *v++;
275235783Skib	}
276235783Skib	if (op && op != '=')
277235783Skib	    stderror(ERR_NAME | ERR_SYNTAX);
278235783Skib	if (eq(p, STRLparen)) {
279	    register Char **e = v;
280
281	    if (hadsub)
282		stderror(ERR_NAME | ERR_SYNTAX);
283	    for (;;) {
284		if (!*e)
285		    stderror(ERR_NAME | ERR_MISSING, ')');
286		if (**e == ')')
287		    break;
288		e++;
289	    }
290	    p = *e;
291	    *e = 0;
292	    vecp = saveblk(v);
293	    if (first_match)
294	       flags |= VAR_FIRST;
295	    else if (last_match)
296	       flags |= VAR_LAST;
297
298	    set1(vp, vecp, &shvhed, flags);
299	    *e = p;
300	    v = e + 1;
301	}
302	else if (hadsub)
303	    asx(vp, subscr, Strsave(p));
304	else
305	    set(vp, Strsave(p), flags);
306	update_vars(vp);
307    } while ((p = *v++) != NULL);
308}
309
310static Char *
311getinx(cp, ip)
312    register Char *cp;
313    register int *ip;
314{
315    *ip = 0;
316    *cp++ = 0;
317    while (*cp && Isdigit(*cp))
318	*ip = *ip * 10 + *cp++ - '0';
319    if (*cp++ != ']')
320	stderror(ERR_NAME | ERR_SUBSCRIPT);
321    return (cp);
322}
323
324static void
325asx(vp, subscr, p)
326    Char   *vp;
327    int     subscr;
328    Char   *p;
329{
330    register struct varent *v = getvx(vp, subscr);
331
332    if (v->v_flags & VAR_READONLY)
333	stderror(ERR_READONLY|ERR_NAME, v->v_name);
334    xfree((ptr_t) v->vec[subscr - 1]);
335    v->vec[subscr - 1] = globone(p, G_APPEND);
336}
337
338static struct varent *
339getvx(vp, subscr)
340    Char   *vp;
341    int     subscr;
342{
343    register struct varent *v = adrof(vp);
344
345    if (v == 0)
346	udvar(vp);
347    if (subscr < 1 || subscr > blklen(v->vec))
348	stderror(ERR_NAME | ERR_RANGE);
349    return (v);
350}
351
352/*ARGSUSED*/
353void
354dolet(v, dummy)
355    Char  **v;
356    struct command *dummy;
357{
358    register Char *p;
359    Char   *vp, c, op;
360    bool    hadsub;
361    int     subscr;
362
363    USE(dummy);
364    v++;
365    p = *v++;
366    if (p == 0) {
367	prvars();
368	return;
369    }
370    do {
371	hadsub = 0;
372	vp = p;
373	if (letter(*p))
374	    for (; alnum(*p); p++)
375		continue;
376	if (vp == p || !letter(*vp))
377	    stderror(ERR_NAME | ERR_VARBEGIN);
378	if ((p - vp) > MAXVARLEN)
379	    stderror(ERR_NAME | ERR_VARTOOLONG);
380	if (*p == '[') {
381	    hadsub++;
382	    p = getinx(p, &subscr);
383	}
384	if (*p == 0 && *v)
385	    p = *v++;
386	if ((op = *p) != 0)
387	    *p++ = 0;
388	else
389	    stderror(ERR_NAME | ERR_ASSIGN);
390
391	/*
392	 * if there is no expression after the '=' then print a "Syntax Error"
393	 * message - strike
394	 */
395	if (*p == '\0' && *v == NULL)
396	    stderror(ERR_NAME | ERR_ASSIGN);
397
398	vp = Strsave(vp);
399	if (op == '=') {
400	    c = '=';
401	    p = xset(p, &v);
402	}
403	else {
404	    c = *p++;
405	    if (any("+-", c)) {
406		if (c != op || *p)
407		    stderror(ERR_NAME | ERR_UNKNOWNOP);
408		p = Strsave(STR1);
409	    }
410	    else {
411		if (any("<>", op)) {
412		    if (c != op)
413			stderror(ERR_NAME | ERR_UNKNOWNOP);
414		    c = *p++;
415		    stderror(ERR_NAME | ERR_SYNTAX);
416		}
417		if (c != '=')
418		    stderror(ERR_NAME | ERR_UNKNOWNOP);
419		p = xset(p, &v);
420	    }
421	}
422	if (op == '=') {
423	    if (hadsub)
424		asx(vp, subscr, p);
425	    else
426		set(vp, p, VAR_READWRITE);
427	}
428	else if (hadsub) {
429	    struct varent *gv = getvx(vp, subscr);
430
431	    asx(vp, subscr, operate(op, gv->vec[subscr - 1], p));
432	}
433	else
434	    set(vp, operate(op, varval(vp), p), VAR_READWRITE);
435	update_vars(vp);
436	xfree((ptr_t) vp);
437	if (c != '=')
438	    xfree((ptr_t) p);
439    } while ((p = *v++) != NULL);
440}
441
442static Char *
443xset(cp, vp)
444    Char   *cp, ***vp;
445{
446    register Char *dp;
447
448    if (*cp) {
449	dp = Strsave(cp);
450	--(*vp);
451	xfree((ptr_t) ** vp);
452	**vp = dp;
453    }
454    return (putn(expr(vp)));
455}
456
457static Char *
458operate(op, vp, p)
459    int     op;
460    Char    *vp, *p;
461{
462    Char    opr[2];
463    Char   *vec[5];
464    register Char **v = vec;
465    Char  **vecp = v;
466    register int i;
467
468    if (op != '=') {
469	if (*vp)
470	    *v++ = vp;
471	opr[0] = (Char) op;
472	opr[1] = 0;
473	*v++ = opr;
474	if (op == '<' || op == '>')
475	    *v++ = opr;
476    }
477    *v++ = p;
478    *v++ = 0;
479    i = expr(&vecp);
480    if (*vecp)
481	stderror(ERR_NAME | ERR_EXPRESSION);
482    return (putn(i));
483}
484
485static Char *putp, nbuf[50];
486
487Char   *
488putn(n)
489    register int n;
490{
491    int     num;
492
493    putp = nbuf;
494    if (n < 0) {
495	n = -n;
496	*putp++ = '-';
497    }
498    num = 2;			/* confuse lint */
499    if (sizeof(int) == num && ((unsigned int) n) == 0x8000) {
500	*putp++ = '3';
501	n = 2768;
502#ifdef pdp11
503    }
504#else /* !pdp11 */
505    }
506    else {
507	num = 4;		/* confuse lint */
508	if (sizeof(int) == num && ((unsigned int) n) == 0x80000000) {
509	    *putp++ = '2';
510	    n = 147483648;
511	}
512    }
513#endif /* pdp11 */
514    putn1(n);
515    *putp = 0;
516    return (Strsave(nbuf));
517}
518
519static void
520putn1(n)
521    register int n;
522{
523    if (n > 9)
524	putn1(n / 10);
525    *putp++ = n % 10 + '0';
526}
527
528int
529getn(cp)
530    register Char *cp;
531{
532    register int n;
533    int     sign;
534
535    if (!cp)			/* PWP: extra error checking */
536	stderror(ERR_NAME | ERR_BADNUM);
537
538    sign = 0;
539    if (cp[0] == '+' && cp[1])
540	cp++;
541    if (*cp == '-') {
542	sign++;
543	cp++;
544	if (!Isdigit(*cp))
545	    stderror(ERR_NAME | ERR_BADNUM);
546    }
547    n = 0;
548    while (Isdigit(*cp))
549	n = n * 10 + *cp++ - '0';
550    if (*cp)
551	stderror(ERR_NAME | ERR_BADNUM);
552    return (sign ? -n : n);
553}
554
555Char   *
556value1(var, head)
557    Char   *var;
558    struct varent *head;
559{
560    register struct varent *vp;
561
562    if (!var || !head)		/* PWP: extra error checking */
563	return (STRNULL);
564
565    vp = adrof1(var, head);
566    return ((vp == NULL || vp->vec == NULL || vp->vec[0] == NULL) ?
567	STRNULL : vp->vec[0]);
568}
569
570static struct varent *
571madrof(pat, vp)
572    Char   *pat;
573    register struct varent *vp;
574{
575    register struct varent *vp1;
576
577    for (vp = vp->v_left; vp; vp = vp->v_right) {
578	if (vp->v_left && (vp1 = madrof(pat, vp)) != NULL)
579	    return vp1;
580	if (Gmatch(vp->v_name, pat))
581	    return vp;
582    }
583    return vp;
584}
585
586struct varent *
587adrof1(name, v)
588    register Char *name;
589    register struct varent *v;
590{
591    int cmp;
592
593    v = v->v_left;
594    while (v && ((cmp = *name - *v->v_name) != 0 ||
595		 (cmp = Strcmp(name, v->v_name)) != 0))
596	if (cmp < 0)
597	    v = v->v_left;
598	else
599	    v = v->v_right;
600    return v;
601}
602
603/*
604 * The caller is responsible for putting value in a safe place
605 */
606void
607set(var, val, flags)
608    Char   *var, *val;
609    int	   flags;
610{
611    register Char **vec = (Char **) xmalloc((size_t) (2 * sizeof(Char **)));
612
613    vec[0] = val;
614    vec[1] = 0;
615    set1(var, vec, &shvhed, flags);
616}
617
618void
619set1(var, vec, head, flags)
620    Char   *var, **vec;
621    struct varent *head;
622    int flags;
623{
624    register Char **oldv = vec;
625
626    if ((flags & VAR_NOGLOB) == 0) {
627	gflag = 0;
628	tglob(oldv);
629	if (gflag) {
630	    vec = globall(oldv);
631	    if (vec == 0) {
632		blkfree(oldv);
633		stderror(ERR_NAME | ERR_NOMATCH);
634		return;
635	    }
636	    blkfree(oldv);
637	    gargv = 0;
638	}
639    }
640    /*
641     * Uniqueness addition from: Michael Veksler <mveksler@vnet.ibm.com>
642     */
643    if ( flags & (VAR_FIRST | VAR_LAST) ) {
644	/*
645	 * Code for -f (VAR_FIRST) and -l (VAR_LAST) options.
646	 * Method:
647	 *  Delete all duplicate words leaving "holes" in the word array (vec).
648	 *  Then remove the "holes", keeping the order of the words unchanged.
649	 */
650	if (vec && vec[0] && vec[1]) { /* more than one word ? */
651	    int i, j;
652	    int num_items;
653
654	    for (num_items = 0; vec[num_items]; num_items++)
655	        continue;
656	    if (flags & VAR_FIRST) {
657		/* delete duplications, keeping first occurance */
658		for (i = 1; i < num_items; i++)
659		    for (j = 0; j < i; j++)
660			/* If have earlier identical item, remove i'th item */
661			if (vec[i] && vec[j] && Strcmp(vec[j], vec[i]) == 0) {
662			    free(vec[i]);
663			    vec[i] = NULL;
664			    break;
665			}
666	    } else if (flags & VAR_LAST) {
667	      /* delete duplications, keeping last occurance */
668		for (i = 0; i < num_items - 1; i++)
669		    for (j = i + 1; j < num_items; j++)
670			/* If have later identical item, remove i'th item */
671			if (vec[i] && vec[j] && Strcmp(vec[j], vec[i]) == 0) {
672			    /* remove identical item (the first) */
673			    free(vec[i]);
674			    vec[i] = NULL;
675			}
676	    }
677	    /* Compress items - remove empty items */
678	    for (j = i = 0; i < num_items; i++)
679	       if (vec[i])
680		  vec[j++] = vec[i];
681
682	    /* NULL-fy remaining items */
683	    for (; j < num_items; j++)
684		 vec[j] = NULL;
685	}
686	/* don't let the attribute propagate */
687	flags &= ~(VAR_FIRST|VAR_LAST);
688    }
689    setq(var, vec, head, flags);
690}
691
692
693void
694setq(name, vec, p, flags)
695    Char   *name, **vec;
696    register struct varent *p;
697    int flags;
698{
699    register struct varent *c;
700    register int f;
701
702    f = 0;			/* tree hangs off the header's left link */
703    while ((c = p->v_link[f]) != 0) {
704	if ((f = *name - *c->v_name) == 0 &&
705	    (f = Strcmp(name, c->v_name)) == 0) {
706	    if (c->v_flags & VAR_READONLY)
707		stderror(ERR_READONLY|ERR_NAME, c->v_name);
708	    blkfree(c->vec);
709	    c->v_flags = flags;
710	    trim(c->vec = vec);
711	    return;
712	}
713	p = c;
714	f = f > 0;
715    }
716    p->v_link[f] = c = (struct varent *) xmalloc((size_t)sizeof(struct varent));
717    c->v_name = Strsave(name);
718    c->v_flags = flags;
719    c->v_bal = 0;
720    c->v_left = c->v_right = 0;
721    c->v_parent = p;
722    balance(p, f, 0);
723    trim(c->vec = vec);
724}
725
726/*ARGSUSED*/
727void
728unset(v, c)
729    Char   **v;
730    struct command *c;
731{
732    bool did_roe, did_edit;
733
734    USE(c);
735    did_roe = adrof(STRrecognize_only_executables) != NULL;
736    did_edit = adrof(STRedit) != NULL;
737    unset1(v, &shvhed);
738
739#if defined(FILEC) && defined(TIOCSTI)
740    if (adrof(STRfilec) == 0)
741	filec = 0;
742#endif /* FILEC && TIOCSTI */
743
744    if (adrof(STRhistchars) == 0) {
745	HIST = '!';
746	HISTSUB = '^';
747    }
748    if (adrof(STRignoreeof) == 0)
749	numeof = 0;
750    if (adrof(STRpromptchars) == 0) {
751	PRCH = '>';
752	PRCHROOT = '#';
753    }
754    if (adrof(STRhistlit) == 0)
755	HistLit = 0;
756    if (adrof(STRloginsh) == 0)
757	loginsh = 0;
758    if (adrof(STRwordchars) == 0)
759	word_chars = STR_WORD_CHARS;
760    if (adrof(STRedit) == 0)
761	editing = 0;
762    if (adrof(STRbackslash_quote) == 0)
763	bslash_quote = 0;
764    if (adrof(STRsymlinks) == 0)
765	symlinks = 0;
766    if (adrof(STRimplicitcd) == 0)
767	implicit_cd = 0;
768    if (adrof(STRkillring) == 0)
769	SetKillRing(0);
770    if (did_edit && noediting && adrof(STRedit) == 0)
771	noediting = 0;
772    if (did_roe && adrof(STRrecognize_only_executables) == 0)
773	tw_cmd_free();
774#ifdef COLOR_LS_F
775    if (adrof(STRcolor) == 0)
776	set_color_context();
777#endif /* COLOR_LS_F */
778#if defined(KANJI) && defined(SHORT_STRINGS) && defined(DSPMBYTE)
779    update_dspmbyte_vars();
780#endif
781#ifdef NLS_CATALOGS
782    (void) catclose(catd);
783    nlsinit();
784#endif /* NLS_CATALOGS */
785}
786
787void
788unset1(v, head)
789    register Char *v[];
790    struct varent *head;
791{
792    register struct varent *vp;
793    register int cnt;
794
795    while (*++v) {
796	cnt = 0;
797	while ((vp = madrof(*v, head)) != NULL)
798	    if (vp->v_flags & VAR_READONLY)
799		stderror(ERR_READONLY|ERR_NAME, vp->v_name);
800	    else
801		unsetv1(vp), cnt++;
802	if (cnt == 0)
803	    setname(short2str(*v));
804    }
805}
806
807void
808unsetv(var)
809    Char   *var;
810{
811    register struct varent *vp;
812
813    if ((vp = adrof1(var, &shvhed)) == 0)
814	udvar(var);
815    unsetv1(vp);
816}
817
818static void
819unsetv1(p)
820    register struct varent *p;
821{
822    register struct varent *c, *pp;
823    register int f;
824
825    /*
826     * Free associated memory first to avoid complications.
827     */
828    blkfree(p->vec);
829    xfree((ptr_t) p->v_name);
830    /*
831     * If p is missing one child, then we can move the other into where p is.
832     * Otherwise, we find the predecessor of p, which is guaranteed to have no
833     * right child, copy it into p, and move it's left child into it.
834     */
835    if (p->v_right == 0)
836	c = p->v_left;
837    else if (p->v_left == 0)
838	c = p->v_right;
839    else {
840	for (c = p->v_left; c->v_right; c = c->v_right)
841	    continue;
842	p->v_name = c->v_name;
843	p->v_flags = c->v_flags;
844	p->vec = c->vec;
845	p = c;
846	c = p->v_left;
847    }
848
849    /*
850     * Move c into where p is.
851     */
852    pp = p->v_parent;
853    f = pp->v_right == p;
854    if ((pp->v_link[f] = c) != 0)
855	c->v_parent = pp;
856    /*
857     * Free the deleted node, and rebalance.
858     */
859    xfree((ptr_t) p);
860    balance(pp, f, 1);
861}
862
863void
864setNS(cp)
865    Char   *cp;
866{
867    set(cp, Strsave(STRNULL), VAR_READWRITE);
868}
869
870/*ARGSUSED*/
871void
872shift(v, c)
873    register Char **v;
874    struct command *c;
875{
876    register struct varent *argv;
877    register Char *name;
878
879    USE(c);
880    v++;
881    name = *v;
882    if (name == 0)
883	name = STRargv;
884    else
885	(void) strip(name);
886    argv = adrof(name);
887    if (argv == NULL || argv->vec == NULL)
888	udvar(name);
889    if (argv->vec[0] == 0)
890	stderror(ERR_NAME | ERR_NOMORE);
891    lshift(argv->vec, 1);
892    update_vars(name);
893}
894
895static Char STRsep[2] = { PATHSEP, '\0' };
896
897static void
898exportpath(val)
899    Char  **val;
900{
901  Char    	*exppath;
902  size_t	exppath_size = BUFSIZE;
903  exppath = (Char *)xmalloc(sizeof(Char)*exppath_size);
904
905    exppath[0] = 0;
906    if (val)
907	while (*val) {
908	  while (Strlen(*val) + Strlen(exppath) + 2 > exppath_size) {
909	    if ((exppath
910		 = (Char *)xrealloc(exppath, sizeof(Char)*(exppath_size *= 2)))
911		 == NULL) {
912		xprintf(CGETS(18, 1,
913			      "Warning: ridiculously long PATH truncated\n"));
914		break;
915	      }
916	    }
917	    (void) Strcat(exppath, *val++);
918	    if (*val == 0 || eq(*val, STRRparen))
919	      break;
920	    (void) Strcat(exppath, STRsep);
921	  }
922  tsetenv(STRKPATH, exppath);
923  free(exppath);
924}
925
926#ifndef lint
927 /*
928  * Lint thinks these have null effect
929  */
930 /* macros to do single rotations on node p */
931# define rright(p) (\
932	t = (p)->v_left,\
933	(t)->v_parent = (p)->v_parent,\
934	(((p)->v_left = t->v_right) != NULL) ?\
935	    (t->v_right->v_parent = (p)) : 0,\
936	(t->v_right = (p))->v_parent = t,\
937	(p) = t)
938# define rleft(p) (\
939	t = (p)->v_right,\
940	((t)->v_parent = (p)->v_parent,\
941	((p)->v_right = t->v_left) != NULL) ? \
942		(t->v_left->v_parent = (p)) : 0,\
943	(t->v_left = (p))->v_parent = t,\
944	(p) = t)
945#else
946static struct varent *
947rleft(p)
948    struct varent *p;
949{
950    return (p);
951}
952static struct varent *
953rright(p)
954    struct varent *p;
955{
956    return (p);
957}
958
959#endif /* ! lint */
960
961
962/*
963 * Rebalance a tree, starting at p and up.
964 * F == 0 means we've come from p's left child.
965 * D == 1 means we've just done a delete, otherwise an insert.
966 */
967static void
968balance(p, f, d)
969    register struct varent *p;
970    register int f, d;
971{
972    register struct varent *pp;
973
974#ifndef lint
975    register struct varent *t;	/* used by the rotate macros */
976#endif /* !lint */
977    register int ff;
978#ifdef lint
979    ff = 0;	/* Sun's lint is dumb! */
980#endif
981
982    /*
983     * Ok, from here on, p is the node we're operating on; pp is it's parent; f
984     * is the branch of p from which we have come; ff is the branch of pp which
985     * is p.
986     */
987    for (; (pp = p->v_parent) != 0; p = pp, f = ff) {
988	ff = pp->v_right == p;
989	if (f ^ d) {		/* right heavy */
990	    switch (p->v_bal) {
991	    case -1:		/* was left heavy */
992		p->v_bal = 0;
993		break;
994	    case 0:		/* was balanced */
995		p->v_bal = 1;
996		break;
997	    case 1:		/* was already right heavy */
998		switch (p->v_right->v_bal) {
999		case 1:	/* sigle rotate */
1000		    pp->v_link[ff] = rleft(p);
1001		    p->v_left->v_bal = 0;
1002		    p->v_bal = 0;
1003		    break;
1004		case 0:	/* single rotate */
1005		    pp->v_link[ff] = rleft(p);
1006		    p->v_left->v_bal = 1;
1007		    p->v_bal = -1;
1008		    break;
1009		case -1:	/* double rotate */
1010		    (void) rright(p->v_right);
1011		    pp->v_link[ff] = rleft(p);
1012		    p->v_left->v_bal =
1013			p->v_bal < 1 ? 0 : -1;
1014		    p->v_right->v_bal =
1015			p->v_bal > -1 ? 0 : 1;
1016		    p->v_bal = 0;
1017		    break;
1018		default:
1019		    break;
1020		}
1021		break;
1022	    default:
1023		break;
1024	    }
1025	}
1026	else {			/* left heavy */
1027	    switch (p->v_bal) {
1028	    case 1:		/* was right heavy */
1029		p->v_bal = 0;
1030		break;
1031	    case 0:		/* was balanced */
1032		p->v_bal = -1;
1033		break;
1034	    case -1:		/* was already left heavy */
1035		switch (p->v_left->v_bal) {
1036		case -1:	/* single rotate */
1037		    pp->v_link[ff] = rright(p);
1038		    p->v_right->v_bal = 0;
1039		    p->v_bal = 0;
1040		    break;
1041		case 0:	/* signle rotate */
1042		    pp->v_link[ff] = rright(p);
1043		    p->v_right->v_bal = -1;
1044		    p->v_bal = 1;
1045		    break;
1046		case 1:	/* double rotate */
1047		    (void) rleft(p->v_left);
1048		    pp->v_link[ff] = rright(p);
1049		    p->v_left->v_bal =
1050			p->v_bal < 1 ? 0 : -1;
1051		    p->v_right->v_bal =
1052			p->v_bal > -1 ? 0 : 1;
1053		    p->v_bal = 0;
1054		    break;
1055		default:
1056		    break;
1057		}
1058		break;
1059	    default:
1060		break;
1061	    }
1062	}
1063	/*
1064	 * If from insert, then we terminate when p is balanced. If from
1065	 * delete, then we terminate when p is unbalanced.
1066	 */
1067	if ((p->v_bal == 0) ^ d)
1068	    break;
1069    }
1070}
1071
1072void
1073plist(p, what)
1074    register struct varent *p;
1075    int what;
1076{
1077    register struct varent *c;
1078    register int len;
1079
1080    if (setintr)
1081#ifdef BSDSIGS
1082	(void) sigsetmask(sigblock((sigmask_t) 0) & ~sigmask(SIGINT));
1083#else /* !BSDSIGS */
1084	(void) sigrelse(SIGINT);
1085#endif /* BSDSIGS */
1086
1087    for (;;) {
1088	while (p->v_left)
1089	    p = p->v_left;
1090x:
1091	if (p->v_parent == 0)	/* is it the header? */
1092	    return;
1093	if ((p->v_flags & what) != 0) {
1094	    len = blklen(p->vec);
1095	    xprintf("%S\t", p->v_name);
1096	    if (len != 1)
1097		xputchar('(');
1098	    blkpr(p->vec);
1099	    if (len != 1)
1100		xputchar(')');
1101	    xputchar('\n');
1102	}
1103	if (p->v_right) {
1104	    p = p->v_right;
1105	    continue;
1106	}
1107	do {
1108	    c = p;
1109	    p = p->v_parent;
1110	} while (p->v_right == c);
1111	goto x;
1112    }
1113}
1114
1115#if defined(KANJI) && defined(SHORT_STRINGS) && defined(DSPMBYTE)
1116bool dspmbyte_ls;
1117
1118void
1119update_dspmbyte_vars()
1120{
1121    int lp, iskcode;
1122    Char *dstr1;
1123    struct varent *vp;
1124
1125    /* if variable "nokanji" is set, multi-byte display is disabled */
1126    if ((vp = adrof(CHECK_MBYTEVAR)) && !adrof(STRnokanji)) {
1127	_enable_mbdisp = 1;
1128	dstr1 = vp->vec[0];
1129	if(eq (dstr1, STRKSJIS))
1130	    iskcode = 1;
1131	else if (eq(dstr1, STRKEUC))
1132	    iskcode = 2;
1133	else if (eq(dstr1, STRKBIG5))
1134	    iskcode = 3;
1135	else if (eq(dstr1, STRKUTF8))
1136	    iskcode = 4;
1137	else if ((dstr1[0] - '0') >= 0 && (dstr1[0] - '0') <= 3) {
1138	    iskcode = 0;
1139	}
1140	else {
1141	    xprintf(CGETS(18, 2,
1142	       "Warning: unknown multibyte display; using default(euc(JP))\n"));
1143	    iskcode = 2;
1144	}
1145	if (dstr1 && vp->vec[1] && eq(vp->vec[1], STRls))
1146	  dspmbyte_ls = 1;
1147	else
1148	  dspmbyte_ls = 0;
1149	for (lp = 0; lp < 256 && iskcode > 0; lp++) {
1150	    switch (iskcode) {
1151	    case 1:
1152		/* Shift-JIS */
1153		_cmap[lp] = _cmap_mbyte[lp];
1154		_mbmap[lp] = _mbmap_sjis[lp];
1155		break;
1156	    case 2:
1157		/* 2 ... euc */
1158		_cmap[lp] = _cmap_mbyte[lp];
1159		_mbmap[lp] = _mbmap_euc[lp];
1160		break;
1161	    case 3:
1162		/* 3 ... big5 */
1163		_cmap[lp] = _cmap_mbyte[lp];
1164		_mbmap[lp] = _mbmap_big5[lp];
1165		break;
1166	    case 4:
1167		/* 4 ... utf8 */
1168		_cmap[lp] = _cmap_mbyte[lp];
1169		_mbmap[lp] = _mbmap_utf8[lp];
1170		break;
1171	    default:
1172		xprintf(CGETS(18, 3,
1173		    "Warning: unknown multibyte code %d; multibyte disabled\n"),
1174		    iskcode);
1175		_cmap[lp] = _cmap_c[lp];
1176		_mbmap[lp] = 0;	/* Default map all 0 */
1177		_enable_mbdisp = 0;
1178		break;
1179	    }
1180	}
1181	if (iskcode == 0) {
1182	    /* check original table */
1183	    if (Strlen(dstr1) != 256) {
1184		xprintf(CGETS(18, 4,
1185       "Warning: Invalid multibyte table length (%d); multibyte disabled\n"),
1186		    Strlen(dstr1));
1187		_enable_mbdisp = 0;
1188	    }
1189	    for (lp = 0; lp < 256 && _enable_mbdisp == 1; lp++) {
1190		if (!((dstr1[lp] - '0') >= 0 && (dstr1[lp] - '0') <= 3)) {
1191		    xprintf(CGETS(18, 4,
1192	   "Warning: bad multibyte code at offset +%d; multibyte diabled\n"),
1193			lp);
1194		    _enable_mbdisp = 0;
1195		    break;
1196		}
1197	    }
1198	    /* set original table */
1199	    for (lp = 0; lp < 256; lp++) {
1200		if (_enable_mbdisp == 1) {
1201		    _cmap[lp] = _cmap_mbyte[lp];
1202		    _mbmap[lp] = (unsigned short) ((dstr1[lp] - '0') & 0x0f);
1203		}
1204		else {
1205		    _cmap[lp] = _cmap_c[lp];
1206		    _mbmap[lp] = 0;	/* Default map all 0 */
1207		}
1208	    }
1209	}
1210    }
1211    else {
1212	for (lp = 0; lp < 256; lp++) {
1213	    _cmap[lp] = _cmap_c[lp];
1214	    _mbmap[lp] = 0;	/* Default map all 0 */
1215	}
1216	_enable_mbdisp = 0;
1217	dspmbyte_ls = 0;
1218    }
1219#ifdef MBYTEDEBUG	/* Sorry, use for beta testing */
1220    {
1221	Char mbmapstr[300];
1222	for (lp = 0; lp < 256; lp++) {
1223	    mbmapstr[lp] = _mbmap[lp] + '0';
1224	    mbmapstr[lp+1] = 0;
1225	}
1226	set(STRmbytemap, Strsave(mbmapstr), VAR_READWRITE);
1227    }
1228#endif /* MBYTEMAP */
1229}
1230
1231/* dspkanji/dspmbyte autosetting */
1232/* PATCH IDEA FROM Issei.Suzuki VERY THANKS */
1233void
1234autoset_dspmbyte(pcp)
1235    Char *pcp;
1236{
1237    int i;
1238    struct dspm_autoset_Table {
1239	Char *n;
1240	Char *v;
1241    } dspmt[] = {
1242	{ STRLANGEUCJP, STRKEUC },
1243	{ STRLANGEUCKR, STRKEUC },
1244	{ STRLANGEUCZH, STRKEUC },
1245	{ STRLANGEUCJPB, STRKEUC },
1246	{ STRLANGEUCKRB, STRKEUC },
1247	{ STRLANGEUCZHB, STRKEUC },
1248#ifdef linux
1249	{ STRLANGEUCJPC, STRKEUC },
1250#endif
1251	{ STRLANGSJIS, STRKSJIS },
1252	{ STRLANGSJISB, STRKSJIS },
1253	{ STRLANGBIG5, STRKBIG5 },
1254	{ STRSTARKUTF8, STRKUTF8 },
1255	{ NULL, NULL }
1256    };
1257
1258    if (*pcp == '\0')
1259	return;
1260
1261    for (i = 0; dspmt[i].n; i++) {
1262	Char *estr;
1263	if (t_pmatch(pcp, dspmt[i].n, &estr, 1) > 0) {
1264	    set(CHECK_MBYTEVAR, Strsave(dspmt[i].v), VAR_READWRITE);
1265	    update_dspmbyte_vars();
1266	    break;
1267	}
1268    }
1269}
1270#endif
1271