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