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