diff options
Diffstat (limited to 'contrib/tcsh/sh.set.c')
-rw-r--r-- | contrib/tcsh/sh.set.c | 1303 |
1 files changed, 1303 insertions, 0 deletions
diff --git a/contrib/tcsh/sh.set.c b/contrib/tcsh/sh.set.c new file mode 100644 index 0000000..0f98a2b --- /dev/null +++ b/contrib/tcsh/sh.set.c @@ -0,0 +1,1303 @@ +/* $Header: /p/tcsh/cvsroot/tcsh/sh.set.c,v 3.83 2012/01/15 17:15:28 christos Exp $ */ +/* + * sh.set.c: Setting and Clearing of variables + */ +/*- + * Copyright (c) 1980, 1991 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. 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. + */ +#include "sh.h" + +RCSID("$tcsh: sh.set.c,v 3.83 2012/01/15 17:15:28 christos Exp $") + +#include "ed.h" +#include "tw.h" + +#ifdef HAVE_NL_LANGINFO +#include <langinfo.h> +#endif + +extern int GotTermCaps; +int numeof = 0; + +static void update_vars (Char *); +static Char *getinx (Char *, int *); +static void asx (Char *, int, Char *); +static struct varent *getvx (Char *, int); +static Char *xset (Char *, Char ***); +static Char *operate (int, Char *, Char *); +static void putn1 (tcsh_number_t); +static struct varent *madrof (Char *, struct varent *); +static void unsetv1 (struct varent *); +static void exportpath (Char **); +static void balance (struct varent *, int, int); + +/* + * C Shell + */ + +static void +update_vars(Char *vp) +{ + if (eq(vp, STRpath)) { + struct varent *p = adrof(STRpath); + if (p == NULL) + stderror(ERR_NAME | ERR_UNDVAR); + else { + exportpath(p->vec); + dohash(NULL, NULL); + } + } + else if (eq(vp, STRhistchars)) { + Char *pn = varval(vp); + + HIST = *pn++; + if (HIST) + HISTSUB = *pn; + else + HISTSUB = HIST; + } + else if (eq(vp, STRpromptchars)) { + Char *pn = varval(vp); + + PRCH = *pn++; + if (PRCH) + PRCHROOT = *pn; + else + PRCHROOT = PRCH; + } + else if (eq(vp, STRhistlit)) { + HistLit = 1; + } + else if (eq(vp, STRuser)) { + tsetenv(STRKUSER, varval(vp)); + tsetenv(STRLOGNAME, varval(vp)); + } + else if (eq(vp, STRgroup)) { + tsetenv(STRKGROUP, varval(vp)); + } + else if (eq(vp, STRwordchars)) { + word_chars = varval(vp); + } + else if (eq(vp, STRloginsh)) { + loginsh = 1; + } + else if (eq(vp, STRanyerror)) { + anyerror = 1; + } + else if (eq(vp, STRsymlinks)) { + Char *pn = varval(vp); + + if (eq(pn, STRignore)) + symlinks = SYM_IGNORE; + else if (eq(pn, STRexpand)) + symlinks = SYM_EXPAND; + else if (eq(pn, STRchase)) + symlinks = SYM_CHASE; + else + symlinks = 0; + } + else if (eq(vp, STRterm)) { + Char *cp = varval(vp); + tsetenv(STRKTERM, cp); +#ifdef DOESNT_WORK_RIGHT + cp = getenv("TERMCAP"); + if (cp && (*cp != '/')) /* if TERMCAP and not a path */ + Unsetenv(STRTERMCAP); +#endif /* DOESNT_WORK_RIGHT */ + GotTermCaps = 0; + if (noediting && Strcmp(cp, STRnetwork) != 0 && + Strcmp(cp, STRunknown) != 0 && Strcmp(cp, STRdumb) != 0) { + editing = 1; + noediting = 0; + setNS(STRedit); + } + ed_Init(); /* reset the editor */ + } + else if (eq(vp, STRhome)) { + Char *cp, *canon; + + cp = Strsave(varval(vp)); /* get the old value back */ + cleanup_push(cp, xfree); + + /* + * convert to cononical pathname (possibly resolving symlinks) + */ + canon = dcanon(cp, cp); + cleanup_ignore(cp); + cleanup_until(cp); + cleanup_push(canon, xfree); + + setcopy(vp, canon, VAR_READWRITE); /* have to save the new val */ + + /* and now mirror home with HOME */ + tsetenv(STRKHOME, canon); + /* fix directory stack for new tilde home */ + dtilde(); + cleanup_until(canon); + } + else if (eq(vp, STRedit)) { + editing = 1; + noediting = 0; + /* PWP: add more stuff in here later */ + } + else if (eq(vp, STRshlvl)) { + tsetenv(STRKSHLVL, varval(vp)); + } + else if (eq(vp, STRignoreeof)) { + Char *cp; + numeof = 0; + for ((cp = varval(STRignoreeof)); cp && *cp; cp++) { + if (!Isdigit(*cp)) { + numeof = 0; + break; + } + numeof = numeof * 10 + *cp - '0'; + } + if (numeof <= 0) numeof = 26; /* Sanity check */ + } + else if (eq(vp, STRbackslash_quote)) { + bslash_quote = 1; + } + else if (eq(vp, STRcompat_expr)) { + compat_expr = 1; + } + else if (eq(vp, STRdirstack)) { + dsetstack(); + } + else if (eq(vp, STRrecognize_only_executables)) { + tw_cmd_free(); + } + else if (eq(vp, STRkillring)) { + SetKillRing((int)getn(varval(vp))); + } +#ifndef HAVENOUTMP + else if (eq(vp, STRwatch)) { + resetwatch(); + } +#endif /* HAVENOUTMP */ + else if (eq(vp, STRimplicitcd)) { + implicit_cd = ((eq(varval(vp), STRverbose)) ? 2 : 1); + } +#ifdef COLOR_LS_F + else if (eq(vp, STRcolor)) { + set_color_context(); + } +#endif /* COLOR_LS_F */ +#if defined(KANJI) && defined(SHORT_STRINGS) && defined(DSPMBYTE) + else if(eq(vp, CHECK_MBYTEVAR) || eq(vp, STRnokanji)) { + update_dspmbyte_vars(); + } +#endif +#ifdef NLS_CATALOGS + else if (eq(vp, STRcatalog)) { + nlsclose(); + nlsinit(); + } +#if defined(FILEC) && defined(TIOCSTI) + else if (eq(vp, STRfilec)) + filec = 1; +#endif +#endif /* NLS_CATALOGS */ +} + + +/*ARGSUSED*/ +void +doset(Char **v, struct command *c) +{ + Char *p; + Char *vp; + Char **vecp; + int hadsub; + int subscr; + int flags = VAR_READWRITE; + int first_match = 0; + int last_match = 0; + int changed = 0; + + USE(c); + v++; + do { + changed = 0; + /* + * Readonly addition From: Tim P. Starrin <noid@cyborg.larc.nasa.gov> + */ + if (*v && eq(*v, STRmr)) { + flags = VAR_READONLY; + v++; + changed = 1; + } + if (*v && eq(*v, STRmf) && !last_match) { + first_match = 1; + v++; + changed = 1; + } + if (*v && eq(*v, STRml) && !first_match) { + last_match = 1; + v++; + changed = 1; + } + } while(changed); + p = *v++; + if (p == 0) { + plist(&shvhed, flags); + return; + } + do { + hadsub = 0; + vp = p; + if (!letter(*p)) + stderror(ERR_NAME | ERR_VARBEGIN); + do { + p++; + } while (alnum(*p)); + if (*p == '[') { + hadsub++; + p = getinx(p, &subscr); + } + if (*p != '\0' && *p != '=') + stderror(ERR_NAME | ERR_VARALNUM); + if (*p == '=') { + *p++ = '\0'; + if (*p == '\0' && *v != NULL && **v == '(') + p = *v++; + } + else if (*v && eq(*v, STRequal)) { + if (*++v != NULL) + p = *v++; + } + if (eq(p, STRLparen)) { + 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); + if (first_match) + flags |= VAR_FIRST; + else if (last_match) + flags |= VAR_LAST; + + set1(vp, vecp, &shvhed, flags); + *e = p; + v = e + 1; + } + else if (hadsub) { + Char *copy; + + copy = Strsave(p); + cleanup_push(copy, xfree); + asx(vp, subscr, copy); + cleanup_ignore(copy); + cleanup_until(copy); + } + else + setv(vp, Strsave(p), flags); + update_vars(vp); + } while ((p = *v++) != NULL); +} + +static Char * +getinx(Char *cp, 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(Char *vp, int subscr, Char *p) +{ + struct varent *v = getvx(vp, subscr); + Char *prev; + + if (v->v_flags & VAR_READONLY) + stderror(ERR_READONLY|ERR_NAME, v->v_name); + prev = v->vec[subscr - 1]; + cleanup_push(prev, xfree); + v->vec[subscr - 1] = globone(p, G_APPEND); + cleanup_until(prev); +} + +static struct varent * +getvx(Char *vp, int subscr) +{ + struct varent *v = adrof(vp); + + if (v == 0) + udvar(vp); + if (subscr < 1 || subscr > blklen(v->vec)) + stderror(ERR_NAME | ERR_RANGE); + return (v); +} + +/*ARGSUSED*/ +void +dolet(Char **v, struct command *dummy) +{ + Char *p; + Char *vp, c, op; + int hadsub; + int subscr; + + USE(dummy); + 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 == '[') { + hadsub++; + p = getinx(p, &subscr); + } + if (*p == 0 && *v) + p = *v++; + if ((op = *p) != 0) + *p++ = 0; + else + stderror(ERR_NAME | ERR_ASSIGN); + + /* + * if there is no expression after the '=' then print a "Syntax Error" + * message - strike + */ + if (*p == '\0' && *v == NULL) + stderror(ERR_NAME | ERR_ASSIGN); + + vp = Strsave(vp); + cleanup_push(vp, xfree); + 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); + stderror(ERR_NAME | ERR_SYNTAX); + } + if (c != '=') + stderror(ERR_NAME | ERR_UNKNOWNOP); + p = xset(p, &v); + } + } + cleanup_push(p, xfree); + if (op == '=') { + if (hadsub) + asx(vp, subscr, p); + else + setv(vp, p, VAR_READWRITE); + cleanup_ignore(p); + } + else if (hadsub) { + struct varent *gv = getvx(vp, subscr); + Char *val; + + val = operate(op, gv->vec[subscr - 1], p); + cleanup_push(val, xfree); + asx(vp, subscr, val); + cleanup_ignore(val); + cleanup_until(val); + } + else { + Char *val; + + val = operate(op, varval(vp), p); + cleanup_push(val, xfree); + setv(vp, val, VAR_READWRITE); + cleanup_ignore(val); + cleanup_until(val); + } + update_vars(vp); + cleanup_until(vp); + } while ((p = *v++) != NULL); +} + +static Char * +xset(Char *cp, Char ***vp) +{ + Char *dp; + + if (*cp) { + dp = Strsave(cp); + --(*vp); + xfree(** vp); + **vp = dp; + } + return (putn(expr(vp))); +} + +static Char * +operate(int op, Char *vp, Char *p) +{ + Char opr[2]; + Char *vec[5]; + Char **v = vec; + Char **vecp = v; + tcsh_number_t 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(tcsh_number_t n) +{ + Char nbuf[1024]; /* Enough even for octal */ + + putp = nbuf; + if (n < 0) { + n = -n; + *putp++ = '-'; + } + putn1(n); + *putp = 0; + return (Strsave(nbuf)); +} + +static void +putn1(tcsh_number_t n) +{ + if (n > 9) + putn1(n / 10); + *putp++ = (Char)(n % 10 + '0'); +} + +tcsh_number_t +getn(const Char *cp) +{ + tcsh_number_t n; + int sign; + int base; + + if (!cp) /* PWP: extra error checking */ + stderror(ERR_NAME | ERR_BADNUM); + + sign = 0; + if (cp[0] == '+' && cp[1]) + cp++; + if (*cp == '-') { + sign++; + cp++; + if (!Isdigit(*cp)) + stderror(ERR_NAME | ERR_BADNUM); + } + + if (cp[0] == '0' && cp[1] && is_set(STRparseoctal)) + base = 8; + else + base = 10; + + n = 0; + while (Isdigit(*cp)) + { + if (base == 8 && *cp >= '8') + stderror(ERR_NAME | ERR_BADNUM); + n = n * base + *cp++ - '0'; + } + if (*cp) + stderror(ERR_NAME | ERR_BADNUM); + return (sign ? -n : n); +} + +Char * +value1(Char *var, struct varent *head) +{ + struct varent *vp; + + if (!var || !head) /* PWP: extra error checking */ + return (STRNULL); + + vp = adrof1(var, head); + return ((vp == NULL || vp->vec == NULL || vp->vec[0] == NULL) ? + STRNULL : vp->vec[0]); +} + +static struct varent * +madrof(Char *pat, struct varent *vp) +{ + struct varent *vp1; + + for (vp = vp->v_left; vp; vp = vp->v_right) { + if (vp->v_left && (vp1 = madrof(pat, vp)) != NULL) + return vp1; + if (Gmatch(vp->v_name, pat)) + return vp; + } + return vp; +} + +struct varent * +adrof1(const Char *name, struct varent *v) +{ + int cmp; + + v = v->v_left; + while (v && ((cmp = *name - *v->v_name) != 0 || + (cmp = Strcmp(name, v->v_name)) != 0)) + if (cmp < 0) + v = v->v_left; + else + v = v->v_right; + return v; +} + +void +setcopy(const Char *var, const Char *val, int flags) +{ + Char *copy; + + copy = Strsave(val); + cleanup_push(copy, xfree); + setv(var, copy, flags); + cleanup_ignore(copy); + cleanup_until(copy); +} + +/* + * The caller is responsible for putting value in a safe place + */ +void +setv(const Char *var, Char *val, int flags) +{ + Char **vec = xmalloc(2 * sizeof(Char **)); + + vec[0] = val; + vec[1] = 0; + set1(var, vec, &shvhed, flags); +} + +void +set1(const Char *var, Char **vec, struct varent *head, int flags) +{ + Char **oldv = vec; + + if ((flags & VAR_NOGLOB) == 0) { + int gflag; + + gflag = tglob(oldv); + if (gflag) { + vec = globall(oldv, gflag); + if (vec == 0) { + blkfree(oldv); + stderror(ERR_NAME | ERR_NOMATCH); + } + blkfree(oldv); + } + } + /* + * Uniqueness addition from: Michael Veksler <mveksler@vnet.ibm.com> + */ + if ( flags & (VAR_FIRST | VAR_LAST) ) { + /* + * Code for -f (VAR_FIRST) and -l (VAR_LAST) options. + * Method: + * Delete all duplicate words leaving "holes" in the word array (vec). + * Then remove the "holes", keeping the order of the words unchanged. + */ + if (vec && vec[0] && vec[1]) { /* more than one word ? */ + int i, j; + int num_items; + + for (num_items = 0; vec[num_items]; num_items++) + continue; + if (flags & VAR_FIRST) { + /* delete duplications, keeping first occurance */ + for (i = 1; i < num_items; i++) + for (j = 0; j < i; j++) + /* If have earlier identical item, remove i'th item */ + if (vec[i] && vec[j] && Strcmp(vec[j], vec[i]) == 0) { + xfree(vec[i]); + vec[i] = NULL; + break; + } + } else if (flags & VAR_LAST) { + /* delete duplications, keeping last occurance */ + for (i = 0; i < num_items - 1; i++) + for (j = i + 1; j < num_items; j++) + /* If have later identical item, remove i'th item */ + if (vec[i] && vec[j] && Strcmp(vec[j], vec[i]) == 0) { + /* remove identical item (the first) */ + xfree(vec[i]); + vec[i] = NULL; + } + } + /* Compress items - remove empty items */ + for (j = i = 0; i < num_items; i++) + if (vec[i]) + vec[j++] = vec[i]; + + /* NULL-fy remaining items */ + for (; j < num_items; j++) + vec[j] = NULL; + } + /* don't let the attribute propagate */ + flags &= ~(VAR_FIRST|VAR_LAST); + } + setq(var, vec, head, flags); +} + + +void +setq(const Char *name, Char **vec, struct varent *p, int flags) +{ + struct varent *c; + int f; + + f = 0; /* tree hangs off the header's left link */ + while ((c = p->v_link[f]) != 0) { + if ((f = *name - *c->v_name) == 0 && + (f = Strcmp(name, c->v_name)) == 0) { + if (c->v_flags & VAR_READONLY) + stderror(ERR_READONLY|ERR_NAME, c->v_name); + blkfree(c->vec); + c->v_flags = flags; + trim(c->vec = vec); + return; + } + p = c; + f = f > 0; + } + p->v_link[f] = c = xmalloc(sizeof(struct varent)); + c->v_name = Strsave(name); + c->v_flags = flags; + c->v_bal = 0; + c->v_left = c->v_right = 0; + c->v_parent = p; + balance(p, f, 0); + trim(c->vec = vec); +} + +/*ARGSUSED*/ +void +unset(Char **v, struct command *c) +{ + int did_roe, did_edit; + + USE(c); + did_roe = adrof(STRrecognize_only_executables) != NULL; + did_edit = adrof(STRedit) != NULL; + unset1(v, &shvhed); + +#if defined(FILEC) && defined(TIOCSTI) + if (adrof(STRfilec) == 0) + filec = 0; +#endif /* FILEC && TIOCSTI */ + + if (adrof(STRhistchars) == 0) { + HIST = '!'; + HISTSUB = '^'; + } + if (adrof(STRignoreeof) == 0) + numeof = 0; + if (adrof(STRpromptchars) == 0) { + PRCH = tcsh ? '>' : '%'; + PRCHROOT = '#'; + } + if (adrof(STRhistlit) == 0) + HistLit = 0; + if (adrof(STRloginsh) == 0) + loginsh = 0; + if (adrof(STRanyerror) == 0) + anyerror = 0; + if (adrof(STRwordchars) == 0) + word_chars = STR_WORD_CHARS; + if (adrof(STRedit) == 0) + editing = 0; + if (adrof(STRbackslash_quote) == 0) + bslash_quote = 0; + if (adrof(STRcompat_expr) == 0) + compat_expr = 0; + if (adrof(STRsymlinks) == 0) + symlinks = 0; + if (adrof(STRimplicitcd) == 0) + implicit_cd = 0; + if (adrof(STRkillring) == 0) + SetKillRing(0); + if (did_edit && noediting && adrof(STRedit) == 0) + noediting = 0; + if (did_roe && adrof(STRrecognize_only_executables) == 0) + tw_cmd_free(); +#ifdef COLOR_LS_F + if (adrof(STRcolor) == 0) + set_color_context(); +#endif /* COLOR_LS_F */ +#if defined(KANJI) && defined(SHORT_STRINGS) && defined(DSPMBYTE) + update_dspmbyte_vars(); +#endif +#ifdef NLS_CATALOGS + nlsclose(); + nlsinit(); +#endif /* NLS_CATALOGS */ +} + +void +unset1(Char *v[], struct varent *head) +{ + struct varent *vp; + int cnt; + + while (*++v) { + cnt = 0; + while ((vp = madrof(*v, head)) != NULL) + if (vp->v_flags & VAR_READONLY) + stderror(ERR_READONLY|ERR_NAME, vp->v_name); + else + unsetv1(vp), cnt++; + if (cnt == 0) + setname(short2str(*v)); + } +} + +void +unsetv(Char *var) +{ + struct varent *vp; + + if ((vp = adrof1(var, &shvhed)) == 0) + udvar(var); + unsetv1(vp); +} + +static void +unsetv1(struct varent *p) +{ + struct varent *c, *pp; + int f; + + /* + * Free associated memory first to avoid complications. + */ + blkfree(p->vec); + xfree(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->v_flags = c->v_flags; + 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) != 0) + c->v_parent = pp; + /* + * Free the deleted node, and rebalance. + */ + xfree(p); + balance(pp, f, 1); +} + +/* Set variable name to NULL. */ +void +setNS(const Char *varName) +{ + setcopy(varName, STRNULL, VAR_READWRITE); +} + +/*ARGSUSED*/ +void +shift(Char **v, struct command *c) +{ + struct varent *argv; + Char *name; + + USE(c); + v++; + name = *v; + if (name == 0) + name = STRargv; + else + (void) strip(name); + argv = adrof(name); + if (argv == NULL || argv->vec == NULL) + udvar(name); + if (argv->vec[0] == 0) + stderror(ERR_NAME | ERR_NOMORE); + lshift(argv->vec, 1); + update_vars(name); +} + +static void +exportpath(Char **val) +{ + struct Strbuf buf = Strbuf_INIT; + Char *exppath; + + if (val) + while (*val) { + Strbuf_append(&buf, *val++); + if (*val == 0 || eq(*val, STRRparen)) + break; + Strbuf_append1(&buf, PATHSEP); + } + exppath = Strbuf_finish(&buf); + cleanup_push(exppath, xfree); + tsetenv(STRKPATH, exppath); + cleanup_until(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) != NULL) ?\ + (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) != NULL) ? \ + (t->v_left->v_parent = (p)) : 0,\ + (t->v_left = (p))->v_parent = t,\ + (p) = t) +#else +static struct varent * +rleft(struct varent *p) +{ + return (p); +} +static struct varent * +rright(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(struct varent *p, int f, int d) +{ + struct varent *pp; + +#ifndef lint + struct varent *t; /* used by the rotate macros */ +#endif /* !lint */ + int ff; +#ifdef lint + ff = 0; /* Sun's lint is dumb! */ +#endif + + /* + * 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) != 0; 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: /* single 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; + default: + break; + } + break; + default: + 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: /* single 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; + default: + break; + } + break; + default: + 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(struct varent *p, int what) +{ + struct varent *c; + int len; + + for (;;) { + while (p->v_left) + p = p->v_left; +x: + if (p->v_parent == 0) /* is it the header? */ + break; + if ((p->v_flags & what) != 0) { + if (setintr) { + int old_pintr_disabled; + + pintr_push_enable(&old_pintr_disabled); + cleanup_until(&old_pintr_disabled); + } + len = blklen(p->vec); + xprintf("%S\t", p->v_name); + if (len != 1) + xputchar('('); + blkpr(p->vec); + if (len != 1) + xputchar(')'); + xputchar('\n'); + } + if (p->v_right) { + p = p->v_right; + continue; + } + do { + c = p; + p = p->v_parent; + } while (p->v_right == c); + goto x; + } +} + +#if defined(KANJI) +# if defined(SHORT_STRINGS) && defined(DSPMBYTE) +extern int dspmbyte_ls; + +void +update_dspmbyte_vars(void) +{ + int lp, iskcode; + Char *dstr1; + struct varent *vp; + + /* if variable "nokanji" is set, multi-byte display is disabled */ + if ((vp = adrof(CHECK_MBYTEVAR)) && !adrof(STRnokanji)) { + _enable_mbdisp = 1; + dstr1 = vp->vec[0]; + if(eq (dstr1, STRsjis)) + iskcode = 1; + else if (eq(dstr1, STReuc)) + iskcode = 2; + else if (eq(dstr1, STRbig5)) + iskcode = 3; + else if (eq(dstr1, STRutf8)) + iskcode = 4; + else if ((dstr1[0] - '0') >= 0 && (dstr1[0] - '0') <= 3) { + iskcode = 0; + } + else { + xprintf(CGETS(18, 2, + "Warning: unknown multibyte display; using default(euc(JP))\n")); + iskcode = 2; + } + if (dstr1 && vp->vec[1] && eq(vp->vec[1], STRls)) + dspmbyte_ls = 1; + else + dspmbyte_ls = 0; + for (lp = 0; lp < 256 && iskcode > 0; lp++) { + switch (iskcode) { + case 1: + /* Shift-JIS */ + _cmap[lp] = _cmap_mbyte[lp]; + _mbmap[lp] = _mbmap_sjis[lp]; + break; + case 2: + /* 2 ... euc */ + _cmap[lp] = _cmap_mbyte[lp]; + _mbmap[lp] = _mbmap_euc[lp]; + break; + case 3: + /* 3 ... big5 */ + _cmap[lp] = _cmap_mbyte[lp]; + _mbmap[lp] = _mbmap_big5[lp]; + break; + case 4: + /* 4 ... utf8 */ + _cmap[lp] = _cmap_mbyte[lp]; + _mbmap[lp] = _mbmap_utf8[lp]; + break; + default: + xprintf(CGETS(18, 3, + "Warning: unknown multibyte code %d; multibyte disabled\n"), + iskcode); + _cmap[lp] = _cmap_c[lp]; + _mbmap[lp] = 0; /* Default map all 0 */ + _enable_mbdisp = 0; + break; + } + } + if (iskcode == 0) { + /* check original table */ + if (Strlen(dstr1) != 256) { + xprintf(CGETS(18, 4, + "Warning: Invalid multibyte table length (%d); multibyte disabled\n"), + Strlen(dstr1)); + _enable_mbdisp = 0; + } + for (lp = 0; lp < 256 && _enable_mbdisp == 1; lp++) { + if (!((dstr1[lp] - '0') >= 0 && (dstr1[lp] - '0') <= 3)) { + xprintf(CGETS(18, 4, + "Warning: bad multibyte code at offset +%d; multibyte diabled\n"), + lp); + _enable_mbdisp = 0; + break; + } + } + /* set original table */ + for (lp = 0; lp < 256; lp++) { + if (_enable_mbdisp == 1) { + _cmap[lp] = _cmap_mbyte[lp]; + _mbmap[lp] = (unsigned short) ((dstr1[lp] - '0') & 0x0f); + } + else { + _cmap[lp] = _cmap_c[lp]; + _mbmap[lp] = 0; /* Default map all 0 */ + } + } + } + } + else { + for (lp = 0; lp < 256; lp++) { + _cmap[lp] = _cmap_c[lp]; + _mbmap[lp] = 0; /* Default map all 0 */ + } + _enable_mbdisp = 0; + dspmbyte_ls = 0; + } +#ifdef MBYTEDEBUG /* Sorry, use for beta testing */ + { + Char mbmapstr[300]; + for (lp = 0; lp < 256; lp++) + mbmapstr[lp] = _mbmap[lp] + '0'; + mbmapstr[lp] = 0; + setcopy(STRmbytemap, mbmapstr, VAR_READWRITE); + } +#endif /* MBYTEMAP */ +} + +/* dspkanji/dspmbyte autosetting */ +/* PATCH IDEA FROM Issei.Suzuki VERY THANKS */ +void +autoset_dspmbyte(const Char *pcp) +{ + int i; + static const struct dspm_autoset_Table { + Char *n; + Char *v; + } dspmt[] = { + { STRLANGEUCJP, STReuc }, + { STRLANGEUCKR, STReuc }, + { STRLANGEUCZH, STReuc }, + { STRLANGEUCJPB, STReuc }, + { STRLANGEUCKRB, STReuc }, + { STRLANGEUCZHB, STReuc }, +#ifdef __linux__ + { STRLANGEUCJPC, STReuc }, +#endif + { STRLANGSJIS, STRsjis }, + { STRLANGSJISB, STRsjis }, + { STRLANGBIG5, STRbig5 }, + { STRstarutfstar8, STRutf8 }, + { NULL, NULL } + }; +#if defined(HAVE_NL_LANGINFO) && defined(CODESET) + static const struct dspm_autoset_Table dspmc[] = { + { STRstarutfstar8, STRutf8 }, + { STReuc, STReuc }, + { STRGB2312, STReuc }, + { STRLANGBIG5, STRbig5 }, + { NULL, NULL } + }; + Char *codeset; + + codeset = str2short(nl_langinfo(CODESET)); + if (*codeset != '\0') { + for (i = 0; dspmc[i].n; i++) { + const Char *estr; + if (dspmc[i].n[0] && t_pmatch(pcp, dspmc[i].n, &estr, 0) > 0) { + setcopy(CHECK_MBYTEVAR, dspmc[i].v, VAR_READWRITE); + update_dspmbyte_vars(); + return; + } + } + } +#endif + + if (*pcp == '\0') + return; + + for (i = 0; dspmt[i].n; i++) { + const Char *estr; + if (dspmt[i].n[0] && t_pmatch(pcp, dspmt[i].n, &estr, 0) > 0) { + setcopy(CHECK_MBYTEVAR, dspmt[i].v, VAR_READWRITE); + update_dspmbyte_vars(); + break; + } + } +} +# elif defined(AUTOSET_KANJI) +void +autoset_kanji(void) +{ + char *codeset = nl_langinfo(CODESET); + + if (*codeset == '\0') { + if (adrof(STRnokanji) == NULL) + setNS(STRnokanji); + return; + } + + if (strcasestr(codeset, "SHIFT_JIS") == (char*)0) { + if (adrof(STRnokanji) == NULL) + setNS(STRnokanji); + return; + } + + if (adrof(STRnokanji) != NULL) + unsetv(STRnokanji); +} +#endif +#endif |