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