diff options
Diffstat (limited to 'bin/csh/set.c')
| -rw-r--r-- | bin/csh/set.c | 844 | 
1 files changed, 844 insertions, 0 deletions
| diff --git a/bin/csh/set.c b/bin/csh/set.c new file mode 100644 index 000000000000..b7b7ff155451 --- /dev/null +++ b/bin/csh/set.c @@ -0,0 +1,844 @@ +/*- + * Copyright (c) 1980, 1991, 1993 + *	The Regents of the University of California.  All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + *    must display the following acknowledgement: + *	This product includes software developed by the University of + *	California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + *    may be used to endorse or promote products derived from this software + *    without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)set.c	8.1 (Berkeley) 5/31/93"; +#endif /* not lint */ + +#include <sys/types.h> +#include <stdlib.h> +#ifndef SHORT_STRINGS +#include <string.h> +#endif /* SHORT_STRINGS */ +#if __STDC__ +# include <stdarg.h> +#else +# include <varargs.h> +#endif + +#include "csh.h" +#include "extern.h" + +static Char	*getinx __P((Char *, int *)); +static void	 asx __P((Char *, int, Char *)); +static struct varent +		*getvx __P((Char *, int)); +static Char	*xset __P((Char *, Char ***)); +static Char	*operate __P((int, Char *, Char *)); +static void	 putn1 __P((int)); +static struct varent +		*madrof __P((Char *, struct varent *)); +static void	 unsetv1 __P((struct varent *)); +static void	 exportpath __P((Char **)); +static void	 balance __P((struct varent *, int, int)); + + +/* + * C Shell + */ + +void +/*ARGSUSED*/ +doset(v, t) +    Char **v; +    struct command *t; +{ +    register Char *p; +    Char   *vp, op; +    Char  **vecp; +    bool    hadsub; +    int     subscr; + +    v++; +    p = *v++; +    if (p == 0) { +	prvars(); +	return; +    } +    do { +	hadsub = 0; +	vp = p; +	if (letter(*p)) +	    for (; alnum(*p); p++) +		continue; +	if (vp == p || !letter(*vp)) +	    stderror(ERR_NAME | ERR_VARBEGIN); +	if ((p - vp) > MAXVARLEN) { +	    stderror(ERR_NAME | ERR_VARTOOLONG); +	    return; +	} +	if (*p == '[') { +	    hadsub++; +	    p = getinx(p, &subscr); +	} +	if ((op = *p) != '\0') { +	    *p++ = 0; +	    if (*p == 0 && *v && **v == '(') +		p = *v++; +	} +	else if (*v && eq(*v, STRequal)) { +	    op = '=', v++; +	    if (*v) +		p = *v++; +	} +	if (op && op != '=') +	    stderror(ERR_NAME | ERR_SYNTAX); +	if (eq(p, STRLparen)) { +	    register Char **e = v; + +	    if (hadsub) +		stderror(ERR_NAME | ERR_SYNTAX); +	    for (;;) { +		if (!*e) +		    stderror(ERR_NAME | ERR_MISSING, ')'); +		if (**e == ')') +		    break; +		e++; +	    } +	    p = *e; +	    *e = 0; +	    vecp = saveblk(v); +	    set1(vp, vecp, &shvhed); +	    *e = p; +	    v = e + 1; +	} +	else if (hadsub) +	    asx(vp, subscr, Strsave(p)); +	else +	    set(vp, Strsave(p)); +	if (eq(vp, STRpath)) { +	    exportpath(adrof(STRpath)->vec); +	    dohash(NULL, NULL); +	} +	else if (eq(vp, STRhistchars)) { +	    register Char *pn = value(STRhistchars); + +	    HIST = *pn++; +	    HISTSUB = *pn; +	} +	else if (eq(vp, STRuser)) { +	    Setenv(STRUSER, value(vp)); +	    Setenv(STRLOGNAME, value(vp)); +	} +	else if (eq(vp, STRwordchars)) { +	    word_chars = value(vp); +	} +	else if (eq(vp, STRterm)) +	    Setenv(STRTERM, value(vp)); +	else if (eq(vp, STRhome)) { +	    register Char *cp; + +	    cp = Strsave(value(vp));	/* get the old value back */ + +	    /* +	     * convert to cononical pathname (possibly resolving symlinks) +	     */ +	    cp = dcanon(cp, cp); + +	    set(vp, Strsave(cp));	/* have to save the new val */ + +	    /* and now mirror home with HOME */ +	    Setenv(STRHOME, cp); +	    /* fix directory stack for new tilde home */ +	    dtilde(); +	    xfree((ptr_t) cp); +	} +#ifdef FILEC +	else if (eq(vp, STRfilec)) +	    filec = 1; +#endif +    } while ((p = *v++) != NULL); +} + +static Char * +getinx(cp, ip) +    register Char *cp; +    register int *ip; +{ + +    *ip = 0; +    *cp++ = 0; +    while (*cp && Isdigit(*cp)) +	*ip = *ip * 10 + *cp++ - '0'; +    if (*cp++ != ']') +	stderror(ERR_NAME | ERR_SUBSCRIPT); +    return (cp); +} + +static void +asx(vp, subscr, p) +    Char   *vp; +    int     subscr; +    Char   *p; +{ +    register struct varent *v = getvx(vp, subscr); + +    xfree((ptr_t) v->vec[subscr - 1]); +    v->vec[subscr - 1] = globone(p, G_APPEND); +} + +static struct varent * +getvx(vp, subscr) +    Char   *vp; +    int     subscr; +{ +    register struct varent *v = adrof(vp); + +    if (v == 0) +	udvar(vp); +    if (subscr < 1 || subscr > blklen(v->vec)) +	stderror(ERR_NAME | ERR_RANGE); +    return (v); +} + +void +/*ARGSUSED*/ +dolet(v, t) +    Char **v; +    struct command *t; +{ +    register Char *p; +    Char   *vp, c, op; +    bool    hadsub; +    int     subscr; + +    v++; +    p = *v++; +    if (p == 0) { +	prvars(); +	return; +    } +    do { +	hadsub = 0; +	vp = p; +	if (letter(*p)) +	    for (; alnum(*p); p++) +		continue; +	if (vp == p || !letter(*vp)) +	    stderror(ERR_NAME | ERR_VARBEGIN); +	if ((p - vp) > MAXVARLEN) +	    stderror(ERR_NAME | ERR_VARTOOLONG); +	if (*p == '[') { +	    hadsub++; +	    p = getinx(p, &subscr); +	} +	if (*p == 0 && *v) +	    p = *v++; +	if ((op = *p) != '\0') +	    *p++ = 0; +	else +	    stderror(ERR_NAME | ERR_ASSIGN); + +	if (*p == '\0' && *v == NULL) +	    stderror(ERR_NAME | ERR_ASSIGN); + +	vp = Strsave(vp); +	if (op == '=') { +	    c = '='; +	    p = xset(p, &v); +	} +	else { +	    c = *p++; +	    if (any("+-", c)) { +		if (c != op || *p) +		    stderror(ERR_NAME | ERR_UNKNOWNOP); +		p = Strsave(STR1); +	    } +	    else { +		if (any("<>", op)) { +		    if (c != op) +			stderror(ERR_NAME | ERR_UNKNOWNOP); +		    c = *p++; +		    stderror(ERR_NAME | ERR_SYNTAX); +		} +		if (c != '=') +		    stderror(ERR_NAME | ERR_UNKNOWNOP); +		p = xset(p, &v); +	    } +	} +	if (op == '=') +	    if (hadsub) +		asx(vp, subscr, p); +	    else +		set(vp, p); +	else if (hadsub) { +	    struct varent *gv = getvx(vp, subscr); + +	    asx(vp, subscr, operate(op, gv->vec[subscr - 1], p)); +	} +	else +	    set(vp, operate(op, value(vp), p)); +	if (eq(vp, STRpath)) { +	    exportpath(adrof(STRpath)->vec); +	    dohash(NULL, NULL); +	} +	xfree((ptr_t) vp); +	if (c != '=') +	    xfree((ptr_t) p); +    } while ((p = *v++) != NULL); +} + +static Char * +xset(cp, vp) +    Char   *cp, ***vp; +{ +    register Char *dp; + +    if (*cp) { +	dp = Strsave(cp); +	--(*vp); +	xfree((ptr_t) ** vp); +	**vp = dp; +    } +    return (putn(expr(vp))); +} + +static Char * +operate(op, vp, p) +    int    op; +    Char  *vp, *p; +{ +    Char    opr[2]; +    Char   *vec[5]; +    register Char **v = vec; +    Char  **vecp = v; +    register int i; + +    if (op != '=') { +	if (*vp) +	    *v++ = vp; +	opr[0] = op; +	opr[1] = 0; +	*v++ = opr; +	if (op == '<' || op == '>') +	    *v++ = opr; +    } +    *v++ = p; +    *v++ = 0; +    i = expr(&vecp); +    if (*vecp) +	stderror(ERR_NAME | ERR_EXPRESSION); +    return (putn(i)); +} + +static Char *putp; + +Char   * +putn(n) +    register int n; +{ +    int     num; +    static Char number[15]; + +    putp = number; +    if (n < 0) { +	n = -n; +	*putp++ = '-'; +    } +    num = 2;			/* confuse lint */ +    if (sizeof(int) == num && ((unsigned int) n) == 0x8000) { +	*putp++ = '3'; +	n = 2768; +#ifdef pdp11 +    } +#else +    } +    else { +	num = 4;		/* confuse lint */ +	if (sizeof(int) == num && ((unsigned int) n) == 0x80000000) { +	    *putp++ = '2'; +	    n = 147483648; +	} +    } +#endif +    putn1(n); +    *putp = 0; +    return (Strsave(number)); +} + +static void +putn1(n) +    register int n; +{ +    if (n > 9) +	putn1(n / 10); +    *putp++ = n % 10 + '0'; +} + +int +getn(cp) +    register Char *cp; +{ +    register int n; +    int     sign; + +    sign = 0; +    if (cp[0] == '+' && cp[1]) +	cp++; +    if (*cp == '-') { +	sign++; +	cp++; +	if (!Isdigit(*cp)) +	    stderror(ERR_NAME | ERR_BADNUM); +    } +    n = 0; +    while (Isdigit(*cp)) +	n = n * 10 + *cp++ - '0'; +    if (*cp) +	stderror(ERR_NAME | ERR_BADNUM); +    return (sign ? -n : n); +} + +Char   * +value1(var, head) +    Char   *var; +    struct varent *head; +{ +    register struct varent *vp; + +    vp = adrof1(var, head); +    return (vp == 0 || vp->vec[0] == 0 ? STRNULL : vp->vec[0]); +} + +static struct varent * +madrof(pat, vp) +    Char   *pat; +    register struct varent *vp; +{ +    register struct varent *vp1; + +    for (; vp; vp = vp->v_right) { +	if (vp->v_left && (vp1 = madrof(pat, vp->v_left))) +	    return vp1; +	if (Gmatch(vp->v_name, pat)) +	    return vp; +    } +    return vp; +} + +struct varent * +adrof1(name, v) +    register Char *name; +    register struct varent *v; +{ +    register cmp; + +    v = v->v_left; +    while (v && ((cmp = *name - *v->v_name) || +		 (cmp = Strcmp(name, v->v_name)))) +	if (cmp < 0) +	    v = v->v_left; +	else +	    v = v->v_right; +    return v; +} + +/* + * The caller is responsible for putting value in a safe place + */ +void +set(var, val) +    Char   *var, *val; +{ +    register Char **vec = (Char **) xmalloc((size_t) (2 * sizeof(Char **))); + +    vec[0] = val; +    vec[1] = 0; +    set1(var, vec, &shvhed); +} + +void +set1(var, vec, head) +    Char   *var, **vec; +    struct varent *head; +{ +    register Char **oldv = vec; + +    gflag = 0; +    tglob(oldv); +    if (gflag) { +	vec = globall(oldv); +	if (vec == 0) { +	    blkfree(oldv); +	    stderror(ERR_NAME | ERR_NOMATCH); +	    return; +	} +	blkfree(oldv); +	gargv = 0; +    } +    setq(var, vec, head); +} + + +void +setq(name, vec, p) +    Char   *name, **vec; +    register struct varent *p; +{ +    register struct varent *c; +    register f; + +    f = 0;			/* tree hangs off the header's left link */ +    while ((c = p->v_link[f]) != NULL) { +	if ((f = *name - *c->v_name) == 0 && +	    (f = Strcmp(name, c->v_name)) == 0) { +	    blkfree(c->vec); +	    goto found; +	} +	p = c; +	f = f > 0; +    } +    p->v_link[f] = c = (struct varent *) xmalloc((size_t) sizeof(struct varent)); +    c->v_name = Strsave(name); +    c->v_bal = 0; +    c->v_left = c->v_right = 0; +    c->v_parent = p; +    balance(p, f, 0); +found: +    trim(c->vec = vec); +} + +void +/*ARGSUSED*/ +unset(v, t) +    Char **v; +    struct command *t; +{ +    unset1(v, &shvhed); +#ifdef FILEC +    if (adrof(STRfilec) == 0) +	filec = 0; +#endif +    if (adrof(STRhistchars) == 0) { +	HIST = '!'; +	HISTSUB = '^'; +    } +    if (adrof(STRwordchars) == 0) +	word_chars = STR_WORD_CHARS; +} + +void +unset1(v, head) +    register Char *v[]; +    struct varent *head; +{ +    register struct varent *vp; +    register int cnt; + +    while (*++v) { +	cnt = 0; +	while ((vp = madrof(*v, head->v_left)) != NULL) +	    unsetv1(vp), cnt++; +	if (cnt == 0) +	    setname(vis_str(*v)); +    } +} + +void +unsetv(var) +    Char   *var; +{ +    register struct varent *vp; + +    if ((vp = adrof1(var, &shvhed)) == 0) +	udvar(var); +    unsetv1(vp); +} + +static void +unsetv1(p) +    register struct varent *p; +{ +    register struct varent *c, *pp; +    register f; + +    /* +     * Free associated memory first to avoid complications. +     */ +    blkfree(p->vec); +    xfree((ptr_t) p->v_name); +    /* +     * If p is missing one child, then we can move the other into where p is. +     * Otherwise, we find the predecessor of p, which is guaranteed to have no +     * right child, copy it into p, and move it's left child into it. +     */ +    if (p->v_right == 0) +	c = p->v_left; +    else if (p->v_left == 0) +	c = p->v_right; +    else { +	for (c = p->v_left; c->v_right; c = c->v_right) +	    continue; +	p->v_name = c->v_name; +	p->vec = c->vec; +	p = c; +	c = p->v_left; +    } +    /* +     * Move c into where p is. +     */ +    pp = p->v_parent; +    f = pp->v_right == p; +    if ((pp->v_link[f] = c) != NULL) +	c->v_parent = pp; +    /* +     * Free the deleted node, and rebalance. +     */ +    xfree((ptr_t) p); +    balance(pp, f, 1); +} + +void +setNS(cp) +    Char   *cp; +{ +    set(cp, Strsave(STRNULL)); +} + +void +/*ARGSUSED*/ +shift(v, t) +    Char **v; +    struct command *t; +{ +    register struct varent *argv; +    register Char *name; + +    v++; +    name = *v; +    if (name == 0) +	name = STRargv; +    else +	(void) strip(name); +    argv = adrof(name); +    if (argv == 0) +	udvar(name); +    if (argv->vec[0] == 0) +	stderror(ERR_NAME | ERR_NOMORE); +    lshift(argv->vec, 1); +} + +static void +exportpath(val) +    Char  **val; +{ +    Char    exppath[BUFSIZ]; + +    exppath[0] = 0; +    if (val) +	while (*val) { +	    if (Strlen(*val) + Strlen(exppath) + 2 > BUFSIZ) { +		(void) fprintf(csherr, +			       "Warning: ridiculously long PATH truncated\n"); +		break; +	    } +	    if ((**val != '/' || **val == '\0') && (euid == 0 || uid == 0))  +		    (void) fprintf(csherr, +		    "Warning: exported path contains relative components.\n"); +	    (void) Strcat(exppath, *val++); +	    if (*val == 0 || eq(*val, STRRparen)) +		break; +	    (void) Strcat(exppath, STRcolon); +	} +    Setenv(STRPATH, exppath); +} + +#ifndef lint + /* +  * Lint thinks these have null effect +  */ + /* macros to do single rotations on node p */ +#define rright(p) (\ +	t = (p)->v_left,\ +	(t)->v_parent = (p)->v_parent,\ +	((p)->v_left = t->v_right) ? (t->v_right->v_parent = (p)) : 0,\ +	(t->v_right = (p))->v_parent = t,\ +	(p) = t) +#define rleft(p) (\ +	t = (p)->v_right,\ +	(t)->v_parent = (p)->v_parent,\ +	((p)->v_right = t->v_left) ? (t->v_left->v_parent = (p)) : 0,\ +	(t->v_left = (p))->v_parent = t,\ +	(p) = t) +#else +struct varent * +rleft(p) +    struct varent *p; +{ +    return (p); +} +struct varent * +rright(p) +    struct varent *p; +{ +    return (p); +} + +#endif				/* ! lint */ + + +/* + * Rebalance a tree, starting at p and up. + * F == 0 means we've come from p's left child. + * D == 1 means we've just done a delete, otherwise an insert. + */ +static void +balance(p, f, d) +    register struct varent *p; +    register int f, d; +{ +    register struct varent *pp; + +#ifndef lint +    register struct varent *t;	/* used by the rotate macros */ + +#endif +    register ff; + +    /* +     * Ok, from here on, p is the node we're operating on; pp is it's parent; f +     * is the branch of p from which we have come; ff is the branch of pp which +     * is p. +     */ +    for (; (pp = p->v_parent) != NULL; p = pp, f = ff) { +	ff = pp->v_right == p; +	if (f ^ d) {		/* right heavy */ +	    switch (p->v_bal) { +	    case -1:		/* was left heavy */ +		p->v_bal = 0; +		break; +	    case 0:		/* was balanced */ +		p->v_bal = 1; +		break; +	    case 1:		/* was already right heavy */ +		switch (p->v_right->v_bal) { +		case 1:	/* sigle rotate */ +		    pp->v_link[ff] = rleft(p); +		    p->v_left->v_bal = 0; +		    p->v_bal = 0; +		    break; +		case 0:	/* single rotate */ +		    pp->v_link[ff] = rleft(p); +		    p->v_left->v_bal = 1; +		    p->v_bal = -1; +		    break; +		case -1:	/* double rotate */ +		    (void) rright(p->v_right); +		    pp->v_link[ff] = rleft(p); +		    p->v_left->v_bal = +			p->v_bal < 1 ? 0 : -1; +		    p->v_right->v_bal = +			p->v_bal > -1 ? 0 : 1; +		    p->v_bal = 0; +		    break; +		} +		break; +	    } +	} +	else {			/* left heavy */ +	    switch (p->v_bal) { +	    case 1:		/* was right heavy */ +		p->v_bal = 0; +		break; +	    case 0:		/* was balanced */ +		p->v_bal = -1; +		break; +	    case -1:		/* was already left heavy */ +		switch (p->v_left->v_bal) { +		case -1:	/* single rotate */ +		    pp->v_link[ff] = rright(p); +		    p->v_right->v_bal = 0; +		    p->v_bal = 0; +		    break; +		case 0:	/* signle rotate */ +		    pp->v_link[ff] = rright(p); +		    p->v_right->v_bal = -1; +		    p->v_bal = 1; +		    break; +		case 1:	/* double rotate */ +		    (void) rleft(p->v_left); +		    pp->v_link[ff] = rright(p); +		    p->v_left->v_bal = +			p->v_bal < 1 ? 0 : -1; +		    p->v_right->v_bal = +			p->v_bal > -1 ? 0 : 1; +		    p->v_bal = 0; +		    break; +		} +		break; +	    } +	} +	/* +	 * If from insert, then we terminate when p is balanced. If from +	 * delete, then we terminate when p is unbalanced. +	 */ +	if ((p->v_bal == 0) ^ d) +	    break; +    } +} + +void +plist(p) +    register struct varent *p; +{ +    register struct varent *c; +    register len; + +    if (setintr) +	(void) sigsetmask(sigblock((sigset_t) 0) & ~sigmask(SIGINT)); + +    for (;;) { +	while (p->v_left) +	    p = p->v_left; +x: +	if (p->v_parent == 0)	/* is it the header? */ +	    return; +	len = blklen(p->vec); +	(void) fprintf(cshout, "%s\t", short2str(p->v_name)); +	if (len != 1) +	    (void) fputc('(', cshout); +	blkpr(cshout, p->vec); +	if (len != 1) +	    (void) fputc(')', cshout); +	(void) fputc('\n', cshout); +	if (p->v_right) { +	    p = p->v_right; +	    continue; +	} +	do { +	    c = p; +	    p = p->v_parent; +	} while (p->v_right == c); +	goto x; +    } +} | 
