"Fossies" - the Fresh Open Source Software Archive

Member "tcsh-6.22.03/sh.set.c" (18 Nov 2020, 29124 Bytes) of package /linux/misc/tcsh-6.22.03.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "sh.set.c": 6.22.02_vs_6.22.03.

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